Public Member Functions | Protected Member Functions | Protected Attributes

TCPBaseAlg Class Reference

#include <TCPBaseAlg.h>

Inheritance diagram for TCPBaseAlg:
TCPAlgorithm TCPNoCongestionControl TCPTahoeRenoFamily TCPNewReno TCPReno TCPTahoe

List of all members.

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)
virtual void restartRexmitTimer ()

Protected Member Functions

virtual void startRexmitTimer ()
virtual void rttMeasurementComplete (simtime_t tSent, simtime_t tAcked)
virtual void rttMeasurementCompleteUsingTS (uint32 echoedTS)
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
cOutVector * numRtosVector

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 SMSS 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.

Definition at line 102 of file TCPBaseAlg.h.


Constructor & Destructor Documentation

TCPBaseAlg::~TCPBaseAlg (  )  [virtual]

Virtual dtor.

Definition at line 102 of file flavours/TCPBaseAlg.cc.

{
    // Note: don't delete "state" here, it'll be deleted from TCPConnection

    // cancel and delete timers
    if (rexmitTimer)     delete cancelEvent(rexmitTimer);
    if (persistTimer)    delete cancelEvent(persistTimer);
    if (delayedAckTimer) delete cancelEvent(delayedAckTimer);
    if (keepAliveTimer)  delete cancelEvent(keepAliveTimer);

    // delete statistics objects
    delete cwndVector;
    delete ssthreshVector;
    delete rttVector;
    delete srttVector;
    delete rttvarVector;
    delete rtoVector;
    delete numRtosVector;
}


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.

Definition at line 642 of file flavours/TCPBaseAlg.cc.

{
    state->full_sized_segment_counter = 0; // reset counter
    state->ack_now = false; // reset flag
    state->last_ack_sent = state->rcv_nxt; // update last_ack_sent, needed for TS option
    // if delayed ACK timer is running, cancel it
    if (delayedAckTimer->isScheduled())
        cancelEvent(delayedAckTimer);
}

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

Utility function

Definition at line 153 of file TCPBaseAlg.h.

Referenced by ackSent(), connectionClosed(), receivedDataAck(), restartRexmitTimer(), and ~TCPBaseAlg().

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

void TCPBaseAlg::connectionClosed (  )  [virtual]

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

Implements TCPAlgorithm.

Definition at line 205 of file flavours/TCPBaseAlg.cc.

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.

Definition at line 652 of file flavours/TCPBaseAlg.cc.

{
    // if retransmission timer not running, schedule it
    if (!rexmitTimer->isScheduled())
    {
        tcpEV << "Starting REXMIT timer\n";
        startRexmitTimer();
    }

    if (!state->ts_enabled)
    {
        // start round-trip time measurement (if not already running)
        if (state->rtseq_sendtime==0)
        {
            // remember this sequence number and when it was sent
            state->rtseq = fromseq;
            state->rtseq_sendtime = simTime();
            tcpEV << "Starting rtt measurement on seq=" << state->rtseq << "\n";
        }
    }

    state->time_last_data_sent = simTime();
}

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.

Definition at line 148 of file flavours/TCPBaseAlg.cc.

{
    // initialize cwnd (we may learn SMSS during connection setup)

    // RFC 3390, page 2: "The upper bound for the initial window is given more precisely in
    // (1):
    //
    //   min (4*MSS, max (2*MSS, 4380 bytes))                        (1)
    //
    // Note: Sending a 1500 byte packet indicates a maximum segment size
    // (MSS) of 1460 bytes (assuming no IP or TCP options).  Therefore,
    // limiting the initial window's MSS to 4380 bytes allows the sender to
    // transmit three segments initially in the common case when using 1500
    // byte packets.
    //
    // Equivalently, the upper bound for the initial window size is based on
    // the MSS, as follows:
    //
    //   If (MSS <= 1095 bytes)
    //     then win <= 4 * MSS;
    //   If (1095 bytes < MSS < 2190 bytes)
    //     then win <= 4380;
    //   If (2190 bytes <= MSS)
    //     then win <= 2 * MSS;
    //
    // This increased initial window is optional: a TCP MAY start with a
    // larger initial window.  However, we expect that most general-purpose
    // TCP implementations would choose to use the larger initial congestion
    // window given in equation (1) above.
    //
    // This upper bound for the initial window size represents a change from
    // RFC 2581 [RFC2581], which specified that the congestion window be
    // initialized to one or two segments.
    // (...)
    // If the SYN or SYN/ACK is
    // lost, the initial window used by a sender after a correctly
    // transmitted SYN MUST be one segment consisting of MSS bytes."
    if (state->increased_IW_enabled && state->syn_rexmit_count==0)
    {
        state->snd_cwnd = std::min(4 * state->snd_mss, std::max(2 * state->snd_mss, (uint32)4380));
        tcpEV << "Enabled Increased Initial Window, CWND is set to: " << state->snd_cwnd << "\n";
    }
    // RFC 2001, page 3:
    // " 1.  Initialization for a given connection sets cwnd to one segment
    // and ssthresh to 65535 bytes."
    else
        state->snd_cwnd = state->snd_mss; // RFC 2001

    if (active)
    {
        // finish connection setup with ACK (possibly piggybacked on data)
        tcpEV << "Completing connection setup by sending ACK (possibly piggybacked on data)\n";
        if (!sendData()) // FIXME TODO - This condition is never true because the buffer is empty (at this time) therefore the first ACK is never piggyback on data
            conn->sendAck();
    }
}

void TCPBaseAlg::initialize (  )  [virtual]

Create timers, etc.

Reimplemented from TCPAlgorithm.

Reimplemented in TCPNoCongestionControl.

Definition at line 122 of file flavours/TCPBaseAlg.cc.

{
    TCPAlgorithm::initialize();

    rexmitTimer = new cMessage("REXMIT");
    persistTimer = new cMessage("PERSIST");
    delayedAckTimer = new cMessage("DELAYEDACK");
    keepAliveTimer = new cMessage("KEEPALIVE");

    rexmitTimer->setContextPointer(conn);
    persistTimer->setContextPointer(conn);
    delayedAckTimer->setContextPointer(conn);
    keepAliveTimer->setContextPointer(conn);

    if (conn->getTcpMain()->recordStatistics)
    {
        cwndVector = new cOutVector("cwnd");
        ssthreshVector = new cOutVector("ssthresh");
        rttVector = new cOutVector("measured RTT");
        srttVector = new cOutVector("smoothed RTT");
        rttvarVector = new cOutVector("RTTVAR");
        rtoVector = new cOutVector("RTO");
        numRtosVector = new cOutVector("numRTOs");
    }
}

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

Definition at line 331 of file flavours/TCPBaseAlg.cc.

Referenced by processTimer().

{
    state->ack_now = true;
    conn->sendAck();
}

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

Definition at line 337 of file flavours/TCPBaseAlg.cc.

Referenced by processTimer().

{
    // TBD
    // RFC 1122, page 102:
    // "A "keep-alive" mechanism periodically probes the other
    // end of a connection when the connection is otherwise
    // idle, even when there is no data to be sent.  The TCP
    // specification does not include a keep-alive mechanism
    // because it could:  (1) cause perfectly good connections
    // to break during transient Internet failures; (2)
    // consume unnecessary bandwidth ("if no one is using the
    // connection, who cares if it is still good?"); and (3)
    // cost money for an Internet path that charges for
    // packets."
}

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

Definition at line 306 of file flavours/TCPBaseAlg.cc.

Referenced by processTimer().

{
    // setup and restart the PERSIST timer
    // FIXME Calculation of PERSIST timer is not as simple as done here!
    // It depends on RTT calculations and is bounded to 5-60 seconds.
    // This simplified PERSIST timer calculation generates values
    // as presented in [Stevens, W.R.: TCP/IP Illustrated, Volume 1, chapter 22.2]
    // (5, 5, 6, 12, 24, 48, 60, 60, 60...)
    if (state->persist_factor == 0)
        state->persist_factor++;
    else if (state->persist_factor < 64)
        state->persist_factor = state->persist_factor*2;
    state->persist_timeout = state->persist_factor * 1.5; // 1.5 is a factor for typical LAN connection [Stevens, W.R.: TCP/IP Ill. Vol. 1, chapter 22.2]

    // PERSIST timer is bounded to 5-60 seconds
    if (state->persist_timeout < MIN_PERSIST_TIMEOUT)
        state->rexmit_timeout = MIN_PERSIST_TIMEOUT;
    if (state->persist_timeout > MAX_PERSIST_TIMEOUT)
        state->rexmit_timeout = MAX_PERSIST_TIMEOUT;
    conn->scheduleTimeout(persistTimer, state->persist_timeout);

    // sending persist probe
    conn->sendProbe();
}

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

Reimplemented in TCPNewReno, TCPNoCongestionControl, TCPReno, and TCPTahoe.

Definition at line 227 of file flavours/TCPBaseAlg.cc.

Referenced by processTimer().

{
    tcpEV << "TCB: " << state->info() << "\n";

    //"
    // For any state if the retransmission timeout expires on a segment in
    // the retransmission queue, send the segment at the front of the
    // retransmission queue again, reinitialize the retransmission timer,
    // and return.
    //"
    // Also: abort connection after max 12 retries.
    //
    // However, retransmission is actually more complicated than that
    // in RFC 793 above, we'll leave it to subclasses (e.g. TCPTahoe, TCPReno).
    //
    if (++state->rexmit_count > MAX_REXMIT_COUNT)
    {
        tcpEV << "Retransmission count exceeds " << MAX_REXMIT_COUNT << ", aborting connection\n";
        conn->signalConnectionTimeout();
        event = TCP_E_ABORT;  // TBD maybe rather introduce a TCP_E_TIMEDOUT event
        return;
    }

    tcpEV << "Performing retransmission #" << state->rexmit_count
          << "; increasing RTO from " << state->rexmit_timeout << "s ";

    //
    // Karn's algorithm is implemented below:
    //  (1) don't measure RTT for retransmitted packets.
    //  (2) RTO should be doubled after retransmission ("exponential back-off")
    //

    // restart the retransmission timer with twice the latest RTO value, or with the max, whichever is smaller
    state->rexmit_timeout += state->rexmit_timeout;
    if (state->rexmit_timeout > MAX_REXMIT_TIMEOUT)
        state->rexmit_timeout = MAX_REXMIT_TIMEOUT;
    conn->scheduleTimeout(rexmitTimer, state->rexmit_timeout);

    tcpEV << " to " << state->rexmit_timeout << "s, and cancelling RTT measurement\n";

    // cancel round-trip time measurement
    state->rtseq_sendtime = 0;

    state->numRtos++;
    if (numRtosVector)
        numRtosVector->record(state->numRtos);

    // if sacked_enabled reset sack related flags
    if (state->sack_enabled)
    {
        conn->rexmitQueue->resetSackedBit();
        conn->rexmitQueue->resetRexmittedBit();

        // RFC 3517, page 8: "If an RTO occurs during loss recovery as specified in this document,
        // RecoveryPoint MUST be set to HighData.  Further, the new value of
        // RecoveryPoint MUST be preserved and the loss recovery algorithm
        // outlined in this document MUST be terminated.  In addition, a new
        // recovery phase (as described in section 5) MUST NOT be initiated
        // until HighACK is greater than or equal to the new value of
        // RecoveryPoint."
        if (state->lossRecovery)
        {
            state->recoveryPoint = state->snd_max; // HighData = snd_max
            tcpEV << "Loss Recovery terminated.\n";
            state->lossRecovery = false;
        }
    }

    state->time_last_data_sent = simTime();

    //
    // Leave congestion window management and actual retransmission to
    // subclasses (e.g. TCPTahoe, TCPReno).
    //
    // That is, subclasses will redefine this method, call us, then perform
    // window adjustments and do the retransmission as they like.
    //
}

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

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

Implements TCPAlgorithm.

Definition at line 213 of file flavours/TCPBaseAlg.cc.

{
    if (timer==rexmitTimer)
        processRexmitTimer(event);
    else if (timer==persistTimer)
        processPersistTimer(event);
    else if (timer==delayedAckTimer)
        processDelayedAckTimer(event);
    else if (timer==keepAliveTimer)
        processKeepAliveTimer(event);
    else
        throw cRuntimeError(timer, "unrecognized timer");
}

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.

Definition at line 631 of file flavours/TCPBaseAlg.cc.

{
    // Note: In this case no immediate ACK will be send because not mentioned
    // in [Stevens, W.R.: TCP/IP Illustrated, Volume 2, page 861].
    // To force immediate ACK use:
        // state->ack_now = true;
        // tcpEV << "ACK acks something not yet sent, sending immediate ACK\n";
    tcpEV << "ACK acks something not yet sent, sending ACK\n";
    conn->sendAck();
}

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 TCPNewReno, TCPNoCongestionControl, TCPReno, and TCPTahoe.

Definition at line 520 of file flavours/TCPBaseAlg.cc.

{
    if (!state->ts_enabled)
    {
        // if round-trip time measurement is running, check if rtseq has been acked
        if (state->rtseq_sendtime!=0 && seqLess(state->rtseq, state->snd_una))
        {
            // print value
            tcpEV << "Round-trip time measured on rtseq=" << state->rtseq << ": "
                  << floor((simTime() - state->rtseq_sendtime)*1000+0.5) << "ms\n";

            rttMeasurementComplete(state->rtseq_sendtime, simTime()); // update RTT variables with new value

            // measurement finished
            state->rtseq_sendtime = 0;
        }
    }

    //
    // handling of retransmission timer: if the ACK is for the last segment sent
    // (no data in flight), cancel the timer, otherwise restart the timer
    // with the current RTO value.
    //
    if (state->snd_una==state->snd_max)
    {
        if (rexmitTimer->isScheduled())
        {
            tcpEV << "ACK acks all outstanding segments, cancel REXMIT timer\n";
            cancelEvent(rexmitTimer);
        }
        else
            tcpEV << "There were no outstanding segments, nothing new in this ACK.\n";
    }
    else
    {
        tcpEV << "ACK acks some but not all outstanding segments ("
              << (state->snd_max - state->snd_una) << " bytes outstanding), "
              << "restarting REXMIT timer\n";
        cancelEvent(rexmitTimer);
        startRexmitTimer();
    }

    //
    // handling of PERSIST timer:
    // If data sender received a zero-sized window, check retransmission timer.
    //  If retransmission timer is not scheduled, start PERSIST timer if not already
    //  running.
    //
    // If data sender received a non zero-sized window, check PERSIST timer.
    //  If PERSIST timer is scheduled, cancel PERSIST timer.
    //
    if (state->snd_wnd==0) // received zero-sized window?
    {
        if (rexmitTimer->isScheduled())
        {
            if (persistTimer->isScheduled())
            {
                tcpEV << "Received zero-sized window and REXMIT timer is running therefore PERSIST timer is canceled.\n";
                cancelEvent(persistTimer);
                state->persist_factor = 0;
            }
            else
                tcpEV << "Received zero-sized window and REXMIT timer is running therefore PERSIST timer is not started.\n";
        }
        else
        {
            if (!persistTimer->isScheduled())
            {
                tcpEV << "Received zero-sized window therefore PERSIST timer is started.\n";
                conn->scheduleTimeout(persistTimer, state->persist_timeout);
            }
            else
                tcpEV << "Received zero-sized window and PERSIST timer is already running.\n";
        }
    }
    else // received non zero-sized window?
    {
        if (persistTimer->isScheduled())
        {
            tcpEV << "Received non zero-sized window therefore PERSIST timer is canceled.\n";
            cancelEvent(persistTimer);
            state->persist_factor = 0;
        }
    }

    //
    // Leave congestion window management and possible sending data to
    // subclasses (e.g. TCPTahoe, TCPReno).
    //
    // That is, subclasses will redefine this method, call us, then perform
    // window adjustments and send data (if there's room in the window).
    //
}

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 TCPNewReno, TCPReno, and TCPTahoe.

Definition at line 614 of file flavours/TCPBaseAlg.cc.

{
    tcpEV << "Duplicate ACK #" << state->dupacks << "\n";

    bool fullSegmentsOnly = state->nagle_enabled && state->snd_una!=state->snd_max;
    if (state->dupacks < DUPTHRESH && state->limited_transmit_enabled) // DUPTRESH = 3
        conn->sendOneNewSegment(fullSegmentsOnly, state->snd_cwnd); // RFC 3042

    //
    // Leave to subclasses (e.g. TCPTahoe, TCPReno) whatever they want to do
    // on duplicate Acks.
    //
    // That is, subclasses will redefine this method, call us, then perform
    // whatever action they want to do on dupAcks (e.g. retransmitting one segment).
    //
}

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. RFC 1122 and RFC 2001 recommend sending an immediate ACK here (Fast Retransmit relies on that).

Implements TCPAlgorithm.

Definition at line 467 of file flavours/TCPBaseAlg.cc.

{
    state->ack_now = true;
    tcpEV << "Out-of-order segment, sending immediate ACK\n";
    conn->sendAck();
}

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.

Definition at line 474 of file flavours/TCPBaseAlg.cc.

{
    // If we send a data segment already (with the updated seqNo) there is no need to send an additional ACK
    if (state->full_sized_segment_counter == 0 && !state->ack_now && state->last_ack_sent == state->rcv_nxt && !delayedAckTimer->isScheduled()) // ackSent?
    {
        // tcpEV << "ACK has already been sent (possibly piggybacked on data)\n";
    }
    else
    {
        // RFC 2581, page 6:
        // "3.2 Fast Retransmit/Fast Recovery
        // (...)
        // In addition, a TCP receiver SHOULD send an immediate ACK
        // when the incoming segment fills in all or part of a gap in the
        // sequence space."
        if (state->lossRecovery)
            state->ack_now = true; // although not mentioned in [Stevens, W.R.: TCP/IP Illustrated, Volume 2, page 861] seems like we have to set ack_now

        if (!state->delayed_acks_enabled) // delayed ACK disabled
        {
            tcpEV << "rcv_nxt changed to " << state->rcv_nxt << ", (delayed ACK disabled) sending ACK now\n";
            conn->sendAck();
        }
        else // delayed ACK enabled
        {
            if (state->ack_now)
            {
                tcpEV << "rcv_nxt changed to " << state->rcv_nxt << ", (delayed ACK enabled, but ack_now is set) sending ACK now\n";
                conn->sendAck();
            }
            // RFC 1122, page 96: "in a stream of full-sized segments there SHOULD be an ACK for at least every second segment."
            else if (state->full_sized_segment_counter >= 2)
            {
                tcpEV << "rcv_nxt changed to " << state->rcv_nxt << ", (delayed ACK enabled, but full_sized_segment_counter=" << state->full_sized_segment_counter << ") sending ACK now\n";
                conn->sendAck();
            }
            else
            {
                tcpEV << "rcv_nxt changed to " << state->rcv_nxt << ", (delayed ACK enabled and full_sized_segment_counter=" << state->full_sized_segment_counter << ") scheduling ACK\n";
                if (!delayedAckTimer->isScheduled()) // schedule delayed ACK timer if not already running
                    conn->scheduleTimeout(delayedAckTimer, DELAYED_ACK_TIMEOUT);
            }
        }
    }
}

void TCPBaseAlg::restartRexmitTimer (  )  [virtual]

Restart REXMIT timer.

Implements TCPAlgorithm.

Definition at line 676 of file flavours/TCPBaseAlg.cc.

Referenced by TCPNewReno::receivedDataAck(), and TCPReno::receivedDuplicateAck().

{
    if (rexmitTimer->isScheduled())
        cancelEvent(rexmitTimer);
    startRexmitTimer();
}

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)

Definition at line 363 of file flavours/TCPBaseAlg.cc.

Referenced by receivedDataAck(), and rttMeasurementCompleteUsingTS().

{
    //
    // Jacobson's algorithm for estimating RTT and adaptively setting RTO.
    //
    // Note: this implementation calculates in doubles. An impl. which uses
    // 500ms ticks is available from old tcpmodule.cc:calcRetransTimer().
    //

    // update smoothed RTT estimate (srtt) and variance (rttvar)
    const double g = 0.125; // 1/8; (1-alpha) where alpha=7/8;
    simtime_t newRTT = tAcked-tSent;

    simtime_t& srtt = state->srtt;
    simtime_t& rttvar = state->rttvar;

    simtime_t err = newRTT - srtt;

    srtt += g*err;
    rttvar += g*(fabs(err) - rttvar);

    // assign RTO (here: rexmit_timeout) a new value
    simtime_t rto = srtt + 4*rttvar;
    if (rto>MAX_REXMIT_TIMEOUT)
        rto = MAX_REXMIT_TIMEOUT;
    else if (rto<MIN_REXMIT_TIMEOUT)
        rto = MIN_REXMIT_TIMEOUT;

    state->rexmit_timeout = rto;

    // record statistics
    tcpEV << "Measured RTT=" << (newRTT*1000) << "ms, updated SRTT=" << (srtt*1000)
          << "ms, new RTO=" << (rto*1000) << "ms\n";
    if (rttVector) rttVector->record(newRTT);
    if (srttVector) srttVector->record(srtt);
    if (rttvarVector) rttvarVector->record(rttvar);
    if (rtoVector) rtoVector->record(rto);
}

void TCPBaseAlg::rttMeasurementCompleteUsingTS ( uint32  echoedTS  )  [protected, virtual]

Converting uint32 echoedTS to simtime_t and calling rttMeasurementComplete() to update state vars with new measured RTT value.

Implements TCPAlgorithm.

Definition at line 402 of file flavours/TCPBaseAlg.cc.

{
    ASSERT (state->ts_enabled);
    // Note: The TS option is using uint32 values (ms precision) therefore we convert the current simTime also to a uint32 value (ms precision)
    // and then convert back to simtime_t to use rttMeasurementComplete() to update srtt and rttvar
    uint32 now = conn->convertSimtimeToTS(simTime());
    simtime_t tSent = conn->convertTSToSimtime(echoedTS);
    simtime_t tAcked = conn->convertTSToSimtime(now);
    rttMeasurementComplete(tSent, tAcked);
}

void TCPBaseAlg::sendCommandInvoked (  )  [virtual]

Called after user sent TCP_C_SEND command to us.

Implements TCPAlgorithm.

Definition at line 461 of file flavours/TCPBaseAlg.cc.

{
    // try sending
    sendData();
}

bool TCPBaseAlg::sendData (  )  [protected, virtual]

Send data, observing Nagle's algorithm and congestion window

Definition at line 413 of file flavours/TCPBaseAlg.cc.

Referenced by established(), TCPTahoe::receivedDataAck(), TCPReno::receivedDataAck(), TCPNoCongestionControl::receivedDataAck(), TCPNewReno::receivedDataAck(), TCPReno::receivedDuplicateAck(), TCPNewReno::receivedDuplicateAck(), and sendCommandInvoked().

{
    //
    // Nagle's algorithm: when a TCP connection has outstanding data that has not
    // yet been acknowledged, small segments cannot be sent until the outstanding
    // data is acknowledged. (In this case, small amounts of data are collected
    // by TCP and sent in a single segment.)
    //
    // FIXME there's also something like this: can still send if
    // "b) a segment that can be sent is at least half the size of
    // the largest window ever advertised by the receiver"

    bool fullSegmentsOnly = state->nagle_enabled && state->snd_una!=state->snd_max;
    if (fullSegmentsOnly)
        tcpEV << "Nagle is enabled and there's unacked data: only full segments will be sent\n";

    // RFC 2581, pages 7 and 8: "When TCP has not received a segment for
    // more than one retransmission timeout, cwnd is reduced to the value
    // of the restart window (RW) before transmission begins.
    // For the purposes of this standard, we define RW = IW.
    // (...)
    // Using the last time a segment was received to determine whether or
    // not to decrease cwnd fails to deflate cwnd in the common case of
    // persistent HTTP connections [HTH98].
    // (...)
    // Therefore, a TCP SHOULD set cwnd to no more than RW before beginning
    // transmission if the TCP has not sent data in an interval exceeding
    // the retransmission timeout."
    if (!conn->isSendQueueEmpty())  // do we have any data to send?
    {
        if ((simTime() - state->time_last_data_sent) > state->rexmit_timeout)
        {
            // RFC 5681, page 11: "For the purposes of this standard, we define RW = min(IW,cwnd)."
            if (state->increased_IW_enabled)
                state->snd_cwnd = std::min (std::min (4 * state->snd_mss, std::max(2 * state->snd_mss, (uint32)4380)), state->snd_cwnd);
            else
                state->snd_cwnd = state->snd_mss;
            tcpEV << "Restarting idle connection, CWND is set to: " << state->snd_cwnd << "\n";
        }
    }

    //
    // Send window is effectively the minimum of the congestion window (cwnd)
    // and the advertised window (snd_wnd).
    //
    return conn->sendData(fullSegmentsOnly, state->snd_cwnd);
}

void TCPBaseAlg::startRexmitTimer (  )  [protected, virtual]

Start REXMIT timer and initialize retransmission variables

Definition at line 353 of file flavours/TCPBaseAlg.cc.

Referenced by dataSent(), receivedDataAck(), and restartRexmitTimer().

{
    // start counting retransmissions for this seq number.
    // Note: state->rexmit_timeout is set from rttMeasurementComplete().
    state->rexmit_count = 0;

    // schedule timer
    conn->scheduleTimeout(rexmitTimer, state->rexmit_timeout);
}


Member Data Documentation

cMessage* TCPBaseAlg::keepAliveTimer [protected]

Definition at line 110 of file TCPBaseAlg.h.

Referenced by connectionClosed(), initialize(), processTimer(), TCPBaseAlg(), and ~TCPBaseAlg().

cOutVector* TCPBaseAlg::numRtosVector [protected]

Definition at line 118 of file TCPBaseAlg.h.

Referenced by initialize(), processRexmitTimer(), TCPBaseAlg(), and ~TCPBaseAlg().

cOutVector* TCPBaseAlg::rtoVector [protected]

Definition at line 117 of file TCPBaseAlg.h.

Referenced by initialize(), rttMeasurementComplete(), TCPBaseAlg(), and ~TCPBaseAlg().

cOutVector* TCPBaseAlg::rttvarVector [protected]

Definition at line 116 of file TCPBaseAlg.h.

Referenced by initialize(), rttMeasurementComplete(), TCPBaseAlg(), and ~TCPBaseAlg().

cOutVector* TCPBaseAlg::rttVector [protected]

Definition at line 114 of file TCPBaseAlg.h.

Referenced by initialize(), rttMeasurementComplete(), TCPBaseAlg(), and ~TCPBaseAlg().

cOutVector* TCPBaseAlg::srttVector [protected]

Definition at line 115 of file TCPBaseAlg.h.

Referenced by initialize(), rttMeasurementComplete(), TCPBaseAlg(), and ~TCPBaseAlg().


The documentation for this class was generated from the following files: