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

📄 tcp-fast.c

📁 fast_tcp的源代码加上了自己对它的中文注释
💻 C
📖 第 1 页 / 共 3 页
字号:
* 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_;//平均RTT时间内收到的确认数
	
	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_)		//超过两倍的平均RTT时间,确定已经超时;
	{
		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 + -