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

📄 tcp_output.pc

📁 simulator for ad hoc
💻 PC
📖 第 1 页 / 共 2 页
字号:
     * 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 + -