📄 tcp-full.cc
字号:
} else { flags_ |= TF_ACKNOW; // ACK peer's SYN } /* * Received <SYN,ACK> in SYN_SENT[*] state. * Transitions: * SYN_SENT --> ESTABLISHED * SYN_SENT* --> FIN_WAIT_1 */ if (flags_ & TF_NEEDFIN) { newstate(TCPS_FIN_WAIT_1); flags_ &= ~TF_NEEDFIN; tiflags &= ~TH_SYN; } else { newstate(TCPS_ESTABLISHED); } // special to ns: // generate pure ACK here. // this simulates the ordinary connection establishment // where the ACK of the peer's SYN+ACK contains // no data. This is typically caused by the way // the connect() socket call works in which the // entire 3-way handshake occurs prior to the app // being able to issue a write() [which actually // causes the segment to be sent]. sendpacket(t_seqno_, rcv_nxt_, TH_ACK, 0, 0); } else { // Check ECN-SYN packet if (ecn_ && fh->ecnecho() && fh->cong_action()) ect_ = TRUE; // SYN (no ACK) (simultaneous active opens) flags_ |= TF_ACKNOW; cancel_rtx_timer(); newstate(TCPS_SYN_RECEIVED); /* * decrement t_seqno_: we are sending a * 2nd SYN (this time in the form of a * SYN+ACK, so t_seqno_ will have been * advanced to 2... reduce this */ t_seqno_--; // CHECKME }trimthenstep6: /* * advance the seq# to correspond to first data byte */ tcph->seqno()++; if (tiflags & TH_ACK) goto process_ACK; goto step6; case TCPS_LAST_ACK: /* * The only way we're in LAST_ACK is if we've already * received a FIN, so ignore all retranmitted FINS. * -M. Weigle 7/23/02 */ if (tiflags & TH_FIN) { goto drop; } break; case TCPS_CLOSING: break; } /* end switch(state_) */ /* * States other than LISTEN or SYN_SENT. * First check timestamp, if present. * Then check that at least some bytes of segment are within * receive window. If segment begins before rcv_nxt, * drop leading data (and SYN); if nothing left, just ack. * * RFC 1323 PAWS: If we have a timestamp reply on this segment * and it's less than ts_recent, drop it. */ if (ts_option_ && !fh->no_ts_ && recent_ && tcph->ts() < recent_) { if ((now() - recent_age_) > TCP_PAWS_IDLE) { /* * this is basically impossible in the simulator, * but here it is... */ /* * Invalidate ts_recent. If this segment updates * ts_recent, the age will be reset later and ts_recent * will get a valid value. If it does not, setting * ts_recent to zero will at least satisfy the * requirement that zero be placed in the timestamp * echo reply when ts_recent isn't valid. The * age isn't reset until we get a valid ts_recent * because we don't want out-of-order segments to be * dropped when ts_recent is old. */ recent_ = 0.0; } else { fprintf(stderr, "%f: FullTcpAgent(%s): dropped pkt due to bad ts\n", now(), name()); goto dropafterack; } } // check for redundant data at head/tail of segment // note that the 4.4bsd [Net/3] code has // a bug here which can cause us to ignore the // perfectly good ACKs on duplicate segments. The // fix is described in (Stevens, Vol2, p. 959-960). // This code is based on that correction. // // In addition, it has a modification so that duplicate segments // with dup acks don't trigger a fast retransmit when dupseg_fix_ // is enabled. // // Yet one more modification: make sure that if the received // segment had datalen=0 and wasn't a SYN or FIN that // we don't turn on the ACKNOW status bit. If we were to // allow ACKNOW to be turned on, normal pure ACKs that happen // to have seq #s below rcv_nxt can trigger an ACK war by // forcing us to ACK the pure ACKs // // Update: if we have a dataless FIN, don't really want to // do anything with it. In particular, would like to // avoid ACKing an incoming FIN+ACK while in CLOSING // todrop = rcv_nxt_ - tcph->seqno(); // how much overlap? if (todrop > 0 && ((tiflags & (TH_SYN)) || datalen > 0)) {//printf("%f(%s): trim 1..todrop:%d, dlen:%d\n",now(), name(), todrop, datalen); if (tiflags & TH_SYN) { tiflags &= ~TH_SYN; tcph->seqno()++; th->size()--; // XXX Must decrease packet size too!! // Q: Why?.. this is only a SYN todrop--; } // // see Stevens, vol 2, p. 960 for this check; // this check is to see if we are dropping // more than this segment (i.e. the whole pkt + a FIN), // or just the whole packet (no FIN) // if ((todrop > datalen) || (todrop == datalen && ((tiflags & TH_FIN) == 0))) {//printf("%f(%s): trim 2..todrop:%d, dlen:%d\n",now(), name(), todrop, datalen); /* * Any valid FIN must be to the left of the window. * At this point the FIN must be a duplicate or out * of sequence; drop it. */ tiflags &= ~TH_FIN; /* * Send an ACK to resynchronize and drop any data. * But keep on processing for RST or ACK. */ flags_ |= TF_ACKNOW; todrop = datalen; dupseg = TRUE; // *completely* duplicate } /* * Trim duplicate data from the front of the packet */ tcph->seqno() += todrop; th->size() -= todrop; // XXX Must decrease size too!! // why? [kf]..prob when put in RQ datalen -= todrop; } /* data trim */ /* * If we are doing timstamps and this packet has one, and * If last ACK falls within this segment's sequence numbers, * record the timestamp. * See RFC1323 (now RFC1323 bis) */ if (ts_option_ && !fh->no_ts_ && tcph->seqno() <= last_ack_sent_) { /* * this is the case where the ts value is newer than * the last one we've seen, and the seq # is the one we expect * [seqno == last_ack_sent_] or older */ recent_age_ = now(); recent_ = tcph->ts(); } if (tiflags & TH_SYN) { fprintf(stderr, "%f: FullTcpAgent::recv(%s) received unexpected SYN (state:%d): ", now(), name(), state_); prpkt(pkt); goto dropwithreset; } if ((tiflags & TH_ACK) == 0) { /* * Added check for state != SYN_RECEIVED. We will receive a * duplicate SYN in SYN_RECEIVED when our SYN/ACK was dropped. * We should just ignore the duplicate SYN (our timeout for * resending the SYN/ACK is about the same as the client's * timeout for resending the SYN), but give no error message. * -M. Weigle 07/24/01 */ if (state_ != TCPS_SYN_RECEIVED) { fprintf(stderr, "%f: FullTcpAgent::recv(%s) got packet lacking ACK (state:%d): ", now(), name(), state_); prpkt(pkt); goto drop; } } /* * Ack processing. */ switch (state_) { case TCPS_SYN_RECEIVED: /* want ACK for our SYN+ACK */ if (ackno < highest_ack_ || ackno > maxseq_) { // not in useful range fprintf(stderr, "%f: FullTcpAgent(%s): ack(%d) not in range while in SYN_RECEIVED: ", now(), name(), ackno); prpkt(pkt); goto dropwithreset; } /* * Make transitions: * SYN-RECEIVED -> ESTABLISHED * SYN-RECEIVED* -> FIN-WAIT-1 */ if (flags_ & TF_NEEDFIN) { newstate(TCPS_FIN_WAIT_1); flags_ &= ~TF_NEEDFIN; } else { newstate(TCPS_ESTABLISHED); } cwnd_ = initial_window(); /* fall into ... */ /* * In ESTABLISHED state: drop duplicate ACKs; ACK out of range * ACKs. If the ack is in the range * tp->snd_una < ti->ti_ack <= tp->snd_max * then advance tp->snd_una to ti->ti_ack and drop * data from the retransmission queue. * * note that state TIME_WAIT isn't used * in the simulator */ case TCPS_ESTABLISHED: case TCPS_FIN_WAIT_1: case TCPS_FIN_WAIT_2: case TCPS_CLOSE_WAIT: case TCPS_CLOSING: case TCPS_LAST_ACK: // // look for ECNs in ACKs, react as necessary // if (fh->ecnecho() && (!ecn_ || !ect_)) { fprintf(stderr, "%f: FullTcp(%s): warning, recvd ecnecho but I am not ECN capable!\n", now(), name()); } // // generate a stream of ecnecho bits until we see a true // cong_action bit // if (ecn_) { if (fh->ce() && fh->ect()) recent_ce_ = TRUE; else if (fh->cwr()) recent_ce_ = FALSE; } // // If ESTABLISHED or starting to close, process SACKS // if (state_ >= TCPS_ESTABLISHED && tcph->sa_length() > 0) { process_sack(tcph); } // // ACK indicates packet left the network // try not to be fooled by data // if (fastrecov_ && (datalen == 0 || ackno > highest_ack_)) pipe_ -= maxseg_; // look for dup ACKs (dup ack numbers, no data) // // do fast retransmit/recovery if at/past thresh if (ackno <= highest_ack_) { // a pure ACK which doesn't advance highest_ack_ if (datalen == 0 && (!dupseg_fix_ || !dupseg)) { /* * If we have outstanding data * this is a completely * duplicate ack, * the ack is the biggest we've * seen and we've seen exactly our rexmt * threshhold of them, assume a packet * has been dropped and retransmit it. * * We know we're losing at the current * window size so do congestion avoidance. * * Dup acks mean that packets have left the * network (they're now cached at the receiver) * so bump cwnd by the amount in the receiver * to keep a constant cwnd packets in the * network. */ if ((rtx_timer_.status() != TIMER_PENDING) || ackno < highest_ack_) { // Q: significance of timer not pending? // ACK below highest_ack_ oldack(); } else if (++dupacks_ == tcprexmtthresh_) { // ACK at highest_ack_ AND meets threshold //trace_event("FAST_RECOVERY"); dupack_action(); // maybe fast rexmt goto drop; } else if (dupacks_ > tcprexmtthresh_) { // ACK at highest_ack_ AND above threshole //trace_event("FAST_RECOVERY"); extra_ack(); // send whatever window allows send_much(0, REASON_DUPACK, maxburst_); goto drop; } } else { // non zero-length [dataful] segment // with a dup ack (normal for dataful segs) // (or window changed in real TCP). if (dupack_reset_) { dupacks_ = 0; fastrecov_ = FALSE; } } break; /* take us to "step6" */ } /* end of dup/old acks */ /* * we've finished the fast retransmit/recovery period * (i.e. received an ACK which advances highest_ack_) * The ACK may be "good" or "partial" */process_ACK: if (ackno > maxseq_) { // ack more than we sent(!?) fprintf(stderr, "%f: FullTcpAgent::recv(%s) too-big ACK (maxseq:%d): ", now(), name(), int(maxseq_)); prpkt(pkt); goto dropafterack; } /* * If we have a timestamp reply, update smoothed * round trip time. If no timestamp is present but * transmit timer is running and timed sequence * number was acked, update smoothed round trip time. * Since we now have an rtt measurement, cancel the * timer backoff (cf., Phil Karn's retransmit alg.). * Recompute the initial retransmit timer. * * If all outstanding data is acked, stop retransmit * If there is more data to be acked, restart retransmit * timer, using current (possibly backed-off) value. */ newack(pkt); // handle timers, update highest_ack_ /* * if this is a partial ACK, invoke whatever we should * note that newack() must be called before the action * functions, as some of them depend on side-effects * of newack() */ int partial = pack(pkt); if (partial) pack_action(pkt); else ack_action(pkt); /* * if this is an ACK with an ECN indication, handle this * but not if it is a syn packet */ if (fh->ecnecho() && !(tiflags&TH_SYN) ) if (fh->ecnecho()) { // Note from Sally: In one-way TCP, // ecn() is called before newack()... ecn(highest_ack_); // updated by newack(), above // "set_rtx_timer();" from T. Kelly. if (cwnd_ < 1) set_rtx_timer(); } // CHECKME: handling of rtx timer if (ackno == maxseq_) { needoutput = TRUE; } /* * If no data (only SYN) was ACK'd, * skip rest of ACK processing. */ if (ackno == (highest_ack_ + 1)) goto step6; // if we are delaying initial cwnd growth (probably due to // large initial windows), then only open cwnd if data has // been received // Q: check whe
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -