/* 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 <memory>
#include <sigc++/signal.h>
#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<void, const packet&> signal_recv_type;
typedef sigc::signal<void> signal_send_type;
typedef sigc::signal<void> signal_close_type;
typedef sigc::signal<void> signal_encrypted_type;
typedef sigc::signal<void> 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<tcp_client_socket> 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<tcp_client_socket> remote_sock;
tcp_encrypted_socket_base* encrypted_sock;
std::auto_ptr<address> 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<typename Selector>
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<typename Selector>
connection<Selector>::connection(selector_type& sel):
selector(sel)
{
}
template<typename Selector>
connection<Selector>::~connection()
{
// TODO: Should be done by connection_base dtor?
selector.set(*remote_sock, IO_NONE);
}
template<typename Selector>
void connection<Selector>::set_select(io_condition cond)
{
selector.set(*remote_sock, cond);
}
template<typename Selector>
io_condition connection<Selector>::get_select() const
{
return selector.get(*remote_sock);
}
template<typename Selector>
void connection<Selector>::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<typename Selector>
unsigned long connection<Selector>::get_timeout() const
{
return selector.get_timeout(*remote_sock);
}
} // namespace net6
#endif // _NET6_CONNECTION_HPP_
syntax highlighted by Code2HTML, v. 0.9.1