old/TCPConnectionEventProc.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 "TCP_old.h"
00021 #include "TCPConnection_old.h"
00022 #include "TCPSegment.h"
00023 #include "TCPCommand_m.h"
00024 #include "TCPSendQueue_old.h"
00025 #include "TCPReceiveQueue_old.h"
00026 #include "TCPAlgorithm_old.h"
00027 
00028 using namespace tcp_old;
00029 
00030 //
00031 // Event processing code
00032 //
00033 
00034 void TCPConnection::process_OPEN_ACTIVE(TCPEventCode& event, TCPCommand *tcpCommand, cMessage *msg)
00035 {
00036     TCPOpenCommand *openCmd = check_and_cast<TCPOpenCommand *>(tcpCommand);
00037     IPvXAddress localAddr, remoteAddr;
00038     int localPort, remotePort;
00039 
00040     switch(fsm.getState())
00041     {
00042         case TCP_S_INIT:
00043             initConnection(openCmd);
00044 
00045             // store local/remote socket
00046             state->active = true;
00047             localAddr = openCmd->getLocalAddr();
00048             remoteAddr = openCmd->getRemoteAddr();
00049             localPort = openCmd->getLocalPort();
00050             remotePort = openCmd->getRemotePort();
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 }
00079 
00080 void TCPConnection::process_OPEN_PASSIVE(TCPEventCode& event, TCPCommand *tcpCommand, cMessage *msg)
00081 {
00082     TCPOpenCommand *openCmd = check_and_cast<TCPOpenCommand *>(tcpCommand);
00083     IPvXAddress localAddr;
00084     int localPort;
00085 
00086     switch(fsm.getState())
00087     {
00088         case TCP_S_INIT:
00089             initConnection(openCmd);
00090 
00091             // store local/remote socket
00092             state->active = false;
00093             state->fork = openCmd->getFork();
00094             localAddr = openCmd->getLocalAddr();
00095             localPort = openCmd->getLocalPort();
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 }
00112 
00113 void TCPConnection::process_SEND(TCPEventCode& event, TCPCommand *tcpCommand, cMessage *msg)
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.getState())
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(PK(msg));  // queue up for later
00132             tcpEV << sendQueue->getBytesAvailable(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(PK(msg)); // queue up for later
00139             tcpEV << sendQueue->getBytesAvailable(state->snd_una) << " bytes in queue\n";
00140             break;
00141 
00142         case TCP_S_ESTABLISHED:
00143         case TCP_S_CLOSE_WAIT:
00144             sendQueue->enqueueAppData(PK(msg));
00145             tcpEV << sendQueue->getBytesAvailable(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 }
00160 
00161 void TCPConnection::process_CLOSE(TCPEventCode& event, TCPCommand *tcpCommand, cMessage *msg)
00162 {
00163     delete tcpCommand;
00164     delete msg;
00165 
00166     switch(fsm.getState())
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->getBufferEndSeq())
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                 tcpAlgorithm->restartRexmitTimer();
00196                 state->snd_max = ++state->snd_nxt;
00197                 if (unackedVector) unackedVector->record(state->snd_max - state->snd_una);
00198 
00199                 // state transition will automatically take us to FIN_WAIT_1 (or LAST_ACK)
00200             }
00201             else
00202             {
00203                 tcpEV << "SEND of " << (sendQueue->getBufferEndSeq()-state->snd_max) <<
00204                       " bytes pending, deferring sending of FIN\n";
00205                 event = TCP_E_IGNORE;
00206             }
00207             state->send_fin = true;
00208             state->snd_fin_seq = sendQueue->getBufferEndSeq();
00209             break;
00210 
00211         case TCP_S_FIN_WAIT_1:
00212         case TCP_S_FIN_WAIT_2:
00213         case TCP_S_CLOSING:
00214         case TCP_S_LAST_ACK:
00215         case TCP_S_TIME_WAIT:
00216             // RFC 793 is not entirely clear on how to handle a duplicate close request.
00217             // Here we treat it as an error.
00218             opp_error("Duplicate CLOSE command: connection already closing");
00219     }
00220 }
00221 
00222 void TCPConnection::process_ABORT(TCPEventCode& event, TCPCommand *tcpCommand, cMessage *msg)
00223 {
00224     delete tcpCommand;
00225     delete msg;
00226 
00227     //
00228     // The ABORT event will automatically take the connection to the CLOSED
00229     // state, flush queues etc -- no need to do it here. Also, we don't need to
00230     // send notification to the user, they know what's going on.
00231     //
00232     switch(fsm.getState())
00233     {
00234         case TCP_S_INIT:
00235             opp_error("Error processing command ABORT: connection not open");
00236 
00237         case TCP_S_SYN_RCVD:
00238         case TCP_S_ESTABLISHED:
00239         case TCP_S_FIN_WAIT_1:
00240         case TCP_S_FIN_WAIT_2:
00241         case TCP_S_CLOSE_WAIT:
00242             //"
00243             // Send a reset segment:
00244             //
00245             //   <SEQ=SND.NXT><CTL=RST>
00246             //"
00247             sendRst(state->snd_nxt);
00248             break;
00249     }
00250 
00251 }
00252 
00253 void TCPConnection::process_STATUS(TCPEventCode& event, TCPCommand *tcpCommand, cMessage *msg)
00254 {
00255     delete tcpCommand; // but reuse msg for reply
00256 
00257     if (fsm.getState()==TCP_S_INIT)
00258         opp_error("Error processing command STATUS: connection not open");
00259 
00260     TCPStatusInfo *statusInfo = new TCPStatusInfo();
00261 
00262     statusInfo->setState(fsm.getState());
00263     statusInfo->setStateName(stateName(fsm.getState()));
00264 
00265     statusInfo->setLocalAddr(localAddr);
00266     statusInfo->setRemoteAddr(remoteAddr);
00267     statusInfo->setLocalPort(localPort);
00268     statusInfo->setRemotePort(remotePort);
00269 
00270     statusInfo->setSnd_mss(state->snd_mss);
00271     statusInfo->setSnd_una(state->snd_una);
00272     statusInfo->setSnd_nxt(state->snd_nxt);
00273     statusInfo->setSnd_max(state->snd_max);
00274     statusInfo->setSnd_wnd(state->snd_wnd);
00275     statusInfo->setSnd_up(state->snd_up);
00276     statusInfo->setSnd_wl1(state->snd_wl1);
00277     statusInfo->setSnd_wl2(state->snd_wl2);
00278     statusInfo->setIss(state->iss);
00279     statusInfo->setRcv_nxt(state->rcv_nxt);
00280     statusInfo->setRcv_wnd(state->rcv_wnd);
00281     statusInfo->setRcv_up(state->rcv_up);
00282     statusInfo->setIrs(state->irs);
00283     statusInfo->setFin_ack_rcvd(state->fin_ack_rcvd);
00284 
00285     msg->setControlInfo(statusInfo);
00286     sendToApp(msg);
00287 }
00288 
00289