⭐ 欢迎来到虫虫下载站! | 📦 资源下载 📁 资源专辑 ℹ️ 关于我们
⭐ 虫虫下载站

📄 tcp_usrreq.c

📁 RTEMS (Real-Time Executive for Multiprocessor Systems) is a free open source real-time operating sys
💻 C
📖 第 1 页 / 共 2 页
字号:
{	int s = splnet();	int error = 0;	struct inpcb *inp = sotoinpcb(so);	struct tcpcb *tp;	COMMON_START();	tp = tcp_drop(tp, ECONNABORTED);	COMMON_END(PRU_ABORT);}/* * Fill in st_bklsize for fstat() operations on a socket. */static inttcp_usr_sense(struct socket *so, struct stat *sb){	int s = splnet();	sb->st_blksize = so->so_snd.sb_hiwat;	splx(s);	return 0;}/* * Receive out-of-band data. */static inttcp_usr_rcvoob(struct socket *so, struct mbuf *m, int flags){	int s = splnet();	int error = 0;	struct inpcb *inp = sotoinpcb(so);	struct tcpcb *tp;	COMMON_START();	if ((so->so_oobmark == 0 &&	     (so->so_state & SS_RCVATMARK) == 0) ||	    so->so_options & SO_OOBINLINE ||	    tp->t_oobflags & TCPOOB_HADDATA) {		error = EINVAL;		goto out;	}	if ((tp->t_oobflags & TCPOOB_HAVEDATA) == 0) {		error = EWOULDBLOCK;		goto out;	}	m->m_len = 1;	*mtod(m, caddr_t) = tp->t_iobc;	if ((flags & MSG_PEEK) == 0)		tp->t_oobflags ^= (TCPOOB_HAVEDATA | TCPOOB_HADDATA);	COMMON_END(PRU_RCVOOB);}static inttcp_usr_sockaddr(struct socket *so, struct mbuf *nam){	int s = splnet();	int error = 0;	struct inpcb *inp = sotoinpcb(so);	struct tcpcb *tp;	COMMON_START();	in_setsockaddr(inp, nam);	COMMON_END(PRU_SOCKADDR);}static inttcp_usr_peeraddr(struct socket *so, struct mbuf *nam){	int s = splnet();	int error = 0;	struct inpcb *inp = sotoinpcb(so);	struct tcpcb *tp;	COMMON_START();	in_setpeeraddr(inp, nam);	COMMON_END(PRU_PEERADDR);}/* * XXX - this should just be a call to in_control, but we need to get * the types worked out. */static inttcp_usr_control(struct socket *so, int cmd, caddr_t arg, struct ifnet *ifp){	return in_control(so, cmd, arg, ifp);}/* xxx - should be const */struct pr_usrreqs tcp_usrreqs = {	tcp_usr_abort, tcp_usr_accept, tcp_usr_attach, tcp_usr_bind,	tcp_usr_connect, pru_connect2_notsupp, tcp_usr_control, tcp_usr_detach,	tcp_usr_disconnect, tcp_usr_listen, tcp_usr_peeraddr, tcp_usr_rcvd,	tcp_usr_rcvoob, tcp_usr_send, tcp_usr_sense, tcp_usr_shutdown,	tcp_usr_sockaddr};/* * Common subroutine to open a TCP connection to remote host specified * by struct sockaddr_in in mbuf *nam.  Call in_pcbbind to assign a local * port number if needed.  Call in_pcbladdr to do the routing and to choose * a local host address (interface).  If there is an existing incarnation * of the same connection in TIME-WAIT state and if the remote host was * sending CC options and if the connection duration was < MSL, then * truncate the previous TIME-WAIT state and proceed. * Initialize connection parameters and enter SYN-SENT state. */static inttcp_connect(tp, nam)	register struct tcpcb *tp;	struct mbuf *nam;{	struct inpcb *inp = tp->t_inpcb, *oinp;	struct socket *so = inp->inp_socket;	struct tcpcb *otp;	struct sockaddr_in *sin = mtod(nam, struct sockaddr_in *);	struct sockaddr_in *ifaddr;	int error;	struct rmxp_tao *taop;	struct rmxp_tao tao_noncached;	if (inp->inp_lport == 0) {		error = in_pcbbind(inp, NULL);		if (error)			return error;	}	/*	 * Cannot simply call in_pcbconnect, because there might be an	 * earlier incarnation of this same connection still in	 * TIME_WAIT state, creating an ADDRINUSE error.	 */	error = in_pcbladdr(inp, nam, &ifaddr);	if (error)		return error;	oinp = in_pcblookuphash(inp->inp_pcbinfo,	    sin->sin_addr, sin->sin_port,	    inp->inp_laddr.s_addr != INADDR_ANY ? inp->inp_laddr						: ifaddr->sin_addr,	    inp->inp_lport,  0);	if (oinp) {		if (oinp != inp && (otp = intotcpcb(oinp)) != NULL &&		otp->t_state == TCPS_TIME_WAIT &&		    otp->t_duration < TCPTV_MSL &&		    (otp->t_flags & TF_RCVD_CC))			otp = tcp_close(otp);		else			return EADDRINUSE;	}	if (inp->inp_laddr.s_addr == INADDR_ANY)		inp->inp_laddr = ifaddr->sin_addr;	inp->inp_faddr = sin->sin_addr;	inp->inp_fport = sin->sin_port;	in_pcbrehash(inp);	tp->t_template = tcp_template(tp);	if (tp->t_template == 0) {		in_pcbdisconnect(inp);		return ENOBUFS;	}	/* Compute window scaling to request.  */	while (tp->request_r_scale < TCP_MAX_WINSHIFT &&	    (TCP_MAXWIN << tp->request_r_scale) < so->so_rcv.sb_hiwat)		tp->request_r_scale++;	soisconnecting(so);	tcpstat.tcps_connattempt++;	tp->t_state = TCPS_SYN_SENT;	tp->t_timer[TCPT_KEEP] = tcp_keepinit;	tp->iss = tcp_iss; tcp_iss += TCP_ISSINCR/2;	tcp_sendseqinit(tp);	/*	 * Generate a CC value for this connection and	 * check whether CC or CCnew should be used.	 */	if ((taop = tcp_gettaocache(tp->t_inpcb)) == NULL) {		taop = &tao_noncached;		bzero(taop, sizeof(*taop));	}	tp->cc_send = CC_INC(tcp_ccgen);	if (taop->tao_ccsent != 0 &&	    CC_GEQ(tp->cc_send, taop->tao_ccsent)) {		taop->tao_ccsent = tp->cc_send;	} else {		taop->tao_ccsent = 0;		tp->t_flags |= TF_SENDCCNEW;	}	return 0;}inttcp_ctloutput(op, so, level, optname, mp)	int op;	struct socket *so;	int level, optname;	struct mbuf **mp;{	int error = 0, s;	struct inpcb *inp;	register struct tcpcb *tp;	register struct mbuf *m;	register int i;	s = splnet();	inp = sotoinpcb(so);	if (inp == NULL) {		splx(s);		if (op == PRCO_SETOPT && *mp)			(void) m_free(*mp);		return (ECONNRESET);	}	if (level != IPPROTO_TCP) {		error = ip_ctloutput(op, so, level, optname, mp);		splx(s);		return (error);	}	tp = intotcpcb(inp);	switch (op) {	case PRCO_SETOPT:		m = *mp;		switch (optname) {		case TCP_NODELAY:			if (m == NULL || m->m_len < sizeof (int))				error = EINVAL;			else if (*mtod(m, int *))				tp->t_flags |= TF_NODELAY;			else				tp->t_flags &= ~TF_NODELAY;			break;		case TCP_MAXSEG:			if (m && (i = *mtod(m, int *)) > 0 && i <= tp->t_maxseg)				tp->t_maxseg = i;			else				error = EINVAL;			break;		case TCP_NOOPT:			if (m == NULL || m->m_len < sizeof (int))				error = EINVAL;			else if (*mtod(m, int *))				tp->t_flags |= TF_NOOPT;			else				tp->t_flags &= ~TF_NOOPT;			break;		case TCP_NOPUSH:			if (m == NULL || m->m_len < sizeof (int))				error = EINVAL;			else if (*mtod(m, int *))				tp->t_flags |= TF_NOPUSH;			else				tp->t_flags &= ~TF_NOPUSH;			break;		default:			error = ENOPROTOOPT;			break;		}		if (m)			(void) m_free(m);		break;	case PRCO_GETOPT:		*mp = m = m_get(M_WAIT, MT_SOOPTS);		m->m_len = sizeof(int);		switch (optname) {		case TCP_NODELAY:			*mtod(m, int *) = tp->t_flags & TF_NODELAY;			break;		case TCP_MAXSEG:			*mtod(m, int *) = tp->t_maxseg;			break;		case TCP_NOOPT:			*mtod(m, int *) = tp->t_flags & TF_NOOPT;			break;		case TCP_NOPUSH:			*mtod(m, int *) = tp->t_flags & TF_NOPUSH;			break;		default:			error = ENOPROTOOPT;			break;		}		break;	}	splx(s);	return (error);}/* * tcp_sendspace and tcp_recvspace are the default send and receive window * sizes, respectively.  These are obsolescent (this information should * be set by the route). */u_long	tcp_sendspace = 1024*16;SYSCTL_INT(_net_inet_tcp, TCPCTL_SENDSPACE, sendspace,	CTLFLAG_RW, &tcp_sendspace , 0, "");u_long	tcp_recvspace = 1024*16;SYSCTL_INT(_net_inet_tcp, TCPCTL_RECVSPACE, recvspace,	CTLFLAG_RW, &tcp_recvspace , 0, "");/* * Attach TCP protocol to socket, allocating * internet protocol control block, tcp control block, * bufer space, and entering LISTEN state if to accept connections. */static inttcp_attach(so)	struct socket *so;{	register struct tcpcb *tp;	struct inpcb *inp;	int error;	if (so->so_snd.sb_hiwat == 0 || so->so_rcv.sb_hiwat == 0) {		error = soreserve(so, tcp_sendspace, tcp_recvspace);		if (error)			return (error);	}	error = in_pcballoc(so, &tcbinfo);	if (error)		return (error);	inp = sotoinpcb(so);	tp = tcp_newtcpcb(inp);	if (tp == 0) {		int nofd = so->so_state & SS_NOFDREF;	/* XXX */		so->so_state &= ~SS_NOFDREF;	/* don't free the socket yet */		in_pcbdetach(inp);		so->so_state |= nofd;		return (ENOBUFS);	}	tp->t_state = TCPS_CLOSED;	return (0);}/* * Initiate (or continue) disconnect. * If embryonic state, just send reset (once). * If in ``let data drain'' option and linger null, just drop. * Otherwise (hard), mark socket disconnecting and drop * current input data; switch states based on user close, and * send segment to peer (with FIN). */static struct tcpcb *tcp_disconnect(tp)	register struct tcpcb *tp;{	struct socket *so = tp->t_inpcb->inp_socket;	if (tp->t_state < TCPS_ESTABLISHED)		tp = tcp_close(tp);	else if ((so->so_options & SO_LINGER) && so->so_linger == 0)		tp = tcp_drop(tp, 0);	else {		soisdisconnecting(so);		sbflush(&so->so_rcv);		tp = tcp_usrclosed(tp);		if (tp)			(void) tcp_output(tp);	}	return (tp);}/* * User issued close, and wish to trail through shutdown states: * if never received SYN, just forget it.  If got a SYN from peer, * but haven't sent FIN, then go to FIN_WAIT_1 state to send peer a FIN. * If already got a FIN from peer, then almost done; go to LAST_ACK * state.  In all other cases, have already sent FIN to peer (e.g. * after PRU_SHUTDOWN), and just have to play tedious game waiting * for peer to send FIN or not respond to keep-alives, etc. * We can let the user exit from the close as soon as the FIN is acked. */static struct tcpcb *tcp_usrclosed(tp)	register struct tcpcb *tp;{	switch (tp->t_state) {	case TCPS_CLOSED:	case TCPS_LISTEN:		tp->t_state = TCPS_CLOSED;		tp = tcp_close(tp);		break;	case TCPS_SYN_SENT:	case TCPS_SYN_RECEIVED:		tp->t_flags |= TF_NEEDFIN;		break;	case TCPS_ESTABLISHED:		tp->t_state = TCPS_FIN_WAIT_1;		break;	case TCPS_CLOSE_WAIT:		tp->t_state = TCPS_LAST_ACK;		break;	}	if (tp && tp->t_state >= TCPS_FIN_WAIT_2) {		soisdisconnected(tp->t_inpcb->inp_socket);		/* To prevent the connection hanging in FIN_WAIT_2 forever. */		if (tp->t_state == TCPS_FIN_WAIT_2)			tp->t_timer[TCPT_2MSL] = tcp_maxidle;	}	return (tp);}

⌨️ 快捷键说明

复制代码 Ctrl + C
搜索代码 Ctrl + F
全屏模式 F11
切换主题 Ctrl + Shift + D
显示快捷键 ?
增大字号 Ctrl + =
减小字号 Ctrl + -