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