/* net6 - Library providing IPv4/IPv6 network access * Copyright (C) 2005, 2006 Armin Burgmeier / 0x539 dev group * * This 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 2 of the License, or (at your option) any later version. * * This 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 library; if not, write to the Free * Software Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. */ #ifndef _NET6_CONNECTION_HPP_ #define _NET6_CONNECTION_HPP_ #include #include #include "non_copyable.hpp" #include "socket.hpp" #include "encrypt.hpp" #include "queue.hpp" #include "packet.hpp" namespace net6 { /** Abstract base connection class. Instantiate net6::connection. */ class connection_base: public sigc::trackable, private non_copyable { public: enum conn_state { UNENCRYPTED, ENCRYPTION_INITIATED_CLIENT, ENCRYPTION_INITIATED_SERVER, ENCRYPTION_REQUESTED_CLIENT, ENCRYPTION_REQUESTED_SERVER, ENCRYPTION_HANDSHAKING, ENCRYPTED, CLOSED }; enum keepalive_state { KEEPALIVE_DISABLED, KEEPALIVE_ENABLED, KEEPALIVE_WAITING }; class fatal: public std::runtime_error { public: fatal(const std::string& error_message): std::runtime_error(error_message) {} }; typedef sigc::signal signal_recv_type; typedef sigc::signal signal_send_type; typedef sigc::signal signal_close_type; typedef sigc::signal signal_encrypted_type; typedef sigc::signal signal_encryption_failed_type; /** @brief Creates a new connection that is initially in closed * state. */ connection_base(); virtual ~connection_base(); /** @brief Connects to the given address if the connection is closed. */ void connect(const address& addr); /** @brief Wraps the given socket into this connection. */ void assign(std::auto_ptr sock, const address& addr); /** Returns the remote internet address. */ const address& get_remote_address() const; /** Returns the underlaying TCP socket object. */ const tcp_client_socket& get_socket() const; /** @brief Sets whether the connection shall send keepalives to the * remote site if the connection is idle. */ void set_enable_keepalives(bool enable); /** @brief Returns whether the connection sends keepalives to the * remote site. */ bool get_enable_keepalives() const; /** Queues a packet to send it to the remote host. */ void send(const packet& pack); /** @brief Requests a secure connection to the remote end. * * signal_encrypted will be emitted when further traffic will be * encrypted. */ void request_encryption(bool as_client); /** @brief Tells to automatically generate dh_params on connection * encryption. * * This function does not generate dh_params immediately but creates * them when needed. * * dh_params are only used on the server side of the encryption. */ void gen_dh_params(); /** @brief Sets the dh params to use when the connection is going * to be encrypted. * * Note that the dh_params are not copied, so they have to exist as * long as the connection exists. * * dh_params are only used on the server side of the encryption. */ void set_dh_params(dh_params& new_params); /** Signal which is emitted when a packet has been received. */ signal_recv_type recv_event() const; /** Signal that is emitted when all available data has been sent. * * TODO: Change this into a send signal for each packet. */ signal_send_type send_event() const; /** Signal which is emitted when the connection has been lost. Note * that the connection is invalid after the close event occured! */ signal_close_type close_event() const; /** Signal which is emitted when the connection is guaranteed to * be encrypted. */ signal_encrypted_type encrypted_event() const; /** @brief Signal that will be emitted when an encryption request * has been denied. */ signal_encryption_failed_type encryption_failed_event() const; protected: virtual void set_select(io_condition cond) = 0; virtual io_condition get_select() const = 0; virtual void set_timeout(unsigned long timeout) = 0; virtual unsigned long get_timeout() const = 0; void on_recv(const packet& pack); void on_send(); void on_close(); queue sendqueue; queue recvqueue; signal_recv_type signal_recv; signal_send_type signal_send; signal_close_type signal_close; signal_encrypted_type signal_encrypted; signal_encryption_failed_type signal_encryption_failed; std::auto_ptr remote_sock; tcp_encrypted_socket_base* encrypted_sock; std::auto_ptr
remote_addr; conn_state state; keepalive_state keepalive; dh_params* params; private: void setup_signal(); void init_impl(); void on_sock_event(io_condition io); void do_io(io_condition io); void begin_handshake(tcp_encrypted_socket_base* sock); void do_recv(const packet& pack); void do_handshake(); void start_keepalive_timer(); void stop_keepalive_timer(); void net_encryption(const packet& pack); void net_encryption_ok(const packet& pack); void net_encryption_failed(const packet& pack); void net_encryption_begin(const packet& pack); void net_ping(const packet& pack); }; /** @brief Connection to another host. */ template class connection: public connection_base { public: typedef Selector selector_type; connection(selector_type& sel); virtual ~connection(); protected: virtual void set_select(io_condition cond); virtual io_condition get_select() const; virtual void set_timeout(unsigned long timeout); virtual unsigned long get_timeout() const; selector_type& selector; }; template connection::connection(selector_type& sel): selector(sel) { } template connection::~connection() { // TODO: Should be done by connection_base dtor? selector.set(*remote_sock, IO_NONE); } template void connection::set_select(io_condition cond) { selector.set(*remote_sock, cond); } template io_condition connection::get_select() const { return selector.get(*remote_sock); } template void connection::set_timeout(unsigned long timeout) { // Set IO_TIMEOUT if necessary io_condition flags = selector.get(*remote_sock); if( (flags & IO_TIMEOUT) == IO_NONE) selector.set(*remote_sock, flags | IO_TIMEOUT); selector.set_timeout(*remote_sock, timeout); } template unsigned long connection::get_timeout() const { return selector.get_timeout(*remote_sock); } } // namespace net6 #endif // _NET6_CONNECTION_HPP_