TCP is an example of an agent which requires timers. There are three timers defined in the basic Tahoe TCP agent defined in tcp.cc:
rtx_timer_; /* Retransmission timer / delsnd_timer_; /* Delays sending of packets by a small random amount of time, / /* to avoid phase effects / burstsnd_timer_; /* Helps TCP to stagger the transmission of a large window / /* into several smaller bursts /In ~ns/tcp.h, three classes are derived from the base class TimerHandlertcp.h:
class RtxTimer : public TimerHandler { public: RtxTimer(TcpAgent *a) : TimerHandler() { a_ = a; } protected: virtual void expire(Event *e); TcpAgent *a_; }; class DelSndTimer : public TimerHandler { public: DelSndTimer(TcpAgent *a) : TimerHandler() { a_ = a; } protected: virtual void expire(Event *e); TcpAgent *a_; }; class BurstSndTimer : public TimerHandler { public: BurstSndTimer(TcpAgent *a) : TimerHandler() { a_ = a; } protected: virtual void expire(Event *e); TcpAgent *a_; };In the constructor for TcpAgent../ns-2/tcp.ccTcpAgent::TcpAgent in tcp.cc, each of these timers is initialized with the this pointer, which is assigned to the pointer a_.
TcpAgent::TcpAgent() : Agent(PT_TCP), rtt_active_(0), rtt_seq_(-1), \ldots rtx_timer_(this), delsnd_timer_(this), burstsnd_timer_(this) { \ldots }In the following, we will focus only on the retransmission timer. Various helper methods may be defined to schedule timer events; ,
/* *Set retransmit timer using current rtt estimate. By calling \fcn[]{resched} *it does not matter whether the timer was already running. */ void TcpAgent::set_rtx_timer() { rtx_timer_.resched(rtt_timeout()); } /* * Set new retransmission timer if not all outstanding * data has been acked. Otherwise, if a timer is still * outstanding, cancel it. */ void TcpAgent::newtimer(Packet* pkt) { hdr_tcp *tcph = (hdr_tcp*)pkt-\>access(off_tcp_); if (t_seqno_ \> tcph-\>seqno()) set_rtx_timer(); else if (rtx_timer_.status() == TIMER_PENDING) rtx_timer_.cancel(); }In the above code, the []set_rtx_timer method reschedules the retransmission timer by calling []rtx_timer_.resched. Note that if it is unclear whether or not the timer is already running, calling []resched eliminates the need to explicitly cancel the timer. In the second function, examples are given of the use of the []status and cancel methods.
Finally, the expire method for class RtxTimer must be defined. In this case, expire calls the timeout method for TcpAgent. This is possible because []timeout is a public member function; if it were not, then RtxTimer would have had to have been declared a friend class of TcpAgent.
void TcpAgent::timeout(int tno) { /* retransmit timer */ if (tno == TCP_TIMER_RTX) { if (highest_ack_ == maxseq_ && !slow_start_restart_) { /* * TCP option: * If no outstanding data, then don't do anything. */ return; }; recover_ = maxseq_; recover_cause_ = 2; closecwnd(0); reset_rtx_timer(0,1); send_much(0, TCP_REASON_TIMEOUT, maxburst_); } else { /* * delayed-send timer, with random overhead * to avoid phase effects */ send_much(1, TCP_REASON_TIMEOUT, maxburst_); } } void RtxTimer::expire(Event *e) { a_-\>timeout(TCP_TIMER_RTX); }
The various TCP agents contain additional examples of timers.
Tom Henderson 2011-11-05