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

📄 tcp-advw.cc

📁 P2P文件共享基于ns2的仿真代码
💻 CC
📖 第 1 页 / 共 2 页
字号:
/*-------------------------------------------------------------------------*//* AdvwTcpAgent: subclass of FullTcpAgent that has receiver advertised     *//* window and application-limited consumption on receiver                  *//* Author: Qi He <http://www.cc.gatech.edu/~qhe> 01Aug2003                 *//* $Revision:$ $Name:$ $Date:$                                             *//*-------------------------------------------------------------------------*/#include "tcp-advw.h"#include "ip.h"#include "flags.h"#include <stdio.h>#define MAX(a, b)	((a) > (b) ? (a) : (b))#define MIN(a, b)	((a) < (b) ? (a) : (b))#define TRUE 1#define FALSE 0static class AdvwTcpClass: public TclClass {public:	AdvwTcpClass(): TclClass("Agent/TCP/FullTcp/AdvwTcp") {}	TclObject* create(int, const char*const*) {		return (new AdvwTcpAgent());	}} class_advwtcp;static class AdvwTcpAppClass: public TclClass {public:	AdvwTcpAppClass(): TclClass("Application/AdvwTcpApplication") {}	TclObject* create(int, const char*const*) {		return (new AdvwTcpApplication());	}} class_advwtcpapp;AdvwTcpAgent::AdvwTcpAgent(): FullTcpAgent(), infinite_rcv_(1), num_bytes_req_(0), num_bytes_avail_(0){	bind("inf_rcv_", &infinite_rcv_);	bind("rcv_wnd_", &rcv_wnd_);	rcv_buff_ = rcv_wnd_;	app_ = NULL;}AdvwTcpAgent::~AdvwTcpAgent(){}void AdvwTcpAgent::tcp_command_nonblock_receive(int num_bytes) {  	num_bytes_req_ += num_bytes;}void AdvwTcpAgent::tcp_command_block_receive(int num_bytes) {	num_bytes_req_ += num_bytes;		recvBytes(0);}void AdvwTcpAgent::recvBytes(int nbytes){	int rcv_buf_free, byte_read=0;		num_bytes_avail_ += nbytes;	while(num_bytes_avail_ > 0) {		if(app_)			byte_read = app_->upcall_recv(num_bytes_avail_);		else {			if(infinite_rcv_)				byte_read = num_bytes_avail_;			else				byte_read = MIN(num_bytes_req_, num_bytes_avail_);		}		if(byte_read==0)		  break;		num_bytes_avail_ -= byte_read;		num_bytes_req_ -= byte_read;		rcv_buf_free = rcv_buff_ - num_bytes_avail_;		if(rcv_buf_free >= rcv_wnd_ + MIN (rcv_buff_/2, maxseg_)) {		  rcv_wnd_ = rcv_buf_free;		  sendpacket(0, rcv_nxt_, TH_ACK, 0, REASON_NORMAL);		}	};}void AdvwTcpAgent::attachApp(Application *app) {	app_ = (AdvwTcpApplication *)app;}void AdvwTcpAgent::recv(Packet *pkt, Handler*){	hdr_tcp *tcph = hdr_tcp::access(pkt);	hdr_cmn *th = hdr_cmn::access(pkt);	hdr_flags *fh = hdr_flags::access(pkt);	hdr_ip *iph = hdr_ip::access(pkt);	int needoutput = FALSE;	int ourfinisacked = FALSE;	int dupseg = FALSE;	int todrop = 0;	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_CLOSED)		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());	}	wnd_ = (double)tcph->advwin()/(double)size_;	//	// 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());	}	// header predication failed (or pure ACK out of valid range)...	// do slow path processing	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) {			goto dropwithreset;		}		if ((tiflags & TH_SYN) == 0) {			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;		if (ecn_ && fh->ecnecho()) {		  ect_ = TRUE;		}		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 (%d) for our SYN(%d)\n",			        now(), name(), int(ackno), int(maxseq_));			goto dropwithreset;		}		if ((tiflags & TH_SYN) == 0) {			fprintf(stderr,			    "%f: FullTcpAgent::recv(%s): no SYN for our SYN(%d)\n",			        now(), name(), int(maxseq_));			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);		/*		 * we are seeing either a SYN or SYN+ACK.  For pure SYN,		 * ecnecho tells us our peer is ecn-capable.  For SYN+ACK,		 * it's acking our SYN, so it already knows we're ecn capable,		 * so it can just turn on ect		 */		if (ecn_ && (fh->ecnecho() || fh->ect()))			ect_ = TRUE;		if (tiflags & TH_ACK) {			// SYN+ACK (our SYN was acked)			// CHECKME			highest_ack_ = ackno;			cwnd_ = initial_window();			if(app_)			  app_->upcall_send();#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			} 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);				//				printf("%d new state TCPS_ESTABLISHED\n", here_.addr_);			}			// 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 {			// 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:	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 {			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 ACKNO 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	//	todrop = rcv_nxt_ - tcph->seqno();  // how much overlap?	if (todrop > 0 && ((tiflags & (TH_SYN|TH_FIN)) || datalen > 0)) {		if (tiflags & TH_SYN) {			tiflags &= ~TH_SYN;			tcph->seqno()++;			th->size()--;	// XXX Must decrease packet size too!!			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)) {                        /*                         * 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;		}		tcph->seqno() += todrop;		th->size() -= todrop;	// XXX Must decrease size too!!		datalen -= todrop;	}	/*	 * 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)\n",		        now(), name(), state_);		goto dropwithreset;	}	// K: added TH_SYN, but it is already known here!	if ((tiflags & TH_ACK) == 0) {		fprintf(stderr, "%f: FullTcpAgent::recv(%s) got packet lacking ACK (seq %d)\n",			now(), name(), tcph->seqno());		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			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);			//			printf("%d new state TCPS_ESTABLISHED\n", here_.addr_);                }		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->cong_action())                                recent_ce_ = FALSE;                }		// look for dup ACKs (dup ack numbers, no data)		//		// do fast retransmit/recovery if at/past thresh		if (ackno <= highest_ack_) {			// an ACK which doesn't advance highest_ack_			if (datalen == 0 && (!dupseg_fix_ || !dupseg)) {				--pipe_; // ACK indicates pkt cached @ receiver

⌨️ 快捷键说明

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