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 $

Generated on Thu Apr 30 15:53:50 2009 for CERTIDeveloperDocumentation by doxygen 1.5.5