LCOV - code coverage report
Current view: top level - INDI/libcommon - SystemSocket.cpp (source / functions) Coverage Total Hit
Test: MagAOX Lines: 0.0 % 455 0
Test Date: 2026-01-03 21:03:39 Functions: 0.0 % 39 0

            Line data    Source code
       1              : // $Id: SystemSocket.cpp 7418 2009-12-16 22:08:43Z pgrenz $
       2              : ////////////////////////////////////////////////////////////////////////////////
       3              : 
       4              : #include "SystemSocket.hpp"
       5              : #include <unistd.h>
       6              : #include <errno.h>
       7              : #include <iostream>
       8              : #include <sstream>
       9              : #include <sstream>
      10              : #include <sys/types.h>
      11              : #include <string.h> // For 'memset'.
      12              : #include <stdlib.h> // For 'malloc', 'free', etc.
      13              : // For the "TCP_NODELAY" constant.
      14              : #include <netinet/tcp.h>
      15              : // For the "geLocalIP" function:
      16              : #include <sys/socket.h>
      17              : #include <net/if.h>
      18              : #include <sys/ioctl.h>
      19              : #include <net/if_arp.h>
      20              : #include <arpa/inet.h>               // for inet_addr
      21              : // End of includes for the "getLocalIP" function.
      22              : 
      23              : using ::std::string;
      24              : using ::std::vector;
      25              : using pcf::SystemSocket;
      26              : 
      27              : // On the MAC, there is no "MSG_NOSIGNAL" flag. The equivalent is
      28              : // "SO_NOSIGPIPE" (on version 10.2 and later)
      29              : #if defined(__APPLE__)
      30              : //#ifdef __FreeBSD__
      31              : //# if __FreeBSD_version >= 400014
      32              : //#  define s6_addr16 __u6_addr.__u6_addr16
      33              : # if !defined(MSG_NOSIGNAL)
      34              : # define MSG_NOSIGNAL SO_NOSIGPIPE
      35              : # endif
      36              : //# endif
      37              : #endif
      38              : 
      39              : ////////////////////////////////////////////////////////////////////////////////
      40              : /// Basic constructor.
      41              : 
      42            0 : SystemSocket::SystemSocket() : m_tType(UnknownType), m_nLastError(0), m_nSocket(-1),
      43            0 :                                 m_nConnectTimeout(1000), m_nPort(-1), m_oIsNagleDisabled(false), m_oIsBound(false)
      44              : {
      45            0 : }
      46              : 
      47              : ////////////////////////////////////////////////////////////////////////////////
      48              : /// Constructor which sets the socket parameters.
      49              : 
      50            0 : SystemSocket::SystemSocket( const Type &tType,
      51              :                             const int &nPort,
      52            0 :                             const string &szHost ) : m_tType(tType), m_nLastError(0), m_nSocket(-1),
      53            0 :                                                       m_nConnectTimeout(1000), m_szHost(szHost), m_nPort(nPort),
      54            0 :                                                        m_oIsNagleDisabled(false), m_oIsBound(false)
      55              : {
      56            0 : }
      57              : 
      58              : ////////////////////////////////////////////////////////////////////////////////
      59              : /// Basic destructor.
      60              : 
      61            0 : SystemSocket::~SystemSocket()
      62              : {
      63            0 :   if ( isValid() == true )
      64            0 :     close();
      65            0 : }
      66              : 
      67              : ////////////////////////////////////////////////////////////////////////////////
      68              : /// Copy constructor. Initialize this SystemSocket from another one.
      69              : 
      70            0 : SystemSocket::SystemSocket( const SystemSocket &rhs )
      71              : {
      72            0 :   m_tType = rhs.m_tType;
      73            0 :   m_nPort = rhs.m_nPort;
      74            0 :   m_szHost = rhs.m_szHost;
      75              :   // The socket file descriptor should not be copied,
      76              :   // since each must be unique.
      77            0 :   m_nSocket = -1;
      78            0 :   m_nConnectTimeout = rhs.m_nConnectTimeout;
      79              :   // The Nagle algorithm is enabled by default.
      80            0 :   m_oIsNagleDisabled = false;
      81              :   // 'bind' has not been called.
      82            0 :   m_oIsBound = false;
      83              :   // No errors yet!
      84            0 :   m_nLastError = 0;
      85            0 : }
      86              : 
      87              : ////////////////////////////////////////////////////////////////////////////////
      88              : /// Assignment operator. Assigns this object from another SystemSocket object.
      89              : 
      90            0 : const SystemSocket &SystemSocket::operator= ( const SystemSocket &rhs )
      91              : {
      92            0 :   if ( &rhs != this )
      93              :   {
      94              :     // We don't want to keep an fd by mistake.
      95            0 :     if ( isValid() == true )
      96            0 :       close();
      97              : 
      98            0 :     m_tType = rhs.m_tType;
      99            0 :     m_nPort = rhs.m_nPort;
     100            0 :     m_szHost = rhs.m_szHost;
     101              :     // The socket file descriptor should not be copied,
     102              :     // since each must be unique.
     103            0 :     m_nSocket = -1;
     104            0 :     m_nConnectTimeout = rhs.m_nConnectTimeout;
     105              :     // The Nagle algorithm is enabled by default.
     106            0 :     m_oIsNagleDisabled = false;
     107              :     // 'bind' has not been called.
     108            0 :     m_oIsBound = false;
     109              :     // No errors yet!
     110            0 :     m_nLastError = 0;
     111              :   }
     112            0 :   return *this;
     113              : }
     114              : 
     115              : ////////////////////////////////////////////////////////////////////////////////
     116              : //  Returns the type of the socket.
     117              : 
     118            0 : SystemSocket::Type SystemSocket::getType() const
     119              : {
     120            0 :   return m_tType;
     121              : }
     122              : 
     123              : ////////////////////////////////////////////////////////////////////////////////
     124              : //  Returns the last error that occurred when maniplating the socket.
     125              : 
     126            0 : int SystemSocket::getLastError() const
     127              : {
     128            0 :   return m_nLastError;
     129              : }
     130              : 
     131              : ////////////////////////////////////////////////////////////////////////////////
     132              : //  Returns the socket descriptor.
     133              : 
     134            0 : int SystemSocket::getFd() const
     135              : {
     136            0 :   return m_nSocket;
     137              : }
     138              : 
     139              : ////////////////////////////////////////////////////////////////////////////////
     140              : // Returns true if the socket file descriptor is valid, false otherwise.
     141              : 
     142            0 : bool SystemSocket::isValid() const
     143              : {
     144            0 :   return ( bool )( m_nSocket >= 0 );
     145              : }
     146              : 
     147              : ////////////////////////////////////////////////////////////////////////////////
     148              : // Returns true if the socket is bound to a port.
     149              : 
     150            0 : bool SystemSocket::isBound() const
     151              : {
     152            0 :   return m_oIsBound;
     153              : }
     154              : 
     155              : ////////////////////////////////////////////////////////////////////////////////
     156              : // Set the connect timeout in milliseconds.
     157              : 
     158            0 : void SystemSocket::setConnectTimeout( const int &nTimeout )
     159              : {
     160            0 :   m_nConnectTimeout = nTimeout;
     161            0 : }
     162              : 
     163              : ////////////////////////////////////////////////////////////////////////////////
     164              : //  returns the socket host address.
     165              : 
     166            0 : string SystemSocket::getHost() const
     167              : {
     168            0 :   return m_szHost;
     169              : }
     170              : 
     171              : ////////////////////////////////////////////////////////////////////////////////
     172              : //  returns the socket port.
     173              : 
     174            0 : int SystemSocket::getPort() const
     175              : {
     176            0 :   return m_nPort;
     177              : }
     178              : 
     179              : ////////////////////////////////////////////////////////////////////////////////
     180              : ///  Makes a socket call to create a certain type of socket.
     181              : 
     182            0 : void SystemSocket::create()
     183              : {
     184              :   try
     185              :   {
     186              :     // We don't want to keep an fd by mistake.
     187            0 :     if ( isValid() == true )
     188            0 :       close();
     189              : 
     190              :     //  The  domain parameter specifies a communication domain; this selects
     191              :     //  the protocol family which will be used for communication.
     192              :     //  These families are defined in  <sys/socket.h>
     193              :     //  PF_INET:
     194              :     //  IPv4 Internet protocols.
     195              :     //  SOCK_STREAM
     196              :     //  Provides sequenced, reliable, two-way, connection-based byte streams.
     197              :     //  An out-of-band data transmission mechanism may be supported.
     198              : 
     199            0 :     int nTrue = 1;
     200              : 
     201            0 :     switch ( m_tType )
     202              :     {
     203            0 :       case Stream:
     204            0 :         if ( ( m_nSocket = ::socket( AF_INET, SOCK_STREAM, 0 ) ) < 0 )
     205              :         {
     206            0 :           m_nLastError = errno;
     207            0 :           throw ( Error( string( ": " ) + strerror( m_nLastError ) ) );
     208              :         }
     209            0 :         m_oIsBound = false;
     210            0 :         break;
     211            0 :       case Datagram:
     212            0 :         if ( ( m_nSocket = ::socket( AF_INET, SOCK_DGRAM, IPPROTO_UDP ) ) < 0 )
     213              :         {
     214            0 :           m_nLastError = errno;
     215            0 :           throw ( Error( string( ": " ) + strerror( m_nLastError ) ) );
     216              :         }
     217            0 :         setOption( SOL_SOCKET, SO_BROADCAST, &nTrue, sizeof ( nTrue ) );
     218            0 :         m_oIsBound = false;
     219            0 :         break;
     220            0 :       case enumMulticast:
     221            0 :         if ( ( m_nSocket = ::socket( AF_INET, SOCK_DGRAM, IPPROTO_UDP ) ) < 0 )
     222              :         {
     223            0 :           m_nLastError = errno;
     224            0 :           throw ( Error( string( ": " ) + strerror( m_nLastError ) ) );
     225              :         }
     226            0 :         setOption( SOL_SOCKET, SO_REUSEADDR, &nTrue, sizeof ( nTrue ) );
     227            0 :         m_oIsBound = false;
     228            0 :         break;
     229            0 :       default:
     230              :       case UnknownType:
     231            0 :         m_nSocket = -1;
     232            0 :         m_oIsBound = false;
     233              :     }
     234              : 
     235              :   }
     236            0 :   catch ( const Error &err )
     237              :   {
     238            0 :     throw Error( string( "::create" ) + err.what() );
     239            0 :   }
     240            0 : }
     241              : 
     242              : ////////////////////////////////////////////////////////////////////////////////
     243              : /// This function creates a sockaddr_in struct based on the arguments
     244              : /// passed in. "sockaddr_in.sin_addr.s_addr" == INADDR_NONE if there was an error.
     245              : 
     246            0 : sockaddr_in SystemSocket::createSockAddr( const int &nPort,
     247              :                                           const string &szHost )
     248              : {
     249              :   try
     250              :   {
     251              :     sockaddr_in saAddr;
     252            0 :     memset( &saAddr, 0, sizeof ( saAddr ) );
     253              : 
     254            0 :     saAddr.sin_family = AF_INET;
     255            0 :     saAddr.sin_port = htons( nPort );
     256            0 :     saAddr.sin_addr.s_addr = ( szHost.size() == 0 ) ?
     257            0 :         htonl( INADDR_ANY ) : ::inet_addr( szHost.c_str() );
     258              : 
     259              :     // Did 'inet_addr' fail?
     260            0 :     if ( saAddr.sin_addr.s_addr == INADDR_NONE )
     261            0 :       throw ( Error( string( ": " ) + strerror( EINVAL ) ) );
     262              : 
     263            0 :     return saAddr;
     264              :   }
     265            0 :   catch ( const Error &err )
     266              :   {
     267            0 :     throw Error( string( "::createSockAddr" ) + err.what() );
     268            0 :   }
     269              : }
     270              : 
     271              : ////////////////////////////////////////////////////////////////////////////////
     272              : //  This function converts the character string szHost into a network address
     273              : //  structure in the af address family, then copies  the  network  address
     274              : //  structure to psaAddr.
     275              : 
     276            0 : sockaddr_in SystemSocket::convertStrToAddr( const string &szHost )
     277              : {
     278              :   try
     279              :   {
     280              :     sockaddr_in saAddr;
     281              : 
     282            0 :     if ( szHost.length() == 0 )
     283              :     {
     284              :       //  no host specified - use all available interface.
     285            0 :       saAddr.sin_addr.s_addr = htonl( INADDR_ANY );
     286              :     }
     287              :     else
     288              :     {
     289              : #ifdef WIN32
     290              :       char[256] pcAddr;
     291              :       memset( pcAddr, 0, 256 );
     292              :       int nRet = WSAStringToAddress( szHost.c_str(), AF_INET, NULL,
     293              :                                      pcAddr, 256 );
     294              :       memcpy( saAddr.sin_addr, pcAddr, 256 )
     295              :       switch ( nRet )
     296              :       {
     297              :         //  no error
     298              :         case 0:
     299              :           break;
     300              :         //  The specified Address buffer is too small.
     301              :         case WSAEFAULT:
     302              :           throw ( Error( string( "SystemSocket::convertStrToAddr: " ) + strerror( EDQUOT ) ) );
     303              :           break;
     304              :         //  Unable to translate the string into a sockaddr.
     305              :         case WSAEINVAL:
     306              :           throw ( Error( string( "SystemSocket::convertStrToAddr: " ) + strerror( EINVAL ) ) );
     307              :           break;
     308              :         //  The WS2_32.DLL has not been initialized. Call "WSAStartup".
     309              :         case WSANOTINITIALISED:
     310              :           throw ( Error( string( "SystemSocket::convertStrToAddr: " ) + strerror( EBADF ) ) );
     311              :           break;
     312              :         //  There was insufficient memory to perform the operation.
     313              :         case WSA_NOT_ENOUGH_MEMORY:
     314              :           throw ( Error( string( "SystemSocket::create: " ) + strerror( ENOMEM ) ) );
     315              :           break;
     316              :       }
     317              : #else  //  assume linux
     318            0 :       int nRet = inet_pton( AF_INET, szHost.c_str(), static_cast<void *>(&(saAddr.sin_addr)) );
     319            0 :       int nErr = errno;
     320              : 
     321              :       //  Is the input not IPv4 dotted decimal string?
     322            0 :       if ( nRet == 0 )
     323            0 :         throw ( Error( string( ": " ) + strerror( EINVAL ) ) );
     324              : 
     325            0 :       if ( nRet == -1 )
     326            0 :         throw ( Error( string( ": " ) + strerror( nErr ) ) );
     327              : #endif
     328              :     }
     329            0 :     return saAddr;
     330              :   }
     331            0 :   catch ( const Error &err )
     332              :   {
     333            0 :     throw Error( string( "::convertStrToAddr" ) + err.what() );
     334            0 :   }
     335              : }
     336              : 
     337              : ////////////////////////////////////////////////////////////////////////////////
     338              : /// Tries to bind a socket to a port.
     339              : 
     340            0 : void SystemSocket::bind()
     341              : {
     342              :   try
     343              :   {
     344            0 :     if ( isValid() == false )
     345            0 :       create();
     346              : 
     347              :     //  SO_REUSEADDR
     348              :     //  Indicates that the rules used in validating addresses supplied
     349              :     //  in a bind(2) call should allow reuse of local addresses.
     350              :     //  For PF_INET sockets this means that a socket may bind, except when
     351              :     //  there is an active listening socket bound to the address. When the
     352              :     //  listening socket is bound to INADDR_ANY with a specific port then it
     353              :     //  is not possible to bind to this port for any local address.
     354              : 
     355              :     //  try to set a reusable address.
     356            0 :     int nTrue = 1;
     357            0 :     setOption( SOL_SOCKET, SO_REUSEADDR, &nTrue, sizeof( nTrue ) );
     358              : 
     359              :     //  bind gives the socket 'm_nSocket' the local address 'm_saAddr' .
     360              :     //  my_addr is addrlen bytes long.  Traditionally, this is called
     361              :     //  "assigning a name to a socket." When a socket is created with
     362              :     //  socket(2) , it exists in a name space (address family) but has no
     363              :     //  name assigned.
     364              :     //  It is normally necessary to assign a local address using bind before
     365              :     //  a SOCK_STREAM socket may receive connections (see accept(2) ).
     366              :     //  The rules used in name binding vary between address families.
     367              :     //  Consult the manual entries in Section 7 for detailed information.
     368              :     //  For AF_INET see ip(7) , for AF_UNIX see unix(7) ,
     369              :     //  for AF_APPLETALK see ddp(7) , for AF_PACKET see packet(7) ,
     370              :     //  for AF_X25 see x25(7) and for AF_NETLINK see netlink(7) .
     371              : 
     372            0 :     sockaddr_in saAddr = createSockAddr( m_nPort, m_szHost );
     373              : 
     374            0 :     if ( ::bind( m_nSocket, reinterpret_cast<sockaddr *>(&saAddr), sizeof( saAddr ) ) == -1 )
     375              :     {
     376            0 :       m_nLastError = errno;
     377            0 :       throw ( Error( string( ": " ) + strerror( m_nLastError ) ) );
     378              :     }
     379              : 
     380              :     // If we got here, there was no error.
     381            0 :     m_oIsBound = true;
     382              :   }
     383            0 :   catch ( const Error &err )
     384              :   {
     385            0 :     throw Error( string( "::bind" ) + err.what() );
     386            0 :   }
     387            0 : }
     388              : 
     389              : ////////////////////////////////////////////////////////////////////////////////
     390              : ///  Listens for TCP connections.
     391              : 
     392            0 : void SystemSocket::listen()
     393              : {
     394              :   try
     395              :   {
     396            0 :     if ( isBound() == false )
     397            0 :       bind();
     398              : 
     399              :     //  To accept connections, a socket is first created with  socket(2) ,
     400              :     //  a willingness to accept incoming connections and a queue limit for
     401              :     //  incoming connections are specified with  listen , and then the
     402              :     //  connections are accepted with  accept(2) . The  listen call applies
     403              :     //  only to sockets of type  SOCK_STREAM or  SOCK_SEQPACKET .
     404              : 
     405            0 :     if ( ::listen( m_nSocket, enumMaxConnections ) == -1 )
     406              :     {
     407            0 :       m_nLastError = errno;
     408            0 :       throw ( Error( string( ": " ) + strerror( m_nLastError ) ) );
     409              :     }
     410              :   }
     411            0 :   catch ( const Error &err )
     412              :   {
     413            0 :     throw Error( string( "::listen" ) + err.what() );
     414            0 :   }
     415            0 : }
     416              : 
     417              : ////////////////////////////////////////////////////////////////////////////////
     418              : /// Accepts a new connection, passes it to another socket.
     419              : 
     420            0 : void SystemSocket::accept( SystemSocket &socNew )
     421              : {
     422              :   try
     423              :   {
     424            0 :     if ( isBound() == false )
     425            0 :       bind();
     426              : 
     427              :     //  The accept function is used with connection-based socket types
     428              :     //  SOCK_SEQPACKET and  SOCK_RDM ). It extracts the first connection request
     429              :     //  on the queue of pending connections, creates a new connected socket with
     430              :     //  mostly the same properties as, and allocates a new file descriptor
     431              :     //  for the socket, which is returned. The newly created socket is no longer
     432              :     //  in the listening state. The original socket is unaffected by this call.
     433              :     //  Note that any per file descriptor flags (everything that can be set with
     434              :     //  the  F_SETFL fcntl, like non blocking or async state) are not inherited
     435              :     //  across an  accept .
     436              : 
     437              :     sockaddr_in saAddr;
     438            0 :     memset( &saAddr, 0, sizeof ( saAddr ) );
     439            0 :     int nAddrLen = sizeof( saAddr );
     440              : 
     441            0 :     if ( ( socNew.m_nSocket = ::accept( m_nSocket, reinterpret_cast<sockaddr *>(&saAddr),
     442            0 :                                         reinterpret_cast<socklen_t *>(&nAddrLen) ) ) == -1 )
     443              :     {
     444            0 :       m_nLastError = errno;
     445            0 :       throw ( Error( string( ": " ) + strerror( m_nLastError ) ) );
     446              :     }
     447              :   }
     448            0 :   catch ( const Error &err )
     449              :   {
     450            0 :     throw Error( string( "::accept" ) + err.what() );
     451            0 :   }
     452            0 : }
     453              : 
     454              : ////////////////////////////////////////////////////////////////////////////////
     455              : ///  Sends a fixed-size chunk. Returns any error encountered.
     456              : ///  nNumBytes will be modified to reflect the number of bytes actually sent.
     457              : 
     458            0 : void SystemSocket::sendChunk( char *pcData,
     459              :                               int &nNumBytes )
     460              : {
     461              :   try
     462              :   {
     463            0 :     if ( isValid() == false )
     464              :     {
     465            0 :       m_nLastError = EBADF;
     466            0 :       throw ( Error( string( ": " ) + strerror( m_nLastError ) ) );
     467              :     }
     468              : 
     469              :     //  The  send call may be used only when the socket is in a  connected state
     470              :     //  (so that the intended recipient is known). The only difference between
     471              :     //  send and  write is the presence of  flags . With zero  flags parameter,
     472              :     //  send is equivalent to  write . Also,  send( s , buf , len ) is equivalent
     473              :     //  to  sendto( s, buf, len, NULL, 0 ).
     474              :     //  MSG_NOSIGNAL
     475              :     //  Requests not to send SIGPIPE on errors on stream oriented sockets when
     476              :     //  the other end breaks the connection. The EPIPE error is still returned.
     477              : 
     478            0 :     int nSent = 0;
     479            0 :     int nTotalSent = 0;
     480            0 :     for ( nTotalSent = 0; nTotalSent < nNumBytes; nTotalSent += nSent )
     481              :     {
     482            0 :       nSent = ::send( m_nSocket, pcData + nTotalSent,
     483            0 :                       nNumBytes - nTotalSent, MSG_NOSIGNAL );
     484            0 :       m_nLastError = errno;
     485              : 
     486              :       // Was there an error?
     487            0 :       if ( nSent == -1 && m_nLastError != EAGAIN )
     488            0 :         throw ( Error( string( ": " ) + strerror( m_nLastError ) ) );
     489              : 
     490              :       // If we got EAGAIN, go around again, otherwise drop out.
     491            0 :       if ( nSent == -1 && m_nLastError == EAGAIN )
     492            0 :         nSent = 0;
     493              :     }
     494              : 
     495              :     // If we got here, nTotalSent holds how many bytes were sent,
     496              :     // So update nNumBytes to this value. This may not be all the bytes
     497              :     // desired, so this value should be checked.
     498            0 :     nNumBytes = nTotalSent;
     499              :   }
     500            0 :   catch ( const Error &err )
     501              :   {
     502            0 :     throw Error( string( "::sendChunk" ) + err.what() );
     503            0 :   }
     504            0 : }
     505              : 
     506              : ////////////////////////////////////////////////////////////////////////////////
     507              : ///  Sends a fixed-size chunk. Returns any error encountered.
     508              : ///  nNumBytes will be modified to reflect the number of bytes actually sent.
     509              : 
     510            0 : void SystemSocket::sendChunkTo( char *pcData,
     511              :                                 int &nNumBytes )
     512              : {
     513              :   try
     514              :   {
     515            0 :     if ( isValid() == false )
     516            0 :       create();
     517              : 
     518              :     //  we need the sockaddr struct to pass the port and host.
     519            0 :     sockaddr_in saAddr = createSockAddr( m_nPort, m_szHost );
     520              : 
     521              :     //  The sendto() function shall send a message through a connection-mode
     522              :     //  or connectionless-mode socket. If the socket is connectionless-mode,
     523              :     //  the message shall be sent to the address specified by dest_addr. If
     524              :     //  the socket is connection-mode, dest_addr shall be ignored.
     525              : 
     526            0 :     int nRet = ::sendto( m_nSocket, pcData, nNumBytes, 0,
     527            0 :                          reinterpret_cast<const sockaddr *>( &saAddr ), sizeof( saAddr ) );
     528            0 :     m_nLastError = errno;
     529              : 
     530              :     // Was there an error?
     531            0 :     if ( nRet == -1 )
     532            0 :       throw ( Error( string( ": " ) + strerror( m_nLastError ) ) );
     533              : 
     534              :     // Otherwise, we sent some data, but did we send it all?
     535            0 :     if ( nRet < nNumBytes )
     536            0 :       throw ( Error( string( ": " ) + strerror( EMSGSIZE ) ) );
     537              : 
     538              :     // If we got here, we sent all the bytes.
     539            0 :     nNumBytes = nRet;
     540              :   }
     541            0 :   catch ( const Error &err )
     542              :   {
     543            0 :     throw Error( string( "::sendChunkTo" ) + err.what() );
     544            0 :   }
     545            0 : }
     546              : 
     547              : ////////////////////////////////////////////////////////////////////////////////
     548              : ///  Receives a fixed-size chunk. Returns any error encountered. nNumBytes will
     549              : ///  be modified to reflect the number of bytes received.
     550              : 
     551            0 : void SystemSocket::recvChunk( char *pcData,
     552              :                               int &nNumBytes )
     553              : {
     554              :   try
     555              :   {
     556            0 :     if ( isValid() == false )
     557              :     {
     558            0 :       m_nLastError = EBADF;
     559            0 :       throw ( Error( string( ": " ) + strerror( m_nLastError ) ) );
     560              :     }
     561              : 
     562              :     //  The  recvfrom and  recvmsg calls are used to receive messages from a
     563              :     //  socket, and may be used to receive data on a socket whether or not it is
     564              :     //  connection-oriented.
     565              :     //  If from is not NULL, and the underlying protocol provides the source
     566              :     //  address, this source address is filled in. The argument fromlen is a
     567              :     //  value-result parameter, initialized to the size of the buffer associated
     568              :     //  with from , and modified on return to indicate the actual size of the
     569              :     //  address stored there.
     570              :     //  The recv call is normally used only on a connected socket (see connect(2))
     571              :     //  and is identical to recvfrom with a NULL from parameter.
     572              :     //  a flag of EAGAIN can be used to indicate a timeout.
     573              : 
     574            0 :     memset( pcData, 0, nNumBytes );
     575            0 :     int nBytesRead = 0;
     576            0 :     int nBytesLeft = nNumBytes;
     577              : 
     578              :     //  read all the data.
     579            0 :     int nRet = 0;
     580            0 :     while ( nBytesLeft > 0 &&
     581            0 :             ( nRet = ::recv( m_nSocket, pcData + nBytesRead, nBytesLeft, 0 ) ) > 0 )
     582              :     {
     583            0 :       nBytesRead += nRet;
     584            0 :       nBytesLeft -= nRet;
     585              :     }
     586              : 
     587            0 :     m_nLastError = errno;
     588              : 
     589              :     // Was there an error?
     590            0 :     if ( nRet == -1 )
     591            0 :       throw ( Error( string( ": " ) + strerror( m_nLastError ) ) );
     592              : 
     593              :     // Did the peer shut down?
     594            0 :     if ( nRet == 0 )
     595            0 :       throw ( Error( string( ": " ) + strerror( ECONNRESET ) ) );
     596              : 
     597              :     // If we got here, nBytesRead holds how many bytes were read,
     598              :     // So update nNumBytes to this value. This may not be all the bytes
     599              :     // requested, so this value should be checked.
     600            0 :     nNumBytes = nBytesRead;
     601              :   }
     602            0 :   catch ( const Error &err )
     603              :   {
     604            0 :     throw Error( string( "::recvChunk" ) + err.what() );
     605            0 :   }
     606            0 : }
     607              : 
     608              : ////////////////////////////////////////////////////////////////////////////////
     609              : /// Receives a fixed-size chunk. Returns any error encountered. nNumBytes will
     610              : /// be modified to reflect the number of bytes received. In the case of a
     611              : /// multicast, szHost should be "".
     612              : 
     613            0 : void SystemSocket::recvChunkFrom( char *pcData,
     614              :                                   int &nNumBytes )
     615              : {
     616              :   try
     617              :   {
     618            0 :     if ( isValid() == false )
     619            0 :       create();
     620              : 
     621              :     // We need the sockaddr struct to pass the port and host.
     622              :     sockaddr_in saAddr;
     623            0 :     if ( getType() == SystemSocket::enumMulticast )
     624            0 :       saAddr = createSockAddr( m_nPort, "" );
     625              :     else
     626            0 :       saAddr = createSockAddr( m_nPort, m_szHost );
     627              : 
     628              :     // Make sure the data is cleared out.
     629            0 :     memset( pcData, 0, nNumBytes );
     630              : 
     631              :     //  The recvfrom() function shall receive a message from a connection-
     632              :     //  mode or connectionless-mode socket. It is normally used with
     633              :     //  connectionless-mode sockets because it permits the application to
     634              :     //  retrieve the source address of received data.
     635              : 
     636            0 :     socklen_t tSockLen = sizeof( saAddr );
     637            0 :     int nRet = ::recvfrom( m_nSocket, pcData, nNumBytes, MSG_WAITALL,
     638            0 :                            reinterpret_cast<sockaddr *>( &saAddr ), &tSockLen );
     639            0 :     m_nLastError = errno;
     640              : 
     641              :     // Was there an error?
     642            0 :     if ( nRet == -1 )
     643            0 :       throw ( Error( string( ": " ) + strerror( m_nLastError ) ) );
     644              : 
     645              :     // Did the peer shut down?
     646            0 :     if ( nRet == 0 )
     647            0 :       throw ( Error( string( ": " ) + strerror( ECONNRESET ) ) );
     648              : 
     649              :     // If we got here, nRet holds how many bytes were read,
     650              :     // So update nNumBytes to this value. This may not be all the bytes
     651              :     // requested, so this value should be checked.
     652            0 :     nNumBytes = nRet;
     653              :   }
     654            0 :   catch ( const Error &err )
     655              :   {
     656            0 :     throw Error( string( "::recvChunkFrom" ) + err.what() );
     657            0 :   }
     658            0 : }
     659              : 
     660              : ////////////////////////////////////////////////////////////////////////////////
     661              : ///  attempts to send data. Returns an error code.
     662              : 
     663            0 : void SystemSocket::send( const string &szData )
     664              : {
     665              :   try
     666              :   {
     667            0 :     if ( isValid() == false )
     668              :     {
     669            0 :       m_nLastError = EBADF;
     670            0 :       throw ( Error( string( ": " ) + strerror( m_nLastError ) ) );
     671              :     }
     672              : 
     673              :     //  The  send call may be used only when the socket is in a  connected state
     674              :     //  (so that the intended recipient is known). The only difference between
     675              :     //  send and  write is the presence of  flags . With zero  flags parameter,
     676              :     //  send is equivalent to  write . Also,  send( s , buf , len ) is equivalent
     677              :     //  to  sendto( s, buf, len, NULL, 0 ).
     678              :     //  MSG_NOSIGNAL
     679              :     //  Requests not to send SIGPIPE on errors on stream oriented sockets when
     680              :     //  the other end breaks the connection. The EPIPE error is still returned.
     681              : 
     682              :     //  nRet will now hold the number of bytes sent or an error code.
     683            0 :     int nRet = ::send( m_nSocket, szData.c_str(), szData.size(), MSG_NOSIGNAL );
     684              : 
     685            0 :     m_nLastError = errno;
     686              : 
     687              :     // Was there an error?
     688            0 :     if ( nRet == -1 )
     689            0 :       throw ( Error( string( ": " ) + strerror( m_nLastError ) ) );
     690              : 
     691              :     // Otherwise, we sent some data, but did we send it all?
     692            0 :     if ( static_cast<unsigned int>( nRet ) < szData.length() )
     693            0 :       throw ( Error( string( ": " ) + strerror( EMSGSIZE ) ) );
     694              :   }
     695            0 :   catch ( const Error &err )
     696              :   {
     697            0 :     throw Error( string( "::send" ) + err.what() );
     698            0 :   }
     699            0 : }
     700              : 
     701              : ////////////////////////////////////////////////////////////////////////////////
     702              : ///  attempts to send data. Returns an error code.
     703              : 
     704            0 : void SystemSocket::sendTo( const string &szData )
     705              : {
     706              :   try
     707              :   {
     708            0 :     if ( isValid() == false )
     709            0 :       create();
     710              : 
     711              :     //  we need the sockaddr struct to pass the port and host.
     712            0 :     sockaddr_in saAddr = createSockAddr( m_nPort, m_szHost );
     713              : 
     714              :     //  The sendto() function shall send a message through a connection-
     715              :     //  mode or connectionless-mode socket. If the socket is connectionless-
     716              :     //  mode, the message shall be sent to the address specified by dest_addr.
     717              :     //  If the socket is connection-mode, dest_addr shall be ignored.
     718              : 
     719              :     //  nRet will now hold the number of bytes sent or an error code.
     720            0 :     int nRet = ::sendto( m_nSocket, szData.c_str(), szData.size(), 0,
     721            0 :                          reinterpret_cast<sockaddr *>( &saAddr ), sizeof( saAddr ) );
     722            0 :     m_nLastError = errno;
     723              : 
     724              :     // Was there an error?
     725            0 :     if ( nRet == -1 )
     726            0 :       throw ( Error( string( ": " ) + strerror( m_nLastError ) ) );
     727              : 
     728              :     //  Otherwise, we sent some data, but did we send it all?
     729            0 :     if ( static_cast<unsigned int>( nRet ) < szData.length() )
     730            0 :       throw ( Error( string( ": " ) + strerror( EMSGSIZE ) ) );
     731              :   }
     732            0 :   catch ( const Error &err )
     733              :   {
     734            0 :     throw Error( string( "::sendTo" ) + err.what() );
     735            0 :   }
     736            0 : }
     737              : 
     738              : ////////////////////////////////////////////////////////////////////////////////
     739              : 
     740            0 : string SystemSocket::recv()
     741              : {
     742              :   try
     743              :   {
     744            0 :     if ( isValid() == false )
     745              :     {
     746            0 :       m_nLastError = EBADF;
     747            0 :       throw ( Error( string( ": " ) + strerror( m_nLastError ) ) );
     748              :     }
     749              : 
     750              :     //  The  recvfrom and  recvmsg calls are used to receive messages from a
     751              :     //  socket, and may be used to receive data on a socket whether or not it is
     752              :     //  connection-oriented.
     753              :     //  If from is not NULL, and the underlying protocol provides the source
     754              :     //  address, this source address is filled in. The argument fromlen is a
     755              :     //  value-result parameter, initialized to the size of the buffer associated
     756              :     //  with from , and modified on return to indicate the actual size of the
     757              :     //  address stored there.
     758              :     //  The recv call is normally used only on a connected socket (see connect(2))
     759              :     //  and is identical to recvfrom with a NULL from parameter.
     760              :     //  a flag of EAGAIN can be used to indicate a timeout.
     761              : 
     762              :     // Get some memory to hold the data.
     763              :     char pcBuf[ enumMaxRecv + 1 ];
     764            0 :     memset( pcBuf, 0, enumMaxRecv + 1 );
     765              : 
     766            0 :     int nRet = ::recv( m_nSocket, pcBuf, enumMaxRecv, 0 );
     767              : 
     768            0 :     m_nLastError = errno;
     769              : 
     770              :     // Was there an error?
     771            0 :     if ( nRet == -1 )
     772            0 :       throw ( Error( string( ": " ) + strerror( m_nLastError ) ) );
     773              : 
     774              :     // Did the peer shut down?
     775            0 :     if ( nRet == 0 )
     776            0 :       throw ( Error( string( ": " ) + strerror( ECONNRESET ) ) );
     777              : 
     778              :     // Otherwise, this is the number of bytes received.
     779            0 :     return string( pcBuf, nRet );
     780              :   }
     781            0 :   catch ( const Error &err )
     782              :   {
     783            0 :     throw Error( string( "::recv" ) + err.what() );
     784            0 :   }
     785              : }
     786              : 
     787              : ////////////////////////////////////////////////////////////////////////////////
     788              : 
     789            0 : std::string SystemSocket::recvFrom()
     790              : {
     791              :   try
     792              :   {
     793            0 :     if ( isValid() == false )
     794            0 :       create();
     795              : 
     796              :     //  we need the sockaddr struct to pass the port and host.
     797              :     sockaddr_in saAddr;
     798            0 :     if ( getType() == SystemSocket::enumMulticast )
     799            0 :       saAddr = createSockAddr( m_nPort, "" );
     800              :     else
     801            0 :       saAddr = createSockAddr( m_nPort, m_szHost );
     802              : 
     803              :     //  The  recvfrom()  function  shall receive a message from a connection-
     804              :     //  mode or connectionless-mode socket. It is  normally  used  with
     805              :     //  connectionless-mode sockets because it permits the application to
     806              :     //  retrieve the source address of received data.
     807              : 
     808              :     //  get some memory to hold the data.
     809              :     char pcBuf[ enumMaxRecv + 1 ];
     810            0 :     memset( pcBuf, 0, enumMaxRecv + 1 );
     811              : 
     812            0 :     socklen_t tSockLen = sizeof( saAddr );
     813            0 :     int nRet = ::recvfrom( m_nSocket, pcBuf, enumMaxRecv, MSG_WAITALL,
     814            0 :                            ( sockaddr * )( &saAddr ), &tSockLen );
     815            0 :     m_nLastError = errno;
     816              : 
     817              :     // Was there an error?
     818            0 :     if ( nRet == -1 )
     819            0 :       throw ( Error( string( ": " ) + strerror( m_nLastError ) ) );
     820              : 
     821              :     // Did the peer shut down? - this is okay - just return empty data.
     822            0 :     if ( nRet == 0 )
     823            0 :       throw ( Error( string( ": " ) + strerror( ECONNRESET ) ) );
     824              : 
     825              :     // Otherwise, nRet is the number of bytes received.
     826            0 :     return string( pcBuf, nRet );
     827              :   }
     828            0 :   catch ( const Error &err )
     829              :   {
     830            0 :     throw Error( string( "::recvFrom" ) + err.what() );
     831            0 :   }
     832              : }
     833              : 
     834              : ////////////////////////////////////////////////////////////////////////////////
     835              : 
     836            0 : void SystemSocket::connect()
     837              : {
     838              :   try
     839              :   {
     840            0 :     if ( isValid() == false )
     841            0 :       create();
     842              : 
     843              :     //  we need the sockaddr struct to pass the port and host.
     844            0 :     sockaddr_in saAddr = createSockAddr( m_nPort, m_szHost );
     845              : 
     846              :     // we need a set to use with 'select' so we can time-out.
     847              :     fd_set setRead;
     848            0 :     FD_ZERO( &setRead );
     849            0 :     FD_SET( m_nSocket, &setRead );
     850              : 
     851              :     fd_set setWrite;
     852            0 :     FD_ZERO ( &setWrite );
     853            0 :     FD_SET ( m_nSocket, &setWrite );
     854              : 
     855              :     // we need a timeval struct to hold our timeout value.
     856              :     timeval tvTimeout;
     857            0 :     tvTimeout.tv_sec = 3;//m_nConnectTimeout / 1000;
     858            0 :     tvTimeout.tv_usec = m_nConnectTimeout % 1000;
     859              :     // set the socket descriptor to non-blocking BEFORE we call 'connect'.
     860            0 :     setNonBlocking( true );
     861              : 
     862              :     //  The  file descriptor sockfd must refer to a socket.  If the socket
     863              :     //  is of type SOCK_DGRAM then the serv_addr address is the address to
     864              :     //  which datagrams are sent by default, and the only address from which
     865              :     //  datagrams are received.  If the socket is of type SOCK_STREAM or
     866              :     //  SOCK_SEQPACKET,  this call attempts to make a connection to another
     867              :     //  socket.  The other socket is specified by serv_addr, which is an
     868              :     //  address (of length addrlen) in the communications space of the
     869              :     //  socket.  Each communications space interprets the serv_addr
     870              :     //  parameter in its own way.
     871              :     //  Generally, connection-based protocol sockets may successfully
     872              :     //  connect only once; connectionless protocol sockets may use connect
     873              :     //  multiple  times to  change their association.  Connectionless
     874              :     //  sockets may dissolve the association by connecting to an address
     875              :     //  with the sa_family member of sockaddr set to AF_UNSPEC.
     876              : 
     877              :     // Will we connect immediately?
     878            0 :     if ( ::connect( m_nSocket, reinterpret_cast<sockaddr *>(&saAddr), sizeof( saAddr ) ) == -1 )
     879              :     {
     880            0 :       m_nLastError = errno;
     881              : 
     882              :       // The only acceptable error is 'in progress'.
     883            0 :       if ( m_nLastError != EINPROGRESS )
     884            0 :         throw ( Error( string( ": " ) + strerror( m_nLastError ) ) );
     885              : 
     886              :       // Wait for the connection to complete.
     887            0 :       int nNum = ::select( m_nSocket + 1,
     888              :                            &setRead, &setWrite, NULL, &tvTimeout );
     889              : 
     890            0 :       m_nLastError = errno;
     891              : 
     892              :       // Did select have an error?
     893            0 :       if ( nNum < 0 )
     894            0 :         throw ( Error( string( ": " ) + strerror( m_nLastError ) ) );
     895              :       // Did we timeout (no descriptors are ready)?
     896            0 :       if ( nNum == 0 )
     897            0 :         throw ( Error( string( ": " ) + strerror( ETIMEDOUT ) ) );
     898              :       // n > 0 - Are we possibly connected?
     899            0 :       if ( FD_ISSET( m_nSocket, &setWrite ) || FD_ISSET( m_nSocket, &setRead ) )
     900              :       {
     901            0 :         m_nLastError = 0;
     902            0 :         socklen_t nSizeErr = sizeof( m_nLastError );
     903            0 :         getOption( SOL_SOCKET, SO_ERROR, &m_nLastError, nSizeErr );
     904            0 :         if ( m_nLastError != 0 )
     905              :         {
     906            0 :           throw ( Error( string( ": " ) + strerror( m_nLastError ) ) );
     907              :         }
     908              :       }
     909              :     }
     910              :   }
     911            0 :   catch ( const Error &err )
     912              :   {
     913              :     // Make sure we clean up.
     914            0 :     close();
     915            0 :     throw Error( string( "::connect" ) + err.what() );
     916            0 :   }
     917            0 : }
     918              : 
     919              : ////////////////////////////////////////////////////////////////////////////////
     920              : /// Join a multicast group in order to receive data.
     921              : 
     922            0 : void SystemSocket::join()
     923              : {
     924              :   try
     925              :   {
     926            0 :     if ( isBound() == false )
     927            0 :       bind();
     928              : 
     929              :     // use setsockopt() to request that the kernel join a multicast group.
     930              :     struct ip_mreq mreq;
     931            0 :     mreq.imr_multiaddr.s_addr = ::inet_addr( m_szHost.c_str() );
     932            0 :     mreq.imr_interface.s_addr = htonl( INADDR_ANY );
     933              : 
     934            0 :     setOption( IPPROTO_IP, IP_ADD_MEMBERSHIP, &mreq, sizeof( mreq ) );
     935              :   }
     936            0 :   catch ( const Error &err )
     937              :   {
     938            0 :     throw Error( string( "::join" ) + err.what() );
     939            0 :   }
     940            0 : }
     941              : 
     942              : ////////////////////////////////////////////////////////////////////////////////
     943              : 
     944            0 : void SystemSocket::close()
     945              : {
     946              :   try
     947              :   {
     948            0 :     if ( isValid() == false )
     949              :     {
     950            0 :       m_nLastError = EBADF;
     951            0 :       throw ( Error( string( ": " ) + strerror( m_nLastError ) ) );
     952              :     }
     953              : 
     954              :     //  close closes a file descriptor, so that it no longer refers to any file
     955              :     //  and may be reused. Any locks held on the file it was associated with,
     956              :     //  and owned by the process, are removed (regardless of the file
     957              :     //  descriptor that was used to obtain the lock).
     958              : 
     959              : #ifdef WIN32
     960              :     if ( closesocket( m_nSocket ) == -1 )
     961              : #else
     962            0 :     if ( ::close( m_nSocket ) == -1 )
     963              : #endif
     964              :     {
     965              :       //  convert to our error code as necessary.
     966            0 :       m_nLastError = errno;
     967            0 :       throw ( Error( string( ": " ) + strerror( m_nLastError ) ) );
     968              :     }
     969            0 :     m_nSocket = -1;
     970            0 :     m_oIsBound = false;
     971              :   }
     972            0 :   catch ( const Error &err )
     973              :   {
     974            0 :     throw Error( string( "::close" ) + err.what() );
     975            0 :   }
     976            0 : }
     977              : 
     978              : ////////////////////////////////////////////////////////////////////////////////
     979              : 
     980            0 : void SystemSocket::getOption( const int &nLevel,
     981              :                               const int &nOption,
     982              :                               void *pvOptionValue,
     983              :                               socklen_t &nOptionLength )
     984              : {
     985              :   try
     986              :   {
     987            0 :     if ( isValid() == false )
     988              :     {
     989            0 :       m_nLastError = EBADF;
     990            0 :       throw ( Error( string( ": " ) + strerror( m_nLastError ) ) );
     991              :     }
     992              : 
     993            0 :     if ( ::getsockopt( m_nSocket, nLevel, nOption,
     994            0 :                        static_cast<char *>( pvOptionValue ), &nOptionLength ) == -1 )
     995              :     {
     996            0 :       m_nLastError = errno;
     997            0 :       throw ( Error( string( ": " ) + strerror( m_nLastError ) ) );
     998              :     }
     999              :   }
    1000            0 :   catch ( const Error &err )
    1001              :   {
    1002            0 :     throw Error( string( "::setOption" ) + err.what() );
    1003            0 :   }
    1004            0 : }
    1005              : 
    1006              : ////////////////////////////////////////////////////////////////////////////////
    1007              : 
    1008            0 : void SystemSocket::setOption(const int &nLevel,
    1009              :                               const int &nOption,
    1010              :                               void *pvOptionValue,
    1011              :                               const socklen_t &nOptionLength )
    1012              : {
    1013              :   try
    1014              :   {
    1015            0 :     if ( isValid() == false )
    1016              :     {
    1017            0 :       m_nLastError = EBADF;
    1018            0 :       throw ( Error( string( ": " ) + strerror( m_nLastError ) ) );
    1019              :     }
    1020              : 
    1021            0 :     if ( ::setsockopt( m_nSocket, nLevel, nOption,
    1022            0 :                        static_cast<char *>( pvOptionValue ), nOptionLength ) == -1 )
    1023              :     {
    1024            0 :       m_nLastError = errno;
    1025            0 :       throw ( Error( string( ": " ) + strerror( m_nLastError ) ) );
    1026              :     }
    1027              :   }
    1028            0 :   catch ( const Error &err )
    1029              :   {
    1030            0 :     throw Error( string( "::setOption" ) + err.what() );
    1031            0 :   }
    1032            0 : }
    1033              : 
    1034              : ////////////////////////////////////////////////////////////////////////////////
    1035              : 
    1036            0 : void SystemSocket::setRecvTimeout( const int &nMillis )
    1037              : {
    1038              :   try
    1039              :   {
    1040            0 :     if ( isValid() == false )
    1041              :     {
    1042            0 :       m_nLastError = EBADF;
    1043            0 :       throw ( Error( string( ": " ) + strerror( m_nLastError ) ) );
    1044              :     }
    1045              : 
    1046              :     //  create the timeval structure.
    1047              :     timeval tvTimeout;
    1048            0 :     tvTimeout.tv_sec = nMillis / 1000;
    1049            0 :     tvTimeout.tv_usec = nMillis * 1000 - tvTimeout.tv_sec * 1000000;
    1050              : 
    1051            0 :     setOption( SOL_SOCKET, SO_RCVTIMEO, &tvTimeout, sizeof( tvTimeout ) );
    1052              :   }
    1053            0 :   catch ( const Error &err )
    1054              :   {
    1055            0 :     throw Error( string( "::setRecvTimeout" ) + err.what() );
    1056            0 :   }
    1057            0 : }
    1058              : 
    1059              : ////////////////////////////////////////////////////////////////////////////////
    1060              : 
    1061            0 : void SystemSocket::setNonBlocking( const bool &oIsNonBlocking )
    1062              : {
    1063              :   try
    1064              :   {
    1065            0 :     if ( isValid() == false )
    1066              :     {
    1067            0 :       m_nLastError = EBADF;
    1068            0 :       throw ( Error( string( ": " ) + strerror( m_nLastError ) ) );
    1069              :     }
    1070              : 
    1071              : #ifdef WIN32
    1072              :     // Set the socket I/O mode: In this case FIONBIO
    1073              :     // enables or disables the blocking mode for the
    1074              :     // socket based on the numerical value of iMode.
    1075              :     // If uiMode = 0, blocking is enabled;
    1076              :     // If uiMode != 0, non-blocking mode is enabled.
    1077              :     unsigned int uiMode = ( oIsNonBlocking == true ) ? ( 1 ) : ( 0 );
    1078              :     ioctlsocket( m_nSocket, FIONBIO, &uiMode );
    1079              : #else
    1080              :     //  fcntl performs one of various miscellaneous operations on fd.
    1081              :     //  The operation in question is determined by cmd.
    1082              :     //  F_GETFL
    1083              :     //  Read the file descriptor's flags.
    1084            0 :     int nOpts = -1;
    1085            0 :     if ( ( nOpts = ::fcntl( m_nSocket, F_GETFL ) ) == -1 )
    1086              :     {
    1087            0 :       m_nLastError = errno;
    1088            0 :       throw ( Error( string( ": " ) + strerror( m_nLastError ) ) );
    1089              :     }
    1090              : 
    1091              :     // Flip the correct bit in the read value.
    1092            0 :     nOpts = ( oIsNonBlocking == true ) ?
    1093              :             ( nOpts | O_NONBLOCK ) : ( nOpts & ~O_NONBLOCK );
    1094              : 
    1095              :     //  write this updated setting.
    1096            0 :     if ( ::fcntl ( m_nSocket, F_SETFL, nOpts ) == -1 )
    1097              :     {
    1098            0 :       m_nLastError = errno;
    1099            0 :       throw ( Error( string( ": " ) + strerror( m_nLastError ) ) );
    1100              :     }
    1101              : #endif
    1102              :   }
    1103            0 :   catch ( const Error &err )
    1104              :   {
    1105            0 :     throw Error( string( "::setNonBlocking" ) + err.what() );
    1106            0 :   }
    1107            0 : }
    1108              : 
    1109              : ////////////////////////////////////////////////////////////////////////////////
    1110              : /// Returns true if the nagle algorithm is disabled, false otherwise.
    1111              : 
    1112            0 : bool SystemSocket::isNagleDisabled() const
    1113              : {
    1114            0 :   return m_oIsNagleDisabled;
    1115              : }
    1116              : 
    1117              : ////////////////////////////////////////////////////////////////////////////////
    1118              : /// Disables the algorithm that conglomerates lots of
    1119              : /// small sends into a large one.
    1120              : 
    1121            0 : void SystemSocket::disableNagle( const bool &oDisable )
    1122              : {
    1123              :   try
    1124              :   {
    1125            0 :     if ( isValid() == false )
    1126              :     {
    1127            0 :       m_nLastError = EBADF;
    1128            0 :       throw ( Error( string( ": " ) + strerror( m_nLastError ) ) );
    1129              :     }
    1130              : 
    1131              : #ifdef WIN32
    1132              :     // todo: Look up the way to do this in windows.
    1133              : #else
    1134            0 :     int nFlag = ( oDisable == true ) ? ( 1 ) : ( 0 );
    1135            0 :     setOption( IPPROTO_TCP, TCP_NODELAY, &nFlag, sizeof( int ) );
    1136              : #endif
    1137              : 
    1138              :     // If we got here, the state of the nagle algorithm has been updated.
    1139            0 :     m_oIsNagleDisabled = oDisable;
    1140              :   }
    1141            0 :   catch ( const Error &err )
    1142              :   {
    1143            0 :     throw Error( string( "::disableNagle" ) + err.what() );
    1144            0 :   }
    1145            0 : }
    1146              : 
    1147              : ////////////////////////////////////////////////////////////////////////////////
    1148              : //  this function will block until data is ready to be read on the socket.
    1149              : /*
    1150              : int SystemSocket::waitForData()
    1151              : {
    1152              :   try
    1153              :   {
    1154              :     if ( isValid() == false )
    1155              :     {
    1156              :       m_nLastError = EBADF;
    1157              :       throw ( Error( string( ": " ) + strerror( m_nLastError ) ) );
    1158              :     }
    1159              : 
    1160              :     fd_set ReadSet;
    1161              :     FD_ZERO( &ReadSet );
    1162              :     FD_SET( m_nSocket, &ReadSet );
    1163              : 
    1164              :     //  The functions select and pselect wait for a number of file
    1165              :     //  descriptors to change status.
    1166              :     int nRet = ::select( m_nSocket+1, &ReadSet, NULL, NULL, NULL );
    1167              : 
    1168              :     m_nLastError = errno;
    1169              : 
    1170              :     if ( nRet == -1 && m_nLastError == EINTR )
    1171              :     {
    1172              :     }
    1173              :     //  there is possibly data available -
    1174              :     //  or the connection may have been closed.
    1175              :     else if ( FD_ISSET( m_nSocket, &ReadSet ) )
    1176              :     {
    1177              :     }
    1178              :     else if ( nRet < 0 )
    1179              :     {
    1180              :     }
    1181              :     else
    1182              :     {
    1183              :     }
    1184              :   }
    1185              :   catch ( const Error &err )
    1186              :   {
    1187              :     throw Error( string( "::disableNagle" ) + err.what() );
    1188              :   }
    1189              : }
    1190              : */
    1191              : ////////////////////////////////////////////////////////////////////////////////
    1192              : ///  return the message concerning the error.
    1193              : /*
    1194              : string SystemSocket::getErrorMsg( const int &nError )
    1195              : {
    1196              :   switch ( nError )
    1197              :   {
    1198              :     case enumNoError:
    1199              :       return string( "No Error" );
    1200              :       break;
    1201              :     case -EBUSY:
    1202              :       return string( "Unwilling to accept connections" );
    1203              :       break;
    1204              :     case -EEXIST:
    1205              :       return string( "Shut down or already bound to an address" );
    1206              :       break;
    1207              :     case -EADDRINUSE:
    1208              :       return string( "Address already in use" );
    1209              :       break;
    1210              :     case -EADDRNOTAVAIL:
    1211              :       return string( "Address not available" );
    1212              :       break;
    1213              :     case -EAFNOSUPPORT:
    1214              :       return string( "Address not supported" );
    1215              :       break;
    1216              :     case -ECONNABORTED:
    1217              :       return string( "Connection aborted" );
    1218              :       break;
    1219              :     case -ECONNRESET:
    1220              :       return string( "Connection reset by peer" );
    1221              :       break;
    1222              :     case -EALREADY:
    1223              :       return string( "A previous connection attempt has not been completed" );
    1224              :       break;
    1225              :     case -EINPROGRESS:
    1226              :       return string( "Connection cannot be completed immediately" );
    1227              :       break;
    1228              :     case -ECONNREFUSED:
    1229              :       return string( "Connection refused" );
    1230              :       break;
    1231              :     case -ENOTSOCK:
    1232              :       return string( "Descriptor not a socket" );
    1233              :       break;
    1234              :     case -EISDIR:
    1235              :       return string( "An empty pathname was specified" );
    1236              :       break;
    1237              :     case -EDESTADDRREQ:
    1238              :       return string( "Destination address required or socket not bound" );
    1239              :       break;
    1240              :     case -EHOSTUNREACH:
    1241              :       return string( "Host unreachable" );
    1242              :       break;
    1243              :     case EINVAL:
    1244              :       return string( "Invalid parameter" );
    1245              :       break;
    1246              :     case -EBADF:
    1247              :       return string( "Invalid socket descriptor" );
    1248              :       break;
    1249              :     case -EIO:
    1250              :       return string( "IO error" );
    1251              :       break;
    1252              :     case -EPIPE:
    1253              :       return string( "Local shutdown" );
    1254              :       break;
    1255              :     case -EMFILE:
    1256              :       return string( "Max descriptors already open" );
    1257              :       break;
    1258              :     case -ENETDOWN:
    1259              :       return string( "Network down" );
    1260              :       break;
    1261              :     case -ENETUNREACH:
    1262              :       return string( "Network unreachable" );
    1263              :       break;
    1264              :     case -EACCES:
    1265              :       return string( "No Access" );
    1266              :       break;
    1267              :     case -ENOBUFS:
    1268              :       return string( "No buffers available" );
    1269              :       break;
    1270              :     case -ENODATA:
    1271              :       return string( "No out-of-band data available" );
    1272              :       break;
    1273              :     case -ENOTCONN:
    1274              :       return string( "Not connected" );
    1275              :       break;
    1276              :     case -ENOMEM:
    1277              :       return string( "Not enough memory" );
    1278              :       break;
    1279              :     case -EOPNOTSUPP:
    1280              :       return string( "Type and/or protocol is not supported for this operation" );
    1281              :       break;
    1282              :     case -EDQUOT:
    1283              :       return string( "Message too big" );
    1284              :       break;
    1285              :     case -EFBIG:
    1286              :       return string( "Only partial data was received" );
    1287              :       break;
    1288              :     case -EMSGSIZE:
    1289              :       return string( "Only partial data was sent" );
    1290              :       break;
    1291              :     case -ENAMETOOLONG:
    1292              :       return string( "Path name too long" );
    1293              :       break;
    1294              :     case -ENOENT:
    1295              :       return string( "Path does not exist" );
    1296              :       break;
    1297              :     case -ENOTDIR:
    1298              :       return string( "Path is not a directory" );
    1299              :       break;
    1300              :     case -EPROTO:
    1301              :       return string( "Protocol error" );
    1302              :       break;
    1303              :     case -EROFS:
    1304              :       return string( "Read-only file system" );
    1305              :       break;
    1306              :     case -EINTR:
    1307              :       return string( "Interrupt signal received" );
    1308              :       break;
    1309              :     case -EISCONN:
    1310              :       return string( "Socket is already connected" );
    1311              :       break;
    1312              :     case -ELOOP:
    1313              :       return string( "Symbolic loop exists" );
    1314              :       break;
    1315              :     case -EDOM:
    1316              :       return string( "Timeout field too big" );
    1317              :       break;
    1318              :     case -ETIMEDOUT:
    1319              :       return string( "Timed out" );
    1320              :       break;
    1321              :     case -EAGAIN:
    1322              :       return string( "Would block (or timed out)" );
    1323              :       break;
    1324              :     case -EPROTOTYPE:
    1325              :       return string( "Wrong address type" );
    1326              :       break;
    1327              :     case enumUnknownError:
    1328              :       return string( "Unknown error" );
    1329              :       break;
    1330              :   }
    1331              :   return string( "" );
    1332              : }
    1333              : */
    1334              : ////////////////////////////////////////////////////////////////////////////////
    1335              : /// Return the standard host name for the current machine.
    1336              : 
    1337            0 : string SystemSocket::getLocalHostName()
    1338              : {
    1339              :   try
    1340              :   {
    1341              :     char pcHostName[256];
    1342            0 :     memset( pcHostName, 0, 256 );
    1343            0 :     if ( ::gethostname( pcHostName, 255 ) == -1 )
    1344              :     {
    1345            0 :       int nErr = errno;
    1346            0 :       throw ( Error( string( ": " ) + strerror( nErr ) ) );
    1347              :     }
    1348              : 
    1349              :     // if we got here, we got a good hostname.
    1350            0 :     return string( pcHostName );
    1351              :   }
    1352            0 :   catch ( const Error &err )
    1353              :   {
    1354            0 :     throw Error( string( "::getLocalHostName" ) + err.what() );
    1355            0 :   }
    1356              : }
    1357              : 
    1358              : ////////////////////////////////////////////////////////////////////////////////
    1359              : /// Get the interface named 'szName'.
    1360              : /// @param szName The name of the interface.
    1361              : /// @return The interface which corresponds to the name 'szName', or the
    1362              : /// loopback if it is not found.
    1363              : 
    1364            0 : SystemSocket::Interface SystemSocket::getInterface( const string &szName )
    1365              : {
    1366              :   // As a default, our interface is undefined.
    1367            0 :   Interface interface( "", "127.0.0.1", "255.0.0.0" );
    1368              : 
    1369              :   // First, get a vector of all the interfaces.
    1370            0 :   vector<Interface> vecInterfaces;
    1371            0 :   SystemSocket::getInterfaces( vecInterfaces );
    1372              : 
    1373              :   // find the one with the name we want.
    1374            0 :   for ( unsigned int ii = 0; ii < vecInterfaces.size(); ii++ )
    1375              :   {
    1376            0 :     if ( vecInterfaces[ii].getName() == szName )
    1377              :     {
    1378            0 :       interface = vecInterfaces[ii];
    1379            0 :       break;
    1380              :     }
    1381              :   }
    1382              : 
    1383            0 :   return interface;
    1384            0 : }
    1385              : 
    1386              : ////////////////////////////////////////////////////////////////////////////////
    1387              : /// This returns the local interfaces as a vector.
    1388              : /// The return value is the number of interfaces found.
    1389              : 
    1390            0 : int SystemSocket::getInterfaces( vector<SystemSocket::Interface> &vecInterfaces )
    1391              : {
    1392              :   /**
    1393              :     SIOCGIFCONF
    1394              :     Return a list of interface (transport layer) addresses. This currently means
    1395              :     only addresses of the AF_INET (IPv4) family for compatibility. The user
    1396              :     passes a ifconf structure as argument to the ioctl. It contains a pointer to
    1397              :     an array of ifreq structures in ifc_req and its length in bytes in ifc_len.
    1398              :     The kernel fills the ifreqs with all current L3 interface addresses that are
    1399              :     running: ifr_name contains the interface name (eth0:1 etc.), ifr_addr the
    1400              :     address. The kernel returns with the actual length in ifc_len. If ifc_len is
    1401              :     equal to the original length the buffer probably has overflowed and you
    1402              :     should retry with a bigger buffer to get all addresses. When no error occurs
    1403              :     the ioctl returns 0; otherwise -1. Overflow is not an error.
    1404              : 
    1405              :     See: http://www.die.net/doc/linux/man/man7/netdevice.7.html
    1406              :   **/
    1407              : 
    1408              :   // This will be an error (<0) or the number of interfaces (>0).
    1409            0 :   int nError = 0;
    1410              :   ifconf ifc;
    1411              :   sockaddr_in addrSock;
    1412              : 
    1413              :   // Make sure the list is empty.
    1414            0 :   vecInterfaces.clear();
    1415              : 
    1416              :   // Create a fd with the correct protocol.
    1417            0 :   int fdSock = ::socket( AF_INET, SOCK_DGRAM, 0 );
    1418              : 
    1419            0 :   if ( fdSock < 0 )
    1420              :   {
    1421            0 :     nError = -1;
    1422              :   }
    1423              :   else
    1424              :   {
    1425            0 :     int nRetVal = 0;
    1426            0 :     unsigned int uiAmt = 0;
    1427            0 :     memset( &ifc, 0, sizeof( ifc ) );
    1428              : 
    1429              :     // Repeat the ioctl call and resize the data structure until
    1430              :     // it is more than big enough to hold information for all the network
    1431              :     // interfaces. Of course, we will stop if we have an error.
    1432            0 :     while ( nRetVal == 0 &&
    1433            0 :             sizeof( struct ifreq ) * uiAmt <= ( unsigned int )( ifc.ifc_len ) )
    1434              :     {
    1435              :       // Try an increment of 10....
    1436            0 :       uiAmt += 10;
    1437            0 :       ifc.ifc_len = sizeof( struct ifreq ) * uiAmt;
    1438            0 :       ifc.ifc_buf = static_cast<char *>( realloc( ifc.ifc_buf, ifc.ifc_len ) );
    1439              :       // Make the call.
    1440            0 :       nRetVal = ::ioctl( fdSock, SIOCGIFCONF, &ifc );
    1441              :     }
    1442              : 
    1443            0 :     if ( nRetVal < 0 )
    1444              :     {
    1445            0 :       nError = -1;
    1446              :     }
    1447              :     else
    1448              :     {
    1449              :       //std::cout << "Final size is: " << uiAmt << std::endl;
    1450            0 :       ifreq *ifr = ifc.ifc_req;
    1451            0 :       for ( unsigned int ii = 0; ii < uiAmt; ii++ )
    1452              :       {
    1453              :         // The name is set in the struct.
    1454            0 :         string szName( ifr->ifr_name );
    1455              : 
    1456              :         // The IP address is set in the struct.
    1457            0 :         struct in_addr *psia1 = reinterpret_cast<struct in_addr *>( &( ifr->ifr_addr.sa_data[sizeof addrSock.sin_port] ) );
    1458              : 
    1459            0 :         string szIP( string( ::inet_ntoa( *psia1 ) ) );
    1460              : 
    1461              :         // Overwrite the same piece of memory with the broadcast address.
    1462            0 :         nRetVal = ::ioctl( fdSock, SIOCGIFBRDADDR, ifr );
    1463              : 
    1464              :         // The broadcast address has replaced the IP address in the struct.
    1465            0 :         struct in_addr *psia2 = reinterpret_cast<struct in_addr *>( &( ifr->ifr_broadaddr.sa_data[sizeof addrSock.sin_port] ) );
    1466            0 :         string szBCast( string( ::inet_ntoa( *psia2 ) ) );
    1467              : 
    1468              :         // Add this info to our vector.
    1469            0 :         vecInterfaces.push_back( Interface( szName, szIP, szBCast ) );
    1470              : 
    1471              :         //std::cout << "adding: '" << szName << "' '" << szIP
    1472              :         //    << "' '" << szBCast <<"'." << std::endl;
    1473            0 :         ifr++;
    1474            0 :       }
    1475              :       // Return a positive size as the error value (no error).
    1476            0 :       nError = vecInterfaces.size();
    1477              :     }
    1478              :     // Free the memory we allocated.
    1479            0 :     free( ifc.ifc_buf );
    1480              :   }
    1481            0 :   return nError;
    1482              : }
    1483              : 
    1484              : ////////////////////////////////////////////////////////////////////////////////
        

Generated by: LCOV version 2.0-1