/* * psocksxx - A C++ wrapper for POSIX sockets * Copyright (C) 2013 Uditha Atukorala * * This software library is free software; you can redistribute it and/or modify * it under the terms of the GNU Lesser General Public License as published by * the Free Software Foundation; either version 3 of the License, or * (at your option) any later version. * * This software library is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU Lesser General Public License for more details. * * You should have received a copy of the GNU Lesser General Public License * along with this software library. If not, see . * */ #ifndef PSOCKSXX_SOCKSTREAMBUF_H #define PSOCKSXX_SOCKSTREAMBUF_H #include #include #include #include #include #include #ifndef SOCKSTREAMBUF_SIZE #define SOCKSTREAMBUF_SIZE 1024 #endif #ifndef SOCKSTREAMBUF_PUTBACK_SIZE #define SOCKSTREAMBUF_PUTBACK_SIZE 8 #endif namespace psocksxx { /** * @brief Socket stream buffer class * * This buffer class associates its both input and output * sequences with an external POSIX socket. */ class sockstreambuf : public std::streambuf { public: /** socket data type definition */ typedef int socket_t; /** socket end-of-file type */ enum eof_t { eof = -1 /*!< end of file */ }; /** socket domains type definition */ enum socket_domain_t { pf_local = PF_LOCAL, /*!< Host-internal protocols */ pf_inet = PF_INET, /*!< Internet version 4 protocols */ pf_route = PF_ROUTE, /*!< Internal Routing protocol */ pf_key = PF_KEY, /*!< Internal key-management function */ pf_inet6 = PF_INET6 /*!< Internet version 6 protocols */ }; /** socket types type definition */ enum socket_type_t { sock_stream = SOCK_STREAM, sock_dgram = SOCK_DGRAM, sock_raw = SOCK_RAW, sock_rdm = SOCK_RDM, sock_seqpacket = SOCK_SEQPACKET }; /** socket protocols type definition */ enum socket_protocol_t { proto_unspec = 0, /*!< Unspecified system default */ ipproto_ip = IPPROTO_IP, /*!< Internet protocol */ ipproto_ipv6 = IPPROTO_IPV6, /*!< Internet Protocol Version 6 */ ipproto_icmp = IPPROTO_ICMP, /*!< Control message protocol */ ipproto_raw = IPPROTO_RAW, /*!< Raw IP Packets Protocol */ ipproto_tcp = IPPROTO_TCP, /*!< Transmission control protocol */ ipproto_udp = IPPROTO_UDP /*!< User datagram protocol */ }; sockstreambuf() throw(); //!< constructor virtual ~sockstreambuf(); //!< destructor /** * @brief overloaded constructor * @param socket socket data * * Create an instance with the passed in sockstreambuf::socket_t * type socket. It is assumed that the socket is initialised and * ready to use. * */ sockstreambuf( socket_t socket ) throw(); /** * @brief get internal socket data * @return socket data * * Returns a read-only reference to the internal POSIX socket * data. * */ const socket_t & socket() const throw(); /** * @brief open a socket * @param domain communications domain for the socket * @param type socket communications type * @param proto socket communications protocol * @throw psocksxx::sockexception socket exception * * Open a socket and initialise socket communications. * */ void open( socket_domain_t domain, socket_type_t type, socket_protocol_t proto = proto_unspec ) throw( sockexception ); /** * @brief close open sockets * * Close any open socket connections used by this buffer. This * will also flush any data in the buffer before closing. * */ void close() throw(); /** * @brief flush the socket output buffer * @return number of characters flushed * @throw psocksxx::socktimeoutexception on socket timeout * * Flush the socket buffer by writing date into the * socket and returns the number of characters flushed. * If the output buffer is empty sockstreambuf::eof is returned. * */ virtual int flush() throw( socktimeoutexception ); /** * @brief initiate a connection on a socket * @param dest_addr destination address to connect to * @param timeout connection timeout value in seconds * @throw psocksxx::sockexception socket exception * @throw psocksxx::socktimeoutexception connection timeout * exception * * Initiate a connection on a socket previously opened using * open() method. If the timeout value is 0 (default) then * the timeouts are ignored. * */ void connect( const sockaddr * dest_addr, unsigned int timeout = 0 ) throw( sockexception, socktimeoutexception ); /** * @brief initiate a connection on a socket * @param dest_addr destination address to connect to * @param timeout connection timeout value as a reference to a * @c timeval structure * * @throw psocksxx::sockexception socket exception * @throw psocksxx::socktimeoutexception connection timeout * exception * * Initiate a connection on a socket previously opened using * open() method. * */ void connect( const sockaddr * dest_addr, timeval * timeout ) throw( sockexception, socktimeoutexception ); /** * @brief bind the socket to a specified address * @param bind_addr address to bind to * @param reuse_addr allow address to be re-used * @throw psocksxx::sockexception socket exception * * After a socket is configured using open() this method can * be used to assign an address to it. If @c reuse_addr is set * to @c true then this will try to re-use the address unless * the address is actively listening. * */ void bind( const sockaddr * bind_addr, bool reuse_addr = false ) throw( sockexception ); /** * @brief make the socket passive and capable of accepting connections * @param backlog maximum length of the queue for pending connections * and defaults to SOMAXCONN (128) defined in @c * * @throw psocksxx::sockexception socket exception * * This method will make the currently opened socket connection * to passive and capable of accepting client connections using accept() * method. * */ void listen( int backlog = SOMAXCONN ) throw( sockexception ); /** * @brief accept a connection on a listening (passive) socket * @throw psocksxx::sockexception socket exception * @return peer socket data structure * * This method will accept incoming connections on a socket * set to be passive using the listen() method. Upon success * this will return the peer socket data structure that can be used * to create a socket stream buffer instance to communicate * with the accepted socket connection. * */ socket_t accept() throw( sockexception ); /** * @brief set the timeout value for the socket * @param sec seconds * @param usec microseconds * @return a reference to the internal timeout structure * * This method will set the timeout for the socket and make this * a non-blocking socket. Note that you cannot clear the timeout * by passing in a 0 timeout, use clear_timeout() method instead. * */ const timeval * timeout( time_t sec, suseconds_t usec ) throw(); /** * @brief clear the timeout value for the socket * @return a reference to the internal timeout structure which will * always be a null-pointer (@c 0) after clearing the timeout * * This will clear any timeout values set for the socket affectively * making this a blocking socket by default. * */ void * clear_timeout() throw(); /** * @brief get the timed-out status * @return boolean @c true if timed-out flag is set or @c false * otherwise. * * Returns the timed-out status. * */ bool timedout() const throw(); protected: /** * @brief initialise internal buffers */ void init_buffers() throw(); /** * @brief cleanup internal buffers */ void cleanup_buffers() throw(); /** * @brief sync data with the socket * @return 0 or -1 to denote success or failure * * Synchronise the buffer with the associated socket * by flushing data from the buffer to the socket. * */ virtual int sync() throw(); /** * @brief consumes the buffer by writing the contents to * the socket * * @param c additional character to consume * @return sockstreambuf::eof to indicate failure or @a c * if successful. * * @throw psocksxx::socktimeoutexception on socket timeout * * * Consumes the buffer contents and writes to the opened socket. * If @a c is not sockstreambuf::eof then @a c is also written * out. * */ virtual int overflow( int c = eof ) throw( socktimeoutexception ); /** * @brief read more data into the buffer from the socket * @return the first character from the buffer or sockstreambuf::eof * if no data is available to read * * @throw psocksxx::socktimeoutexception on socket timeout * * * This reads more data into the buffer from the socket when * the input buffer is empty and returns the next readable * character from the buffer. If the buffer is empty and no * data is available through the socket, this returns sockstreambuf::eof. * */ virtual int underflow() throw( socktimeoutexception ); /** * @brief check for the read/write availability on the socket * @param timeout timeout value reference to a @c timeval structure * @param chk_read check for read availability * @param chk_write check for write availability * @throw psocksxx::sockexception socket exception * @return boolean @c true to denote availability or @c false * if none of the checked actions are available. * * This will check the socket for read and/or write availability. * */ bool ready( timeval * timeout, bool chk_read = true, bool chk_write = true ) throw( sockexception ); private: /** POSIX socket data */ socket_t _socket; size_t _bufsize; size_t _putbacksize; timeval * _timeout; bool _timed_out; void init_defaults() throw(); }; } /* end of namespace psocksxx */ #endif /* !PSOCKSXX_SOCKSTREAMBUF_H */