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

📄 tcpsend.c

📁 用于嵌入式系统的TCP/IP协议栈及若干服务
💻 C
📖 第 1 页 / 共 4 页
字号:
#ifndef TCP_RETRANSMIT_ENHANCEMENTS        seqno = MU32(svp->sv_suna);#else        seqno = MU32(svp->sv_rexmt_seqno);#endif        /* calculate the amount of data that could be sent, up         * to one maximum segment */        nsend = M32U(svp->sv_snxt, -, seqno);#ifdef TCP_RETRANSMIT_ENHANCEMENTS 	    nsend = min( ((int) svp->sv_rexmt_gaplen), nsend); #endif /* TCP_RETRANSMIT_ENHANCEMENTS */        if (svp->sv_mss  &&  nsend > svp->sv_mss) {            nsend = svp->sv_mss;    /* just one segment */		} /* if */#ifdef FAST_REXMT_DEBUG        os_printf("(%d) tcp_sqxmit: retransmitting sequence # %u, suna=%u\n",			           t_time, seqno,MU32(svp->sv_suna));#endif	} else { /* not retransmitting */        seqno = MU32(svp->sv_spsh);     /* transmit all new data */        nsend = M32U(svp->sv_snxt, -, seqno); /* initialize at all not-yet-sent data */        if (nmp == (m *)0  &&  MC32M(svp->sv_surg, !=, svp->sv_suna)) {            if (UC32M(seqno, >=, svp->sv_surg)) {                /* past the urgent pointer; include the last                 * URGENT byte (notification purposes) */                seqno = MU32(svp->sv_surg) - 1;			}         } else if (nsend  != 0) { /* There is some not-yet-sent data */			/* We never want to send more than an MSS-worth of data in a single 			   segment, if the MSS is known yet at this point */			if ( (svp->sv_mss) && (nsend > svp->sv_mss) ) {				nsend = svp->sv_mss;			}            /* At this point, "nsend" is the lesser of the mss or the amount of			   unsent data in the send buffer. Normally we want to delay sending			   segments less than a full MSS in size (Nagle algorithm). Before			   applying the Nagle algorithm, check various other conditions which			   override the Nagle algorithm. */            if (svp->sv_flags & (SV_TSYNFLG|SV_TFINFLG)) { /* sending a SYN or a FIN */                /* no point in delaying any data now */                skip;#if 0		/* The stuff conditionally uncompiled here is old legacy code that seems		   to be using IP layer options within the TCP layer. These options are only		   intended to set fields within the IP header. They seem to be used here in		   a way that is similar to enabling or disabling the Nagle algorithm via		   the TCP_NODELAY socket option, which was just implemented for Fusion 6.0.		   So I don't think we need to reference here the IP_DELAY/IP_THROUGHPUT		   options any more. Leaving it here for a while conditioned out just in 		   case ...		   */            } else if (svp->sv_tos & IP_DELAY) {                /* ULP has asked to push data as                 * quickly as it comes from ULP, so send                 * whatever is queued */				/* Note from MBM: I'm not sure that this condition should be checked				   here in the TCP layer. But out of caution about removing legacy 				   code that I don't fully understand the intent of, I leave it here				   for now. */                skip;            } else if (!(svp->sv_tos & IP_THROUGHPUT) && MC32U(svp->sv_suna, ==, seqno)) {                /* All data sent has been ACKed. */			    /* ULP has not promised to give data continuously, so since another 				   ACKnowledgment can't be counted upon, send whatever is queued */				/* Note from MBM: I'm not sure that this condition should be checked				   here in the TCP layer. This seems to have the same intent as checking				   whether the Nagle algorithm is disabled (TCP_NODELAY option) but this 				   was written long before that socket option was implemented. 				   But out of caution (timidity) about removing legacy code that I don't 				   fully understand the intent of, I leave it here for now. */                skip;#endif            } else if (svp->sv_mss) {  				/* If we have less than an MSS worth of data to send, and the Nagle				   algorithm is enabled, and there is outstanding un-ACKed data, 				   don't send the data now. */                if ( (nsend < svp->sv_mss) && 					 (!(svp->sv_flags2 & SV_NAGLE_DISABLED)) &&					 (MC32U(svp->sv_suna, !=, seqno)) ) {                     nsend = 0L;                }             } /* if MSS is known */        } /* there is unsent data */    } /* transmitting or not retransmitting */    if (nsend == 0L) { 		/* no data to send, this would just be an ACK */        normal;        return;    } /* if */    trace2(tcp_tsqxmit, "tcp_sqxmit: %s from 0x%x\n", 		      (retransmitting) ? "retransmission" : "new data", 			   seqno);    /* inner block to skip over send queue bytes which are not being     * sent in this packet */    {  /*SKIP*/        fast    i32     nskip, swind;		/* calculate number of bytes to skip */        nskip = U32M(seqno, -, svp->sv_suna);#ifndef TCP_SS_CA_FRETR_FREC         swind = svp->sv_swnd;   /* send window */#else		/* When slow-start/congestion avoidance is enabled, the operational send 		   window is the minimum of the current congestion window and peer-advertised		   receive window. */		if (svp->sv_flags2 & SV_SLOW_START_CA) {           swind = TCP_OPERATIONAL_SEND_WINDOW(svp);   		} else {           swind = svp->sv_swnd;   /* send window */		} /* if-else */#endif        if (swind == 0L) {            if ((svp->sv_flags & SV_NOPROBE) == 0) {            /* closed, allow 1 byte (SYN & window probes) */                swind = 1;			}        }        swind -= nskip; /* calculate # of bytes in win. past skip pnt. */        if (swind <= 0L) {            trace2(tcp_tsqxmit, "tcp_sqxmit: %d skip fills %d window\n", nskip, swind);            /* if the user requested expeditious delivery, and we have             * managed to send the entire window (in whatever mode we're             * currently in), cause an immediate retransmission at the             * next timer tick (user may be pounding on the keyboard,             * and he/she wants to be heard!) */            if ((svp->sv_tos & IP_DELAY)  &&  (t_stopped(svp->sv_rextcb)                ||  t_period(svp->sv_rextcb) > MS_PER_TICK)) {                /* don't interfere with the normal timeout process */                if (svp->sv_abort) {                    ++svp->sv_abort;				}				(void) t_start(svp->sv_rextcb, IMMEDIATE_REX_DELAY);            }            normal;            return;        }        finflg = false;        synflg = false;        if (nsend > swind) {     /* more bytes to send than window allows? */            nsend = swind;  /* reduce to size of window */        } else if ((svp->sv_flags & SV_TFINFLG) && UC32M(seqno + nsend, ==, svp->sv_snxt)) {            finflg = true;            --nsend;        /* not really data */        }        if (svp->sv_flags & SV_TSYNFLG) {		  if (nskip) {                --nskip;        /* gets skipped */          } else {            synflg = true;            --nsend;        /* not really data */          }        }        /* skip over bytes in send queue to the first byte to be sent */        trace1(tcp_tsqxmit, "tcp_sqxmit: skipping %d\n", nskip);        if (sop) {            for (mp = (m *)sop->so_sq.gq_q.q_next; !is_header(&mp->m_q);                 mp = (m *)mp->m_q.q_next) {                if (nskip < (i1 = m_dsize(mp))) {                    dp = mp->m_hp + nskip;  /* partially eaten */                    break;                }                nskip -= i1;    /* fully eaten */			} /* for */        }        trace3(tcp_tsqxmit, "tcp_sqxmit: %d%s%s to send\n", nsend, synflg ? " SYN" : "", finflg ? " FIN" : "" );	}  /*SKIP*/    /* inner block to actually construct the packet beginning at     * 'seqno'; 'mp' is now pointing at the 'm' structure which     * contains 'seqno', and 'dp' points at the byte which is 'seqno' */    {  /*SEND*/        fast    TCPH_T  * tcphp;        fast    int     i2;        fast    u16     flags;        int             hsize;        int     seg_optsize = 0;		u16     seg_which_options;        /* determine the actual packet size; no more than what is really         * there or the maximum packet size */        hsize = (int)nc_hsize;        if (sop) {            hsize += sop->so_hsize;        } else {   /* no socket -- guess */            hsize += IP_MHL + SIZEOF_TCPH_T;		}        /* MBM note: I think at this point, "hsize" has the combined sizes 		   of all protocol headers (link layer/ethernet, IP, and the 		   standard TCP header, not including TCP options. */        /* Determine the length of the part of the segment that follows the standard		   TCP header. This includes the user data plus the length of the TCP options,		   if any. "i1" will contain that value. */        if (synflg) { 		   seg_optsize = tcp_seg_optsize(svp,1,&seg_which_options);#ifdef TCP_TRANSACTION_TCP		   /* For transaction TCP, make sure we don't follow an initial SYN with additional		      segments unless we know that the peer understands transaction TCP. Stevens		      TCP/IP vol 3, section 3.6 */		   if (svp->sv_t_tcp_flags & SV_TRANSACTION) {			    if ( (svp->sv_state == SYN_SENT) && 					 (seg_which_options & TCP_OPT_INCLUDE_CCNEW) ) {					loop_again = false;                }		   }#endif /* TCP_TRANSACTION_TCP */        } else {		   seg_optsize = (svp->sv_mss - svp->sv_mssd);		   seg_which_options = svp->sv_dseg_options;#ifdef TCP_SELACK_ENHANCEMENTS           /* If we need to send a selective ack, adjust the option size according		       to how large that will be. */		   if (svp->sv_flags2 & SV_OUT_SACKS_ENABLED) {		      tcp_selective_ack_needed(svp,&seg_optsize,&seg_which_options);		   } /* if */#endif        }		i1 = min(svp->sv_mss, (nsend + seg_optsize) );				/* if the segment we want to send is mss-sized and the message		   size we need corresponds to that size of segment, see if we		   have any saved from previous usage -- otherwise, allocate one */        nmp = (m *) 0;		if ( M_NEW_ALLOCLEN_FOR_SIZE(hsize + (int)i1) == svp->sv_mss_m_len ) {			if (svp->sv_num_mss_sized_msgs > 0) {				nmp = svp->sv_tcp_mss_sized_msgs[--(svp->sv_num_mss_sized_msgs)];				/* Initialize any necessary fields here that would ordinarily be				   done within m_new, either explicitly or via the MEMSET to 0.				   Only initiaslize those that are necessary.				 */				{  					q_init(&nmp->m_q, F_Q_LOCKED);					q_init(&nmp->m_wq, 0);					q_initparent(&nmp->m_mq, 0, (char *)nmp);					nmp->m_ctime = t_time;				    nmp->m_hp = nmp->m_tp = &((char *)&nmp[1])[hsize + (int)i1];					nmp->m_type = 0;					nmp->m_owners = 1;					nmp->m_outndp = (struct netdev *) 0;					nmp->m_ndp = (struct netdev *) 0;				}			} /* if */		} /* if */        /* If we can't re-use a message, allocate one from the heap */		if (nmp == (m *) 0) {    		trace1(tcp_tsqxmit, "tcp_sqxmit: packet data is %d\n", i1);            /* now try to allocate a reasonable size packet */            while ((nmp = m_new(hsize + (int)i1, (int *)0, (u16)0)) == (m *)0) {                i1 >>= 1;       /* try 1/2 size */                if (i1 < seg_optsize) {                    /* cannot allocate a useful size packet */                    trace0(tcp_tsqxmit, "tcp_sqxmit: m_new failed\n");                    svp->sv_abort = 0;                    (void) t_start(svp->sv_rextcb, HALLOC_REX_DELAY);                    normal;                    return;       /* timer will come back */				}                trace2(tcp_tsqxmit, "tcp_sqxmit: %d was too big, trying %d\n", i1 << 1, i1);			} /* while */            /* bind the message to the state vector */            (void)sv_m_bind(svp, nmp, tcp_sqxmit_termfn);        } /* if */        /* Normally this value would be passed to m_new and within m_new, them_flags		   field would be set to this value. But m_new also uses it to decide whether		   to block until it can allocate a message of the specified size, and TCP		   doesn't want that, because of the "attempt to allocate decreasing sizes		   until we succeed" strategy above. So, we pass a zero to m_new so it won't		   block, and set these flags here instead. */		/* Note: The reason its necessary to set these flags is because, in ip_xmt2,		   if it can't route the packet, it calls smerr, which will record an error		   code in the message for examination by TCP's disposal function, but only		   if the blocking or nonblocking flag is set (the "want_status" macro) */        nmp->m_flags = (u16) give_bs(sop->so_flags);        nmp->m_hp -= i1;        nmp->m_tp = nmp->m_hp;        /* fill the new packet */        flags = 0;        /* attach TCP options */        tcp_construct_seg_options(svp, (char *) m_ptr(nmp,TCPO_T), 			                      seg_optsize, seg_which_options);        i1 -= seg_optsize;        nmp->m_tp += seg_optsize;		if (synflg) {           flags = SYN;           synflg = false; /* consumed the SYN */        } /* if */        /* We started with nsend equal to all of the data in the transmit           queue that has never been sent, i.e., sv_snxt - sv_spsh, then we           see how much we can send based on the MSS or window size, and we           reduce nsend by that amount which we'll use later to see if we           can send a FIN now should we need to.        */        nsend -= i1;        while (i1 > 0L) {			/* take bytes from send queue packets */            assert(!is_header(&mp->m_q), "tcp_sqxmit: tried to send sq header\n");            i2 = (int)(min(mp->m_tp - dp, i1));

⌨️ 快捷键说明

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