|
INET Framework for OMNeT++/OMNEST
|
00001 // 00002 // Copyright (C) 2004 Andras Varga 00003 // 00004 // This program is free software; you can redistribute it and/or 00005 // modify it under the terms of the GNU Lesser General Public License 00006 // as published by the Free Software Foundation; either version 2 00007 // of the License, or (at your option) any later version. 00008 // 00009 // This program is distributed in the hope that it will be useful, 00010 // but WITHOUT ANY WARRANTY; without even the implied warranty of 00011 // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 00012 // GNU Lesser General Public License for more details. 00013 // 00014 // You should have received a copy of the GNU Lesser General Public License 00015 // along with this program; if not, see <http://www.gnu.org/licenses/>. 00016 // 00017 00018 00019 #include <string.h> 00020 #include <assert.h> 00021 #include "TCP_old.h" 00022 #include "TCPConnection_old.h" 00023 #include "TCPSegment.h" 00024 #include "TCPCommand_m.h" 00025 #include "TCPSendQueue_old.h" 00026 #include "TCPReceiveQueue_old.h" 00027 #include "TCPAlgorithm_old.h" 00028 00029 using namespace tcp_old; 00030 00031 TCPStateVariables::TCPStateVariables() 00032 { 00033 // set everything to 0 -- real init values will be set manually 00034 active = false; 00035 fork = false; 00036 snd_mss = -1; // will be set from configureStateVariables() 00037 snd_una = 0; 00038 snd_nxt = 0; 00039 snd_max = 0; 00040 snd_wnd = 0; 00041 snd_up = 0; 00042 snd_wl1 = 0; 00043 snd_wl2 = 0; 00044 iss = 0; 00045 rcv_nxt = 0; 00046 rcv_wnd = -1; // will be set from configureStateVariables() 00047 rcv_up = 0; 00048 irs = 0; 00049 00050 dupacks = 0; 00051 00052 syn_rexmit_count = 0; 00053 syn_rexmit_timeout = 0; 00054 00055 fin_ack_rcvd = false; 00056 send_fin = false; 00057 snd_fin_seq = 0; 00058 fin_rcvd = false; 00059 rcv_fin_seq = 0; 00060 afterRto = false; 00061 00062 last_ack_sent = 0; 00063 } 00064 00065 std::string TCPStateVariables::info() const 00066 { 00067 std::stringstream out; 00068 out << "snd_una=" << snd_una; 00069 out << " snd_nxt=" << snd_nxt; 00070 out << " snd_max=" << snd_max; 00071 out << " snd_wnd=" << snd_wnd; 00072 out << " rcv_nxt=" << rcv_nxt; 00073 out << " rcv_wnd=" << rcv_wnd; 00074 return out.str(); 00075 } 00076 00077 std::string TCPStateVariables::detailedInfo() const 00078 { 00079 std::stringstream out; 00080 out << "active = " << active << "\n"; 00081 out << "snd_mss = " << snd_mss << "\n"; 00082 out << "snd_una = " << snd_una << "\n"; 00083 out << "snd_nxt = " << snd_nxt << "\n"; 00084 out << "snd_max = " << snd_max << "\n"; 00085 out << "snd_wnd = " << snd_wnd << "\n"; 00086 out << "snd_up = " << snd_up << "\n"; 00087 out << "snd_wl1 = " << snd_wl1 << "\n"; 00088 out << "snd_wl2 = " << snd_wl2 << "\n"; 00089 out << "iss = " << iss << "\n"; 00090 out << "rcv_nxt = " << rcv_nxt << "\n"; 00091 out << "rcv_wnd = " << rcv_wnd << "\n"; 00092 out << "rcv_up = " << rcv_up << "\n"; 00093 out << "irs = " << irs << "\n"; 00094 out << "fin_ack_rcvd = " << fin_ack_rcvd << "\n"; 00095 return out.str(); 00096 } 00097 00098 TCPConnection::TCPConnection() 00099 { 00100 // Note: this ctor is NOT used to create live connections, only 00101 // temporary ones to invoke segmentArrivalWhileClosed() on 00102 sendQueue = NULL; 00103 receiveQueue = NULL; 00104 tcpAlgorithm = NULL; 00105 state = NULL; 00106 the2MSLTimer = connEstabTimer = finWait2Timer = synRexmitTimer = NULL; 00107 sndWndVector = sndNxtVector = sndAckVector = rcvSeqVector = rcvAckVector = unackedVector = NULL; 00108 } 00109 00110 // 00111 // FSM framework, TCP FSM 00112 // 00113 00114 TCPConnection::TCPConnection(TCP *_mod, int _appGateIndex, int _connId) 00115 { 00116 tcpMain = _mod; 00117 appGateIndex = _appGateIndex; 00118 connId = _connId; 00119 00120 localPort = remotePort = -1; 00121 00122 char fsmname[24]; 00123 sprintf(fsmname, "fsm-%d", connId); 00124 fsm.setName(fsmname); 00125 fsm.setState(TCP_S_INIT); 00126 00127 00128 // queues and algorithm will be created on active or passive open 00129 sendQueue = NULL; 00130 receiveQueue = NULL; 00131 tcpAlgorithm = NULL; 00132 state = NULL; 00133 00134 the2MSLTimer = new cMessage("2MSL"); 00135 connEstabTimer = new cMessage("CONN-ESTAB"); 00136 finWait2Timer = new cMessage("FIN-WAIT-2"); 00137 synRexmitTimer = new cMessage("SYN-REXMIT"); 00138 00139 the2MSLTimer->setContextPointer(this); 00140 connEstabTimer->setContextPointer(this); 00141 finWait2Timer->setContextPointer(this); 00142 synRexmitTimer->setContextPointer(this); 00143 00144 // statistics 00145 sndWndVector = NULL; 00146 sndNxtVector = NULL; 00147 sndAckVector = NULL; 00148 rcvSeqVector = NULL; 00149 rcvAckVector = NULL; 00150 unackedVector = NULL; 00151 00152 if (getTcpMain()->recordStatistics) 00153 { 00154 sndWndVector = new cOutVector("send window"); 00155 sndNxtVector = new cOutVector("send seq"); 00156 sndAckVector = new cOutVector("sent ack"); 00157 rcvSeqVector = new cOutVector("rcvd seq"); 00158 rcvAckVector = new cOutVector("rcvd ack"); 00159 unackedVector = new cOutVector("unacked bytes"); 00160 } 00161 } 00162 00163 TCPConnection::~TCPConnection() 00164 { 00165 delete sendQueue; 00166 delete receiveQueue; 00167 delete tcpAlgorithm; 00168 delete state; 00169 00170 if (the2MSLTimer) delete cancelEvent(the2MSLTimer); 00171 if (connEstabTimer) delete cancelEvent(connEstabTimer); 00172 if (finWait2Timer) delete cancelEvent(finWait2Timer); 00173 if (synRexmitTimer) delete cancelEvent(synRexmitTimer); 00174 00175 // statistics 00176 delete sndWndVector; 00177 delete sndNxtVector; 00178 delete sndAckVector; 00179 delete rcvSeqVector; 00180 delete rcvAckVector; 00181 delete unackedVector; 00182 } 00183 00184 bool TCPConnection::processTimer(cMessage *msg) 00185 { 00186 printConnBrief(); 00187 tcpEV << msg->getName() << " timer expired\n"; 00188 00189 // first do actions 00190 TCPEventCode event; 00191 if (msg==the2MSLTimer) 00192 { 00193 event = TCP_E_TIMEOUT_2MSL; 00194 process_TIMEOUT_2MSL(); 00195 } 00196 else if (msg==connEstabTimer) 00197 { 00198 event = TCP_E_TIMEOUT_CONN_ESTAB; 00199 process_TIMEOUT_CONN_ESTAB(); 00200 } 00201 else if (msg==finWait2Timer) 00202 { 00203 event = TCP_E_TIMEOUT_FIN_WAIT_2; 00204 process_TIMEOUT_FIN_WAIT_2(); 00205 } 00206 else if (msg==synRexmitTimer) 00207 { 00208 event = TCP_E_IGNORE; 00209 process_TIMEOUT_SYN_REXMIT(event); 00210 } 00211 else 00212 { 00213 event = TCP_E_IGNORE; 00214 tcpAlgorithm->processTimer(msg, event); 00215 } 00216 00217 // then state transitions 00218 return performStateTransition(event); 00219 } 00220 00221 bool TCPConnection::processTCPSegment(TCPSegment *tcpseg, IPvXAddress segSrcAddr, IPvXAddress segDestAddr) 00222 { 00223 printConnBrief(); 00224 if (!localAddr.isUnspecified()) 00225 { 00226 ASSERT(localAddr==segDestAddr); 00227 ASSERT(localPort==tcpseg->getDestPort()); 00228 } 00229 if (!remoteAddr.isUnspecified()) 00230 { 00231 ASSERT(remoteAddr==segSrcAddr); 00232 ASSERT(remotePort==tcpseg->getSrcPort()); 00233 } 00234 00235 if (tryFastRoute(tcpseg)) 00236 return true; 00237 00238 // first do actions 00239 TCPEventCode event = process_RCV_SEGMENT(tcpseg, segSrcAddr, segDestAddr); 00240 00241 // then state transitions 00242 return performStateTransition(event); 00243 } 00244 00245 bool TCPConnection::processAppCommand(cMessage *msg) 00246 { 00247 printConnBrief(); 00248 00249 // first do actions 00250 TCPCommand *tcpCommand = (TCPCommand *)(msg->removeControlInfo()); 00251 TCPEventCode event = preanalyseAppCommandEvent(msg->getKind()); 00252 tcpEV << "App command: " << eventName(event) << "\n"; 00253 switch (event) 00254 { 00255 case TCP_E_OPEN_ACTIVE: process_OPEN_ACTIVE(event, tcpCommand, msg); break; 00256 case TCP_E_OPEN_PASSIVE: process_OPEN_PASSIVE(event, tcpCommand, msg); break; 00257 case TCP_E_SEND: process_SEND(event, tcpCommand, msg); break; 00258 case TCP_E_CLOSE: process_CLOSE(event, tcpCommand, msg); break; 00259 case TCP_E_ABORT: process_ABORT(event, tcpCommand, msg); break; 00260 case TCP_E_STATUS: process_STATUS(event, tcpCommand, msg); break; 00261 default: opp_error("wrong event code"); 00262 } 00263 00264 // then state transitions 00265 return performStateTransition(event); 00266 } 00267 00268 00269 TCPEventCode TCPConnection::preanalyseAppCommandEvent(int commandCode) 00270 { 00271 switch (commandCode) 00272 { 00273 case TCP_C_OPEN_ACTIVE: return TCP_E_OPEN_ACTIVE; 00274 case TCP_C_OPEN_PASSIVE: return TCP_E_OPEN_PASSIVE; 00275 case TCP_C_SEND: return TCP_E_SEND; 00276 case TCP_C_CLOSE: return TCP_E_CLOSE; 00277 case TCP_C_ABORT: return TCP_E_ABORT; 00278 case TCP_C_STATUS: return TCP_E_STATUS; 00279 default: opp_error("Unknown message kind in app command"); 00280 return (TCPEventCode)0; // to satisfy compiler 00281 } 00282 } 00283 00284 bool TCPConnection::performStateTransition(const TCPEventCode& event) 00285 { 00286 ASSERT(fsm.getState()!=TCP_S_CLOSED); // closed connections should be deleted immediately 00287 00288 if (event==TCP_E_IGNORE) // e.g. discarded segment 00289 { 00290 tcpEV << "Staying in state: " << stateName(fsm.getState()) << " (no FSM event)\n"; 00291 return true; 00292 } 00293 00294 // state machine 00295 // TBD add handling of connection timeout event (keepalive), with transition to CLOSED 00296 // Note: empty "default:" lines are for gcc's benefit which would otherwise spit warnings 00297 int oldState = fsm.getState(); 00298 switch (fsm.getState()) 00299 { 00300 case TCP_S_INIT: 00301 switch (event) 00302 { 00303 case TCP_E_OPEN_PASSIVE:FSM_Goto(fsm, TCP_S_LISTEN); break; 00304 case TCP_E_OPEN_ACTIVE: FSM_Goto(fsm, TCP_S_SYN_SENT); break; 00305 default:; 00306 } 00307 break; 00308 00309 case TCP_S_LISTEN: 00310 switch (event) 00311 { 00312 case TCP_E_OPEN_ACTIVE: FSM_Goto(fsm, TCP_S_SYN_SENT); break; 00313 case TCP_E_SEND: FSM_Goto(fsm, TCP_S_SYN_SENT); break; 00314 case TCP_E_CLOSE: FSM_Goto(fsm, TCP_S_CLOSED); break; 00315 case TCP_E_ABORT: FSM_Goto(fsm, TCP_S_CLOSED); break; 00316 case TCP_E_RCV_SYN: FSM_Goto(fsm, TCP_S_SYN_RCVD);break; 00317 default:; 00318 } 00319 break; 00320 00321 case TCP_S_SYN_RCVD: 00322 switch (event) 00323 { 00324 case TCP_E_CLOSE: FSM_Goto(fsm, TCP_S_FIN_WAIT_1); break; 00325 case TCP_E_ABORT: FSM_Goto(fsm, TCP_S_CLOSED); break; 00326 case TCP_E_TIMEOUT_CONN_ESTAB: FSM_Goto(fsm, state->active ? TCP_S_CLOSED : TCP_S_LISTEN); break; 00327 case TCP_E_RCV_RST: FSM_Goto(fsm, state->active ? TCP_S_CLOSED : TCP_S_LISTEN); break; 00328 case TCP_E_RCV_ACK: FSM_Goto(fsm, TCP_S_ESTABLISHED); break; 00329 case TCP_E_RCV_FIN: FSM_Goto(fsm, TCP_S_CLOSE_WAIT); break; 00330 case TCP_E_RCV_UNEXP_SYN: FSM_Goto(fsm, TCP_S_CLOSED); break; 00331 default:; 00332 } 00333 break; 00334 00335 case TCP_S_SYN_SENT: 00336 switch (event) 00337 { 00338 case TCP_E_CLOSE: FSM_Goto(fsm, TCP_S_CLOSED); break; 00339 case TCP_E_ABORT: FSM_Goto(fsm, TCP_S_CLOSED); break; 00340 case TCP_E_TIMEOUT_CONN_ESTAB: FSM_Goto(fsm, TCP_S_CLOSED); break; 00341 case TCP_E_RCV_RST: FSM_Goto(fsm, TCP_S_CLOSED); break; 00342 case TCP_E_RCV_SYN_ACK: FSM_Goto(fsm, TCP_S_ESTABLISHED); break; 00343 case TCP_E_RCV_SYN: FSM_Goto(fsm, TCP_S_SYN_RCVD); break; 00344 default:; 00345 } 00346 break; 00347 00348 case TCP_S_ESTABLISHED: 00349 switch (event) 00350 { 00351 case TCP_E_CLOSE: FSM_Goto(fsm, TCP_S_FIN_WAIT_1); break; 00352 case TCP_E_ABORT: FSM_Goto(fsm, TCP_S_CLOSED); break; 00353 case TCP_E_RCV_FIN: FSM_Goto(fsm, TCP_S_CLOSE_WAIT); break; 00354 case TCP_E_RCV_RST: FSM_Goto(fsm, TCP_S_CLOSED); break; 00355 case TCP_E_RCV_UNEXP_SYN: FSM_Goto(fsm, TCP_S_CLOSED); break; 00356 default:; 00357 } 00358 break; 00359 00360 case TCP_S_CLOSE_WAIT: 00361 switch (event) 00362 { 00363 case TCP_E_CLOSE: FSM_Goto(fsm, TCP_S_LAST_ACK); break; 00364 case TCP_E_ABORT: FSM_Goto(fsm, TCP_S_CLOSED); break; 00365 case TCP_E_RCV_RST: FSM_Goto(fsm, TCP_S_CLOSED); break; 00366 case TCP_E_RCV_UNEXP_SYN: FSM_Goto(fsm, TCP_S_CLOSED); break; 00367 default:; 00368 } 00369 break; 00370 00371 case TCP_S_LAST_ACK: 00372 switch (event) 00373 { 00374 case TCP_E_ABORT: FSM_Goto(fsm, TCP_S_CLOSED); break; 00375 case TCP_E_RCV_ACK: FSM_Goto(fsm, TCP_S_CLOSED); 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_1: 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_CLOSING); break; 00387 case TCP_E_RCV_ACK: FSM_Goto(fsm, TCP_S_FIN_WAIT_2); break; 00388 case TCP_E_RCV_FIN_ACK: FSM_Goto(fsm, TCP_S_TIME_WAIT); break; 00389 case TCP_E_RCV_RST: FSM_Goto(fsm, TCP_S_CLOSED); break; 00390 case TCP_E_RCV_UNEXP_SYN: FSM_Goto(fsm, TCP_S_CLOSED); break; 00391 default:; 00392 } 00393 break; 00394 00395 case TCP_S_FIN_WAIT_2: 00396 switch (event) 00397 { 00398 case TCP_E_ABORT: FSM_Goto(fsm, TCP_S_CLOSED); break; 00399 case TCP_E_RCV_FIN: FSM_Goto(fsm, TCP_S_TIME_WAIT); break; 00400 case TCP_E_TIMEOUT_FIN_WAIT_2: FSM_Goto(fsm, TCP_S_CLOSED); break; 00401 case TCP_E_RCV_RST: FSM_Goto(fsm, TCP_S_CLOSED); break; 00402 case TCP_E_RCV_UNEXP_SYN: FSM_Goto(fsm, TCP_S_CLOSED); break; 00403 default:; 00404 } 00405 break; 00406 00407 case TCP_S_CLOSING: 00408 switch (event) 00409 { 00410 case TCP_E_ABORT: FSM_Goto(fsm, TCP_S_CLOSED); break; 00411 case TCP_E_RCV_ACK: FSM_Goto(fsm, TCP_S_TIME_WAIT); break; 00412 case TCP_E_RCV_RST: FSM_Goto(fsm, TCP_S_CLOSED); break; 00413 case TCP_E_RCV_UNEXP_SYN: FSM_Goto(fsm, TCP_S_CLOSED); break; 00414 default:; 00415 } 00416 break; 00417 00418 case TCP_S_TIME_WAIT: 00419 switch (event) 00420 { 00421 case TCP_E_ABORT: FSM_Goto(fsm, TCP_S_CLOSED); break; 00422 case TCP_E_TIMEOUT_2MSL: FSM_Goto(fsm, TCP_S_CLOSED); break; 00423 case TCP_E_RCV_RST: FSM_Goto(fsm, TCP_S_CLOSED); break; 00424 case TCP_E_RCV_UNEXP_SYN: FSM_Goto(fsm, TCP_S_CLOSED); break; 00425 default:; 00426 } 00427 break; 00428 00429 case TCP_S_CLOSED: 00430 break; 00431 } 00432 00433 if (oldState!=fsm.getState()) 00434 { 00435 tcpEV << "Transition: " << stateName(oldState) << " --> " << stateName(fsm.getState()) << " (event was: " << eventName(event) << ")\n"; 00436 testingEV << tcpMain->getName() << ": " << stateName(oldState) << " --> " << stateName(fsm.getState()) << " (on " << eventName(event) << ")\n"; 00437 00438 // cancel timers, etc. 00439 stateEntered(fsm.getState()); 00440 } 00441 else 00442 { 00443 tcpEV << "Staying in state: " << stateName(fsm.getState()) << " (event was: " << eventName(event) << ")\n"; 00444 } 00445 00446 return fsm.getState()!=TCP_S_CLOSED; 00447 } 00448 00449 void TCPConnection::stateEntered(int state) 00450 { 00451 // cancel timers 00452 switch (state) 00453 { 00454 case TCP_S_INIT: 00455 // we'll never get back to INIT 00456 break; 00457 case TCP_S_LISTEN: 00458 // we may get back to LISTEN from SYN_RCVD 00459 ASSERT(connEstabTimer && synRexmitTimer); 00460 cancelEvent(connEstabTimer); 00461 cancelEvent(synRexmitTimer); 00462 break; 00463 case TCP_S_SYN_RCVD: 00464 case TCP_S_SYN_SENT: 00465 break; 00466 case TCP_S_ESTABLISHED: 00467 // we're in ESTABLISHED, these timers are no longer needed 00468 delete cancelEvent(connEstabTimer); 00469 delete cancelEvent(synRexmitTimer); 00470 connEstabTimer = synRexmitTimer = NULL; 00471 // TCP_I_ESTAB notification moved inside event processing 00472 break; 00473 case TCP_S_CLOSE_WAIT: 00474 case TCP_S_LAST_ACK: 00475 case TCP_S_FIN_WAIT_1: 00476 case TCP_S_FIN_WAIT_2: 00477 case TCP_S_CLOSING: 00478 case TCP_S_TIME_WAIT: 00479 // whether connection setup succeeded (ESTABLISHED) or not (others), 00480 // cancel these timers 00481 if (connEstabTimer) cancelEvent(connEstabTimer); 00482 if (synRexmitTimer) cancelEvent(synRexmitTimer); 00483 break; 00484 case TCP_S_CLOSED: 00485 // all timers need to be cancelled 00486 if (the2MSLTimer) cancelEvent(the2MSLTimer); 00487 if (connEstabTimer) cancelEvent(connEstabTimer); 00488 if (finWait2Timer) cancelEvent(finWait2Timer); 00489 if (synRexmitTimer) cancelEvent(synRexmitTimer); 00490 tcpAlgorithm->connectionClosed(); 00491 break; 00492 } 00493 } 00494 00495