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

📄 tcp-full.cc

📁 Ns2 TCP 协议改进 版本 提高goodput
💻 CC
📖 第 1 页 / 共 5 页
字号:
/* * this is the simulated form of the header prediction * predicate.  While not really necessary for a simulation, it * follows the code base more closely and can sometimes help to reveal * odd behavior caused by the implementation structure.. * * Here's the comment from the real TCP: * * Header prediction: check for the two common cases * of a uni-directional data xfer.  If the packet has * no control flags, is in-sequence, the window didn't * change and we're not retransmitting, it's a * candidate.  If the length is zero and the ack moved * forward, we're the sender side of the xfer.  Just * free the data acked & wake any higher level process * that was blocked waiting for space.  If the length * is non-zero and the ack didn't move, we're the * receiver side.  If we're getting packets in-order * (the reassembly queue is empty), add the data to * the socket buffer and note that we need a delayed ack. * Make sure that the hidden state-flags are also off. * Since we check for TCPS_ESTABLISHED above, it can only * be TF_NEEDSYN. */intFullTcpAgent::predict_ok(Packet* pkt){	hdr_tcp *tcph = hdr_tcp::access(pkt);        hdr_flags *fh = hdr_flags::access(pkt);	/* not the fastest way to do this, but perhaps clearest */	int p1 = (state_ == TCPS_ESTABLISHED);		// ready	int p2 = ((tcph->flags() & (TH_SYN|TH_FIN|TH_ACK)) == TH_ACK); // ACK	int p3 = ((flags_ & TF_NEEDFIN) == 0);		// don't need fin	int p4 = (!ts_option_ || fh->no_ts_ || (tcph->ts() >= recent_)); // tsok	int p5 = (tcph->seqno() == rcv_nxt_);		// in-order data	int p6 = (t_seqno_ == maxseq_);			// not re-xmit	int p7 = (!ecn_ || fh->ecnecho() == 0);		// no ECN	int p8 = (tcph->sa_length() == 0);		// no SACK info	return (p1 && p2 && p3 && p4 && p5 && p6 && p7 && p8);}/* * fast_retransmit using the given seqno *	perform fast RTX, set recover_, set last_cwnd_action */intFullTcpAgent::fast_retransmit(int seq){	// we are now going to fast-retransmit and willtrace that event	trace_event("FAST_RETX");		recover_ = maxseq_;	// recovery target	last_cwnd_action_ = CWND_ACTION_DUPACK;	return(foutput(seq, REASON_DUPACK));	// send one pkt}/* * real tcp determines if the remote * side should receive a window update/ACK from us, and often * results in sending an update every 2 segments, thereby * giving the familiar 2-packets-per-ack behavior of TCP. * Here, we don't advertise any windows, so we just see if * there's at least 'segs_per_ack_' pkts not yet acked * * also, provide for a segs-per-ack "threshold" where * we generate 1-ack-per-seg until enough stuff * (spa_thresh_ bytes) has been received from the other side * This idea came from vj/kmn in BayTcp.  Added 8/21/01. */intFullTcpAgent::need_send(){	if (flags_ & TF_ACKNOW)		return TRUE;	int spa = (spa_thresh_ > 0 && ((rcv_nxt_ - irs_)  < spa_thresh_)) ?		1 : segs_per_ack_;			return ((rcv_nxt_ - last_ack_sent_) >= (spa * maxseg_));}/* * determine whether enough time has elapsed in order to * conclude a "restart" is necessary (e.g. a slow-start) * * for now, keep track of this similarly to how rtt_update() does */intFullTcpAgent::idle_restart(){	if (last_send_time_ < 0.0) {		// last_send_time_ isn't set up yet, we shouldn't		// do the idle_restart		return (0);	}	double tao = now() - last_send_time_;	if (!ts_option_) {                double tickoff = fmod(last_send_time_ + boot_time_,			tcp_tick_);                tao = int((tao + tickoff) / tcp_tick_) * tcp_tick_;	}	return (tao > t_rtxcur_);  // verify this CHECKME}/* * tcp-full's version of set_initial_window()... over-rides * the one in tcp.cc */voidFullTcpAgent::set_initial_window(){	syn_ = TRUE;	// full-tcp always models SYN exchange	TcpAgent::set_initial_window();}       /* * main reception path -  * called from the agent that handles the data path below in its muxing mode * advance() is called when connection is established with size sent from * user/application agent * * This is a fairly complex function.  It operates generally as follows: *	do header prediction for simple cases (pure ACKS or data) *	if in LISTEN and we get a SYN, begin initializing connection *	if in SYN_SENT and we get an ACK, complete connection init *	trim any redundant data from received dataful segment *	deal with ACKS: *		if in SYN_RCVD, complete connection init then go on *		see if ACK is old or at the current highest_ack *		if at current high, is the threshold reached or not *		if so, maybe do fast rtx... otherwise drop or inflate win *	deal with incoming data *	deal with FIN bit on in arriving packet */voidFullTcpAgent::recv(Packet *pkt, Handler*){	hdr_tcp *tcph = hdr_tcp::access(pkt);	// TCP header	hdr_cmn *th = hdr_cmn::access(pkt);	// common header (size, etc)	hdr_flags *fh = hdr_flags::access(pkt);	// flags (CWR, CE, bits)	int needoutput = FALSE;	int ourfinisacked = FALSE;	int dupseg = FALSE;			// recv'd dup data segment	int todrop = 0;				// duplicate DATA cnt in seg	last_state_ = state_;	int datalen = th->size() - tcph->hlen(); // # payload bytes	int ackno = tcph->ackno();		 // ack # from packet	int tiflags = tcph->flags() ; 		 // tcp flags from packet//if (state_ != TCPS_ESTABLISHED || (tiflags&(TH_SYN|TH_FIN))) {//fprintf(stdout, "%f(%s)in state %s recv'd this packet: ", now(), name(), statestr(state_));//prpkt(pkt);//}	/* 	 * Acknowledge FIN from passive closer even in TCPS_CLOSED state	 * (since we lack TIME_WAIT state and RST packets,	 * the loss of the FIN packet from the passive closer will make that	 * endpoint retransmit the FIN forever)	 * -F. Hernandez-Campos 8/6/00	 */	if ( (state_ == TCPS_CLOSED) && (tiflags & TH_FIN) ) {		goto dropafterack;	}	/*	 * Don't expect to see anything while closed	 */	if (state_ == TCPS_CLOSED) {		fprintf(stderr, "%f: FullTcp(%s): recv'd pkt in CLOSED state: ",			now(), name());		prpkt(pkt);		goto drop;	}        /*         * Process options if not in LISTEN state,         * else do it below         */	if (state_ != TCPS_LISTEN)		dooptions(pkt);	/*	 * if we are using delayed-ACK timers and	 * no delayed-ACK timer is set, set one.	 * They are set to fire every 'interval_' secs, starting	 * at time t0 = (0.0 + k * interval_) for some k such	 * that t0 > now	 */	if (delack_interval_ > 0.0 &&	    (delack_timer_.status() != TIMER_PENDING)) {		int last = int(now() / delack_interval_);		delack_timer_.resched(delack_interval_ * (last + 1.0) - now());	}	/*	 * sanity check for ECN: shouldn't be seeing a CE bit if	 * ECT wasn't set on the packet first.  If we see this, we	 * probably have a misbehaving router...	 */	if (fh->ce() && !fh->ect()) {	    fprintf(stderr,	    "%f: FullTcpAgent::recv(%s): warning: CE bit on, but ECT false!\n",		now(), name());	}	/*	 * Try header prediction: in seq data or in seq pure ACK	 *	with no funny business	 */	if (!nopredict_ && predict_ok(pkt)) {                /*                 * 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();                }		//		// generate a stream of ecnecho bits until we see a true		// cong_action bit		//		if (ecn_) {			if (fh->ce() && fh->ect()) {				// no CWR from peer yet... arrange to				// keep sending ECNECHO				recent_ce_ = TRUE;			} else if (fh->cwr()) {				// got CWR response from peer.. stop				// sending ECNECHO bits				recent_ce_ = FALSE;			}		}		// Header predication basically looks to see		// if the incoming packet is an expected pure ACK		// or an expected data segment		if (datalen == 0) {			// check for a received pure ACK in the correct range..			// also checks to see if we are wnd_ limited			// (we don't change cwnd at all below), plus			// not being in fast recovery and not a partial ack.			// If we are in fast			// recovery, go below so we can remember to deflate			// the window if we need to			if (ackno > highest_ack_ && ackno < maxseq_ &&			    cwnd_ >= wnd_ && !fastrecov_) {				newack(pkt);	// update timers,  highest_ack_				send_much(0, REASON_NORMAL, maxburst_);				Packet::free(pkt);				return;			}		} else if (ackno == highest_ack_ && rq_.empty()) {			// check for pure incoming segment			// the next data segment we're awaiting, and			// that there's nothing sitting in the reassem-			// bly queue			// 	give to "application" here			//	note: DELACK is inspected only by			//	tcp_fasttimo() in real tcp.  Every 200 ms			//	this routine scans all tcpcb's looking for			//	DELACK segments and when it finds them			//	changes DELACK to ACKNOW and calls tcp_output()			rcv_nxt_ += datalen;			flags_ |= TF_DELACK;			recvBytes(datalen); // notify application of "delivery"			//			// special code here to simulate the operation			// of a receiver who always consumes data,			// resulting in a call to tcp_output			Packet::free(pkt);			if (need_send())				send_much(1, REASON_NORMAL, maxburst_);			return;		}	} /* header prediction */	//	// header prediction failed	// (e.g. pure ACK out of valid range, SACK present, etc)...	// do slow path processing	//	// the following switch does special things for these states:	//	TCPS_LISTEN, TCPS_SYN_SENT	//	switch (state_) {        /*         * If the segment contains an ACK then it is bad and do reset.         * If it does not contain a SYN then it is not interesting; drop it.         * Otherwise initialize tp->rcv_nxt, and tp->irs, iss is already	 * selected, and send a segment:         *     <SEQ=ISS><ACK=RCV_NXT><CTL=SYN,ACK>         * Initialize tp->snd_nxt to tp->iss.         * Enter SYN_RECEIVED state, and process any other fields of this         * segment in this state.         */	case TCPS_LISTEN:	/* awaiting peer's SYN */		if (tiflags & TH_ACK) {		    	fprintf(stderr,		    		"%f: FullTcpAgent(%s): warning: recv'd ACK while in LISTEN: ",				now(), name());			prpkt(pkt);			// don't want ACKs in LISTEN			goto dropwithreset;		}		if ((tiflags & TH_SYN) == 0) {		    	fprintf(stderr,		    		"%f: FullTcpAgent(%s): warning: recv'd NON-SYN while in LISTEN\n",				now(), name());			prpkt(pkt);			// any non-SYN is discarded			goto drop;		}		/*		 * must by a SYN (no ACK) at this point...		 * in real tcp we would bump the iss counter here also		 */		dooptions(pkt);		irs_ = tcph->seqno();		t_seqno_ = iss_; /* tcp_sendseqinit() macro in real tcp */		rcv_nxt_ = rcvseqinit(irs_, datalen);		flags_ |= TF_ACKNOW;		// check for a ECN-SYN with ECE|CWR		if (ecn_ && fh->ecnecho() && fh->cong_action()) {			ect_ = TRUE;		}		if (fid_ == 0) {			// XXX: sort of hack... If we do not			// have a special flow ID, pick up that			// of the sender (active opener)			hdr_ip* iph = hdr_ip::access(pkt);			fid_ = iph->flowid();		}		newstate(TCPS_SYN_RECEIVED);		goto trimthenstep6;        /*         * If the state is SYN_SENT:         *      if seg contains an ACK, but not for our SYN, drop the input.         *      if seg does not contain SYN, then drop it.         * Otherwise this is an acceptable SYN segment         *      initialize tp->rcv_nxt and tp->irs         *      if seg contains ack then advance tp->snd_una         *      if SYN has been acked change to ESTABLISHED else SYN_RCVD state         *      arrange for segment to be acked (eventually)         *      continue processing rest of data/controls, beginning with URG         */	case TCPS_SYN_SENT:	/* we sent SYN, expecting SYN+ACK (or SYN) */		/* drop if it's a SYN+ACK and the ack field is bad */		if ((tiflags & TH_ACK) &&			((ackno <= iss_) || (ackno > maxseq_))) {			// not an ACK for our SYN, discard			fprintf(stderr,			    "%f: FullTcpAgent::recv(%s): bad ACK for our SYN: ",			        now(), name());			prpkt(pkt);			goto dropwithreset;		}		if ((tiflags & TH_SYN) == 0) {			fprintf(stderr,			    "%f: FullTcpAgent::recv(%s): no SYN for our SYN: ",			        now(), name());			prpkt(pkt);			goto drop;		}		/* looks like an ok SYN or SYN+ACK */#ifdef notdefcancel_rtx_timer();	// cancel timer on our 1st SYN [does this belong!?]#endif		irs_ = tcph->seqno();	// get initial recv'd seq #		rcv_nxt_ = rcvseqinit(irs_, datalen);		if (tiflags & TH_ACK) {			// SYN+ACK (our SYN was acked)			// CHECKME                        // Check ECN-SYN+ACK packet                        if (ecn_ && fh->ecnecho() && !fh->cong_action())                                ect_ = TRUE;			highest_ack_ = ackno;			cwnd_ = initial_window();#ifdef notdef/* * if we didn't have to retransmit the SYN, * use its rtt as our initial srtt & rtt var. */if (t_rtt_) {	double tao = now() - tcph->ts();	rtt_update(tao);}#endif			/*			 * if there's data, delay ACK; if there's also a FIN			 * ACKNOW will be turned on later.			 */			if (datalen > 0) {				flags_ |= TF_DELACK;	// data there: wait

⌨️ 快捷键说明

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