Main Page | Namespace List | Class Hierarchy | Class List | Directories | File List | Namespace Members | Class Members | File Members | Related Pages

TCPBaseAlg Class Reference

#include <TCPBaseAlg.h>

Inheritance diagram for TCPBaseAlg:

TCPAlgorithm TCPNoCongestionControl TCPTahoeRenoFamily TCPReno TCPTahoe List of all members.

Detailed Description

Includes basic TCP algorithms: adaptive retransmission, persist timer, keep-alive, delayed acks -- EXCLUDING congestion control. Congestion control is implemented in subclasses such as TCPTahoeAlg or TCPRenoAlg.

Implements:

To be done:

Note: currently the timers and time calculations are done in double and NOT in Unix (200ms or 500ms) ticks. It's possible to write another TCPAlgorithm which uses ticks (or rather, factor out timer handling to separate methods, and redefine only those).

Congestion window is set to MSS when the connection is established, and not touched after that. Subclasses may redefine any of the virtual functions here to add their congestion control code.


Public Member Functions

 TCPBaseAlg ()
virtual ~TCPBaseAlg ()
virtual void initialize ()
virtual void established (bool active)
virtual void connectionClosed ()
virtual void processTimer (cMessage *timer, TCPEventCode &event)
virtual void sendCommandInvoked ()
virtual void receivedOutOfOrderSegment ()
virtual void receiveSeqChanged ()
virtual void receivedDataAck (uint32 firstSeqAcked)
virtual void receivedDuplicateAck ()
virtual void receivedAckForDataNotYetSent (uint32 seq)
virtual void ackSent ()
virtual void dataSent (uint32 fromseq)

Protected Member Functions

virtual void startRexmitTimer ()
virtual void rttMeasurementComplete (simtime_t tSent, simtime_t tAcked)
virtual bool sendData ()
cMessage * cancelEvent (cMessage *msg)
Process REXMIT, PERSIST, DELAYED-ACK and KEEP-ALIVE timers
virtual void processRexmitTimer (TCPEventCode &event)
virtual void processPersistTimer (TCPEventCode &event)
virtual void processDelayedAckTimer (TCPEventCode &event)
virtual void processKeepAliveTimer (TCPEventCode &event)

Protected Attributes

TCPBaseAlgStateVariables *& state
cMessage * rexmitTimer
cMessage * persistTimer
cMessage * delayedAckTimer
cMessage * keepAliveTimer
cOutVector * cwndVector
cOutVector * ssthreshVector
cOutVector * rttVector
cOutVector * srttVector
cOutVector * rttvarVector
cOutVector * rtoVector


Constructor & Destructor Documentation

TCPBaseAlg::TCPBaseAlg  ) 
 

Ctor.

00090                        : TCPAlgorithm(),
00091   state((TCPBaseAlgStateVariables *&)TCPAlgorithm::state)
00092 {
00093     rexmitTimer = persistTimer = delayedAckTimer = keepAliveTimer = NULL;
00094     cwndVector = ssthreshVector = rttVector = srttVector = rttvarVector = rtoVector = NULL;
00095 }

TCPBaseAlg::~TCPBaseAlg  )  [virtual]
 

Virtual dtor.

00098 {
00099     // Note: don't delete "state" here, it'll be deleted from TCPConnection
00100 
00101     // cancel and delete timers
00102     if (rexmitTimer)     delete cancelEvent(rexmitTimer);
00103     if (persistTimer)    delete cancelEvent(persistTimer);
00104     if (delayedAckTimer) delete cancelEvent(delayedAckTimer);
00105     if (keepAliveTimer)  delete cancelEvent(keepAliveTimer);
00106 
00107     // delete statistics objects
00108     delete cwndVector;
00109     delete ssthreshVector;
00110     delete rttVector;
00111     delete srttVector;
00112     delete rttvarVector;
00113     delete rtoVector;
00114 }


Member Function Documentation

void TCPBaseAlg::ackSent  )  [virtual]
 

Called after we sent an ACK. This hook can be used to cancel the delayed-ACK timer.

Implements TCPAlgorithm.

00417 {
00418     // if delayed ACK timer is running, cancel it
00419     if (delayedAckTimer->isScheduled())
00420         cancelEvent(delayedAckTimer);
00421 }

cMessage* TCPBaseAlg::cancelEvent cMessage *  msg  )  [inline, protected]
 

Utility function

00133 {return conn->getTcpMain()->cancelEvent(msg);}

void TCPBaseAlg::connectionClosed  )  [virtual]
 

Called when the connection closes, it should cancel all running timers.

Implements TCPAlgorithm.

00158 {
00159     cancelEvent(rexmitTimer);
00160     cancelEvent(persistTimer);
00161     cancelEvent(delayedAckTimer);
00162     cancelEvent(keepAliveTimer);
00163 }

void TCPBaseAlg::dataSent uint32  fromseq  )  [virtual]
 

Called after we sent data. This hook can be used to schedule the retransmission timer, to start round-trip time measurement, etc. The argument is the seqno of the first byte sent.

Implements TCPAlgorithm.

00424 {
00425     // if retransmission timer not running, schedule it
00426     if (!rexmitTimer->isScheduled())
00427     {
00428         tcpEV << "Starting REXMIT timer\n";
00429         startRexmitTimer();
00430     }
00431 
00432     // start round-trip time measurement (if not already running)
00433     if (state->rtseq_sendtime==0)
00434     {
00435         // remember this sequence number and when it was sent
00436         state->rtseq = fromseq;
00437         state->rtseq_sendtime = conn->getTcpMain()->simTime();
00438         tcpEV << "Starting rtt measurement on seq=" << state->rtseq << "\n";
00439     }
00440 }

void TCPBaseAlg::established bool  active  )  [virtual]
 

Called when the connection is going to ESTABLISHED from SYN_SENT or SYN_RCVD. This is a place to initialize some variables (e.g. set cwnd to the MSS learned during connection setup). If we are on the active side, here we also have to finish the 3-way connection setup procedure by sending an ACK, possibly piggybacked on data.

Implements TCPAlgorithm.

00142 {
00143     // initialize cwnd (we may learn MSS during connection setup --
00144     // this (MSS TCP option) is not implemented yet though)
00145     state->snd_cwnd = state->snd_mss;
00146     if (cwndVector) cwndVector->record(state->snd_cwnd);
00147 
00148     if (active)
00149     {
00150         // finish connection setup with ACK (possibly piggybacked on data)
00151         tcpEV << "Completing connection setup by sending ACK (possibly piggybacked on data)\n";
00152         if (!sendData())
00153             conn->sendAck();
00154     }
00155 }

void TCPBaseAlg::initialize  )  [virtual]
 

Create timers, etc.

Reimplemented from TCPAlgorithm.

Reimplemented in TCPNoCongestionControl.

00117 {
00118     TCPAlgorithm::initialize();
00119 
00120     rexmitTimer = new cMessage("REXMIT");
00121     persistTimer = new cMessage("PERSIST");
00122     delayedAckTimer = new cMessage("DELAYEDACK");
00123     keepAliveTimer = new cMessage("KEEPALIVE");
00124 
00125     rexmitTimer->setContextPointer(conn);
00126     persistTimer->setContextPointer(conn);
00127     delayedAckTimer->setContextPointer(conn);
00128     keepAliveTimer->setContextPointer(conn);
00129 
00130     if (conn->getTcpMain()->recordStatistics)
00131     {
00132         cwndVector = new cOutVector("cwnd");
00133         ssthreshVector = new cOutVector("ssthresh");
00134         rttVector = new cOutVector("measured RTT");
00135         srttVector = new cOutVector("smoothed RTT");
00136         rttvarVector = new cOutVector("RTTVAR");
00137         rtoVector = new cOutVector("RTO");
00138     }
00139 }

void TCPBaseAlg::processDelayedAckTimer TCPEventCode event  )  [protected, virtual]
 

00236 {
00237     conn->sendAck();
00238 }

void TCPBaseAlg::processKeepAliveTimer TCPEventCode event  )  [protected, virtual]
 

00241 {
00242     // FIXME TBD
00243 }

void TCPBaseAlg::processPersistTimer TCPEventCode event  )  [protected, virtual]
 

00230 {
00231     // FIXME TBD finish (currently Persist Timer never gets scheduled)
00232     conn->sendProbe();
00233 }

void TCPBaseAlg::processRexmitTimer TCPEventCode event  )  [protected, virtual]
 

Reimplemented in TCPNoCongestionControl, TCPReno, and TCPTahoe.

00180 {
00181     //"
00182     // For any state if the retransmission timeout expires on a segment in
00183     // the retransmission queue, send the segment at the front of the
00184     // retransmission queue again, reinitialize the retransmission timer,
00185     // and return.
00186     //"
00187     // Also: abort connection after max 12 retries.
00188     //
00189     // However, retransmission is actually more complicated than that
00190     // in RFC 793 above, we'll leave it to subclasses (e.g. TCPTahoe, TCPReno).
00191     //
00192     if (++state->rexmit_count > MAX_REXMIT_COUNT)
00193     {
00194         tcpEV << "Retransmission count exceeds " << MAX_REXMIT_COUNT << ", aborting connection\n";
00195         conn->signalConnectionTimeout();
00196         event = TCP_E_ABORT;  // TBD maybe rather introduce a TCP_E_TIMEDOUT event
00197         return;
00198     }
00199 
00200     tcpEV << "Performing retransmission #" << state->rexmit_count
00201           << "; increasing RTO from " << state->rexmit_timeout << "s ";
00202 
00203     //
00204     // Karn's algorithm is implemented below:
00205     //  (1) don't measure RTT for retransmitted packets.
00206     //  (2) RTO should be doubled after retransmission ("exponential back-off")
00207     //
00208 
00209     // restart the retransmission timer with twice the latest RTO value, or with the max, whichever is smaller
00210     state->rexmit_timeout += state->rexmit_timeout;
00211     if (state->rexmit_timeout > MAX_REXMIT_TIMEOUT)
00212         state->rexmit_timeout = MAX_REXMIT_TIMEOUT;
00213     conn->scheduleTimeout(rexmitTimer, state->rexmit_timeout);
00214 
00215     tcpEV << " to " << state->rexmit_timeout << "s, and cancelling RTT measurement\n";
00216 
00217     // cancel round-trip time measurement
00218     state->rtseq_sendtime = 0;
00219 
00220     //
00221     // Leave congestion window management and actual retransmission to
00222     // subclasses (e.g. TCPTahoe, TCPReno).
00223     //
00224     // That is, subclasses will redefine this method, call us, then perform
00225     // window adjustments and do the retransmission as they like.
00226     //
00227 }

void TCPBaseAlg::processTimer cMessage *  timer,
TCPEventCode event
[virtual]
 

Process REXMIT, PERSIST, DELAYED-ACK and KEEP-ALIVE timers.

Implements TCPAlgorithm.

00166 {
00167     if (timer==rexmitTimer)
00168         processRexmitTimer(event);
00169     else if (timer==persistTimer)
00170         processPersistTimer(event);
00171     else if (timer==delayedAckTimer)
00172         processDelayedAckTimer(event);
00173     else if (timer==keepAliveTimer)
00174         processKeepAliveTimer(event);
00175     else
00176         throw new cException(timer, "unrecognized timer");
00177 }

void TCPBaseAlg::receivedAckForDataNotYetSent uint32  seq  )  [virtual]
 

Called after we received an ACK for data not yet sent. According to RFC 793 this function should send an ACK.

Implements TCPAlgorithm.

00411 {
00412     tcpEV << "ACK acks something not yet sent, sending immediate ACK\n";
00413     conn->sendAck();
00414 }

void TCPBaseAlg::receivedDataAck uint32  firstSeqAcked  )  [virtual]
 

Called after we received an ACK which acked some data (that is, we could advance snd_una). At this point the state variables (snd_una, snd_wnd) have already been updated. The argument firstSeqAcked is the previous snd_una value, that is, the number of bytes acked is (snd_una-firstSeqAcked). The dupack counter still reflects the old value (needed for Reno and NewReno); it'll be reset to 0 after this call returns.

Implements TCPAlgorithm.

Reimplemented in TCPNoCongestionControl, TCPReno, and TCPTahoe.

00347 {
00348     // if round-trip time measurement is running, check if rtseq has been acked
00349     if (state->rtseq_sendtime!=0 && seqLess(state->rtseq, state->snd_una))
00350     {
00351         // print value
00352         tcpEV << "Round-trip time measured on rtseq=" << state->rtseq << ": "
00353               << int((conn->getTcpMain()->simTime() - state->rtseq_sendtime)*1000+0.5) << "ms\n";
00354 
00355         // update RTT variables with new value
00356         rttMeasurementComplete(state->rtseq_sendtime, conn->getTcpMain()->simTime());
00357 
00358         // measurement finished
00359         state->rtseq_sendtime = 0;
00360     }
00361 
00362     //
00363     // handling of retransmission timer: if the ACK is for the last segment sent
00364     // (no data in flight), cancel the timer, otherwise restart the timer
00365     // with the current RTO value.
00366     //
00367     if (state->snd_una==state->snd_max)
00368     {
00369         if (rexmitTimer->isScheduled())
00370         {
00371             tcpEV << "ACK acks all outstanding segments, cancel REXMIT timer\n";
00372             cancelEvent(rexmitTimer);
00373         }
00374         else
00375         {
00376             tcpEV << "There were no outstanding segments, nothing new in this ACK.\n";
00377         }
00378     }
00379     else
00380     {
00381         tcpEV << "ACK acks some but not all outstanding segments ("
00382               << (state->snd_max - state->snd_una) << " bytes outstanding), "
00383               << "restarting REXMIT timer\n";
00384         cancelEvent(rexmitTimer);
00385         startRexmitTimer();
00386     }
00387 
00388     //
00389     // Leave congestion window management and possible sending data to
00390     // subclasses (e.g. TCPTahoe, TCPReno).
00391     //
00392     // That is, subclasses will redefine this method, call us, then perform
00393     // window adjustments and send data (if there's room in the window).
00394     //
00395 }

void TCPBaseAlg::receivedDuplicateAck  )  [virtual]
 

Called after we received a duplicate ACK (that is: ackNo==snd_una, no data in segment, segment doesn't carry window update, and also, we have unacked data). The dupack counter got already updated when calling this method (i.e. dupack==1 on first duplicate ACK.)

Implements TCPAlgorithm.

Reimplemented in TCPReno, and TCPTahoe.

00398 {
00399     tcpEV << "Duplicate ACK #" << state->dupacks << "\n";
00400 
00401     //
00402     // Leave to subclasses (e.g. TCPTahoe, TCPReno) whatever they want to do
00403     // on duplicate Acks.
00404     //
00405     // That is, subclasses will redefine this method, call us, then perform
00406     // whatever action they want to do on dupAcks (e.g. retransmitting one segment).
00407     //
00408 }

void TCPBaseAlg::receivedOutOfOrderSegment  )  [virtual]
 

Called after receiving data which are in the window, but not at its left edge (seq!=rcv_nxt). This indicates that either segments got re-ordered in the way, or one segment was lost. RFC1122 and RFC2001 recommend sending an immediate ACK here (Fast Retransmit relies on that).

Implements TCPAlgorithm.

00324 {
00325     tcpEV << "Out-of-order segment, sending immediate ACK\n";
00326     conn->sendAck();
00327 }

void TCPBaseAlg::receiveSeqChanged  )  [virtual]
 

Called after rcv_nxt got advanced, either because we received in-sequence data ("text" in RFC 793 lingo) or a FIN. At this point, rcv_nxt has already been updated. This method should take care to send or schedule an ACK some time.

Implements TCPAlgorithm.

00330 {
00331     if (!state->delayed_acks_enabled)
00332     {
00333         tcpEV << "rcv_nxt changed to " << state->rcv_nxt << ", sending ACK now (delayed ACKs are disabled)\n";
00334         conn->sendAck();
00335     }
00336     else
00337     {
00338         // FIXME ACK should be generated for at least every second SMSS-sized segment!
00339         // schedule delayed ACK timer if not already running
00340         tcpEV << "rcv_nxt changed to " << state->rcv_nxt << ", scheduling ACK\n";
00341         if (!delayedAckTimer->isScheduled())
00342             conn->scheduleTimeout(delayedAckTimer, DELAYED_ACK_TIMEOUT);
00343     }
00344 }

void TCPBaseAlg::rttMeasurementComplete simtime_t  tSent,
simtime_t  tAcked
[protected, virtual]
 

Update state vars with new measured RTT value. Passing two simtime_t's will allow rttMeasurementComplete() to do calculations in double or in 200ms/500ms ticks, as needed)

00256 {
00257     //
00258     // Jacobson's algorithm for estimating RTT and adaptively setting RTO.
00259     //
00260     // Note: this implementation calculates in doubles. An impl. which uses
00261     // 500ms ticks is available from old tcpmodule.cc:calcRetransTimer().
00262     //
00263 
00264     // update smoothed RTT estimate (srtt) and variance (rttvar)
00265     const double g = 0.125;   // 1/8; (1-alpha) where alpha=7/8;
00266     double newRTT = tAcked-tSent;
00267 
00268     double& srtt = state->srtt;
00269     double& rttvar = state->rttvar;
00270 
00271     double err = newRTT - srtt;
00272 
00273     srtt += g*err;
00274     rttvar += g*(fabs(err) - rttvar);
00275 
00276     // assign RTO (here: rexmit_timeout) a new value
00277     double rto = srtt + 4*rttvar;
00278     if (rto>MAX_REXMIT_TIMEOUT)
00279         rto = MAX_REXMIT_TIMEOUT;
00280     else if (rto<MIN_REXMIT_TIMEOUT)
00281         rto = MIN_REXMIT_TIMEOUT;
00282 
00283     state->rexmit_timeout = rto;
00284 
00285     // record statistics
00286     tcpEV << "Measured RTT=" << (newRTT*1000) << "ms, updated SRTT=" << (srtt*1000)
00287           << "ms, new RTO=" << (rto*1000) << "ms\n";
00288     if (rttVector) rttVector->record(newRTT);
00289     if (srttVector) srttVector->record(srtt);
00290     if (rttvarVector) rttvarVector->record(rttvar);
00291     if (rtoVector) rtoVector->record(rto);
00292 }

void TCPBaseAlg::sendCommandInvoked  )  [virtual]
 

Called after user sent TCP_C_SEND command to us.

Implements TCPAlgorithm.

00318 {
00319     // try sending
00320     sendData();
00321 }

bool TCPBaseAlg::sendData  )  [protected, virtual]
 

Send data, observing Nagle's algorithm and congestion window

00295 {
00296     //
00297     // Nagle's algorithm: when a TCP connection has outstanding data that has not
00298     // yet been acknowledged, small segments cannot be sent until the outstanding
00299     // data is acknowledged. (In this case, small amounts of data are collected
00300     // by TCP and sent in a single segment.)
00301     //
00302     // FIXME there's also something like this: can still send if
00303     // "b) a segment that can be sent is at least half the size of
00304     // the largest window ever advertised by the receiver"
00305 
00306     bool fullSegmentsOnly = state->nagle_enabled && state->snd_una!=state->snd_max;
00307     if (fullSegmentsOnly)
00308         tcpEV << "Nagle is enabled and there's unacked data: only full segments will be sent\n";
00309 
00310     //
00311     // Send window is effectively the minimum of the congestion window (cwnd)
00312     // and the advertised window (snd_wnd).
00313     //
00314     return conn->sendData(fullSegmentsOnly, state->snd_cwnd);
00315 }

void TCPBaseAlg::startRexmitTimer  )  [protected, virtual]
 

Start REXMIT timer and initialize retransmission variables

00246 {
00247     // start counting retransmissions for this seq number.
00248     // Note: state->rexmit_timeout is set from rttMeasurementComplete().
00249     state->rexmit_count = 0;
00250 
00251     // schedule timer
00252     conn->scheduleTimeout(rexmitTimer, state->rexmit_timeout);
00253 }


Member Data Documentation

cOutVector* TCPBaseAlg::cwndVector [protected]
 

cMessage* TCPBaseAlg::delayedAckTimer [protected]
 

cMessage* TCPBaseAlg::keepAliveTimer [protected]
 

cMessage* TCPBaseAlg::persistTimer [protected]
 

cMessage* TCPBaseAlg::rexmitTimer [protected]
 

cOutVector* TCPBaseAlg::rtoVector [protected]
 

cOutVector* TCPBaseAlg::rttvarVector [protected]
 

cOutVector* TCPBaseAlg::rttVector [protected]
 

cOutVector* TCPBaseAlg::srttVector [protected]
 

cOutVector* TCPBaseAlg::ssthreshVector [protected]
 

TCPBaseAlgStateVariables*& TCPBaseAlg::state [protected]
 

Reimplemented from TCPAlgorithm.

Reimplemented in TCPNoCongestionControl, TCPReno, TCPTahoe, and TCPTahoeRenoFamily.


The documentation for this class was generated from the following files:
Generated on Sat Apr 1 20:52:24 2006 for INET Framework for OMNeT++/OMNEST by  doxygen 1.4.1