old/TCPConnectionBase.cc

Go to the documentation of this file.
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