Free Web Hosting Provider - Web Hosting - E-commerce - High Speed Internet - Free Web Page
Search the Web


// =================================================================
//
//  Copyright (C) 2001 Maciej Sobczak
//  Copyright (C) 2003 Alex Vinokur - minor (cosmetic) changes
//
//  For conditions of distribution and use, see
//  copyright notice in common.h
//
// =================================================================


// #################################################################
//
//  SOFTWARE : C++ Stream-Compatible TCP/IP Sockets Demo Application
//  FILE     : sockets.h
//
//  DESCRIPTION :
//         The wrapper classes that can be used
//         as a iostream-compatible TCP/IP sockets.
//         Classes definition
//
// #################################################################


//////////////////////////
#ifndef INCLUDED_SOCKETS_H
#define INCLUDED_SOCKETS_H
//////////////////////////


// =======================
#if (defined WIN32 || defined __CYGWIN32__)
// --- this is for MS Windows ---
#include <winsock2.h>
typedef int socklen_t;
#else
// --- this is for Linux ---
#include <netinet/in.h>
#endif

#include <streambuf>
#include <stdexcept>
#include <winsock.h>

#include "trace.h"
// =======================


// ------------------------------------
#define BUFSIZE_DEFAULT 2048


// ------------------------------------
// --- exception class which designates 
// --- errors from socket functions
// ------------------------------------
class SocketRunTimeException : public runtime_error
{
  private:
    // this will serve as a message returned from what()
    mutable string   msg_;
    int        errnum_;

  public:
    virtual const char * what() const throw();
    int  errornumber() const throw();

    // Constructor-1
    explicit SocketRunTimeException (const string &what);

    // Destructor
    ~SocketRunTimeException () throw ();

};

// -------------------------------------------
// --- exception class which designates 
// --- logic (programming) errors with sockets
// -------------------------------------------
class SocketLogicException : public logic_error
{
  public:

    // Constructor-1
    explicit SocketLogicException (const string &what);
};


// -----------------------------------------
// --- this class serves as a socket wrapper
// -----------------------------------------
class TCPSocketWrapper
{
  public:
    enum sockstate_type { CLOSED, LISTENING, ACCEPTED, CONNECTED };

  private:
#ifdef WIN32
  // on Windows, socket is represented by the opaque handler
  typedef SOCKET socket_type;
#else
  // on Linux, socket is just a descriptor number
  typedef int socket_type;
#endif

  // proxy helper for syntax:
  // Sock s2(s1.accept());
  class TCPAcceptedSocket
  {
    friend class TCPSocketWrapper;

    private:

      socket_type sock_;
      sockaddr_in addr_;


      // Constructor-1
      TCPAcceptedSocket(socket_type s, sockaddr_in a);

      // --- only copy constructor provided for the proxy
      // --- so that the TCPSocketWrapper::accept can
      // --- successfully return by value
      // Copy Constructor
      TCPAcceptedSocket(const TCPAcceptedSocket& a);

      // assignment not provided
      TCPAcceptedSocket& operator=(const TCPAcceptedSocket& );

  };


  private:
    socket_type      sock_;
    sockaddr_in      sockaddress_;
    sockstate_type   sockstate_;

    // --- not for use
    TCPSocketWrapper(const TCPSocketWrapper& );
    TCPSocketWrapper& operator=(const TCPSocketWrapper& );


  public:

    // Constructor-0
    TCPSocketWrapper();

    // Destructor
    ~TCPSocketWrapper();

    // --- this is provided for syntax
    // --- TCPSocketWrapper s2(s2.accept());
    // Constructor-1
    TCPSocketWrapper(const TCPAcceptedSocket& as);


    // ------------------
    // --- server methods
    // ------------------

    // --- binds and listens on a given port number
    void listen(int port, int backlog = 100);

    // --- accepts the new connection
    // --- it requires the earlier call to listen
    TCPAcceptedSocket accept();


    sockaddr_in   get_sockaddress () const;

    // ------------------
    // --- client methods
    // ------------------

    // --- creates the new connection
    void connect(const char* address, int port);


    // ------------------
    // --- general methods
    // ------------------

    // --- get the current state of the socket wrapper
    sockstate_type state() const;

    // --- get the network address and port number of the socket
    const char * address() const;
    int port() const;

    // --- write data to the socket
    void write(const void *buf, size_t len);

    // --- read data from the socket
    // --- returns the number of bytes read
    size_t read(void *buf, size_t len);

    void close();

}; // TCPSocketWrapper


// ------------------------------------------------------
// --- this class is supposed to serve as a stream buffer 
// --- associated with a socket
// ------------------------------------------------------
template <class charT, class traits = char_traits<charT> >
class TCPStreamBuffer : public basic_streambuf<charT, traits>
{
typedef basic_streambuf<charT, traits> sbuf_type;
typedef typename sbuf_type::int_type   int_type;
typedef charT           char_type;

  public:

    // --- the buffer will take ownership of the socket 
    // --- (ie. it will close it
    // --- in the destructor) if takeowner == true
    // Constructor-1
    explicit TCPStreamBuffer (
      TCPSocketWrapper& sock,
      bool        takeowner = false,
      streamsize     bufsize = BUFSIZE_DEFAULT
      );

    // Destructor
    ~TCPStreamBuffer();


  protected:
    basic_streambuf<charT, traits>* setbuf(char_type *s, streamsize n);
    void _flush();
    int_type   overflow(int_type c = traits::eof());
    int     sync();
    int_type   underflow();

  private:

    // --- not for use
    TCPStreamBuffer(const TCPStreamBuffer& );
    TCPStreamBuffer& operator=(const TCPStreamBuffer& );

    TCPSocketWrapper&   rsocket_;
    bool    ownsocket_;
    char_type*    inbuf_;
    char_type*    outbuf_;
    streamsize    bufsize_;
    size_t     remained_;
    char_type     remainedchar_;
    bool    ownbuffers_;

}; // TCPStreamBuffer


// -------------------------------------------------------------
// --- this class is an ultimate stream associated with a socket
// -------------------------------------------------------------
template <class charT, class traits = char_traits<charT> >
class TCPGenericStream :
   private  TCPStreamBuffer<charT, traits>,
   public   basic_iostream<charT, traits>
{
  public:

    // --- this constructor takes 
    // --- 'ownership' of the socket wrapper if btakeowner == true,
    // --- so that the socket will be closed in the destructor of the
    // --- TCPStreamBuffer object
    // Constructor-1
    explicit TCPGenericStream (
      TCPSocketWrapper& sock,
      bool        takeowner = false
      );

  private:
    // not for use

    // Copy Constructor
    TCPGenericStream(const TCPGenericStream& );

    TCPGenericStream& operator=(const TCPGenericStream& );
};


// -----------------------------------------------------
// --- this is even more specialized for use as a client
// -----------------------------------------------------
template <class charT, class traits = char_traits<charT> >
class TCPGenericClientStream :
   private  TCPSocketWrapper,
   public   TCPGenericStream<charT, traits>
{
  public:

    // Constructor-1
    TCPGenericClientStream(const char *address, int port);

    ~TCPGenericClientStream();   // for testing only

  private:
    // --- not for use

    // Copy Constructor
    TCPGenericClientStream(const TCPGenericClientStream& );

    TCPGenericClientStream& operator=(const TCPGenericClientStream& );
};


// ---------------------------------------------------
// --- helper declarations for narrow and wide streams
// ---------------------------------------------------
typedef TCPGenericStream<char>      TCPStream;
typedef TCPGenericStream<wchar_t>   TCPWStream;
typedef TCPGenericClientStream<char>   TCPClientStream;
typedef TCPGenericClientStream<wchar_t>   TCPWClientStream;

// ---------------------------------------------------------------------
// --- 'portable' code should call those 
// --- on the beginning and end of the program
// --- (Linux/Unix code does not require any initialization and cleanup)
// ---------------------------------------------------------------------
bool socketsInit();  // returns true in success
void socketsEnd();

//////
#endif
//////