terom@185: #ifndef NETWORK_SOCKET_HH terom@185: #define NETWORK_SOCKET_HH terom@185: terom@186: #include "../Error.hh" terom@378: #include "Address.hh" terom@185: terom@378: /* terom@378: * Platform-specific includes terom@378: */ terom@378: #ifndef WIN32 terom@378: // linux terom@378: #include terom@378: #include terom@378: #include terom@378: #include terom@378: terom@378: #define closesocket close terom@378: #else terom@378: #error "This network code won't compile on win32 :)" terom@378: #endif terom@378: terom@185: #include terom@185: #include terom@185: terom@284: /** terom@378: * We use ClanLib's Socket API, but with our own extensions... terom@284: */ terom@378: class NetworkSocket { terom@378: private: terom@378: /** The file descriptor */ terom@378: int fd; terom@378: terom@378: /** Socket domain */ terom@378: int family; terom@378: terom@378: /** Socket type */ terom@378: int socktype; terom@378: terom@378: /** Socket protocol */ terom@378: int protocol; terom@378: terom@378: /** terom@378: * Has the socket been explicitly bind()'d? If so, force ourselves to use this socket in connect(). terom@378: */ terom@378: bool bound; terom@378: terom@378: /** terom@378: * Read/write signals terom@378: */ terom@378: CL_Signal_v0 _sig_read, _sig_write; terom@378: terom@378: public: terom@378: /** terom@378: * Construct a socket of the specific type. Family and protocol can be left as NULL, but type should usually terom@378: * be specified. terom@378: */ terom@378: NetworkSocket (int family, int socktype, int protocol = 0); terom@378: terom@378: /** terom@378: * Create a socket from the given pre-existing fd terom@378: */ terom@378: NetworkSocket (int fd); terom@378: terom@378: /** terom@378: * Force-close the socket if it's still open terom@378: */ terom@378: ~NetworkSocket (void); terom@378: terom@378: private: terom@378: // XXX: nocopy terom@378: terom@378: /** terom@378: * Create a new socket of the given type, unless we already have one terom@378: */ terom@378: void lazy_socket (int family, int type, int protocol); terom@378: terom@378: /** terom@378: * Close, ignoring errors terom@378: */ terom@378: void force_close (void); terom@378: terom@378: public: terom@378: /** terom@378: * Get the socket fd... promise not to break it terom@378: */ terom@378: int get_socket (void) const { return fd; } terom@378: terom@378: /** terom@378: * Bind to a specific local address terom@378: */ terom@378: void bind (const NetworkAddress &addr); terom@378: terom@378: /** terom@378: * Put socket into listen mode terom@378: */ terom@378: void listen (int backlog); terom@378: terom@378: /** terom@378: * Get local address terom@378: */ terom@378: NetworkAddress get_local_address (void); terom@378: terom@378: /** terom@378: * Get remote address terom@378: */ terom@378: NetworkAddress get_remote_address (void); terom@378: terom@378: /** terom@378: * Make send/recv/connect non-blocking terom@378: */ terom@378: void set_nonblocking (bool nonblocking); terom@378: terom@378: /** terom@378: * Accept a new connection, optionally giving the connection's source address terom@378: */ terom@378: NetworkSocket* accept (NetworkAddress *src); terom@378: terom@378: /** terom@378: * Establish a new connection terom@378: */ terom@378: void connect (const NetworkAddress &addr); terom@378: terom@378: /** terom@378: * Send, optionally using the specific destination terom@378: * terom@378: * @return number of bytes sent, zero if busy terom@378: * @throw NetworkSocketError on error terom@378: */ terom@378: size_t send (const char *buf, size_t size, const NetworkAddress *dest = NULL); terom@378: terom@378: /** terom@378: * Recv, optionally storing the source in src terom@378: * terom@378: * @return number of bytes received, zero if none available terom@378: * @throw NetworkSocketEOFError if the connection was closed terom@378: * @throw NetworkSocketError on error terom@378: */ terom@378: size_t recv (char *buf, size_t size, NetworkAddress *src = NULL); terom@378: terom@378: /** terom@378: * Close the socket terom@378: */ terom@378: void close (void); terom@378: terom@378: /** terom@378: * Triggered when socket becomes readable terom@378: */ terom@378: CL_Signal_v0& sig_read (void) { return _sig_read; } terom@378: terom@378: /** terom@378: * Triggered when socket becomes writeable after a send that returned zero terom@378: */ terom@378: CL_Signal_v0& sig_write (void) { return _sig_write; } terom@378: }; terom@185: terom@284: /** terom@284: * Base class for expcetions thrown by socket methods terom@284: */ terom@185: class NetworkSocketError : public Error { terom@185: protected: terom@378: static std::string build_str (const NetworkSocket &socket, const char *op, const char *err); terom@378: terom@378: public: terom@185: NetworkSocketError (const NetworkSocket &socket, const char *op, const char *err); terom@185: }; terom@185: terom@284: /** terom@284: * Errno-enabled exception, most common type of NetworkSocketError terom@284: */ terom@185: class NetworkSocketOSError : public NetworkSocketError { terom@185: public: terom@185: NetworkSocketOSError (const NetworkSocket &socket, const char *op) : terom@185: NetworkSocketError(socket, op, strerror(errno)) { } terom@185: }; terom@185: terom@284: /** terom@284: * Recv returned EOF terom@284: */ terom@185: class NetworkSocketEOFError : public NetworkSocketError { terom@185: public: terom@185: NetworkSocketEOFError (const NetworkSocket &socket, const char *op) : terom@185: NetworkSocketError(socket, op, "EOF") { } terom@185: }; terom@185: terom@185: #endif /* NETWORK_SOCKET_HH */