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