|
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 #include "TCPSocket.h" 00019 00020 00021 TCPSocket::TCPSocket() 00022 { 00023 // don't allow user-specified connIds because they may conflict with 00024 // automatically assigned ones. 00025 connId = ev.getUniqueNumber(); 00026 sockstate = NOT_BOUND; 00027 00028 localPrt = remotePrt = -1; 00029 cb = NULL; 00030 yourPtr = NULL; 00031 00032 gateToTcp = NULL; 00033 } 00034 00035 TCPSocket::TCPSocket(cMessage *msg) 00036 { 00037 TCPCommand *ind = dynamic_cast<TCPCommand *>(msg->getControlInfo()); 00038 if (!ind) 00039 opp_error("TCPSocket::TCPSocket(cMessage *): no TCPCommand control info in message (not from TCP?)"); 00040 00041 connId = ind->getConnId(); 00042 sockstate = CONNECTED; 00043 00044 localPrt = remotePrt = -1; 00045 cb = NULL; 00046 yourPtr = NULL; 00047 00048 gateToTcp = NULL; 00049 00050 if (msg->getKind()==TCP_I_ESTABLISHED) 00051 { 00052 // management of stockstate is left to processMessage() so we always 00053 // set it to CONNECTED in the ctor, whatever TCP_I_xxx arrives. 00054 // However, for convenience we extract TCPConnectInfo already here, so that 00055 // remote address/port can be read already after the ctor call. 00056 00057 TCPConnectInfo *connectInfo = dynamic_cast<TCPConnectInfo *>(msg->getControlInfo()); 00058 localAddr = connectInfo->getLocalAddr(); 00059 remoteAddr = connectInfo->getRemoteAddr(); 00060 localPrt = connectInfo->getLocalPort(); 00061 remotePrt = connectInfo->getRemotePort(); 00062 } 00063 } 00064 00065 const char *TCPSocket::stateName(int state) 00066 { 00067 #define CASE(x) case x: s=#x; break 00068 const char *s = "unknown"; 00069 switch (state) 00070 { 00071 CASE(NOT_BOUND); 00072 CASE(BOUND); 00073 CASE(LISTENING); 00074 CASE(CONNECTING); 00075 CASE(CONNECTED); 00076 CASE(PEER_CLOSED); 00077 CASE(LOCALLY_CLOSED); 00078 CASE(CLOSED); 00079 CASE(SOCKERROR); 00080 } 00081 return s; 00082 #undef CASE 00083 } 00084 00085 void TCPSocket::sendToTCP(cMessage *msg) 00086 { 00087 if (!gateToTcp) 00088 opp_error("TCPSocket: setOutputGate() must be invoked before socket can be used"); 00089 00090 check_and_cast<cSimpleModule *>(gateToTcp->getOwnerModule())->send(msg, gateToTcp); 00091 } 00092 00093 void TCPSocket::bind(int lPort) 00094 { 00095 if (sockstate!=NOT_BOUND) 00096 opp_error("TCPSocket::bind(): socket already bound"); 00097 if (lPort<0 || lPort>65535) 00098 opp_error("TCPSocket::bind(): invalid port number %d", lPort); 00099 00100 localPrt = lPort; 00101 sockstate = BOUND; 00102 } 00103 00104 void TCPSocket::bind(IPvXAddress lAddr, int lPort) 00105 { 00106 if (sockstate!=NOT_BOUND) 00107 opp_error("TCPSocket::bind(): socket already bound"); 00108 // allow -1 here, to make it possible to specify address only 00109 if ((lPort<0 || lPort>65535) && lPort!=-1) 00110 opp_error("TCPSocket::bind(): invalid port number %d", lPort); 00111 00112 localAddr = lAddr; 00113 localPrt = lPort; 00114 sockstate = BOUND; 00115 } 00116 00117 void TCPSocket::listen(bool fork) 00118 { 00119 if (sockstate!=BOUND) 00120 opp_error(sockstate==NOT_BOUND ? "TCPSocket: must call bind() before listen()" 00121 : "TCPSocket::listen(): connect() or listen() already called"); 00122 00123 cMessage *msg = new cMessage("PassiveOPEN", TCP_C_OPEN_PASSIVE); 00124 00125 TCPOpenCommand *openCmd = new TCPOpenCommand(); 00126 openCmd->setLocalAddr(localAddr); 00127 openCmd->setLocalPort(localPrt); 00128 openCmd->setConnId(connId); 00129 openCmd->setFork(fork); 00130 openCmd->setSendQueueClass(sendQueueClass.c_str()); 00131 openCmd->setReceiveQueueClass(receiveQueueClass.c_str()); 00132 openCmd->setTcpAlgorithmClass(tcpAlgorithmClass.c_str()); 00133 00134 msg->setControlInfo(openCmd); 00135 sendToTCP(msg); 00136 sockstate = LISTENING; 00137 } 00138 00139 void TCPSocket::connect(IPvXAddress remoteAddress, int remotePort) 00140 { 00141 if (sockstate!=NOT_BOUND && sockstate!=BOUND) 00142 opp_error( "TCPSocket::connect(): connect() or listen() already called (need renewSocket()?)"); 00143 if (remotePort<0 || remotePort>65535) 00144 opp_error("TCPSocket::connect(): invalid remote port number %d", remotePort); 00145 00146 cMessage *msg = new cMessage("ActiveOPEN", TCP_C_OPEN_ACTIVE); 00147 00148 remoteAddr = remoteAddress; 00149 remotePrt = remotePort; 00150 00151 TCPOpenCommand *openCmd = new TCPOpenCommand(); 00152 openCmd->setConnId(connId); 00153 openCmd->setLocalAddr(localAddr); 00154 openCmd->setLocalPort(localPrt); 00155 openCmd->setRemoteAddr(remoteAddr); 00156 openCmd->setRemotePort(remotePrt); 00157 openCmd->setSendQueueClass(sendQueueClass.c_str()); 00158 openCmd->setReceiveQueueClass(receiveQueueClass.c_str()); 00159 openCmd->setTcpAlgorithmClass(tcpAlgorithmClass.c_str()); 00160 00161 msg->setControlInfo(openCmd); 00162 sendToTCP(msg); 00163 sockstate = CONNECTING; 00164 } 00165 00166 void TCPSocket::send(cMessage *msg) 00167 { 00168 if (sockstate!=CONNECTED && sockstate!=CONNECTING && sockstate!=PEER_CLOSED) 00169 opp_error("TCPSocket::send(): not connected or connecting"); 00170 00171 msg->setKind(TCP_C_SEND); 00172 TCPSendCommand *cmd = new TCPSendCommand(); 00173 cmd->setConnId(connId); 00174 msg->setControlInfo(cmd); 00175 sendToTCP(msg); 00176 } 00177 00178 void TCPSocket::close() 00179 { 00180 if (sockstate!=CONNECTED && sockstate!=PEER_CLOSED && sockstate!=CONNECTING && sockstate!=LISTENING) 00181 opp_error("TCPSocket::close(): not connected or close() already called"); 00182 00183 cMessage *msg = new cMessage("CLOSE", TCP_C_CLOSE); 00184 TCPCommand *cmd = new TCPCommand(); 00185 cmd->setConnId(connId); 00186 msg->setControlInfo(cmd); 00187 sendToTCP(msg); 00188 sockstate = sockstate==CONNECTED ? LOCALLY_CLOSED : CLOSED; 00189 } 00190 00191 void TCPSocket::abort() 00192 { 00193 if (sockstate!=NOT_BOUND && sockstate!=BOUND && sockstate!=CLOSED && sockstate!=SOCKERROR) 00194 { 00195 cMessage *msg = new cMessage("ABORT", TCP_C_ABORT); 00196 TCPCommand *cmd = new TCPCommand(); 00197 cmd->setConnId(connId); 00198 msg->setControlInfo(cmd); 00199 sendToTCP(msg); 00200 } 00201 sockstate = CLOSED; 00202 } 00203 00204 void TCPSocket::requestStatus() 00205 { 00206 cMessage *msg = new cMessage("STATUS", TCP_C_STATUS); 00207 TCPCommand *cmd = new TCPCommand(); 00208 cmd->setConnId(connId); 00209 msg->setControlInfo(cmd); 00210 sendToTCP(msg); 00211 } 00212 00213 void TCPSocket::renewSocket() 00214 { 00215 connId = ev.getUniqueNumber(); 00216 remoteAddr = localAddr = IPvXAddress(); 00217 remotePrt = localPrt = -1; 00218 00219 sockstate = NOT_BOUND; 00220 } 00221 00222 bool TCPSocket::belongsToSocket(cMessage *msg) 00223 { 00224 return dynamic_cast<TCPCommand *>(msg->getControlInfo()) && 00225 ((TCPCommand *)(msg->getControlInfo()))->getConnId()==connId; 00226 } 00227 00228 bool TCPSocket::belongsToAnyTCPSocket(cMessage *msg) 00229 { 00230 return dynamic_cast<TCPCommand *>(msg->getControlInfo()); 00231 } 00232 00233 void TCPSocket::setCallbackObject(CallbackInterface *callback, void *yourPointer) 00234 { 00235 cb = callback; 00236 yourPtr = yourPointer; 00237 } 00238 00239 void TCPSocket::processMessage(cMessage *msg) 00240 { 00241 ASSERT(belongsToSocket(msg)); 00242 00243 TCPStatusInfo *status; 00244 TCPConnectInfo *connectInfo; 00245 switch (msg->getKind()) 00246 { 00247 case TCP_I_DATA: 00248 if (cb) 00249 cb->socketDataArrived(connId, yourPtr, PK(msg), false); 00250 else 00251 delete msg; 00252 break; 00253 case TCP_I_URGENT_DATA: 00254 if (cb) 00255 cb->socketDataArrived(connId, yourPtr, PK(msg), true); 00256 else 00257 delete msg; 00258 break; 00259 case TCP_I_ESTABLISHED: 00260 // Note: this code is only for sockets doing active open, and nonforking 00261 // listening sockets. For a forking listening sockets, TCP_I_ESTABLISHED 00262 // carries a new connId which won't match the connId of this TCPSocket, 00263 // so you won't get here. Rather, when you see TCP_I_ESTABLISHED, you'll 00264 // want to create a new TCPSocket object via new TCPSocket(msg). 00265 sockstate = CONNECTED; 00266 connectInfo = dynamic_cast<TCPConnectInfo *>(msg->getControlInfo()); 00267 localAddr = connectInfo->getLocalAddr(); 00268 remoteAddr = connectInfo->getRemoteAddr(); 00269 localPrt = connectInfo->getLocalPort(); 00270 remotePrt = connectInfo->getRemotePort(); 00271 delete msg; 00272 if (cb) 00273 cb->socketEstablished(connId, yourPtr); 00274 break; 00275 case TCP_I_PEER_CLOSED: 00276 sockstate = sockstate==CONNECTED ? PEER_CLOSED : CLOSED; 00277 delete msg; 00278 if (cb) 00279 cb->socketPeerClosed(connId, yourPtr); 00280 break; 00281 case TCP_I_CLOSED: 00282 sockstate = CLOSED; 00283 delete msg; 00284 if (cb) 00285 cb->socketClosed(connId, yourPtr); 00286 break; 00287 case TCP_I_CONNECTION_REFUSED: 00288 case TCP_I_CONNECTION_RESET: 00289 case TCP_I_TIMED_OUT: 00290 sockstate = SOCKERROR; 00291 if (cb) 00292 cb->socketFailure(connId, yourPtr, msg->getKind()); 00293 delete msg; 00294 break; 00295 case TCP_I_STATUS: 00296 status = check_and_cast<TCPStatusInfo *>(msg->removeControlInfo()); 00297 delete msg; 00298 if (cb) 00299 cb->socketStatusArrived(connId, yourPtr, status); 00300 break; 00301 default: 00302 opp_error("TCPSocket: invalid msg kind %d, one of the TCP_I_xxx constants expected", msg->getKind()); 00303 } 00304 } 00305