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