Public Member Functions | Static Public Member Functions | Public Attributes | Protected Member Functions | Static Protected Member Functions | Protected Attributes

tcp_old::TCPConnection Class Reference

#include <TCPConnection_old.h>

List of all members.

Public Member Functions

virtual void sendAck ()
virtual bool sendData (bool fullSegmentsOnly, int congestionWindow=-1)
virtual bool sendProbe ()
virtual void retransmitOneSegment (bool called_at_rto)
virtual void retransmitData ()
virtual void sendRst (uint32 seqNo)
virtual void sendRst (uint32 seq, IPvXAddress src, IPvXAddress dest, int srcPort, int destPort)
virtual void sendRstAck (uint32 seq, uint32 ack, IPvXAddress src, IPvXAddress dest, int srcPort, int destPort)
virtual void sendFin ()
virtual void sendSegment (uint32 bytes)
virtual void sendToIP (TCPSegment *tcpseg)
virtual TCPSegmentcreateTCPSegment (const char *name)
virtual void startSynRexmitTimer ()
virtual void signalConnectionTimeout ()
void scheduleTimeout (cMessage *msg, simtime_t timeout)
virtual void printConnBrief ()
 TCPConnection (TCP *mod, int appGateIndex, int connId)
 TCPConnection ()
virtual ~TCPConnection ()
virtual void segmentArrivalWhileClosed (TCPSegment *tcpseg, IPvXAddress src, IPvXAddress dest)
virtual bool processTimer (cMessage *msg)
virtual bool processTCPSegment (TCPSegment *tcpSeg, IPvXAddress srcAddr, IPvXAddress destAddr)
virtual bool processAppCommand (cMessage *msg)

int getFsmState () const
TCPStateVariablesgetState ()
TCPSendQueuegetSendQueue ()
TCPReceiveQueuegetReceiveQueue ()
TCPAlgorithmgetTcpAlgorithm ()
TCPgetTcpMain ()

Static Public Member Functions

static void printSegmentBrief (TCPSegment *tcpseg)
static const char * stateName (int state)
static const char * eventName (int event)
static const char * indicationName (int code)

Public Attributes

int appGateIndex
int connId
IPvXAddress localAddr
IPvXAddress remoteAddr
int localPort
int remotePort

Protected Member Functions

virtual TCPConnectioncloneListeningConnection ()
virtual void initConnection (TCPOpenCommand *openCmd)
virtual void configureStateVariables ()
virtual void selectInitialSeqNum ()
virtual bool isSegmentAcceptable (TCPSegment *tcpseg)
virtual void sendSyn ()
virtual void sendSynAck ()
cMessage * cancelEvent (cMessage *msg)
virtual void sendToApp (cMessage *msg)
virtual void sendIndicationToApp (int code)
virtual void sendEstabIndicationToApp ()
FSM transitions: analysing events and executing state transitions

virtual TCPEventCode preanalyseAppCommandEvent (int commandCode)
virtual bool performStateTransition (const TCPEventCode &event)
virtual void stateEntered (int state)
Processing app commands. Invoked from processAppCommand().

virtual void process_OPEN_ACTIVE (TCPEventCode &event, TCPCommand *tcpCommand, cMessage *msg)
virtual void process_OPEN_PASSIVE (TCPEventCode &event, TCPCommand *tcpCommand, cMessage *msg)
virtual void process_SEND (TCPEventCode &event, TCPCommand *tcpCommand, cMessage *msg)
virtual void process_CLOSE (TCPEventCode &event, TCPCommand *tcpCommand, cMessage *msg)
virtual void process_ABORT (TCPEventCode &event, TCPCommand *tcpCommand, cMessage *msg)
virtual void process_STATUS (TCPEventCode &event, TCPCommand *tcpCommand, cMessage *msg)
Processing TCP segment arrivals. Invoked from processTCPSegment().

virtual bool tryFastRoute (TCPSegment *tcpseg)
virtual TCPEventCode process_RCV_SEGMENT (TCPSegment *tcpseg, IPvXAddress src, IPvXAddress dest)
virtual TCPEventCode processSegmentInListen (TCPSegment *tcpseg, IPvXAddress src, IPvXAddress dest)
virtual TCPEventCode processSegmentInSynSent (TCPSegment *tcpseg, IPvXAddress src, IPvXAddress dest)
virtual TCPEventCode processSegment1stThru8th (TCPSegment *tcpseg)
virtual TCPEventCode processRstInSynReceived (TCPSegment *tcpseg)
virtual bool processAckInEstabEtc (TCPSegment *tcpseg)
Processing timeouts. Invoked from processTimer().

virtual void process_TIMEOUT_2MSL ()
virtual void process_TIMEOUT_CONN_ESTAB ()
virtual void process_TIMEOUT_FIN_WAIT_2 ()
virtual void process_TIMEOUT_SYN_REXMIT (TCPEventCode &event)

Static Protected Member Functions

static void sendToIP (TCPSegment *tcpseg, IPvXAddress src, IPvXAddress dest)

Protected Attributes

TCPtcpMain
cFSM fsm
TCPStateVariablesstate
TCPSendQueuesendQueue
TCPReceiveQueuereceiveQueue
TCPAlgorithmtcpAlgorithm
cMessage * the2MSLTimer
cMessage * connEstabTimer
cMessage * finWait2Timer
cMessage * synRexmitTimer
cOutVector * sndWndVector
cOutVector * sndNxtVector
cOutVector * sndAckVector
cOutVector * rcvSeqVector
cOutVector * rcvAckVector
cOutVector * unackedVector

Detailed Description

Manages a TCP connection. This class itself implements the TCP state machine as well as handling control PDUs (SYN, SYN+ACK, RST, FIN, etc.), timers (2MSL, CONN-ESTAB, FIN-WAIT-2) and events (OPEN, SEND, etc) associated with TCP state changes.

The implementation largely follows the functional specification at the end of RFC 793. Code comments extensively quote RFC 793 to make it easier to understand.

TCPConnection objects are not used alone -- they are instantiated and managed by a TCP module.

TCPConnection "outsources" several tasks to objects subclassed from TCPSendQueue, TCPReceiveQueue and TCPAlgorithm; see overview of this with TCP documentation.

Connection variables (TCB) are kept in TCPStateVariables. TCPAlgorithm implementations can extend TCPStateVariables to add their own stuff (see TCPAlgorithm::createStateVariables() factory method.)

The "entry points" of TCPConnnection from TCP are:

All three methods follow a common structure:

  1. dispatch to specific methods. For example, processAppCommand() invokes one of process_OPEN_ACTIVE(), process_OPEN_PASSIVE() or process_SEND(), etc., and processTCPSegment() dispatches to processSegmentInListen(), processSegmentInSynSent() or processSegment1stThru8th(). Those methods will do the REAL JOB.
  2. after they return, we'll know the state machine event (TCPEventCode, TCP_E_xxx) for sure, so we can:
  3. invoke performStateTransition() which executes the necessary state transition (for example, TCP_E_RCV_SYN will take the state machine from TCP_S_LISTEN to TCP_S_SYN_RCVD). No other actions are taken in this step.
  4. if there was a state change (for example, we entered the TCP_S_ESTABLISHED state), performStateTransition() invokes stateEntered(), which performs some necessary housekeeping (cancel the CONN-ESTAB timer).

When the CLOSED state is reached, TCP will delete the TCPConnection object.

Definition at line 256 of file TCPConnection_old.h.


Constructor & Destructor Documentation

TCPConnection::TCPConnection ( TCP mod,
int  appGateIndex,
int  connId 
)

The "normal" constructor.

Definition at line 114 of file old/TCPConnectionBase.cc.

{
    tcpMain = _mod;
    appGateIndex = _appGateIndex;
    connId = _connId;

    localPort = remotePort = -1;

    char fsmname[24];
    sprintf(fsmname, "fsm-%d", connId);
    fsm.setName(fsmname);
    fsm.setState(TCP_S_INIT);


    // queues and algorithm will be created on active or passive open
    sendQueue = NULL;
    receiveQueue = NULL;
    tcpAlgorithm = NULL;
    state = NULL;

    the2MSLTimer = new cMessage("2MSL");
    connEstabTimer = new cMessage("CONN-ESTAB");
    finWait2Timer = new cMessage("FIN-WAIT-2");
    synRexmitTimer = new cMessage("SYN-REXMIT");

    the2MSLTimer->setContextPointer(this);
    connEstabTimer->setContextPointer(this);
    finWait2Timer->setContextPointer(this);
    synRexmitTimer->setContextPointer(this);

    // statistics
    sndWndVector = NULL;
    sndNxtVector = NULL;
    sndAckVector = NULL;
    rcvSeqVector = NULL;
    rcvAckVector = NULL;
    unackedVector = NULL;

    if (getTcpMain()->recordStatistics)
    {
        sndWndVector = new cOutVector("send window");
        sndNxtVector = new cOutVector("send seq");
        sndAckVector = new cOutVector("sent ack");
        rcvSeqVector = new cOutVector("rcvd seq");
        rcvAckVector = new cOutVector("rcvd ack");
        unackedVector = new cOutVector("unacked bytes");
    }
}

TCPConnection::TCPConnection (  ) 

Note: this default ctor is NOT used to create live connections, only temporary ones so that TCPMain can invoke their segmentArrivalWhileClosed().

Definition at line 98 of file old/TCPConnectionBase.cc.

Referenced by cloneListeningConnection().

{
    // Note: this ctor is NOT used to create live connections, only
    // temporary ones to invoke segmentArrivalWhileClosed() on
    sendQueue = NULL;
    receiveQueue = NULL;
    tcpAlgorithm = NULL;
    state = NULL;
    the2MSLTimer = connEstabTimer = finWait2Timer = synRexmitTimer = NULL;
    sndWndVector = sndNxtVector = sndAckVector = rcvSeqVector = rcvAckVector = unackedVector = NULL;
}

TCPConnection::~TCPConnection (  )  [virtual]

Destructor.

Definition at line 163 of file old/TCPConnectionBase.cc.

{
    delete sendQueue;
    delete receiveQueue;
    delete tcpAlgorithm;
    delete state;

    if (the2MSLTimer)   delete cancelEvent(the2MSLTimer);
    if (connEstabTimer) delete cancelEvent(connEstabTimer);
    if (finWait2Timer)  delete cancelEvent(finWait2Timer);
    if (synRexmitTimer) delete cancelEvent(synRexmitTimer);

    // statistics
    delete sndWndVector;
    delete sndNxtVector;
    delete sndAckVector;
    delete rcvSeqVector;
    delete rcvAckVector;
    delete unackedVector;
}


Member Function Documentation

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

Utility: cancel a timer

Definition at line 425 of file TCPConnection_old.h.

Referenced by processSegment1stThru8th(), startSynRexmitTimer(), stateEntered(), and ~TCPConnection().

{return tcpMain->cancelEvent(msg);}

TCPConnection * TCPConnection::cloneListeningConnection (  )  [protected, virtual]

Utility: clone a listening connection. Used for forking.

Definition at line 138 of file old/TCPConnectionUtil.cc.

Referenced by processSegmentInListen().

{
    TCPConnection *conn = new TCPConnection(tcpMain,appGateIndex,connId);

    // following code to be kept consistent with initConnection()
    const char *sendQueueClass = sendQueue->getClassName();
    conn->sendQueue = check_and_cast<TCPSendQueue *>(createOne(sendQueueClass));
    conn->sendQueue->setConnection(conn);

    const char *receiveQueueClass = receiveQueue->getClassName();
    conn->receiveQueue = check_and_cast<TCPReceiveQueue *>(createOne(receiveQueueClass));
    conn->receiveQueue->setConnection(conn);

    const char *tcpAlgorithmClass = tcpAlgorithm->getClassName();
    conn->tcpAlgorithm = check_and_cast<TCPAlgorithm *>(createOne(tcpAlgorithmClass));
    conn->tcpAlgorithm->setConnection(conn);

    conn->state = conn->tcpAlgorithm->getStateVariables();
    configureStateVariables();
    conn->tcpAlgorithm->initialize();

    // put it into LISTEN, with our localAddr/localPort
    conn->state->active = false;
    conn->state->fork = true;
    conn->localAddr = localAddr;
    conn->localPort = localPort;
    FSM_Goto(conn->fsm, TCP_S_LISTEN);

    return conn;
}

void TCPConnection::configureStateVariables (  )  [protected, virtual]

Utility: set snd_mss and rcv_wnd in newly created state variables block

Definition at line 311 of file old/TCPConnectionUtil.cc.

Referenced by cloneListeningConnection(), and initConnection().

{
    state->snd_mss = tcpMain->par("mss").longValue(); // TODO: mss=-1 should mean autodetect
    long advertisedWindowPar = tcpMain->par("advertisedWindow").longValue();
    if (advertisedWindowPar > TCP_MAX_WIN || advertisedWindowPar <= 0)
        throw cRuntimeError("Invalid advertisedWindow parameter: %d", advertisedWindowPar);
    state->rcv_wnd = advertisedWindowPar;
}

TCPSegment * TCPConnection::createTCPSegment ( const char *  name  )  [virtual]

Utility: This factory method gets invoked throughout the TCP model to create a TCPSegment. Override it if you need to subclass TCPSegment.

Definition at line 240 of file old/TCPConnectionUtil.cc.

Referenced by tcp_old::TCPVirtualDataSendQueue::createSegmentWithBytes(), tcp_old::TCPMsgBasedSendQueue::createSegmentWithBytes(), sendAck(), sendFin(), sendRst(), sendRstAck(), sendSyn(), and sendSynAck().

{
    return new TCPSegment(name);
}

const char * TCPConnection::eventName ( int  event  )  [static]

Utility: returns name of TCP_E_xxx constants

Definition at line 60 of file old/TCPConnectionUtil.cc.

Referenced by performStateTransition(), and processAppCommand().

int tcp_old::TCPConnection::getFsmState (  )  const [inline]

Definition at line 478 of file TCPConnection_old.h.

{return fsm.getState();}

TCPReceiveQueue* tcp_old::TCPConnection::getReceiveQueue (  )  [inline]

Definition at line 481 of file TCPConnection_old.h.

{return receiveQueue;}

TCPSendQueue* tcp_old::TCPConnection::getSendQueue (  )  [inline]

Definition at line 480 of file TCPConnection_old.h.

{return sendQueue;}

TCPStateVariables* tcp_old::TCPConnection::getState (  )  [inline]

Definition at line 479 of file TCPConnection_old.h.

{return state;}

TCPAlgorithm* tcp_old::TCPConnection::getTcpAlgorithm (  )  [inline]

Definition at line 482 of file TCPConnection_old.h.

{return tcpAlgorithm;}

TCP* tcp_old::TCPConnection::getTcpMain (  )  [inline]
const char * TCPConnection::indicationName ( int  code  )  [static]

Utility: returns name of TCP_I_xxx constants

Definition at line 89 of file old/TCPConnectionUtil.cc.

Referenced by sendEstabIndicationToApp(), and sendIndicationToApp().

{
#define CASE(x) case x: s=#x+6; break
    const char *s = "unknown";
    switch (code)
    {
        CASE(TCP_I_DATA);
        CASE(TCP_I_URGENT_DATA);
        CASE(TCP_I_ESTABLISHED);
        CASE(TCP_I_PEER_CLOSED);
        CASE(TCP_I_CLOSED);
        CASE(TCP_I_CONNECTION_REFUSED);
        CASE(TCP_I_CONNECTION_RESET);
        CASE(TCP_I_TIMED_OUT);
        CASE(TCP_I_STATUS);
    }
    return s;
#undef CASE
}

void TCPConnection::initConnection ( TCPOpenCommand *  openCmd  )  [protected, virtual]

Utility: creates send/receive queues and tcpAlgorithm

Definition at line 283 of file old/TCPConnectionUtil.cc.

Referenced by process_OPEN_ACTIVE(), and process_OPEN_PASSIVE().

{
    // create send/receive queues
    const char *sendQueueClass = openCmd->getSendQueueClass();
    if (!sendQueueClass || !sendQueueClass[0])
        sendQueueClass = tcpMain->par("sendQueueClass");
    sendQueue = check_and_cast<TCPSendQueue *>(createOne(sendQueueClass));
    sendQueue->setConnection(this);

    const char *receiveQueueClass = openCmd->getReceiveQueueClass();
    if (!receiveQueueClass || !receiveQueueClass[0])
        receiveQueueClass = tcpMain->par("receiveQueueClass");
    receiveQueue = check_and_cast<TCPReceiveQueue *>(createOne(receiveQueueClass));
    receiveQueue->setConnection(this);

    // create algorithm
    const char *tcpAlgorithmClass = openCmd->getTcpAlgorithmClass();
    if (!tcpAlgorithmClass || !tcpAlgorithmClass[0])
        tcpAlgorithmClass = tcpMain->par("tcpAlgorithmClass");
    tcpAlgorithm = check_and_cast<TCPAlgorithm *>(createOne(tcpAlgorithmClass));
    tcpAlgorithm->setConnection(this);

    // create state block
    state = tcpAlgorithm->getStateVariables();
    configureStateVariables();
    tcpAlgorithm->initialize();
}

bool TCPConnection::isSegmentAcceptable ( TCPSegment tcpseg  )  [protected, virtual]

Utility: check if segment is acceptable (all bytes are in receive window)

Definition at line 330 of file old/TCPConnectionUtil.cc.

Referenced by processSegment1stThru8th().

{
    // check that segment entirely falls in receive window
    //FIXME probably not this simple, see old code segAccept() below...
    return seqGE(tcpseg->getSequenceNo(),state->rcv_nxt) &&
           seqLE(tcpseg->getSequenceNo()+tcpseg->getPayloadLength(),state->rcv_nxt+state->rcv_wnd);
}

bool TCPConnection::performStateTransition ( const TCPEventCode event  )  [protected, virtual]

Implemements the pure TCP state machine

Definition at line 284 of file old/TCPConnectionBase.cc.

Referenced by processAppCommand(), processTCPSegment(), and processTimer().

{
    ASSERT(fsm.getState()!=TCP_S_CLOSED); // closed connections should be deleted immediately

    if (event==TCP_E_IGNORE)  // e.g. discarded segment
    {
        tcpEV << "Staying in state: " << stateName(fsm.getState()) << " (no FSM event)\n";
        return true;
    }

    // state machine
    // TBD add handling of connection timeout event (keepalive), with transition to CLOSED
    // Note: empty "default:" lines are for gcc's benefit which would otherwise spit warnings
    int oldState = fsm.getState();
    switch (fsm.getState())
    {
        case TCP_S_INIT:
            switch (event)
            {
                case TCP_E_OPEN_PASSIVE:FSM_Goto(fsm, TCP_S_LISTEN); break;
                case TCP_E_OPEN_ACTIVE: FSM_Goto(fsm, TCP_S_SYN_SENT); break;
                default:;
            }
            break;

        case TCP_S_LISTEN:
            switch (event)
            {
                case TCP_E_OPEN_ACTIVE: FSM_Goto(fsm, TCP_S_SYN_SENT); break;
                case TCP_E_SEND:        FSM_Goto(fsm, TCP_S_SYN_SENT); break;
                case TCP_E_CLOSE:       FSM_Goto(fsm, TCP_S_CLOSED); break;
                case TCP_E_ABORT:       FSM_Goto(fsm, TCP_S_CLOSED); break;
                case TCP_E_RCV_SYN:     FSM_Goto(fsm, TCP_S_SYN_RCVD);break;
                default:;
            }
            break;

        case TCP_S_SYN_RCVD:
            switch (event)
            {
                case TCP_E_CLOSE:       FSM_Goto(fsm, TCP_S_FIN_WAIT_1); break;
                case TCP_E_ABORT:       FSM_Goto(fsm, TCP_S_CLOSED); break;
                case TCP_E_TIMEOUT_CONN_ESTAB: FSM_Goto(fsm, state->active ? TCP_S_CLOSED : TCP_S_LISTEN); break;
                case TCP_E_RCV_RST:     FSM_Goto(fsm, state->active ? TCP_S_CLOSED : TCP_S_LISTEN); break;
                case TCP_E_RCV_ACK:     FSM_Goto(fsm, TCP_S_ESTABLISHED); break;
                case TCP_E_RCV_FIN:     FSM_Goto(fsm, TCP_S_CLOSE_WAIT); break;
                case TCP_E_RCV_UNEXP_SYN: FSM_Goto(fsm, TCP_S_CLOSED); break;
                default:;
            }
            break;

        case TCP_S_SYN_SENT:
            switch (event)
            {
                case TCP_E_CLOSE:       FSM_Goto(fsm, TCP_S_CLOSED); break;
                case TCP_E_ABORT:       FSM_Goto(fsm, TCP_S_CLOSED); break;
                case TCP_E_TIMEOUT_CONN_ESTAB: FSM_Goto(fsm, TCP_S_CLOSED); break;
                case TCP_E_RCV_RST:     FSM_Goto(fsm, TCP_S_CLOSED); break;
                case TCP_E_RCV_SYN_ACK: FSM_Goto(fsm, TCP_S_ESTABLISHED); break;
                case TCP_E_RCV_SYN:     FSM_Goto(fsm, TCP_S_SYN_RCVD); break;
                default:;
            }
            break;

        case TCP_S_ESTABLISHED:
            switch (event)
            {
                case TCP_E_CLOSE:       FSM_Goto(fsm, TCP_S_FIN_WAIT_1); break;
                case TCP_E_ABORT:       FSM_Goto(fsm, TCP_S_CLOSED); break;
                case TCP_E_RCV_FIN:     FSM_Goto(fsm, TCP_S_CLOSE_WAIT); break;
                case TCP_E_RCV_RST:     FSM_Goto(fsm, TCP_S_CLOSED); break;
                case TCP_E_RCV_UNEXP_SYN: FSM_Goto(fsm, TCP_S_CLOSED); break;
                default:;
            }
            break;

        case TCP_S_CLOSE_WAIT:
            switch (event)
            {
                case TCP_E_CLOSE:       FSM_Goto(fsm, TCP_S_LAST_ACK); break;
                case TCP_E_ABORT:       FSM_Goto(fsm, TCP_S_CLOSED); break;
                case TCP_E_RCV_RST:     FSM_Goto(fsm, TCP_S_CLOSED); break;
                case TCP_E_RCV_UNEXP_SYN: FSM_Goto(fsm, TCP_S_CLOSED); break;
                default:;
            }
            break;

        case TCP_S_LAST_ACK:
            switch (event)
            {
                case TCP_E_ABORT:       FSM_Goto(fsm, TCP_S_CLOSED); break;
                case TCP_E_RCV_ACK:     FSM_Goto(fsm, TCP_S_CLOSED); break;
                case TCP_E_RCV_RST:     FSM_Goto(fsm, TCP_S_CLOSED); break;
                case TCP_E_RCV_UNEXP_SYN: FSM_Goto(fsm, TCP_S_CLOSED); break;
                default:;
            }
            break;

        case TCP_S_FIN_WAIT_1:
            switch (event)
            {
                case TCP_E_ABORT:       FSM_Goto(fsm, TCP_S_CLOSED); break;
                case TCP_E_RCV_FIN:     FSM_Goto(fsm, TCP_S_CLOSING); break;
                case TCP_E_RCV_ACK:     FSM_Goto(fsm, TCP_S_FIN_WAIT_2); break;
                case TCP_E_RCV_FIN_ACK: FSM_Goto(fsm, TCP_S_TIME_WAIT); break;
                case TCP_E_RCV_RST:     FSM_Goto(fsm, TCP_S_CLOSED); break;
                case TCP_E_RCV_UNEXP_SYN: FSM_Goto(fsm, TCP_S_CLOSED); break;
                default:;
            }
            break;

        case TCP_S_FIN_WAIT_2:
            switch (event)
            {
                case TCP_E_ABORT:       FSM_Goto(fsm, TCP_S_CLOSED); break;
                case TCP_E_RCV_FIN:     FSM_Goto(fsm, TCP_S_TIME_WAIT); break;
                case TCP_E_TIMEOUT_FIN_WAIT_2: FSM_Goto(fsm, TCP_S_CLOSED); break;
                case TCP_E_RCV_RST:     FSM_Goto(fsm, TCP_S_CLOSED); break;
                case TCP_E_RCV_UNEXP_SYN: FSM_Goto(fsm, TCP_S_CLOSED); break;
                default:;
            }
            break;

        case TCP_S_CLOSING:
            switch (event)
            {
                case TCP_E_ABORT:       FSM_Goto(fsm, TCP_S_CLOSED); break;
                case TCP_E_RCV_ACK:     FSM_Goto(fsm, TCP_S_TIME_WAIT); break;
                case TCP_E_RCV_RST:     FSM_Goto(fsm, TCP_S_CLOSED); break;
                case TCP_E_RCV_UNEXP_SYN: FSM_Goto(fsm, TCP_S_CLOSED); break;
                default:;
            }
            break;

        case TCP_S_TIME_WAIT:
            switch (event)
            {
                case TCP_E_ABORT:       FSM_Goto(fsm, TCP_S_CLOSED); break;
                case TCP_E_TIMEOUT_2MSL: FSM_Goto(fsm, TCP_S_CLOSED); break;
                case TCP_E_RCV_RST:     FSM_Goto(fsm, TCP_S_CLOSED); break;
                case TCP_E_RCV_UNEXP_SYN: FSM_Goto(fsm, TCP_S_CLOSED); break;
                default:;
            }
            break;

        case TCP_S_CLOSED:
            break;
    }

    if (oldState!=fsm.getState())
    {
        tcpEV << "Transition: " << stateName(oldState) << " --> " << stateName(fsm.getState()) << "  (event was: " << eventName(event) << ")\n";
        testingEV << tcpMain->getName() << ": " << stateName(oldState) << " --> " << stateName(fsm.getState()) << "  (on " << eventName(event) << ")\n";

        // cancel timers, etc.
        stateEntered(fsm.getState());
    }
    else
    {
        tcpEV << "Staying in state: " << stateName(fsm.getState()) << " (event was: " << eventName(event) << ")\n";
    }

    return fsm.getState()!=TCP_S_CLOSED;
}

TCPEventCode TCPConnection::preanalyseAppCommandEvent ( int  commandCode  )  [protected, virtual]

Maps app command codes (msg kind of app command msgs) to TCP_E_xxx event codes

Definition at line 269 of file old/TCPConnectionBase.cc.

Referenced by processAppCommand().

{
    switch (commandCode)
    {
        case TCP_C_OPEN_ACTIVE:  return TCP_E_OPEN_ACTIVE;
        case TCP_C_OPEN_PASSIVE: return TCP_E_OPEN_PASSIVE;
        case TCP_C_SEND:         return TCP_E_SEND;
        case TCP_C_CLOSE:        return TCP_E_CLOSE;
        case TCP_C_ABORT:        return TCP_E_ABORT;
        case TCP_C_STATUS:       return TCP_E_STATUS;
        default: opp_error("Unknown message kind in app command");
                 return (TCPEventCode)0; // to satisfy compiler
    }
}

void TCPConnection::printConnBrief (  )  [virtual]

Utility: prints local/remote addr/port and app gate index/connId

Definition at line 109 of file old/TCPConnectionUtil.cc.

Referenced by processAppCommand(), processTCPSegment(), and processTimer().

{
    tcpEV << "Connection ";
    tcpEV << localAddr << ":" << localPort << " to " << remoteAddr << ":" << remotePort;
    tcpEV << "  on app[" << appGateIndex << "],connId=" << connId;
    tcpEV << "  in " << stateName(fsm.getState());
    tcpEV << "  (ptr=0x" << this << ")\n";
}

void TCPConnection::printSegmentBrief ( TCPSegment tcpseg  )  [static]

Utility: prints important header fields

Definition at line 118 of file old/TCPConnectionUtil.cc.

Referenced by process_RCV_SEGMENT(), segmentArrivalWhileClosed(), and sendToIP().

{
    tcpEV << "." << tcpseg->getSrcPort() << " > ";
    tcpEV << "." << tcpseg->getDestPort() << ": ";

    if (tcpseg->getSynBit())  tcpEV << (tcpseg->getAckBit() ? "SYN+ACK " : "SYN ");
    if (tcpseg->getFinBit())  tcpEV << "FIN(+ACK) ";
    if (tcpseg->getRstBit())  tcpEV << (tcpseg->getAckBit() ? "RST+ACK " : "RST ");
    if (tcpseg->getPshBit())  tcpEV << "PSH ";

    if (tcpseg->getPayloadLength()>0 || tcpseg->getSynBit())
    {
        tcpEV << tcpseg->getSequenceNo() << ":" << tcpseg->getSequenceNo()+tcpseg->getPayloadLength();
        tcpEV << "(" << tcpseg->getPayloadLength() << ") ";
    }
    if (tcpseg->getAckBit())  tcpEV << "ack " << tcpseg->getAckNo() << " ";
    tcpEV << "win " << tcpseg->getWindow() << "\n";
    if (tcpseg->getUrgBit())  tcpEV << "urg " << tcpseg->getUrgentPointer() << " ";
}

void TCPConnection::process_ABORT ( TCPEventCode event,
TCPCommand *  tcpCommand,
cMessage *  msg 
) [protected, virtual]

Definition at line 222 of file old/TCPConnectionEventProc.cc.

Referenced by processAppCommand().

{
    delete tcpCommand;
    delete msg;

    //
    // The ABORT event will automatically take the connection to the CLOSED
    // state, flush queues etc -- no need to do it here. Also, we don't need to
    // send notification to the user, they know what's going on.
    //
    switch(fsm.getState())
    {
        case TCP_S_INIT:
            opp_error("Error processing command ABORT: connection not open");

        case TCP_S_SYN_RCVD:
        case TCP_S_ESTABLISHED:
        case TCP_S_FIN_WAIT_1:
        case TCP_S_FIN_WAIT_2:
        case TCP_S_CLOSE_WAIT:
            //"
            // Send a reset segment:
            //
            //   <SEQ=SND.NXT><CTL=RST>
            //"
            sendRst(state->snd_nxt);
            break;
    }

}

void TCPConnection::process_CLOSE ( TCPEventCode event,
TCPCommand *  tcpCommand,
cMessage *  msg 
) [protected, virtual]

Definition at line 161 of file old/TCPConnectionEventProc.cc.

Referenced by processAppCommand().

{
    delete tcpCommand;
    delete msg;

    switch(fsm.getState())
    {
        case TCP_S_INIT:
            opp_error("Error processing command CLOSE: connection not open");

        case TCP_S_LISTEN:
            // Nothing to do here
            break;

        case TCP_S_SYN_SENT:
            // Delete the TCB and return "error:  closing" responses to any
            // queued SENDs, or RECEIVEs.
            break;

        case TCP_S_SYN_RCVD:
        case TCP_S_ESTABLISHED:
        case TCP_S_CLOSE_WAIT:
            //
            // SYN_RCVD processing (ESTABLISHED and CLOSE_WAIT are similar):
            //"
            // If no SENDs have been issued and there is no pending data to send,
            // then form a FIN segment and send it, and enter FIN-WAIT-1 state;
            // otherwise queue for processing after entering ESTABLISHED state.
            //"
            if (state->snd_max==sendQueue->getBufferEndSeq())
            {
                tcpEV << "No outstanding SENDs, sending FIN right away, advancing snd_nxt over the FIN\n";
                state->snd_nxt = state->snd_max;
                sendFin();
                tcpAlgorithm->restartRexmitTimer();
                state->snd_max = ++state->snd_nxt;
                if (unackedVector) unackedVector->record(state->snd_max - state->snd_una);

                // state transition will automatically take us to FIN_WAIT_1 (or LAST_ACK)
            }
            else
            {
                tcpEV << "SEND of " << (sendQueue->getBufferEndSeq()-state->snd_max) <<
                      " bytes pending, deferring sending of FIN\n";
                event = TCP_E_IGNORE;
            }
            state->send_fin = true;
            state->snd_fin_seq = sendQueue->getBufferEndSeq();
            break;

        case TCP_S_FIN_WAIT_1:
        case TCP_S_FIN_WAIT_2:
        case TCP_S_CLOSING:
        case TCP_S_LAST_ACK:
        case TCP_S_TIME_WAIT:
            // RFC 793 is not entirely clear on how to handle a duplicate close request.
            // Here we treat it as an error.
            opp_error("Duplicate CLOSE command: connection already closing");
    }
}

void TCPConnection::process_OPEN_ACTIVE ( TCPEventCode event,
TCPCommand *  tcpCommand,
cMessage *  msg 
) [protected, virtual]

Definition at line 34 of file old/TCPConnectionEventProc.cc.

Referenced by processAppCommand().

{
    TCPOpenCommand *openCmd = check_and_cast<TCPOpenCommand *>(tcpCommand);
    IPvXAddress localAddr, remoteAddr;
    int localPort, remotePort;

    switch(fsm.getState())
    {
        case TCP_S_INIT:
            initConnection(openCmd);

            // store local/remote socket
            state->active = true;
            localAddr = openCmd->getLocalAddr();
            remoteAddr = openCmd->getRemoteAddr();
            localPort = openCmd->getLocalPort();
            remotePort = openCmd->getRemotePort();

            if (remoteAddr.isUnspecified() || remotePort==-1)
                opp_error("Error processing command OPEN_ACTIVE: remote address and port must be specified");

            if (localPort==-1)
            {
                localPort = tcpMain->getEphemeralPort();
                tcpEV << "Assigned ephemeral port " << localPort << "\n";
            }

            tcpEV << "OPEN: " << localAddr << ":" << localPort << " --> " << remoteAddr << ":" << remotePort << "\n";

            tcpMain->addSockPair(this, localAddr, remoteAddr, localPort, remotePort);

            // send initial SYN
            selectInitialSeqNum();
            sendSyn();
            startSynRexmitTimer();
            scheduleTimeout(connEstabTimer, TCP_TIMEOUT_CONN_ESTAB);
            break;

        default:
            opp_error("Error processing command OPEN_ACTIVE: connection already exists");
    }

    delete openCmd;
    delete msg;
}

void TCPConnection::process_OPEN_PASSIVE ( TCPEventCode event,
TCPCommand *  tcpCommand,
cMessage *  msg 
) [protected, virtual]

Definition at line 80 of file old/TCPConnectionEventProc.cc.

Referenced by processAppCommand().

{
    TCPOpenCommand *openCmd = check_and_cast<TCPOpenCommand *>(tcpCommand);
    IPvXAddress localAddr;
    int localPort;

    switch(fsm.getState())
    {
        case TCP_S_INIT:
            initConnection(openCmd);

            // store local/remote socket
            state->active = false;
            state->fork = openCmd->getFork();
            localAddr = openCmd->getLocalAddr();
            localPort = openCmd->getLocalPort();

            if (localPort==-1)
                opp_error("Error processing command OPEN_PASSIVE: local port must be specified");

            tcpEV << "Starting to listen on: " << localAddr << ":" << localPort << "\n";

            tcpMain->addSockPair(this, localAddr, IPvXAddress(), localPort, -1);
            break;

        default:
            opp_error("Error processing command OPEN_PASSIVE: connection already exists");
    }

    delete openCmd;
    delete msg;
}

TCPEventCode TCPConnection::process_RCV_SEGMENT ( TCPSegment tcpseg,
IPvXAddress  src,
IPvXAddress  dest 
) [protected, virtual]

Process incoming TCP segment. Returns a specific event code (e.g. TCP_E_RCV_SYN) which will drive the state machine.

Definition at line 83 of file old/TCPConnectionRcvSegment.cc.

Referenced by processTCPSegment().

{
    tcpEV << "Seg arrived: ";
    printSegmentBrief(tcpseg);
    tcpEV << "TCB: " << state->info() << "\n";

    if (rcvSeqVector) rcvSeqVector->record(tcpseg->getSequenceNo());
    if (rcvAckVector) rcvAckVector->record(tcpseg->getAckNo());

    //
    // Note: this code is organized exactly as RFC 793, section "3.9 Event
    // Processing", subsection "SEGMENT ARRIVES".
    //
    TCPEventCode event;
    if (fsm.getState()==TCP_S_LISTEN)
    {
        event = processSegmentInListen(tcpseg, src, dest);
    }
    else if (fsm.getState()==TCP_S_SYN_SENT)
    {
        event = processSegmentInSynSent(tcpseg, src, dest);
    }
    else
    {
        // RFC 793 steps "first check sequence number", "second check the RST bit", etc
        event = processSegment1stThru8th(tcpseg);
    }
    delete tcpseg;
    return event;
}

void TCPConnection::process_SEND ( TCPEventCode event,
TCPCommand *  tcpCommand,
cMessage *  msg 
) [protected, virtual]

Definition at line 113 of file old/TCPConnectionEventProc.cc.

Referenced by processAppCommand().

{
    TCPSendCommand *sendCommand = check_and_cast<TCPSendCommand *>(tcpCommand);

    // FIXME how to support PUSH? One option is to treat each SEND as a unit of data,
    // and set PSH at SEND boundaries
    switch(fsm.getState())
    {
        case TCP_S_INIT:
            opp_error("Error processing command SEND: connection not open");

        case TCP_S_LISTEN:
            tcpEV << "SEND command turns passive open into active open, sending initial SYN\n";
            state->active = true;
            selectInitialSeqNum();
            sendSyn();
            startSynRexmitTimer();
            scheduleTimeout(connEstabTimer, TCP_TIMEOUT_CONN_ESTAB);
            sendQueue->enqueueAppData(PK(msg));  // queue up for later
            tcpEV << sendQueue->getBytesAvailable(state->snd_una) << " bytes in queue\n";
            break;

        case TCP_S_SYN_RCVD:
        case TCP_S_SYN_SENT:
            tcpEV << "Queueing up data for sending later.\n";
            sendQueue->enqueueAppData(PK(msg)); // queue up for later
            tcpEV << sendQueue->getBytesAvailable(state->snd_una) << " bytes in queue\n";
            break;

        case TCP_S_ESTABLISHED:
        case TCP_S_CLOSE_WAIT:
            sendQueue->enqueueAppData(PK(msg));
            tcpEV << sendQueue->getBytesAvailable(state->snd_una) << " bytes in queue, plus "
                  << (state->snd_max-state->snd_una) << " bytes unacknowledged\n";
            tcpAlgorithm->sendCommandInvoked();
            break;

        case TCP_S_LAST_ACK:
        case TCP_S_FIN_WAIT_1:
        case TCP_S_FIN_WAIT_2:
        case TCP_S_CLOSING:
        case TCP_S_TIME_WAIT:
            opp_error("Error processing command SEND: connection closing");
    }

    delete sendCommand; // msg itself has been taken by the sendQueue
}

void TCPConnection::process_STATUS ( TCPEventCode event,
TCPCommand *  tcpCommand,
cMessage *  msg 
) [protected, virtual]

Definition at line 253 of file old/TCPConnectionEventProc.cc.

Referenced by processAppCommand().

{
    delete tcpCommand; // but reuse msg for reply

    if (fsm.getState()==TCP_S_INIT)
        opp_error("Error processing command STATUS: connection not open");

    TCPStatusInfo *statusInfo = new TCPStatusInfo();

    statusInfo->setState(fsm.getState());
    statusInfo->setStateName(stateName(fsm.getState()));

    statusInfo->setLocalAddr(localAddr);
    statusInfo->setRemoteAddr(remoteAddr);
    statusInfo->setLocalPort(localPort);
    statusInfo->setRemotePort(remotePort);

    statusInfo->setSnd_mss(state->snd_mss);
    statusInfo->setSnd_una(state->snd_una);
    statusInfo->setSnd_nxt(state->snd_nxt);
    statusInfo->setSnd_max(state->snd_max);
    statusInfo->setSnd_wnd(state->snd_wnd);
    statusInfo->setSnd_up(state->snd_up);
    statusInfo->setSnd_wl1(state->snd_wl1);
    statusInfo->setSnd_wl2(state->snd_wl2);
    statusInfo->setIss(state->iss);
    statusInfo->setRcv_nxt(state->rcv_nxt);
    statusInfo->setRcv_wnd(state->rcv_wnd);
    statusInfo->setRcv_up(state->rcv_up);
    statusInfo->setIrs(state->irs);
    statusInfo->setFin_ack_rcvd(state->fin_ack_rcvd);

    msg->setControlInfo(statusInfo);
    sendToApp(msg);
}

void TCPConnection::process_TIMEOUT_2MSL (  )  [protected, virtual]

Definition at line 1079 of file old/TCPConnectionRcvSegment.cc.

Referenced by processTimer().

{
    //"
    // If the time-wait timeout expires on a connection delete the TCB,
    // enter the CLOSED state and return.
    //"
    switch(fsm.getState())
    {
        case TCP_S_TIME_WAIT:
            // Nothing to do here. The TIMEOUT_2MSL event will automatically take
            // the connection to CLOSED. We already notified the user
            // (TCP_I_CLOSED) when we entered the TIME_WAIT state from CLOSING,
            // FIN_WAIT_1 or FIN_WAIT_2.
            break;
        default:
            // We should not receive this timeout in this state.
            opp_error("Internal error: received time-wait (2MSL) timeout in state %s", stateName(fsm.getState()));
    }

}

void TCPConnection::process_TIMEOUT_CONN_ESTAB (  )  [protected, virtual]

Definition at line 1059 of file old/TCPConnectionRcvSegment.cc.

Referenced by processTimer().

{
    switch(fsm.getState())
    {
        case TCP_S_SYN_RCVD:
        case TCP_S_SYN_SENT:
            // Nothing to do here. TIMEOUT_CONN_ESTAB event will automatically
            // take the connection to LISTEN or CLOSED, and cancel SYN-REXMIT timer.
            if (state->active)
            {
                // notify user if we're on the active side
                sendIndicationToApp(TCP_I_TIMED_OUT);
            }
            break;
        default:
            // We should not receive this timeout in this state.
            opp_error("Internal error: received CONN_ESTAB timeout in state %s", stateName(fsm.getState()));
    }
}

void TCPConnection::process_TIMEOUT_FIN_WAIT_2 (  )  [protected, virtual]

Definition at line 1100 of file old/TCPConnectionRcvSegment.cc.

Referenced by processTimer().

{
    switch(fsm.getState())
    {
        case TCP_S_FIN_WAIT_2:
            // Nothing to do here. The TIMEOUT_FIN_WAIT_2 event will automatically take
            // the connection to CLOSED.
            sendIndicationToApp(TCP_I_CLOSED);
            break;
        default:
            // We should not receive this timeout in this state.
            opp_error("Internal error: received FIN_WAIT_2 timeout in state %s", stateName(fsm.getState()));
    }
}

void TCPConnection::process_TIMEOUT_SYN_REXMIT ( TCPEventCode event  )  [protected, virtual]

Definition at line 1125 of file old/TCPConnectionRcvSegment.cc.

Referenced by processTimer().

{
    if (++state->syn_rexmit_count>MAX_SYN_REXMIT_COUNT)
    {
        tcpEV << "Retransmission count during connection setup exceeds " << MAX_SYN_REXMIT_COUNT << ", giving up\n";
        // Note ABORT will take the connection to closed, and cancel CONN-ESTAB timer as well
        event = TCP_E_ABORT;
        return;
    }

    tcpEV << "Performing retransmission #" << state->syn_rexmit_count << "\n";

    // resend what's needed
    switch(fsm.getState())
    {
        case TCP_S_SYN_SENT: sendSyn(); break;
        case TCP_S_SYN_RCVD: sendSynAck(); break;
        default:  opp_error("Internal error: SYN-REXMIT timer expired while in state %s", stateName(fsm.getState()));
    }

    // reschedule timer
    state->syn_rexmit_timeout *= 2;

    if (state->syn_rexmit_timeout > TCP_TIMEOUT_SYN_REXMIT_MAX)
        state->syn_rexmit_timeout = TCP_TIMEOUT_SYN_REXMIT_MAX;
    scheduleTimeout(synRexmitTimer, state->syn_rexmit_timeout);
}

bool TCPConnection::processAckInEstabEtc ( TCPSegment tcpseg  )  [protected, virtual]

Definition at line 937 of file old/TCPConnectionRcvSegment.cc.

Referenced by processSegment1stThru8th().

{
    tcpEV2 << "Processing ACK in a data transfer state\n";

    //
    //"
    //  If SND.UNA < SEG.ACK =< SND.NXT then, set SND.UNA <- SEG.ACK.
    //  Any segments on the retransmission queue which are thereby
    //  entirely acknowledged are removed.  Users should receive
    //  positive acknowledgments for buffers which have been SENT and
    //  fully acknowledged (i.e., SEND buffer should be returned with
    //  "ok" response).  If the ACK is a duplicate
    //  (SEG.ACK < SND.UNA), it can be ignored.  If the ACK acks
    //  something not yet sent (SEG.ACK > SND.NXT) then send an ACK,
    //  drop the segment, and return.
    //
    //  If SND.UNA < SEG.ACK =< SND.NXT, the send window should be
    //  updated.  If (SND.WL1 < SEG.SEQ or (SND.WL1 = SEG.SEQ and
    //  SND.WL2 =< SEG.ACK)), set SND.WND <- SEG.WND, set
    //  SND.WL1 <- SEG.SEQ, and set SND.WL2 <- SEG.ACK.
    //
    //  Note that SND.WND is an offset from SND.UNA, that SND.WL1
    //  records the sequence number of the last segment used to update
    //  SND.WND, and that SND.WL2 records the acknowledgment number of
    //  the last segment used to update SND.WND.  The check here
    //  prevents using old segments to update the window.
    //"
    // Note: should use SND.MAX instead of SND.NXT in above checks
    //
    if (seqGE(state->snd_una, tcpseg->getAckNo()))
    {
        //
        // duplicate ACK? A received TCP segment is a duplicate ACK if all of
        // the following apply:
        //    (1) snd_una==ackNo
        //    (2) segment contains no data
        //    (3) there's unacked data (snd_una!=snd_max)
        //
        // Note: ssfnet uses additional constraint "window is the same as last
        // received (not an update)" -- we don't do that because window updates
        // are ignored anyway if neither seqNo nor ackNo has changed.
        //
        if (state->snd_una==tcpseg->getAckNo() && tcpseg->getPayloadLength()==0 &&
            state->snd_una!=state->snd_max)
        {
            state->dupacks++;
            tcpAlgorithm->receivedDuplicateAck();
        }
        else
        {
            // if doesn't qualify as duplicate ACK, just ignore it.
            if (tcpseg->getPayloadLength()==0)
            {
                if (state->snd_una!=tcpseg->getAckNo())
                    tcpEV << "Old ACK: ackNo<snd_una\n";
                else if (state->snd_una==state->snd_max)
                    tcpEV << "ACK looks duplicate but we have currently no unacked data (snd_una==snd_max)\n";
            }

            // reset counter
            state->dupacks = 0;
        }
    }
    else if (seqLE(tcpseg->getAckNo(), state->snd_max))
    {
        // ack in window.
        uint32 old_snd_una = state->snd_una;
        state->snd_una = tcpseg->getAckNo();
        if (unackedVector) unackedVector->record(state->snd_max - state->snd_una);

        // after retransmitting a lost segment, we may get an ack well ahead of snd_nxt
        if (seqLess(state->snd_nxt, state->snd_una))
            state->snd_nxt = state->snd_una;

        uint32 discardUpToSeq = state->snd_una;

        // our FIN acked?
        if (state->send_fin && tcpseg->getAckNo()==state->snd_fin_seq+1)
        {
            // set flag that our FIN has been acked
            tcpEV << "ACK acks our FIN\n";
            state->fin_ack_rcvd = true;
            discardUpToSeq--; // the FIN sequence number is not real data
        }

        // acked data no longer needed in send queue
        sendQueue->discardUpTo(discardUpToSeq);

        if (seqLess(state->snd_wl1, tcpseg->getSequenceNo()) ||
            (state->snd_wl1==tcpseg->getSequenceNo() && seqLE(state->snd_wl2, tcpseg->getAckNo())))
        {
            // send window should be updated
            tcpEV << "Updating send window from segment: new wnd=" << tcpseg->getWindow() << "\n";
            state->snd_wnd = tcpseg->getWindow();
            state->snd_wl1 = tcpseg->getSequenceNo();
            state->snd_wl2 = tcpseg->getAckNo();
            if (sndWndVector) sndWndVector->record(state->snd_wnd);
        }

        if (tcpseg->getPayloadLength() == 0 && fsm.getState()!=TCP_S_SYN_RCVD) // if segment contains data, wait until data has been forwarded to app before sending ACK, otherwise we would use an old ACKNo
        {
            // notify
            tcpAlgorithm->receivedDataAck(old_snd_una);

            // in the receivedDataAck we need the old value
            state->dupacks = 0;
        }
    }
    else
    {
        ASSERT(seqGreater(tcpseg->getAckNo(), state->snd_max)); // from if-ladder

        // send an ACK, drop the segment, and return.
        tcpAlgorithm->receivedAckForDataNotYetSent(tcpseg->getAckNo());
        state->dupacks = 0;
        return false;  // means "drop"
    }
    return true;
}

bool TCPConnection::processAppCommand ( cMessage *  msg  )  [virtual]

Process commands from the application. Normally returns true. A return value of false means that the connection structure must be deleted by the caller (TCP).

Definition at line 245 of file old/TCPConnectionBase.cc.

Referenced by tcp_old::TCP::handleMessage().

{
    printConnBrief();

    // first do actions
    TCPCommand *tcpCommand = (TCPCommand *)(msg->removeControlInfo());
    TCPEventCode event = preanalyseAppCommandEvent(msg->getKind());
    tcpEV << "App command: " << eventName(event) << "\n";
    switch (event)
    {
        case TCP_E_OPEN_ACTIVE: process_OPEN_ACTIVE(event, tcpCommand, msg); break;
        case TCP_E_OPEN_PASSIVE: process_OPEN_PASSIVE(event, tcpCommand, msg); break;
        case TCP_E_SEND: process_SEND(event, tcpCommand, msg); break;
        case TCP_E_CLOSE: process_CLOSE(event, tcpCommand, msg); break;
        case TCP_E_ABORT: process_ABORT(event, tcpCommand, msg); break;
        case TCP_E_STATUS: process_STATUS(event, tcpCommand, msg); break;
        default: opp_error("wrong event code");
    }

    // then state transitions
    return performStateTransition(event);
}

TCPEventCode TCPConnection::processRstInSynReceived ( TCPSegment tcpseg  )  [protected, virtual]

Definition at line 909 of file old/TCPConnectionRcvSegment.cc.

Referenced by processSegment1stThru8th().

{
    tcpEV2 << "Processing RST in SYN_RCVD\n";

    //"
    // If this connection was initiated with a passive OPEN (i.e.,
    // came from the LISTEN state), then return this connection to
    // LISTEN state and return.  The user need not be informed.  If
    // this connection was initiated with an active OPEN (i.e., came
    // from SYN-SENT state) then the connection was refused, signal
    // the user "connection refused".  In either case, all segments
    // on the retransmission queue should be removed.  And in the
    // active OPEN case, enter the CLOSED state and delete the TCB,
    // and return.
    //"

    sendQueue->discardUpTo(sendQueue->getBufferEndSeq()); // flush send queue

    if (state->active)
    {
        // signal "connection refused"
        sendIndicationToApp(TCP_I_CONNECTION_REFUSED);
    }

    // on RCV_RST, FSM will go either to LISTEN or to CLOSED, depending on state->active
    return TCP_E_RCV_RST;
}

TCPEventCode TCPConnection::processSegment1stThru8th ( TCPSegment tcpseg  )  [protected, virtual]

Definition at line 114 of file old/TCPConnectionRcvSegment.cc.

Referenced by process_RCV_SEGMENT().

{
    //
    // RFC 793: first check sequence number
    //
    bool acceptable = isSegmentAcceptable(tcpseg);
    if (!acceptable)
    {
        //"
        // If an incoming segment is not acceptable, an acknowledgment
        // should be sent in reply (unless the RST bit is set, if so drop
        // the segment and return):
        //
        //  <SEQ=SND.NXT><ACK=RCV.NXT><CTL=ACK>
        //"
        if (tcpseg->getRstBit())
        {
            tcpEV << "RST with unacceptable seqNum: dropping\n";
        }
        else
        {
            tcpEV << "Segment seqNum not acceptable, sending ACK with current receive seq\n";
            sendAck();
        }
        return TCP_E_IGNORE;
    }

    //
    // RFC 793: second check the RST bit,
    //
    if (tcpseg->getRstBit())
    {
        // Note: if we come from LISTEN, processSegmentInListen() has already handled RST.
        switch (fsm.getState())
        {
            case TCP_S_SYN_RCVD:
                //"
                // If this connection was initiated with a passive OPEN (i.e.,
                // came from the LISTEN state), then return this connection to
                // LISTEN state and return.  The user need not be informed.  If
                // this connection was initiated with an active OPEN (i.e., came
                // from SYN-SENT state) then the connection was refused, signal
                // the user "connection refused".  In either case, all segments
                // on the retransmission queue should be removed.  And in the
                // active OPEN case, enter the CLOSED state and delete the TCB,
                // and return.
                //"
                return processRstInSynReceived(tcpseg);

            case TCP_S_ESTABLISHED:
            case TCP_S_FIN_WAIT_1:
            case TCP_S_FIN_WAIT_2:
            case TCP_S_CLOSE_WAIT:
                //"
                // If the RST bit is set then, any outstanding RECEIVEs and SEND
                // should receive "reset" responses.  All segment queues should be
                // flushed.  Users should also receive an unsolicited general
                // "connection reset" signal.
                //
                // Enter the CLOSED state, delete the TCB, and return.
                //"
                tcpEV << "RST: performing connection reset, closing connection\n";
                sendIndicationToApp(TCP_I_CONNECTION_RESET);
                return TCP_E_RCV_RST;  // this will trigger state transition

            case TCP_S_CLOSING:
            case TCP_S_LAST_ACK:
            case TCP_S_TIME_WAIT:
                //"
                // enter the CLOSED state, delete the TCB, and return.
                //"
                tcpEV << "RST: closing connection\n";
                if (fsm.getState()!=TCP_S_TIME_WAIT)
                    sendIndicationToApp(TCP_I_CLOSED); // in TIME_WAIT, we've already sent it
                return TCP_E_RCV_RST; // this will trigger state transition

            default: ASSERT(0);
        }
    }

    // RFC 793: third check security and precedence
    // This step is ignored.

    //
    // RFC 793: fourth, check the SYN bit,
    //
    if (tcpseg->getSynBit())
    {
        //"
        // If the SYN is in the window it is an error, send a reset, any
        // outstanding RECEIVEs and SEND should receive "reset" responses,
        // all segment queues should be flushed, the user should also
        // receive an unsolicited general "connection reset" signal, enter
        // the CLOSED state, delete the TCB, and return.
        //
        // If the SYN is not in the window this step would not be reached
        // and an ack would have been sent in the first step (sequence
        // number check).
        //"

        ASSERT(isSegmentAcceptable(tcpseg));  // assert SYN is in the window
        tcpEV << "SYN is in the window: performing connection reset, closing connection\n";
        sendIndicationToApp(TCP_I_CONNECTION_RESET);
        return TCP_E_RCV_UNEXP_SYN;
    }

    //
    // RFC 793: fifth check the ACK field,
    //
    if (!tcpseg->getAckBit())
    {
        // if the ACK bit is off drop the segment and return
        tcpEV << "ACK not set, dropping segment\n";
        return TCP_E_IGNORE;
    }

    uint32 old_snd_una = state->snd_una;

    TCPEventCode event = TCP_E_IGNORE;

    if (fsm.getState()==TCP_S_SYN_RCVD)
    {
        //"
        // If SND.UNA =< SEG.ACK =< SND.NXT then enter ESTABLISHED state
        // and continue processing.
        //
        // If the segment acknowledgment is not acceptable, form a
        // reset segment,
        //
        //  <SEQ=SEG.ACK><CTL=RST>
        //
        // and send it.
        //"
        if (!seqLE(state->snd_una,tcpseg->getAckNo()) || !seqLE(tcpseg->getAckNo(),state->snd_nxt))
        {
            sendRst(tcpseg->getAckNo());
            return TCP_E_IGNORE;
        }

        // notify tcpAlgorithm and app layer
        tcpAlgorithm->established(false);
        sendEstabIndicationToApp();

        // This will trigger transition to ESTABLISHED. Timers and notifying
        // app will be taken care of in stateEntered().
        event = TCP_E_RCV_ACK;
    }

    uint32 old_snd_nxt = state->snd_nxt; // later we'll need to see if snd_nxt changed
    // Note: If one of the last data segments is lost while already in LAST-ACK state (e.g. if using TCPEchoApps)
    // TCP must be able to process acceptable acknowledgments, however please note RFC 793, page 73:
        // "LAST-ACK STATE
    //    The only thing that can arrive in this state is an
    //    acknowledgment of our FIN.  If our FIN is now acknowledged,
    //    delete the TCB, enter the CLOSED state, and return."
    if (fsm.getState()==TCP_S_SYN_RCVD || fsm.getState()==TCP_S_ESTABLISHED ||
        fsm.getState()==TCP_S_FIN_WAIT_1 || fsm.getState()==TCP_S_FIN_WAIT_2 ||
        fsm.getState()==TCP_S_CLOSE_WAIT || fsm.getState()==TCP_S_CLOSING || fsm.getState()==TCP_S_LAST_ACK)
    {
        //
        // ESTABLISHED processing:
        //"
        //  If SND.UNA < SEG.ACK =< SND.NXT then, set SND.UNA <- SEG.ACK.
        //  Any segments on the retransmission queue which are thereby
        //  entirely acknowledged are removed.  Users should receive
        //  positive acknowledgments for buffers which have been SENT and
        //  fully acknowledged (i.e., SEND buffer should be returned with
        //  "ok" response).  If the ACK is a duplicate
        //  (SEG.ACK < SND.UNA), it can be ignored.  If the ACK acks
        //  something not yet sent (SEG.ACK > SND.NXT) then send an ACK,
        //  drop the segment, and return.
        //
        //  If SND.UNA < SEG.ACK =< SND.NXT, the send window should be
        //  updated.  If (SND.WL1 < SEG.SEQ or (SND.WL1 = SEG.SEQ and
        //  SND.WL2 =< SEG.ACK)), set SND.WND <- SEG.WND, set
        //  SND.WL1 <- SEG.SEQ, and set SND.WL2 <- SEG.ACK.
        //
        //  Note that SND.WND is an offset from SND.UNA, that SND.WL1
        //  records the sequence number of the last segment used to update
        //  SND.WND, and that SND.WL2 records the acknowledgment number of
        //  the last segment used to update SND.WND.  The check here
        //  prevents using old segments to update the window.
        //"
        bool ok = processAckInEstabEtc(tcpseg);
        if (!ok)
            return TCP_E_IGNORE;  // if acks something not yet sent, drop it
    }

    if ((fsm.getState()==TCP_S_FIN_WAIT_1 && state->fin_ack_rcvd))
    {
        //"
        // FIN-WAIT-1 STATE
        //   In addition to the processing for the ESTABLISHED state, if
        //   our FIN is now acknowledged then enter FIN-WAIT-2 and continue
        //   processing in that state.
        //"
        event = TCP_E_RCV_ACK;  // will trigger transition to FIN-WAIT-2
    }

    if (fsm.getState()==TCP_S_FIN_WAIT_2)
    {
        //"
        // FIN-WAIT-2 STATE
        //  In addition to the processing for the ESTABLISHED state, if
        //  the retransmission queue is empty, the user's CLOSE can be
        //  acknowledged ("ok") but do not delete the TCB.
        //"
        // nothing to do here (in our model, used commands don't need to be
        // acknowledged)
    }

    if (fsm.getState()==TCP_S_CLOSING)
    {
        //"
        // In addition to the processing for the ESTABLISHED state, if
        // the ACK acknowledges our FIN then enter the TIME-WAIT state,
        // otherwise ignore the segment.
        //"
        if (state->fin_ack_rcvd)
        {
            tcpEV << "Our FIN acked -- can go to TIME_WAIT now\n";
            event = TCP_E_RCV_ACK;  // will trigger transition to TIME-WAIT
            scheduleTimeout(the2MSLTimer, TCP_TIMEOUT_2MSL);  // start timer

            // we're entering TIME_WAIT, so we can signal CLOSED the user
            // (the only thing left to do is wait until the 2MSL timer expires)
            sendIndicationToApp(TCP_I_CLOSED);
        }
    }

    if (fsm.getState()==TCP_S_LAST_ACK)
    {
        //"
        // The only thing that can arrive in this state is an
        // acknowledgment of our FIN.  If our FIN is now acknowledged,
        // delete the TCB, enter the CLOSED state, and return.
        //"
        if (state->send_fin && tcpseg->getAckNo()==state->snd_fin_seq+1)
        {
            tcpEV << "Last ACK arrived\n";
            sendIndicationToApp(TCP_I_CLOSED);
            return TCP_E_RCV_ACK; // will trigger transition to CLOSED
        }
    }

    if (fsm.getState()==TCP_S_TIME_WAIT)
    {
        //"
        // The only thing that can arrive in this state is a
        // retransmission of the remote FIN.  Acknowledge it, and restart
        // the 2 MSL timeout.
        //"
        // And we are staying in the TIME_WAIT state.
        //
        sendAck();
        cancelEvent(the2MSLTimer);
        scheduleTimeout(the2MSLTimer, TCP_TIMEOUT_2MSL);
    }

    //
    // RFC 793: sixth, check the URG bit,
    //
    if (tcpseg->getUrgBit() && (fsm.getState()==TCP_S_ESTABLISHED || fsm.getState()==TCP_S_FIN_WAIT_1 ||
        fsm.getState()==TCP_S_FIN_WAIT_2))
    {
        //"
        // If the URG bit is set, RCV.UP <- max(RCV.UP,SEG.UP), and signal
        // the user that the remote side has urgent data if the urgent
        // pointer (RCV.UP) is in advance of the data consumed.  If the
        // user has already been signaled (or is still in the "urgent
        // mode") for this continuous sequence of urgent data, do not
        // signal the user again.
        //"

        // TBD: URG currently not supported
    }

    //
    // RFC 793: seventh, process the segment text,
    //
    uint32 old_rcv_nxt = state->rcv_nxt; // if rcv_nxt changes, we need to send/schedule an ACK
    if (fsm.getState()==TCP_S_SYN_RCVD || fsm.getState()==TCP_S_ESTABLISHED || fsm.getState()==TCP_S_FIN_WAIT_1 || fsm.getState()==TCP_S_FIN_WAIT_2)
    {
        //"
        // Once in the ESTABLISHED state, it is possible to deliver segment
        // text to user RECEIVE buffers.  Text from segments can be moved
        // into buffers until either the buffer is full or the segment is
        // empty.  If the segment empties and carries an PUSH flag, then
        // the user is informed, when the buffer is returned, that a PUSH
        // has been received.
        //
        // When the TCP takes responsibility for delivering the data to the
        // user it must also acknowledge the receipt of the data.
        //
        // Once the TCP takes responsibility for the data it advances
        // RCV.NXT over the data accepted, and adjusts RCV.WND as
        // apporopriate to the current buffer availability.  The total of
        // RCV.NXT and RCV.WND should not be reduced.
        //
        // Please note the window management suggestions in section 3.7.
        //
        // Send an acknowledgment of the form:
        //
        //   <SEQ=SND.NXT><ACK=RCV.NXT><CTL=ACK>
        //
        // This acknowledgment should be piggybacked on a segment being
        // transmitted if possible without incurring undue delay.
        //"
        if (tcpseg->getPayloadLength()>0)
        {
            tcpEV2 << "Processing segment text in a data transfer state\n";

            // insert into receive buffers. If this segment is contiguous with
            // previously received ones (seqNo==rcv_nxt), rcv_nxt can be increased;
            // otherwise it stays the same but the data must be cached nevertheless
            // (to avoid "Failure to retain above-sequence data" problem, RFC 2525
            // section 2.5).
            uint32 old_rcv_nxt = state->rcv_nxt;
            state->rcv_nxt = receiveQueue->insertBytesFromSegment(tcpseg);

            if (seqGreater(state->snd_una, old_snd_una))
            {
                // notify
                tcpAlgorithm->receivedDataAck(old_snd_una);

                // in the receivedDataAck we need the old value
                state->dupacks = 0;
            }

            // out-of-order segment?
            if (old_rcv_nxt==state->rcv_nxt)
            {
                // we'll probably want to send an ACK here
                tcpAlgorithm->receivedOutOfOrderSegment();
            }
            else
            {
                // forward data to app
                //
                // FIXME observe PSH bit
                //
                // FIXME we should implement socket READ command, and pass up only
                // as many bytes as requested. rcv_wnd should be decreased
                // accordingly! (right now we *always* advertise win=16384,
                // that is, there's practically no receiver-imposed flow control!)
                //
                cPacket *msg;
                while ((msg=receiveQueue->extractBytesUpTo(state->rcv_nxt))!=NULL)
                {
                    msg->setKind(TCP_I_DATA);  // TBD currently we never send TCP_I_URGENT_DATA
                    TCPCommand *cmd = new TCPCommand();
                    cmd->setConnId(connId);
                    msg->setControlInfo(cmd);
                    sendToApp(msg);
                }

                // if this segment "filled the gap" until the previously arrived segment
                // that carried a FIN (i.e.rcv_nxt==rcv_fin_seq), we have to advance
                // rcv_nxt over the FIN.
                if (state->fin_rcvd && state->rcv_nxt==state->rcv_fin_seq)
                {
                    tcpEV << "All segments arrived up to the FIN segment, advancing rcv_nxt over the FIN\n";
                    state->rcv_nxt = state->rcv_fin_seq+1;
                    // state transitions will be done in the state machine, here we just set
                    // the proper event code (TCP_E_RCV_FIN or TCP_E_RCV_FIN_ACK)
                    event = TCP_E_RCV_FIN;
                    switch (fsm.getState())
                    {
                        case TCP_S_FIN_WAIT_1:
                            if (state->fin_ack_rcvd)
                            {
                                event = TCP_E_RCV_FIN_ACK;
                                // start the time-wait timer, turn off the other timers
                                cancelEvent(finWait2Timer);
                                scheduleTimeout(the2MSLTimer, TCP_TIMEOUT_2MSL);

                                // we're entering TIME_WAIT, so we can signal CLOSED the user
                                // (the only thing left to do is wait until the 2MSL timer expires)
                                sendIndicationToApp(TCP_I_CLOSED);
                            }
                            break;
                        case TCP_S_FIN_WAIT_2:
                            // Start the time-wait timer, turn off the other timers.
                            cancelEvent(finWait2Timer);
                            scheduleTimeout(the2MSLTimer, TCP_TIMEOUT_2MSL);

                            // we're entering TIME_WAIT, so we can signal CLOSED the user
                            // (the only thing left to do is wait until the 2MSL timer expires)
                            sendIndicationToApp(TCP_I_CLOSED);
                            break;
                        case TCP_S_TIME_WAIT:
                            // Restart the 2 MSL time-wait timeout.
                            cancelEvent(the2MSLTimer);
                            scheduleTimeout(the2MSLTimer, TCP_TIMEOUT_2MSL);
                            break;
                    }
                    sendIndicationToApp(TCP_I_PEER_CLOSED);
                }
            }
        }
    }

    //
    // RFC 793: eighth, check the FIN bit,
    //
    if (tcpseg->getFinBit())
    {
        //"
        // If the FIN bit is set, signal the user "connection closing" and
        // return any pending RECEIVEs with same message, advance RCV.NXT
        // over the FIN, and send an acknowledgment for the FIN.  Note that
        // FIN implies PUSH for any segment text not yet delivered to the
        // user.
        //"

        // Note: seems like RFC 793 is not entirely correct here: if the
        // segment is "above sequence" (ie. RCV.NXT < SEG.SEQ), we cannot
        // advance RCV.NXT over the FIN. Instead we remember this sequence
        // number and do it later.
        uint32 fin_seq = (uint32)tcpseg->getSequenceNo() + (uint32)tcpseg->getPayloadLength();
        if (state->rcv_nxt==fin_seq)
        {
            // advance rcv_nxt over FIN now
            tcpEV << "FIN arrived, advancing rcv_nxt over the FIN\n";
            state->rcv_nxt++;
            // state transitions will be done in the state machine, here we just set
            // the proper event code (TCP_E_RCV_FIN or TCP_E_RCV_FIN_ACK)
            event = TCP_E_RCV_FIN;
            switch (fsm.getState())
            {
                case TCP_S_FIN_WAIT_1:
                    if (state->fin_ack_rcvd)
                    {
                        event = TCP_E_RCV_FIN_ACK;
                        // start the time-wait timer, turn off the other timers
                        cancelEvent(finWait2Timer);
                        scheduleTimeout(the2MSLTimer, TCP_TIMEOUT_2MSL);

                        // we're entering TIME_WAIT, so we can signal CLOSED the user
                        // (the only thing left to do is wait until the 2MSL timer expires)
                        sendIndicationToApp(TCP_I_CLOSED);
                    }
                    break;
                case TCP_S_FIN_WAIT_2:
                    // Start the time-wait timer, turn off the other timers.
                    cancelEvent(finWait2Timer);
                    scheduleTimeout(the2MSLTimer, TCP_TIMEOUT_2MSL);

                    // we're entering TIME_WAIT, so we can signal CLOSED the user
                    // (the only thing left to do is wait until the 2MSL timer expires)
                    sendIndicationToApp(TCP_I_CLOSED);
                    break;
                case TCP_S_TIME_WAIT:
                    // Restart the 2 MSL time-wait timeout.
                    cancelEvent(the2MSLTimer);
                    scheduleTimeout(the2MSLTimer, TCP_TIMEOUT_2MSL);
                    break;
            }
            sendIndicationToApp(TCP_I_PEER_CLOSED);
        }
        else
        {
            // we'll have to do it later (when an arriving segment "fills the gap")
            tcpEV << "FIN segment above sequence, storing sequence number of FIN\n";
            state->fin_rcvd = true;
            state->rcv_fin_seq = fin_seq;
        }

        // TBD do PUSH stuff
    }

    if (old_rcv_nxt!=state->rcv_nxt)
    {
        // if rcv_nxt changed, either because we received segment text or we
        // received a FIN that needs to be acked (or both), we need to send or
        // schedule an ACK.

        // tcpAlgorithm decides when and how to do ACKs
        tcpAlgorithm->receiveSeqChanged();
    }

    if ((fsm.getState()==TCP_S_ESTABLISHED || fsm.getState()==TCP_S_SYN_RCVD) &&
        state->send_fin && state->snd_nxt==state->snd_fin_seq+1)
    {
        // if the user issued the CLOSE command a long time ago and we've just
        // managed to send off FIN, we simulate a CLOSE command now (we had to
        // defer it at that time because we still had data in the send queue.)
        // This CLOSE will take us into the FIN_WAIT_1 state.
        tcpEV << "Now we can do the CLOSE which was deferred a while ago\n";
        event = TCP_E_CLOSE;
    }

    if (fsm.getState()==TCP_S_CLOSE_WAIT && state->send_fin &&
        state->snd_nxt==state->snd_fin_seq+1 && old_snd_nxt!=state->snd_nxt)
    {
        // if we're in CLOSE_WAIT and we just got to sent our long-pending FIN,
        // we simulate a CLOSE command now (we had to defer it at that time because
        // we still had data in the send queue.) This CLOSE will take us into the
        // LAST_ACK state.
        tcpEV << "Now we can do the CLOSE which was deferred a while ago\n";
        event = TCP_E_CLOSE;
    }

    return event;
}

TCPEventCode TCPConnection::processSegmentInListen ( TCPSegment tcpseg,
IPvXAddress  src,
IPvXAddress  dest 
) [protected, virtual]

Definition at line 622 of file old/TCPConnectionRcvSegment.cc.

Referenced by process_RCV_SEGMENT().

{
    tcpEV2 << "Processing segment in LISTEN\n";

    //"
    // first check for an RST
    //   An incoming RST should be ignored.  Return.
    //"
    if (tcpseg->getRstBit())
    {
        tcpEV << "RST bit set: dropping segment\n";
        return TCP_E_IGNORE;
    }

    //"
    // second check for an ACK
    //    Any acknowledgment is bad if it arrives on a connection still in
    //    the LISTEN state.  An acceptable reset segment should be formed
    //    for any arriving ACK-bearing segment.  The RST should be
    //    formatted as follows:
    //
    //      <SEQ=SEG.ACK><CTL=RST>
    //
    //    Return.
    //"
    if (tcpseg->getAckBit())
    {
        tcpEV << "ACK bit set: dropping segment and sending RST\n";
        sendRst(tcpseg->getAckNo(),destAddr,srcAddr,tcpseg->getDestPort(),tcpseg->getSrcPort());
        return TCP_E_IGNORE;
    }

    //"
    // third check for a SYN
    //"
    if (tcpseg->getSynBit())
    {
        if (tcpseg->getFinBit())
        {
            // Looks like implementations vary on how to react to SYN+FIN.
            // Some treat it as plain SYN (and reply with SYN+ACK), some send RST+ACK.
            // Let's just do the former here.
            tcpEV << "SYN+FIN received: ignoring FIN\n";
        }

        tcpEV << "SYN bit set: filling in foreign socket and sending SYN+ACK\n";

        //"
        // If the listen was not fully specified (i.e., the foreign socket was not
        // fully specified), then the unspecified fields should be filled in now.
        //"
        //
        // Also, we may need to fork, in order to leave another connection
        // LISTENing on the port. Note: forking will change our connId.
        //
        if (state->fork)
        {
            TCPConnection *conn = cloneListeningConnection(); // this will stay LISTENing
            tcpMain->addForkedConnection(this, conn, destAddr, srcAddr, tcpseg->getDestPort(), tcpseg->getSrcPort());
            tcpEV << "Connection forked: this connection got new connId=" << connId << ", "
                     "spinoff keeps LISTENing with connId=" << conn->connId << "\n";
        }
        else
        {
            tcpMain->updateSockPair(this, destAddr, srcAddr, tcpseg->getDestPort(), tcpseg->getSrcPort());
        }

        //"
        //  Set RCV.NXT to SEG.SEQ+1, IRS is set to SEG.SEQ and any other
        //  control or text should be queued for processing later.  ISS
        //  should be selected and a SYN segment sent of the form:
        //
        //    <SEQ=ISS><ACK=RCV.NXT><CTL=SYN,ACK>
        //
        //  SND.NXT is set to ISS+1 and SND.UNA to ISS.  The connection
        //  state should be changed to SYN-RECEIVED.
        //"
        state->rcv_nxt = tcpseg->getSequenceNo()+1;
        state->irs = tcpseg->getSequenceNo();
        receiveQueue->init(state->rcv_nxt);   // FIXME may init twice...
        selectInitialSeqNum();

        // although not mentioned in RFC 793, seems like we have to pick up
        // initial snd_wnd from the segment here.
        state->snd_wnd = tcpseg->getWindow();
        state->snd_wl1 = tcpseg->getSequenceNo();
        state->snd_wl2 = state->iss;
        if (sndWndVector) sndWndVector->record(state->snd_wnd);

        sendSynAck();
        startSynRexmitTimer();
        if (!connEstabTimer->isScheduled())
            scheduleTimeout(connEstabTimer, TCP_TIMEOUT_CONN_ESTAB);

        //"
        // Note that any other incoming control or data (combined with SYN)
        // will be processed in the SYN-RECEIVED state, but processing of SYN
        // and ACK should not be repeated.
        //"
        // We don't send text in SYN or SYN+ACK, but accept it. Otherwise
        // there isn't much left to do: RST, SYN, ACK, FIN got processed already,
        // so there's only URG and PSH left to handle.
        //
        if (tcpseg->getPayloadLength()>0)
            receiveQueue->insertBytesFromSegment(tcpseg);
        if (tcpseg->getUrgBit() || tcpseg->getPshBit())
            tcpEV << "Ignoring URG and PSH bits in SYN\n"; // TBD

        return TCP_E_RCV_SYN;  // this will take us to SYN_RCVD
    }

    //"
    //  fourth other text or control
    //   So you are unlikely to get here, but if you do, drop the segment, and return.
    //"
    tcpEV << "Unexpected segment: dropping it\n";
    return TCP_E_IGNORE;
}

TCPEventCode TCPConnection::processSegmentInSynSent ( TCPSegment tcpseg,
IPvXAddress  src,
IPvXAddress  dest 
) [protected, virtual]

Definition at line 741 of file old/TCPConnectionRcvSegment.cc.

Referenced by process_RCV_SEGMENT().

{
    tcpEV2 << "Processing segment in SYN_SENT\n";

    //"
    // first check the ACK bit
    //
    //   If the ACK bit is set
    //
    //     If SEG.ACK =< ISS, or SEG.ACK > SND.NXT, send a reset (unless
    //     the RST bit is set, if so drop the segment and return)
    //
    //       <SEQ=SEG.ACK><CTL=RST>
    //
    //     and discard the segment.  Return.
    //
    //     If SND.UNA =< SEG.ACK =< SND.NXT then the ACK is acceptable.
    //"
    if (tcpseg->getAckBit())
    {
        if (seqLE(tcpseg->getAckNo(),state->iss) || seqGreater(tcpseg->getAckNo(),state->snd_nxt))
        {
            tcpEV << "ACK bit set but wrong AckNo, sending RST\n";
            sendRst(tcpseg->getAckNo(),destAddr,srcAddr,tcpseg->getDestPort(),tcpseg->getSrcPort());
            return TCP_E_IGNORE;
        }
        tcpEV << "ACK bit set, AckNo acceptable\n";
    }

    //"
    // second check the RST bit
    //
    //   If the RST bit is set
    //
    //     If the ACK was acceptable then signal the user "error:
    //     connection reset", drop the segment, enter CLOSED state,
    //     delete TCB, and return.  Otherwise (no ACK) drop the segment
    //     and return.
    //"
    if (tcpseg->getRstBit())
    {
        if (tcpseg->getAckBit())
        {
            tcpEV << "RST+ACK: performing connection reset\n";
            sendIndicationToApp(TCP_I_CONNECTION_RESET);
            return TCP_E_RCV_RST;
        }
        else
        {
            tcpEV << "RST without ACK: dropping segment\n";
            return TCP_E_IGNORE;
        }
    }

    //"
    // third check the security and precedence -- not done
    //
    // fourth check the SYN bit
    //
    //   This step should be reached only if the ACK is ok, or there is
    //   no ACK, and it the segment did not contain a RST.
    //
    //   If the SYN bit is on and the security/compartment and precedence
    //   are acceptable then,
    //"
    if (tcpseg->getSynBit())
    {
        //
        //   RCV.NXT is set to SEG.SEQ+1, IRS is set to
        //   SEG.SEQ.  SND.UNA should be advanced to equal SEG.ACK (if there
        //   is an ACK), and any segments on the retransmission queue which
        //   are thereby acknowledged should be removed.
        //
        state->rcv_nxt = tcpseg->getSequenceNo()+1;
        state->irs = tcpseg->getSequenceNo();
        receiveQueue->init(state->rcv_nxt);

        if (tcpseg->getAckBit())
        {
            state->snd_una = tcpseg->getAckNo();
            sendQueue->discardUpTo(state->snd_una);

            // although not mentioned in RFC 793, seems like we have to pick up
            // initial snd_wnd from the segment here.
            state->snd_wnd = tcpseg->getWindow();
            state->snd_wl1 = tcpseg->getSequenceNo();
            state->snd_wl2 = tcpseg->getAckNo();
            if (sndWndVector) sndWndVector->record(state->snd_wnd);
        }

        // this also seems to be a good time to learn our local IP address
        // (was probably unspecified at connection open)
        tcpMain->updateSockPair(this, destAddr, srcAddr, tcpseg->getDestPort(), tcpseg->getSrcPort());

        //"
        //   If SND.UNA > ISS (our SYN has been ACKed), change the connection
        //   state to ESTABLISHED, form an ACK segment
        //
        //     <SEQ=SND.NXT><ACK=RCV.NXT><CTL=ACK>
        //
        //   and send it.  Data or controls which were queued for
        //   transmission may be included.  If there are other controls or
        //   text in the segment then continue processing at the sixth step
        //   below where the URG bit is checked, otherwise return.
        //"
        if (seqGreater(state->snd_una, state->iss))
        {
            tcpEV << "SYN+ACK bits set, connection established.\n";

            // RFC says "continue processing at the sixth step below where
            // the URG bit is checked". Those steps deal with: URG, segment text
            // (and PSH), and FIN.
            // Now: URG and PSH we don't support yet; in SYN+FIN we ignore FIN;
            // with segment text we just take it easy and put it in the receiveQueue
            // -- we'll forward it to the user when more data arrives.
            if (tcpseg->getFinBit())
                tcpEV << "SYN+ACK+FIN received: ignoring FIN\n";
            if (tcpseg->getPayloadLength()>0)
                state->rcv_nxt = receiveQueue->insertBytesFromSegment(tcpseg); // TBD forward to app, etc.
            if (tcpseg->getUrgBit() || tcpseg->getPshBit())
                tcpEV << "Ignoring URG and PSH bits in SYN+ACK\n"; // TBD

            // notify tcpAlgorithm (it has to send ACK of SYN) and app layer
            tcpAlgorithm->established(true);
            sendEstabIndicationToApp();

            // This will trigger transition to ESTABLISHED. Timers and notifying
            // app will be taken care of in stateEntered().
            return TCP_E_RCV_SYN_ACK;
        }

        //"
        //   Otherwise enter SYN-RECEIVED, form a SYN,ACK segment
        //
        //     <SEQ=ISS><ACK=RCV.NXT><CTL=SYN,ACK>
        //
        //   and send it.  If there are other controls or text in the
        //   segment, queue them for processing after the ESTABLISHED state
        //   has been reached, return.
        //"
        tcpEV << "SYN bit set: sending SYN+ACK\n";
        state->snd_max = state->snd_nxt = state->iss;
        sendSynAck();
        startSynRexmitTimer();

        // Note: code below is similar to processing SYN in LISTEN.

        // For consistency with that code, we ignore SYN+FIN here
        if (tcpseg->getFinBit())
            tcpEV << "SYN+FIN received: ignoring FIN\n";

        // We don't send text in SYN or SYN+ACK, but accept it. Otherwise
        // there isn't much left to do: RST, SYN, ACK, FIN got processed already,
        // so there's only URG and PSH left to handle.
        if (tcpseg->getPayloadLength()>0)
            receiveQueue->insertBytesFromSegment(tcpseg);
        if (tcpseg->getUrgBit() || tcpseg->getPshBit())
            tcpEV << "Ignoring URG and PSH bits in SYN\n"; // TBD
        return TCP_E_RCV_SYN;
    }

    //"
    // fifth, if neither of the SYN or RST bits is set then drop the
    // segment and return.
    //"
    return TCP_E_IGNORE;
}

bool TCPConnection::processTCPSegment ( TCPSegment tcpSeg,
IPvXAddress  srcAddr,
IPvXAddress  destAddr 
) [virtual]

Process incoming TCP segment. Normally returns true. A return value of false means that the connection structure must be deleted by the caller (TCP).

Definition at line 221 of file old/TCPConnectionBase.cc.

Referenced by tcp_old::TCP::handleMessage().

{
    printConnBrief();
    if (!localAddr.isUnspecified())
    {
        ASSERT(localAddr==segDestAddr);
        ASSERT(localPort==tcpseg->getDestPort());
    }
    if (!remoteAddr.isUnspecified())
    {
        ASSERT(remoteAddr==segSrcAddr);
        ASSERT(remotePort==tcpseg->getSrcPort());
    }

    if (tryFastRoute(tcpseg))
        return true;

    // first do actions
    TCPEventCode event = process_RCV_SEGMENT(tcpseg, segSrcAddr, segDestAddr);

    // then state transitions
    return performStateTransition(event);
}

bool TCPConnection::processTimer ( cMessage *  msg  )  [virtual]

Process self-messages (timers). Normally returns true. A return value of false means that the connection structure must be deleted by the caller (TCP).

Definition at line 184 of file old/TCPConnectionBase.cc.

Referenced by tcp_old::TCP::handleMessage().

{
    printConnBrief();
    tcpEV << msg->getName() << " timer expired\n";

    // first do actions
    TCPEventCode event;
    if (msg==the2MSLTimer)
    {
        event = TCP_E_TIMEOUT_2MSL;
        process_TIMEOUT_2MSL();
    }
    else if (msg==connEstabTimer)
    {
        event = TCP_E_TIMEOUT_CONN_ESTAB;
        process_TIMEOUT_CONN_ESTAB();
    }
    else if (msg==finWait2Timer)
    {
        event = TCP_E_TIMEOUT_FIN_WAIT_2;
        process_TIMEOUT_FIN_WAIT_2();
    }
    else if (msg==synRexmitTimer)
    {
        event = TCP_E_IGNORE;
        process_TIMEOUT_SYN_REXMIT(event);
    }
    else
    {
        event = TCP_E_IGNORE;
        tcpAlgorithm->processTimer(msg, event);
    }

    // then state transitions
    return performStateTransition(event);
}

void TCPConnection::retransmitData (  )  [virtual]

Utility: retransmit all from snd_una to snd_max

Definition at line 623 of file old/TCPConnectionUtil.cc.

Referenced by tcp_old::DumbTCP::processTimer().

{
    // retransmit everything from snd_una
    state->snd_nxt = state->snd_una;

    uint32 bytesToSend = state->snd_max - state->snd_nxt;
    ASSERT(bytesToSend!=0);

    // TBD - avoid to send more than allowed - check cwnd and rwnd before retransmitting data!
    while (bytesToSend>0)
    {
        uint32 bytes = std::min(bytesToSend, state->snd_mss);
        bytes = std::min(bytes, (uint32)(sendQueue->getBytesAvailable(state->snd_nxt)));
        sendSegment(bytes);
        // Do not send packets after the FIN.
        // fixes bug that occurs in examples/inet/bulktransfer at event #64043  T=13.861159213744
        if (state->send_fin && state->snd_nxt==state->snd_fin_seq+1)
            break;
        bytesToSend -= bytes;
    }
}

void TCPConnection::retransmitOneSegment ( bool  called_at_rto  )  [virtual]

Utility: retransmit one segment from snd_una

Definition at line 602 of file old/TCPConnectionUtil.cc.

Referenced by tcp_old::TCPTahoe::processRexmitTimer(), tcp_old::TCPReno::processRexmitTimer(), tcp_old::TCPNoCongestionControl::processRexmitTimer(), tcp_old::TCPTahoe::receivedDuplicateAck(), and tcp_old::TCPReno::receivedDuplicateAck().

{
    // retransmit one segment at snd_una, and set snd_nxt accordingly (if not called at RTO)
    uint32 old_snd_nxt = state->snd_nxt;

    state->snd_nxt = state->snd_una;

    ulong bytes = std::min(state->snd_mss, state->snd_max - state->snd_nxt);
    ASSERT(bytes!=0);

    sendSegment(bytes);

    if (!called_at_rto)
    {
        if (seqGreater(old_snd_nxt, state->snd_nxt))
            state->snd_nxt = old_snd_nxt;
    }
    // notify
    tcpAlgorithm->ackSent();
}

void tcp_old::TCPConnection::scheduleTimeout ( cMessage *  msg,
simtime_t  timeout 
) [inline]
void TCPConnection::segmentArrivalWhileClosed ( TCPSegment tcpseg,
IPvXAddress  src,
IPvXAddress  dest 
) [virtual]

This method gets invoked from TCP when a segment arrives which doesn't belong to an existing connection. TCP creates a temporary connection object so that it can call this method, then immediately deletes it.

Definition at line 37 of file old/TCPConnectionRcvSegment.cc.

Referenced by tcp_old::TCP::segmentArrivalWhileClosed().

{
    tcpEV << "Seg arrived: ";
    printSegmentBrief(tcpseg);

    // This segment doesn't belong to any connection, so this object
    // must be a temp object created solely for the purpose of calling us
    ASSERT(state==NULL);
    tcpEV << "Segment doesn't belong to any existing connection\n";

    // RFC 793:
    //"
    // all data in the incoming segment is discarded.  An incoming
    // segment containing a RST is discarded.  An incoming segment not
    // containing a RST causes a RST to be sent in response.  The
    // acknowledgment and sequence field values are selected to make the
    // reset sequence acceptable to the TCP that sent the offending
    // segment.
    //
    // If the ACK bit is off, sequence number zero is used,
    //
    //    <SEQ=0><ACK=SEG.SEQ+SEG.LEN><CTL=RST,ACK>
    //
    // If the ACK bit is on,
    //
    //    <SEQ=SEG.ACK><CTL=RST>
    //"
    if (tcpseg->getRstBit())
    {
        tcpEV << "RST bit set: dropping segment\n";
        return;
    }

    if (!tcpseg->getAckBit())
    {
        tcpEV << "ACK bit not set: sending RST+ACK\n";
        uint32 ackNo = tcpseg->getSequenceNo() + (uint32)tcpseg->getPayloadLength();
        sendRstAck(0,ackNo,destAddr,srcAddr,tcpseg->getDestPort(),tcpseg->getSrcPort());
    }
    else
    {
        tcpEV << "ACK bit set: sending RST\n";
        sendRst(tcpseg->getAckNo(),destAddr,srcAddr,tcpseg->getDestPort(),tcpseg->getSrcPort());
    }
}

void TCPConnection::selectInitialSeqNum (  )  [protected, virtual]

Utility: generates ISS and initializes corresponding state variables

Definition at line 320 of file old/TCPConnectionUtil.cc.

Referenced by process_OPEN_ACTIVE(), process_SEND(), and processSegmentInListen().

{
    // set the initial send sequence number
    state->iss = (unsigned long)fmod(SIMTIME_DBL(simTime())*250000.0, 1.0+(double)(unsigned)0xffffffffUL) & 0xffffffffUL;

    state->snd_una = state->snd_nxt = state->snd_max = state->iss;

    sendQueue->init(state->iss+1); // +1 is for SYN
}

void TCPConnection::sendAck (  )  [virtual]
bool TCPConnection::sendData ( bool  fullSegmentsOnly,
int  congestionWindow = -1 
) [virtual]

Utility: Send data from sendQueue, at most congestionWindow (-1 means no limit). FIXME adjust comment!!! If fullSegmentsOnly is set, don't send segments smaller than MSS (needed for Nagle). Returns true if some data was actually sent.

Definition at line 480 of file old/TCPConnectionUtil.cc.

Referenced by tcp_old::DumbTCP::established(), tcp_old::DumbTCP::receivedDataAck(), tcp_old::DumbTCP::sendCommandInvoked(), and tcp_old::TCPBaseAlg::sendData().

{
    if (!state->afterRto)
    {
        // we'll start sending from snd_max
        state->snd_nxt = state->snd_max;
    }

    // check how many bytes we have
    ulong buffered = sendQueue->getBytesAvailable(state->snd_nxt);
    if (buffered==0)
        return false;

    // maxWindow is smaller of (snd_wnd, congestionWindow)
    long maxWindow = state->snd_wnd;
    if (congestionWindow>=0 && maxWindow > congestionWindow)
        maxWindow = congestionWindow;

    // effectiveWindow: number of bytes we're allowed to send now
    long effectiveWin = maxWindow - (state->snd_nxt - state->snd_una);
    if (effectiveWin <= 0)
    {
        tcpEV << "Effective window is zero (advertised window " << state->snd_wnd <<
                 ", congestion window " << congestionWindow << "), cannot send.\n";
        return false;
    }

    ulong bytesToSend = effectiveWin;

    if (bytesToSend > buffered)
        bytesToSend = buffered;

    if (fullSegmentsOnly && bytesToSend < state->snd_mss && buffered > (ulong) effectiveWin) // last segment could be less than state->snd_mss
    {
        tcpEV << "Cannot send, not enough data for a full segment (SMSS=" << state->snd_mss
            << ", in buffer " << buffered << ")\n";
        return false;
    }

    // start sending 'bytesToSend' bytes
    tcpEV << "Will send " << bytesToSend << " bytes (effectiveWindow " << effectiveWin
        << ", in buffer " << buffered << " bytes)\n";

    uint32 old_snd_nxt = state->snd_nxt;
    ASSERT(bytesToSend>0);

#ifdef TCP_SENDFRAGMENTS  /* normally undefined */
    // make agressive use of the window until the last byte
    while (bytesToSend>0)
    {
        ulong bytes = std::min(bytesToSend, state->snd_mss);
        sendSegment(bytes);
        bytesToSend -= bytes;
    }
#else
    // send <MSS segments only if it's the only segment we can send now
    // FIXME this should probably obey Nagle's alg -- to be checked
    if (bytesToSend <= state->snd_mss)
    {
        sendSegment(bytesToSend);
    }
    else
    {
        // send whole segments only (nagle_enabled)
        while (bytesToSend>=state->snd_mss)
        {
            sendSegment(state->snd_mss);
            bytesToSend -= state->snd_mss;
        }
        // check how many bytes we have - last segment could be less than state->snd_mss
        buffered = sendQueue->getBytesAvailable(state->snd_nxt);
        if (bytesToSend==buffered && buffered!=0) // last segment?
            sendSegment(bytesToSend);
        else if (bytesToSend>0)
            tcpEV << bytesToSend << " bytes of space left in effectiveWindow\n";
    }
#endif

    // remember highest seq sent (snd_nxt may be set back on retransmission,
    // but we'll need snd_max to check validity of ACKs -- they must ack
    // something we really sent)
    if (seqGreater(state->snd_nxt, state->snd_max))
        state->snd_max = state->snd_nxt;
    if (unackedVector) unackedVector->record(state->snd_max - state->snd_una);

    // notify (once is enough)
    tcpAlgorithm->ackSent();
    tcpAlgorithm->dataSent(old_snd_nxt);

    return true;
}

void TCPConnection::sendEstabIndicationToApp (  )  [protected, virtual]

Utility: sends TCP_I_ESTABLISHED indication with TCPConnectInfo to application

Definition at line 261 of file old/TCPConnectionUtil.cc.

Referenced by processSegment1stThru8th(), and processSegmentInSynSent().

{
    tcpEV << "Notifying app: " << indicationName(TCP_I_ESTABLISHED) << "\n";
    cMessage *msg = new cMessage(indicationName(TCP_I_ESTABLISHED));
    msg->setKind(TCP_I_ESTABLISHED);

    TCPConnectInfo *ind = new TCPConnectInfo();
    ind->setConnId(connId);
    ind->setLocalAddr(localAddr);
    ind->setRemoteAddr(remoteAddr);
    ind->setLocalPort(localPort);
    ind->setRemotePort(remotePort);

    msg->setControlInfo(ind);
    tcpMain->send(msg, "appOut", appGateIndex);
}

void TCPConnection::sendFin (  )  [virtual]

Utility: sends FIN

Definition at line 430 of file old/TCPConnectionUtil.cc.

Referenced by process_CLOSE().

{
    TCPSegment *tcpseg = createTCPSegment("FIN");

    // Note: ACK bit *must* be set for both FIN and FIN+ACK. What makes
    // the difference for FIN+ACK is that its ackNo acks the remote TCP's FIN.
    tcpseg->setFinBit(true);
    tcpseg->setAckBit(true);
    tcpseg->setAckNo(state->rcv_nxt);
    tcpseg->setSequenceNo(state->snd_nxt);
    tcpseg->setWindow(state->rcv_wnd);

    // send it
    sendToIP(tcpseg);

    // notify
    tcpAlgorithm->ackSent();
}

void TCPConnection::sendIndicationToApp ( int  code  )  [protected, virtual]

Utility: sends status indication (TCP_I_xxx) to application

Definition at line 250 of file old/TCPConnectionUtil.cc.

Referenced by process_TIMEOUT_CONN_ESTAB(), process_TIMEOUT_FIN_WAIT_2(), processRstInSynReceived(), processSegment1stThru8th(), processSegmentInSynSent(), and signalConnectionTimeout().

{
    tcpEV << "Notifying app: " << indicationName(code) << "\n";
    cMessage *msg = new cMessage(indicationName(code));
    msg->setKind(code);
    TCPCommand *ind = new TCPCommand();
    ind->setConnId(connId);
    msg->setControlInfo(ind);
    tcpMain->send(msg, "appOut", appGateIndex);
}

bool TCPConnection::sendProbe (  )  [virtual]

Utility: sends 1 bytes as "probe", called by the "persist" mechanism

Definition at line 572 of file old/TCPConnectionUtil.cc.

Referenced by tcp_old::TCPBaseAlg::processPersistTimer().

{
    // we'll start sending from snd_max
    state->snd_nxt = state->snd_max;

    // check we have 1 byte to send
    if (sendQueue->getBytesAvailable(state->snd_nxt)==0)
    {
        tcpEV << "Cannot send probe because send buffer is empty\n";
        return false;
    }

    uint32 old_snd_nxt = state->snd_nxt;

    tcpEV << "Sending 1 byte as probe, with seq=" << state->snd_nxt << "\n";
    sendSegment(1);

    // remember highest seq sent (snd_nxt may be set back on retransmission,
    // but we'll need snd_max to check validity of ACKs -- they must ack
    // something we really sent)
    state->snd_max = state->snd_nxt;
    if (unackedVector) unackedVector->record(state->snd_max - state->snd_una);

    // notify
    tcpAlgorithm->ackSent();
    tcpAlgorithm->dataSent(old_snd_nxt);

    return true;
}

void TCPConnection::sendRst ( uint32  seqNo  )  [virtual]
void TCPConnection::sendRst ( uint32  seq,
IPvXAddress  src,
IPvXAddress  dest,
int  srcPort,
int  destPort 
) [virtual]

Utility: sends RST; does not use connection state

Definition at line 381 of file old/TCPConnectionUtil.cc.

{
    TCPSegment *tcpseg = createTCPSegment("RST");

    tcpseg->setSrcPort(srcPort);
    tcpseg->setDestPort(destPort);

    tcpseg->setRstBit(true);
    tcpseg->setSequenceNo(seq);

    // send it
    sendToIP(tcpseg, src, dest);
}

void TCPConnection::sendRstAck ( uint32  seq,
uint32  ack,
IPvXAddress  src,
IPvXAddress  dest,
int  srcPort,
int  destPort 
) [virtual]

Utility: sends RST+ACK; does not use connection state

Definition at line 395 of file old/TCPConnectionUtil.cc.

Referenced by segmentArrivalWhileClosed().

{
    TCPSegment *tcpseg = createTCPSegment("RST+ACK");

    tcpseg->setSrcPort(srcPort);
    tcpseg->setDestPort(destPort);

    tcpseg->setRstBit(true);
    tcpseg->setAckBit(true);
    tcpseg->setSequenceNo(seq);
    tcpseg->setAckNo(ack);

    // send it
    sendToIP(tcpseg, src, dest);

    // notify
    tcpAlgorithm->ackSent();
}

void TCPConnection::sendSegment ( uint32  bytes  )  [virtual]

Utility: sends one segment of 'bytes' bytes from snd_nxt, and advances snd_nxt. sendData(), sendProbe() and retransmitData() internally all rely on this one.

Definition at line 449 of file old/TCPConnectionUtil.cc.

Referenced by retransmitData(), retransmitOneSegment(), sendData(), and sendProbe().

{
    ulong buffered = sendQueue->getBytesAvailable(state->snd_nxt);
    if (bytes > buffered) // last segment?
        bytes = buffered;

    // send one segment of 'bytes' bytes from snd_nxt, and advance snd_nxt
    TCPSegment *tcpseg = sendQueue->createSegmentWithBytes(state->snd_nxt, bytes);
    tcpseg->setAckNo(state->rcv_nxt);
    tcpseg->setAckBit(true);
    tcpseg->setWindow(state->rcv_wnd);
    // TBD when to set PSH bit?
    // TBD set URG bit if needed
    ASSERT(bytes==tcpseg->getPayloadLength());

    state->snd_nxt += bytes;

    // check if afterRto bit can be reset
    if (state->afterRto && seqGE(state->snd_nxt, state->snd_max))
        state->afterRto = false;

    if (state->send_fin && state->snd_nxt==state->snd_fin_seq)
    {
        tcpEV << "Setting FIN on segment\n";
        tcpseg->setFinBit(true);
        state->snd_nxt = state->snd_fin_seq+1;
    }

    sendToIP(tcpseg);
}

void TCPConnection::sendSyn (  )  [protected, virtual]

Utility: send SYN

Definition at line 338 of file old/TCPConnectionUtil.cc.

Referenced by process_OPEN_ACTIVE(), process_SEND(), and process_TIMEOUT_SYN_REXMIT().

{
    if (remoteAddr.isUnspecified() || remotePort==-1)
        opp_error("Error processing command OPEN_ACTIVE: foreign socket unspecified");
    if (localPort==-1)
        opp_error("Error processing command OPEN_ACTIVE: local port unspecified");

    // create segment
    TCPSegment *tcpseg = createTCPSegment("SYN");
    tcpseg->setSequenceNo(state->iss);
    tcpseg->setSynBit(true);
    tcpseg->setWindow(state->rcv_wnd);

    state->snd_max = state->snd_nxt = state->iss+1;

    // send it
    sendToIP(tcpseg);
}

void TCPConnection::sendSynAck (  )  [protected, virtual]

Utility: send SYN+ACK

Definition at line 357 of file old/TCPConnectionUtil.cc.

Referenced by process_TIMEOUT_SYN_REXMIT(), processSegmentInListen(), and processSegmentInSynSent().

{
    // create segment
    TCPSegment *tcpseg = createTCPSegment("SYN+ACK");
    tcpseg->setSequenceNo(state->iss);
    tcpseg->setAckNo(state->rcv_nxt);
    tcpseg->setSynBit(true);
    tcpseg->setAckBit(true);
    tcpseg->setWindow(state->rcv_wnd);

    state->snd_max = state->snd_nxt = state->iss+1;

    // send it
    sendToIP(tcpseg);

    // notify
    tcpAlgorithm->ackSent();
}

void TCPConnection::sendToApp ( cMessage *  msg  )  [protected, virtual]

Utility: sends packet to application

Definition at line 278 of file old/TCPConnectionUtil.cc.

Referenced by process_STATUS(), and processSegment1stThru8th().

{
    tcpMain->send(msg, "appOut", appGateIndex);
}

void TCPConnection::sendToIP ( TCPSegment tcpseg  )  [virtual]

Utility: adds control info to segment and sends it to IP

Definition at line 169 of file old/TCPConnectionUtil.cc.

Referenced by sendAck(), sendFin(), sendRst(), sendRstAck(), sendSegment(), sendSyn(), and sendSynAck().

{
    // record seq (only if we do send data) and ackno
    if (sndNxtVector && tcpseg->getPayloadLength()!=0)
        sndNxtVector->record(tcpseg->getSequenceNo());
    if (sndAckVector) sndAckVector->record(tcpseg->getAckNo());

    // final touches on the segment before sending
    tcpseg->setSrcPort(localPort);
    tcpseg->setDestPort(remotePort);
    tcpseg->setByteLength(TCP_HEADER_OCTETS+tcpseg->getPayloadLength());
    // TBD account for Options (once they get implemented)

    tcpEV << "Sending: ";
    printSegmentBrief(tcpseg);

    // TBD reuse next function for sending

    if (!remoteAddr.isIPv6())
    {
        // send over IPv4
        IPControlInfo *controlInfo = new IPControlInfo();
        controlInfo->setProtocol(IP_PROT_TCP);
        controlInfo->setSrcAddr(localAddr.get4());
        controlInfo->setDestAddr(remoteAddr.get4());
        tcpseg->setControlInfo(controlInfo);

        tcpMain->send(tcpseg,"ipOut");
    }
    else
    {
        // send over IPv6
        IPv6ControlInfo *controlInfo = new IPv6ControlInfo();
        controlInfo->setProtocol(IP_PROT_TCP);
        controlInfo->setSrcAddr(localAddr.get6());
        controlInfo->setDestAddr(remoteAddr.get6());
        tcpseg->setControlInfo(controlInfo);

        tcpMain->send(tcpseg,"ipv6Out");
    }
}

void TCPConnection::sendToIP ( TCPSegment tcpseg,
IPvXAddress  src,
IPvXAddress  dest 
) [static, protected]

Utility: send IP packet

Definition at line 211 of file old/TCPConnectionUtil.cc.

{
    tcpEV << "Sending: ";
    printSegmentBrief(tcpseg);

    if (!dest.isIPv6())
    {
        // send over IPv4
        IPControlInfo *controlInfo = new IPControlInfo();
        controlInfo->setProtocol(IP_PROT_TCP);
        controlInfo->setSrcAddr(src.get4());
        controlInfo->setDestAddr(dest.get4());
        tcpseg->setControlInfo(controlInfo);

        check_and_cast<TCP *>(simulation.getContextModule())->send(tcpseg,"ipOut");
    }
    else
    {
        // send over IPv6
        IPv6ControlInfo *controlInfo = new IPv6ControlInfo();
        controlInfo->setProtocol(IP_PROT_TCP);
        controlInfo->setSrcAddr(src.get6());
        controlInfo->setDestAddr(dest.get6());
        tcpseg->setControlInfo(controlInfo);

        check_and_cast<TCP *>(simulation.getContextModule())->send(tcpseg,"ipv6Out");
    }
}

void TCPConnection::signalConnectionTimeout (  )  [virtual]

Utility: signal to user that connection timed out

Definition at line 245 of file old/TCPConnectionUtil.cc.

Referenced by tcp_old::TCPBaseAlg::processRexmitTimer().

{
    sendIndicationToApp(TCP_I_TIMED_OUT);
}

void TCPConnection::startSynRexmitTimer (  )  [virtual]
void TCPConnection::stateEntered ( int  state  )  [protected, virtual]

Perform cleanup necessary when entering a new state, e.g. cancelling timers

Definition at line 449 of file old/TCPConnectionBase.cc.

Referenced by performStateTransition().

{
    // cancel timers
    switch (state)
    {
        case TCP_S_INIT:
            // we'll never get back to INIT
            break;
        case TCP_S_LISTEN:
            // we may get back to LISTEN from SYN_RCVD
            ASSERT(connEstabTimer && synRexmitTimer);
            cancelEvent(connEstabTimer);
            cancelEvent(synRexmitTimer);
            break;
        case TCP_S_SYN_RCVD:
        case TCP_S_SYN_SENT:
            break;
        case TCP_S_ESTABLISHED:
            // we're in ESTABLISHED, these timers are no longer needed
            delete cancelEvent(connEstabTimer);
            delete cancelEvent(synRexmitTimer);
            connEstabTimer = synRexmitTimer = NULL;
            // TCP_I_ESTAB notification moved inside event processing
            break;
        case TCP_S_CLOSE_WAIT:
        case TCP_S_LAST_ACK:
        case TCP_S_FIN_WAIT_1:
        case TCP_S_FIN_WAIT_2:
        case TCP_S_CLOSING:
        case TCP_S_TIME_WAIT:
            // whether connection setup succeeded (ESTABLISHED) or not (others),
            // cancel these timers
            if (connEstabTimer) cancelEvent(connEstabTimer);
            if (synRexmitTimer) cancelEvent(synRexmitTimer);
            break;
        case TCP_S_CLOSED:
            // all timers need to be cancelled
            if (the2MSLTimer)   cancelEvent(the2MSLTimer);
            if (connEstabTimer) cancelEvent(connEstabTimer);
            if (finWait2Timer)  cancelEvent(finWait2Timer);
            if (synRexmitTimer) cancelEvent(synRexmitTimer);
            tcpAlgorithm->connectionClosed();
            break;
    }
}

const char * TCPConnection::stateName ( int  state  )  [static]
bool TCPConnection::tryFastRoute ( TCPSegment tcpseg  )  [protected, virtual]

Shortcut to process most common case as fast as possible. Returns false if segment requires normal (slow) route.

Definition at line 30 of file old/TCPConnectionRcvSegment.cc.

Referenced by processTCPSegment().

{
    // fast route processing not yet implemented
    return false;
}


Member Data Documentation

cFSM tcp_old::TCPConnection::fsm [protected]
cOutVector* tcp_old::TCPConnection::rcvAckVector [protected]

Definition at line 296 of file TCPConnection_old.h.

Referenced by process_RCV_SEGMENT(), TCPConnection(), and ~TCPConnection().

cOutVector* tcp_old::TCPConnection::rcvSeqVector [protected]

Definition at line 295 of file TCPConnection_old.h.

Referenced by process_RCV_SEGMENT(), TCPConnection(), and ~TCPConnection().

cOutVector* tcp_old::TCPConnection::sndAckVector [protected]

Definition at line 294 of file TCPConnection_old.h.

Referenced by sendToIP(), TCPConnection(), and ~TCPConnection().

cOutVector* tcp_old::TCPConnection::sndNxtVector [protected]

Definition at line 293 of file TCPConnection_old.h.

Referenced by sendToIP(), TCPConnection(), and ~TCPConnection().

cOutVector* tcp_old::TCPConnection::sndWndVector [protected]
cMessage* tcp_old::TCPConnection::the2MSLTimer [protected]
cOutVector* tcp_old::TCPConnection::unackedVector [protected]

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