static const char* version_id =
  "$Id: Socket.cc,v 1.15 1999/10/28 17:11:05 v2kea318 Exp $";

// $Log: Socket.cc,v $
// Revision 1.15  1999/10/28  17:11:05  v2kea318
// Add the port to the ConnectFailure exception.
//
// Revision 1.14  1999/10/19  15:58:55  v2kea318
// *** empty log message ***
//
// Revision 1.13  1999/09/24  16:13:15  v2kea318
// Changed the handling of the SIGPIPE signal.  It's not a good idea to
// throw an exception from a signal handler as one cannot guarantee that there
// is a valid stack to unwind in the exception propogation.  Therefore, simply
// ignore the signal; the ::write will return -1 if any error occurred and
// we check that.
//
// Revision 1.12  1999/08/12  19:24:37  v2kea318
// Do not embed C++ style comments (//) inside C style comments (/* */).
//
// Revision 1.11  1999/07/30  20:44:12  v2kea318
// Converted the code to G++ compliance.
//
// Revision 1.10  1999/07/13  21:19:40  v2kea318
// Handle SIGPIPE signals in the write() method.  We will throw a ClosedSocket
// exception in this case.
//
// Revision 1.9  1999/05/19  18:46:43  v2kea318
// Fixed the read method to correctly handle closed sockets.
//
// Revision 1.8  1999/05/19  15:48:12  v2kea318
// Fixed the write method to correctly determine when the socket is closed.
//
// Revision 1.7  1999/05/10  15:29:52  v2kea318
// In the read method, when failing with a bad number of bytes, supply
// a copy of the data that was read.
//
// Revision 1.6  1999/05/04  20:40:05  v2kea318
// Made the read and write methods const.
//
// Revision 1.5  1999/04/30  21:04:54  v2kea318
// If we read or write 0 bytes to the socket, throw a ClosedSocket exception.
//
// Revision 1.4  1999/04/27  15:45:41  v2kea318
// Use the BadNBytes versions of the IO exceptions.
//
// Revision 1.3  1999/04/27  14:58:13  v2kea318
// Update the use of the hp data field in the base class.
//
// Revision 1.2  1999/04/23  20:30:44  v2kea318
// Fixed up the read code.
//
// Revision 1.1  1999/04/23  19:52:13  v2kea318
// Initial revision
//
//***************************************************************************

#include "Socket.h"
#include <cstring>
#include <csignal>

//***************************************************************************

Socket::Socket(const string& host, int port) : SocketBase(host, port)
{
  // finish building the sa object.
  memcpy(&(sa.sin_addr), hp.data()->h_addr, hp.data()->h_length);

  // finish building the socket.
  build();

  // connect
  if (connect(sock, (const struct sockaddr *) &sa, sizeof sa) < 0)
    throw ConnectFailure(host, port);
}

//***************************************************************************

void Socket::write(const void* data, size_t nbytes) const
{
  /* Ignore SIGPIPE signals.  This signal can be triggered by a write 
     to a closed socket so, to make the system consistent, ignore the signal;
     the return value of ::write will be -1 which we will check and throw
     the appropriate exception.  There is no need to check for EPIPE in
     the global errno because the -1 return value indicates the socket is
     closed, just as SIGPIPE or errno = EPIPE would. */
  signal(SIGPIPE, SIG_IGN);
  long len = ::write(sock, data, nbytes);
  if (len <= 0) throw ClosedSocket();
  if (static_cast<size_t>(len) != nbytes) // cast quiets compiler warnings.
    throw SocketWriteErrorBadNBytes(nbytes, len);
}

//***************************************************************************

void Socket::write(const string& text) const
{
  write(text.c_str(), text.size());
}

//***************************************************************************

void Socket::read(void* data, size_t nbytes) const
{
  long len = ::read(sock, data, nbytes);
  if (len <= 0) throw ClosedSocket();
  if (static_cast<size_t>(len) != nbytes) // cast quiets compiler warnings.
    throw SocketReadErrorBadNBytes(nbytes, len, data);
}

//***************************************************************************

void Socket::read(string& text) const
{
  // set aside a buffer to write to.
  const size_t sz_buff = 1024;
  static char buff[sz_buff];

  // read.
  try {
    read(buff, sz_buff);
  } catch (const SocketReadErrorBadNBytes& s) {
    /* This exception indicates that we read fewer than sz_buff bytes
       from the socket.  But this could be valid; we most likely do not
       know how big the string actually is.  So, just eat it. */
  }

  // return the string.
  text = buff;
}

//***************************************************************************

void read_force(const Socket& s, void* ptr, size_t nbytes)  
{
  char* c_ptr = static_cast<char*>(ptr);
  for (size_t i = 0; i < nbytes; i++) read(s, c_ptr[i]);
}
