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

📄 tcp-full.cc

📁 Ns2 TCP 协议改进 版本 提高goodput
💻 CC
📖 第 1 页 / 共 5 页
字号:
        }	last_ack_sent_ = ackno;//if (state_ != TCPS_ESTABLISHED) {//printf("%f(%s)[state:%s]: sending pkt ", now(), name(), statestr(state_));//prpkt(p);//}	send(p, 0);	return;}//// reset_rtx_timer: called during a retransmission timeout// to perform exponential backoff.  Also, note that because// we have performed a retransmission, our rtt timer is now// invalidated (indicate this by setting rtt_active_ false)//voidFullTcpAgent::reset_rtx_timer(int /* mild */){	// cancel old timer, set a new one	/* if there is no outstanding data, don't back off rtx timer *	 * (Fix from T. Kelly.) */	if (!(highest_ack_ == maxseq_ && restart_bugfix_)) {        	rtt_backoff();		// double current timeout	}        set_rtx_timer();	// set new timer        rtt_active_ = FALSE;	// no timing during this window}/* * see if we should send a segment, and if so, send it * 	(may be ACK or data) * return the number of data bytes sent (count a SYN or FIN as 1 each) * * simulator var, desc (name in real TCP) * -------------------------------------- * maxseq_, largest seq# we've sent plus one (snd_max) * flags_, flags regarding our internal state (t_state) * pflags, a local used to build up the tcp header flags (flags) * curseq_, is the highest sequence number given to us by "application" * highest_ack_, the highest ACK we've seen for our data (snd_una-1) * seqno, the next seq# we're going to send (snd_nxt) */intFullTcpAgent::foutput(int seqno, int reason){	// if maxseg_ not set, set it appropriately	// Q: how can this happen?	if (maxseg_ == 0) 	   	maxseg_ = size_ - headersize();	else		size_ =  maxseg_ + headersize();	int is_retransmit = (seqno < maxseq_);	int quiet = (highest_ack_ == maxseq_);	int pflags = outflags();	int syn = (seqno == iss_);	int emptying_buffer = FALSE;	int buffered_bytes = (infinite_send_) ? TCP_MAXSEQ :				curseq_ - highest_ack_ + 1;	int win = window() * maxseg_;	// window (in bytes)	int off = seqno - highest_ack_;	// offset of seg in window	int datalen;	//int amtsent = 0;	// be careful if we have not received any ACK yet	if (highest_ack_ < 0) {		if (!infinite_send_)			buffered_bytes = curseq_ - iss_;;		off = seqno - iss_;	}	if (syn && !data_on_syn_)		datalen = 0;	else if (pipectrl_)		datalen = buffered_bytes - off;	else		datalen = min(buffered_bytes, win) - off;        if ((signal_on_empty_) && (!buffered_bytes) && (!syn))	                bufferempty();	//	// in real TCP datalen (len) could be < 0 if there was window	// shrinkage, or if a FIN has been sent and neither ACKd nor	// retransmitted.  Only this 2nd case concerns us here...	//	if (datalen < 0) {		datalen = 0;	} else if (datalen > maxseg_) {		datalen = maxseg_;	}	//	// this is an option that causes us to slow-start if we've	// been idle for a "long" time, where long means a rto or longer	// the slow-start is a sort that does not set ssthresh	//	if (slow_start_restart_ && quiet && datalen > 0) {		if (idle_restart()) {			slowdown(CLOSE_CWND_INIT);		}	}	//	// see if sending this packet will empty the send buffer	// a dataless SYN packet counts also	//	if (!infinite_send_ && ((seqno + datalen) > curseq_ || 	    (syn && datalen == 0))) {		emptying_buffer = TRUE;		//		// if not a retransmission, notify application that 		// everything has been sent out at least once.		//		if (!syn) {			idle();			if (close_on_empty_ && quiet) {				flags_ |= TF_NEEDCLOSE;			}		}		pflags |= TH_PUSH;		//		// if close_on_empty set, we are finished		// with this connection; close it		//	} else  {		/* not emptying buffer, so can't be FIN */		pflags &= ~TH_FIN;	}	if (infinite_send_ && (syn && datalen == 0))		pflags |= TH_PUSH;  // set PUSH for dataless SYN	/* sender SWS avoidance (Nagle) */	if (datalen > 0) {		// if full-sized segment, ok		if (datalen == maxseg_)			goto send;		// if Nagle disabled and buffer clearing, ok		if ((quiet || nodelay_)  && emptying_buffer)			goto send;		// if a retransmission		if (is_retransmit)			goto send;		// if big "enough", ok...		//	(this is not a likely case, and would		//	only happen for tiny windows)		if (datalen >= ((wnd_ * maxseg_) / 2.0))			goto send;	}	if (need_send())		goto send;	/*	 * send now if a control packet or we owe peer an ACK	 * TF_ACKNOW can be set during connection establishment and	 * to generate acks for out-of-order data	 */	if ((flags_ & (TF_ACKNOW|TF_NEEDCLOSE)) ||	    (pflags & (TH_SYN|TH_FIN))) {		goto send;	}        /*               * No reason to send a segment, just return.         */      	return 0;send:	// is a syn or fin?	syn = (pflags & TH_SYN) ? 1 : 0;	int fin = (pflags & TH_FIN) ? 1 : 0;        /* setup ECN syn and ECN SYN+ACK packet headers */        if (ecn_ && syn && !(pflags & TH_ACK)){                pflags |= TH_ECE;                pflags |= TH_CWR;        }        if (ecn_ && syn && (pflags & TH_ACK)){                pflags |= TH_ECE;                pflags &= ~TH_CWR;        }	else if (ecn_ && ect_ && cong_action_ && 	             (!is_retransmit || SetCWRonRetransmit_)) 		/* 		 * Don't set CWR for a retranmitted SYN+ACK (has ecn_ 		 * and cong_action_ set) or on any retransmits.		 * -M. Weigle 6/19/02		 */		/* set CWR if necessary */		pflags |= TH_CWR;	/* moved from sendpacket()  -M. Weigle 6/19/02 */	//	// although CWR bit is ordinarily associated with ECN,	// it has utility within the simulator for traces. Thus, set	// it even if we aren't doing ECN	//	if (datalen > 0 && cong_action_ && !is_retransmit) {		pflags |= TH_CWR;	}          /* set ECE if necessary */        if (ecn_ && ect_ && recent_ce_ ) pflags |= TH_ECE;        /*          * Tack on the FIN flag to the data segment if close_on_empty_         * was previously set-- avoids sending a separate FIN         */         if (flags_ & TF_NEEDCLOSE) {                flags_ &= ~TF_NEEDCLOSE;                if (state_ <= TCPS_ESTABLISHED && state_ != TCPS_CLOSED)                {                    pflags |=TH_FIN;                    fin = 1;  /* FIN consumes sequence number */                    newstate(TCPS_FIN_WAIT_1);                }        }	sendpacket(seqno, rcv_nxt_, pflags, datalen, reason);        /*               * Data sent (as far as we can tell).         * Any pending ACK has now been sent.         */      	flags_ &= ~(TF_ACKNOW|TF_DELACK);	/*	 * if we have reacted to congestion recently, the	 * slowdown() procedure will have set cong_action_ and	 * sendpacket will have copied that to the outgoing pkt	 * CWR field. If that packet contains data, then	 * it will be reliably delivered, so we are free to turn off the	 * cong_action_ state now  If only a pure ACK, we keep the state	 * around until we actually send a segment	 */	int reliable = datalen + syn + fin; // seq #'s reliably sent	/* 	 * Don't reset cong_action_ until we send new data.	 * -M. Weigle 6/19/02	 */	if (cong_action_ && reliable > 0 && !is_retransmit)		cong_action_ = FALSE;	// highest: greatest sequence number sent + 1	//	and adjusted for SYNs and FINs which use up one number	int highest = seqno + reliable;	if (highest > maxseq_) {		maxseq_ = highest;		//		// if we are using conventional RTT estimation,		// establish timing on this segment		//		if (!ts_option_ && rtt_active_ == FALSE) {			rtt_active_ = TRUE;	// set timer			rtt_seq_ = seqno; 	// timed seq #			rtt_ts_ = now();	// when set		}	}	/*	 * 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.	 * Future values are rtt + 4 * rttvar.	 */	if (rtx_timer_.status() != TIMER_PENDING && reliable) {		set_rtx_timer();  // no timer pending, schedule one	}	return (reliable);}/* * * send_much: send as much data as we are allowed to.  This is * controlled by the "pipectrl_" variable.  If pipectrl_ is set * to FALSE, then we are working as a normal window-based TCP and * we are allowed to send whatever the window allows. * If pipectrl_ is set to TRUE, then we are allowed to send whatever * pipe_ allows us to send.  One tricky part is to make sure we * do not overshoot the receiver's advertised window if we are * in (pipectrl_ == TRUE) mode. */  voidFullTcpAgent::send_much(int force, int reason, int maxburst){	int npackets = 0;	// sent so far//if ((int(t_seqno_)) > 1)//printf("%f: send_much(f:%d, win:%d, pipectrl:%d, pipe:%d, t_seqno:%d, topwin:%d, maxseq_:%d\n",//now(), force, win, pipectrl_, pipe_, int(t_seqno_), topwin, int(maxseq_));	if (!force && (delsnd_timer_.status() == TIMER_PENDING))		return;	while (1) {		/*		 * note that if output decides to not actually send		 * (e.g. because of Nagle), then if we don't break out		 * of this loop, we can loop forever at the same		 * simulated time instant		 */		int amt;		int seq = nxt_tseq();		if (!force && !send_allowed(seq))			break;		// Q: does this need to be here too?		if (!force && overhead_ != 0 &&		    (delsnd_timer_.status() != TIMER_PENDING)) {			delsnd_timer_.resched(Random::uniform(overhead_));			return;		}		if ((amt = foutput(seq, reason)) <= 0)			break;		if ((outflags() & TH_FIN))			--amt;	// don't count FINs		sent(seq, amt);		force = 0;		if ((outflags() & (TH_SYN|TH_FIN)) ||		    (maxburst && ++npackets >= maxburst))			break;	}	return;}/* * base TCP: we are allowed to send a sequence number if it * is in the window */intFullTcpAgent::send_allowed(int seq){        int win = window() * maxseg_;        int topwin = curseq_; // 1 seq number past the last byte we can send        if ((topwin > highest_ack_ + win) || infinite_send_)                topwin = highest_ack_ + win; 	return (seq < topwin);}/* * Process an ACK *	this version of the routine doesn't necessarily *	require the ack to be one which advances the ack number * * if this ACKs a rtt estimate *	indicate we are not timing *	reset the exponential timer backoff (gamma) * update rtt estimate * cancel retrans timer if everything is sent and ACK'd, else set it * advance the ack number if appropriate * update segment to send next if appropriate */voidFullTcpAgent::newack(Packet* pkt){	hdr_tcp *tcph = hdr_tcp::access(pkt);	register int ackno = tcph->ackno();	int progress = (ackno > highest_ack_);	if (ackno == maxseq_) {		cancel_rtx_timer();	// all data ACKd	} else if (progress) {		set_rtx_timer();	}	// advance the ack number if this is for new data	if (progress)		highest_ack_ = ackno;	// if we have suffered a retransmit timeout, t_seqno_	// will have been reset to highest_ ack.  If the	// receiver has cached some data above t_seqno_, the	// new-ack value could (should) jump forward.  We must	// update t_seqno_ here, otherwise we would be doing	// go-back-n.	if (t_seqno_ < highest_ack_)		t_seqno_ = highest_ack_; // seq# to send next        /*         * Update RTT only if it's OK to do so from info in the flags header.         * This is needed for protocols in which intermediate agents         * in the network intersperse acks (e.g., ack-reconstructors) for         * various reasons (without violating e2e semantics).         */        hdr_flags *fh = hdr_flags::access(pkt);	if (!fh->no_ts_) {                if (ts_option_) {			recent_age_ = now();			recent_ = tcph->ts();			rtt_update(now() - tcph->ts_echo());			if (ts_resetRTO_ && (!ect_ || !ecn_backoff_ ||		           !hdr_flags::access(pkt)->ecnecho())) { 				// From Andrei Gurtov				//                         	// Don't end backoff if still in ECN-Echo with                         	// a congestion window of 1 packet.				t_backoff_ = 1;			}		} else if (rtt_active_ && ackno > rtt_seq_) {			// got an RTT sample, record it			// "t_backoff_ = 1;" deleted by T. Kelly.			rtt_active_ = FALSE;			rtt_update(now() - rtt_ts_);                }		if (!ect_ || !ecn_backoff_ ||		    !hdr_flags::access(pkt)->ecnecho()) {			/*			 * Don't end backoff if still in ECN-Echo with			 * a congestion window of 1 packet.			 * Fix from T. Kelly.			 */			t_backoff_ = 1;			ecn_backoff_ = 0;		}        }	return;}

⌨️ 快捷键说明

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