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