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

📄 tcpsock.c

📁 用于嵌入式系统的TCP/IP协议栈及若干服务
💻 C
📖 第 1 页 / 共 5 页
字号:
	svp->sv_initretrim = tcp_initial_rex_delay;  	svp->sv_minretrim =  tcp_min_rex_delay;   	svp->sv_maxretrim =  tcp_max_rex_delay;	svp->sv_ackdelay =  MAX_ACK_DELAY;	svp->sv_ackEveryN =  2;#ifdef TCP_TIMESTAMPS	svp->sv_flags2 &= ~SV_PROVIDE_TIMESTAMPS; /* Socket option default is off */	svp->sv_flags2 &= ~SV_TIMESTAMPS_ENABLED; /* This will be set if the timestamps option											     is succesfully negotiated. */	svp->sv_recent_rx_tmstmp = 0;#endif#ifdef TCP_SELACK_ENHANCEMENTS	/* Selective acknowldegemnt processing and generation are by default disabled */	svp->sv_flags2 &= ~(SV_PERMIT_IN_SACKS | SV_OUT_SACKS_ALLOWED | SV_OUT_SACKS_ENABLED);	svp->sv_num_out_sack_blocks = 0;#endif#ifdef TCP_SS_CA_FRETR_FREC 	svp->sv_flags2 |= SV_SLOW_START_CA;	svp->sv_flags2 &= ~SV_FAST_RETR_RECOV;#endif /* TCP_SS_CA_FRETR_FREC */	svp->sv_flags2 &= ~SV_NAGLE_DISABLED; #ifdef TCP_TRANSACTION_TCP#ifdef T_TCP_TRANS_DEFAULT_ON		svp->sv_t_tcp_flags = SV_TRANSACTION; #else		svp->sv_t_tcp_flags = 0; #endif#endif /* TCP_TRANSACTION_TCP */    sop->so_hsize += SIZEOF_TCPH_T;    /* Linger is OFF by default.  But this does NOT imply that       the close done on a TCP socket won't be graceful.  It       only won't be graceful if linger is ON, AND, if the        linger time is zero.    */    SET_SOCKET_OPTION_OFF(sop,SO_LINGER);    sop->so_poptions = DEFAULT_LINGER_TIME;    /* insert the new state vector into the tcp state vector queue */    (void) q_in(&tcp_q, &svp->sv_q);    sv_detach(svp, tcpattach, true);    return OK;} /* tcpattach *//*******************************************************************/export  int tcp_bind (so_t * sop, saddr * to, int tolen){    fast    tcpsv_t * svp;    fast    int     err;    fast    ipa     * ipap;    fast    u16     port;    auto    so_addr addr;    struct  in_sockaddr;    so_t    * nsop;    use_critical;    trace0(tcp_trace, "tcp_bind:\n");    trace2(tcp_tbind, "tcp_bind: [%d], sop->so_prp = %x\n", sop->so_index, sop->so_prp);    err = 0;    critical;    if ((svp = sop->so_svp) == (tcpsv_t *)0) {        debug0(tcp_debug, "tcp_bind: no state vector\n");        normal;        return FNS_EINVAL;  /* no state vector */    }    sv_bind(svp, tcp_bind, true);    normal;    if (svp->sv_state != CLOSED) {        /* not possible to bind in any other state */        debug1(tcp_debug, "tcp_bind: non-closed state, (%s)\n", tcp_st(svp->sv_state));        err = FNS_EINVAL;        goto out;    }    if ((err = ip_inaddr(to, tolen, (so_addr *)&addr)) != 0)    {        debug1(tcp_debug, "tcp_bind: ip_inaddr returned %d\n", err);        goto out;    }    /* Make sure not bound already by checking svp->sv_src */    if( (svp->sv_src.ip_port != 0) ||        (svp->sv_src.ip_nethost != 0) ) {        err = FNS_EINVAL;        goto out;    }    ipap = (ipa *)&addr.a_ipa;    if ((port = ntohs(ipap->ip_port)) != (u16)0) {        fast    tcpsv_t * nsvp;        /* look through the TCP sockets for a port collision. */        critical;        for (nsvp = (tcpsv_t *)tcp_q.q_next; nsvp != (tcpsv_t *)&tcp_q;                     nsvp = (tcpsv_t *)nsvp->sv_q.q_next) {			if (nsvp == svp) continue;            /* If this state vector is not associated with a socket at present,			   of if its local port number is different than the port which is the			   object of this bind, no collision */			if ( ((nsop = sv_valid_sop(nsvp, nsop)) == (so_t *)0) ||				 (ntohs(nsvp->sv_src.ip_port) != port) ) {				continue;			}#ifndef SOCKET_USE_OLD_SOCKOPT_FUNCTIONS			/* The below logic implements the discussion of SO_REUSEPORT and SO_REUSEADDR			   in Stevens: Unix Network Programming Volume 1, second edition. */			/* The socket we are looking at has the same port number as the socket that			   is attempting to bind. If both sockets have the SO_REUSEPORT socket option			   in effect, then there is no need to look further -- complete port/address			   matches are allowed. */            if ( (GET_SOCKET_OPTION_STATUS(nsop,SO_REUSEPORT)) &&				(GET_SOCKET_OPTION_STATUS(sop,SO_REUSEPORT)) ) {				continue;			}#else		/* NOTE: Does this need to be fixed for the case where we don't support the'		   SO_REUSEPORT socket option??? -- MBM */#endif			/*  No SO_REUSEPORT here, so cannot have a complete port/address match.			    But we can allow a port match if the SO_REUSEADDR socket option is				effect, as long as the local IP address doesn't match. */            if ( ( (GET_SOCKET_OPTION_STATUS(nsop,SO_REUSEADDR)) == 0) ||			  (nsvp->sv_src.ip_nethost == addr.a_ipa.ip_nethost) ) {                normal;                err = FNS_EADDRINUSE;                goto out;			}		} /* for */        normal;    } else {        /* port 0 special case */            /* pick a new port number */            ipap->ip_port = htons((u16)(TCP_MIN_FREE + (tcp_port|(sop->so_index<<8))));            tcp_port++;            tcp_port &= 0xFF;	}    /* otherwise, bind to 0.0.0.0, 0 */    trace2(tcp_tbind, "tcp_bind: binding [%d] to (%s)\n", sop->so_index, ipa2str(ipap, (char *)0));    stass(svp->sv_src, addr.a_ipa); /* grab it */out:    sv_detach(svp, tcp_bind, true);    return err;} /* tcp_bind *//*******************************************************************//* ULP abort */export  int     tcp_cabort (fast so_t * sop){    fast    tcpsv_t * svp;    use_critical;    trace0(tcp_trace, "tcp_cabort:\n");    critical;    if ((svp = sop->so_svp) == (tcpsv_t *)0) {      /* no state vector */        debug0(tcp_debug, "tcp_cabort: no state vector\n");        normal;        return FNS_ENOTCONN;    }    sv_bind(svp, tcp_cabort, true);    normal;    if (svp->sv_state != CLOSED)        tcpabort(svp, FNS_ECONNABORTED);    sv_detach(svp, tcp_cabort, true);    return 0;}/*******************************************************************//* ULP close event */export  int     tcpclose (fast so_t * sop){    fast    tcpsv_t * svp;    int     err = 0;    use_critical;    critical;    trace0(tcp_trace, "tcpclose:\n");    if ((svp = sop->so_svp) == (tcpsv_t *)0) {        /* state vector is already gone. Should not be an error */        goto out;    }    trace1(tcp_tstate, "tcpclose: close(%s)\n", ipa2str(&svp->sv_src, (char *)0));    sv_bind(svp, tcpclose, true);    trace2(tcp_tclose, "tcpclose: [%d] state = %s\n", sop->so_index, tcp_st(svp->sv_state));    switch (svp->sv_state) {      case CLOSED:kludge_o:;        /* fake a non-closed state, so the close can occur */        set_state("tcpclose", svp, LISTEN);        err = FNS_ENOTCONN;        goto rslf;      case LISTEN:      case SYN_SENT:        err = AB_UC;rslf:           tcp_rslf(svp, err);     /* Reset self changes state to CLOSED */        break;      case ESTAB:#ifdef TCP_KEEP_ALIVE        /* we are closing and don't need Keep-Alive any more */        if (so_keepalive(sop)) {            /* if the socket is with Keep-Alive option set */            tcp_end_ka(svp);        }#endif      case SYN_RECVD:      case CLOSE_WAIT:#ifndef TCP_TRANSACTION_TCP		tcp_sfin(svp);  /* state changes in 'tcp_sfin' */#else		tcp_sfin(svp,true);  /* state changes in 'tcp_sfin' */#endif /* TCP_TRANSACTION_TCP */        if ( svp->sv_state == CLOSED )             goto kludge_o;        fallthru;      case CLOSING:   /* Connection closing */      case FIN1_WAIT: /*      "       "     */      case FIN2_WAIT: /*      "       "     */      case LAST_ACK:  /*      "       "     */      case TIME_WAIT: /*      "       "     */        /* state is FIN1_WAIT, LAST_ACK, FIN2_WAIT, CLOSING or TIME_WAIT */        sop = sv_valid_sop(svp, sop);        assert(sop != (so_t *)0, "tcpclose: 0 sop\n");        if (sop->so_rq.gq_cnt == 0  &&  q_empty(&sop->so_hq.gq_q)) {#ifdef TCP_TRANSACTION_TCPkludge_oo:;#endif            gq_smoke(&sop->so_hq);  /* shutdown the receive queues */            gq_smoke(&sop->so_rq);            so_notify(sop, RSHUTDOWN_NOTIFY);        } else {#ifdef TCP_TRANSACTION_TCP			/* If this is a transaction TCP session and we are in the TIME_WAIT			   state, we don't want to do an abort (causing a "reset" to be sent),			   even though there is still something in the receive queue,			   because:			      1) We observe that FreeBSD's t/tcp client doesn't send a reset				     under this circumstance, and;				  2) Applications don't normally close before they know they've 				     read all of the incoming data -- they are not robust 					 applications if they behave this way (i.e., the lack of a reset					 perhaps leading the peer application to think the transaction					 completed is an application-layer bug, not a TCP protocol 					 violation). 			*/			if ( (svp->sv_t_tcp_flags & SV_TRANSACTION) &&				(svp->sv_state == TIME_WAIT) ) {                goto kludge_oo;			}#endif            tcpabort(svp, AB_UC);   /* abort if receive-data exists --			                           this causes a TCP reset to be sent */		}        /* state is FIN1_WAIT, LAST_ACK, FIN2_WAIT, CLOSING,         * TIME_WAIT or CLOSED */        sop = sv_valid_sop(svp, sop);        if (sop != (so_t *)0)            /* the socket and state vector part company */            sv_so_detach(svp);/* Notes on the conditions of the various states after 'closing' *      FIN1_WAIT : Normally we can receive data in this state, but since we *              now no-longer have a socket, we must abort if any new data *              is received.  We are expecting the ACK of our FIN as well as *              the FIN of the remote TCP.  We must time-out and abort if *              our FIN is not ACKED within the normal timeout period. *      FIN2_WAIT : We were in the FIN1_WAIT state, except that our FIN has *              been ACKED.  Since we cannot accept new data in this state, *              nor are we going to generate any new data packets or FINs, *              we must time-out after a reasonable amount of time, so that *              this state vector does not hang about forever if the remote *              side fails to send the expected FIN. *      CLOSING :  We were in the FIN1_WAIT state, and we have just received *              the FIN from the remote TCP, and ACKED that FIN.  We are still *              expecting the ACK of our FIN, and as in the FIN1_WAIT state, *              we must time-out and abort if our FIN is not ACKED within the *              normal timeout period. *      TIME_WAIT :  Our FIN has been ACKED, and we have ACKED the remote *              TCP's FIN.  We are waiting in this state for two maximum *              segment lifetimes to pick up any straggler-packets, or a *              retransmission of the remote TCP's FIN in case our ACK was lost. *      LAST_ACK :  We were in the CLOSE_WAIT state, and have already seen *              and ACKED the remote TCP's FIN, and sent off our FIN.  We *              are waiting for the ACK of our FIN before going on to the *              CLOSED state.  We must time-out and abort if our FIN is not *              ACKED within the normal timeout period. */        if (svp->sv_state == FIN2_WAIT) {       /* see note above */            svp->sv_abort = 1;      /* start FIN2_WAIT timeout */            (void) t_start(svp->sv_rextcb, (u32)TWOMSL);        }        break;    }    sv_detach(svp, tcpclose, true);out:    normal;    return err;}/*******************************************************************//* "inner connect" processing. Called for either explicit connects *//* or implied (via tcp_send) connects                              *//*  Was originally inline with tcp_connect.                        */export int tcp_connect_inner(so_t *sop, saddr *to, int tolen, tcpsv_t **svpp){ tcpsv_t *svp; int     err; auto    so_addr addr; use_critical; trace0(tcp_trace, "tcp_connect_inner:\n");#ifdef TCP_QUIET /* If TCP is in its quiet period after systm bootup,     don't allow the connection */ if (tcp_quiet) {	 return(FNS_ENETDOWN); }#endif  critical; if ((svp = sop->so_svp) == (tcpsv_t *) 0) {  /* no state vector */     debug0(tcp_debug, "tcp_connect: no state vector\n");     normal;     return FNS_ENOTCONN; } /* if */ *svpp = svp; sv_bind(svp, tcp_connect_inner, true); normal; trace3(tcp_trace, "tcp_connect state %x ref_cnt %x abort %x\n", svp->sv_state, svp->sv_refcnt, svp->sv_abort);  if ( (err = svp->sv_err) != 0) {    /* Connect failed (when sv_err is set, sv_state is set to CLOSED) */        goto i_out;    } else {		switch (svp->sv_state) {		   case CLOSED: break; /* This is the normal case */		   case ESTAB: err = FNS_EALREADY; goto i_out;           case LISTEN: err = FNS_EINVAL; goto i_out;		   default:                   /* Still trying to connect. Let the user know about it */			   if (give_bs(sop->so_flags) == F_NONBLOCKING) {			      err = FNS_EALREADY; 			   } else {				   /* MBM note: I don't think this case can be hit because

⌨️ 快捷键说明

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