// =================================================================
//
// 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
//////