# SocketTCP.cc

Go to the documentation of this file.

    00001 // ----------------------------------------------------------------------------
    00002 // CERTI - HLA RunTime Infrastructure
    00003 // Copyright (C) 2002-2005  ONERA
    00004 //
    00005 // This program is free software ; you can redistribute it and/or
    00006 // modify it under the terms of the GNU Lesser General Public License
    00007 // as published by the Free Software Foundation ; either version 2 of
    00008 // the License, or (at your option) any later version.
    00009 //
    00010 // This program is distributed in the hope that it will be useful, but
    00011 // WITHOUT ANY WARRANTY ; without even the implied warranty of
    00012 // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
    00013 // Lesser General Public License for more details.
    00014 //
    00015 // You should have received a copy of the GNU Lesser General Public
    00016 // License along with this program ; if not, write to the Free Software
    00017 // Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307
    00018 // USA
    00019 //
    00020 // $Id: SocketTCP.cc,v 3.27 2008/12/07 20:16:15 gotthardp Exp $
    00021 // ----------------------------------------------------------------------------
    00022
    00023 #ifdef _WIN32
    00024     #define EADDRINUSE      WSAEADDRINUSE
    00025     #include <winsock2.h>
    00026 #else
    00027     #include <netdb.h>
    00028     #include <unistd.h>
    00029     #include <netinet/tcp.h>
    00030     #include <iostream>
    00031 #endif
    00032
    00033 #include "SocketTCP.hh"
    00034 #include "PrettyDebug.hh"
    00035
    00036 #include <cassert>
    00037 #include <cerrno>
    00038 #include <cstdlib>
    00039 #include <cstring>
    00040
    00041 using std::cout ;
    00042 using std::endl ;
    00043
    00044 namespace certi {
    00045
    00046 static pdCDebug D("SOCKTCP", "(SocketTCP) - ");
    00047 static PrettyDebug G("GENDOC",__FILE__);
    00048
    00049 #ifdef _WIN32
    00050 int SocketTCP::winsockInits = 0;
    00051
    00052 bool SocketTCP::winsockStartup()
    00053 {
    00054 WORD wVersionRequested;
    00055 WSADATA wsaData;
    00056 int lError;
    00057
    00058 if (winsockInits > 0)
    00059     {
    00060     winsockInits++;
    00061     return true;
    00062     }
    00063 else if (winsockInits <0)
    00064     {
    00065     return false;
    00066     }
    00067
    00068 wVersionRequested = MAKEWORD( 2, 0 );
    00069 lError = WSAStartup( wVersionRequested, &wsaData );
    00070 if (lError != 0)
    00071     {
    00072     winsockInits = -1;
    00073     return false;
    00074     }
    00075
    00076 if (LOBYTE( wsaData.wVersion ) != 2 || HIBYTE( wsaData.wVersion ) != 0)
    00077     {// Tell the user that we couldn't find a usable WinSock DLL.
    00078     WSACleanup( );
    00079     winsockInits = -1;
    00080     return false;
    00081     }
    00082
    00083 winsockInits = 1;
    00084 return true;
    00085 }
    00086
    00087 void SocketTCP::winsockShutdown()
    00088 {
    00089 winsockInits--;
    00090 if (winsockInits==0)
    00091     WSACleanup( );
    00092 }
    00093 #endif
    00094
    00095 // ----------------------------------------------------------------------------
    00096 SocketTCP::SocketTCP()
    00097 {
    00098 _est_init_tcp = false ;
    00099
    00100 SentBytesCount = 0 ;
    00101 RcvdBytesCount = 0 ;
    00102
    00103 #ifdef _WIN32
    00104     winsockStartup();
    00105 #endif
    00106
    00107 #ifdef SOCKTCP_BUFFER_LENGTH
    00108     RBLength = 0 ;
    00109 #endif
    00110 }
    00111
    00112 // ----------------------------------------------------------------------------
    00113 SocketTCP::~SocketTCP()
    00114 {// Fermeture
    00115 if (_est_init_tcp)
    00116     close();
    00117
    00118 #ifdef _WIN32
    00119     winsockShutdown();
    00120 #endif
    00121
    00122 #ifdef RTI_PRINTS_STATISTICS
    00123     cout << " TCP Socket " ;
    00124     cout.width(2);
    00125     cout << _socket_tcp << " : total = " ;
    00126     cout.width(9);
    00127     cout << SentBytesCount << "b sent " << endl ;
    00128     cout << " TCP Socket " ;
    00129     cout.width(2);
    00130     cout << _socket_tcp << " : total = " ;
    00131     cout.width(9);
    00132     cout << RcvdBytesCount << "b received" << endl ;
    00133 #endif
    00134 }
    00135
    00136 // ----------------------------------------------------------------------------
    00137 int SocketTCP::connect(in_port_t port, in_addr_t addr)
    00138 {
    00139 int Result ;
    00140 struct protoent *TCPent ;
    00141 int optval = 1 ;
    00142
    00143 assert(!_est_init_tcp);
    00144
    00145 _sockIn.sin_family=AF_INET ;
    00146 _sockIn.sin_port=htons(port);
    00147 _sockIn.sin_addr.s_addr=addr ;
    00148
    00149
    00150 Result = ::connect(_socket_tcp, (sockaddr*)&_sockIn, sizeof(_sockIn));
    00151
    00152 if (Result < 0)
    00153     return 0 ;
    00154
    00155 // Set the TCP_NODELAY option(Client Side)
    00156
    00157 TCPent = getprotobyname("tcp");
    00158 if (TCPent == NULL)
    00159     {
    00160     cout << "Unable to retrieve TCP protocol number." << endl ;
    00161     return 0 ;
    00162     }
    00163
    00164 if (setsockopt(_socket_tcp,
    00165                 TCPent->p_proto,
    00166                 TCP_NODELAY,
    00167                 (char *) &optval,
    00168                 sizeof(optval)))
    00169     {
    00170     cout << "Error while calling setsockopt." << endl ;
    00171     return 0 ;
    00172     }
    00173
    00174 if (Result < 0)
    00175     return 0 ;
    00176 else
    00177     return 1 ;
    00178 }
    00179
    00180 // ----------------------------------------------------------------------------
    00181 int SocketTCP::accept(SocketTCP *serveur) throw (NetworkError)
    00182 {
    00183     std::stringstream msg;
    00184 struct protoent *TCPent ;
    00185 int optval = 1 ;
    00186
    00187 #ifdef _WIN32
    00188     int         l;
    00189 #else
    00190     socklen_t   l;
    00191 #endif
    00192
    00193 assert(!_est_init_tcp);
    00194 assert(serveur != NULL);
    00195
    00196 l = sizeof(_sockIn);
    00197
    00198 _socket_tcp = ::accept(serveur->_socket_tcp, (sockaddr*)&_sockIn, &l);
    00199 if (_socket_tcp < 0)
    00200     {
    00201       msg << "SocketTCP: Accept Failed"
    00202           << "<" << strerror(errno) <<">";
    00203       throw NetworkError(msg.str().c_str());
    00204     }
    00205
    00206 // Set the TCP_NODELAY option(Server Side)
    00207 TCPent = getprotobyname("tcp");
    00208 if (TCPent == NULL)
    00209     {
    00210     cout << "Unable to retrieve TCP protocol number." << endl ;
    00211     return 0 ;
    00212     }
    00213
    00214 if (setsockopt(_socket_tcp,
    00215                     TCPent->p_proto,
    00216                     TCP_NODELAY,
    00217                     (char *) &optval,
    00218                     sizeof(optval)))
    00219     {
    00220     cout << "Error while calling setsockopt." << endl ;
    00221     return 0 ;
    00222     }
    00223
    00224 _est_init_tcp = true ;
    00225
    00226 return 1 ;
    00227 }
    00228
    00229 // ----------------------------------------------------------------------------
    00230 int
    00231 SocketTCP::bind(in_port_t port, in_addr_t addr)
    00232 {
    00233 long Length, Result ;
    00234
    00235 assert(!_est_init_tcp);
    00236
    00237 memset(&_sockIn, 0, sizeof(_sockIn));
    00238
    00239 _sockIn.sin_family = AF_INET ;
    00240 _sockIn.sin_addr.s_addr = addr ;
    00241 _sockIn.sin_port = htons(port);
    00242
    00243 Length = sizeof(_sockIn);
    00244
    00245     int on = 1 ;
    00246     /* Bind even if the port is in the TIME_WAIT. If the port is busy,
    00247      * An error will be reported if the port is busy with another state. */
    00248     if (setsockopt(_socket_tcp,
    00249         SOL_SOCKET, SO_REUSEADDR, (char *)&on, sizeof(on)))
    00250     perror("setsockopt");
    00251
    00252     Result = ::bind(_socket_tcp, (sockaddr *)&_sockIn, Length);
    00253
    00254     if (Result != 0) {
    00255         perror("bind");
    00256     return 0;
    00257     }
    00258     else
    00259         return 1;
    00260 }
    00261
    00262 // ----------------------------------------------------------------------------
    00263 void
    00264 SocketTCP::createConnection(const char *server_name, unsigned int port)
    00265     throw (NetworkError)
    00266 {
    00267     std::stringstream msg;
    00268     // get host information from server name
    00269     // this may perform DNS query
    00270     struct hostent *hptr = gethostbyname(server_name);
    00271     if (NULL == hptr)
    00272     {
    00273         msg << "gethostbyname gave NULL answer for hostname <"
    00274         << server_name
    00275         << "> with error <"
    00276         << strerror(errno)
    00277         << ">";
    00278         throw NetworkError(msg.str().c_str());
    00279     }
    00280
    00281     in_addr_t addr = 0;
    00282     memcpy((void *) &addr, (void *) hptr->h_addr, hptr->h_length);
    00283
    00284     createTCPClient(port, addr);
    00285 }
    00286
    00287 // ----------------------------------------------------------------------------
    00288 void
    00289 SocketTCP::createTCPClient(in_port_t port, in_addr_t addr)
    00290 throw (NetworkError)
    00291 {
    00292 assert(!_est_init_tcp);
    00293 std::stringstream msg;
    00294 if (!open())
    00295     {
    00296         msg << "Cannot open port <" << port
    00297             << "> on addr <" << addr2string(addr)
    00298             << "> : error =" << strerror(errno);
    00299         throw NetworkError(msg.str().c_str());
    00300     }
    00301
    00302 if (!connect(port, addr))
    00303     {
    00304         msg << "Cannot connect port <" << port
    00305             << "> on addr <" << addr2string(addr)
    00306             << "> : error =" << strerror(errno);
    00307         throw NetworkError(msg.str().c_str());
    00308     }
    00309
    00310 _est_init_tcp = true ;
    00311 }
    00312
    00313 // ----------------------------------------------------------------------------
    00314 void
    00315 SocketTCP::createTCPServer(in_port_t port, in_addr_t addr)
    00316 throw (NetworkError)
    00317 {
    00318     std::stringstream msg;
    00319     assert(!_est_init_tcp);
    00320
    00321
    00322 if (!open())
    00323     {
    00324     msg << "Cannot open port <" << port
    00325         << "> on addr <" << addr2string(addr)
    00326         << "> : error =" << strerror(errno);
    00327     throw NetworkError(msg.str().c_str());
    00328     }
    00329
    00330 if (!bind(port, addr))
    00331     {
    00332     msg << "Cannot bind port <" << port
    00333         << "> on addr <" << addr2string(addr)
    00334         << "> : error =" << strerror(errno);
    00335     throw NetworkError(msg.str().c_str());
    00336     }
    00337
    00338 if (!listen(MAX_BACKLOG))
    00339     {
    00340     msg << "Cannot listen port <" << port
    00341         << "> on addr <" << addr2string(addr)
    00342         << "> : error =" << strerror(errno);
    00343     throw NetworkError(msg.str().c_str());
    00344     }
    00345
    00346 _est_init_tcp = true ;
    00347 }
    00348
    00349
    00350 // ----------------------------------------------------------------------------
    00351 void
    00352 SocketTCP::send(const unsigned char *buffer, size_t size)
    00353                      throw (NetworkError, NetworkSignal)
    00354 {
    00355 long total_sent = 0 ;
    00356 long expected_size = size ;
    00357
    00358 assert(_est_init_tcp);
    00359
    00360 D.Out(pdDebug, "Beginning to send TCP message...");
    00361
    00362 while (total_sent < expected_size)
    00363     {
    00364     #ifdef _WIN32
    00365         int sent = ::send(_socket_tcp, (char*) buffer + total_sent, expected_size - total_sent, 0);
    00366     #else
    00367         int sent = ::send(_socket_tcp, buffer + total_sent, expected_size - total_sent, 0);
    00368     #endif
    00369
    00370     if (sent < 0)
    00371         {
    00372         D.Out(pdExcept, "Error while sending on TCP socket.");
    00373
    00374         #ifdef _WIN32
    00375             if(WSAGetLastError() == WSAEINTR)
    00376         #else
    00377             if(errno == EINTR)
    00378         #endif
    00379             throw NetworkSignal("");
    00380         else
    00381             {
    00382             perror("TCP Socket(EmettreTCP) ");
    00383             throw NetworkError("Error while sending TCP message.");
    00384             }
    00385         }
    00386
    00387     if (sent == 0)
    00388         {
    00389         D.Out(pdExcept, "No data could be sent, connection closed?.");
    00390         throw NetworkError("Could not send any data on TCP socket.");
    00391         }
    00392
    00393     total_sent += sent ;
    00394     D.Out(pdTrace, "Sent %ld bytes out of %ld.", total_sent, expected_size);
    00395     }
    00396
    00397 SentBytesCount += total_sent ;
    00398 }
    00399
    00400 // ----------------------------------------------------------------------------
    00401 void
    00402 SocketTCP::close()
    00403 {
    00404 if (_est_init_tcp)
    00405     {
    00406     #ifdef _WIN32
    00407         ::closesocket(_socket_tcp);
    00408     #else
    00409 		::close(_socket_tcp);
    00410     #endif
    00411     _est_init_tcp = false ;
    00412     }
    00413 }
    00414
    00415 // ----------------------------------------------------------------------------
    00416 int
    00417 SocketTCP::listen(unsigned long howMuch)
    00418 {
    00419 assert(!_est_init_tcp);
    00420
    00421 return ::listen(_socket_tcp, howMuch) >= 0 ;
    00422 }
    00423
    00424 // ----------------------------------------------------------------------------
    00425 in_addr_t
    00426 SocketTCP::getAddr() const
    00427 {
    00428 return(_sockIn.sin_addr.s_addr);
    00429 }
    00430
    00431 // ----------------------------------------------------------------------------
    00432 in_port_t
    00433 SocketTCP::getPort() const
    00434 {
    00435 return _sockIn.sin_port ;
    00436 }
    00437
    00438 // ----------------------------------------------------------------------------
    00442 bool
    00443 SocketTCP::isDataReady() const
    00444 {
    00445 #ifdef SOCKTCP_BUFFER_LENGTH
    00446     return RBLength > 0 ;
    00447 #else
    00448     return false ;
    00449 #endif
    00450 }
    00451
    00452 // ----------------------------------------------------------------------------
    00453 int
    00454 SocketTCP::open()
    00455 {
    00456 #ifdef _WIN32
    00457     assert(winsockInits>0);
    00458 #endif
    00459     return(((_socket_tcp=socket(AF_INET,SOCK_STREAM,0))<0)?0:1);
    00460 }
    00461
    00462 // ----------------------------------------------------------------------------
    00463 SocketTCP &
    00464 SocketTCP::operator=(SocketTCP &theSocket)
    00465 {
    00466 _sockIn.sin_addr.s_addr=theSocket.getAddr();
    00467 _sockIn.sin_port =theSocket.getPort();
    00468 _socket_tcp =theSocket.returnSocket();
    00469
    00470 return(*this);
    00471 }
    00472
    00473 // ----------------------------------------------------------------------------
    00474 void
    00475 SocketTCP::receive(void *buffer, unsigned long size)
    00476                         throw (NetworkError, NetworkSignal)
    00477 {
    00478 // G.Out(pdGendoc,"enter SocketTCP::receive");
    00479 assert(_est_init_tcp);
    00480
    00481 long nReceived = 0 ;
    00482 #ifndef SOCKTCP_BUFFER_LENGTH
    00483 unsigned long RBLength = 0 ;
    00484 #endif
    00485
    00486 D.Out(pdDebug, "Beginning to receive TCP message...(Size  %ld)",size);
    00487
    00488 while (RBLength < size)
    00489     {
    00490
    00491     #ifdef SOCKTCP_BUFFER_LENGTH
    00492     nReceived = recv(_socket_tcp,
    00493                             ReadBuffer + RBLength,
    00494                             SOCKTCP_BUFFER_LENGTH - RBLength,
    00495                             0);
    00496     #else
    00497     nReceived = recv(_socket_tcp,
    00498                             (char *) buffer + RBLength,
    00499                             size - RBLength,
    00500                             0);
    00501     #endif
    00502
    00503     if (nReceived < 0)
    00504         {
    00505         D.Out(pdExcept, "Error while receiving on TCP socket.");
    00506         #ifdef _WIN32
    00507             if(WSAGetLastError() == WSAEINTR)
    00508         #else
    00509             if(errno == EINTR)
    00510         #endif
    00511             throw NetworkSignal("");
    00512         else
    00513             {
    00514             perror("TCP Socket(RecevoirTCP) ");
    00515             throw NetworkError("Error while receiving TCP message.");
    00516             }
    00517         }
    00518
    00519     if (nReceived == 0)
    00520         {
    00521         D.Out(pdExcept, "TCP connection has been closed by peer.");
    00522         throw NetworkError("Connection closed by client.");
    00523         }
    00524
    00525     RBLength += nReceived ;
    00526     RcvdBytesCount += nReceived ;
    00527     }
    00528 D.Out(pdTrace, "Received %ld bytes out of %ld.", RBLength, size);
    00529
    00530 #ifdef SOCKTCP_BUFFER_LENGTH
    00531     memcpy(buffer, (void *) ReadBuffer, size);
    00532     memmove((void *) ReadBuffer, (void *)(ReadBuffer + size), RBLength - size);
    00533     RBLength -= size ;
    00534 #endif
    00535 // G.Out(pdGendoc,"exit  SocketTCP::receive");
    00536 }
    00537
    00538 // ----------------------------------------------------------------------------
    00539 unsigned long
    00540 SocketTCP::returnAdress() const
    00541 {
    00542 return getAddr();
    00543 }
    00544
    00545 // ----------------------------------------------------------------------------
    00546 #ifdef _WIN32
    00547 SOCKET SocketTCP::returnSocket()    { return _socket_tcp ;}
    00548 #else
    00549 int SocketTCP::returnSocket()       { return _socket_tcp ;}
    00550 #endif
    00551
    00552 // ----------------------------------------------------------------------------
    00554 void SocketTCP::setPort(in_port_t port)
    00555 {
    00556 _sockIn.sin_port=port ;
    00557 }
    00558
    00559 // ----------------------------------------------------------------------------
    00567 int
    00568 SocketTCP::timeoutTCP(int sec, int usec)
    00569 {
    00570 assert(_est_init_tcp);
    00571
    00572 struct timeval time_out ;
    00573 time_out.tv_sec = sec ;
    00574 time_out.tv_usec = usec ;
    00575
    00576 fd_set fdset ;
    00577 FD_ZERO(&fdset);
    00578 FD_SET(_socket_tcp, &fdset);
    00579
    00580 int nb = select(_socket_tcp+1, &fdset, NULL, NULL, &time_out);
    00581
    00582 if (nb < 0)
    00583     {
    00584     #ifdef _WIN32
    00585          if(WSAGetLastError() == WSAEINTR)
    00586     #else
    00587          if(errno == EINTR)
    00588     #endif
    00589         throw NetworkSignal("TCP::TimeOut signal interrupt.");
    00590     else
    00591         throw NetworkError("Select gave negative return value");
    00592     }
    00593 else
    00594     return nb > 0 ;
    00595 }
    00596
    00597 } // namespace
    00598
    00599 // $Id: SocketTCP.cc,v 3.27 2008/12/07 20:16:15 gotthardp Exp $