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.h"
00021 #include "TCPConnection.h"
00022 #include "TCPSegment.h"
00023 #include "TCPCommand_m.h"
00024 #include "TCPSendQueue.h"
00025 #include "TCPReceiveQueue.h"
00026 #include "TCPAlgorithm.h"
00027 
00028 
00029 //
00030 // Event processing code
00031 //
00032 
00033 void TCPConnection::process_OPEN_ACTIVE(TCPEventCode& event, TCPCommand *tcpCommand, cMessage *msg)
00034 {
00035     TCPOpenCommand *openCmd = check_and_cast<TCPOpenCommand *>(tcpCommand);
00036     IPvXAddress localAddr, remoteAddr;
00037     int localPort, remotePort;
00038 
00039     switch(fsm.getState())
00040     {
00041         case TCP_S_INIT:
00042             initConnection(openCmd);
00043 
00044             // store local/remote socket
00045             state->active = true;
00046             localAddr = openCmd->getLocalAddr();
00047             remoteAddr = openCmd->getRemoteAddr();
00048             localPort = openCmd->getLocalPort();
00049             remotePort = openCmd->getRemotePort();
00050 
00051             if (remoteAddr.isUnspecified() || remotePort==-1)
00052                 opp_error("Error processing command OPEN_ACTIVE: remote address and port must be specified");
00053 
00054             if (localPort==-1)
00055             {
00056                 localPort = tcpMain->getEphemeralPort();
00057                 tcpEV << "Assigned ephemeral port " << localPort << "\n";
00058             }
00059 
00060             tcpEV << "OPEN: " << localAddr << ":" << localPort << " --> " << remoteAddr << ":" << remotePort << "\n";
00061 
00062             tcpMain->addSockPair(this, localAddr, remoteAddr, localPort, remotePort);
00063 
00064             // send initial SYN
00065             selectInitialSeqNum();
00066             sendSyn();
00067             startSynRexmitTimer();
00068             scheduleTimeout(connEstabTimer, TCP_TIMEOUT_CONN_ESTAB);
00069             break;
00070 
00071         default:
00072             opp_error("Error processing command OPEN_ACTIVE: connection already exists");
00073     }
00074 
00075     delete openCmd;
00076     delete msg;
00077 }
00078 
00079 void TCPConnection::process_OPEN_PASSIVE(TCPEventCode& event, TCPCommand *tcpCommand, cMessage *msg)
00080 {
00081     TCPOpenCommand *openCmd = check_and_cast<TCPOpenCommand *>(tcpCommand);
00082     IPvXAddress localAddr;
00083     int localPort;
00084 
00085     switch(fsm.getState())
00086     {
00087         case TCP_S_INIT:
00088             initConnection(openCmd);
00089 
00090             // store local/remote socket
00091             state->active = false;
00092             state->fork = openCmd->getFork();
00093             localAddr = openCmd->getLocalAddr();
00094             localPort = openCmd->getLocalPort();
00095 
00096             if (localPort==-1)
00097                 opp_error("Error processing command OPEN_PASSIVE: local port must be specified");
00098 
00099             tcpEV << "Starting to listen on: " << localAddr << ":" << localPort << "\n";
00100 
00101             tcpMain->addSockPair(this, localAddr, IPvXAddress(), localPort, -1);
00102             break;
00103 
00104         default:
00105             opp_error("Error processing command OPEN_PASSIVE: connection already exists");
00106     }
00107 
00108     delete openCmd;
00109     delete msg;
00110 }
00111 
00112 void TCPConnection::process_SEND(TCPEventCode& event, TCPCommand *tcpCommand, cMessage *msg)
00113 {
00114     TCPSendCommand *sendCommand = check_and_cast<TCPSendCommand *>(tcpCommand);
00115 
00116     // FIXME how to support PUSH? One option is to treat each SEND as a unit of data,
00117     // and set PSH at SEND boundaries
00118     switch(fsm.getState())
00119     {
00120         case TCP_S_INIT:
00121             opp_error("Error processing command SEND: connection not open");
00122 
00123         case TCP_S_LISTEN:
00124             tcpEV << "SEND command turns passive open into active open, sending initial SYN\n";
00125             state->active = true;
00126             selectInitialSeqNum();
00127             sendSyn();
00128             startSynRexmitTimer();
00129             scheduleTimeout(connEstabTimer, TCP_TIMEOUT_CONN_ESTAB);
00130             sendQueue->enqueueAppData(PK(msg));  // queue up for later
00131             tcpEV << sendQueue->getBytesAvailable(state->snd_una) << " bytes in queue\n";
00132             break;
00133 
00134         case TCP_S_SYN_RCVD:
00135         case TCP_S_SYN_SENT:
00136             tcpEV << "Queueing up data for sending later.\n";
00137             sendQueue->enqueueAppData(PK(msg)); // queue up for later
00138             tcpEV << sendQueue->getBytesAvailable(state->snd_una) << " bytes in queue\n";
00139             break;
00140 
00141         case TCP_S_ESTABLISHED:
00142         case TCP_S_CLOSE_WAIT:
00143             sendQueue->enqueueAppData(PK(msg));
00144             tcpEV << sendQueue->getBytesAvailable(state->snd_una) << " bytes in queue, plus "
00145                   << (state->snd_max-state->snd_una) << " bytes unacknowledged\n";
00146             tcpAlgorithm->sendCommandInvoked();
00147             break;
00148 
00149         case TCP_S_LAST_ACK:
00150         case TCP_S_FIN_WAIT_1:
00151         case TCP_S_FIN_WAIT_2:
00152         case TCP_S_CLOSING:
00153         case TCP_S_TIME_WAIT:
00154             opp_error("Error processing command SEND: connection closing");
00155     }
00156 
00157     delete sendCommand; // msg itself has been taken by the sendQueue
00158 }
00159 
00160 void TCPConnection::process_CLOSE(TCPEventCode& event, TCPCommand *tcpCommand, cMessage *msg)
00161 {
00162     delete tcpCommand;
00163     delete msg;
00164 
00165     switch(fsm.getState())
00166     {
00167         case TCP_S_INIT:
00168             opp_error("Error processing command CLOSE: connection not open");
00169 
00170         case TCP_S_LISTEN:
00171             // Nothing to do here
00172             break;
00173 
00174         case TCP_S_SYN_SENT:
00175             // Delete the TCB and return "error:  closing" responses to any
00176             // queued SENDs, or RECEIVEs.
00177             break;
00178 
00179         case TCP_S_SYN_RCVD:
00180         case TCP_S_ESTABLISHED:
00181         case TCP_S_CLOSE_WAIT:
00182             //
00183             // SYN_RCVD processing (ESTABLISHED and CLOSE_WAIT are similar):
00184             //"
00185             // If no SENDs have been issued and there is no pending data to send,
00186             // then form a FIN segment and send it, and enter FIN-WAIT-1 state;
00187             // otherwise queue for processing after entering ESTABLISHED state.
00188             //"
00189             if (state->snd_max==sendQueue->getBufferEndSeq())
00190             {
00191                 tcpEV << "No outstanding SENDs, sending FIN right away, advancing snd_nxt over the FIN\n";
00192                 state->snd_nxt = state->snd_max;
00193                 sendFin();
00194                 tcpAlgorithm->restartRexmitTimer();
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->getBufferEndSeq()-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->getBufferEndSeq();
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 }
00220 
00221 void TCPConnection::process_ABORT(TCPEventCode& event, TCPCommand *tcpCommand, cMessage *msg)
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.getState())
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 }
00251 
00252 void TCPConnection::process_STATUS(TCPEventCode& event, TCPCommand *tcpCommand, cMessage *msg)
00253 {
00254     delete tcpCommand; // but reuse msg for reply
00255 
00256     if (fsm.getState()==TCP_S_INIT)
00257         opp_error("Error processing command STATUS: connection not open");
00258 
00259     TCPStatusInfo *statusInfo = new TCPStatusInfo();
00260 
00261     statusInfo->setState(fsm.getState());
00262     statusInfo->setStateName(stateName(fsm.getState()));
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 }
00287 
00288