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

📄 tcp-fast.cc

📁 关于ns2的一些源码和资料
💻 CC
📖 第 1 页 / 共 2 页
字号:
 				 * and try to resume the sequence.
 				 */
 				   	dupack_action();
 				} else if (dupacks_ < numdupacks(cwnd_) && singledup_ ) {
					send_one();
 				}
			}
		}
        	if (valid_ack || aggressive_maxburst_)
			if (dupacks_ == 0)
				send_much(FALSE, 0, maxburst_);
	} else {
		/* we are in fast recovery */
		cwnd_update_time = currentTime;
		--pipe_;
		if ((int)tcph->seqno() >= recover_) {
			/* ACK indicates fast recovery is over */
			recover_ = 0;
			fastrecov_ = FALSE;
			newack(pkt);
			/* if the connection is done, call finish() */
			if ((highest_ack_ >= curseq_-1) && !closed_) {
				closed_ = 1;
				finish();
			}
			timeout_ = FALSE;
			scb_->ClearScoreBoard();

			/* New window: W/2 - K or W/2? */
		} else if ((int)tcph->seqno() > highest_ack_) {
			/* Not out of fast recovery yet.
			 * Update highest_ack_, but not last_ack_. */
			highest_ack_ = (int)tcph->seqno();
			scb_->UpdateScoreBoard (highest_ack_, tcph);
			if (partial_ack_) {
			  /* partial_ack_ is needed to guarantee that */
			  /*  a new packet is sent in response to a   */
			  /*  partial ack.                            */
				partial_ack_action();
				++pipe_;
				if (firstpartial_ == 0) {
					newtimer(pkt);
					t_backoff_ = 1;
					firstpartial_ = 1;
				}
			} else {
				--pipe_;
				newtimer(pkt);
				t_backoff_ = 1;
 			 /* If this partial ACK is from a retransmitted pkt,*/
 			 /* then we decrement pipe_ again, so that we never */
 			 /* do worse than slow-start.  If this partial ACK  */
 			 /* was instead from the original packet, reordered,*/
 			 /* then this might be too aggressive. */
			}
		} else if (timeout_ == FALSE) {
			/* got another dup ack */
			scb_->UpdateScoreBoard (highest_ack_, tcph);
 		        if(scb_->CheckUpdate()) {
 				if (dupacks_ > 0)
 			        	dupacks_++;
 			}
		}
        	if (valid_ack || aggressive_maxburst_)
			send_much(FALSE, 0, maxburst_);
	}

	Packet::free(pkt);
}

/******************************************************************************/
void
FastTcpAgent::dupack_action()
{
	int recovered = (highest_ack_ > recover_);
	if (recovered || (!bug_fix_ && !ecn_)) {
		goto sack_action;
	}
 
	if (ecn_ && last_cwnd_action_ == CWND_ACTION_ECN) {
		last_cwnd_action_ = CWND_ACTION_DUPACK;
		/*
		 * What if there is a DUPACK action followed closely by ECN
		 * followed closely by a DUPACK action?
		 * The optimal thing to do would be to remember all
		 * congestion actions from the most recent window
		 * of data.  Otherwise "bugfix" might not prevent
		 * all unnecessary Fast Retransmits.
		 */
		reset_rtx_timer(1,0);
		/*
		 * There are three possibilities: 
		 * (1) pipe_ = int(cwnd_) - numdupacks_;
		 * (2) pipe_ = window() - numdupacks_;
		 * (3) pipe_ = maxseq_ - highest_ack_ - numdupacks_;
		 * equation (2) takes into account the receiver's
		 * advertised window, and equation (3) takes into
		 * account a data-limited sender.
		 */
		if (singledup_ && LimTransmitFix_) {
		  pipe_ = maxseq_ - highest_ack_ - 1;
		}
		else {
		  // numdupacks(cwnd_) packets have left the pipe
		  pipe_ = maxseq_ - highest_ack_ - numdupacks(cwnd_);
		}
		fastrecov_ = TRUE;
		scb_->MarkRetran(highest_ack_+1);
		output(last_ack_ + 1, TCP_REASON_DUPACK);
		return;
	}

	if (bug_fix_) {
		/*
		 * The line below, for "bug_fix_" true, avoids
		 * problems with multiple fast retransmits in one
		 * window of data.
		 */
		return;
	}

sack_action:
	// we are now going into fast_recovery and will trace that event
	trace_event("FAST_RECOVERY");

	recover_ = maxseq_;
	last_cwnd_action_ = CWND_ACTION_DUPACK;
	if (oldCode_) {
	 	pipe_ = int(cwnd_) - numdupacks(cwnd_);
	} else if (singledup_ && LimTransmitFix_) {
		  pipe_ = maxseq_ - highest_ack_ - 1;
	}
	else {
		  // numdupacks(cwnd_) packets have left the pipe
		  pipe_ = maxseq_ - highest_ack_ - numdupacks(cwnd_);
	}
	slowdown(CLOSE_SSTHRESH_HALF|CLOSE_CWND_HALF);
	reset_rtx_timer(1,0);
	fastrecov_ = TRUE;
	scb_->MarkRetran(highest_ack_+1);
	output(last_ack_ + 1, TCP_REASON_DUPACK);	// from top
	/*
	 * If dynamically adjusting numdupacks_, record information
	 *  at this point.
	 */
	return;
}

/*
 * Process a packet that acks previously unacknowleges data, but
 * does not take us out of Fast Retransmit.
 *
 * The need for a mechanism to ensure that Sack TCP sends a packet in
 * response to a partial ACK has been discussed in
 * "Challenges to Reliable Data Transport over Heterogeneous
 * Wireless Networks", Hari Balakrishnan, 1998, and in
 * "Responding to Spurious Timeouts in TCP", Andrei Gurtov and 
 * Reiner Ludwig, 2003. 
 */
void
FastTcpAgent::partial_ack_action()
{
	if (next_pkt_ < highest_ack_ + 1) {
		next_pkt_ = highest_ack_ + 1;
	}
	// Output two packets in response to a partial ack,
	//   so as not to do worse than slow-start.
	int i;
	for (i = 1; i<=2; i++) {
		int getNext = scb_->GetNextUnacked(next_pkt_);

		if (getNext > next_pkt_) {
			next_pkt_ = getNext;
		}
		if (t_seqno_ < next_pkt_) {
			t_seqno_ = next_pkt_;
		}
		output(next_pkt_, TCP_REASON_PARTIALACK);	
		scb_->MarkRetran(next_pkt_);
		++next_pkt_; 
	}
	return;
}

void FastTcpAgent::timeout(int tno)
{
	if (tno == TCP_TIMER_RTX) {
		/*
		 * IF DSACK and dynamic adjustment of numdupacks_,
		 *  check whether a smaller value of numdupacks_
		 *  would have prevented this retransmit timeout.
		 * If DSACK and detection of premature retransmit
		 *  timeouts, then save some info here.
		 */ 
		dupacks_ = 0;
		fastrecov_ = FALSE;
		timeout_ = TRUE;
		if (highest_ack_ > last_ack_)
			last_ack_ = highest_ack_;
		recover_ = maxseq_;
		scb_->ClearScoreBoard();
		if (highest_ack_ == maxseq_ && !slow_start_restart_) {
			/*
			 * TCP option:
			 * If no outstanding data, then don't do anything.
			 *
			 * Note:  in the USC implementation,
			 * slow_start_restart_ == 0.
			 * I don't know what the U. Arizona implementation
			 * defaults to.
			 */
			return;
		};
		last_cwnd_action_ = CWND_ACTION_TIMEOUT;
		reset_rtx_timer(0, 0);
		++nrexmit_;
		slowdown(CLOSE_CWND_RESTART|CLOSE_SSTHRESH_HALF);
		cwnd_ = double(slowstart_);
		newcwnd_ = 0;
		send_much(0, TCP_REASON_TIMEOUT, maxburst_);
	} else {
		/* delayed-sent timer, with random overhead to avoid
		 * phase effect. */
		send_much(1, TCP_REASON_TIMEOUT, 3);
	}
}

void FastTcpAgent::send_much(int force, int reason, int maxburst)
{
	register int found, npacket = 0;
	int win = window();
	int xmit_seqno;

	found = 1;
	if (!force && delsnd_timer_.status() == TIMER_PENDING)
		return;
	/* Save time when first packet was sent, for newreno  --Allman */
	if (t_seqno_ == 0)
		firstsent_ = Scheduler::instance().clock();
	/*
	 * as long as the pipe is open and there is app data to send...
	 */
	while (((!fastrecov_ && (t_seqno_ <= last_ack_ + win)) ||
			(fastrecov_ && (pipe_ < int(cwnd_)))) 
			&& t_seqno_ < curseq_ && found) {

		if (overhead_ == 0 || force) {
			found = 0;
			int oldest_unacked_pkt = scb_->GetNextUnacked(last_ack_);
			if (oldest_unacked_pkt != -1 &&
			fasttime() - sendtime_[oldest_unacked_pkt%maxwnd_] > 2*avgRTT_){
				xmit_seqno = oldest_unacked_pkt;
			}
			else
				xmit_seqno = scb_->GetNextRetran ();
			if (xmit_seqno == -1) { 
				if ((!fastrecov_ && t_seqno_<=highest_ack_+win)||
					(fastrecov_ && t_seqno_<=highest_ack_+int(wnd_))) {
					found = 1;
					xmit_seqno = t_seqno_++;
				}
			} else if (recover_>0 && xmit_seqno<=highest_ack_+int(wnd_)) {
				found = 1;
				scb_->MarkRetran (xmit_seqno);
				win = window();
			}
			if (found) {
				output(xmit_seqno, reason);
				if (t_seqno_ <= xmit_seqno)
					t_seqno_ = xmit_seqno + 1;
				npacket++;
				pipe_++;
				if (QOption_)
					process_qoption_after_send () ;
	                        if (qs_approved_ == 1) {
	                                double delay = (double) t_rtt_ * tcp_tick_ / cwnd_;
	                                delsnd_timer_.resched(delay);
	                                return;
	                        }
			}
		} else if (!(delsnd_timer_.status() == TIMER_PENDING)) {
			/*
			 * Set a delayed send timeout.
			 * This is only for the simulator,to add some
			 *   randomization if speficied.
			 */
			delsnd_timer_.resched(Random::uniform(overhead_));
			return;
		}
		if (maxburst && npacket == maxburst)
			break;
	} /* while */
}

void
FastTcpAgent::output(int seqno, int reason)
{
	Packet* p = allocpkt();
	hdr_tcp *tcph = hdr_tcp::access(p);
	double now = Scheduler::instance().clock();
	hdr_flags* hf = hdr_flags::access(p);
	hdr_ip *iph = hdr_ip::access(p);
	int databytes = hdr_cmn::access(p)->size();
	tcph->seqno() = seqno;
	tcph->ts() = now;
	tcph->reason() = reason;
	/* if this is the 1st pkt, setup senttime[] and transmits[]
	 * I alloc mem here, instrad of in the constructor, to cover
	 * cases which windows get set by each different tcp flows */
	if (seqno==0) {
		maxwnd_ = int(wnd_);
		if (sendtime_)
			delete []sendtime_;
        	if (transmits_)
			delete []transmits_;
        	if (cwnd_array_)
			delete []cwnd_array_;
		sendtime_ = new double[maxwnd_];
		transmits_ = new int[maxwnd_];
		cwnd_array_= new double[maxwnd_];
		for(int i=0;i<maxwnd_;i++) {
			sendtime_[i] = -1.;
			transmits_[i] = 0;
			cwnd_array_[i]=-1;
		}
	}

	if (ecn_) {
		hf->ect() = 1; // ECN capable transport.
	}

	/* Check if this is the initial SYN packet. */
	if (seqno == 0) {
		if (syn_) {
			databytes= 0;
			curseq_ += 1;
			hdr_cmn::access(p)->size() = tcpip_base_hdr_size_;
		}
		if (ecn_) {
			hf->ecnecho() = 1;
//			hf->cong_action() = 1;
			hf->ect() = 0;
		}
	}
	else if (useHeaders_ == true) {
		hdr_cmn::access(p)->size() += headersize();
	}

	// record a find grained send time and # of transmits 
	int index = seqno % maxwnd_;
	sendtime_[index] = fasttime(); 
	cwnd_array_[index]=avg_cwnd_last_RTT_; 
	++transmits_[index];
	/* support ndatabytes_ in output - Lloyd Wood 14 March 2000 */
	int bytes = hdr_cmn::access(p)->size(); 
	ndatabytes_ += bytes; 
	ndatapack_++; // Added this - Debojyoti 12th Oct 2000
	send(p, 0);

	if (seqno == curseq_ && seqno > maxseq_)
		idle();  // Tell application I have sent everything so far

	if (seqno > maxseq_) {
		maxseq_ = seqno;
		if (!rtt_active_) {
			rtt_active_ = 1;
			if (seqno > rtt_seq_) {
				rtt_seq_ = seqno;
				rtt_ts_ = now;
			}
		}
	} else {
		++nrexmitpack_;
       		nrexmitbytes_ += bytes;
    	}

	if (!(rtx_timer_.status() == TIMER_PENDING))
		/* No timer pending.  Schedule one. */
		set_rtx_timer();
}

/******************************************************************************/
/* Space out increments to cwnd as acknowledegements arrive */
/* cwndp points to the actual cwnd value */
/* cwnd_incre (0 or 1) specifies the desired amount to increase cwnd by */
/* (eventually) */
void
FastTcpAgent::fast_pace(TracedDouble *cwndp, int incre_4_cwnd)
{
	if ( !avgRTT_ )
		return;

	double acks_per_period = (double)acks_last_rtt * fast_update_cwnd_interval_ / avgRTT_;

	if ( incre_4_cwnd >= 1 )
	{
		cwnd_increments += incre_4_cwnd;
		/* bc_spacing: target number of ACKs between increments */
		bc_spacing = (short unsigned int)(acks_per_period/cwnd_increments);
		/* bc_ack: number of ACKs since last increment */
		bc_ack = 1;
	}
	else { 
		bc_ack ++;
	}

	if (cwnd_increments)
	{
		/* if cwnd small, increment immediately */
		if (*cwndp <= 4) {
		/* if increment would more than double cwnd, do it in stages */
			if (*cwndp < cwnd_increments) {
				cwnd_increments -= (unsigned int)*cwndp;
				*cwndp += *cwndp;
			}
			else {
				*cwndp += cwnd_increments;
				cwnd_increments=0;
				bc_spacing=0;
			}
			bc_ack=0;
		}
		else if (bc_ack >= bc_spacing)
		{
			(*cwndp)++;
			cwnd_increments--;
			bc_ack = 0;
		}
	}
}

/******************************************************************************/
/*
 * return -1 if the oldest sent pkt has not been timeout (based on
 * fine grained timer).
 */
int
FastTcpAgent::fast_expire(Packet* pkt)
{
	hdr_tcp *tcph = hdr_tcp::access(pkt);
	double elapse = fasttime() - sendtime_[(tcph->seqno()+1)%maxwnd_];
	if (elapse >= 2 * avgRTT_) {
		return(tcph->seqno()+1);
	}
	return(-1);
}

/******************************************************************************/
void
FastTcpAgent::fast_recv_newack_helper(Packet *pkt) {
	newack(pkt);

	if (ect_) {
		if (!hdr_flags::access(pkt)->ecnecho())
			ecn_backoff_ = 0;
		if (!ecn_burst_ && hdr_flags::access(pkt)->ecnecho())
			ecn_burst_ = TRUE;
		else if (ecn_burst_ && ! hdr_flags::access(pkt)->ecnecho())
			ecn_burst_ = FALSE;
	}
	if (!ect_ && hdr_flags::access(pkt)->ecnecho() &&
		!hdr_flags::access(pkt)->cong_action())
		ect_ = 1;
	/* if the connection is done, call finish() */
	if ((highest_ack_ >= curseq_-1) && !closed_) {
		closed_ = 1;
		finish();
	}
	if (QOption_ && curseq_ == highest_ack_ +1) {
		cancel_rtx_timer();
	}
}

⌨️ 快捷键说明

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