src/Network/Socket.hh
author terom
Mon, 15 Dec 2008 23:56:42 +0000
changeset 378 5589abf5e61b
parent 284 27ce69fd1e06
child 380 d193dd1d8a7e
permissions -rw-r--r--
break the network code. Too late to set up a branch for this now
#ifndef NETWORK_SOCKET_HH
#define NETWORK_SOCKET_HH

#include "../Error.hh"
#include "Address.hh"

/*
 * Platform-specific includes
 */
#ifndef WIN32
    // linux
    #include <sys/types.h>
    #include <sys/socket.h>
    #include <unistd.h>
    #include <fcntl.h>
    
    #define closesocket close
#else
    #error "This network code won't compile on win32 :)"
#endif

#include <cerrno>
#include <cstring>

/**
 * We use ClanLib's Socket API, but with our own extensions...
 */
class NetworkSocket {
    private:
        /** The file descriptor */
        int fd;

        /** Socket domain */
        int family;

        /** Socket type */
        int socktype;

        /** Socket protocol */
        int protocol;

        /** 
         * Has the socket been explicitly bind()'d? If so, force ourselves to use this socket in connect().
         */
        bool bound;

        /**
         * Read/write signals
         */
        CL_Signal_v0 _sig_read, _sig_write;

    public:
        /**
         * Construct a socket of the specific type. Family and protocol can be left as NULL, but type should usually
         * be specified.
         */
        NetworkSocket (int family, int socktype, int protocol = 0);
        
        /**
         * Create a socket from the given pre-existing fd
         */
        NetworkSocket (int fd);

        /**
         * Force-close the socket if it's still open
         */
        ~NetworkSocket (void);

    private:
        // XXX: nocopy
        
        /**
         * Create a new socket of the given type, unless we already have one
         */
        void lazy_socket (int family, int type, int protocol);
        
        /**
         * Close, ignoring errors
         */
        void force_close (void);

    public:
        /**
         * Get the socket fd... promise not to break it
         */
        int get_socket (void) const { return fd; }

        /**
         * Bind to a specific local address
         */ 
        void bind (const NetworkAddress &addr);

        /**
         * Put socket into listen mode
         */
        void listen (int backlog);

        /**
         * Get local address
         */
        NetworkAddress get_local_address (void); 

        /**
         * Get remote address
         */
        NetworkAddress get_remote_address (void); 

        /**
         * Make send/recv/connect non-blocking
         */
        void set_nonblocking (bool nonblocking);

        /**
         * Accept a new connection, optionally giving the connection's source address
         */
        NetworkSocket* accept (NetworkAddress *src);

        /**
         * Establish a new connection
         */
        void connect (const NetworkAddress &addr);

        /**
         * Send, optionally using the specific destination
         *
         * @return number of bytes sent, zero if busy
         * @throw NetworkSocketError on error
         */
        size_t send (const char *buf, size_t size, const NetworkAddress *dest = NULL);

        /**
         * Recv, optionally storing the source in src
         *
         * @return number of bytes received, zero if none available
         * @throw NetworkSocketEOFError if the connection was closed
         * @throw NetworkSocketError on error
         */
        size_t recv (char *buf, size_t size, NetworkAddress *src = NULL);

        /**
         * Close the socket
         */
        void close (void);

        /**
         * Triggered when socket becomes readable
         */
        CL_Signal_v0& sig_read (void) { return _sig_read; }

        /**
         * Triggered when socket becomes writeable after a send that returned zero
         */
        CL_Signal_v0& sig_write (void) { return _sig_write; }
};

/**
 * Base class for expcetions thrown by socket methods
 */
class NetworkSocketError : public Error {
    protected:
        static std::string build_str (const NetworkSocket &socket, const char *op, const char *err);
    
    public:
        NetworkSocketError (const NetworkSocket &socket, const char *op, const char *err);
};

/**
 * Errno-enabled exception, most common type of NetworkSocketError
 */
class NetworkSocketOSError : public NetworkSocketError {
    public:
        NetworkSocketOSError (const NetworkSocket &socket, const char *op) :
            NetworkSocketError(socket, op, strerror(errno)) { }
};

/**
 * Recv returned EOF
 */
class NetworkSocketEOFError : public NetworkSocketError {
    public:
        NetworkSocketEOFError (const NetworkSocket &socket, const char *op) :
            NetworkSocketError(socket, op, "EOF") { }
};

#endif /* NETWORK_SOCKET_HH */