#include <TCPConnection.h>
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:
When the CLOSED state is reached, TCP will delete the TCPConnection object.
Public Member Functions | |
virtual void | sendAck () |
virtual bool | sendData (bool fullSegmentsOnly, int congestionWindow=-1) |
virtual bool | sendProbe () |
virtual void | retransmitOneSegment () |
virtual void | retransmitData () |
virtual void | sendRst (uint32 seqNo) |
virtual void | sendRst (uint32 seq, IPvXAddress src, IPvXAddress dest, int srcPort, int destPort) |
virtual void | sendRstAck (uint32 seq, uint32 ack, IPvXAddress src, IPvXAddress dest, int srcPort, int destPort) |
virtual void | sendFin () |
virtual void | sendSegment (int bytes) |
virtual void | sendToIP (TCPSegment *tcpseg) |
virtual TCPSegment * | createTCPSegment (const char *name) |
virtual void | startSynRexmitTimer () |
virtual void | signalConnectionTimeout () |
void | scheduleTimeout (cMessage *msg, simtime_t timeout) |
virtual void | printConnBrief () |
TCPConnection (TCP *mod, int appGateIndex, int connId) | |
TCPConnection () | |
virtual | ~TCPConnection () |
virtual void | segmentArrivalWhileClosed (TCPSegment *tcpseg, IPvXAddress src, IPvXAddress dest) |
virtual bool | processTimer (cMessage *msg) |
virtual bool | processTCPSegment (TCPSegment *tcpSeg, IPvXAddress srcAddr, IPvXAddress destAddr) |
virtual bool | processAppCommand (cMessage *msg) |
int | getFsmState () const |
TCPStateVariables * | getState () |
TCPSendQueue * | getSendQueue () |
TCPReceiveQueue * | getReceiveQueue () |
TCPAlgorithm * | getTcpAlgorithm () |
TCP * | getTcpMain () |
Static Public Member Functions | |
static void | printSegmentBrief (TCPSegment *tcpseg) |
static const char * | stateName (int state) |
static const char * | eventName (int event) |
static const char * | indicationName (int code) |
Public Attributes | |
int | appGateIndex |
int | connId |
IPvXAddress | localAddr |
IPvXAddress | remoteAddr |
int | localPort |
int | remotePort |
Protected Member Functions | |
virtual TCPConnection * | cloneListeningConnection () |
virtual void | initConnection (TCPOpenCommand *openCmd) |
virtual void | configureStateVariables () |
virtual void | selectInitialSeqNum () |
virtual bool | isSegmentAcceptable (TCPSegment *tcpseg) |
virtual void | sendSyn () |
virtual void | sendSynAck () |
cMessage * | cancelEvent (cMessage *msg) |
virtual void | sendToApp (cMessage *msg) |
virtual void | sendIndicationToApp (int code) |
virtual void | sendEstabIndicationToApp () |
FSM transitions: analysing events and executing state transitions | |
virtual TCPEventCode | preanalyseAppCommandEvent (int commandCode) |
virtual bool | performStateTransition (const TCPEventCode &event) |
virtual void | stateEntered (int state) |
Processing app commands. Invoked from processAppCommand(). | |
virtual void | process_OPEN_ACTIVE (TCPEventCode &event, TCPCommand *tcpCommand, cMessage *msg) |
virtual void | process_OPEN_PASSIVE (TCPEventCode &event, TCPCommand *tcpCommand, cMessage *msg) |
virtual void | process_SEND (TCPEventCode &event, TCPCommand *tcpCommand, cMessage *msg) |
virtual void | process_CLOSE (TCPEventCode &event, TCPCommand *tcpCommand, cMessage *msg) |
virtual void | process_ABORT (TCPEventCode &event, TCPCommand *tcpCommand, cMessage *msg) |
virtual void | process_STATUS (TCPEventCode &event, TCPCommand *tcpCommand, cMessage *msg) |
Processing TCP segment arrivals. Invoked from processTCPSegment(). | |
virtual bool | tryFastRoute (TCPSegment *tcpseg) |
virtual TCPEventCode | process_RCV_SEGMENT (TCPSegment *tcpseg, IPvXAddress src, IPvXAddress dest) |
virtual TCPEventCode | processSegmentInListen (TCPSegment *tcpseg, IPvXAddress src, IPvXAddress dest) |
virtual TCPEventCode | processSegmentInSynSent (TCPSegment *tcpseg, IPvXAddress src, IPvXAddress dest) |
virtual TCPEventCode | processSegment1stThru8th (TCPSegment *tcpseg) |
virtual TCPEventCode | processRstInSynReceived (TCPSegment *tcpseg) |
virtual bool | processAckInEstabEtc (TCPSegment *tcpseg) |
Processing timeouts. Invoked from processTimer(). | |
virtual void | process_TIMEOUT_2MSL () |
virtual void | process_TIMEOUT_CONN_ESTAB () |
virtual void | process_TIMEOUT_FIN_WAIT_2 () |
virtual void | process_TIMEOUT_SYN_REXMIT (TCPEventCode &event) |
Static Protected Member Functions | |
static void | sendToIP (TCPSegment *tcpseg, IPvXAddress src, IPvXAddress dest) |
Protected Attributes | |
TCP * | tcpMain |
cFSM | fsm |
TCPStateVariables * | state |
TCPSendQueue * | sendQueue |
TCPReceiveQueue * | receiveQueue |
TCPAlgorithm * | tcpAlgorithm |
cMessage * | the2MSLTimer |
cMessage * | connEstabTimer |
cMessage * | finWait2Timer |
cMessage * | synRexmitTimer |
cOutVector * | sndWndVector |
cOutVector * | sndNxtVector |
cOutVector * | sndAckVector |
cOutVector * | rcvSeqVector |
cOutVector * | rcvAckVector |
cOutVector * | unackedVector |
TCPConnection::TCPConnection | ( | TCP * | mod, | |
int | appGateIndex, | |||
int | connId | |||
) |
The "normal" constructor.
00112 { 00113 tcpMain = _mod; 00114 appGateIndex = _appGateIndex; 00115 connId = _connId; 00116 00117 localPort = remotePort = -1; 00118 00119 char fsmname[24]; 00120 sprintf(fsmname, "fsm-%d", connId); 00121 fsm.setName(fsmname); 00122 fsm.setState(TCP_S_INIT); 00123 00124 00125 // queues and algorithm will be created on active or passive open 00126 sendQueue = NULL; 00127 receiveQueue = NULL; 00128 tcpAlgorithm = NULL; 00129 state = NULL; 00130 00131 the2MSLTimer = new cMessage("2MSL"); 00132 connEstabTimer = new cMessage("CONN-ESTAB"); 00133 finWait2Timer = new cMessage("FIN-WAIT-2"); 00134 synRexmitTimer = new cMessage("SYN-REXMIT"); 00135 00136 the2MSLTimer->setContextPointer(this); 00137 connEstabTimer->setContextPointer(this); 00138 finWait2Timer->setContextPointer(this); 00139 synRexmitTimer->setContextPointer(this); 00140 00141 // statistics 00142 sndWndVector = NULL; 00143 sndNxtVector = NULL; 00144 sndAckVector = NULL; 00145 rcvSeqVector = NULL; 00146 rcvAckVector = NULL; 00147 unackedVector = NULL; 00148 00149 if (getTcpMain()->recordStatistics) 00150 { 00151 sndWndVector = new cOutVector("send window"); 00152 sndNxtVector = new cOutVector("send seq"); 00153 sndAckVector = new cOutVector("sent ack"); 00154 rcvSeqVector = new cOutVector("rcvd seq"); 00155 rcvAckVector = new cOutVector("rcvd ack"); 00156 unackedVector = new cOutVector("unacked bytes"); 00157 } 00158 }
TCPConnection::TCPConnection | ( | ) |
Note: this default ctor is NOT used to create live connections, only temporary ones so that TCPMain can invoke their segmentArrivalWhileClosed().
Referenced by cloneListeningConnection().
00096 { 00097 // Note: this ctor is NOT used to create live connections, only 00098 // temporary ones to invoke segmentArrivalWhileClosed() on 00099 sendQueue = NULL; 00100 receiveQueue = NULL; 00101 tcpAlgorithm = NULL; 00102 state = NULL; 00103 the2MSLTimer = connEstabTimer = finWait2Timer = synRexmitTimer = NULL; 00104 sndWndVector = sndNxtVector = sndAckVector = rcvSeqVector = rcvAckVector = unackedVector = NULL; 00105 }
TCPConnection::~TCPConnection | ( | ) | [virtual] |
Destructor.
00161 { 00162 delete sendQueue; 00163 delete receiveQueue; 00164 delete tcpAlgorithm; 00165 delete state; 00166 00167 if (the2MSLTimer) delete cancelEvent(the2MSLTimer); 00168 if (connEstabTimer) delete cancelEvent(connEstabTimer); 00169 if (finWait2Timer) delete cancelEvent(finWait2Timer); 00170 if (synRexmitTimer) delete cancelEvent(synRexmitTimer); 00171 00172 // statistics 00173 delete sndWndVector; 00174 delete sndNxtVector; 00175 delete sndAckVector; 00176 delete rcvSeqVector; 00177 delete rcvAckVector; 00178 delete unackedVector; 00179 }
TCPEventCode TCPConnection::preanalyseAppCommandEvent | ( | int | commandCode | ) | [protected, virtual] |
Maps app command codes (msg kind of app command msgs) to TCP_E_xxx event codes
Referenced by processAppCommand().
00267 { 00268 switch (commandCode) 00269 { 00270 case TCP_C_OPEN_ACTIVE: return TCP_E_OPEN_ACTIVE; 00271 case TCP_C_OPEN_PASSIVE: return TCP_E_OPEN_PASSIVE; 00272 case TCP_C_SEND: return TCP_E_SEND; 00273 case TCP_C_CLOSE: return TCP_E_CLOSE; 00274 case TCP_C_ABORT: return TCP_E_ABORT; 00275 case TCP_C_STATUS: return TCP_E_STATUS; 00276 default: opp_error("Unknown message kind in app command"); 00277 return (TCPEventCode)0; // to satisfy compiler 00278 } 00279 }
bool TCPConnection::performStateTransition | ( | const TCPEventCode & | event | ) | [protected, virtual] |
Implemements the pure TCP state machine
Referenced by processAppCommand(), processTCPSegment(), and processTimer().
00282 { 00283 ASSERT(fsm.getState()!=TCP_S_CLOSED); // closed connections should be deleted immediately 00284 00285 if (event==TCP_E_IGNORE) // e.g. discarded segment 00286 { 00287 tcpEV << "Staying in state: " << stateName(fsm.getState()) << " (no FSM event)\n"; 00288 return true; 00289 } 00290 00291 // state machine 00292 // TBD add handling of connection timeout event (keepalive), with transition to CLOSED 00293 // Note: empty "default:" lines are for gcc's benefit which would otherwise spit warnings 00294 int oldState = fsm.getState(); 00295 switch (fsm.getState()) 00296 { 00297 case TCP_S_INIT: 00298 switch (event) 00299 { 00300 case TCP_E_OPEN_PASSIVE:FSM_Goto(fsm, TCP_S_LISTEN); break; 00301 case TCP_E_OPEN_ACTIVE: FSM_Goto(fsm, TCP_S_SYN_SENT); break; 00302 default:; 00303 } 00304 break; 00305 00306 case TCP_S_LISTEN: 00307 switch (event) 00308 { 00309 case TCP_E_OPEN_ACTIVE: FSM_Goto(fsm, TCP_S_SYN_SENT); break; 00310 case TCP_E_SEND: FSM_Goto(fsm, TCP_S_SYN_SENT); break; 00311 case TCP_E_CLOSE: FSM_Goto(fsm, TCP_S_CLOSED); break; 00312 case TCP_E_ABORT: FSM_Goto(fsm, TCP_S_CLOSED); break; 00313 case TCP_E_RCV_SYN: FSM_Goto(fsm, TCP_S_SYN_RCVD);break; 00314 default:; 00315 } 00316 break; 00317 00318 case TCP_S_SYN_RCVD: 00319 switch (event) 00320 { 00321 case TCP_E_CLOSE: FSM_Goto(fsm, TCP_S_FIN_WAIT_1); break; 00322 case TCP_E_ABORT: FSM_Goto(fsm, TCP_S_CLOSED); break; 00323 case TCP_E_TIMEOUT_CONN_ESTAB: FSM_Goto(fsm, state->active ? TCP_S_CLOSED : TCP_S_LISTEN); break; 00324 case TCP_E_RCV_RST: FSM_Goto(fsm, state->active ? TCP_S_CLOSED : TCP_S_LISTEN); break; 00325 case TCP_E_RCV_ACK: FSM_Goto(fsm, TCP_S_ESTABLISHED); break; 00326 case TCP_E_RCV_FIN: FSM_Goto(fsm, TCP_S_CLOSE_WAIT); break; 00327 case TCP_E_RCV_UNEXP_SYN: FSM_Goto(fsm, TCP_S_CLOSED); break; 00328 default:; 00329 } 00330 break; 00331 00332 case TCP_S_SYN_SENT: 00333 switch (event) 00334 { 00335 case TCP_E_CLOSE: FSM_Goto(fsm, TCP_S_CLOSED); break; 00336 case TCP_E_ABORT: FSM_Goto(fsm, TCP_S_CLOSED); break; 00337 case TCP_E_TIMEOUT_CONN_ESTAB: FSM_Goto(fsm, TCP_S_CLOSED); break; 00338 case TCP_E_RCV_RST: FSM_Goto(fsm, TCP_S_CLOSED); break; 00339 case TCP_E_RCV_SYN_ACK: FSM_Goto(fsm, TCP_S_ESTABLISHED); break; 00340 case TCP_E_RCV_SYN: FSM_Goto(fsm, TCP_S_SYN_RCVD); break; 00341 default:; 00342 } 00343 break; 00344 00345 case TCP_S_ESTABLISHED: 00346 switch (event) 00347 { 00348 case TCP_E_CLOSE: FSM_Goto(fsm, TCP_S_FIN_WAIT_1); break; 00349 case TCP_E_ABORT: FSM_Goto(fsm, TCP_S_CLOSED); break; 00350 case TCP_E_RCV_FIN: FSM_Goto(fsm, TCP_S_CLOSE_WAIT); break; 00351 case TCP_E_RCV_RST: FSM_Goto(fsm, TCP_S_CLOSED); break; 00352 case TCP_E_RCV_UNEXP_SYN: FSM_Goto(fsm, TCP_S_CLOSED); break; 00353 default:; 00354 } 00355 break; 00356 00357 case TCP_S_CLOSE_WAIT: 00358 switch (event) 00359 { 00360 case TCP_E_CLOSE: FSM_Goto(fsm, TCP_S_LAST_ACK); break; 00361 case TCP_E_ABORT: FSM_Goto(fsm, TCP_S_CLOSED); break; 00362 case TCP_E_RCV_RST: FSM_Goto(fsm, TCP_S_CLOSED); break; 00363 case TCP_E_RCV_UNEXP_SYN: FSM_Goto(fsm, TCP_S_CLOSED); break; 00364 default:; 00365 } 00366 break; 00367 00368 case TCP_S_LAST_ACK: 00369 switch (event) 00370 { 00371 case TCP_E_ABORT: FSM_Goto(fsm, TCP_S_CLOSED); break; 00372 case TCP_E_RCV_ACK: FSM_Goto(fsm, TCP_S_CLOSED); break; 00373 case TCP_E_RCV_RST: FSM_Goto(fsm, TCP_S_CLOSED); break; 00374 case TCP_E_RCV_UNEXP_SYN: FSM_Goto(fsm, TCP_S_CLOSED); break; 00375 default:; 00376 } 00377 break; 00378 00379 case TCP_S_FIN_WAIT_1: 00380 switch (event) 00381 { 00382 case TCP_E_ABORT: FSM_Goto(fsm, TCP_S_CLOSED); break; 00383 case TCP_E_RCV_FIN: FSM_Goto(fsm, TCP_S_CLOSING); break; 00384 case TCP_E_RCV_ACK: FSM_Goto(fsm, TCP_S_FIN_WAIT_2); break; 00385 case TCP_E_RCV_FIN_ACK: FSM_Goto(fsm, TCP_S_TIME_WAIT); break; 00386 case TCP_E_RCV_RST: FSM_Goto(fsm, TCP_S_CLOSED); break; 00387 case TCP_E_RCV_UNEXP_SYN: FSM_Goto(fsm, TCP_S_CLOSED); break; 00388 default:; 00389 } 00390 break; 00391 00392 case TCP_S_FIN_WAIT_2: 00393 switch (event) 00394 { 00395 case TCP_E_ABORT: FSM_Goto(fsm, TCP_S_CLOSED); break; 00396 case TCP_E_RCV_FIN: FSM_Goto(fsm, TCP_S_TIME_WAIT); break; 00397 case TCP_E_TIMEOUT_FIN_WAIT_2: FSM_Goto(fsm, TCP_S_CLOSED); break; 00398 case TCP_E_RCV_RST: FSM_Goto(fsm, TCP_S_CLOSED); break; 00399 case TCP_E_RCV_UNEXP_SYN: FSM_Goto(fsm, TCP_S_CLOSED); break; 00400 default:; 00401 } 00402 break; 00403 00404 case TCP_S_CLOSING: 00405 switch (event) 00406 { 00407 case TCP_E_ABORT: FSM_Goto(fsm, TCP_S_CLOSED); break; 00408 case TCP_E_RCV_ACK: FSM_Goto(fsm, TCP_S_TIME_WAIT); break; 00409 case TCP_E_RCV_RST: FSM_Goto(fsm, TCP_S_CLOSED); break; 00410 case TCP_E_RCV_UNEXP_SYN: FSM_Goto(fsm, TCP_S_CLOSED); break; 00411 default:; 00412 } 00413 break; 00414 00415 case TCP_S_TIME_WAIT: 00416 switch (event) 00417 { 00418 case TCP_E_ABORT: FSM_Goto(fsm, TCP_S_CLOSED); break; 00419 case TCP_E_TIMEOUT_2MSL: FSM_Goto(fsm, TCP_S_CLOSED); break; 00420 case TCP_E_RCV_RST: FSM_Goto(fsm, TCP_S_CLOSED); break; 00421 case TCP_E_RCV_UNEXP_SYN: FSM_Goto(fsm, TCP_S_CLOSED); break; 00422 default:; 00423 } 00424 break; 00425 00426 case TCP_S_CLOSED: 00427 break; 00428 } 00429 00430 if (oldState!=fsm.getState()) 00431 { 00432 tcpEV << "Transition: " << stateName(oldState) << " --> " << stateName(fsm.getState()) << " (event was: " << eventName(event) << ")\n"; 00433 testingEV << tcpMain->getName() << ": " << stateName(oldState) << " --> " << stateName(fsm.getState()) << " (on " << eventName(event) << ")\n"; 00434 00435 // cancel timers, etc. 00436 stateEntered(fsm.getState()); 00437 } 00438 else 00439 { 00440 tcpEV << "Staying in state: " << stateName(fsm.getState()) << " (event was: " << eventName(event) << ")\n"; 00441 } 00442 00443 return fsm.getState()!=TCP_S_CLOSED; 00444 }
void TCPConnection::stateEntered | ( | int | state | ) | [protected, virtual] |
Perform cleanup necessary when entering a new state, e.g. cancelling timers
Referenced by performStateTransition().
00447 { 00448 // cancel timers 00449 switch (state) 00450 { 00451 case TCP_S_INIT: 00452 // we'll never get back to INIT 00453 break; 00454 case TCP_S_LISTEN: 00455 // we may get back to LISTEN from SYN_RCVD 00456 ASSERT(connEstabTimer && synRexmitTimer); 00457 cancelEvent(connEstabTimer); 00458 cancelEvent(synRexmitTimer); 00459 break; 00460 case TCP_S_SYN_RCVD: 00461 case TCP_S_SYN_SENT: 00462 break; 00463 case TCP_S_ESTABLISHED: 00464 // we're in ESTABLISHED, these timers are no longer needed 00465 delete cancelEvent(connEstabTimer); 00466 delete cancelEvent(synRexmitTimer); 00467 connEstabTimer = synRexmitTimer = NULL; 00468 // TCP_I_ESTAB notification moved inside event processing 00469 break; 00470 case TCP_S_CLOSE_WAIT: 00471 case TCP_S_LAST_ACK: 00472 case TCP_S_FIN_WAIT_1: 00473 case TCP_S_FIN_WAIT_2: 00474 case TCP_S_CLOSING: 00475 case TCP_S_TIME_WAIT: 00476 // whether connection setup succeeded (ESTABLISHED) or not (others), 00477 // cancel these timers 00478 if (connEstabTimer) cancelEvent(connEstabTimer); 00479 if (synRexmitTimer) cancelEvent(synRexmitTimer); 00480 break; 00481 case TCP_S_CLOSED: 00482 // all timers need to be cancelled 00483 if (the2MSLTimer) cancelEvent(the2MSLTimer); 00484 if (connEstabTimer) cancelEvent(connEstabTimer); 00485 if (finWait2Timer) cancelEvent(finWait2Timer); 00486 if (synRexmitTimer) cancelEvent(synRexmitTimer); 00487 tcpAlgorithm->connectionClosed(); 00488 break; 00489 } 00490 }
void TCPConnection::process_OPEN_ACTIVE | ( | TCPEventCode & | event, | |
TCPCommand * | tcpCommand, | |||
cMessage * | msg | |||
) | [protected, virtual] |
Referenced by processAppCommand().
00034 { 00035 TCPOpenCommand *openCmd = check_and_cast<TCPOpenCommand *>(tcpCommand); 00036 IPvXAddress localAddr, remoteAddr; 00037 short localPort, remotePort; 00038 00039 switch(fsm.getState()) 00040 { 00041 case TCP_S_INIT: 00042 initConnection(openCmd); 00043 00044 // store local/remote socket 00045 state->active = true; 00046 localAddr = openCmd->getLocalAddr(); 00047 remoteAddr = openCmd->getRemoteAddr(); 00048 localPort = openCmd->getLocalPort(); 00049 remotePort = openCmd->getRemotePort(); 00050 00051 if (remoteAddr.isUnspecified() || remotePort==-1) 00052 opp_error("Error processing command OPEN_ACTIVE: remote address and port must be specified"); 00053 00054 if (localPort==-1) 00055 { 00056 localPort = tcpMain->getEphemeralPort(); 00057 tcpEV << "Assigned ephemeral port " << localPort << "\n"; 00058 } 00059 00060 tcpEV << "OPEN: " << localAddr << ":" << localPort << " --> " << remoteAddr << ":" << remotePort << "\n"; 00061 00062 tcpMain->addSockPair(this, localAddr, remoteAddr, localPort, remotePort); 00063 00064 // send initial SYN 00065 selectInitialSeqNum(); 00066 sendSyn(); 00067 startSynRexmitTimer(); 00068 scheduleTimeout(connEstabTimer, TCP_TIMEOUT_CONN_ESTAB); 00069 break; 00070 00071 default: 00072 opp_error("Error processing command OPEN_ACTIVE: connection already exists"); 00073 } 00074 00075 delete openCmd; 00076 delete msg; 00077 }
void TCPConnection::process_OPEN_PASSIVE | ( | TCPEventCode & | event, | |
TCPCommand * | tcpCommand, | |||
cMessage * | msg | |||
) | [protected, virtual] |
Referenced by processAppCommand().
00080 { 00081 TCPOpenCommand *openCmd = check_and_cast<TCPOpenCommand *>(tcpCommand); 00082 IPvXAddress localAddr; 00083 short localPort; 00084 00085 switch(fsm.getState()) 00086 { 00087 case TCP_S_INIT: 00088 initConnection(openCmd); 00089 00090 // store local/remote socket 00091 state->active = false; 00092 state->fork = openCmd->getFork(); 00093 localAddr = openCmd->getLocalAddr(); 00094 localPort = openCmd->getLocalPort(); 00095 00096 if (localPort==-1) 00097 opp_error("Error processing command OPEN_PASSIVE: local port must be specified"); 00098 00099 tcpEV << "Starting to listen on: " << localAddr << ":" << localPort << "\n"; 00100 00101 tcpMain->addSockPair(this, localAddr, IPvXAddress(), localPort, -1); 00102 break; 00103 00104 default: 00105 opp_error("Error processing command OPEN_PASSIVE: connection already exists"); 00106 } 00107 00108 delete openCmd; 00109 delete msg; 00110 }
void TCPConnection::process_SEND | ( | TCPEventCode & | event, | |
TCPCommand * | tcpCommand, | |||
cMessage * | msg | |||
) | [protected, virtual] |
Referenced by processAppCommand().
00113 { 00114 TCPSendCommand *sendCommand = check_and_cast<TCPSendCommand *>(tcpCommand); 00115 00116 // FIXME how to support PUSH? One option is to treat each SEND as a unit of data, 00117 // and set PSH at SEND boundaries 00118 switch(fsm.getState()) 00119 { 00120 case TCP_S_INIT: 00121 opp_error("Error processing command SEND: connection not open"); 00122 00123 case TCP_S_LISTEN: 00124 tcpEV << "SEND command turns passive open into active open, sending initial SYN\n"; 00125 state->active = true; 00126 selectInitialSeqNum(); 00127 sendSyn(); 00128 startSynRexmitTimer(); 00129 scheduleTimeout(connEstabTimer, TCP_TIMEOUT_CONN_ESTAB); 00130 sendQueue->enqueueAppData(PK(msg)); // queue up for later 00131 tcpEV << sendQueue->getBytesAvailable(state->snd_una) << " bytes in queue\n"; 00132 break; 00133 00134 case TCP_S_SYN_RCVD: 00135 case TCP_S_SYN_SENT: 00136 tcpEV << "Queueing up data for sending later.\n"; 00137 sendQueue->enqueueAppData(PK(msg)); // queue up for later 00138 tcpEV << sendQueue->getBytesAvailable(state->snd_una) << " bytes in queue\n"; 00139 break; 00140 00141 case TCP_S_ESTABLISHED: 00142 case TCP_S_CLOSE_WAIT: 00143 sendQueue->enqueueAppData(PK(msg)); 00144 tcpEV << sendQueue->getBytesAvailable(state->snd_una) << " bytes in queue, plus " 00145 << (state->snd_max-state->snd_una) << " bytes unacknowledged\n"; 00146 tcpAlgorithm->sendCommandInvoked(); 00147 break; 00148 00149 case TCP_S_LAST_ACK: 00150 case TCP_S_FIN_WAIT_1: 00151 case TCP_S_FIN_WAIT_2: 00152 case TCP_S_CLOSING: 00153 case TCP_S_TIME_WAIT: 00154 opp_error("Error processing command SEND: connection closing"); 00155 } 00156 00157 delete sendCommand; // msg itself has been taken by the sendQueue 00158 }
void TCPConnection::process_CLOSE | ( | TCPEventCode & | event, | |
TCPCommand * | tcpCommand, | |||
cMessage * | msg | |||
) | [protected, virtual] |
Referenced by processAppCommand().
00161 { 00162 delete tcpCommand; 00163 delete msg; 00164 00165 switch(fsm.getState()) 00166 { 00167 case TCP_S_INIT: 00168 opp_error("Error processing command CLOSE: connection not open"); 00169 00170 case TCP_S_LISTEN: 00171 // Nothing to do here 00172 break; 00173 00174 case TCP_S_SYN_SENT: 00175 // Delete the TCB and return "error: closing" responses to any 00176 // queued SENDs, or RECEIVEs. 00177 break; 00178 00179 case TCP_S_SYN_RCVD: 00180 case TCP_S_ESTABLISHED: 00181 case TCP_S_CLOSE_WAIT: 00182 // 00183 // SYN_RCVD processing (ESTABLISHED and CLOSE_WAIT are similar): 00184 //" 00185 // If no SENDs have been issued and there is no pending data to send, 00186 // then form a FIN segment and send it, and enter FIN-WAIT-1 state; 00187 // otherwise queue for processing after entering ESTABLISHED state. 00188 //" 00189 if (state->snd_max==sendQueue->getBufferEndSeq()) 00190 { 00191 tcpEV << "No outstanding SENDs, sending FIN right away, advancing snd_nxt over the FIN\n"; 00192 state->snd_nxt = state->snd_max; 00193 sendFin(); 00194 state->snd_max = ++state->snd_nxt; 00195 if (unackedVector) unackedVector->record(state->snd_max - state->snd_una); 00196 00197 // state transition will automatically take us to FIN_WAIT_1 (or LAST_ACK) 00198 } 00199 else 00200 { 00201 tcpEV << "SEND of " << (sendQueue->getBufferEndSeq()-state->snd_max) << 00202 " bytes pending, deferring sending of FIN\n"; 00203 event = TCP_E_IGNORE; 00204 } 00205 state->send_fin = true; 00206 state->snd_fin_seq = sendQueue->getBufferEndSeq(); 00207 break; 00208 00209 case TCP_S_FIN_WAIT_1: 00210 case TCP_S_FIN_WAIT_2: 00211 case TCP_S_CLOSING: 00212 case TCP_S_LAST_ACK: 00213 case TCP_S_TIME_WAIT: 00214 // RFC 793 is not entirely clear on how to handle a duplicate close request. 00215 // Here we treat it as an error. 00216 opp_error("Duplicate CLOSE command: connection already closing"); 00217 } 00218 }
void TCPConnection::process_ABORT | ( | TCPEventCode & | event, | |
TCPCommand * | tcpCommand, | |||
cMessage * | msg | |||
) | [protected, virtual] |
Referenced by processAppCommand().
00221 { 00222 delete tcpCommand; 00223 delete msg; 00224 00225 // 00226 // The ABORT event will automatically take the connection to the CLOSED 00227 // state, flush queues etc -- no need to do it here. Also, we don't need to 00228 // send notification to the user, they know what's going on. 00229 // 00230 switch(fsm.getState()) 00231 { 00232 case TCP_S_INIT: 00233 opp_error("Error processing command ABORT: connection not open"); 00234 00235 case TCP_S_SYN_RCVD: 00236 case TCP_S_ESTABLISHED: 00237 case TCP_S_FIN_WAIT_1: 00238 case TCP_S_FIN_WAIT_2: 00239 case TCP_S_CLOSE_WAIT: 00240 //" 00241 // Send a reset segment: 00242 // 00243 // <SEQ=SND.NXT><CTL=RST> 00244 //" 00245 sendRst(state->snd_nxt); 00246 break; 00247 } 00248 00249 }
void TCPConnection::process_STATUS | ( | TCPEventCode & | event, | |
TCPCommand * | tcpCommand, | |||
cMessage * | msg | |||
) | [protected, virtual] |
Referenced by processAppCommand().
00252 { 00253 delete tcpCommand; // but reuse msg for reply 00254 00255 if (fsm.getState()==TCP_S_INIT) 00256 opp_error("Error processing command STATUS: connection not open"); 00257 00258 TCPStatusInfo *statusInfo = new TCPStatusInfo(); 00259 00260 statusInfo->setState(fsm.getState()); 00261 statusInfo->setStateName(stateName(fsm.getState())); 00262 00263 statusInfo->setLocalAddr(localAddr); 00264 statusInfo->setRemoteAddr(remoteAddr); 00265 statusInfo->setLocalPort(localPort); 00266 statusInfo->setRemotePort(remotePort); 00267 00268 statusInfo->setSnd_mss(state->snd_mss); 00269 statusInfo->setSnd_una(state->snd_una); 00270 statusInfo->setSnd_nxt(state->snd_nxt); 00271 statusInfo->setSnd_max(state->snd_max); 00272 statusInfo->setSnd_wnd(state->snd_wnd); 00273 statusInfo->setSnd_up(state->snd_up); 00274 statusInfo->setSnd_wl1(state->snd_wl1); 00275 statusInfo->setSnd_wl2(state->snd_wl2); 00276 statusInfo->setIss(state->iss); 00277 statusInfo->setRcv_nxt(state->rcv_nxt); 00278 statusInfo->setRcv_wnd(state->rcv_wnd); 00279 statusInfo->setRcv_up(state->rcv_up); 00280 statusInfo->setIrs(state->irs); 00281 statusInfo->setFin_ack_rcvd(state->fin_ack_rcvd); 00282 00283 msg->setControlInfo(statusInfo); 00284 sendToApp(msg); 00285 }
bool TCPConnection::tryFastRoute | ( | TCPSegment * | tcpseg | ) | [protected, virtual] |
Shortcut to process most common case as fast as possible. Returns false if segment requires normal (slow) route.
Referenced by processTCPSegment().
TCPEventCode TCPConnection::process_RCV_SEGMENT | ( | TCPSegment * | tcpseg, | |
IPvXAddress | src, | |||
IPvXAddress | dest | |||
) | [protected, virtual] |
Process incoming TCP segment. Returns a specific event code (e.g. TCP_E_RCV_SYN) which will drive the state machine.
Referenced by processTCPSegment().
00082 { 00083 tcpEV << "Seg arrived: "; 00084 printSegmentBrief(tcpseg); 00085 tcpEV << "TCB: " << state->info() << "\n"; 00086 00087 if (rcvSeqVector) rcvSeqVector->record(tcpseg->getSequenceNo()); 00088 if (rcvAckVector) rcvAckVector->record(tcpseg->getAckNo()); 00089 00090 // 00091 // Note: this code is organized exactly as RFC 793, section "3.9 Event 00092 // Processing", subsection "SEGMENT ARRIVES". 00093 // 00094 TCPEventCode event; 00095 if (fsm.getState()==TCP_S_LISTEN) 00096 { 00097 event = processSegmentInListen(tcpseg, src, dest); 00098 } 00099 else if (fsm.getState()==TCP_S_SYN_SENT) 00100 { 00101 event = processSegmentInSynSent(tcpseg, src, dest); 00102 } 00103 else 00104 { 00105 // RFC 793 steps "first check sequence number", "second check the RST bit", etc 00106 event = processSegment1stThru8th(tcpseg); 00107 } 00108 delete tcpseg; 00109 return event; 00110 }
TCPEventCode TCPConnection::processSegmentInListen | ( | TCPSegment * | tcpseg, | |
IPvXAddress | src, | |||
IPvXAddress | dest | |||
) | [protected, virtual] |
Referenced by process_RCV_SEGMENT().
00572 { 00573 tcpEV2 << "Processing segment in LISTEN\n"; 00574 00575 //" 00576 // first check for an RST 00577 // An incoming RST should be ignored. Return. 00578 //" 00579 if (tcpseg->getRstBit()) 00580 { 00581 tcpEV << "RST bit set: dropping segment\n"; 00582 return TCP_E_IGNORE; 00583 } 00584 00585 //" 00586 // second check for an ACK 00587 // Any acknowledgment is bad if it arrives on a connection still in 00588 // the LISTEN state. An acceptable reset segment should be formed 00589 // for any arriving ACK-bearing segment. The RST should be 00590 // formatted as follows: 00591 // 00592 // <SEQ=SEG.ACK><CTL=RST> 00593 // 00594 // Return. 00595 //" 00596 if (tcpseg->getAckBit()) 00597 { 00598 tcpEV << "ACK bit set: dropping segment and sending RST\n"; 00599 sendRst(tcpseg->getAckNo(),destAddr,srcAddr,tcpseg->getDestPort(),tcpseg->getSrcPort()); 00600 return TCP_E_IGNORE; 00601 } 00602 00603 //" 00604 // third check for a SYN 00605 //" 00606 if (tcpseg->getSynBit()) 00607 { 00608 if (tcpseg->getFinBit()) 00609 { 00610 // Looks like implementations vary on how to react to SYN+FIN. 00611 // Some treat it as plain SYN (and reply with SYN+ACK), some send RST+ACK. 00612 // Let's just do the former here. 00613 tcpEV << "SYN+FIN received: ignoring FIN\n"; 00614 } 00615 00616 tcpEV << "SYN bit set: filling in foreign socket and sending SYN+ACK\n"; 00617 00618 //" 00619 // If the listen was not fully specified (i.e., the foreign socket was not 00620 // fully specified), then the unspecified fields should be filled in now. 00621 //" 00622 // 00623 // Also, we may need to fork, in order to leave another connection 00624 // LISTENing on the port. Note: forking will change our connId. 00625 // 00626 if (state->fork) 00627 { 00628 TCPConnection *conn = cloneListeningConnection(); // this will stay LISTENing 00629 tcpMain->addForkedConnection(this, conn, destAddr, srcAddr, tcpseg->getDestPort(), tcpseg->getSrcPort()); 00630 tcpEV << "Connection forked: this connection got new connId=" << connId << ", " 00631 "spinoff keeps LISTENing with connId=" << conn->connId << "\n"; 00632 } 00633 else 00634 { 00635 tcpMain->updateSockPair(this, destAddr, srcAddr, tcpseg->getDestPort(), tcpseg->getSrcPort()); 00636 } 00637 00638 //" 00639 // Set RCV.NXT to SEG.SEQ+1, IRS is set to SEG.SEQ and any other 00640 // control or text should be queued for processing later. ISS 00641 // should be selected and a SYN segment sent of the form: 00642 // 00643 // <SEQ=ISS><ACK=RCV.NXT><CTL=SYN,ACK> 00644 // 00645 // SND.NXT is set to ISS+1 and SND.UNA to ISS. The connection 00646 // state should be changed to SYN-RECEIVED. 00647 //" 00648 state->rcv_nxt = tcpseg->getSequenceNo()+1; 00649 state->irs = tcpseg->getSequenceNo(); 00650 receiveQueue->init(state->rcv_nxt); // FIXME may init twice... 00651 selectInitialSeqNum(); 00652 00653 // although not mentioned in RFC 793, seems like we have to pick up 00654 // initial snd_wnd from the segment here. 00655 state->snd_wnd = tcpseg->getWindow(); 00656 state->snd_wl1 = tcpseg->getSequenceNo(); 00657 state->snd_wl2 = state->iss; 00658 if (sndWndVector) sndWndVector->record(state->snd_wnd); 00659 00660 sendSynAck(); 00661 startSynRexmitTimer(); 00662 if (!connEstabTimer->isScheduled()) 00663 scheduleTimeout(connEstabTimer, TCP_TIMEOUT_CONN_ESTAB); 00664 00665 //" 00666 // Note that any other incoming control or data (combined with SYN) 00667 // will be processed in the SYN-RECEIVED state, but processing of SYN 00668 // and ACK should not be repeated. 00669 //" 00670 // We don't send text in SYN or SYN+ACK, but accept it. Otherwise 00671 // there isn't much left to do: RST, SYN, ACK, FIN got processed already, 00672 // so there's only URG and PSH left to handle. 00673 // 00674 if (tcpseg->getPayloadLength()>0) 00675 receiveQueue->insertBytesFromSegment(tcpseg); 00676 if (tcpseg->getUrgBit() || tcpseg->getPshBit()) 00677 tcpEV << "Ignoring URG and PSH bits in SYN\n"; // TBD 00678 00679 return TCP_E_RCV_SYN; // this will take us to SYN_RCVD 00680 } 00681 00682 //" 00683 // fourth other text or control 00684 // So you are unlikely to get here, but if you do, drop the segment, and return. 00685 //" 00686 tcpEV << "Unexpected segment: dropping it\n"; 00687 return TCP_E_IGNORE; 00688 }
TCPEventCode TCPConnection::processSegmentInSynSent | ( | TCPSegment * | tcpseg, | |
IPvXAddress | src, | |||
IPvXAddress | dest | |||
) | [protected, virtual] |
Referenced by process_RCV_SEGMENT().
00691 { 00692 tcpEV2 << "Processing segment in SYN_SENT\n"; 00693 00694 //" 00695 // first check the ACK bit 00696 // 00697 // If the ACK bit is set 00698 // 00699 // If SEG.ACK =< ISS, or SEG.ACK > SND.NXT, send a reset (unless 00700 // the RST bit is set, if so drop the segment and return) 00701 // 00702 // <SEQ=SEG.ACK><CTL=RST> 00703 // 00704 // and discard the segment. Return. 00705 // 00706 // If SND.UNA =< SEG.ACK =< SND.NXT then the ACK is acceptable. 00707 //" 00708 if (tcpseg->getAckBit()) 00709 { 00710 if (seqLE(tcpseg->getAckNo(),state->iss) || seqGreater(tcpseg->getAckNo(),state->snd_nxt)) 00711 { 00712 tcpEV << "ACK bit set but wrong AckNo, sending RST\n"; 00713 sendRst(tcpseg->getAckNo(),destAddr,srcAddr,tcpseg->getDestPort(),tcpseg->getSrcPort()); 00714 return TCP_E_IGNORE; 00715 } 00716 tcpEV << "ACK bit set, AckNo acceptable\n"; 00717 } 00718 00719 //" 00720 // second check the RST bit 00721 // 00722 // If the RST bit is set 00723 // 00724 // If the ACK was acceptable then signal the user "error: 00725 // connection reset", drop the segment, enter CLOSED state, 00726 // delete TCB, and return. Otherwise (no ACK) drop the segment 00727 // and return. 00728 //" 00729 if (tcpseg->getRstBit()) 00730 { 00731 if (tcpseg->getAckBit()) 00732 { 00733 tcpEV << "RST+ACK: performing connection reset\n"; 00734 sendIndicationToApp(TCP_I_CONNECTION_RESET); 00735 return TCP_E_RCV_RST; 00736 } 00737 else 00738 { 00739 tcpEV << "RST without ACK: dropping segment\n"; 00740 return TCP_E_IGNORE; 00741 } 00742 } 00743 00744 //" 00745 // third check the security and precedence -- not done 00746 // 00747 // fourth check the SYN bit 00748 // 00749 // This step should be reached only if the ACK is ok, or there is 00750 // no ACK, and it the segment did not contain a RST. 00751 // 00752 // If the SYN bit is on and the security/compartment and precedence 00753 // are acceptable then, 00754 //" 00755 if (tcpseg->getSynBit()) 00756 { 00757 // 00758 // RCV.NXT is set to SEG.SEQ+1, IRS is set to 00759 // SEG.SEQ. SND.UNA should be advanced to equal SEG.ACK (if there 00760 // is an ACK), and any segments on the retransmission queue which 00761 // are thereby acknowledged should be removed. 00762 // 00763 state->rcv_nxt = tcpseg->getSequenceNo()+1; 00764 state->irs = tcpseg->getSequenceNo(); 00765 receiveQueue->init(state->rcv_nxt); 00766 00767 if (tcpseg->getAckBit()) 00768 { 00769 state->snd_una = tcpseg->getAckNo(); 00770 sendQueue->discardUpTo(state->snd_una); 00771 00772 // although not mentioned in RFC 793, seems like we have to pick up 00773 // initial snd_wnd from the segment here. 00774 state->snd_wnd = tcpseg->getWindow(); 00775 state->snd_wl1 = tcpseg->getSequenceNo(); 00776 state->snd_wl2 = tcpseg->getAckNo(); 00777 if (sndWndVector) sndWndVector->record(state->snd_wnd); 00778 } 00779 00780 // this also seems to be a good time to learn our local IP address 00781 // (was probably unspecified at connection open) 00782 tcpMain->updateSockPair(this, destAddr, srcAddr, tcpseg->getDestPort(), tcpseg->getSrcPort()); 00783 00784 //" 00785 // If SND.UNA > ISS (our SYN has been ACKed), change the connection 00786 // state to ESTABLISHED, form an ACK segment 00787 // 00788 // <SEQ=SND.NXT><ACK=RCV.NXT><CTL=ACK> 00789 // 00790 // and send it. Data or controls which were queued for 00791 // transmission may be included. If there are other controls or 00792 // text in the segment then continue processing at the sixth step 00793 // below where the URG bit is checked, otherwise return. 00794 //" 00795 if (seqGreater(state->snd_una, state->iss)) 00796 { 00797 tcpEV << "SYN+ACK bits set, connection established.\n"; 00798 00799 // RFC says "continue processing at the sixth step below where 00800 // the URG bit is checked". Those steps deal with: URG, segment text 00801 // (and PSH), and FIN. 00802 // Now: URG and PSH we don't support yet; in SYN+FIN we ignore FIN; 00803 // with segment text we just take it easy and put it in the receiveQueue 00804 // -- we'll forward it to the user when more data arrives. 00805 if (tcpseg->getFinBit()) 00806 tcpEV << "SYN+ACK+FIN received: ignoring FIN\n"; 00807 if (tcpseg->getPayloadLength()>0) 00808 state->rcv_nxt = receiveQueue->insertBytesFromSegment(tcpseg); // TBD forward to app, etc. 00809 if (tcpseg->getUrgBit() || tcpseg->getPshBit()) 00810 tcpEV << "Ignoring URG and PSH bits in SYN+ACK\n"; // TBD 00811 00812 // notify tcpAlgorithm (it has to send ACK of SYN) and app layer 00813 tcpAlgorithm->established(true); 00814 sendEstabIndicationToApp(); 00815 00816 // This will trigger transition to ESTABLISHED. Timers and notifying 00817 // app will be taken care of in stateEntered(). 00818 return TCP_E_RCV_SYN_ACK; 00819 } 00820 00821 //" 00822 // Otherwise enter SYN-RECEIVED, form a SYN,ACK segment 00823 // 00824 // <SEQ=ISS><ACK=RCV.NXT><CTL=SYN,ACK> 00825 // 00826 // and send it. If there are other controls or text in the 00827 // segment, queue them for processing after the ESTABLISHED state 00828 // has been reached, return. 00829 //" 00830 tcpEV << "SYN bit set: sending SYN+ACK\n"; 00831 state->snd_max = state->snd_nxt = state->iss; 00832 sendSynAck(); 00833 startSynRexmitTimer(); 00834 00835 // Note: code below is similar to processing SYN in LISTEN. 00836 00837 // For consistency with that code, we ignore SYN+FIN here 00838 if (tcpseg->getFinBit()) 00839 tcpEV << "SYN+FIN received: ignoring FIN\n"; 00840 00841 // We don't send text in SYN or SYN+ACK, but accept it. Otherwise 00842 // there isn't much left to do: RST, SYN, ACK, FIN got processed already, 00843 // so there's only URG and PSH left to handle. 00844 if (tcpseg->getPayloadLength()>0) 00845 receiveQueue->insertBytesFromSegment(tcpseg); 00846 if (tcpseg->getUrgBit() || tcpseg->getPshBit()) 00847 tcpEV << "Ignoring URG and PSH bits in SYN\n"; // TBD 00848 return TCP_E_RCV_SYN; 00849 } 00850 00851 //" 00852 // fifth, if neither of the SYN or RST bits is set then drop the 00853 // segment and return. 00854 //" 00855 return TCP_E_IGNORE; 00856 }
TCPEventCode TCPConnection::processSegment1stThru8th | ( | TCPSegment * | tcpseg | ) | [protected, virtual] |
Referenced by process_RCV_SEGMENT().
00113 { 00114 // 00115 // RFC 793: first check sequence number 00116 // 00117 bool acceptable = isSegmentAcceptable(tcpseg); 00118 if (!acceptable) 00119 { 00120 //" 00121 // If an incoming segment is not acceptable, an acknowledgment 00122 // should be sent in reply (unless the RST bit is set, if so drop 00123 // the segment and return): 00124 // 00125 // <SEQ=SND.NXT><ACK=RCV.NXT><CTL=ACK> 00126 //" 00127 if (tcpseg->getRstBit()) 00128 { 00129 tcpEV << "RST with unacceptable seqNum: dropping\n"; 00130 } 00131 else 00132 { 00133 tcpEV << "Segment seqNum not acceptable, sending ACK with current receive seq\n"; 00134 sendAck(); 00135 } 00136 return TCP_E_IGNORE; 00137 } 00138 00139 // 00140 // RFC 793: second check the RST bit, 00141 // 00142 if (tcpseg->getRstBit()) 00143 { 00144 // Note: if we come from LISTEN, processSegmentInListen() has already handled RST. 00145 switch (fsm.getState()) 00146 { 00147 case TCP_S_SYN_RCVD: 00148 //" 00149 // If this connection was initiated with a passive OPEN (i.e., 00150 // came from the LISTEN state), then return this connection to 00151 // LISTEN state and return. The user need not be informed. If 00152 // this connection was initiated with an active OPEN (i.e., came 00153 // from SYN-SENT state) then the connection was refused, signal 00154 // the user "connection refused". In either case, all segments 00155 // on the retransmission queue should be removed. And in the 00156 // active OPEN case, enter the CLOSED state and delete the TCB, 00157 // and return. 00158 //" 00159 return processRstInSynReceived(tcpseg); 00160 00161 case TCP_S_ESTABLISHED: 00162 case TCP_S_FIN_WAIT_1: 00163 case TCP_S_FIN_WAIT_2: 00164 case TCP_S_CLOSE_WAIT: 00165 //" 00166 // If the RST bit is set then, any outstanding RECEIVEs and SEND 00167 // should receive "reset" responses. All segment queues should be 00168 // flushed. Users should also receive an unsolicited general 00169 // "connection reset" signal. 00170 // 00171 // Enter the CLOSED state, delete the TCB, and return. 00172 //" 00173 tcpEV << "RST: performing connection reset, closing connection\n"; 00174 sendIndicationToApp(TCP_I_CONNECTION_RESET); 00175 return TCP_E_RCV_RST; // this will trigger state transition 00176 00177 case TCP_S_CLOSING: 00178 case TCP_S_LAST_ACK: 00179 case TCP_S_TIME_WAIT: 00180 //" 00181 // enter the CLOSED state, delete the TCB, and return. 00182 //" 00183 tcpEV << "RST: closing connection\n"; 00184 if (fsm.getState()!=TCP_S_TIME_WAIT) 00185 sendIndicationToApp(TCP_I_CLOSED); // in TIME_WAIT, we've already sent it 00186 return TCP_E_RCV_RST; // this will trigger state transition 00187 00188 default: ASSERT(0); 00189 } 00190 } 00191 00192 // RFC 793: third check security and precedence 00193 // This step is ignored. 00194 00195 // 00196 // RFC 793: fourth, check the SYN bit, 00197 // 00198 if (tcpseg->getSynBit()) 00199 { 00200 //" 00201 // If the SYN is in the window it is an error, send a reset, any 00202 // outstanding RECEIVEs and SEND should receive "reset" responses, 00203 // all segment queues should be flushed, the user should also 00204 // receive an unsolicited general "connection reset" signal, enter 00205 // the CLOSED state, delete the TCB, and return. 00206 // 00207 // If the SYN is not in the window this step would not be reached 00208 // and an ack would have been sent in the first step (sequence 00209 // number check). 00210 //" 00211 00212 ASSERT(isSegmentAcceptable(tcpseg)); // assert SYN is in the window 00213 tcpEV << "SYN is in the window: performing connection reset, closing connection\n"; 00214 sendIndicationToApp(TCP_I_CONNECTION_RESET); 00215 return TCP_E_RCV_UNEXP_SYN; 00216 } 00217 00218 // 00219 // RFC 793: fifth check the ACK field, 00220 // 00221 if (!tcpseg->getAckBit()) 00222 { 00223 // if the ACK bit is off drop the segment and return 00224 tcpEV << "ACK not set, dropping segment\n"; 00225 return TCP_E_IGNORE; 00226 } 00227 00228 TCPEventCode event = TCP_E_IGNORE; 00229 00230 if (fsm.getState()==TCP_S_SYN_RCVD) 00231 { 00232 //" 00233 // If SND.UNA =< SEG.ACK =< SND.NXT then enter ESTABLISHED state 00234 // and continue processing. 00235 // 00236 // If the segment acknowledgment is not acceptable, form a 00237 // reset segment, 00238 // 00239 // <SEQ=SEG.ACK><CTL=RST> 00240 // 00241 // and send it. 00242 //" 00243 if (!seqLE(state->snd_una,tcpseg->getAckNo()) || !seqLE(tcpseg->getAckNo(),state->snd_nxt)) 00244 { 00245 sendRst(tcpseg->getAckNo()); 00246 return TCP_E_IGNORE; 00247 } 00248 00249 // notify tcpAlgorithm and app layer 00250 tcpAlgorithm->established(false); 00251 sendEstabIndicationToApp(); 00252 00253 // This will trigger transition to ESTABLISHED. Timers and notifying 00254 // app will be taken care of in stateEntered(). 00255 event = TCP_E_RCV_ACK; 00256 } 00257 00258 uint32 old_snd_nxt = state->snd_nxt; // later we'll need to see if snd_nxt changed 00259 if (fsm.getState()==TCP_S_SYN_RCVD || fsm.getState()==TCP_S_ESTABLISHED || 00260 fsm.getState()==TCP_S_FIN_WAIT_1 || fsm.getState()==TCP_S_FIN_WAIT_2 || 00261 fsm.getState()==TCP_S_CLOSE_WAIT || fsm.getState()==TCP_S_CLOSING) 00262 { 00263 // 00264 // ESTABLISHED processing: 00265 //" 00266 // If SND.UNA < SEG.ACK =< SND.NXT then, set SND.UNA <- SEG.ACK. 00267 // Any segments on the retransmission queue which are thereby 00268 // entirely acknowledged are removed. Users should receive 00269 // positive acknowledgments for buffers which have been SENT and 00270 // fully acknowledged (i.e., SEND buffer should be returned with 00271 // "ok" response). If the ACK is a duplicate 00272 // (SEG.ACK < SND.UNA), it can be ignored. If the ACK acks 00273 // something not yet sent (SEG.ACK > SND.NXT) then send an ACK, 00274 // drop the segment, and return. 00275 // 00276 // If SND.UNA < SEG.ACK =< SND.NXT, the send window should be 00277 // updated. If (SND.WL1 < SEG.SEQ or (SND.WL1 = SEG.SEQ and 00278 // SND.WL2 =< SEG.ACK)), set SND.WND <- SEG.WND, set 00279 // SND.WL1 <- SEG.SEQ, and set SND.WL2 <- SEG.ACK. 00280 // 00281 // Note that SND.WND is an offset from SND.UNA, that SND.WL1 00282 // records the sequence number of the last segment used to update 00283 // SND.WND, and that SND.WL2 records the acknowledgment number of 00284 // the last segment used to update SND.WND. The check here 00285 // prevents using old segments to update the window. 00286 //" 00287 bool ok = processAckInEstabEtc(tcpseg); 00288 if (!ok) 00289 return TCP_E_IGNORE; // if acks something not yet sent, drop it 00290 } 00291 00292 if ((fsm.getState()==TCP_S_FIN_WAIT_1 && state->fin_ack_rcvd)) 00293 { 00294 //" 00295 // FIN-WAIT-1 STATE 00296 // In addition to the processing for the ESTABLISHED state, if 00297 // our FIN is now acknowledged then enter FIN-WAIT-2 and continue 00298 // processing in that state. 00299 //" 00300 event = TCP_E_RCV_ACK; // will trigger transition to FIN-WAIT-2 00301 } 00302 00303 if (fsm.getState()==TCP_S_FIN_WAIT_2) 00304 { 00305 //" 00306 // FIN-WAIT-2 STATE 00307 // In addition to the processing for the ESTABLISHED state, if 00308 // the retransmission queue is empty, the user's CLOSE can be 00309 // acknowledged ("ok") but do not delete the TCB. 00310 //" 00311 // nothing to do here (in our model, used commands don't need to be 00312 // acknowledged) 00313 } 00314 00315 if (fsm.getState()==TCP_S_CLOSING) 00316 { 00317 //" 00318 // In addition to the processing for the ESTABLISHED state, if 00319 // the ACK acknowledges our FIN then enter the TIME-WAIT state, 00320 // otherwise ignore the segment. 00321 //" 00322 if (state->fin_ack_rcvd) 00323 { 00324 tcpEV << "Our FIN acked -- can go to TIME_WAIT now\n"; 00325 event = TCP_E_RCV_ACK; // will trigger transition to TIME-WAIT 00326 scheduleTimeout(the2MSLTimer, TCP_TIMEOUT_2MSL); // start timer 00327 00328 // we're entering TIME_WAIT, so we can signal CLOSED the user 00329 // (the only thing left to do is wait until the 2MSL timer expires) 00330 sendIndicationToApp(TCP_I_CLOSED); 00331 } 00332 } 00333 00334 if (fsm.getState()==TCP_S_LAST_ACK) 00335 { 00336 //" 00337 // The only thing that can arrive in this state is an 00338 // acknowledgment of our FIN. If our FIN is now acknowledged, 00339 // delete the TCB, enter the CLOSED state, and return. 00340 //" 00341 if (state->send_fin && tcpseg->getAckNo()==state->snd_fin_seq+1) 00342 { 00343 tcpEV << "Last ACK arrived\n"; 00344 sendIndicationToApp(TCP_I_CLOSED); 00345 return TCP_E_RCV_ACK; // will trigger transition to CLOSED 00346 } 00347 } 00348 00349 if (fsm.getState()==TCP_S_TIME_WAIT) 00350 { 00351 //" 00352 // The only thing that can arrive in this state is a 00353 // retransmission of the remote FIN. Acknowledge it, and restart 00354 // the 2 MSL timeout. 00355 //" 00356 // And we are staying in the TIME_WAIT state. 00357 // 00358 sendAck(); 00359 cancelEvent(the2MSLTimer); 00360 scheduleTimeout(the2MSLTimer, TCP_TIMEOUT_2MSL); 00361 } 00362 00363 // 00364 // RFC 793: sixth, check the URG bit, 00365 // 00366 if (tcpseg->getUrgBit() && (fsm.getState()==TCP_S_ESTABLISHED || fsm.getState()==TCP_S_FIN_WAIT_1 || 00367 fsm.getState()==TCP_S_FIN_WAIT_2)) 00368 { 00369 //" 00370 // If the URG bit is set, RCV.UP <- max(RCV.UP,SEG.UP), and signal 00371 // the user that the remote side has urgent data if the urgent 00372 // pointer (RCV.UP) is in advance of the data consumed. If the 00373 // user has already been signaled (or is still in the "urgent 00374 // mode") for this continuous sequence of urgent data, do not 00375 // signal the user again. 00376 //" 00377 00378 // TBD: URG currently not supported 00379 } 00380 00381 // 00382 // RFC 793: seventh, process the segment text, 00383 // 00384 uint32 old_rcv_nxt = state->rcv_nxt; // if rcv_nxt changes, we need to send/schedule an ACK 00385 if (fsm.getState()==TCP_S_SYN_RCVD || fsm.getState()==TCP_S_ESTABLISHED || fsm.getState()==TCP_S_FIN_WAIT_1 || fsm.getState()==TCP_S_FIN_WAIT_2) 00386 { 00387 //" 00388 // Once in the ESTABLISHED state, it is possible to deliver segment 00389 // text to user RECEIVE buffers. Text from segments can be moved 00390 // into buffers until either the buffer is full or the segment is 00391 // empty. If the segment empties and carries an PUSH flag, then 00392 // the user is informed, when the buffer is returned, that a PUSH 00393 // has been received. 00394 // 00395 // When the TCP takes responsibility for delivering the data to the 00396 // user it must also acknowledge the receipt of the data. 00397 // 00398 // Once the TCP takes responsibility for the data it advances 00399 // RCV.NXT over the data accepted, and adjusts RCV.WND as 00400 // apporopriate to the current buffer availability. The total of 00401 // RCV.NXT and RCV.WND should not be reduced. 00402 // 00403 // Please note the window management suggestions in section 3.7. 00404 // 00405 // Send an acknowledgment of the form: 00406 // 00407 // <SEQ=SND.NXT><ACK=RCV.NXT><CTL=ACK> 00408 // 00409 // This acknowledgment should be piggybacked on a segment being 00410 // transmitted if possible without incurring undue delay. 00411 //" 00412 if (tcpseg->getPayloadLength()>0) 00413 { 00414 tcpEV2 << "Processing segment text in a data transfer state\n"; 00415 00416 // insert into receive buffers. If this segment is contiguous with 00417 // previously received ones (seqNo==rcv_nxt), rcv_nxt can be increased; 00418 // otherwise it stays the same but the data must be cached nevertheless 00419 // (to avoid "Failure to retain above-sequence data" problem, RFC 2525 00420 // section 2.5). 00421 uint32 old_rcv_nxt = state->rcv_nxt; 00422 state->rcv_nxt = receiveQueue->insertBytesFromSegment(tcpseg); 00423 00424 // out-of-order segment? 00425 if (old_rcv_nxt==state->rcv_nxt) 00426 { 00427 // we'll probably want to send an ACK here 00428 tcpAlgorithm->receivedOutOfOrderSegment(); 00429 } 00430 else 00431 { 00432 // forward data to app 00433 // 00434 // FIXME observe PSH bit 00435 // 00436 // FIXME we should implement socket READ command, and pass up only 00437 // as many bytes as requested. rcv_wnd should be decreased 00438 // accordingly! (right now we *always* advertise win=16384, 00439 // that is, there's practically no receiver-imposed flow control!) 00440 // 00441 cPacket *msg; 00442 while ((msg=receiveQueue->extractBytesUpTo(state->rcv_nxt))!=NULL) 00443 { 00444 msg->setKind(TCP_I_DATA); // TBD currently we never send TCP_I_URGENT_DATA 00445 TCPCommand *cmd = new TCPCommand(); 00446 cmd->setConnId(connId); 00447 msg->setControlInfo(cmd); 00448 sendToApp(msg); 00449 } 00450 00451 // if this segment "filled the gap" until the previously arrived segment 00452 // that carried a FIN (i.e.rcv_nxt==rcv_fin_seq), we have to advance 00453 // rcv_nxt over the FIN. 00454 if (state->fin_rcvd && state->rcv_nxt==state->rcv_fin_seq) 00455 { 00456 tcpEV << "All segments arrived up to the FIN segment, advancing rcv_nxt over the FIN\n"; 00457 state->rcv_nxt = state->rcv_fin_seq+1; 00458 sendIndicationToApp(TCP_I_PEER_CLOSED); 00459 } 00460 } 00461 } 00462 } 00463 00464 // 00465 // RFC 793: eighth, check the FIN bit, 00466 // 00467 if (tcpseg->getFinBit()) 00468 { 00469 //" 00470 // If the FIN bit is set, signal the user "connection closing" and 00471 // return any pending RECEIVEs with same message, advance RCV.NXT 00472 // over the FIN, and send an acknowledgment for the FIN. Note that 00473 // FIN implies PUSH for any segment text not yet delivered to the 00474 // user. 00475 //" 00476 00477 // Note: seems like RFC 793 is not entirely correct here: if the 00478 // segment is "above sequence" (ie. RCV.NXT < SEG.SEQ), we cannot 00479 // advance RCV.NXT over the FIN. Instead we remember this sequence 00480 // number and do it later. 00481 uint32 fin_seq = (uint32)tcpseg->getSequenceNo() + (uint32)tcpseg->getPayloadLength(); 00482 if (state->rcv_nxt==fin_seq) 00483 { 00484 // advance rcv_nxt over FIN now 00485 tcpEV << "FIN arrived, advancing rcv_nxt over the FIN\n"; 00486 state->rcv_nxt++; 00487 sendIndicationToApp(TCP_I_PEER_CLOSED); 00488 } 00489 else 00490 { 00491 // we'll have to do it later (when an arriving segment "fills the gap") 00492 tcpEV << "FIN segment above sequence, storing sequence number of FIN\n"; 00493 state->fin_rcvd = true; 00494 state->rcv_fin_seq = fin_seq; 00495 } 00496 00497 // TBD do PUSH stuff 00498 00499 // state transitions will be done in the state machine, here we just set 00500 // the proper event code (TCP_E_RCV_FIN or TCP_E_RCV_FIN_ACK) 00501 event = TCP_E_RCV_FIN; 00502 switch (fsm.getState()) 00503 { 00504 case TCP_S_FIN_WAIT_1: 00505 if (state->fin_ack_rcvd) 00506 { 00507 event = TCP_E_RCV_FIN_ACK; 00508 // start the time-wait timer, turn off the other timers 00509 cancelEvent(finWait2Timer); 00510 scheduleTimeout(the2MSLTimer, TCP_TIMEOUT_2MSL); 00511 00512 // we're entering TIME_WAIT, so we can signal CLOSED the user 00513 // (the only thing left to do is wait until the 2MSL timer expires) 00514 sendIndicationToApp(TCP_I_CLOSED); 00515 } 00516 break; 00517 case TCP_S_FIN_WAIT_2: 00518 // Start the time-wait timer, turn off the other timers. 00519 cancelEvent(finWait2Timer); 00520 scheduleTimeout(the2MSLTimer, TCP_TIMEOUT_2MSL); 00521 00522 // we're entering TIME_WAIT, so we can signal CLOSED the user 00523 // (the only thing left to do is wait until the 2MSL timer expires) 00524 sendIndicationToApp(TCP_I_CLOSED); 00525 break; 00526 case TCP_S_TIME_WAIT: 00527 // Restart the 2 MSL time-wait timeout. 00528 cancelEvent(the2MSLTimer); 00529 scheduleTimeout(the2MSLTimer, TCP_TIMEOUT_2MSL); 00530 break; 00531 } 00532 } 00533 00534 if (old_rcv_nxt!=state->rcv_nxt) 00535 { 00536 // if rcv_nxt changed, either because we received segment text or we 00537 // received a FIN that needs to be acked (or both), we need to send or 00538 // schedule an ACK. 00539 00540 // tcpAlgorithm decides when and how to do ACKs 00541 tcpAlgorithm->receiveSeqChanged(); 00542 } 00543 00544 if ((fsm.getState()==TCP_S_ESTABLISHED || fsm.getState()==TCP_S_SYN_RCVD) && 00545 state->send_fin && state->snd_nxt==state->snd_fin_seq+1) 00546 { 00547 // if the user issued the CLOSE command a long time ago and we've just 00548 // managed to send off FIN, we simulate a CLOSE command now (we had to 00549 // defer it at that time because we still had data in the send queue.) 00550 // This CLOSE will take us into the FIN_WAIT_1 state. 00551 tcpEV << "Now we can do the CLOSE which was deferred a while ago\n"; 00552 event = TCP_E_CLOSE; 00553 } 00554 00555 if (fsm.getState()==TCP_S_CLOSE_WAIT && state->send_fin && 00556 state->snd_nxt==state->snd_fin_seq+1 && old_snd_nxt!=state->snd_nxt) 00557 { 00558 // if we're in CLOSE_WAIT and we just got to sent our long-pending FIN, 00559 // we simulate a CLOSE command now (we had to defer it at that time because 00560 // we still had data in the send queue.) This CLOSE will take us into the 00561 // LAST_ACK state. 00562 tcpEV << "Now we can do the CLOSE which was deferred a while ago\n"; 00563 event = TCP_E_CLOSE; 00564 } 00565 00566 return event; 00567 }
TCPEventCode TCPConnection::processRstInSynReceived | ( | TCPSegment * | tcpseg | ) | [protected, virtual] |
Referenced by processSegment1stThru8th().
00859 { 00860 tcpEV2 << "Processing RST in SYN_RCVD\n"; 00861 00862 //" 00863 // If this connection was initiated with a passive OPEN (i.e., 00864 // came from the LISTEN state), then return this connection to 00865 // LISTEN state and return. The user need not be informed. If 00866 // this connection was initiated with an active OPEN (i.e., came 00867 // from SYN-SENT state) then the connection was refused, signal 00868 // the user "connection refused". In either case, all segments 00869 // on the retransmission queue should be removed. And in the 00870 // active OPEN case, enter the CLOSED state and delete the TCB, 00871 // and return. 00872 //" 00873 00874 sendQueue->discardUpTo(sendQueue->getBufferEndSeq()); // flush send queue 00875 00876 if (state->active) 00877 { 00878 // signal "connection refused" 00879 sendIndicationToApp(TCP_I_CONNECTION_REFUSED); 00880 } 00881 00882 // on RCV_RST, FSM will go either to LISTEN or to CLOSED, depending on state->active 00883 return TCP_E_RCV_RST; 00884 }
bool TCPConnection::processAckInEstabEtc | ( | TCPSegment * | tcpseg | ) | [protected, virtual] |
Referenced by processSegment1stThru8th().
00887 { 00888 tcpEV2 << "Processing ACK in a data transfer state\n"; 00889 00890 // 00891 //" 00892 // If SND.UNA < SEG.ACK =< SND.NXT then, set SND.UNA <- SEG.ACK. 00893 // Any segments on the retransmission queue which are thereby 00894 // entirely acknowledged are removed. Users should receive 00895 // positive acknowledgments for buffers which have been SENT and 00896 // fully acknowledged (i.e., SEND buffer should be returned with 00897 // "ok" response). If the ACK is a duplicate 00898 // (SEG.ACK < SND.UNA), it can be ignored. If the ACK acks 00899 // something not yet sent (SEG.ACK > SND.NXT) then send an ACK, 00900 // drop the segment, and return. 00901 // 00902 // If SND.UNA < SEG.ACK =< SND.NXT, the send window should be 00903 // updated. If (SND.WL1 < SEG.SEQ or (SND.WL1 = SEG.SEQ and 00904 // SND.WL2 =< SEG.ACK)), set SND.WND <- SEG.WND, set 00905 // SND.WL1 <- SEG.SEQ, and set SND.WL2 <- SEG.ACK. 00906 // 00907 // Note that SND.WND is an offset from SND.UNA, that SND.WL1 00908 // records the sequence number of the last segment used to update 00909 // SND.WND, and that SND.WL2 records the acknowledgment number of 00910 // the last segment used to update SND.WND. The check here 00911 // prevents using old segments to update the window. 00912 //" 00913 // Note: should use SND.MAX instead of SND.NXT in above checks 00914 // 00915 if (seqGE(state->snd_una, tcpseg->getAckNo())) 00916 { 00917 // 00918 // duplicate ACK? A received TCP segment is a duplicate ACK if all of 00919 // the following apply: 00920 // (1) snd_una==ackNo 00921 // (2) segment contains no data 00922 // (3) there's unacked data (snd_una!=snd_max) 00923 // 00924 // Note: ssfnet uses additional constraint "window is the same as last 00925 // received (not an update)" -- we don't do that because window updates 00926 // are ignored anyway if neither seqNo nor ackNo has changed. 00927 // 00928 if (state->snd_una==tcpseg->getAckNo() && tcpseg->getPayloadLength()==0 && 00929 state->snd_una!=state->snd_max) 00930 { 00931 state->dupacks++; 00932 tcpAlgorithm->receivedDuplicateAck(); 00933 } 00934 else 00935 { 00936 // if doesn't qualify as duplicate ACK, just ignore it. 00937 if (tcpseg->getPayloadLength()==0) 00938 { 00939 if (state->snd_una!=tcpseg->getAckNo()) 00940 tcpEV << "Old ACK: ackNo<snd_una\n"; 00941 else if (state->snd_una==state->snd_max) 00942 tcpEV << "ACK looks duplicate but we have currently no unacked data (snd_una==snd_max)\n"; 00943 } 00944 00945 // reset counter 00946 state->dupacks = 0; 00947 } 00948 } 00949 else if (seqLE(tcpseg->getAckNo(), state->snd_max)) 00950 { 00951 // ack in window. 00952 uint32 old_snd_una = state->snd_una; 00953 state->snd_una = tcpseg->getAckNo(); 00954 if (unackedVector) unackedVector->record(state->snd_max - state->snd_una); 00955 00956 // after retransmitting a lost segment, we may get an ack well ahead of snd_nxt 00957 if (seqLess(state->snd_nxt, state->snd_una)) 00958 state->snd_nxt = state->snd_una; 00959 00960 uint32 discardUpToSeq = state->snd_una; 00961 00962 // our FIN acked? 00963 if (state->send_fin && tcpseg->getAckNo()==state->snd_fin_seq+1) 00964 { 00965 // set flag that our FIN has been acked 00966 tcpEV << "ACK acks our FIN\n"; 00967 state->fin_ack_rcvd = true; 00968 discardUpToSeq--; // the FIN sequence number is not real data 00969 } 00970 00971 // acked data no longer needed in send queue 00972 sendQueue->discardUpTo(discardUpToSeq); 00973 00974 if (seqLess(state->snd_wl1, tcpseg->getSequenceNo()) || 00975 (state->snd_wl1==tcpseg->getSequenceNo() && seqLE(state->snd_wl2, tcpseg->getAckNo()))) 00976 { 00977 // send window should be updated 00978 tcpEV << "Updating send window from segment: new wnd=" << tcpseg->getWindow() << "\n"; 00979 state->snd_wnd = tcpseg->getWindow(); 00980 state->snd_wl1 = tcpseg->getSequenceNo(); 00981 state->snd_wl2 = tcpseg->getAckNo(); 00982 if (sndWndVector) sndWndVector->record(state->snd_wnd); 00983 } 00984 00985 // notify 00986 tcpAlgorithm->receivedDataAck(old_snd_una); 00987 00988 // in the receivedDataAck we need the old value 00989 state->dupacks = 0; 00990 } 00991 else 00992 { 00993 ASSERT(seqGreater(tcpseg->getAckNo(), state->snd_max)); // from if-ladder 00994 00995 // send an ACK, drop the segment, and return. 00996 tcpAlgorithm->receivedAckForDataNotYetSent(tcpseg->getAckNo()); 00997 state->dupacks = 0; 00998 return false; // means "drop" 00999 } 01000 return true; 01001 }
void TCPConnection::process_TIMEOUT_2MSL | ( | ) | [protected, virtual] |
Referenced by processTimer().
01026 { 01027 //" 01028 // If the time-wait timeout expires on a connection delete the TCB, 01029 // enter the CLOSED state and return. 01030 //" 01031 switch(fsm.getState()) 01032 { 01033 case TCP_S_TIME_WAIT: 01034 // Nothing to do here. The TIMEOUT_2MSL event will automatically take 01035 // the connection to CLOSED. We already notified the user 01036 // (TCP_I_CLOSED) when we entered the TIME_WAIT state from CLOSING, 01037 // FIN_WAIT_1 or FIN_WAIT_2. 01038 break; 01039 default: 01040 // We should not receive this timeout in this state. 01041 opp_error("Internal error: received time-wait (2MSL) timeout in state %s", stateName(fsm.getState())); 01042 } 01043 01044 }
void TCPConnection::process_TIMEOUT_CONN_ESTAB | ( | ) | [protected, virtual] |
Referenced by processTimer().
01006 { 01007 switch(fsm.getState()) 01008 { 01009 case TCP_S_SYN_RCVD: 01010 case TCP_S_SYN_SENT: 01011 // Nothing to do here. TIMEOUT_CONN_ESTAB event will automatically 01012 // take the connection to LISTEN or CLOSED, and cancel SYN-REXMIT timer. 01013 if (state->active) 01014 { 01015 // notify user if we're on the active side 01016 sendIndicationToApp(TCP_I_TIMED_OUT); 01017 } 01018 break; 01019 default: 01020 // We should not receive this timeout in this state. 01021 opp_error("Internal error: received CONN_ESTAB timeout in state %s", stateName(fsm.getState())); 01022 } 01023 }
void TCPConnection::process_TIMEOUT_FIN_WAIT_2 | ( | ) | [protected, virtual] |
Referenced by processTimer().
01047 { 01048 switch(fsm.getState()) 01049 { 01050 case TCP_S_FIN_WAIT_2: 01051 // Nothing to do here. The TIMEOUT_FIN_WAIT_2 event will automatically take 01052 // the connection to CLOSED. 01053 sendIndicationToApp(TCP_I_CLOSED); 01054 break; 01055 default: 01056 // We should not receive this timeout in this state. 01057 opp_error("Internal error: received FIN_WAIT_2 timeout in state %s", stateName(fsm.getState())); 01058 } 01059 }
void TCPConnection::process_TIMEOUT_SYN_REXMIT | ( | TCPEventCode & | event | ) | [protected, virtual] |
Referenced by processTimer().
01072 { 01073 if (++state->syn_rexmit_count>MAX_SYN_REXMIT_COUNT) 01074 { 01075 tcpEV << "Retransmission count during connection setup exceeds " << MAX_SYN_REXMIT_COUNT << ", giving up\n"; 01076 // Note ABORT will take the connection to closed, and cancel CONN-ESTAB timer as well 01077 event = TCP_E_ABORT; 01078 return; 01079 } 01080 01081 tcpEV << "Performing retransmission #" << state->syn_rexmit_count << "\n"; 01082 01083 // resend what's needed 01084 switch(fsm.getState()) 01085 { 01086 case TCP_S_SYN_SENT: sendSyn(); break; 01087 case TCP_S_SYN_RCVD: sendSynAck(); break; 01088 default: opp_error("Internal error: SYN-REXMIT timer expired while in state %s", stateName(fsm.getState())); 01089 } 01090 01091 // reschedule timer 01092 state->syn_rexmit_timeout *= 2; 01093 01094 if (state->syn_rexmit_timeout > TCP_TIMEOUT_SYN_REXMIT_MAX) 01095 state->syn_rexmit_timeout = TCP_TIMEOUT_SYN_REXMIT_MAX; 01096 scheduleTimeout(synRexmitTimer, state->syn_rexmit_timeout); 01097 }
TCPConnection * TCPConnection::cloneListeningConnection | ( | ) | [protected, virtual] |
Utility: clone a listening connection. Used for forking.
Referenced by processSegmentInListen().
00138 { 00139 TCPConnection *conn = new TCPConnection(tcpMain,appGateIndex,connId); 00140 00141 // following code to be kept consistent with initConnection() 00142 const char *sendQueueClass = sendQueue->getClassName(); 00143 conn->sendQueue = check_and_cast<TCPSendQueue *>(createOne(sendQueueClass)); 00144 conn->sendQueue->setConnection(conn); 00145 00146 const char *receiveQueueClass = receiveQueue->getClassName(); 00147 conn->receiveQueue = check_and_cast<TCPReceiveQueue *>(createOne(receiveQueueClass)); 00148 conn->receiveQueue->setConnection(conn); 00149 00150 const char *tcpAlgorithmClass = tcpAlgorithm->getClassName(); 00151 conn->tcpAlgorithm = check_and_cast<TCPAlgorithm *>(createOne(tcpAlgorithmClass)); 00152 conn->tcpAlgorithm->setConnection(conn); 00153 00154 conn->state = conn->tcpAlgorithm->getStateVariables(); 00155 configureStateVariables(); 00156 conn->tcpAlgorithm->initialize(); 00157 00158 // put it into LISTEN, with our localAddr/localPort 00159 conn->state->active = false; 00160 conn->state->fork = true; 00161 conn->localAddr = localAddr; 00162 conn->localPort = localPort; 00163 FSM_Goto(conn->fsm, TCP_S_LISTEN); 00164 00165 return conn; 00166 }
void TCPConnection::initConnection | ( | TCPOpenCommand * | openCmd | ) | [protected, virtual] |
Utility: creates send/receive queues and tcpAlgorithm
Referenced by process_OPEN_ACTIVE(), and process_OPEN_PASSIVE().
00283 { 00284 // create send/receive queues 00285 const char *sendQueueClass = openCmd->getSendQueueClass(); 00286 if (!sendQueueClass || !sendQueueClass[0]) 00287 sendQueueClass = tcpMain->par("sendQueueClass"); 00288 sendQueue = check_and_cast<TCPSendQueue *>(createOne(sendQueueClass)); 00289 sendQueue->setConnection(this); 00290 00291 const char *receiveQueueClass = openCmd->getReceiveQueueClass(); 00292 if (!receiveQueueClass || !receiveQueueClass[0]) 00293 receiveQueueClass = tcpMain->par("receiveQueueClass"); 00294 receiveQueue = check_and_cast<TCPReceiveQueue *>(createOne(receiveQueueClass)); 00295 receiveQueue->setConnection(this); 00296 00297 // create algorithm 00298 const char *tcpAlgorithmClass = openCmd->getTcpAlgorithmClass(); 00299 if (!tcpAlgorithmClass || !tcpAlgorithmClass[0]) 00300 tcpAlgorithmClass = tcpMain->par("tcpAlgorithmClass"); 00301 tcpAlgorithm = check_and_cast<TCPAlgorithm *>(createOne(tcpAlgorithmClass)); 00302 tcpAlgorithm->setConnection(this); 00303 00304 // create state block 00305 state = tcpAlgorithm->getStateVariables(); 00306 configureStateVariables(); 00307 tcpAlgorithm->initialize(); 00308 }
void TCPConnection::configureStateVariables | ( | ) | [protected, virtual] |
Utility: set snd_mss and rcv_wnd in newly created state variables block
Referenced by cloneListeningConnection(), and initConnection().
00311 { 00312 state->snd_mss = tcpMain->par("mss").longValue(); // TODO: mss=-1 should mean autodetect 00313 state->rcv_wnd = tcpMain->par("advertisedWindow").longValue(); 00314 }
void TCPConnection::selectInitialSeqNum | ( | ) | [protected, virtual] |
Utility: generates ISS and initializes corresponding state variables
Referenced by process_OPEN_ACTIVE(), process_SEND(), and processSegmentInListen().
00317 { 00318 // set the initial send sequence number 00319 state->iss = (unsigned long)fmod(SIMTIME_DBL(simTime())*250000.0, 1.0+(double)(unsigned)0xffffffffUL) & 0xffffffffUL; 00320 00321 state->snd_una = state->snd_nxt = state->snd_max = state->iss; 00322 00323 sendQueue->init(state->iss+1); // +1 is for SYN 00324 }
bool TCPConnection::isSegmentAcceptable | ( | TCPSegment * | tcpseg | ) | [protected, virtual] |
Utility: check if segment is acceptable (all bytes are in receive window)
Referenced by processSegment1stThru8th().
00327 { 00328 // check that segment entirely falls in receive window 00329 //FIXME probably not this simple, see old code segAccept() below... 00330 return seqGE(tcpseg->getSequenceNo(),state->rcv_nxt) && 00331 seqLE(tcpseg->getSequenceNo()+tcpseg->getPayloadLength(),state->rcv_nxt+state->rcv_wnd); 00332 }
void TCPConnection::sendSyn | ( | ) | [protected, virtual] |
Utility: send SYN
Referenced by process_OPEN_ACTIVE(), process_SEND(), and process_TIMEOUT_SYN_REXMIT().
00335 { 00336 if (remoteAddr.isUnspecified() || remotePort==-1) 00337 opp_error("Error processing command OPEN_ACTIVE: foreign socket unspecified"); 00338 if (localPort==-1) 00339 opp_error("Error processing command OPEN_ACTIVE: local port unspecified"); 00340 00341 // create segment 00342 TCPSegment *tcpseg = createTCPSegment("SYN"); 00343 tcpseg->setSequenceNo(state->iss); 00344 tcpseg->setSynBit(true); 00345 tcpseg->setWindow(state->rcv_wnd); 00346 00347 state->snd_max = state->snd_nxt = state->iss+1; 00348 00349 // send it 00350 sendToIP(tcpseg); 00351 }
void TCPConnection::sendSynAck | ( | ) | [protected, virtual] |
Utility: send SYN+ACK
Referenced by process_TIMEOUT_SYN_REXMIT(), processSegmentInListen(), and processSegmentInSynSent().
00354 { 00355 // create segment 00356 TCPSegment *tcpseg = createTCPSegment("SYN+ACK"); 00357 tcpseg->setSequenceNo(state->iss); 00358 tcpseg->setAckNo(state->rcv_nxt); 00359 tcpseg->setSynBit(true); 00360 tcpseg->setAckBit(true); 00361 tcpseg->setWindow(state->rcv_wnd); 00362 00363 state->snd_max = state->snd_nxt = state->iss+1; 00364 00365 // send it 00366 sendToIP(tcpseg); 00367 }
void TCPConnection::sendAck | ( | ) | [virtual] |
Utility: send ACK
Referenced by TCPBaseAlg::established(), DumbTCP::established(), TCPBaseAlg::processDelayedAckTimer(), processSegment1stThru8th(), TCPBaseAlg::receivedAckForDataNotYetSent(), DumbTCP::receivedAckForDataNotYetSent(), TCPBaseAlg::receivedOutOfOrderSegment(), DumbTCP::receivedOutOfOrderSegment(), TCPBaseAlg::receiveSeqChanged(), and DumbTCP::receiveSeqChanged().
00405 { 00406 TCPSegment *tcpseg = createTCPSegment("ACK"); 00407 00408 tcpseg->setAckBit(true); 00409 tcpseg->setSequenceNo(state->snd_nxt); 00410 tcpseg->setAckNo(state->rcv_nxt); 00411 tcpseg->setWindow(state->rcv_wnd); 00412 00413 // send it 00414 sendToIP(tcpseg); 00415 00416 // notify 00417 tcpAlgorithm->ackSent(); 00418 }
bool TCPConnection::sendData | ( | bool | fullSegmentsOnly, | |
int | congestionWindow = -1 | |||
) | [virtual] |
Utility: Send data from sendQueue, at most congestionWindow (-1 means no limit). FIXME adjust comment!!! If fullSegmentsOnly is set, don't send segments smaller than MSS (needed for Nagle). Returns true if some data was actually sent.
Referenced by DumbTCP::established(), DumbTCP::receivedDataAck(), DumbTCP::sendCommandInvoked(), and TCPBaseAlg::sendData().
00463 { 00464 // we'll start sending from snd_max 00465 state->snd_nxt = state->snd_max; 00466 00467 // check how many bytes we have 00468 ulong buffered = sendQueue->getBytesAvailable(state->snd_nxt); 00469 if (buffered==0) 00470 return false; 00471 00472 // maxWindow is smaller of (snd_wnd, congestionWindow) 00473 long maxWindow = state->snd_wnd; 00474 if (congestionWindow>=0 && maxWindow > congestionWindow) 00475 maxWindow = congestionWindow; 00476 00477 // effectiveWindow: number of bytes we're allowed to send now 00478 long effectiveWin = maxWindow - (state->snd_nxt - state->snd_una); 00479 if (effectiveWin <= 0) 00480 { 00481 tcpEV << "Effective window is zero (advertised window " << state->snd_wnd << 00482 ", congestion window " << congestionWindow << "), cannot send.\n"; 00483 return false; 00484 } 00485 00486 ulong bytesToSend = effectiveWin; 00487 00488 if (bytesToSend > buffered) 00489 bytesToSend = buffered; 00490 00491 if (fullSegmentsOnly && bytesToSend < state->snd_mss) 00492 { 00493 tcpEV << "Cannot send, not enough data for a full segment (MSS=" << state->snd_mss 00494 << ", in buffer " << buffered << ")\n"; 00495 return false; 00496 } 00497 00498 // start sending 'bytesToSend' bytes 00499 tcpEV << "Will send " << bytesToSend << " bytes (effectiveWindow " << effectiveWin 00500 << ", in buffer " << buffered << " bytes)\n"; 00501 00502 uint32 old_snd_nxt = state->snd_nxt; 00503 ASSERT(bytesToSend>0); 00504 00505 #ifdef TCP_SENDFRAGMENTS /* normally undefined */ 00506 // make agressive use of the window until the last byte 00507 while (bytesToSend>0) 00508 { 00509 ulong bytes = std::min(bytesToSend, state->snd_mss); 00510 sendSegment(bytes); 00511 bytesToSend -= bytes; 00512 } 00513 #else 00514 // send <MSS segments only if it's the only segment we can send now 00515 // FIXME this should probably obey Nagle's alg -- to be checked 00516 if (bytesToSend <= state->snd_mss) 00517 { 00518 sendSegment(bytesToSend); 00519 } 00520 else 00521 { 00522 // send whole segments only 00523 while (bytesToSend>=state->snd_mss) 00524 { 00525 sendSegment(state->snd_mss); 00526 bytesToSend -= state->snd_mss; 00527 } 00528 if (bytesToSend>0) 00529 tcpEV << bytesToSend << " bytes of space left in effectiveWindow\n"; 00530 } 00531 #endif 00532 00533 // remember highest seq sent (snd_nxt may be set back on retransmission, 00534 // but we'll need snd_max to check validity of ACKs -- they must ack 00535 // something we really sent) 00536 state->snd_max = state->snd_nxt; 00537 if (unackedVector) unackedVector->record(state->snd_max - state->snd_una); 00538 00539 // notify (once is enough) 00540 tcpAlgorithm->ackSent(); 00541 tcpAlgorithm->dataSent(old_snd_nxt); 00542 00543 return true; 00544 }
bool TCPConnection::sendProbe | ( | ) | [virtual] |
Utility: sends 1 bytes as "probe", called by the "persist" mechanism
Referenced by TCPBaseAlg::processPersistTimer().
00547 { 00548 // we'll start sending from snd_max 00549 state->snd_nxt = state->snd_max; 00550 00551 // check we have 1 byte to send 00552 if (sendQueue->getBytesAvailable(state->snd_nxt)==0) 00553 { 00554 tcpEV << "Cannot send probe because send buffer is empty\n"; 00555 return false; 00556 } 00557 00558 uint32 old_snd_nxt = state->snd_nxt; 00559 00560 tcpEV << "Sending 1 byte as probe, with seq=" << state->snd_nxt << "\n"; 00561 sendSegment(1); 00562 00563 // remember highest seq sent (snd_nxt may be set back on retransmission, 00564 // but we'll need snd_max to check validity of ACKs -- they must ack 00565 // something we really sent) 00566 state->snd_max = state->snd_nxt; 00567 if (unackedVector) unackedVector->record(state->snd_max - state->snd_una); 00568 00569 // notify 00570 tcpAlgorithm->ackSent(); 00571 tcpAlgorithm->dataSent(old_snd_nxt); 00572 00573 return true; 00574 }
void TCPConnection::retransmitOneSegment | ( | ) | [virtual] |
Utility: retransmit one segment from snd_una
Referenced by TCPTahoe::processRexmitTimer(), TCPNoCongestionControl::processRexmitTimer(), TCPTahoe::receivedDuplicateAck(), and TCPReno::receivedDuplicateAck().
00577 { 00578 // retransmit one segment at snd_una, and set snd_nxt accordingly 00579 state->snd_nxt = state->snd_una; 00580 00581 ulong bytes = std::min(state->snd_mss, state->snd_max - state->snd_nxt); 00582 ASSERT(bytes!=0); 00583 00584 sendSegment(bytes); 00585 00586 // notify 00587 tcpAlgorithm->ackSent(); 00588 }
void TCPConnection::retransmitData | ( | ) | [virtual] |
Utility: retransmit all from snd_una to snd_max
Referenced by TCPReno::processRexmitTimer(), and DumbTCP::processTimer().
00591 { 00592 // retransmit everything from snd_una 00593 state->snd_nxt = state->snd_una; 00594 00595 ulong bytesToSend = state->snd_max - state->snd_nxt; 00596 ASSERT(bytesToSend!=0); 00597 00598 while (bytesToSend>0) 00599 { 00600 ulong bytes = std::min(bytesToSend, (ulong)state->snd_mss); 00601 bytes = std::min(bytes, sendQueue->getBytesAvailable(state->snd_nxt)); 00602 sendSegment(bytes); 00603 // Do not send packets after the FIN. 00604 // fixes bug that occurs in examples/inet/bulktransfer at event #64043 T=13.861159213744 00605 if (state->send_fin && state->snd_nxt==state->snd_fin_seq+1) 00606 break; 00607 bytesToSend -= bytes; 00608 } 00609 }
void TCPConnection::sendRst | ( | uint32 | seqNo | ) | [virtual] |
Utility: sends RST
Referenced by process_ABORT(), processSegment1stThru8th(), processSegmentInListen(), processSegmentInSynSent(), and segmentArrivalWhileClosed().
00370 { 00371 sendRst(seqNo, localAddr, remoteAddr, localPort, remotePort); 00372 }
void TCPConnection::sendRst | ( | uint32 | seq, | |
IPvXAddress | src, | |||
IPvXAddress | dest, | |||
int | srcPort, | |||
int | destPort | |||
) | [virtual] |
Utility: sends RST; does not use connection state
00375 { 00376 TCPSegment *tcpseg = createTCPSegment("RST"); 00377 00378 tcpseg->setSrcPort(srcPort); 00379 tcpseg->setDestPort(destPort); 00380 00381 tcpseg->setRstBit(true); 00382 tcpseg->setSequenceNo(seq); 00383 00384 // send it 00385 sendToIP(tcpseg, src, dest); 00386 }
void TCPConnection::sendRstAck | ( | uint32 | seq, | |
uint32 | ack, | |||
IPvXAddress | src, | |||
IPvXAddress | dest, | |||
int | srcPort, | |||
int | destPort | |||
) | [virtual] |
Utility: sends RST+ACK; does not use connection state
Referenced by segmentArrivalWhileClosed().
00389 { 00390 TCPSegment *tcpseg = createTCPSegment("RST+ACK"); 00391 00392 tcpseg->setSrcPort(srcPort); 00393 tcpseg->setDestPort(destPort); 00394 00395 tcpseg->setRstBit(true); 00396 tcpseg->setAckBit(true); 00397 tcpseg->setSequenceNo(seq); 00398 tcpseg->setAckNo(ack); 00399 00400 // send it 00401 sendToIP(tcpseg, src, dest); 00402 }
void TCPConnection::sendFin | ( | ) | [virtual] |
Utility: sends FIN
Referenced by process_CLOSE().
00421 { 00422 TCPSegment *tcpseg = createTCPSegment("FIN"); 00423 00424 // Note: ACK bit *must* be set for both FIN and FIN+ACK. What makes 00425 // the difference for FIN+ACK is that its ackNo acks the remote TCP's FIN. 00426 tcpseg->setFinBit(true); 00427 tcpseg->setAckBit(true); 00428 tcpseg->setAckNo(state->rcv_nxt); 00429 tcpseg->setSequenceNo(state->snd_nxt); 00430 tcpseg->setWindow(state->rcv_wnd); 00431 00432 // send it 00433 sendToIP(tcpseg); 00434 00435 // notify 00436 tcpAlgorithm->ackSent(); 00437 }
void TCPConnection::sendSegment | ( | int | bytes | ) | [virtual] |
Utility: sends one segment of 'bytes' bytes from snd_nxt, and advances snd_nxt. sendData(), sendProbe() and retransmitData() internally all rely on this one.
Referenced by retransmitData(), retransmitOneSegment(), sendData(), and sendProbe().
00440 { 00441 // send one segment of 'bytes' bytes from snd_nxt, and advance snd_nxt 00442 TCPSegment *tcpseg = sendQueue->createSegmentWithBytes(state->snd_nxt, bytes); 00443 tcpseg->setAckNo(state->rcv_nxt); 00444 tcpseg->setAckBit(true); 00445 tcpseg->setWindow(state->rcv_wnd); 00446 // TBD when to set PSH bit? 00447 // TBD set URG bit if needed 00448 ASSERT(bytes==tcpseg->getPayloadLength()); 00449 00450 state->snd_nxt += bytes; 00451 00452 if (state->send_fin && state->snd_nxt==state->snd_fin_seq) 00453 { 00454 tcpEV << "Setting FIN on segment\n"; 00455 tcpseg->setFinBit(true); 00456 state->snd_nxt = state->snd_fin_seq+1; 00457 } 00458 00459 sendToIP(tcpseg); 00460 }
void TCPConnection::sendToIP | ( | TCPSegment * | tcpseg | ) | [virtual] |
Utility: adds control info to segment and sends it to IP
Referenced by sendAck(), sendFin(), sendRst(), sendRstAck(), sendSegment(), sendSyn(), and sendSynAck().
00169 { 00170 // record seq (only if we do send data) and ackno 00171 if (sndNxtVector && tcpseg->getPayloadLength()!=0) 00172 sndNxtVector->record(tcpseg->getSequenceNo()); 00173 if (sndAckVector) sndAckVector->record(tcpseg->getAckNo()); 00174 00175 // final touches on the segment before sending 00176 tcpseg->setSrcPort(localPort); 00177 tcpseg->setDestPort(remotePort); 00178 tcpseg->setByteLength(TCP_HEADER_OCTETS+tcpseg->getPayloadLength()); 00179 // TBD account for Options (once they get implemented) 00180 00181 tcpEV << "Sending: "; 00182 printSegmentBrief(tcpseg); 00183 00184 // TBD reuse next function for sending 00185 00186 if (!remoteAddr.isIPv6()) 00187 { 00188 // send over IPv4 00189 IPControlInfo *controlInfo = new IPControlInfo(); 00190 controlInfo->setProtocol(IP_PROT_TCP); 00191 controlInfo->setSrcAddr(localAddr.get4()); 00192 controlInfo->setDestAddr(remoteAddr.get4()); 00193 tcpseg->setControlInfo(controlInfo); 00194 00195 tcpMain->send(tcpseg,"ipOut"); 00196 } 00197 else 00198 { 00199 // send over IPv6 00200 IPv6ControlInfo *controlInfo = new IPv6ControlInfo(); 00201 controlInfo->setProtocol(IP_PROT_TCP); 00202 controlInfo->setSrcAddr(localAddr.get6()); 00203 controlInfo->setDestAddr(remoteAddr.get6()); 00204 tcpseg->setControlInfo(controlInfo); 00205 00206 tcpMain->send(tcpseg,"ipv6Out"); 00207 } 00208 }
TCPSegment * TCPConnection::createTCPSegment | ( | const char * | name | ) | [virtual] |
Utility: This factory method gets invoked throughout the TCP model to create a TCPSegment. Override it if you need to subclass TCPSegment.
Referenced by TCPVirtualDataSendQueue::createSegmentWithBytes(), TCPMsgBasedSendQueue::createSegmentWithBytes(), sendAck(), sendFin(), sendRst(), sendRstAck(), sendSyn(), and sendSynAck().
00240 { 00241 return new TCPSegment(name); 00242 }
void TCPConnection::startSynRexmitTimer | ( | ) | [virtual] |
Utility: start SYN-REXMIT timer
Referenced by process_OPEN_ACTIVE(), process_SEND(), processSegmentInListen(), and processSegmentInSynSent().
01062 { 01063 state->syn_rexmit_count = 0; 01064 state->syn_rexmit_timeout = TCP_TIMEOUT_SYN_REXMIT; 01065 01066 if (synRexmitTimer->isScheduled()) 01067 cancelEvent(synRexmitTimer); 01068 scheduleTimeout(synRexmitTimer, state->syn_rexmit_timeout); 01069 }
void TCPConnection::signalConnectionTimeout | ( | ) | [virtual] |
Utility: signal to user that connection timed out
Referenced by TCPBaseAlg::processRexmitTimer().
00245 { 00246 sendIndicationToApp(TCP_I_TIMED_OUT); 00247 }
void TCPConnection::scheduleTimeout | ( | cMessage * | msg, | |
simtime_t | timeout | |||
) | [inline] |
Utility: start a timer
Referenced by DumbTCP::dataSent(), process_OPEN_ACTIVE(), process_SEND(), process_TIMEOUT_SYN_REXMIT(), TCPBaseAlg::processRexmitTimer(), processSegment1stThru8th(), processSegmentInListen(), DumbTCP::processTimer(), TCPBaseAlg::receiveSeqChanged(), TCPBaseAlg::startRexmitTimer(), and startSynRexmitTimer().
00413 {tcpMain->scheduleAt(simTime()+timeout, msg);}
cMessage* TCPConnection::cancelEvent | ( | cMessage * | msg | ) | [inline, protected] |
Utility: cancel a timer
Referenced by processSegment1stThru8th(), startSynRexmitTimer(), stateEntered(), and ~TCPConnection().
00417 {return tcpMain->cancelEvent(msg);}
void TCPConnection::sendToIP | ( | TCPSegment * | tcpseg, | |
IPvXAddress | src, | |||
IPvXAddress | dest | |||
) | [static, protected] |
Utility: send IP packet
00211 { 00212 tcpEV << "Sending: "; 00213 printSegmentBrief(tcpseg); 00214 00215 if (!dest.isIPv6()) 00216 { 00217 // send over IPv4 00218 IPControlInfo *controlInfo = new IPControlInfo(); 00219 controlInfo->setProtocol(IP_PROT_TCP); 00220 controlInfo->setSrcAddr(src.get4()); 00221 controlInfo->setDestAddr(dest.get4()); 00222 tcpseg->setControlInfo(controlInfo); 00223 00224 check_and_cast<TCP *>(simulation.getContextModule())->send(tcpseg,"ipOut"); 00225 } 00226 else 00227 { 00228 // send over IPv6 00229 IPv6ControlInfo *controlInfo = new IPv6ControlInfo(); 00230 controlInfo->setProtocol(IP_PROT_TCP); 00231 controlInfo->setSrcAddr(src.get6()); 00232 controlInfo->setDestAddr(dest.get6()); 00233 tcpseg->setControlInfo(controlInfo); 00234 00235 check_and_cast<TCP *>(simulation.getContextModule())->send(tcpseg,"ipv6Out"); 00236 } 00237 }
void TCPConnection::sendToApp | ( | cMessage * | msg | ) | [protected, virtual] |
Utility: sends packet to application
Referenced by process_STATUS(), and processSegment1stThru8th().
00278 { 00279 tcpMain->send(msg, "appOut", appGateIndex); 00280 }
void TCPConnection::sendIndicationToApp | ( | int | code | ) | [protected, virtual] |
Utility: sends status indication (TCP_I_xxx) to application
Referenced by process_TIMEOUT_CONN_ESTAB(), process_TIMEOUT_FIN_WAIT_2(), processRstInSynReceived(), processSegment1stThru8th(), processSegmentInSynSent(), and signalConnectionTimeout().
00250 { 00251 tcpEV << "Notifying app: " << indicationName(code) << "\n"; 00252 cMessage *msg = new cMessage(indicationName(code)); 00253 msg->setKind(code); 00254 TCPCommand *ind = new TCPCommand(); 00255 ind->setConnId(connId); 00256 msg->setControlInfo(ind); 00257 tcpMain->send(msg, "appOut", appGateIndex); 00258 }
void TCPConnection::sendEstabIndicationToApp | ( | ) | [protected, virtual] |
Utility: sends TCP_I_ESTABLISHED indication with TCPConnectInfo to application
Referenced by processSegment1stThru8th(), and processSegmentInSynSent().
00261 { 00262 tcpEV << "Notifying app: " << indicationName(TCP_I_ESTABLISHED) << "\n"; 00263 cMessage *msg = new cMessage(indicationName(TCP_I_ESTABLISHED)); 00264 msg->setKind(TCP_I_ESTABLISHED); 00265 00266 TCPConnectInfo *ind = new TCPConnectInfo(); 00267 ind->setConnId(connId); 00268 ind->setLocalAddr(localAddr); 00269 ind->setRemoteAddr(remoteAddr); 00270 ind->setLocalPort(localPort); 00271 ind->setRemotePort(remotePort); 00272 00273 msg->setControlInfo(ind); 00274 tcpMain->send(msg, "appOut", appGateIndex); 00275 }
void TCPConnection::printConnBrief | ( | ) | [virtual] |
Utility: prints local/remote addr/port and app gate index/connId
Referenced by processAppCommand(), processTCPSegment(), and processTimer().
00109 { 00110 tcpEV << "Connection "; 00111 tcpEV << localAddr << ":" << localPort << " to " << remoteAddr << ":" << remotePort; 00112 tcpEV << " on app[" << appGateIndex << "],connId=" << connId; 00113 tcpEV << " in " << stateName(fsm.getState()); 00114 tcpEV << " (ptr=0x" << this << ")\n"; 00115 }
void TCPConnection::printSegmentBrief | ( | TCPSegment * | tcpseg | ) | [static] |
Utility: prints important header fields
Referenced by process_RCV_SEGMENT(), segmentArrivalWhileClosed(), and sendToIP().
00118 { 00119 tcpEV << "." << tcpseg->getSrcPort() << " > "; 00120 tcpEV << "." << tcpseg->getDestPort() << ": "; 00121 00122 if (tcpseg->getSynBit()) tcpEV << (tcpseg->getAckBit() ? "SYN+ACK " : "SYN "); 00123 if (tcpseg->getFinBit()) tcpEV << "FIN(+ACK) "; 00124 if (tcpseg->getRstBit()) tcpEV << (tcpseg->getAckBit() ? "RST+ACK " : "RST "); 00125 if (tcpseg->getPshBit()) tcpEV << "PSH "; 00126 00127 if (tcpseg->getPayloadLength()>0 || tcpseg->getSynBit()) 00128 { 00129 tcpEV << tcpseg->getSequenceNo() << ":" << tcpseg->getSequenceNo()+tcpseg->getPayloadLength(); 00130 tcpEV << "(" << tcpseg->getPayloadLength() << ") "; 00131 } 00132 if (tcpseg->getAckBit()) tcpEV << "ack " << tcpseg->getAckNo() << " "; 00133 tcpEV << "win " << tcpseg->getWindow() << "\n"; 00134 if (tcpseg->getUrgBit()) tcpEV << "urg " << tcpseg->getUrgentPointer() << " "; 00135 }
const char * TCPConnection::stateName | ( | int | state | ) | [static] |
Utility: returns name of TCP_S_xxx constants
Referenced by performStateTransition(), printConnBrief(), process_STATUS(), process_TIMEOUT_2MSL(), process_TIMEOUT_CONN_ESTAB(), process_TIMEOUT_FIN_WAIT_2(), and process_TIMEOUT_SYN_REXMIT().
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 }
const char * TCPConnection::eventName | ( | int | event | ) | [static] |
Utility: returns name of TCP_E_xxx constants
Referenced by performStateTransition(), and processAppCommand().
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 }
const char * TCPConnection::indicationName | ( | int | code | ) | [static] |
Utility: returns name of TCP_I_xxx constants
Referenced by sendEstabIndicationToApp(), and sendIndicationToApp().
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::segmentArrivalWhileClosed | ( | TCPSegment * | tcpseg, | |
IPvXAddress | src, | |||
IPvXAddress | dest | |||
) | [virtual] |
This method gets invoked from TCP when a segment arrives which doesn't belong to an existing connection. TCP creates a temporary connection object so that it can call this method, then immediately deletes it.
Referenced by TCP::segmentArrivalWhileClosed().
00036 { 00037 tcpEV << "Seg arrived: "; 00038 printSegmentBrief(tcpseg); 00039 00040 // This segment doesn't belong to any connection, so this object 00041 // must be a temp object created solely for the purpose of calling us 00042 ASSERT(state==NULL); 00043 tcpEV << "Segment doesn't belong to any existing connection\n"; 00044 00045 // RFC 793: 00046 //" 00047 // all data in the incoming segment is discarded. An incoming 00048 // segment containing a RST is discarded. An incoming segment not 00049 // containing a RST causes a RST to be sent in response. The 00050 // acknowledgment and sequence field values are selected to make the 00051 // reset sequence acceptable to the TCP that sent the offending 00052 // segment. 00053 // 00054 // If the ACK bit is off, sequence number zero is used, 00055 // 00056 // <SEQ=0><ACK=SEG.SEQ+SEG.LEN><CTL=RST,ACK> 00057 // 00058 // If the ACK bit is on, 00059 // 00060 // <SEQ=SEG.ACK><CTL=RST> 00061 //" 00062 if (tcpseg->getRstBit()) 00063 { 00064 tcpEV << "RST bit set: dropping segment\n"; 00065 return; 00066 } 00067 00068 if (!tcpseg->getAckBit()) 00069 { 00070 tcpEV << "ACK bit not set: sending RST+ACK\n"; 00071 uint32 ackNo = tcpseg->getSequenceNo() + (uint32)tcpseg->getPayloadLength(); 00072 sendRstAck(0,ackNo,destAddr,srcAddr,tcpseg->getDestPort(),tcpseg->getSrcPort()); 00073 } 00074 else 00075 { 00076 tcpEV << "ACK bit set: sending RST\n"; 00077 sendRst(tcpseg->getAckNo(),destAddr,srcAddr,tcpseg->getDestPort(),tcpseg->getSrcPort()); 00078 } 00079 }
int TCPConnection::getFsmState | ( | ) | const [inline] |
TCPStateVariables* TCPConnection::getState | ( | ) | [inline] |
TCPSendQueue* TCPConnection::getSendQueue | ( | ) | [inline] |
TCPReceiveQueue* TCPConnection::getReceiveQueue | ( | ) | [inline] |
TCPAlgorithm* TCPConnection::getTcpAlgorithm | ( | ) | [inline] |
TCP* TCPConnection::getTcpMain | ( | ) | [inline] |
Referenced by DumbTCP::connectionClosed(), DumbTCP::dataSent(), TCPBaseAlg::initialize(), TCPConnection(), and DumbTCP::~DumbTCP().
00475 {return tcpMain;}
bool TCPConnection::processTimer | ( | cMessage * | msg | ) | [virtual] |
Process self-messages (timers). Normally returns true. A return value of false means that the connection structure must be deleted by the caller (TCP).
Referenced by TCP::handleMessage().
00182 { 00183 printConnBrief(); 00184 tcpEV << msg->getName() << " timer expired\n"; 00185 00186 // first do actions 00187 TCPEventCode event; 00188 if (msg==the2MSLTimer) 00189 { 00190 event = TCP_E_TIMEOUT_2MSL; 00191 process_TIMEOUT_2MSL(); 00192 } 00193 else if (msg==connEstabTimer) 00194 { 00195 event = TCP_E_TIMEOUT_CONN_ESTAB; 00196 process_TIMEOUT_CONN_ESTAB(); 00197 } 00198 else if (msg==finWait2Timer) 00199 { 00200 event = TCP_E_TIMEOUT_FIN_WAIT_2; 00201 process_TIMEOUT_FIN_WAIT_2(); 00202 } 00203 else if (msg==synRexmitTimer) 00204 { 00205 event = TCP_E_IGNORE; 00206 process_TIMEOUT_SYN_REXMIT(event); 00207 } 00208 else 00209 { 00210 event = TCP_E_IGNORE; 00211 tcpAlgorithm->processTimer(msg, event); 00212 } 00213 00214 // then state transitions 00215 return performStateTransition(event); 00216 }
bool TCPConnection::processTCPSegment | ( | TCPSegment * | tcpSeg, | |
IPvXAddress | srcAddr, | |||
IPvXAddress | destAddr | |||
) | [virtual] |
Process incoming TCP segment. Normally returns true. A return value of false means that the connection structure must be deleted by the caller (TCP).
Referenced by TCP::handleMessage().
00219 { 00220 printConnBrief(); 00221 if (!localAddr.isUnspecified()) 00222 { 00223 ASSERT(localAddr==segDestAddr); 00224 ASSERT(localPort==tcpseg->getDestPort()); 00225 } 00226 if (!remoteAddr.isUnspecified()) 00227 { 00228 ASSERT(remoteAddr==segSrcAddr); 00229 ASSERT(remotePort==tcpseg->getSrcPort()); 00230 } 00231 00232 if (tryFastRoute(tcpseg)) 00233 return true; 00234 00235 // first do actions 00236 TCPEventCode event = process_RCV_SEGMENT(tcpseg, segSrcAddr, segDestAddr); 00237 00238 // then state transitions 00239 return performStateTransition(event); 00240 }
bool TCPConnection::processAppCommand | ( | cMessage * | msg | ) | [virtual] |
Process commands from the application. Normally returns true. A return value of false means that the connection structure must be deleted by the caller (TCP).
Referenced by TCP::handleMessage().
00243 { 00244 printConnBrief(); 00245 00246 // first do actions 00247 TCPCommand *tcpCommand = (TCPCommand *)(msg->removeControlInfo()); 00248 TCPEventCode event = preanalyseAppCommandEvent(msg->getKind()); 00249 tcpEV << "App command: " << eventName(event) << "\n"; 00250 switch (event) 00251 { 00252 case TCP_E_OPEN_ACTIVE: process_OPEN_ACTIVE(event, tcpCommand, msg); break; 00253 case TCP_E_OPEN_PASSIVE: process_OPEN_PASSIVE(event, tcpCommand, msg); break; 00254 case TCP_E_SEND: process_SEND(event, tcpCommand, msg); break; 00255 case TCP_E_CLOSE: process_CLOSE(event, tcpCommand, msg); break; 00256 case TCP_E_ABORT: process_ABORT(event, tcpCommand, msg); break; 00257 case TCP_E_STATUS: process_STATUS(event, tcpCommand, msg); break; 00258 default: opp_error("wrong event code"); 00259 } 00260 00261 // then state transitions 00262 return performStateTransition(event); 00263 }
Referenced by TCP::addForkedConnection(), TCP::addSockPair(), cloneListeningConnection(), printConnBrief(), process_OPEN_ACTIVE(), process_OPEN_PASSIVE(), process_STATUS(), processTCPSegment(), TCP::removeConnection(), sendEstabIndicationToApp(), sendRst(), sendSyn(), sendToIP(), TCPConnection(), and TCP::updateSockPair().
TCP* TCPConnection::tcpMain [protected] |
Referenced by cloneListeningConnection(), configureStateVariables(), initConnection(), performStateTransition(), process_OPEN_ACTIVE(), process_OPEN_PASSIVE(), processSegmentInListen(), processSegmentInSynSent(), sendEstabIndicationToApp(), sendIndicationToApp(), sendToApp(), sendToIP(), and TCPConnection().
cFSM TCPConnection::fsm [protected] |
Referenced by cloneListeningConnection(), performStateTransition(), printConnBrief(), process_ABORT(), process_CLOSE(), process_OPEN_ACTIVE(), process_OPEN_PASSIVE(), process_RCV_SEGMENT(), process_SEND(), process_STATUS(), process_TIMEOUT_2MSL(), process_TIMEOUT_CONN_ESTAB(), process_TIMEOUT_FIN_WAIT_2(), process_TIMEOUT_SYN_REXMIT(), processSegment1stThru8th(), and TCPConnection().
TCPStateVariables* TCPConnection::state [protected] |
Referenced by cloneListeningConnection(), configureStateVariables(), initConnection(), isSegmentAcceptable(), performStateTransition(), process_ABORT(), process_CLOSE(), process_OPEN_ACTIVE(), process_OPEN_PASSIVE(), process_RCV_SEGMENT(), process_SEND(), process_STATUS(), process_TIMEOUT_CONN_ESTAB(), process_TIMEOUT_SYN_REXMIT(), processAckInEstabEtc(), processRstInSynReceived(), processSegment1stThru8th(), processSegmentInListen(), processSegmentInSynSent(), retransmitData(), retransmitOneSegment(), segmentArrivalWhileClosed(), selectInitialSeqNum(), sendAck(), sendData(), sendFin(), sendProbe(), sendSegment(), sendSyn(), sendSynAck(), startSynRexmitTimer(), TCPConnection(), and ~TCPConnection().
TCPSendQueue* TCPConnection::sendQueue [protected] |
TCPReceiveQueue* TCPConnection::receiveQueue [protected] |
TCPAlgorithm* TCPConnection::tcpAlgorithm [protected] |
cMessage* TCPConnection::the2MSLTimer [protected] |
Referenced by processSegment1stThru8th(), processTimer(), stateEntered(), TCPConnection(), and ~TCPConnection().
cMessage* TCPConnection::connEstabTimer [protected] |
Referenced by process_OPEN_ACTIVE(), process_SEND(), processSegmentInListen(), processTimer(), stateEntered(), TCPConnection(), and ~TCPConnection().
cMessage* TCPConnection::finWait2Timer [protected] |
Referenced by processSegment1stThru8th(), processTimer(), stateEntered(), TCPConnection(), and ~TCPConnection().
cMessage* TCPConnection::synRexmitTimer [protected] |
Referenced by process_TIMEOUT_SYN_REXMIT(), processTimer(), startSynRexmitTimer(), stateEntered(), TCPConnection(), and ~TCPConnection().
cOutVector* TCPConnection::sndWndVector [protected] |
Referenced by processAckInEstabEtc(), processSegmentInListen(), processSegmentInSynSent(), TCPConnection(), and ~TCPConnection().
cOutVector* TCPConnection::sndNxtVector [protected] |
Referenced by sendToIP(), TCPConnection(), and ~TCPConnection().
cOutVector* TCPConnection::sndAckVector [protected] |
Referenced by sendToIP(), TCPConnection(), and ~TCPConnection().
cOutVector* TCPConnection::rcvSeqVector [protected] |
Referenced by process_RCV_SEGMENT(), TCPConnection(), and ~TCPConnection().
cOutVector* TCPConnection::rcvAckVector [protected] |
Referenced by process_RCV_SEGMENT(), TCPConnection(), and ~TCPConnection().
cOutVector* TCPConnection::unackedVector [protected] |
Referenced by process_CLOSE(), processAckInEstabEtc(), sendData(), sendProbe(), TCPConnection(), and ~TCPConnection().