|
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 "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