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

📄 tcp_input.pc

📁 无线自组织网络的一个协议仿真软件
💻 PC
📖 第 1 页 / 共 4 页
字号:
                    tp->t_flags |= TF_DELACK;                 tp->rcv_nxt += ti->ti_len;                 tiflags = ti->ti_flags & TH_FIN;                 submit_data(node, inp->app_proto_type, inp->con_id,                             (unsigned char *)(ti + 1), ti->ti_len, tp);                pc_free(tcp_seg);            } else {                 tiflags = tcp_reass(node, tp, ti, tcp_stat);                 tp->t_flags |= TF_ACKNOW;             }         } else {            if (ti->ti_seq == tp->rcv_nxt &&                 tp->seg_next == (struct tcpiphdr *)tp &&                 tp->t_state == TCPS_ESTABLISHED) {                 tp->t_flags |= TF_DELACK;                 (tp)->rcv_nxt += (ti)->ti_len;                 tiflags = (ti)->ti_flags & TH_FIN;                 submit_data(node, inp->app_proto_type, inp->con_id,                             datap, ti->ti_len, tp);                pc_free(tcp_seg);            } else {                 tiflags = tcp_reass(node, tp, ti, tcp_stat);                 tp->t_flags |= TF_ACKNOW;             }         }        /*         * Note the amount of data that peer has sent into         * our window, in order to estimate the sender's         * buffer size.         */        len = inp->inp_rcv_hiwat - (tp->rcv_adv - tp->rcv_nxt);    } else {        pc_free(tcp_seg);        tiflags &= ~TH_FIN;    }    /*     * If FIN is received ACK the FIN and let the user know     * that the connection is closing.     */    if (tiflags & TH_FIN) {        if (TCPS_HAVERCVDFIN(tp->t_state) == 0) {            /*             *  If connection is half-synchronized             *  (ie NEEDSYN flag on) then delay ACK,             *  so it may be piggybacked when SYN is sent.             *  Otherwise, since we received a FIN then no             *  more input can be expected, send ACK now.             */            if (tp->t_flags & TF_NEEDSYN)                tp->t_flags |= TF_DELACK;            else                tp->t_flags |= TF_ACKNOW;            tp->rcv_nxt++;        }        switch (tp->t_state) {        /*         * In SYN_RECEIVED and ESTABLISHED STATES         * enter the CLOSE_WAIT state.         */        case TCPS_SYN_RECEIVED:        case TCPS_ESTABLISHED:            tp->t_state = TCPS_CLOSE_WAIT;            break;        /*         * If still in FIN_WAIT_1 STATE FIN has not been acked so         * enter the CLOSING state.         */        case TCPS_FIN_WAIT_1:            tp->t_state = TCPS_CLOSING;            break;        /*         * In FIN_WAIT_2 state enter the TIME_WAIT state,         * starting the time-wait timer, turning off the other         * standard timers.         */        case TCPS_FIN_WAIT_2:            tp->t_state = TCPS_TIME_WAIT;            tcp_canceltimers(tp);            tp->t_timer[TCPT_2MSL] = 2 * TCPTV_MSL;            break;        /*         * In TIME_WAIT state restart the 2 MSL time_wait timer.         */        case TCPS_TIME_WAIT:            tp->t_timer[TCPT_2MSL] = 2 * TCPTV_MSL;            break;        }    }    /*     * Return any desired output.     */    if (needoutput || (tp->t_flags & TF_ACKNOW)){        tcp_output(node, tp, tcp_now, tcp_stat);    }    return;dropafterack:    /*     * Generate an ACK dropping incoming segment if it occupies     * sequence space, where the ACK reflects our state.     */    if (tiflags & TH_RST)        goto drop;    tp->t_flags |= TF_ACKNOW;    pc_free(tcp_seg);    tcp_output(node, tp, tcp_now, tcp_stat);    return;dropwithreset:    /*      * ADDED by Ken.  Problem occurs when server already closes connection     * while client is still sending or vice versa.  If this happens,     * tp == NULL.  Just do nothing and return in this case.     */     if (tp == NULL)    {        pc_free(tcp_seg);        return;    }    /*     * Generate a RST, dropping incoming segment.     * Make ACK acceptable to originator of segment.     * Don't bother to respond if destination was broadcast/multicast.     */    if (tiflags & TH_RST)         goto drop;    if (tiflags & TH_ACK){         tcp_respond(node, tp, ti,                    1, (tcp_seq)0, ti->ti_ack,                    TH_RST, tcp_stat);    }       else {        if (tiflags & TH_SYN)            ti->ti_len++;        tcp_respond(node, tp, ti,                    1, ti->ti_seq+ti->ti_len, (tcp_seq)0,                    TH_RST|TH_ACK, tcp_stat);    }    pc_free(tcp_seg);    return;drop:    /*     * Drop space held by incoming segment and return.     */    pc_free(tcp_seg);    return;}static voidtcp_dooptions(tp, cp, cnt, ti, topt, tcp_now, tcp_stat)    struct tcpcb *tp;    unsigned char *cp;    int cnt;    struct tcpiphdr *ti;    struct tcpopt *topt;    unsigned long tcp_now;    struct tcpstat *tcp_stat;{    unsigned short mss = 0;    int opt, optlen;    unsigned char *optp = cp;    unsigned char *datap = cp + cnt;    if (cnt==0) return;    for (; cnt > 0; cnt -= optlen, cp += optlen) {        opt = cp[0];        if (opt == TCPOPT_EOL)            break;        if (opt == TCPOPT_NOP)            optlen = 1;        else {            optlen = cp[1];            if (optlen <= 0)                break;        }        switch (opt) {        default:            continue;        case TCPOPT_MAXSEG:            if (optlen != TCPOLEN_MAXSEG)                continue;            if (!(ti->ti_flags & TH_SYN))                continue;            memcpy((char *) &mss, (char *) cp + 2, sizeof(mss));            break;        case TCPOPT_WINDOW:            if (optlen != TCPOLEN_WINDOW)                continue;            if (!(ti->ti_flags & TH_SYN))                continue;            tp->t_flags |= TF_RCVD_SCALE;            tp->requested_s_scale = MIN(cp[2], TCP_MAX_WINSHIFT);            break;        case TCPOPT_TIMESTAMP:            if (optlen != TCPOLEN_TIMESTAMP)                continue;            topt->to_flag |= TOF_TS;            memcpy((char *)&topt->to_tsval,                   (char *)cp + 2, sizeof(topt->to_tsval));            memcpy((char *)&topt->to_tsecr,                   (char *)cp + 6, sizeof(topt->to_tsecr));            /*             * A timestamp received in a SYN makes             * it ok to send timestamp requests and replies.             */            if (ti->ti_flags & TH_SYN) {                tp->t_flags |= TF_RCVD_TSTMP;                tp->ts_recent = topt->to_tsval;                tp->ts_recent_age = tcp_now;            }            break;        }    }    if (ti->ti_flags & TH_SYN)        tcp_mss(tp, mss, tcp_stat);  /* sets t_maxseg */    /* remove options */    memcpy(optp, datap, ti->ti_len);}/* * Collect new round-trip time estimate * and update averages and current timeout. */static voidtcp_xmit_timer(tp, rtt, tcp_stat)    struct tcpcb *tp;    int rtt;    struct tcpstat *tcp_stat;{    int delta;    tp->t_rttupdated++;    if (tp->t_srtt != 0) {        /*         * srtt is stored as fixed point with 5 bits after the         * binary point (i.e., scaled by 8).  The following magic         * is equivalent to the smoothing algorithm in rfc793 with         * an alpha of .875 (srtt = rtt/8 + srtt*7/8 in fixed         * point).  Adjust rtt to origin 0.         */        delta = ((rtt - 1) << TCP_DELTA_SHIFT)            - (tp->t_srtt >> (TCP_RTT_SHIFT - TCP_DELTA_SHIFT));        if ((tp->t_srtt += delta) <= 0)            tp->t_srtt = 1;        /*         * We accumulate a smoothed rtt variance (actually, a         * smoothed mean difference), then set the retransmit         * timer to smoothed rtt + 4 times the smoothed variance.         * rttvar is stored as fixed point with 4 bits after the         * binary point (scaled by 16).  The following is         * equivalent to rfc793 smoothing with an alpha of .75         * (rttvar = rttvar*3/4 + |delta| / 4).  This replaces         * rfc793's wired-in beta.         */        if (delta < 0)            delta = -delta;        delta -= tp->t_rttvar >> (TCP_RTTVAR_SHIFT - TCP_DELTA_SHIFT);        if ((tp->t_rttvar += delta) <= 0)            tp->t_rttvar = 1;    } else {        /*         * No rtt measurement yet - use the unsmoothed rtt.         * Set the variance to half the rtt (so our first         * retransmit happens at 3*rtt).         */        tp->t_srtt = rtt << TCP_RTT_SHIFT;        tp->t_rttvar = rtt << (TCP_RTTVAR_SHIFT - 1);    }    tp->t_rtt = 0;    tp->t_rxtshift = 0;    /*     * the retransmit should happen at rtt + 4 * rttvar.     * Because of the way we do the smoothing, srtt and rttvar     * will each average +1/2 tick of bias.  When we compute     * the retransmit timer, we want 1/2 tick of rounding and     * 1 extra tick because of +-1/2 tick uncertainty in the     * firing of the timer.  The bias will give us exactly the     * 1.5 tick we need.  But, because the bias is     * statistical, we have to test that we don't drop below     * the minimum feasible timer (which is 2 ticks).     */    TCPT_RANGESET(tp->t_rxtcur, TCP_REXMTVAL(tp),                  MAX(tp->t_rttmin, rtt + 2), TCPTV_REXMTMAX);    /*     * We received an ack for a packet that wasn't retransmitted;     * it is probably safe to discard any error indications we've     * received recently.  This isn't quite right, but close enough     * for now (a route might have failed after we sent a segment,     * and the return path might not be symmetrical).     */    tp->t_softerror = 0;    if (tcp_stat)         tcp_stat->tcps_rttupdated++;}/* * Determine a reasonable value for maxseg size. * If the route is known, check route for mtu. * If none, use an mss that can be handled on the outgoing * interface without forcing IP to fragment; if bigger than * an mbuf cluster (MCLBYTES), round down to nearest multiple of MCLBYTES * to utilize large mbufs.  If no route is found, route has no mtu, * or the destination isn't local, use a default, hopefully conservative * size (usually 512 or the default IP max size, but no more than the mtu * of the interface), as we can't discover anything about intervening * gateways or networks.  We also initialize the congestion/slow start * window to be a single segment if the destination isn't local. * While looking at the routing entry, we also initialize other path-dependent * parameters from pre-set or cached values in the routing entry. * * Also take into account the space needed for options that we * send regularly.  Make maxseg shorter by that amount to assure * that we can send maxseg amount of data even when the options * are present.  Store the upper limit of the length of options plus * data in maxopd. * * NOTE that this routine is only called when we process an incoming * segment, for outgoing segments only tcp_mssopt is called. * */static voidtcp_mss(tp, offer, tcp_stat)    struct tcpcb *tp;    int offer;    struct tcpstat *tcp_stat;{    int mss;    unsigned long bufsize;    struct inpcb *inp = tp->t_inpcb;    /*     * Offer == 0 means that there was no MSS on the SYN segment,     * in this case we use TCP_MSS.     */    if (offer == 0)        offer = TCP_MSS;    else        /*         * Sanity check: make sure that maxopd will be large         * enough to allow some data on segments even is the         * all the option space is used (40bytes).  Otherwise         * funny things may happen in tcp_output.         */        offer = MAX(offer, 64);    mss = MIN(tp->t_maxseg, offer);   /*    * If there's a pipesize, change the socket buffer to that size.    * if the mss is larger than the buffer size, derease the mss.    */    bufsize = inp->inp_snd.hiwat;    if (bufsize < mss)        mss = bufsize;    /*     * maxopd stores the maximum length of data AND options     * in a segment; maxseg is the amount of data in a normal     * segment.  We need to store this value (maxopd) apart     * from maxseg, because now every segment carries options     * and thus we normally have somewhat less data in segments.     */    tp->t_maxopd = mss;    if ((tp->t_flags & (TF_REQ_TSTMP|TF_NOOPT)) == TF_REQ_TSTMP &&         (tp->t_flags & TF_RCVD_TSTMP) == TF_RCVD_TSTMP)        mss -= TCPOLEN_TSTAMP_APPA;    tp->t_maxseg = mss;    tp->snd_cwnd = mss;}/* * Determine the MSS option to send on an outgoing SYN. */inttcp_mssopt(){    return TCP_MSS;}/* * Deliver data to application. */static voidsubmit_data(node, app_type, conn_id, datap, length, tp)    GlomoNode *node;    APP_TYPE app_type;    int conn_id;    unsigned char *datap;    int length;    struct tcpcb *tp;{    Message *msg;    TransportToAppDataReceived *tcpDataReceived;    GlomoTransportTcp *tcpLayer = node->transportData.tcp;    if (length > 0) {        msg = GLOMO_MsgAlloc(node, GLOMO_APP_LAYER,                             app_type, MSG_APP_FromTransDataReceived);        GLOMO_MsgInfoAlloc(node, msg, sizeof(TransportToAppDataReceived));        tcpDataReceived = (TransportToAppDataReceived *) msg->info;        tcpDataReceived->connectionId = conn_id;        GLOMO_MsgPacketAlloc(node, msg, length);        memcpy(msg->packet, datap, length);        GLOMO_MsgSend(node, msg, TRANSPORT_DELAY);        tcpLayer->tp = tp;        TransportTcpSetTimerForOutput(node);    }}

⌨️ 快捷键说明

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