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

TCPConnection Class Reference

#include <TCPConnection.h>

List of all members.


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.


Public Member Functions

void sendAck ()
bool sendData (bool fullSegmentsOnly, int congestionWindow=-1)
bool sendProbe ()
void retransmitOneSegment ()
void retransmitData ()
void sendRst (uint32 seqNo)
void sendFin ()
void sendSegment (int bytes)
void sendToIP (TCPSegment *tcpseg)
void startSynRexmitTimer ()
void signalConnectionTimeout ()
void scheduleTimeout (cMessage *msg, simtime_t timeout)
void printConnBrief ()
 TCPConnection (TCP *mod, int appGateIndex, int connId)
 ~TCPConnection ()
bool processTimer (cMessage *msg)
bool processTCPSegment (TCPSegment *tcpSeg, IPvXAddress srcAddr, IPvXAddress destAddr)
bool processAppCommand (cMessage *msg)
int getFsmState () const
TCPStateVariablesgetState ()
TCPSendQueuegetSendQueue ()
TCPReceiveQueuegetReceiveQueue ()
TCPAlgorithmgetTcpAlgorithm ()
TCPgetTcpMain ()

Static Public Member Functions

static void sendRst (uint32 seq, IPvXAddress src, IPvXAddress dest, int srcPort, int destPort)
static void sendRstAck (uint32 seq, uint32 ack, IPvXAddress src, IPvXAddress dest, int srcPort, int destPort)
static void printSegmentBrief (TCPSegment *tcpseg)
static const char * stateName (int state)
static const char * eventName (int event)
static const char * indicationName (int code)
static void segmentArrivalWhileClosed (TCPSegment *tcpseg, IPvXAddress src, IPvXAddress dest)

Public Attributes

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

Protected Member Functions

TCPConnectioncloneListeningConnection ()
void initConnection (TCPOpenCommand *openCmd)
void configureStateVariables ()
void selectInitialSeqNum ()
bool isSegmentAcceptable (TCPSegment *tcpseg)
void sendSyn ()
void sendSynAck ()
cMessage * cancelEvent (cMessage *msg)
void sendToApp (cMessage *msg)
void sendIndicationToApp (int code)
void sendEstabIndicationToApp ()
FSM transitions: analysing events and executing state transitions
TCPEventCode preanalyseAppCommandEvent (int commandCode)
bool performStateTransition (const TCPEventCode &event)
void stateEntered (int state)
Processing app commands. Invoked from processAppCommand().
void process_OPEN_ACTIVE (TCPEventCode &event, TCPCommand *tcpCommand, cMessage *msg)
void process_OPEN_PASSIVE (TCPEventCode &event, TCPCommand *tcpCommand, cMessage *msg)
void process_SEND (TCPEventCode &event, TCPCommand *tcpCommand, cMessage *msg)
void process_CLOSE (TCPEventCode &event, TCPCommand *tcpCommand, cMessage *msg)
void process_ABORT (TCPEventCode &event, TCPCommand *tcpCommand, cMessage *msg)
void process_STATUS (TCPEventCode &event, TCPCommand *tcpCommand, cMessage *msg)
Processing TCP segment arrivals. Invoked from processTCPSegment().
bool tryFastRoute (TCPSegment *tcpseg)
TCPEventCode process_RCV_SEGMENT (TCPSegment *tcpseg, IPvXAddress src, IPvXAddress dest)
TCPEventCode processSegmentInListen (TCPSegment *tcpseg, IPvXAddress src, IPvXAddress dest)
TCPEventCode processSegmentInSynSent (TCPSegment *tcpseg, IPvXAddress src, IPvXAddress dest)
TCPEventCode processSegment1stThru8th (TCPSegment *tcpseg)
TCPEventCode processRstInSynReceived (TCPSegment *tcpseg)
bool processAckInEstabEtc (TCPSegment *tcpseg)
Processing timeouts. Invoked from processTimer().
void process_TIMEOUT_2MSL ()
void process_TIMEOUT_CONN_ESTAB ()
void process_TIMEOUT_FIN_WAIT_2 ()
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


Constructor & Destructor Documentation

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

Constructor.

00102 {
00103     tcpMain = _mod;
00104     appGateIndex = _appGateIndex;
00105     connId = _connId;
00106 
00107     localPort = remotePort = -1;
00108 
00109     char fsmname[24];
00110     sprintf(fsmname, "fsm-%d", connId);
00111     fsm.setName(fsmname);
00112     fsm.setState(TCP_S_INIT);
00113 
00114 
00115     // queues and algorithm will be created on active or passive open
00116     sendQueue = NULL;
00117     receiveQueue = NULL;
00118     tcpAlgorithm = NULL;
00119     state = NULL;
00120 
00121     the2MSLTimer = new cMessage("2MSL");
00122     connEstabTimer = new cMessage("CONN-ESTAB");
00123     finWait2Timer = new cMessage("FIN-WAIT-2");
00124     synRexmitTimer = new cMessage("SYN-REXMIT");
00125 
00126     the2MSLTimer->setContextPointer(this);
00127     connEstabTimer->setContextPointer(this);
00128     finWait2Timer->setContextPointer(this);
00129     synRexmitTimer->setContextPointer(this);
00130 
00131     // statistics
00132     sndWndVector = NULL;
00133     sndNxtVector = NULL;
00134     sndAckVector = NULL;
00135     rcvSeqVector = NULL;
00136     rcvAckVector = NULL;
00137     unackedVector = NULL;
00138 
00139     if (getTcpMain()->recordStatistics)
00140     {
00141         sndWndVector = new cOutVector("send window");
00142         sndNxtVector = new cOutVector("send seq");
00143         sndAckVector = new cOutVector("sent ack");
00144         rcvSeqVector = new cOutVector("rcvd seq");
00145         rcvAckVector = new cOutVector("rcvd ack");
00146         unackedVector = new cOutVector("unacked bytes");
00147     }
00148 }

TCPConnection::~TCPConnection  ) 
 

Destructor.

00151 {
00152     delete sendQueue;
00153     delete receiveQueue;
00154     delete tcpAlgorithm;
00155     delete state;
00156 
00157     if (the2MSLTimer)   delete cancelEvent(the2MSLTimer);
00158     if (connEstabTimer) delete cancelEvent(connEstabTimer);
00159     if (finWait2Timer)  delete cancelEvent(finWait2Timer);
00160     if (synRexmitTimer) delete cancelEvent(synRexmitTimer);
00161 
00162     // statistics
00163     delete sndWndVector;
00164     delete sndNxtVector;
00165     delete sndAckVector;
00166     delete rcvSeqVector;
00167     delete rcvAckVector;
00168     delete unackedVector;
00169 }


Member Function Documentation

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

Utility: cancel a timer

00412 {return tcpMain->cancelEvent(msg);}

TCPConnection * TCPConnection::cloneListeningConnection  )  [protected]
 

Utility: clone a listening connection. Used for forking.

00138 {
00139     TCPConnection *conn = new TCPConnection(tcpMain,appGateIndex,connId);
00140 
00141     // following code to be kept consistent with initConnection()
00142     const char *sendQueueClass = sendQueue->className();
00143     conn->sendQueue = check_and_cast<TCPSendQueue *>(createOne(sendQueueClass));
00144 
00145     const char *receiveQueueClass = receiveQueue->className();
00146     conn->receiveQueue = check_and_cast<TCPReceiveQueue *>(createOne(receiveQueueClass));
00147 
00148     const char *tcpAlgorithmClass = tcpAlgorithm->className();
00149     conn->tcpAlgorithm = check_and_cast<TCPAlgorithm *>(createOne(tcpAlgorithmClass));
00150     conn->tcpAlgorithm->setConnection(conn);
00151 
00152     conn->state = conn->tcpAlgorithm->stateVariables();
00153     configureStateVariables();
00154     conn->tcpAlgorithm->initialize();
00155 
00156     // put it into LISTEN, with our localAddr/localPort
00157     conn->state->active = false;
00158     conn->state->fork = true;
00159     conn->localAddr = localAddr;
00160     conn->localPort = localPort;
00161     FSM_Goto(conn->fsm, TCP_S_LISTEN);
00162 
00163     return conn;
00164 }

void TCPConnection::configureStateVariables  )  [protected]
 

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

00302 {
00303     state->snd_mss = tcpMain->par("mss").longValue(); // TODO: mss=-1 should mean autodetect
00304     state->rcv_wnd = tcpMain->par("advertisedWindow").longValue();
00305 }

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

Utility: returns name of TCP_E_xxx constants

00060 {
00061 #define CASE(x) case x: s=#x+6; break
00062     const char *s = "unknown";
00063     switch (event)
00064     {
00065         CASE(TCP_E_IGNORE);
00066         CASE(TCP_E_OPEN_ACTIVE);
00067         CASE(TCP_E_OPEN_PASSIVE);
00068         CASE(TCP_E_SEND);
00069         CASE(TCP_E_CLOSE);
00070         CASE(TCP_E_ABORT);
00071         CASE(TCP_E_STATUS);
00072         CASE(TCP_E_RCV_DATA);
00073         CASE(TCP_E_RCV_ACK);
00074         CASE(TCP_E_RCV_SYN);
00075         CASE(TCP_E_RCV_SYN_ACK);
00076         CASE(TCP_E_RCV_FIN);
00077         CASE(TCP_E_RCV_FIN_ACK);
00078         CASE(TCP_E_RCV_RST);
00079         CASE(TCP_E_RCV_UNEXP_SYN);
00080         CASE(TCP_E_TIMEOUT_2MSL);
00081         CASE(TCP_E_TIMEOUT_CONN_ESTAB);
00082         CASE(TCP_E_TIMEOUT_FIN_WAIT_2);
00083     }
00084     return s;
00085 #undef CASE
00086 }

int TCPConnection::getFsmState  )  const [inline]
 

00457 {return fsm.state();}

TCPReceiveQueue* TCPConnection::getReceiveQueue  )  [inline]
 

00460 {return receiveQueue;}

TCPSendQueue* TCPConnection::getSendQueue  )  [inline]
 

00459 {return sendQueue;}

TCPStateVariables* TCPConnection::getState  )  [inline]
 

00458 {return state;}

TCPAlgorithm* TCPConnection::getTcpAlgorithm  )  [inline]
 

00461 {return tcpAlgorithm;}

TCP* TCPConnection::getTcpMain  )  [inline]
 

00462 {return tcpMain;}

const char * TCPConnection::indicationName int  code  )  [static]
 

Utility: returns name of TCP_I_xxx constants

00089 {
00090 #define CASE(x) case x: s=#x+6; break
00091     const char *s = "unknown";
00092     switch (code)
00093     {
00094         CASE(TCP_I_DATA);
00095         CASE(TCP_I_URGENT_DATA);
00096         CASE(TCP_I_ESTABLISHED);
00097         CASE(TCP_I_PEER_CLOSED);
00098         CASE(TCP_I_CLOSED);
00099         CASE(TCP_I_CONNECTION_REFUSED);
00100         CASE(TCP_I_CONNECTION_RESET);
00101         CASE(TCP_I_TIMED_OUT);
00102         CASE(TCP_I_STATUS);
00103     }
00104     return s;
00105 #undef CASE
00106 }

void TCPConnection::initConnection TCPOpenCommand *  openCmd  )  [protected]
 

Utility: creates send/receive queues and tcpAlgorithm

00276 {
00277     // create send/receive queues
00278     const char *sendQueueClass = openCmd->sendQueueClass();
00279     if (!sendQueueClass || !sendQueueClass[0])
00280         sendQueueClass = tcpMain->par("sendQueueClass");
00281     sendQueue = check_and_cast<TCPSendQueue *>(createOne(sendQueueClass));
00282 
00283     const char *receiveQueueClass = openCmd->receiveQueueClass();
00284     if (!receiveQueueClass || !receiveQueueClass[0])
00285         receiveQueueClass = tcpMain->par("receiveQueueClass");
00286     receiveQueue = check_and_cast<TCPReceiveQueue *>(createOne(receiveQueueClass));
00287 
00288     // create algorithm
00289     const char *tcpAlgorithmClass = openCmd->tcpAlgorithmClass();
00290     if (!tcpAlgorithmClass || !tcpAlgorithmClass[0])
00291         tcpAlgorithmClass = tcpMain->par("tcpAlgorithmClass");
00292     tcpAlgorithm = check_and_cast<TCPAlgorithm *>(createOne(tcpAlgorithmClass));
00293     tcpAlgorithm->setConnection(this);
00294 
00295     // create state block
00296     state = tcpAlgorithm->stateVariables();
00297     configureStateVariables();
00298     tcpAlgorithm->initialize();
00299 }

bool TCPConnection::isSegmentAcceptable TCPSegment tcpseg  )  [protected]
 

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

00318 {
00319     // segment entirely falls in receive window
00320     //FIXME probably not this simple, see old code segAccept() below...
00321     return seqGE(tcpseg->sequenceNo(),state->rcv_nxt) &&
00322            seqLE(tcpseg->sequenceNo()+tcpseg->payloadLength(),state->rcv_nxt+state->rcv_wnd);
00323 }

bool TCPConnection::performStateTransition const TCPEventCode event  )  [protected]
 

Implemements the pure TCP state machine

00272 {
00273     ASSERT(fsm.state()!=TCP_S_CLOSED); // closed connections should be deleted immediately
00274 
00275     if (event==TCP_E_IGNORE)  // e.g. discarded segment
00276     {
00277         tcpEV << "Staying in state: " << stateName(fsm.state()) << " (no FSM event)\n";
00278         return true;
00279     }
00280 
00281     // state machine
00282     // TBD add handling of connection timeout event (keepalive), with transition to CLOSED
00283     // Note: empty "default:" lines are for gcc's benefit which would otherwise spit warnings
00284     int oldState = fsm.state();
00285     switch (fsm.state())
00286     {
00287         case TCP_S_INIT:
00288             switch (event)
00289             {
00290                 case TCP_E_OPEN_PASSIVE:FSM_Goto(fsm, TCP_S_LISTEN); break;
00291                 case TCP_E_OPEN_ACTIVE: FSM_Goto(fsm, TCP_S_SYN_SENT); break;
00292                 default:;
00293             }
00294             break;
00295 
00296         case TCP_S_LISTEN:
00297             switch (event)
00298             {
00299                 case TCP_E_OPEN_ACTIVE: FSM_Goto(fsm, TCP_S_SYN_SENT); break;
00300                 case TCP_E_SEND:        FSM_Goto(fsm, TCP_S_SYN_SENT); break;
00301                 case TCP_E_CLOSE:       FSM_Goto(fsm, TCP_S_CLOSED); break;
00302                 case TCP_E_ABORT:       FSM_Goto(fsm, TCP_S_CLOSED); break;
00303                 case TCP_E_RCV_SYN:     FSM_Goto(fsm, TCP_S_SYN_RCVD);break;
00304                 default:;
00305             }
00306             break;
00307 
00308         case TCP_S_SYN_RCVD:
00309             switch (event)
00310             {
00311                 case TCP_E_CLOSE:       FSM_Goto(fsm, TCP_S_FIN_WAIT_1); break;
00312                 case TCP_E_ABORT:       FSM_Goto(fsm, TCP_S_CLOSED); break;
00313                 case TCP_E_TIMEOUT_CONN_ESTAB: FSM_Goto(fsm, state->active ? TCP_S_CLOSED : TCP_S_LISTEN); break;
00314                 case TCP_E_RCV_RST:     FSM_Goto(fsm, state->active ? TCP_S_CLOSED : TCP_S_LISTEN); break;
00315                 case TCP_E_RCV_ACK:     FSM_Goto(fsm, TCP_S_ESTABLISHED); break;
00316                 case TCP_E_RCV_FIN:     FSM_Goto(fsm, TCP_S_CLOSE_WAIT); break;
00317                 case TCP_E_RCV_UNEXP_SYN: FSM_Goto(fsm, TCP_S_CLOSED); break;
00318                 default:;
00319             }
00320             break;
00321 
00322         case TCP_S_SYN_SENT:
00323             switch (event)
00324             {
00325                 case TCP_E_CLOSE:       FSM_Goto(fsm, TCP_S_CLOSED); break;
00326                 case TCP_E_ABORT:       FSM_Goto(fsm, TCP_S_CLOSED); break;
00327                 case TCP_E_TIMEOUT_CONN_ESTAB: FSM_Goto(fsm, TCP_S_CLOSED); break;
00328                 case TCP_E_RCV_RST:     FSM_Goto(fsm, TCP_S_CLOSED); break;
00329                 case TCP_E_RCV_SYN_ACK: FSM_Goto(fsm, TCP_S_ESTABLISHED); break;
00330                 case TCP_E_RCV_SYN:     FSM_Goto(fsm, TCP_S_SYN_RCVD); break;
00331                 default:;
00332             }
00333             break;
00334 
00335         case TCP_S_ESTABLISHED:
00336             switch (event)
00337             {
00338                 case TCP_E_CLOSE:       FSM_Goto(fsm, TCP_S_FIN_WAIT_1); break;
00339                 case TCP_E_ABORT:       FSM_Goto(fsm, TCP_S_CLOSED); break;
00340                 case TCP_E_RCV_FIN:     FSM_Goto(fsm, TCP_S_CLOSE_WAIT); break;
00341                 case TCP_E_RCV_RST:     FSM_Goto(fsm, TCP_S_CLOSED); break;
00342                 case TCP_E_RCV_UNEXP_SYN: FSM_Goto(fsm, TCP_S_CLOSED); break;
00343                 default:;
00344             }
00345             break;
00346 
00347         case TCP_S_CLOSE_WAIT:
00348             switch (event)
00349             {
00350                 case TCP_E_CLOSE:       FSM_Goto(fsm, TCP_S_LAST_ACK); break;
00351                 case TCP_E_ABORT:       FSM_Goto(fsm, TCP_S_CLOSED); break;
00352                 case TCP_E_RCV_RST:     FSM_Goto(fsm, TCP_S_CLOSED); break;
00353                 case TCP_E_RCV_UNEXP_SYN: FSM_Goto(fsm, TCP_S_CLOSED); break;
00354                 default:;
00355             }
00356             break;
00357 
00358         case TCP_S_LAST_ACK:
00359             switch (event)
00360             {
00361                 case TCP_E_ABORT:       FSM_Goto(fsm, TCP_S_CLOSED); break;
00362                 case TCP_E_RCV_ACK:     FSM_Goto(fsm, TCP_S_CLOSED); break;
00363                 case TCP_E_RCV_RST:     FSM_Goto(fsm, TCP_S_CLOSED); break;
00364                 case TCP_E_RCV_UNEXP_SYN: FSM_Goto(fsm, TCP_S_CLOSED); break;
00365                 default:;
00366             }
00367             break;
00368 
00369         case TCP_S_FIN_WAIT_1:
00370             switch (event)
00371             {
00372                 case TCP_E_ABORT:       FSM_Goto(fsm, TCP_S_CLOSED); break;
00373                 case TCP_E_RCV_FIN:     FSM_Goto(fsm, TCP_S_CLOSING); break;
00374                 case TCP_E_RCV_ACK:     FSM_Goto(fsm, TCP_S_FIN_WAIT_2); break;
00375                 case TCP_E_RCV_FIN_ACK: FSM_Goto(fsm, TCP_S_TIME_WAIT); break;
00376                 case TCP_E_RCV_RST:     FSM_Goto(fsm, TCP_S_CLOSED); break;
00377                 case TCP_E_RCV_UNEXP_SYN: FSM_Goto(fsm, TCP_S_CLOSED); break;
00378                 default:;
00379             }
00380             break;
00381 
00382         case TCP_S_FIN_WAIT_2:
00383             switch (event)
00384             {
00385                 case TCP_E_ABORT:       FSM_Goto(fsm, TCP_S_CLOSED); break;
00386                 case TCP_E_RCV_FIN:     FSM_Goto(fsm, TCP_S_TIME_WAIT); break;
00387                 case TCP_E_TIMEOUT_FIN_WAIT_2: FSM_Goto(fsm, TCP_S_CLOSED); break;
00388                 case TCP_E_RCV_RST:     FSM_Goto(fsm, TCP_S_CLOSED); break;
00389                 case TCP_E_RCV_UNEXP_SYN: FSM_Goto(fsm, TCP_S_CLOSED); break;
00390                 default:;
00391             }
00392             break;
00393 
00394         case TCP_S_CLOSING:
00395             switch (event)
00396             {
00397                 case TCP_E_ABORT:       FSM_Goto(fsm, TCP_S_CLOSED); break;
00398                 case TCP_E_RCV_ACK:     FSM_Goto(fsm, TCP_S_TIME_WAIT); break;
00399                 case TCP_E_RCV_RST:     FSM_Goto(fsm, TCP_S_CLOSED); break;
00400                 case TCP_E_RCV_UNEXP_SYN: FSM_Goto(fsm, TCP_S_CLOSED); break;
00401                 default:;
00402             }
00403             break;
00404 
00405         case TCP_S_TIME_WAIT:
00406             switch (event)
00407             {
00408                 case TCP_E_ABORT:       FSM_Goto(fsm, TCP_S_CLOSED); break;
00409                 case TCP_E_TIMEOUT_2MSL: FSM_Goto(fsm, TCP_S_CLOSED); break;
00410                 case TCP_E_RCV_RST:     FSM_Goto(fsm, TCP_S_CLOSED); break;
00411                 case TCP_E_RCV_UNEXP_SYN: FSM_Goto(fsm, TCP_S_CLOSED); break;
00412                 default:;
00413             }
00414             break;
00415 
00416         case TCP_S_CLOSED:
00417             break;
00418     }
00419 
00420     if (oldState!=fsm.state())
00421     {
00422         tcpEV << "Transition: " << stateName(oldState) << " --> " << stateName(fsm.state()) << "  (event was: " << eventName(event) << ")\n";
00423         testingEV << tcpMain->name() << ": " << stateName(oldState) << " --> " << stateName(fsm.state()) << "  (on " << eventName(event) << ")\n";
00424 
00425         // cancel timers, etc.
00426         stateEntered(fsm.state());
00427     }
00428     else
00429     {
00430         tcpEV << "Staying in state: " << stateName(fsm.state()) << " (event was: " << eventName(event) << ")\n";
00431     }
00432 
00433     return fsm.state()!=TCP_S_CLOSED;
00434 }

TCPEventCode TCPConnection::preanalyseAppCommandEvent int  commandCode  )  [protected]
 

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

00257 {
00258     switch (commandCode)
00259     {
00260         case TCP_C_OPEN_ACTIVE:  return TCP_E_OPEN_ACTIVE;
00261         case TCP_C_OPEN_PASSIVE: return TCP_E_OPEN_PASSIVE;
00262         case TCP_C_SEND:         return TCP_E_SEND;
00263         case TCP_C_CLOSE:        return TCP_E_CLOSE;
00264         case TCP_C_ABORT:        return TCP_E_ABORT;
00265         case TCP_C_STATUS:       return TCP_E_STATUS;
00266         default: opp_error("Unknown message kind in app command");
00267                  return (TCPEventCode)0; // to satisfy compiler
00268     }
00269 }

void TCPConnection::printConnBrief  ) 
 

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

00109 {
00110     tcpEV << "Connection ";
00111     tcpEV << localAddr << ":" << localPort << " to " << remoteAddr << ":" << remotePort;
00112     tcpEV << "  on app[" << appGateIndex << "],connId=" << connId;
00113     tcpEV << "  in " << stateName(fsm.state());
00114     tcpEV << "  (ptr=0x" << this << ")\n";
00115 }

void TCPConnection::printSegmentBrief TCPSegment tcpseg  )  [static]
 

Utility: prints important header fields

00118 {
00119     tcpEV << "." << tcpseg->srcPort() << " > ";
00120     tcpEV << "." << tcpseg->destPort() << ": ";
00121 
00122     if (tcpseg->synBit())  tcpEV << (tcpseg->ackBit() ? "SYN+ACK " : "SYN ");
00123     if (tcpseg->finBit())  tcpEV << "FIN(+ACK) ";
00124     if (tcpseg->rstBit())  tcpEV << (tcpseg->ackBit() ? "RST+ACK " : "RST ");
00125     if (tcpseg->pshBit())  tcpEV << "PSH ";
00126 
00127     if (tcpseg->payloadLength()>0 || tcpseg->synBit())
00128     {
00129         tcpEV << tcpseg->sequenceNo() << ":" << tcpseg->sequenceNo()+tcpseg->payloadLength();
00130         tcpEV << "(" << tcpseg->payloadLength() << ") ";
00131     }
00132     if (tcpseg->ackBit())  tcpEV << "ack " << tcpseg->ackNo() << " ";
00133     tcpEV << "win " << tcpseg->window() << "\n";
00134     if (tcpseg->urgBit())  tcpEV << "urg " << tcpseg->urgentPointer() << " ";
00135 }

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

00222 {
00223     delete tcpCommand;
00224     delete msg;
00225 
00226     //
00227     // The ABORT event will automatically take the connection to the CLOSED
00228     // state, flush queues etc -- no need to do it here. Also, we don't need to
00229     // send notification to the user, they know what's going on.
00230     //
00231     switch(fsm.state())
00232     {
00233         case TCP_S_INIT:
00234             opp_error("Error processing command ABORT: connection not open");
00235 
00236         case TCP_S_SYN_RCVD:
00237         case TCP_S_ESTABLISHED:
00238         case TCP_S_FIN_WAIT_1:
00239         case TCP_S_FIN_WAIT_2:
00240         case TCP_S_CLOSE_WAIT:
00241             //"
00242             // Send a reset segment:
00243             //
00244             //   <SEQ=SND.NXT><CTL=RST>
00245             //"
00246             sendRst(state->snd_nxt);
00247             break;
00248     }
00249 
00250 }

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

00162 {
00163     delete tcpCommand;
00164     delete msg;
00165 
00166     switch(fsm.state())
00167     {
00168         case TCP_S_INIT:
00169             opp_error("Error processing command CLOSE: connection not open");
00170 
00171         case TCP_S_LISTEN:
00172             // Nothing to do here
00173             break;
00174 
00175         case TCP_S_SYN_SENT:
00176             // Delete the TCB and return "error:  closing" responses to any
00177             // queued SENDs, or RECEIVEs.
00178             break;
00179 
00180         case TCP_S_SYN_RCVD:
00181         case TCP_S_ESTABLISHED:
00182         case TCP_S_CLOSE_WAIT:
00183             //
00184             // SYN_RCVD processing (ESTABLISHED and CLOSE_WAIT are similar):
00185             //"
00186             // If no SENDs have been issued and there is no pending data to send,
00187             // then form a FIN segment and send it, and enter FIN-WAIT-1 state;
00188             // otherwise queue for processing after entering ESTABLISHED state.
00189             //"
00190             if (state->snd_max==sendQueue->bufferEndSeq())
00191             {
00192                 tcpEV << "No outstanding SENDs, sending FIN right away, advancing snd_nxt over the FIN\n";
00193                 state->snd_nxt = state->snd_max;
00194                 sendFin();
00195                 state->snd_max = ++state->snd_nxt;
00196                 if (unackedVector) unackedVector->record(state->snd_max - state->snd_una);
00197 
00198                 // state transition will automatically take us to FIN_WAIT_1 (or LAST_ACK)
00199             }
00200             else
00201             {
00202                 tcpEV << "SEND of " << (sendQueue->bufferEndSeq()-state->snd_max) <<
00203                       " bytes pending, deferring sending of FIN\n";
00204                 event = TCP_E_IGNORE;
00205             }
00206             state->send_fin = true;
00207             state->snd_fin_seq = sendQueue->bufferEndSeq();
00208             break;
00209 
00210         case TCP_S_FIN_WAIT_1:
00211         case TCP_S_FIN_WAIT_2:
00212         case TCP_S_CLOSING:
00213         case TCP_S_LAST_ACK:
00214         case TCP_S_TIME_WAIT:
00215             // RFC 793 is not entirely clear on how to handle a duplicate close request.
00216             // Here we treat it as an error.
00217             opp_error("Duplicate CLOSE command: connection already closing");
00218     }
00219 }

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

00035 {
00036     TCPOpenCommand *openCmd = check_and_cast<TCPOpenCommand *>(tcpCommand);
00037     IPvXAddress localAddr, remoteAddr;
00038     short localPort, remotePort;
00039 
00040     switch(fsm.state())
00041     {
00042         case TCP_S_INIT:
00043             initConnection(openCmd);
00044 
00045             // store local/remote socket
00046             state->active = true;
00047             localAddr = openCmd->localAddr();
00048             remoteAddr = openCmd->remoteAddr();
00049             localPort = openCmd->localPort();
00050             remotePort = openCmd->remotePort();
00051 
00052             if (remoteAddr.isUnspecified() || remotePort==-1)
00053                 opp_error("Error processing command OPEN_ACTIVE: remote address and port must be specified");
00054 
00055             if (localPort==-1)
00056             {
00057                 localPort = tcpMain->getEphemeralPort();
00058                 tcpEV << "Assigned ephemeral port " << localPort << "\n";
00059             }
00060 
00061             tcpEV << "OPEN: " << localAddr << ":" << localPort << " --> " << remoteAddr << ":" << remotePort << "\n";
00062 
00063             tcpMain->addSockPair(this, localAddr, remoteAddr, localPort, remotePort);
00064 
00065             // send initial SYN
00066             selectInitialSeqNum();
00067             sendSyn();
00068             startSynRexmitTimer();
00069             scheduleTimeout(connEstabTimer, TCP_TIMEOUT_CONN_ESTAB);
00070             break;
00071 
00072         default:
00073             opp_error("Error processing command OPEN_ACTIVE: connection already exists");
00074     }
00075 
00076     delete openCmd;
00077     delete msg;
00078 }

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

00081 {
00082     TCPOpenCommand *openCmd = check_and_cast<TCPOpenCommand *>(tcpCommand);
00083     IPvXAddress localAddr;
00084     short localPort;
00085 
00086     switch(fsm.state())
00087     {
00088         case TCP_S_INIT:
00089             initConnection(openCmd);
00090 
00091             // store local/remote socket
00092             state->active = false;
00093             state->fork = openCmd->fork();
00094             localAddr = openCmd->localAddr();
00095             localPort = openCmd->localPort();
00096 
00097             if (localPort==-1)
00098                 opp_error("Error processing command OPEN_PASSIVE: local port must be specified");
00099 
00100             tcpEV << "Starting to listen on: " << localAddr << ":" << localPort << "\n";
00101 
00102             tcpMain->addSockPair(this, localAddr, IPvXAddress(), localPort, -1);
00103             break;
00104 
00105         default:
00106             opp_error("Error processing command OPEN_PASSIVE: connection already exists");
00107     }
00108 
00109     delete openCmd;
00110     delete msg;
00111 }

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

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

00080 {
00081     tcpEV << "Seg arrived: ";
00082     printSegmentBrief(tcpseg);
00083     tcpEV << "TCB: " << state->info() << "\n";
00084 
00085     if (rcvSeqVector) rcvSeqVector->record(tcpseg->sequenceNo());
00086     if (rcvAckVector) rcvAckVector->record(tcpseg->ackNo());
00087 
00088     //
00089     // Note: this code is organized exactly as RFC 793, section "3.9 Event
00090     // Processing", subsection "SEGMENT ARRIVES".
00091     //
00092     TCPEventCode event;
00093     if (fsm.state()==TCP_S_LISTEN)
00094     {
00095         event = processSegmentInListen(tcpseg, src, dest);
00096     }
00097     else if (fsm.state()==TCP_S_SYN_SENT)
00098     {
00099         event = processSegmentInSynSent(tcpseg, src, dest);
00100     }
00101     else
00102     {
00103         // RFC 793 steps "first check sequence number", "second check the RST bit", etc
00104         event = processSegment1stThru8th(tcpseg);
00105     }
00106     delete tcpseg;
00107     return event;
00108 }

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

00114 {
00115     TCPSendCommand *sendCommand = check_and_cast<TCPSendCommand *>(tcpCommand);
00116 
00117     // FIXME how to support PUSH? One option is to treat each SEND as a unit of data,
00118     // and set PSH at SEND boundaries
00119     switch(fsm.state())
00120     {
00121         case TCP_S_INIT:
00122             opp_error("Error processing command SEND: connection not open");
00123 
00124         case TCP_S_LISTEN:
00125             tcpEV << "SEND command turns passive open into active open, sending initial SYN\n";
00126             state->active = true;
00127             selectInitialSeqNum();
00128             sendSyn();
00129             startSynRexmitTimer();
00130             scheduleTimeout(connEstabTimer, TCP_TIMEOUT_CONN_ESTAB);
00131             sendQueue->enqueueAppData(msg);  // queue up for later
00132             tcpEV << sendQueue->bytesAvailable(state->snd_una) << " bytes in queue\n";
00133             break;
00134 
00135         case TCP_S_SYN_RCVD:
00136         case TCP_S_SYN_SENT:
00137             tcpEV << "Queueing up data for sending later.\n";
00138             sendQueue->enqueueAppData(msg); // queue up for later
00139             tcpEV << sendQueue->bytesAvailable(state->snd_una) << " bytes in queue\n";
00140             break;
00141 
00142         case TCP_S_ESTABLISHED:
00143         case TCP_S_CLOSE_WAIT:
00144             sendQueue->enqueueAppData(msg);
00145             tcpEV << sendQueue->bytesAvailable(state->snd_una) << " bytes in queue, plus "
00146                   << (state->snd_max-state->snd_una) << " bytes unacknowledged\n";
00147             tcpAlgorithm->sendCommandInvoked();
00148             break;
00149 
00150         case TCP_S_LAST_ACK:
00151         case TCP_S_FIN_WAIT_1:
00152         case TCP_S_FIN_WAIT_2:
00153         case TCP_S_CLOSING:
00154         case TCP_S_TIME_WAIT:
00155             opp_error("Error processing command SEND: connection closing");
00156     }
00157 
00158     delete sendCommand; // msg itself has been taken by the sendQueue
00159 }

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

00253 {
00254     delete tcpCommand; // but reuse msg for reply
00255 
00256     if (fsm.state()==TCP_S_INIT)
00257         opp_error("Error processing command STATUS: connection not open");
00258 
00259     TCPStatusInfo *statusInfo = new TCPStatusInfo();
00260 
00261     statusInfo->setState(fsm.state());
00262     statusInfo->setStateName(stateName(fsm.state()));
00263 
00264     statusInfo->setLocalAddr(localAddr);
00265     statusInfo->setRemoteAddr(remoteAddr);
00266     statusInfo->setLocalPort(localPort);
00267     statusInfo->setRemotePort(remotePort);
00268 
00269     statusInfo->setSnd_mss(state->snd_mss);
00270     statusInfo->setSnd_una(state->snd_una);
00271     statusInfo->setSnd_nxt(state->snd_nxt);
00272     statusInfo->setSnd_max(state->snd_max);
00273     statusInfo->setSnd_wnd(state->snd_wnd);
00274     statusInfo->setSnd_up(state->snd_up);
00275     statusInfo->setSnd_wl1(state->snd_wl1);
00276     statusInfo->setSnd_wl2(state->snd_wl2);
00277     statusInfo->setIss(state->iss);
00278     statusInfo->setRcv_nxt(state->rcv_nxt);
00279     statusInfo->setRcv_wnd(state->rcv_wnd);
00280     statusInfo->setRcv_up(state->rcv_up);
00281     statusInfo->setIrs(state->irs);
00282     statusInfo->setFin_ack_rcvd(state->fin_ack_rcvd);
00283 
00284     msg->setControlInfo(statusInfo);
00285     sendToApp(msg);
00286 }

void TCPConnection::process_TIMEOUT_2MSL  )  [protected]
 

01024 {
01025     //"
01026     // If the time-wait timeout expires on a connection delete the TCB,
01027     // enter the CLOSED state and return.
01028     //"
01029     switch(fsm.state())
01030     {
01031         case TCP_S_TIME_WAIT:
01032             // Nothing to do here. The TIMEOUT_2MSL event will automatically take
01033             // the connection to CLOSED. We already notified the user
01034             // (TCP_I_CLOSED) when we entered the TIME_WAIT state from CLOSING,
01035             // FIN_WAIT_1 or FIN_WAIT_2.
01036             break;
01037         default:
01038             // We should not receive this timeout in this state.
01039             opp_error("Internal error: received time-wait (2MSL) timeout in state %s", stateName(fsm.state()));
01040     }
01041 
01042 }

void TCPConnection::process_TIMEOUT_CONN_ESTAB  )  [protected]
 

01004 {
01005     switch(fsm.state())
01006     {
01007         case TCP_S_SYN_RCVD:
01008         case TCP_S_SYN_SENT:
01009             // Nothing to do here. TIMEOUT_CONN_ESTAB event will automatically
01010             // take the connection to LISTEN or CLOSED, and cancel SYN-REXMIT timer.
01011             if (state->active)
01012             {
01013                 // notify user if we're on the active side
01014                 sendIndicationToApp(TCP_I_TIMED_OUT);
01015             }
01016             break;
01017         default:
01018             // We should not receive this timeout in this state.
01019             opp_error("Internal error: received CONN_ESTAB timeout in state %s", stateName(fsm.state()));
01020     }
01021 }

void TCPConnection::process_TIMEOUT_FIN_WAIT_2  )  [protected]
 

01045 {
01046     switch(fsm.state())
01047     {
01048         case TCP_S_FIN_WAIT_2:
01049             // Nothing to do here. The TIMEOUT_FIN_WAIT_2 event will automatically take
01050             // the connection to CLOSED.
01051             sendIndicationToApp(TCP_I_CLOSED);
01052             break;
01053         default:
01054             // We should not receive this timeout in this state.
01055             opp_error("Internal error: received FIN_WAIT_2 timeout in state %s", stateName(fsm.state()));
01056     }
01057 }

void TCPConnection::process_TIMEOUT_SYN_REXMIT TCPEventCode event  )  [protected]
 

01070 {
01071     if (++state->syn_rexmit_count>MAX_SYN_REXMIT_COUNT)
01072     {
01073         tcpEV << "Retransmission count during connection setup exceeds " << MAX_SYN_REXMIT_COUNT << ", giving up\n";
01074         // Note ABORT will take the connection to closed, and cancel CONN-ESTAB timer as well
01075         event = TCP_E_ABORT;
01076         return;
01077     }
01078 
01079     tcpEV << "Performing retransmission #" << state->syn_rexmit_count << "\n";
01080 
01081     // resend what's needed
01082     switch(fsm.state())
01083     {
01084         case TCP_S_SYN_SENT: sendSyn(); break;
01085         case TCP_S_SYN_RCVD: sendSynAck(); break;
01086         default:  opp_error("Internal error: SYN-REXMIT timer expired while in state %s", stateName(fsm.state()));
01087     }
01088 
01089     // reschedule timer
01090     state->syn_rexmit_timeout *= 2;
01091 
01092     if (state->syn_rexmit_timeout > TCP_TIMEOUT_SYN_REXMIT_MAX)
01093         state->syn_rexmit_timeout = TCP_TIMEOUT_SYN_REXMIT_MAX;
01094     scheduleTimeout(synRexmitTimer, state->syn_rexmit_timeout);
01095 }

bool TCPConnection::processAckInEstabEtc TCPSegment tcpseg  )  [protected]
 

00885 {
00886     tcpEV2 << "Processing ACK in a data transfer state\n";
00887 
00888     //
00889     //"
00890     //  If SND.UNA < SEG.ACK =< SND.NXT then, set SND.UNA <- SEG.ACK.
00891     //  Any segments on the retransmission queue which are thereby
00892     //  entirely acknowledged are removed.  Users should receive
00893     //  positive acknowledgments for buffers which have been SENT and
00894     //  fully acknowledged (i.e., SEND buffer should be returned with
00895     //  "ok" response).  If the ACK is a duplicate
00896     //  (SEG.ACK < SND.UNA), it can be ignored.  If the ACK acks
00897     //  something not yet sent (SEG.ACK > SND.NXT) then send an ACK,
00898     //  drop the segment, and return.
00899     //
00900     //  If SND.UNA < SEG.ACK =< SND.NXT, the send window should be
00901     //  updated.  If (SND.WL1 < SEG.SEQ or (SND.WL1 = SEG.SEQ and
00902     //  SND.WL2 =< SEG.ACK)), set SND.WND <- SEG.WND, set
00903     //  SND.WL1 <- SEG.SEQ, and set SND.WL2 <- SEG.ACK.
00904     //
00905     //  Note that SND.WND is an offset from SND.UNA, that SND.WL1
00906     //  records the sequence number of the last segment used to update
00907     //  SND.WND, and that SND.WL2 records the acknowledgment number of
00908     //  the last segment used to update SND.WND.  The check here
00909     //  prevents using old segments to update the window.
00910     //"
00911     // Note: should use SND.MAX instead of SND.NXT in above checks
00912     //
00913     if (seqGE(state->snd_una, tcpseg->ackNo()))
00914     {
00915         //
00916         // duplicate ACK? A received TCP segment is a duplicate ACK if all of
00917         // the following apply:
00918         //    (1) snd_una==ackNo
00919         //    (2) segment contains no data
00920         //    (3) there's unacked data (snd_una!=snd_max)
00921         //
00922         // Note: ssfnet uses additional constraint "window is the same as last
00923         // received (not an update)" -- we don't do that because window updates
00924         // are ignored anyway if neither seqNo nor ackNo has changed.
00925         //
00926         if (state->snd_una==tcpseg->ackNo() && tcpseg->payloadLength()==0 &&
00927             state->snd_una!=state->snd_max)
00928         {
00929             state->dupacks++;
00930             tcpAlgorithm->receivedDuplicateAck();
00931         }
00932         else
00933         {
00934             // if doesn't qualify as duplicate ACK, just ignore it.
00935             if (tcpseg->payloadLength()==0)
00936             {
00937                 if (state->snd_una!=tcpseg->ackNo())
00938                     tcpEV << "Old ACK: ackNo<snd_una\n";
00939                 else if (state->snd_una==state->snd_max)
00940                     tcpEV << "ACK looks duplicate but we have currently no unacked data (snd_una==snd_max)\n";
00941             }
00942 
00943             // reset counter
00944             state->dupacks = 0;
00945         }
00946     }
00947     else if (seqLE(tcpseg->ackNo(), state->snd_max))
00948     {
00949         // ack in window.
00950         uint32 old_snd_una = state->snd_una;
00951         state->snd_una = tcpseg->ackNo();
00952         if (unackedVector) unackedVector->record(state->snd_max - state->snd_una);
00953 
00954         // after retransmitting a lost segment, we may get an ack well ahead of snd_nxt
00955         if (seqLess(state->snd_nxt, state->snd_una))
00956             state->snd_nxt = state->snd_una;
00957 
00958         uint32 discardUpToSeq = state->snd_una;
00959 
00960         // our FIN acked?
00961         if (state->send_fin && tcpseg->ackNo()==state->snd_fin_seq+1)
00962         {
00963             // set flag that our FIN has been acked
00964             tcpEV << "ACK acks our FIN\n";
00965             state->fin_ack_rcvd = true;
00966             discardUpToSeq--; // the FIN sequence number is not real data
00967         }
00968 
00969         // acked data no longer needed in send queue
00970         sendQueue->discardUpTo(discardUpToSeq);
00971 
00972         if (seqLess(state->snd_wl1, tcpseg->sequenceNo()) ||
00973             (state->snd_wl1==tcpseg->sequenceNo() && seqLE(state->snd_wl2, tcpseg->ackNo())))
00974         {
00975             // send window should be updated
00976             tcpEV << "Updating send window from segment: new wnd=" << tcpseg->window() << "\n";
00977             state->snd_wnd = tcpseg->window();
00978             state->snd_wl1 = tcpseg->sequenceNo();
00979             state->snd_wl2 = tcpseg->ackNo();
00980             if (sndWndVector) sndWndVector->record(state->snd_wnd);
00981         }
00982 
00983         // notify
00984         tcpAlgorithm->receivedDataAck(old_snd_una);
00985 
00986         // in the receivedDataAck we need the old value
00987         state->dupacks = 0;
00988     }
00989     else
00990     {
00991         ASSERT(seqGreater(tcpseg->ackNo(), state->snd_max)); // from if-ladder
00992 
00993         // send an ACK, drop the segment, and return.
00994         tcpAlgorithm->receivedAckForDataNotYetSent(tcpseg->ackNo());
00995         state->dupacks = 0;
00996         return false;  // means "drop"
00997     }
00998     return true;
00999 }

bool TCPConnection::processAppCommand cMessage *  msg  ) 
 

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

00233 {
00234     printConnBrief();
00235 
00236     // first do actions
00237     TCPCommand *tcpCommand = (TCPCommand *)(msg->removeControlInfo());
00238     TCPEventCode event = preanalyseAppCommandEvent(msg->kind());
00239     tcpEV << "App command: " << eventName(event) << "\n";
00240     switch (event)
00241     {
00242         case TCP_E_OPEN_ACTIVE: process_OPEN_ACTIVE(event, tcpCommand, msg); break;
00243         case TCP_E_OPEN_PASSIVE: process_OPEN_PASSIVE(event, tcpCommand, msg); break;
00244         case TCP_E_SEND: process_SEND(event, tcpCommand, msg); break;
00245         case TCP_E_CLOSE: process_CLOSE(event, tcpCommand, msg); break;
00246         case TCP_E_ABORT: process_ABORT(event, tcpCommand, msg); break;
00247         case TCP_E_STATUS: process_STATUS(event, tcpCommand, msg); break;
00248         default: opp_error("wrong event code");
00249     }
00250 
00251     // then state transitions
00252     return performStateTransition(event);
00253 }

TCPEventCode TCPConnection::processRstInSynReceived TCPSegment tcpseg  )  [protected]
 

00857 {
00858     tcpEV2 << "Processing RST in SYN_RCVD\n";
00859 
00860     //"
00861     // If this connection was initiated with a passive OPEN (i.e.,
00862     // came from the LISTEN state), then return this connection to
00863     // LISTEN state and return.  The user need not be informed.  If
00864     // this connection was initiated with an active OPEN (i.e., came
00865     // from SYN-SENT state) then the connection was refused, signal
00866     // the user "connection refused".  In either case, all segments
00867     // on the retransmission queue should be removed.  And in the
00868     // active OPEN case, enter the CLOSED state and delete the TCB,
00869     // and return.
00870     //"
00871 
00872     sendQueue->discardUpTo(sendQueue->bufferEndSeq()); // flush send queue
00873 
00874     if (state->active)
00875     {
00876         // signal "connection refused"
00877         sendIndicationToApp(TCP_I_CONNECTION_REFUSED);
00878     }
00879 
00880     // on RCV_RST, FSM will go either to LISTEN or to CLOSED, depending on state->active
00881     return TCP_E_RCV_RST;
00882 }

TCPEventCode TCPConnection::processSegment1stThru8th TCPSegment tcpseg  )  [protected]
 

00111 {
00112     //
00113     // RFC 793: first check sequence number
00114     //
00115     bool acceptable = isSegmentAcceptable(tcpseg);
00116     if (!acceptable)
00117     {
00118         //"
00119         // If an incoming segment is not acceptable, an acknowledgment
00120         // should be sent in reply (unless the RST bit is set, if so drop
00121         // the segment and return):
00122         //
00123         //  <SEQ=SND.NXT><ACK=RCV.NXT><CTL=ACK>
00124         //"
00125         if (tcpseg->rstBit())
00126         {
00127             tcpEV << "RST with unacceptable seqNum: dropping\n";
00128         }
00129         else
00130         {
00131             tcpEV << "Segment seqNum not acceptable, sending ACK with current receive seq\n";
00132             sendAck();
00133         }
00134         return TCP_E_IGNORE;
00135     }
00136 
00137     //
00138     // RFC 793: second check the RST bit,
00139     //
00140     if (tcpseg->rstBit())
00141     {
00142         // Note: if we come from LISTEN, processSegmentInListen() has already handled RST.
00143         switch (fsm.state())
00144         {
00145             case TCP_S_SYN_RCVD:
00146                 //"
00147                 // If this connection was initiated with a passive OPEN (i.e.,
00148                 // came from the LISTEN state), then return this connection to
00149                 // LISTEN state and return.  The user need not be informed.  If
00150                 // this connection was initiated with an active OPEN (i.e., came
00151                 // from SYN-SENT state) then the connection was refused, signal
00152                 // the user "connection refused".  In either case, all segments
00153                 // on the retransmission queue should be removed.  And in the
00154                 // active OPEN case, enter the CLOSED state and delete the TCB,
00155                 // and return.
00156                 //"
00157                 return processRstInSynReceived(tcpseg);
00158 
00159             case TCP_S_ESTABLISHED:
00160             case TCP_S_FIN_WAIT_1:
00161             case TCP_S_FIN_WAIT_2:
00162             case TCP_S_CLOSE_WAIT:
00163                 //"
00164                 // If the RST bit is set then, any outstanding RECEIVEs and SEND
00165                 // should receive "reset" responses.  All segment queues should be
00166                 // flushed.  Users should also receive an unsolicited general
00167                 // "connection reset" signal.
00168                 //
00169                 // Enter the CLOSED state, delete the TCB, and return.
00170                 //"
00171                 tcpEV << "RST: performing connection reset, closing connection\n";
00172                 sendIndicationToApp(TCP_I_CONNECTION_RESET);
00173                 return TCP_E_RCV_RST;  // this will trigger state transition
00174 
00175             case TCP_S_CLOSING:
00176             case TCP_S_LAST_ACK:
00177             case TCP_S_TIME_WAIT:
00178                 //"
00179                 // enter the CLOSED state, delete the TCB, and return.
00180                 //"
00181                 tcpEV << "RST: closing connection\n";
00182                 if (fsm.state()!=TCP_S_TIME_WAIT)
00183                     sendIndicationToApp(TCP_I_CLOSED); // in TIME_WAIT, we've already sent it
00184                 return TCP_E_RCV_RST; // this will trigger state transition
00185 
00186             default: ASSERT(0);
00187         }
00188     }
00189 
00190     // RFC 793: third check security and precedence
00191     // This step is ignored.
00192 
00193     //
00194     // RFC 793: fourth, check the SYN bit,
00195     //
00196     if (tcpseg->synBit())
00197     {
00198         //"
00199         // If the SYN is in the window it is an error, send a reset, any
00200         // outstanding RECEIVEs and SEND should receive "reset" responses,
00201         // all segment queues should be flushed, the user should also
00202         // receive an unsolicited general "connection reset" signal, enter
00203         // the CLOSED state, delete the TCB, and return.
00204         //
00205         // If the SYN is not in the window this step would not be reached
00206         // and an ack would have been sent in the first step (sequence
00207         // number check).
00208         //"
00209 
00210         ASSERT(isSegmentAcceptable(tcpseg));  // assert SYN is in the window
00211         tcpEV << "SYN is in the window: performing connection reset, closing connection\n";
00212         sendIndicationToApp(TCP_I_CONNECTION_RESET);
00213         return TCP_E_RCV_UNEXP_SYN;
00214     }
00215 
00216     //
00217     // RFC 793: fifth check the ACK field,
00218     //
00219     if (!tcpseg->ackBit())
00220     {
00221         // if the ACK bit is off drop the segment and return
00222         tcpEV << "ACK not set, dropping segment\n";
00223         return TCP_E_IGNORE;
00224     }
00225 
00226     TCPEventCode event = TCP_E_IGNORE;
00227 
00228     if (fsm.state()==TCP_S_SYN_RCVD)
00229     {
00230         //"
00231         // If SND.UNA =< SEG.ACK =< SND.NXT then enter ESTABLISHED state
00232         // and continue processing.
00233         //
00234         // If the segment acknowledgment is not acceptable, form a
00235         // reset segment,
00236         //
00237         //  <SEQ=SEG.ACK><CTL=RST>
00238         //
00239         // and send it.
00240         //"
00241         if (!seqLE(state->snd_una,tcpseg->ackNo()) || !seqLE(tcpseg->ackNo(),state->snd_nxt))
00242         {
00243             sendRst(tcpseg->ackNo());
00244             return TCP_E_IGNORE;
00245         }
00246 
00247         // notify tcpAlgorithm and app layer
00248         tcpAlgorithm->established(false);
00249         sendEstabIndicationToApp();
00250 
00251         // This will trigger transition to ESTABLISHED. Timers and notifying
00252         // app will be taken care of in stateEntered().
00253         event = TCP_E_RCV_ACK;
00254     }
00255 
00256     uint32 old_snd_nxt = state->snd_nxt; // later we'll need to see if snd_nxt changed
00257     if (fsm.state()==TCP_S_SYN_RCVD || fsm.state()==TCP_S_ESTABLISHED ||
00258         fsm.state()==TCP_S_FIN_WAIT_1 || fsm.state()==TCP_S_FIN_WAIT_2 ||
00259         fsm.state()==TCP_S_CLOSE_WAIT || fsm.state()==TCP_S_CLOSING)
00260     {
00261         //
00262         // ESTABLISHED processing:
00263         //"
00264         //  If SND.UNA < SEG.ACK =< SND.NXT then, set SND.UNA <- SEG.ACK.
00265         //  Any segments on the retransmission queue which are thereby
00266         //  entirely acknowledged are removed.  Users should receive
00267         //  positive acknowledgments for buffers which have been SENT and
00268         //  fully acknowledged (i.e., SEND buffer should be returned with
00269         //  "ok" response).  If the ACK is a duplicate
00270         //  (SEG.ACK < SND.UNA), it can be ignored.  If the ACK acks
00271         //  something not yet sent (SEG.ACK > SND.NXT) then send an ACK,
00272         //  drop the segment, and return.
00273         //
00274         //  If SND.UNA < SEG.ACK =< SND.NXT, the send window should be
00275         //  updated.  If (SND.WL1 < SEG.SEQ or (SND.WL1 = SEG.SEQ and
00276         //  SND.WL2 =< SEG.ACK)), set SND.WND <- SEG.WND, set
00277         //  SND.WL1 <- SEG.SEQ, and set SND.WL2 <- SEG.ACK.
00278         //
00279         //  Note that SND.WND is an offset from SND.UNA, that SND.WL1
00280         //  records the sequence number of the last segment used to update
00281         //  SND.WND, and that SND.WL2 records the acknowledgment number of
00282         //  the last segment used to update SND.WND.  The check here
00283         //  prevents using old segments to update the window.
00284         //"
00285         bool ok = processAckInEstabEtc(tcpseg);
00286         if (!ok)
00287             return TCP_E_IGNORE;  // if acks something not yet sent, drop it
00288     }
00289 
00290     if ((fsm.state()==TCP_S_FIN_WAIT_1 && state->fin_ack_rcvd))
00291     {
00292         //"
00293         // FIN-WAIT-1 STATE
00294         //   In addition to the processing for the ESTABLISHED state, if
00295         //   our FIN is now acknowledged then enter FIN-WAIT-2 and continue
00296         //   processing in that state.
00297         //"
00298         event = TCP_E_RCV_ACK;  // will trigger transition to FIN-WAIT-2
00299     }
00300 
00301     if (fsm.state()==TCP_S_FIN_WAIT_2)
00302     {
00303         //"
00304         // FIN-WAIT-2 STATE
00305         //  In addition to the processing for the ESTABLISHED state, if
00306         //  the retransmission queue is empty, the user's CLOSE can be
00307         //  acknowledged ("ok") but do not delete the TCB.
00308         //"
00309         // nothing to do here (in our model, used commands don't need to be
00310         // acknowledged)
00311     }
00312 
00313     if (fsm.state()==TCP_S_CLOSING)
00314     {
00315         //"
00316         // In addition to the processing for the ESTABLISHED state, if
00317         // the ACK acknowledges our FIN then enter the TIME-WAIT state,
00318         // otherwise ignore the segment.
00319         //"
00320         if (state->fin_ack_rcvd)
00321         {
00322             tcpEV << "Our FIN acked -- can go to TIME_WAIT now\n";
00323             event = TCP_E_RCV_ACK;  // will trigger transition to TIME-WAIT
00324             scheduleTimeout(the2MSLTimer, TCP_TIMEOUT_2MSL);  // start timer
00325 
00326             // we're entering TIME_WAIT, so we can signal CLOSED the user
00327             // (the only thing left to do is wait until the 2MSL timer expires)
00328             sendIndicationToApp(TCP_I_CLOSED);
00329         }
00330     }
00331 
00332     if (fsm.state()==TCP_S_LAST_ACK)
00333     {
00334         //"
00335         // The only thing that can arrive in this state is an
00336         // acknowledgment of our FIN.  If our FIN is now acknowledged,
00337         // delete the TCB, enter the CLOSED state, and return.
00338         //"
00339         if (state->send_fin && tcpseg->ackNo()==state->snd_fin_seq+1)
00340         {
00341             tcpEV << "Last ACK arrived\n";
00342             sendIndicationToApp(TCP_I_CLOSED);
00343             return TCP_E_RCV_ACK; // will trigger transition to CLOSED
00344         }
00345     }
00346 
00347     if (fsm.state()==TCP_S_TIME_WAIT)
00348     {
00349         //"
00350         // The only thing that can arrive in this state is a
00351         // retransmission of the remote FIN.  Acknowledge it, and restart
00352         // the 2 MSL timeout.
00353         //"
00354         // And we are staying in the TIME_WAIT state.
00355         //
00356         sendAck();
00357         cancelEvent(the2MSLTimer);
00358         scheduleTimeout(the2MSLTimer, TCP_TIMEOUT_2MSL);
00359     }
00360 
00361     //
00362     // RFC 793: sixth, check the URG bit,
00363     //
00364     if (tcpseg->urgBit() && (fsm.state()==TCP_S_ESTABLISHED || fsm.state()==TCP_S_FIN_WAIT_1 ||
00365         fsm.state()==TCP_S_FIN_WAIT_2))
00366     {
00367         //"
00368         // If the URG bit is set, RCV.UP <- max(RCV.UP,SEG.UP), and signal
00369         // the user that the remote side has urgent data if the urgent
00370         // pointer (RCV.UP) is in advance of the data consumed.  If the
00371         // user has already been signaled (or is still in the "urgent
00372         // mode") for this continuous sequence of urgent data, do not
00373         // signal the user again.
00374         //"
00375 
00376         // TBD: URG currently not supported
00377     }
00378 
00379     //
00380     // RFC 793: seventh, process the segment text,
00381     //
00382     uint32 old_rcv_nxt = state->rcv_nxt; // if rcv_nxt changes, we need to send/schedule an ACK
00383     if (fsm.state()==TCP_S_SYN_RCVD || fsm.state()==TCP_S_ESTABLISHED || fsm.state()==TCP_S_FIN_WAIT_1 || fsm.state()==TCP_S_FIN_WAIT_2)
00384     {
00385         //"
00386         // Once in the ESTABLISHED state, it is possible to deliver segment
00387         // text to user RECEIVE buffers.  Text from segments can be moved
00388         // into buffers until either the buffer is full or the segment is
00389         // empty.  If the segment empties and carries an PUSH flag, then
00390         // the user is informed, when the buffer is returned, that a PUSH
00391         // has been received.
00392         //
00393         // When the TCP takes responsibility for delivering the data to the
00394         // user it must also acknowledge the receipt of the data.
00395         //
00396         // Once the TCP takes responsibility for the data it advances
00397         // RCV.NXT over the data accepted, and adjusts RCV.WND as
00398         // apporopriate to the current buffer availability.  The total of
00399         // RCV.NXT and RCV.WND should not be reduced.
00400         //
00401         // Please note the window management suggestions in section 3.7.
00402         //
00403         // Send an acknowledgment of the form:
00404         //
00405         //   <SEQ=SND.NXT><ACK=RCV.NXT><CTL=ACK>
00406         //
00407         // This acknowledgment should be piggybacked on a segment being
00408         // transmitted if possible without incurring undue delay.
00409         //"
00410         if (tcpseg->payloadLength()>0)
00411         {
00412             tcpEV2 << "Processing segment text in a data transfer state\n";
00413 
00414             // insert into receive buffers. If this segment is contiguous with
00415             // previously received ones (seqNo==rcv_nxt), rcv_nxt can be increased;
00416             // otherwise it stays the same but the data must be cached nevertheless
00417             // (to avoid "Failure to retain above-sequence data" problem, RFC 2525
00418             // section 2.5).
00419             uint32 old_rcv_nxt = state->rcv_nxt;
00420             state->rcv_nxt = receiveQueue->insertBytesFromSegment(tcpseg);
00421 
00422             // out-of-order segment?
00423             if (old_rcv_nxt==state->rcv_nxt)
00424             {
00425                 // we'll probably want to send an ACK here
00426                 tcpAlgorithm->receivedOutOfOrderSegment();
00427             }
00428             else
00429             {
00430                 // forward data to app
00431                 //
00432                 // FIXME observe PSH bit
00433                 //
00434                 // FIXME we should implement socket READ command, and pass up only
00435                 // as many bytes as requested. rcv_wnd should be decreased
00436                 // accordingly! (right now we *always* advertise win=16384,
00437                 // that is, there's practically no receiver-imposed flow control!)
00438                 //
00439                 cMessage *msg;
00440                 while ((msg=receiveQueue->extractBytesUpTo(state->rcv_nxt))!=NULL)
00441                 {
00442                     msg->setKind(TCP_I_DATA);  // TBD currently we never send TCP_I_URGENT_DATA
00443                     TCPCommand *cmd = new TCPCommand();
00444                     cmd->setConnId(connId);
00445                     msg->setControlInfo(cmd);
00446                     sendToApp(msg);
00447                 }
00448 
00449                 // if this segment "filled the gap" until the previously arrived segment
00450                 // that carried a FIN (i.e.rcv_nxt==rcv_fin_seq), we have to advance
00451                 // rcv_nxt over the FIN.
00452                 if (state->fin_rcvd && state->rcv_nxt==state->rcv_fin_seq)
00453                 {
00454                     tcpEV << "All segments arrived up to the FIN segment, advancing rcv_nxt over the FIN\n";
00455                     state->rcv_nxt = state->rcv_fin_seq+1;
00456                     sendIndicationToApp(TCP_I_PEER_CLOSED);
00457                 }
00458             }
00459         }
00460     }
00461 
00462     //
00463     // RFC 793: eighth, check the FIN bit,
00464     //
00465     if (tcpseg->finBit())
00466     {
00467         //"
00468         // If the FIN bit is set, signal the user "connection closing" and
00469         // return any pending RECEIVEs with same message, advance RCV.NXT
00470         // over the FIN, and send an acknowledgment for the FIN.  Note that
00471         // FIN implies PUSH for any segment text not yet delivered to the
00472         // user.
00473         //"
00474 
00475         // Note: seems like RFC 793 is not entirely correct here: if the
00476         // segment is "above sequence" (ie. RCV.NXT < SEG.SEQ), we cannot
00477         // advance RCV.NXT over the FIN. Instead we remember this sequence
00478         // number and do it later.
00479         uint32 fin_seq = (uint32)tcpseg->sequenceNo() + (uint32)tcpseg->payloadLength();
00480         if (state->rcv_nxt==fin_seq)
00481         {
00482             // advance rcv_nxt over FIN now
00483             tcpEV << "FIN arrived, advancing rcv_nxt over the FIN\n";
00484             state->rcv_nxt++;
00485             sendIndicationToApp(TCP_I_PEER_CLOSED);
00486         }
00487         else
00488         {
00489             // we'll have to do it later (when an arriving segment "fills the gap")
00490             tcpEV << "FIN segment above sequence, storing sequence number of FIN\n";
00491             state->fin_rcvd = true;
00492             state->rcv_fin_seq = fin_seq;
00493         }
00494 
00495         // TBD do PUSH stuff
00496 
00497         // state transitions will be done in the state machine, here we just set
00498         // the proper event code (TCP_E_RCV_FIN or TCP_E_RCV_FIN_ACK)
00499         event = TCP_E_RCV_FIN;
00500         switch (fsm.state())
00501         {
00502             case TCP_S_FIN_WAIT_1:
00503                 if (state->fin_ack_rcvd)
00504                 {
00505                     event = TCP_E_RCV_FIN_ACK;
00506                     // start the time-wait timer, turn off the other timers
00507                     cancelEvent(finWait2Timer);
00508                     scheduleTimeout(the2MSLTimer, TCP_TIMEOUT_2MSL);
00509 
00510                     // we're entering TIME_WAIT, so we can signal CLOSED the user
00511                     // (the only thing left to do is wait until the 2MSL timer expires)
00512                     sendIndicationToApp(TCP_I_CLOSED);
00513                 }
00514                 break;
00515             case TCP_S_FIN_WAIT_2:
00516                 // Start the time-wait timer, turn off the other timers.
00517                 cancelEvent(finWait2Timer);
00518                 scheduleTimeout(the2MSLTimer, TCP_TIMEOUT_2MSL);
00519 
00520                 // we're entering TIME_WAIT, so we can signal CLOSED the user
00521                 // (the only thing left to do is wait until the 2MSL timer expires)
00522                 sendIndicationToApp(TCP_I_CLOSED);
00523                 break;
00524             case TCP_S_TIME_WAIT:
00525                 // Restart the 2 MSL time-wait timeout.
00526                 cancelEvent(the2MSLTimer);
00527                 scheduleTimeout(the2MSLTimer, TCP_TIMEOUT_2MSL);
00528                 break;
00529         }
00530     }
00531 
00532     if (old_rcv_nxt!=state->rcv_nxt)
00533     {
00534         // if rcv_nxt changed, either because we received segment text or we
00535         // received a FIN that needs to be acked (or both), we need to send or
00536         // schedule an ACK.
00537 
00538         // tcpAlgorithm decides when and how to do ACKs
00539         tcpAlgorithm->receiveSeqChanged();
00540     }
00541 
00542     if ((fsm.state()==TCP_S_ESTABLISHED || fsm.state()==TCP_S_SYN_RCVD) &&
00543         state->send_fin && state->snd_nxt==state->snd_fin_seq+1)
00544     {
00545         // if the user issued the CLOSE command a long time ago and we've just
00546         // managed to send off FIN, we simulate a CLOSE command now (we had to
00547         // defer it at that time because we still had data in the send queue.)
00548         // This CLOSE will take us into the FIN_WAIT_1 state.
00549         tcpEV << "Now we can do the CLOSE which was deferred a while ago\n";
00550         event = TCP_E_CLOSE;
00551     }
00552 
00553     if (fsm.state()==TCP_S_CLOSE_WAIT && state->send_fin &&
00554         state->snd_nxt==state->snd_fin_seq+1 && old_snd_nxt!=state->snd_nxt)
00555     {
00556         // if we're in CLOSE_WAIT and we just got to sent our long-pending FIN,
00557         // we simulate a CLOSE command now (we had to defer it at that time because
00558         // we still had data in the send queue.) This CLOSE will take us into the
00559         // LAST_ACK state.
00560         tcpEV << "Now we can do the CLOSE which was deferred a while ago\n";
00561         event = TCP_E_CLOSE;
00562     }
00563 
00564     return event;
00565 }

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

00570 {
00571     tcpEV2 << "Processing segment in LISTEN\n";
00572 
00573     //"
00574     // first check for an RST
00575     //   An incoming RST should be ignored.  Return.
00576     //"
00577     if (tcpseg->rstBit())
00578     {
00579         tcpEV << "RST bit set: dropping segment\n";
00580         return TCP_E_IGNORE;
00581     }
00582 
00583     //"
00584     // second check for an ACK
00585     //    Any acknowledgment is bad if it arrives on a connection still in
00586     //    the LISTEN state.  An acceptable reset segment should be formed
00587     //    for any arriving ACK-bearing segment.  The RST should be
00588     //    formatted as follows:
00589     //
00590     //      <SEQ=SEG.ACK><CTL=RST>
00591     //
00592     //    Return.
00593     //"
00594     if (tcpseg->ackBit())
00595     {
00596         tcpEV << "ACK bit set: dropping segment and sending RST\n";
00597         sendRst(tcpseg->ackNo(),destAddr,srcAddr,tcpseg->destPort(),tcpseg->srcPort());
00598         return TCP_E_IGNORE;
00599     }
00600 
00601     //"
00602     // third check for a SYN
00603     //"
00604     if (tcpseg->synBit())
00605     {
00606         if (tcpseg->finBit())
00607         {
00608             // Looks like implementations vary on how to react to SYN+FIN.
00609             // Some treat it as plain SYN (and reply with SYN+ACK), some send RST+ACK.
00610             // Let's just do the former here.
00611             tcpEV << "SYN+FIN received: ignoring FIN\n";
00612         }
00613 
00614         tcpEV << "SYN bit set: filling in foreign socket and sending SYN+ACK\n";
00615 
00616         //"
00617         // If the listen was not fully specified (i.e., the foreign socket was not
00618         // fully specified), then the unspecified fields should be filled in now.
00619         //"
00620         //
00621         // Also, we may need to fork, in order to leave another connection
00622         // LISTENing on the port. Note: forking will change our connId.
00623         //
00624         if (state->fork)
00625         {
00626             TCPConnection *conn = cloneListeningConnection(); // this will stay LISTENing
00627             tcpMain->addForkedConnection(this, conn, destAddr, srcAddr, tcpseg->destPort(), tcpseg->srcPort());
00628             tcpEV << "Connection forked: this connection got new connId=" << connId << ", "
00629                      "spinoff keeps LISTENing with connId=" << conn->connId << "\n";
00630         }
00631         else
00632         {
00633             tcpMain->updateSockPair(this, destAddr, srcAddr, tcpseg->destPort(), tcpseg->srcPort());
00634         }
00635 
00636         //"
00637         //  Set RCV.NXT to SEG.SEQ+1, IRS is set to SEG.SEQ and any other
00638         //  control or text should be queued for processing later.  ISS
00639         //  should be selected and a SYN segment sent of the form:
00640         //
00641         //    <SEQ=ISS><ACK=RCV.NXT><CTL=SYN,ACK>
00642         //
00643         //  SND.NXT is set to ISS+1 and SND.UNA to ISS.  The connection
00644         //  state should be changed to SYN-RECEIVED.
00645         //"
00646         state->rcv_nxt = tcpseg->sequenceNo()+1;
00647         state->irs = tcpseg->sequenceNo();
00648         receiveQueue->init(state->rcv_nxt);   // FIXME may init twice...
00649         selectInitialSeqNum();
00650 
00651         // although not mentioned in RFC 793, seems like we have to pick up
00652         // initial snd_wnd from the segment here.
00653         state->snd_wnd = tcpseg->window();
00654         state->snd_wl1 = tcpseg->sequenceNo();
00655         state->snd_wl2 = state->iss;
00656         if (sndWndVector) sndWndVector->record(state->snd_wnd);
00657 
00658         sendSynAck();
00659         startSynRexmitTimer();
00660         if (!connEstabTimer->isScheduled())
00661             scheduleTimeout(connEstabTimer, TCP_TIMEOUT_CONN_ESTAB);
00662 
00663         //"
00664         // Note that any other incoming control or data (combined with SYN)
00665         // will be processed in the SYN-RECEIVED state, but processing of SYN
00666         // and ACK should not be repeated.
00667         //"
00668         // We don't send text in SYN or SYN+ACK, but accept it. Otherwise
00669         // there isn't much left to do: RST, SYN, ACK, FIN got processed already,
00670         // so there's only URG and PSH left to handle.
00671         //
00672         if (tcpseg->payloadLength()>0)
00673             receiveQueue->insertBytesFromSegment(tcpseg);
00674         if (tcpseg->urgBit() || tcpseg->pshBit())
00675             tcpEV << "Ignoring URG and PSH bits in SYN\n"; // TBD
00676 
00677         return TCP_E_RCV_SYN;  // this will take us to SYN_RCVD
00678     }
00679 
00680     //"
00681     //  fourth other text or control
00682     //   So you are unlikely to get here, but if you do, drop the segment, and return.
00683     //"
00684     tcpEV << "Unexpected segment: dropping it\n";
00685     return TCP_E_IGNORE;
00686 }

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

00689 {
00690     tcpEV2 << "Processing segment in SYN_SENT\n";
00691 
00692     //"
00693     // first check the ACK bit
00694     //
00695     //   If the ACK bit is set
00696     //
00697     //     If SEG.ACK =< ISS, or SEG.ACK > SND.NXT, send a reset (unless
00698     //     the RST bit is set, if so drop the segment and return)
00699     //
00700     //       <SEQ=SEG.ACK><CTL=RST>
00701     //
00702     //     and discard the segment.  Return.
00703     //
00704     //     If SND.UNA =< SEG.ACK =< SND.NXT then the ACK is acceptable.
00705     //"
00706     if (tcpseg->ackBit())
00707     {
00708         if (seqLE(tcpseg->ackNo(),state->iss) || seqGreater(tcpseg->ackNo(),state->snd_nxt))
00709         {
00710             tcpEV << "ACK bit set but wrong AckNo, sending RST\n";
00711             sendRst(tcpseg->ackNo(),destAddr,srcAddr,tcpseg->destPort(),tcpseg->srcPort());
00712             return TCP_E_IGNORE;
00713         }
00714         tcpEV << "ACK bit set, AckNo acceptable\n";
00715     }
00716 
00717     //"
00718     // second check the RST bit
00719     //
00720     //   If the RST bit is set
00721     //
00722     //     If the ACK was acceptable then signal the user "error:
00723     //     connection reset", drop the segment, enter CLOSED state,
00724     //     delete TCB, and return.  Otherwise (no ACK) drop the segment
00725     //     and return.
00726     //"
00727     if (tcpseg->rstBit())
00728     {
00729         if (tcpseg->ackBit())
00730         {
00731             tcpEV << "RST+ACK: performing connection reset\n";
00732             sendIndicationToApp(TCP_I_CONNECTION_RESET);
00733             return TCP_E_RCV_RST;
00734         }
00735         else
00736         {
00737             tcpEV << "RST without ACK: dropping segment\n";
00738             return TCP_E_IGNORE;
00739         }
00740     }
00741 
00742     //"
00743     // third check the security and precedence -- not done
00744     //
00745     // fourth check the SYN bit
00746     //
00747     //   This step should be reached only if the ACK is ok, or there is
00748     //   no ACK, and it the segment did not contain a RST.
00749     //
00750     //   If the SYN bit is on and the security/compartment and precedence
00751     //   are acceptable then,
00752     //"
00753     if (tcpseg->synBit())
00754     {
00755         //
00756         //   RCV.NXT is set to SEG.SEQ+1, IRS is set to
00757         //   SEG.SEQ.  SND.UNA should be advanced to equal SEG.ACK (if there
00758         //   is an ACK), and any segments on the retransmission queue which
00759         //   are thereby acknowledged should be removed.
00760         //
00761         state->rcv_nxt = tcpseg->sequenceNo()+1;
00762         state->irs = tcpseg->sequenceNo();
00763         receiveQueue->init(state->rcv_nxt);
00764 
00765         if (tcpseg->ackBit())
00766         {
00767             state->snd_una = tcpseg->ackNo();
00768             sendQueue->discardUpTo(state->snd_una);
00769 
00770             // although not mentioned in RFC 793, seems like we have to pick up
00771             // initial snd_wnd from the segment here.
00772             state->snd_wnd = tcpseg->window();
00773             state->snd_wl1 = tcpseg->sequenceNo();
00774             state->snd_wl2 = tcpseg->ackNo();
00775             if (sndWndVector) sndWndVector->record(state->snd_wnd);
00776         }
00777 
00778         // this also seems to be a good time to learn our local IP address
00779         // (was probably unspecified at connection open)
00780         tcpMain->updateSockPair(this, destAddr, srcAddr, tcpseg->destPort(), tcpseg->srcPort());
00781 
00782         //"
00783         //   If SND.UNA > ISS (our SYN has been ACKed), change the connection
00784         //   state to ESTABLISHED, form an ACK segment
00785         //
00786         //     <SEQ=SND.NXT><ACK=RCV.NXT><CTL=ACK>
00787         //
00788         //   and send it.  Data or controls which were queued for
00789         //   transmission may be included.  If there are other controls or
00790         //   text in the segment then continue processing at the sixth step
00791         //   below where the URG bit is checked, otherwise return.
00792         //"
00793         if (seqGreater(state->snd_una, state->iss))
00794         {
00795             tcpEV << "SYN+ACK bits set, connection established.\n";
00796 
00797             // RFC says "continue processing at the sixth step below where
00798             // the URG bit is checked". Those steps deal with: URG, segment text
00799             // (and PSH), and FIN.
00800             // Now: URG and PSH we don't support yet; in SYN+FIN we ignore FIN;
00801             // with segment text we just take it easy and put it in the receiveQueue
00802             // -- we'll forward it to the user when more data arrives.
00803             if (tcpseg->finBit())
00804                 tcpEV << "SYN+ACK+FIN received: ignoring FIN\n";
00805             if (tcpseg->payloadLength()>0)
00806                 state->rcv_nxt = receiveQueue->insertBytesFromSegment(tcpseg); // TBD forward to app, etc.
00807             if (tcpseg->urgBit() || tcpseg->pshBit())
00808                 tcpEV << "Ignoring URG and PSH bits in SYN+ACK\n"; // TBD
00809 
00810             // notify tcpAlgorithm (it has to send ACK of SYN) and app layer
00811             tcpAlgorithm->established(true);
00812             sendEstabIndicationToApp();
00813 
00814             // This will trigger transition to ESTABLISHED. Timers and notifying
00815             // app will be taken care of in stateEntered().
00816             return TCP_E_RCV_SYN_ACK;
00817         }
00818 
00819         //"
00820         //   Otherwise enter SYN-RECEIVED, form a SYN,ACK segment
00821         //
00822         //     <SEQ=ISS><ACK=RCV.NXT><CTL=SYN,ACK>
00823         //
00824         //   and send it.  If there are other controls or text in the
00825         //   segment, queue them for processing after the ESTABLISHED state
00826         //   has been reached, return.
00827         //"
00828         tcpEV << "SYN bit set: sending SYN+ACK\n";
00829         state->snd_max = state->snd_nxt = state->iss;
00830         sendSynAck();
00831         startSynRexmitTimer();
00832 
00833         // Note: code below is similar to processing SYN in LISTEN.
00834 
00835         // For consistency with that code, we ignore SYN+FIN here
00836         if (tcpseg->finBit())
00837             tcpEV << "SYN+FIN received: ignoring FIN\n";
00838 
00839         // We don't send text in SYN or SYN+ACK, but accept it. Otherwise
00840         // there isn't much left to do: RST, SYN, ACK, FIN got processed already,
00841         // so there's only URG and PSH left to handle.
00842         if (tcpseg->payloadLength()>0)
00843             receiveQueue->insertBytesFromSegment(tcpseg);
00844         if (tcpseg->urgBit() || tcpseg->pshBit())
00845             tcpEV << "Ignoring URG and PSH bits in SYN\n"; // TBD
00846         return TCP_E_RCV_SYN;
00847     }
00848 
00849     //"
00850     // fifth, if neither of the SYN or RST bits is set then drop the
00851     // segment and return.
00852     //"
00853     return TCP_E_IGNORE;
00854 }

bool TCPConnection::processTCPSegment TCPSegment tcpSeg,
IPvXAddress  srcAddr,
IPvXAddress  destAddr
 

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

00209 {
00210     printConnBrief();
00211     if (!localAddr.isUnspecified())
00212     {
00213         ASSERT(localAddr==segDestAddr);
00214         ASSERT(localPort==tcpseg->destPort());
00215     }
00216     if (!remoteAddr.isUnspecified())
00217     {
00218         ASSERT(remoteAddr==segSrcAddr);
00219         ASSERT(remotePort==tcpseg->srcPort());
00220     }
00221 
00222     if (tryFastRoute(tcpseg))
00223         return true;
00224 
00225     // first do actions
00226     TCPEventCode event = process_RCV_SEGMENT(tcpseg, segSrcAddr, segDestAddr);
00227 
00228     // then state transitions
00229     return performStateTransition(event);
00230 }

bool TCPConnection::processTimer cMessage *  msg  ) 
 

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

00172 {
00173     printConnBrief();
00174     tcpEV << msg->name() << " timer expired\n";
00175 
00176     // first do actions
00177     TCPEventCode event;
00178     if (msg==the2MSLTimer)
00179     {
00180         event = TCP_E_TIMEOUT_2MSL;
00181         process_TIMEOUT_2MSL();
00182     }
00183     else if (msg==connEstabTimer)
00184     {
00185         event = TCP_E_TIMEOUT_CONN_ESTAB;
00186         process_TIMEOUT_CONN_ESTAB();
00187     }
00188     else if (msg==finWait2Timer)
00189     {
00190         event = TCP_E_TIMEOUT_FIN_WAIT_2;
00191         process_TIMEOUT_FIN_WAIT_2();
00192     }
00193     else if (msg==synRexmitTimer)
00194     {
00195         event = TCP_E_IGNORE;
00196         process_TIMEOUT_SYN_REXMIT(event);
00197     }
00198     else
00199     {
00200         event = TCP_E_IGNORE;
00201         tcpAlgorithm->processTimer(msg, event);
00202     }
00203 
00204     // then state transitions
00205     return performStateTransition(event);
00206 }

void TCPConnection::retransmitData  ) 
 

Utility: retransmit all from snd_una to snd_max

00582 {
00583     // retransmit everything from snd_una
00584     state->snd_nxt = state->snd_una;
00585 
00586     ulong bytesToSend = state->snd_max - state->snd_nxt;
00587     ASSERT(bytesToSend!=0);
00588 
00589     while (bytesToSend>0)
00590     {
00591         ulong bytes = Min(bytesToSend, state->snd_mss);
00592         sendSegment(bytes);
00593         bytesToSend -= bytes;
00594     }
00595 }

void TCPConnection::retransmitOneSegment  ) 
 

Utility: retransmit one segment from snd_una

00568 {
00569     // retransmit one segment at snd_una, and set snd_nxt accordingly
00570     state->snd_nxt = state->snd_una;
00571 
00572     ulong bytes = Min(state->snd_mss, state->snd_max - state->snd_nxt);
00573     ASSERT(bytes!=0);
00574 
00575     sendSegment(bytes);
00576 
00577     // notify
00578     tcpAlgorithm->ackSent();
00579 }

void TCPConnection::scheduleTimeout cMessage *  msg,
simtime_t  timeout
[inline]
 

Utility: start a timer

00408         {tcpMain->scheduleAt(tcpMain->simTime()+timeout, msg);}

void TCPConnection::segmentArrivalWhileClosed TCPSegment tcpseg,
IPvXAddress  src,
IPvXAddress  dest
[static]
 

Static function, invoked from TCP when a segment arrives which doesn't belong to an existing connection.

00037 {
00038     tcpEV << "Seg arrived: ";
00039     printSegmentBrief(tcpseg);
00040 
00041     tcpEV << "Segment doesn't belong to any existing connection\n";
00042 
00043     // RFC 793:
00044     //"
00045     // all data in the incoming segment is discarded.  An incoming
00046     // segment containing a RST is discarded.  An incoming segment not
00047     // containing a RST causes a RST to be sent in response.  The
00048     // acknowledgment and sequence field values are selected to make the
00049     // reset sequence acceptable to the TCP that sent the offending
00050     // segment.
00051     //
00052     // If the ACK bit is off, sequence number zero is used,
00053     //
00054     //    <SEQ=0><ACK=SEG.SEQ+SEG.LEN><CTL=RST,ACK>
00055     //
00056     // If the ACK bit is on,
00057     //
00058     //    <SEQ=SEG.ACK><CTL=RST>
00059     //"
00060     if (tcpseg->rstBit())
00061     {
00062         tcpEV << "RST bit set: dropping segment\n";
00063         return;
00064     }
00065 
00066     if (!tcpseg->ackBit())
00067     {
00068         tcpEV << "ACK bit not set: sending RST+ACK\n";
00069         uint32 ackNo = tcpseg->sequenceNo() + (uint32)tcpseg->payloadLength();
00070         sendRstAck(0,ackNo,destAddr,srcAddr,tcpseg->destPort(),tcpseg->srcPort());
00071     }
00072     else
00073     {
00074         tcpEV << "ACK bit set: sending RST\n";
00075         sendRst(tcpseg->ackNo(),destAddr,srcAddr,tcpseg->destPort(),tcpseg->srcPort());
00076     }
00077 }

void TCPConnection::selectInitialSeqNum  )  [protected]
 

Utility: generates ISS and initializes corresponding state variables

00308 {
00309     // set the initial send sequence number
00310     state->iss = (unsigned long)(fmod(tcpMain->simTime()*250000.0, 1.0+(double)(unsigned)0xffffffffUL)) & 0xffffffffUL;
00311 
00312     state->snd_una = state->snd_nxt = state->snd_max = state->iss;
00313 
00314     sendQueue->init(state->iss+1); // +1 is for SYN
00315 }

void TCPConnection::sendAck  ) 
 

Utility: send ACK

00396 {
00397     TCPSegment *tcpseg = new TCPSegment("ACK");
00398 
00399     tcpseg->setAckBit(true);
00400     tcpseg->setSequenceNo(state->snd_nxt);
00401     tcpseg->setAckNo(state->rcv_nxt);
00402     tcpseg->setWindow(state->rcv_wnd);
00403 
00404     // send it
00405     sendToIP(tcpseg);
00406 
00407     // notify
00408     tcpAlgorithm->ackSent();
00409 }

bool TCPConnection::sendData bool  fullSegmentsOnly,
int  congestionWindow = -1
 

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.

00454 {
00455     // we'll start sending from snd_max
00456     state->snd_nxt = state->snd_max;
00457 
00458     // check how many bytes we have
00459     ulong buffered = sendQueue->bytesAvailable(state->snd_nxt);
00460     if (buffered==0)
00461         return false;
00462 
00463     // maxWindow is smaller of (snd_wnd, congestionWindow)
00464     long maxWindow = state->snd_wnd;
00465     if (congestionWindow>=0 && maxWindow > congestionWindow)
00466         maxWindow = congestionWindow;
00467 
00468     // effectiveWindow: number of bytes we're allowed to send now
00469     long effectiveWin = maxWindow - (state->snd_nxt - state->snd_una);
00470     if (effectiveWin <= 0)
00471     {
00472         tcpEV << "Effective window is zero (advertised window " << state->snd_wnd <<
00473                  ", congestion window " << congestionWindow << "), cannot send.\n";
00474         return false;
00475     }
00476 
00477     ulong bytesToSend = effectiveWin;
00478 
00479     if (bytesToSend > buffered)
00480         bytesToSend = buffered;
00481 
00482     if (fullSegmentsOnly && bytesToSend < state->snd_mss)
00483     {
00484         tcpEV << "Cannot send, not enough data for a full segment (MSS=" << state->snd_mss
00485               << ", in buffer " << buffered << ")\n";
00486         return false;
00487     }
00488 
00489     // start sending 'bytesToSend' bytes
00490     tcpEV << "Will send " << bytesToSend << " bytes (effectiveWindow " << effectiveWin
00491           << ", in buffer " << buffered << " bytes)\n";
00492 
00493     uint32 old_snd_nxt = state->snd_nxt;
00494     ASSERT(bytesToSend>0);
00495 
00496 #ifdef TCP_SENDFRAGMENTS  /* normally undefined */
00497     // make agressive use of the window until the last byte
00498     while (bytesToSend>0)
00499     {
00500         ulong bytes = Min(bytesToSend, state->snd_mss);
00501         sendSegment(bytes);
00502         bytesToSend -= bytes;
00503     }
00504 #else
00505     // send <MSS segments only if it's the only segment we can send now
00506     // FIXME this should probably obey Nagle's alg -- to be checked
00507     if (bytesToSend <= state->snd_mss)
00508     {
00509         sendSegment(bytesToSend);
00510     }
00511     else
00512     {
00513         // send whole segments only
00514         while (bytesToSend>=state->snd_mss)
00515         {
00516             sendSegment(state->snd_mss);
00517             bytesToSend -= state->snd_mss;
00518         }
00519         if (bytesToSend>0)
00520            tcpEV << bytesToSend << " bytes of space left in effectiveWindow\n";
00521     }
00522 #endif
00523 
00524     // remember highest seq sent (snd_nxt may be set back on retransmission,
00525     // but we'll need snd_max to check validity of ACKs -- they must ack
00526     // something we really sent)
00527     state->snd_max = state->snd_nxt;
00528     if (unackedVector) unackedVector->record(state->snd_max - state->snd_una);
00529 
00530     // notify (once is enough)
00531     tcpAlgorithm->ackSent();
00532     tcpAlgorithm->dataSent(old_snd_nxt);
00533 
00534     return true;
00535 }

void TCPConnection::sendEstabIndicationToApp  )  [protected]
 

Utility: sends TCP_I_ESTABLISHED indication with TCPConnectInfo to application

00254 {
00255     tcpEV << "Notifying app: " << indicationName(TCP_I_ESTABLISHED) << "\n";
00256     cMessage *msg = new cMessage(indicationName(TCP_I_ESTABLISHED));
00257     msg->setKind(TCP_I_ESTABLISHED);
00258 
00259     TCPConnectInfo *ind = new TCPConnectInfo();
00260     ind->setConnId(connId);
00261     ind->setLocalAddr(localAddr);
00262     ind->setRemoteAddr(remoteAddr);
00263     ind->setLocalPort(localPort);
00264     ind->setRemotePort(remotePort);
00265 
00266     msg->setControlInfo(ind);
00267     tcpMain->send(msg, "to_appl", appGateIndex);
00268 }

void TCPConnection::sendFin  ) 
 

Utility: sends FIN

00412 {
00413     TCPSegment *tcpseg = new TCPSegment("FIN");
00414 
00415     // Note: ACK bit *must* be set for both FIN and FIN+ACK. What makes
00416     // the difference for FIN+ACK is that its ackNo acks the remote TCP's FIN.
00417     tcpseg->setFinBit(true);
00418     tcpseg->setAckBit(true);
00419     tcpseg->setAckNo(state->rcv_nxt);
00420     tcpseg->setSequenceNo(state->snd_nxt);
00421     tcpseg->setWindow(state->rcv_wnd);
00422 
00423     // send it
00424     sendToIP(tcpseg);
00425 
00426     // notify
00427     tcpAlgorithm->ackSent();
00428 }

void TCPConnection::sendIndicationToApp int  code  )  [protected]
 

Utility: sends status indication (TCP_I_xxx) to application

00243 {
00244     tcpEV << "Notifying app: " << indicationName(code) << "\n";
00245     cMessage *msg = new cMessage(indicationName(code));
00246     msg->setKind(code);
00247     TCPCommand *ind = new TCPCommand();
00248     ind->setConnId(connId);
00249     msg->setControlInfo(ind);
00250     tcpMain->send(msg, "to_appl", appGateIndex);
00251 }

bool TCPConnection::sendProbe  ) 
 

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

00538 {
00539     // we'll start sending from snd_max
00540     state->snd_nxt = state->snd_max;
00541 
00542     // check we have 1 byte to send
00543     if (sendQueue->bytesAvailable(state->snd_nxt)==0)
00544     {
00545         tcpEV << "Cannot send probe because send buffer is empty\n";
00546         return false;
00547     }
00548 
00549     uint32 old_snd_nxt = state->snd_nxt;
00550 
00551     tcpEV << "Sending 1 byte as probe, with seq=" << state->snd_nxt << "\n";
00552     sendSegment(1);
00553 
00554     // remember highest seq sent (snd_nxt may be set back on retransmission,
00555     // but we'll need snd_max to check validity of ACKs -- they must ack
00556     // something we really sent)
00557     state->snd_max = state->snd_nxt;
00558     if (unackedVector) unackedVector->record(state->snd_max - state->snd_una);
00559 
00560     // notify
00561     tcpAlgorithm->ackSent();
00562     tcpAlgorithm->dataSent(old_snd_nxt);
00563 
00564     return true;
00565 }

void TCPConnection::sendRst uint32  seq,
IPvXAddress  src,
IPvXAddress  dest,
int  srcPort,
int  destPort
[static]
 

Utility: sends RST (called from TCP)

00366 {
00367     TCPSegment *tcpseg = new TCPSegment("RST");
00368 
00369     tcpseg->setSrcPort(srcPort);
00370     tcpseg->setDestPort(destPort);
00371 
00372     tcpseg->setRstBit(true);
00373     tcpseg->setSequenceNo(seq);
00374 
00375     // send it
00376     sendToIP(tcpseg, src, dest);
00377 }

void TCPConnection::sendRst uint32  seqNo  ) 
 

Utility: sends RST

00361 {
00362     sendRst(seqNo, localAddr, remoteAddr, localPort, remotePort);
00363 }

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

Utility: sends RST+ACK (called from TCP)

00380 {
00381     TCPSegment *tcpseg = new TCPSegment("RST+ACK");
00382 
00383     tcpseg->setSrcPort(srcPort);
00384     tcpseg->setDestPort(destPort);
00385 
00386     tcpseg->setRstBit(true);
00387     tcpseg->setAckBit(true);
00388     tcpseg->setSequenceNo(seq);
00389     tcpseg->setAckNo(ack);
00390 
00391     // send it
00392     sendToIP(tcpseg, src, dest);
00393 }

void TCPConnection::sendSegment int  bytes  ) 
 

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

00431 {
00432     // send one segment of 'bytes' bytes from snd_nxt, and advance snd_nxt
00433     TCPSegment *tcpseg = sendQueue->createSegmentWithBytes(state->snd_nxt, bytes);
00434     tcpseg->setAckNo(state->rcv_nxt);
00435     tcpseg->setAckBit(true);
00436     tcpseg->setWindow(state->rcv_wnd);
00437     // TBD when to set PSH bit?
00438     // TBD set URG bit if needed
00439     ASSERT(bytes==tcpseg->payloadLength());
00440 
00441     state->snd_nxt += bytes;
00442 
00443     if (state->send_fin && state->snd_nxt==state->snd_fin_seq)
00444     {
00445         tcpEV << "Setting FIN on segment\n";
00446         tcpseg->setFinBit(true);
00447         state->snd_nxt = state->snd_fin_seq+1;
00448     }
00449 
00450     sendToIP(tcpseg);
00451 }

void TCPConnection::sendSyn  )  [protected]
 

Utility: send SYN

00326 {
00327     if (remoteAddr.isUnspecified() || remotePort==-1)
00328         opp_error("Error processing command OPEN_ACTIVE: foreign socket unspecified");
00329     if (localPort==-1)
00330         opp_error("Error processing command OPEN_ACTIVE: local port unspecified");
00331 
00332     // create segment
00333     TCPSegment *tcpseg = new TCPSegment("SYN");
00334     tcpseg->setSequenceNo(state->iss);
00335     tcpseg->setSynBit(true);
00336     tcpseg->setWindow(state->rcv_wnd);
00337 
00338     state->snd_max = state->snd_nxt = state->iss+1;
00339 
00340     // send it
00341     sendToIP(tcpseg);
00342 }

void TCPConnection::sendSynAck  )  [protected]
 

Utility: send SYN+ACK

00345 {
00346     // create segment
00347     TCPSegment *tcpseg = new TCPSegment("SYN+ACK");
00348     tcpseg->setSequenceNo(state->iss);
00349     tcpseg->setAckNo(state->rcv_nxt);
00350     tcpseg->setSynBit(true);
00351     tcpseg->setAckBit(true);
00352     tcpseg->setWindow(state->rcv_wnd);
00353 
00354     state->snd_max = state->snd_nxt = state->iss+1;
00355 
00356     // send it
00357     sendToIP(tcpseg);
00358 }

void TCPConnection::sendToApp cMessage *  msg  )  [protected]
 

Utility: sends packet to application

00271 {
00272     tcpMain->send(msg, "to_appl", appGateIndex);
00273 }

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

Utility: send IP packet

00209 {
00210     tcpEV << "Sending: ";
00211     printSegmentBrief(tcpseg);
00212 
00213     if (!dest.isIPv6())
00214     {
00215         // send over IPv4
00216         IPControlInfo *controlInfo = new IPControlInfo();
00217         controlInfo->setProtocol(IP_PROT_TCP);
00218         controlInfo->setSrcAddr(src.get4());
00219         controlInfo->setDestAddr(dest.get4());
00220         tcpseg->setControlInfo(controlInfo);
00221 
00222         check_and_cast<TCP *>(simulation.contextModule())->send(tcpseg,"to_ip");
00223     }
00224     else
00225     {
00226         // send over IPv6
00227         IPv6ControlInfo *controlInfo = new IPv6ControlInfo();
00228         controlInfo->setProtocol(IP_PROT_TCP);
00229         controlInfo->setSrcAddr(src.get6());
00230         controlInfo->setDestAddr(dest.get6());
00231         tcpseg->setControlInfo(controlInfo);
00232 
00233         check_and_cast<TCP *>(simulation.contextModule())->send(tcpseg,"to_ipv6");
00234     }
00235 }

void TCPConnection::sendToIP TCPSegment tcpseg  ) 
 

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

00167 {
00168     // record seq (only if we do send data) and ackno
00169     if (sndNxtVector && tcpseg->payloadLength()!=0)
00170         sndNxtVector->record(tcpseg->sequenceNo());
00171     if (sndAckVector) sndAckVector->record(tcpseg->ackNo());
00172 
00173     // final touches on the segment before sending
00174     tcpseg->setSrcPort(localPort);
00175     tcpseg->setDestPort(remotePort);
00176     tcpseg->setByteLength(TCP_HEADER_OCTETS+tcpseg->payloadLength());
00177     // TBD account for Options (once they get implemented)
00178 
00179     tcpEV << "Sending: ";
00180     printSegmentBrief(tcpseg);
00181 
00182     // TBD reuse next function for sending
00183 
00184     if (!remoteAddr.isIPv6())
00185     {
00186         // send over IPv4
00187         IPControlInfo *controlInfo = new IPControlInfo();
00188         controlInfo->setProtocol(IP_PROT_TCP);
00189         controlInfo->setSrcAddr(localAddr.get4());
00190         controlInfo->setDestAddr(remoteAddr.get4());
00191         tcpseg->setControlInfo(controlInfo);
00192 
00193         tcpMain->send(tcpseg,"to_ip");
00194     }
00195     else
00196     {
00197         // send over IPv6
00198         IPv6ControlInfo *controlInfo = new IPv6ControlInfo();
00199         controlInfo->setProtocol(IP_PROT_TCP);
00200         controlInfo->setSrcAddr(localAddr.get6());
00201         controlInfo->setDestAddr(remoteAddr.get6());
00202         tcpseg->setControlInfo(controlInfo);
00203 
00204         tcpMain->send(tcpseg,"to_ipv6");
00205     }
00206 }

void TCPConnection::signalConnectionTimeout  ) 
 

Utility: signal to user that connection timed out

00238 {
00239     sendIndicationToApp(TCP_I_TIMED_OUT);
00240 }

void TCPConnection::startSynRexmitTimer  ) 
 

Utility: start SYN-REXMIT timer

01060 {
01061     state->syn_rexmit_count = 0;
01062     state->syn_rexmit_timeout = TCP_TIMEOUT_SYN_REXMIT;
01063 
01064     if (synRexmitTimer->isScheduled())
01065         cancelEvent(synRexmitTimer);
01066     scheduleTimeout(synRexmitTimer, state->syn_rexmit_timeout);
01067 }

void TCPConnection::stateEntered int  state  )  [protected]
 

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

00437 {
00438     // cancel timers
00439     switch (state)
00440     {
00441         case TCP_S_INIT:
00442             // we'll never get back to INIT
00443             break;
00444         case TCP_S_LISTEN:
00445             // we may get back to LISTEN from SYN_RCVD
00446             ASSERT(connEstabTimer && synRexmitTimer);
00447             cancelEvent(connEstabTimer);
00448             cancelEvent(synRexmitTimer);
00449             break;
00450         case TCP_S_SYN_RCVD:
00451         case TCP_S_SYN_SENT:
00452             break;
00453         case TCP_S_ESTABLISHED:
00454             // we're in ESTABLISHED, these timers are no longer needed
00455             delete cancelEvent(connEstabTimer);
00456             delete cancelEvent(synRexmitTimer);
00457             connEstabTimer = synRexmitTimer = NULL;
00458             // TCP_I_ESTAB notification moved inside event processing
00459             break;
00460         case TCP_S_CLOSE_WAIT:
00461         case TCP_S_LAST_ACK:
00462         case TCP_S_FIN_WAIT_1:
00463         case TCP_S_FIN_WAIT_2:
00464         case TCP_S_CLOSING:
00465         case TCP_S_TIME_WAIT:
00466             // whether connection setup succeeded (ESTABLISHED) or not (others),
00467             // cancel these timers
00468             if (connEstabTimer) cancelEvent(connEstabTimer);
00469             if (synRexmitTimer) cancelEvent(synRexmitTimer);
00470             break;
00471         case TCP_S_CLOSED:
00472             // all timers need to be cancelled
00473             if (the2MSLTimer)   cancelEvent(the2MSLTimer);
00474             if (connEstabTimer) cancelEvent(connEstabTimer);
00475             if (finWait2Timer)  cancelEvent(finWait2Timer);
00476             if (synRexmitTimer) cancelEvent(synRexmitTimer);
00477             tcpAlgorithm->connectionClosed();
00478             break;
00479     }
00480 }

const char * TCPConnection::stateName int  state  )  [static]
 

Utility: returns name of TCP_S_xxx constants

00037 {
00038 #define CASE(x) case x: s=#x+6; break
00039     const char *s = "unknown";
00040     switch (state)
00041     {
00042         CASE(TCP_S_INIT);
00043         CASE(TCP_S_CLOSED);
00044         CASE(TCP_S_LISTEN);
00045         CASE(TCP_S_SYN_SENT);
00046         CASE(TCP_S_SYN_RCVD);
00047         CASE(TCP_S_ESTABLISHED);
00048         CASE(TCP_S_CLOSE_WAIT);
00049         CASE(TCP_S_LAST_ACK);
00050         CASE(TCP_S_FIN_WAIT_1);
00051         CASE(TCP_S_FIN_WAIT_2);
00052         CASE(TCP_S_CLOSING);
00053         CASE(TCP_S_TIME_WAIT);
00054     }
00055     return s;
00056 #undef CASE
00057 }

bool TCPConnection::tryFastRoute TCPSegment tcpseg  )  [protected]
 

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

00030 {
00031     // fast route processing not yet implemented
00032     return false;
00033 }


Member Data Documentation

int TCPConnection::appGateIndex
 

cMessage* TCPConnection::connEstabTimer [protected]
 

int TCPConnection::connId
 

cMessage* TCPConnection::finWait2Timer [protected]
 

cFSM TCPConnection::fsm [protected]
 

IPvXAddress TCPConnection::localAddr
 

int TCPConnection::localPort
 

cOutVector* TCPConnection::rcvAckVector [protected]
 

cOutVector* TCPConnection::rcvSeqVector [protected]
 

TCPReceiveQueue* TCPConnection::receiveQueue [protected]
 

IPvXAddress TCPConnection::remoteAddr
 

int TCPConnection::remotePort
 

TCPSendQueue* TCPConnection::sendQueue [protected]
 

cOutVector* TCPConnection::sndAckVector [protected]
 

cOutVector* TCPConnection::sndNxtVector [protected]
 

cOutVector* TCPConnection::sndWndVector [protected]
 

TCPStateVariables* TCPConnection::state [protected]
 

cMessage* TCPConnection::synRexmitTimer [protected]
 

TCPAlgorithm* TCPConnection::tcpAlgorithm [protected]
 

TCP* TCPConnection::tcpMain [protected]
 

cMessage* TCPConnection::the2MSLTimer [protected]
 

cOutVector* TCPConnection::unackedVector [protected]
 


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