📄 tcpsend.c
字号:
OS_MOVE_N(nmp->m_tp, dp, i2); nmp->m_tp += i2; i1 -= i2; if ((dp += i2) == mp->m_tp) { mp = (m *)mp->m_q.q_next; dp = mp->m_hp; } } /* while */ /* If there is no more data left in the transmit queue then, as discussed above, nsend be zero. Then if we want to send a FIN we can put it in this segment with the last data that is being sent. Note that at this time not all of the data may have been acknowledged, but that is OK since the receiver SHOULDN'T process our FIN until he has acknowledged all the data. */ if (nsend == 0L && finflg) { assert((sop == (so_t *)0) || is_header(&mp->m_q), "tcp_sqxmit: early FIN\n"); flags |= PSH|FIN; /* always PuSH the FIN */ svp->sv_flags |= SV_SFINFLG; /* sent it */ } /* attach TCP header */ tcphp = M_HPTR(nmp, TCPH_T, SIZEOF_TCPH_T); /* ML: initialize tcph_urgent to 0.*/ HostToNet16(&tcphp[TCPH_URGENT], 0); nmp->m_cp = (char *)tcphp; if (MU32(svp->sv_rnxt) || svp->sv_state > SYN_SENT) { flags |= ACK; /* ACK */ tcp_clr_ack(svp); /* piggy-backed ACK */ /* The receive window will get set later on in tcp_dink */ } else { /* no ACK */ HostToNet16(&tcphp[TCPH_WINDOW], 0); } /* If this segment contains the final data presently in the send queue, set the PUSH flag */ /* MBM note: not sure if this logic is completely correct -- I think the use of "nsend: functions differently here than in previous releases, and may need to check against something else */ if (SYN_OFF(flags) && nsend == 0L) { /* no SYN and last packet out */ flags |= PSH; /* PuSH */ } /* If we have urgent data in the send queue beyond the beginning sequence number of this packet, set the urgent flag and the urgent pointer */ if ( SYN_OFF(flags) ) { if ( MC32U(svp->sv_surg, <=, seqno) ) { /* no urgent data */ HostToNet16(&tcphp[TCPH_URGENT], 0); /* cosmetic packet */ } else { /* urgent data */ trace0(tcp_turgent, "tcp_sqxmit: sending an URGENT data packet\n"); flags |= URG; HostToNet16(&tcphp[TCPH_URGENT], (u16)M32U(svp->sv_surg, -, seqno)); } } HostToNet16(&tcphp[TCPH_FLAGS], (u16)(flags | ( (SIZEOF_TCPH_T + seg_optsize) << 10) ) ); HostToNet32(&tcphp[TCPH_SEQNO], seqno); HostToNet32(&tcphp[TCPH_ACKNO], MU32(svp->sv_rnxt)); /* Now check to see if round-trip-timing can be started. Dont do it for retransmitted segments */ if (retransmitting) { INC_MIB_CNTR_TCP_RETRANS_SEGS } else {#ifdef TCP_RTTM /* If we are using the RFC 1323 method of round-trip-time measurement, we we don't need to do anything here -- its all done on the receive side using timestamps on segments */ if (!RTTM_USING_RFC1323(svp)) {#endif /* Don't start a measurement if we're already in the midst of one */ if (!(svp->sv_flags & SV_XTIME)) { /* we can start a RTTM measurement */ svp->sv_flags |= SV_XTIME; /* go into in-progress state */ svp->sv_trtt = TCP_CURRENT_HRES_TIME; /* sample time */ M32U(svp->sv_brtt, =, seqno); /* remember this seq number */ } /* if */#ifdef TCP_RTTM } /* if */#endif } if (svp->sv_swnd || svp->sv_state < ESTAB) { u32 delay; /* value for retransmission delay timer */ /* update, if there really was a send window */ seqno += tcp_dl(nmp); if (UC32M(seqno, >, svp->sv_spsh)) { M32U(svp->sv_spsh, =, seqno); }#ifdef TCP_RETRANSMIT_ENHANCEMENTS /* If we are retransmitting, remember the final sequence number of the segment were are retransmitting */ if (retransmitting) { M32U(svp->sv_rexmt_seqno, =, seqno); } /* if */#endif /* TCP_RETRANSMIT_ENHANCEMENTS */ assert(MC32M(svp->sv_spsh, <=, svp->sv_snxt), "tcp_sqxmit: [2] spsh too big\n"); if (svp->sv_retrtim == 0L) { assert(SYN_ON(flags), "tcp_sqxmit: 0 rtt w/o SYN\n"); /* prior to getting the first datagram routed out, * default the retransmission timer */ delay = svp->sv_initretrim; } else { /* Retransmission timer is double the measured round trip time. Prevents over-eager retransmission */ delay = svp->sv_retrtim; } /* special error function during connection * attempt to abort early if datagrams don't * get out of this host */ if (SYN_ON(flags)) { nmp->m_dispfn = tcp_sqconndispfn; } if (svp->sv_abort == 0) { /* start connection time-out */ svp->sv_abort = (int)tcp_try_max; } else { i1 = (int)tcp_try_max - (int)svp->sv_abort; if (SYN_ON(flags)) { /* we're not having much luck yet; alternate * doubling the delay with encouraging * the router to try different routes */ if (i1 & 1) { /* try successively larger * retransmission values */ if ((svp->sv_srtt <<= 1) > TWOMSL) { svp->sv_srtt = TWOMSL; } /* MBM NOTE: The following removed from Fusion 6.0 -- seems no good reason for it. The peer's retransmit timer backoff should take care of this, if it is retransmitting too quickly. Furthermore, we now have a configureable (via socket option) ack delay time. */#ifdef NEED_ADJUST_ACK_DELAY /* Note from MBM: This line of code has the effect of moving the ack delay timer 1/8 of the distance from its present value to the value being passed in (4 times the current value of the smooth round trip timer), bound by the configured minimum and maximum limits on the ack timer for this connection. I'm not sure what the rationale for doing this is (during a troubled attempt to establish a connection) but I left this line unchanged when implementing configureable delayed ack values */ tcp_adjust_ack_delay(svp, svp->sv_srtt >> 2);#endif if (sop) { i1 = ipsu.ipsu_ttl << 1; ipsu.ipsu_ttl = (u8)(bound(i1, ipsu.ipsu_mnttl, ipsu.ipsu_mxttl)); } /* if */ } else { /* try to encourage rerouting */ nmp->m_pflags |= MSG_REXMIT; } /* if i1 & 1 */ } else if (i1 > 2) { /* notify lower layers that we're * struggling; in particular, this * encourages the routing logic to * try alternatives; perhaps the * network topology is changing */ nmp->m_pflags |= MSG_REXMIT; /* we want to pop a few retransmissions * out at what we presume is the correct * rate, this to deal with packet loss; * after that, we will try progressively * longer delays */ if (i1 > 14) { i1 = 14; } /* if */ if ((delay <<= (i1 - 2)) > TWOMSL) { delay = TWOMSL; } /* if */ } } /* Only restart ack timer if not already running * since otherwise will just keep resetting it * and prevent us from detecting a packet loss */ if ( t_stopped( svp->sv_rextcb ) ) { (void) t_start(svp->sv_rextcb, delay); } } else { /* now that we've probed once quickly (to ensure against loss), * only retry every 2 minutes (PROBE_REX_INTERVAL) UNTIL the * window opens up */ svp->sv_abort = 0; (void) t_start(svp->sv_rextcb, PROBE_REX_DELAY); svp->sv_flags |= SV_NOPROBE; } } /*SEND*/ nmp->m_src.a_len = sizeof(ipa); nmp->m_src.a_type = AF_INET; stass(nmp->m_src.a_ipa, svp->sv_src); nmp->m_dest.a_len = sizeof(ipa); nmp->m_dest.a_type = AF_INET; stass( nmp->m_dest.a_ipa, svp->sv_dest);#ifdef M_HISTORY smfhist(nmp, tcp_sqxmit);#endif#ifdef FAST_REXMT_DEBUG if (!retransmitting) { if (entered_with_rip_flag_set) { os_printf("\n(%d) (i=%d)entered with SV_RIP, sending non-rexmit seqno %u, suna=%u\n", t_time,iter_ctr,seqno,MU32(svp->sv_suna)); } }#endif if (retransmitting) {#ifndef TCP_RETRANSMIT_ENHANCEMENTS /* Without the retransmit improvements, if we retransmit a frame thats all we do, then get out. With the improvements, we go thru the logic again to see if we either can retransmit another frame and/or (if the window permits) send some new data. */ loop_again = false;#else#if ( defined(TCP_SS_CA_FRETR_FREC) && defined(TCP_SELACK_ENHANCEMENTS) ) if ( !(svp->sv_flags2 & (SV_FAST_RETR_RECOV | SV_SLOW_START_CA | SV_PERMIT_IN_SACKS) ) ) {#elif (defined(TCP_SS_CA_FRETR_FREC) ) if ( !(svp->sv_flags2 & (SV_FAST_RETR_RECOV | SV_SLOW_START_CA) ) ) { loop_again = false;#elif (defined (TCP_SELACK_ENHANCEMENTS ) ) if (!(svp->sv_flags2 & SV_PERMIT_IN_SACKS) ) { #endif loop_again = false; }#endif /* TCP_RETRANSMIT_ENHANCEMENTS */ } /* Set the send flag to prevent other senders (usually due to an ACK * received during the time interrupts are enabled); we must make a * final look at send variables to avoid sending out-of-order (but only if we are indeed going to be cycling thru again) */ if (loop_again) svp->sv_flags |= SV_SENDING; #ifdef TRACE_SQXMIT { int ll = tcp_dl(nmp); u32 sq = (seqno - ll ); sctr++;#ifdef TCP_RETRANSMIT_ENHANCEMENTS#ifdef TCP_SS_CA_FRETR_FREC os_printf("\n(%d)(%d) sq=%u,l=%d,suna=%u,surg=%u,cwnd=%u,swnd=%d %c (%d)", sctr,local_inv_ctr,sq,ll,MU32(svp->sv_suna), MU32(svp->sv_surg), svp->sv_cwnd,svp->sv_swnd, (retransmitting ? 'R' : ' '),t_time);#else os_printf("\n(%d)(%d) sq=%u,l=%d,suna=%u,surg=%u,swnd=%d %c (%d)", sctr,local_inv_ctr,sq,ll,MU32(svp->sv_suna), MU32(svp->sv_surg), svp->sv_swnd, (retransmitting ? 'R' : ' '),t_time);#endif#else os_printf("\n(%d)(%d) sq=%u,l=%d,suna=%u,surg=%uswnd=%d, %c (%d)", sctr,local_inv_ctr,sq,ll,MU32(svp->sv_suna), MU32(svp->sv_surg), svp->sv_swnd, (retransmitting ? 'R' : ' '),t_time);#endif /* TCP_SS_CA_FRETR_FREC */ }#endif /* TRACE_SQXMIT */#ifdef TCP_RETRANSMIT_ENHANCEMENTS if (retransmitting) { tcp_retransmit_fsm(svp,TCP_RETR_SEG_RETRANSMITTED); }#endif /* now restore interrupt state to send the packet; this allows * overlap between the transmission and liberation of packets * and generation of subsequent ones, relieving heap congestion */ normal; trace0(tcp_tsqxmit, "tcp_sqxmit: transmit\n"); (void)msm(nmp, tcp_xmit); /* go back for more; we must go back through all the stuff at the * top since things may have changed while the interrupts were on */ /* Except that, if we retransmitted a segment, we don't go back */ /* That is, unless we have the fast-retransmit code in place */ if (loop_again){ goto top;} svp->sv_flags &= ~SV_SENDING; return;}
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -