Listing 3: TCP class hierarchy: selected method implementation


                            // Make sure that a system call went well
                            // If a system call (say, fcntl()) fails
                            // it returns -1 and sets the errno
#define do_well(FX) (void)( (FX) < 0 ? (perror("System error"), \
        _error("Failed system call " #FX " at line %d of ´%s'.\n", \
               __LINE__, __FILE__),0) : 1)

                            // Obtains the IP address of the specified
                            // host. The host name may be specified
                            // either in the dot notation, or as a
                            // host "name".
                            // Name resolution is performed in the
                            // latter case.
IPaddress::IPaddress(const char * host_name)
{
                                // First check to see if the host
                                // name is specified in the IP address
                                // dot notation
  if( (address = inet_addr(host_name)) != (unsigned long)(-1) )
    return;

  struct hostent *host_ptr = ::gethostbyname(host_name);
  if( host_ptr == 0 )
    _error("Host name '%s' cannot be resolved",host_name);
  if( host_ptr->h_addrtype != AF_INET )
    _error("'%s' isn't an Internet site, or so the DNS says",host_name);

  address = *(unsigned long *)(host_ptr->h_addr);
}

                                // Read from the socket returning the
                                // size of the block read
StreamSocket::ReadResult
StreamSocket::read(void  * buffer, const unsigned int len)
{
  assert( status == Good );
  assert( len != 0 );
  ReadResult result = { ::read(socket_handle,buffer,len), Good };
  if( result.len == 0 )
    return result.status = (status = Eof), result;
  if( result.len == (unsigned)(-1L) )
    if( errno == EWOULDBLOCK )
      return result.len = 0, result.status = Nodata, result;
    else
    {
      perror("reading from the socket");
      return result.len = 0, result.status = (status = Failure), result;
    }
  return result;
}

                          // Set blocking/non-blocking I/O
                          // If the blocking i/o is set, reading
                          // on socket blocks the process until
                          // the packet arrives. If i/o is non-blocking,
                          // read() returns -1 with errno=EWOULDBLOCK
                          // if there is nothing to read
void  StreamSocket::set_blocking_io(const BOOL onoff)
{
  int arg = fcntl(socket_handle,F_GETFL,0);
  do_well( arg );
  do_well( fcntl(socket_handle,F_SETFL,onoff ? arg & ~FNDELAY :
                 arg | FNDELAY) );
}

                             // Enable/disable SIGIO upon arriving of a
                             // new packet
void StreamSocket::enable_sigio(const BOOL onoff)
{
  int arg = fcntl(socket_handle,F_GETFL,0);
  do_well( arg );
  do_well( fcntl(socket_handle,F_SETFL,onoff ? arg | FASYNC :
                 arg & ~FASYNC) );
  if( onoff )                    // Tell which process should get SIGIO
    do_well( fcntl(socket_handle,F_SETOWN,getpid()) );
}

//End of File