text: /**
   * This is originally from Baylor University:
   * http://cs.ecs.baylor.edu/~donahoo/practical/CSockets/practical/
   * 
   * 
   */
  
  #ifndef __SOCKET_INCLUDED__
  #define __SOCKET_INCLUDED__
  
  #include <string>     // For string
  #include <exception>  // For exception class
  
  /**
   *   Signals a problem with the execution of a socket call.
   */
  class SocketException : public std::exception {
  public:
    /**
     *   Construct a SocketException with a explanatory message.
     *   @param message explanatory message
     *   @param incSysMsg true if system message (from strerror(errno))
     *   should be postfixed to the user provided message
     */
    SocketException(const std::string &message, bool inclSysMsg = false)
      throw();
  
    /**
     *   Provided just to guarantee that no exceptions are thrown.
     */
    ~SocketException() throw();
  
    /**
     *   Get the exception message
     *   @return exception message
     */
    const char *what() const throw();
  
  private:
    std::string userMessage;  // Exception message
  };
  
  /**
   *   Base class representing basic communication endpoint
   */
  class Socket {
  public:
    /**
     *   Close and deallocate this socket
     */
    ~Socket();
  
    /**
     *   Get the local address
     *   @return local address of socket
     *   @exception SocketException thrown if fetch fails
     */
    std::string getLocalAddress();
  
    /**
     *   Get the local port
     *   @return local port of socket
     *   @exception SocketException thrown if fetch fails
     */
    unsigned short getLocalPort();
  
    /**
     *   Set the local port to the specified port and the local address
     *   to any interface
     *   @param localPort local port
     *   @exception SocketException thrown if setting local port fails
     */
    void setLocalPort(unsigned short localPort);
  
    /**
     *   Set the local port to the specified port and the local address
     *   to the specified address.  If you omit the port, a random port 
     *   will be selected.
     *   @param localAddress local address
     *   @param localPort local port
     *   @exception SocketException thrown if setting local port or address fails
     */
    void setLocalAddressAndPort(const std::string &localAddress, 
      unsigned short localPort = 0);
  
    /**
     *   If WinSock, unload the WinSock DLLs; otherwise do nothing.  We ignore
     *   this in our sample client code but include it in the library for
     *   completeness.  If you are running on Windows and you are concerned
     *   about DLL resource consumption, call this after you are done with all
     *   Socket instances.  If you execute this on Windows while some instance of
     *   Socket exists, you are toast.  For portability of client code, this is 
     *   an empty function on non-Windows platforms so you can always include it.
     *   @param buffer buffer to receive the data
     *   @param bufferLen maximum number of bytes to read into buffer
     *   @return number of bytes read, 0 for EOF, and -1 for error
     *   @exception SocketException thrown WinSock clean up fails
     */
    static void cleanUp();
  
    /**
     *   Resolve the specified service for the specified protocol to the
     *   corresponding port number in host byte order
     *   @param service service to resolve (e.g., "http")
     *   @param protocol protocol of service to resolve.  Default is "tcp".
     */
    static unsigned short resolveService(const std::string &service,
                                         const std::string &protocol = "tcp");
  
  private:
    // Prevent the user from trying to use value semantics on this object
    Socket(const Socket &sock);
    void operator=(const Socket &sock);
  
  protected:
    int sockDesc;              // Socket descriptor
    Socket(int type, int protocol);
    Socket(int sockDesc);
  };
  
  /**
   *   Socket which is able to connect, send, and receive
   */
  class CommunicatingSocket : public Socket {
  public:
    /**
     *   Establish a socket connection with the given foreign
     *   address and port
     *   @param foreignAddress foreign address (IP address or name)
     *   @param foreignPort foreign port
     *   @exception SocketException thrown if unable to establish connection
     */
    void connect(const std::string &foreignAddress, unsigned short foreignPort);
  
    /**
     *   Write the given buffer to this socket.  Call connect() before
     *   calling send()
     *   @param buffer buffer to be written
     *   @param bufferLen number of bytes from buffer to be written
     *   @exception SocketException thrown if unable to send data
     */
    void send(const void *buffer, int bufferLen);
  
    /**
     *   Read into the given buffer up to bufferLen bytes data from this
     *   socket.  Call connect() before calling recv()
     *   @param buffer buffer to receive the data
     *   @param bufferLen maximum number of bytes to read into buffer
     *   @return number of bytes read, 0 for EOF, and -1 for error
     *   @exception SocketException thrown if unable to receive data
     */
    int recv(void *buffer, int bufferLen);
  
    /**
     *   Get the foreign address.  Call connect() before calling recv()
     *   @return foreign address
     *   @exception SocketException thrown if unable to fetch foreign address
     */
    std::string getForeignAddress();
  
    /**
     *   Get the foreign port.  Call connect() before calling recv()
     *   @return foreign port
     *   @exception SocketException thrown if unable to fetch foreign port
     */
    unsigned short getForeignPort();
  
  protected:
    CommunicatingSocket(int type, int protocol);
    CommunicatingSocket(int newConnSD);
  };
  
  /**
   *   TCP socket for communication with other TCP sockets
   */
  class TCPSocket : public CommunicatingSocket {
  public:
    /**
     *   Construct a TCP socket with no connection
     *   @exception SocketException thrown if unable to create TCP socket
     */
    TCPSocket();
  
    /**
     *   Construct a TCP socket with a connection to the given foreign address
     *   and port
     *   @param foreignAddress foreign address (IP address or name)
     *   @param foreignPort foreign port
     *   @exception SocketException thrown if unable to create TCP socket
     */
    TCPSocket(const std::string &foreignAddress, unsigned short foreignPort);
  
  private:
    // Access for TCPServerSocket::accept() connection creation
    friend class TCPServerSocket;
    TCPSocket(int newConnSD);
  };
  
  /**
   *   TCP socket class for servers
   */
  class TCPServerSocket : public Socket {
  public:
    /**
     *   Construct a TCP socket for use with a server, accepting connections
     *   on the specified port on any interface
     *   @param localPort local port of server socket, a value of zero will
     *                    give a system-assigned unused port
     *   @param queueLen maximum queue length for outstanding 
     *                   connection requests (default 5)
     *   @exception SocketException thrown if unable to create TCP server socket
     */
    TCPServerSocket(unsigned short localPort, int queueLen = 5);
  
    /**
     *   Construct a TCP socket for use with a server, accepting connections
     *   on the specified port on the interface specified by the given address
     *   @param localAddress local interface (address) of server socket
     *   @param localPort local port of server socket
     *   @param queueLen maximum queue length for outstanding 
     *                   connection requests (default 5)
     *   @exception SocketException thrown if unable to create TCP server socket
     */
    TCPServerSocket(const std::string &localAddress, unsigned short localPort,
        int queueLen = 5);
  
    /**
     *   Blocks until a new connection is established on this socket or error
     *   @return new connection socket
     *   @exception SocketException thrown if attempt to accept a new connection fails
     */
    TCPSocket *accept();
  
  private:
    void setListen(int queueLen);
  };
  
  #endif