📄 tcp_output.pc
字号:
* tp->t_timer[TCPT_REXMT] * is set when we are retransmitting * The output side is idle when both timers are zero. * * If send window is too small, there is data to transmit, and no * retransmit or persist is pending, then go to persist state. * If nothing happens soon, send when timer expires: * if window is nonzero, transmit what we can, * otherwise force out a byte. */ if (inp->inp_snd.cc && tp->t_timer[TCPT_REXMT] == 0 && tp->t_timer[TCPT_PERSIST] == 0) { tp->t_rxtshift = 0; tcp_setpersist(tp); } /* * No reason to send a segment, just return. */ return;send0: /* * Before ESTABLISHED, force sending of initial options * unless TCP set not to do any options. * NOTE: we assume that the IP/TCP header plus TCP options * always fit in a single mbuf, leaving room for a maximum * link header, i.e. * max_linkhdr + sizeof (struct tcpiphdr) + optlen <= MHLEN */ optlen = 0; hdrlen = sizeof (struct tcpiphdr); if (flags & TH_SYN) { tp->snd_nxt = tp->iss; if ((tp->t_flags & TF_NOOPT) == 0) { unsigned short mss; opt[0] = TCPOPT_MAXSEG; opt[1] = TCPOLEN_MAXSEG; mss = (unsigned short) tcp_mssopt(); (void)memcpy(opt + 2, &mss, sizeof(mss)); optlen = TCPOLEN_MAXSEG; if ((tp->t_flags & TF_REQ_SCALE) && ((flags & TH_ACK) == 0 || (tp->t_flags & TF_RCVD_SCALE))) { *((unsigned long *) (opt + optlen)) = ( TCPOPT_NOP << 24 | TCPOPT_WINDOW << 16 | TCPOLEN_WINDOW << 8 | tp->request_r_scale); optlen += 4; } } } /* * Send a timestamp and echo-reply if this is a SYN and our side * wants to use timestamps (TF_REQ_TSTMP is set) or both our side * and our peer have sent timestamps in our SYN's. */ if ((tp->t_flags & (TF_REQ_TSTMP|TF_NOOPT)) == TF_REQ_TSTMP && (flags & TH_RST) == 0 && ((flags & TH_ACK) == 0 || (tp->t_flags & TF_RCVD_TSTMP))) { unsigned long *lp = (unsigned long *)(opt + optlen); /* Form timestamp option as shown in appendix A of RFC 1323. */ *lp++ = TCPOPT_TSTAMP_HDR; *lp++ = tcp_now; *lp = tp->ts_recent; optlen += TCPOLEN_TSTAMP_APPA; } hdrlen += optlen; /* * Adjust data length if insertion of options will * bump the packet length beyond the t_maxseg length. * Clear the FIN bit because we cut off the tail of * the segment. */ if (len + optlen > tp->t_maxseg) { /* * If there is still more to send, don't close the connection. */ flags &= ~TH_FIN; len = tp->t_maxseg - optlen; sendalot = 1; } /* * Create a TCP segment, attaching a copy of data to * be transmitted, and initialize the header from * the template for sends on this connection. */ /* allocate the space for a tcp segment and copy data*/ msg = GLOMO_MsgAlloc(node, 0, 0, 0); GLOMO_MsgPacketAlloc(node, msg, len + hdrlen); tcpseg = (unsigned char *) msg->packet; assert(tcpseg != NULL); if (len) { if (tcp_stat) { if (tp->t_force && len == 1) tcp_stat->tcps_sndprobe++; else if (SEQ_LT(tp->snd_nxt, tp->snd_max)) { tcp_stat->tcps_sndrexmitpack++; tcp_stat->tcps_sndrexmitbyte += len; } else { tcp_stat->tcps_sndpack++; tcp_stat->tcps_sndbyte += len; } } memcpy(tcpseg+hdrlen, (inp->inp_snd.buffer)+off, len); /* * If we're sending everything we've got, set PUSH. * (This will keep happy those implementations which only * give data to the user when a buffer fills or * a PUSH comes in.) */ if (off + len == inp->inp_snd.cc) flags |= TH_PUSH; } else { /* len == 0 */ if (tcp_stat) { if (flags & (TH_SYN|TH_FIN|TH_RST)) tcp_stat->tcps_sndctrl++; else if (tp->t_flags & TF_ACKNOW) tcp_stat->tcps_sndacks++; else if (SEQ_GT(tp->snd_up, tp->snd_una)) tcp_stat->tcps_sndurg++; else tcp_stat->tcps_sndwinup++; } } ti = (struct tcpiphdr *)tcpseg; assert(tp->t_template != 0); (void)memcpy(ti, tp->t_template, sizeof (struct tcpiphdr)); /* * Fill in fields, remembering maximum advertised * window for use in delaying messages about window sizes. * If resending a FIN, be sure not to use a new sequence number. */ if (flags & TH_FIN && tp->t_flags & TF_SENTFIN && tp->snd_nxt == tp->snd_max) tp->snd_nxt--; /* * If we are doing retransmissions, then snd_nxt will * not reflect the first unsent octet. For ACK only * packets, we do not want the sequence number of the * retransmitted packet, we want the sequence number * of the next unsent octet. So, if there is no data * (and no SYN or FIN), use snd_max instead of snd_nxt * when filling in ti_seq. But if we are in persist * state, snd_max might reflect one byte beyond the * right edge of the window, so use snd_nxt in that * case, since we know we aren't doing a retransmission. * (retransmit and persist are mutually exclusive...) */ if (len || (flags & (TH_SYN|TH_FIN)) || tp->t_timer[TCPT_PERSIST]) ti->ti_seq = tp->snd_nxt; else ti->ti_seq = tp->snd_max; ti->ti_ack = tp->rcv_nxt; if (optlen) { memcpy(ti + 1, opt, optlen); ti->ti_off = (sizeof (struct tcphdr) + optlen) >> 2; } ti->ti_flags = flags; /* * Calculate receive window. Don't shrink window, * but avoid silly window syndrome. */ if (win < (long)(inp->inp_rcv_hiwat / 4) && win < (long)tp->t_maxseg) win = 0; if (win > (long)TCP_MAXWIN << tp->rcv_scale) win = (long)TCP_MAXWIN << tp->rcv_scale; if (win < (long)(tp->rcv_adv - tp->rcv_nxt)) win = (long)(tp->rcv_adv - tp->rcv_nxt); ti->ti_win = (unsigned short) (win>>tp->rcv_scale); if (SEQ_GT(tp->snd_up, tp->snd_nxt)) { ti->ti_urp = (unsigned short)(tp->snd_up - tp->snd_nxt); ti->ti_flags |= TH_URG; } else /* * If no urgent pointer to send, then we pull * the urgent pointer to the left edge of the send window * so that it doesn't drift into the send window on sequence * number wraparound. */ tp->snd_up = tp->snd_una; /* drag it along */ /* * Put TCP length in extended header, and then * checksum extended header and data. */ if (len + optlen) { ti->ti_len = (unsigned short)(sizeof (struct tcphdr) + optlen + len); } ti->ti_sum = in_cksum((unsigned short *)tcpseg, (int)(hdrlen + len)); /* * In transmit state, time the transmission and arrange for * the retransmit. In persist state, just set snd_max. */ if (tp->t_force == 0 || tp->t_timer[TCPT_PERSIST] == 0) { tcp_seq startseq = tp->snd_nxt; /* * Advance snd_nxt over sequence space of this segment. */ if (flags & (TH_SYN|TH_FIN)) { if (flags & TH_SYN) tp->snd_nxt++; if (flags & TH_FIN) { tp->snd_nxt++; tp->t_flags |= TF_SENTFIN; } } tp->snd_nxt += len; if (SEQ_GT(tp->snd_nxt, tp->snd_max)) { tp->snd_max = tp->snd_nxt; /* * Time this transmission if not a retransmission and * not currently timing anything. */ if (tp->t_rtt == 0) { tp->t_rtt = 1; tp->t_rtseq = startseq; if (tcp_stat) tcp_stat->tcps_segstimed++; } } /* * Set retransmit timer if not currently set, * and not doing an ack or a keep-alive probe. * Initial value for retransmit timer is smoothed * round-trip time + 2 * round-trip time variance. * Initialize shift counter which is used for backoff * of retransmit time. */ if (tp->t_timer[TCPT_REXMT] == 0 && tp->snd_nxt != tp->snd_una) { tp->t_timer[TCPT_REXMT] = tp->t_rxtcur; if (tp->t_timer[TCPT_PERSIST]) { tp->t_timer[TCPT_PERSIST] = 0; tp->t_rxtshift = 0; } } } else { if (SEQ_GT(tp->snd_nxt + len, tp->snd_max)) { tp->snd_max = tp->snd_nxt + len; } } /* * Send the packet and remove the IP header so that * it can be put back on in IP Layer. * */ { NODE_ADDR destinationAddress = ti->ti_dst; GLOMO_MsgRemoveHeader(node, msg, sizeof(struct ipovly)); NetworkIpReceivePacketFromTransportLayer(node, msg, destinationAddress, priority, IPPROTO_TCP, TRANSPORT_DELAY); } if (tcp_stat) tcp_stat->tcps_sndtotal++; /* * Data sent (as far as we can tell). * If this advertises a larger window than any other segment, * then remember the size of the advertised window. * Any pending ACK has now been sent. */ if (win > 0 && SEQ_GT(tp->rcv_nxt+win, tp->rcv_adv)) tp->rcv_adv = tp->rcv_nxt + win; tp->last_ack_sent = tp->rcv_nxt; tp->t_flags &= ~(TF_ACKNOW|TF_DELACK); if (sendalot) goto again; return;}voidtcp_setpersist(tp) struct tcpcb *tp;{ int t = ((tp->t_srtt >> 2) + tp->t_rttvar) >> 1; assert(tp->t_timer[TCPT_REXMT] == 0); /* * Start/restart persistance timer. */ TCPT_RANGESET(tp->t_timer[TCPT_PERSIST], t * tcp_backoff[tp->t_rxtshift], TCPTV_PERSMIN, TCPTV_PERSMAX); if (tp->t_rxtshift < TCP_MAXRXTSHIFT) tp->t_rxtshift++;}
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -