mirror of
https://github.com/wesnoth/wesnoth
synced 2025-05-15 02:19:05 +00:00
585 lines
19 KiB
C++
585 lines
19 KiB
C++
/* $Id$ */
|
|
|
|
/**
|
|
* @file
|
|
* @brief Header file for network features using ana.
|
|
*
|
|
* Copyright (C) 2010 - 2011 Guillermo Biset.
|
|
*
|
|
* Part of the Battle for Wesnoth Project http://www.wesnoth.org/
|
|
*
|
|
* This program is free software; you can redistribute it and/or modify
|
|
* it under the terms of the GNU General Public License as published by
|
|
* the Free Software Foundation; either version 2 of the License, or
|
|
(at your option) any later version.
|
|
* This program is distributed in the hope that it will be useful,
|
|
* but WITHOUT ANY WARRANTY.
|
|
*
|
|
* See the COPYING file for more details.
|
|
*/
|
|
|
|
#include <set>
|
|
#include <queue>
|
|
|
|
#include <boost/thread.hpp>
|
|
#include <boost/variant.hpp>
|
|
|
|
#include "network.hpp"
|
|
#include "ana/api/ana.hpp"
|
|
|
|
#ifndef NETWORK_MANAGER_ANA_HPP_INCLUDED
|
|
#define NETWORK_MANAGER_ANA_HPP_INCLUDED
|
|
|
|
/**
|
|
* A representative of a network component to the application.
|
|
*/
|
|
class ana_component
|
|
{
|
|
public:
|
|
/** Constructs a server component. */
|
|
ana_component( );
|
|
|
|
~ana_component( );
|
|
|
|
/**
|
|
* Constructs a client component.
|
|
*
|
|
* @param host : The hostname to which it is supposed to connect to.
|
|
* @param port : The port it is supposed to connect to.
|
|
*/
|
|
ana_component( const std::string& host, const std::string& port);
|
|
|
|
/** Get network upload statistics for this component. */
|
|
network::statistics get_send_stats() const;
|
|
|
|
/** Get network download statistics for this component. */
|
|
network::statistics get_receive_stats() const;
|
|
|
|
/**
|
|
* Get the pointer to an ana::server object for this component.
|
|
*
|
|
* @pre : This component is a server.
|
|
*/
|
|
ana::server* server() const;
|
|
|
|
/**
|
|
* Get the pointer to an ana::client object for this component.
|
|
*
|
|
* @pre : This component is a client.
|
|
*/
|
|
ana::client* client() const;
|
|
|
|
/**
|
|
* Get the pointer to an ana::listener object for this component.
|
|
* Both an ana::client an the ana::server are listeners.
|
|
*/
|
|
ana::detail::listener* listener() const;
|
|
|
|
/** Returns true iff this component is a server. */
|
|
bool is_server() const;
|
|
|
|
/** Returns true iff this component is a client. */
|
|
bool is_client() const;
|
|
|
|
/** Returns this component's id. */
|
|
ana::net_id get_id() const;
|
|
|
|
network::connection get_wesnoth_id() const;
|
|
|
|
void set_wesnoth_id( network::connection ) ;
|
|
|
|
/** Returns a pointer to the ana::stats object for accumulated network stats. */
|
|
const ana::stats* get_stats( ana::stat_type type = ana::ACCUMULATED ) const;
|
|
|
|
/** Push a buffer to the queue of incoming messages. */
|
|
void add_buffer(ana::read_buffer buffer, ana::net_id id);
|
|
|
|
/**
|
|
* Blocking operation to wait for a message in a component.
|
|
*
|
|
* @returns The buffer that was received first from all pending buffers.
|
|
*/
|
|
ana::read_buffer wait_for_element();
|
|
|
|
/** Returns the network id of the oldest sender of a pending buffer. */
|
|
network::connection oldest_sender_id_still_pending();
|
|
|
|
/** Returns true iff. the component has a read buffer ready that hasn't been returned. */
|
|
bool new_buffer_ready(); // non const due to mutex blockage
|
|
|
|
private:
|
|
boost::variant<ana::server*, ana::client*> base_;
|
|
|
|
bool is_server_;
|
|
|
|
ana::net_id id_;
|
|
network::connection wesnoth_id_;
|
|
|
|
//Buffer queue attributes
|
|
boost::mutex mutex_;
|
|
boost::condition_variable condition_;
|
|
|
|
std::queue< ana::read_buffer > buffers_;
|
|
std::queue< network::connection > sender_ids_;
|
|
};
|
|
|
|
typedef std::set<ana_component*> ana_component_set;
|
|
|
|
/**
|
|
* Manages connected client ids for a given server.
|
|
*/
|
|
class clients_manager : public ana::connection_handler
|
|
{
|
|
public:
|
|
/** Constructor. */
|
|
clients_manager( ana::server* );
|
|
|
|
/** Returns the amount of components connected to this server. */
|
|
size_t client_amount() const;
|
|
|
|
void connected( ana::net_id id );
|
|
|
|
void remove( ana::net_id id );
|
|
|
|
void handshaked( ana::net_id id );
|
|
|
|
bool has_connection_pending() const;
|
|
|
|
bool is_pending_handshake( ana::net_id ) const;
|
|
|
|
bool is_a_client( ana::net_id id ) const;
|
|
|
|
network::connection get_pending_connection_id();
|
|
|
|
private:
|
|
virtual void handle_connect(ana::error_code error, ana::net_id client);
|
|
|
|
virtual void handle_disconnect(ana::error_code /*error*/, ana::net_id client);
|
|
|
|
ana::server* server_; // the server managing these clients
|
|
|
|
std::set< ana::net_id > ids_;
|
|
std::set< network::connection > pending_ids_;
|
|
std::set< ana::net_id > pending_handshakes_;
|
|
};
|
|
|
|
/**
|
|
* To use the asynchronous library synchronously, objects of this
|
|
* type lock a mutex until enough calls have been made to the
|
|
* associated handler.
|
|
*/
|
|
class ana_send_handler : public ana::send_handler
|
|
{
|
|
public:
|
|
/**
|
|
* Constructs a handler object.
|
|
* @param calls [optional, default 1] : The amount of calls to the handler expected.
|
|
*/
|
|
ana_send_handler( size_t calls = 1 );
|
|
|
|
/** Destructor, checks that the necessary calls were made. */
|
|
~ana_send_handler();
|
|
|
|
/** Locks current thread until all the calls are made. */
|
|
void wait_completion();
|
|
|
|
const ana::error_code& error() const
|
|
{
|
|
return error_code_;
|
|
}
|
|
|
|
private:
|
|
virtual void handle_send(ana::error_code, ana::net_id, ana::operation_id);
|
|
|
|
boost::mutex mutex_;
|
|
size_t target_calls_;
|
|
ana::error_code error_code_;
|
|
};
|
|
|
|
class ana_handshake_finisher_handler : public ana::send_handler
|
|
{
|
|
public:
|
|
ana_handshake_finisher_handler( ana::server*, clients_manager* );
|
|
|
|
~ana_handshake_finisher_handler();
|
|
private:
|
|
|
|
virtual void handle_send(ana::error_code, ana::net_id, ana::operation_id);
|
|
|
|
ana::server* server_;
|
|
clients_manager* manager_;
|
|
};
|
|
|
|
|
|
/**
|
|
* To use the asynchronous library synchronously, objects of this
|
|
* type lock a mutex until enough calls have been made to the
|
|
* associated handler.
|
|
*/
|
|
class ana_receive_handler : public ana::listener_handler
|
|
{
|
|
public:
|
|
/**
|
|
* Constructs a reader handler object.
|
|
*/
|
|
ana_receive_handler( ana_component_set::iterator );
|
|
|
|
/** Destructor. */
|
|
~ana_receive_handler();
|
|
|
|
/**
|
|
* Attempts to read from those network components associated with this
|
|
* handler object up until timeout_ms milliseconds.
|
|
*
|
|
* If the timeout parameter is 0, it will lock the current thread until
|
|
* one of these components has received a message.
|
|
*
|
|
* @param component : A network component running an io_service which
|
|
* supports timeout capabilities.
|
|
* @param timeout_ms : Amount of milliseconds to timeout the operation.
|
|
*/
|
|
void wait_completion(ana::detail::timed_sender* component, size_t timeout_ms = 0);
|
|
|
|
/** Returns the error_code from the operation. */
|
|
const ana::error_code& error() const
|
|
{
|
|
return error_code_;
|
|
}
|
|
|
|
private:
|
|
virtual void handle_receive (ana::error_code, ana::net_id, ana::read_buffer);
|
|
virtual void handle_disconnect(ana::error_code, ana::net_id);
|
|
|
|
void handle_timeout(ana::error_code error_code);
|
|
|
|
ana_component_set::iterator iterator_;
|
|
|
|
boost::mutex mutex_;
|
|
boost::mutex handler_mutex_;
|
|
boost::mutex timeout_called_mutex_;
|
|
ana::error_code error_code_;
|
|
ana::timer* receive_timer_;
|
|
bool finished_;
|
|
};
|
|
|
|
/**
|
|
* To use the asynchronous library synchronously, objects of this
|
|
* type lock a mutex until enough calls have been made to the
|
|
* associated handler.
|
|
*/
|
|
class ana_multiple_receive_handler : public ana::listener_handler
|
|
{
|
|
public:
|
|
/**
|
|
* Constructs a reader handler object.
|
|
*/
|
|
ana_multiple_receive_handler( ana_component_set& components );
|
|
|
|
/** Destructor. */
|
|
~ana_multiple_receive_handler();
|
|
|
|
/**
|
|
* Attempts to read from those network components associated with this
|
|
* handler object up until timeout_ms milliseconds.
|
|
*
|
|
* If the timeout parameter is 0, it will lock the current thread until
|
|
* one of these components has received a message.
|
|
*
|
|
* @param component : A network component running an io_service
|
|
* which supports timeout capabilities.
|
|
* @param timeout_ms : Amount of milliseconds to timeout the operation.
|
|
*/
|
|
void wait_completion(size_t timeout_ms = 0);
|
|
|
|
/** Returns the error_code from the operation. */
|
|
const ana::error_code& error() const
|
|
{
|
|
return error_code_;
|
|
}
|
|
|
|
/** Returns the buffer from the operation. */
|
|
ana::read_buffer buffer() const
|
|
{
|
|
return buffer_;
|
|
}
|
|
|
|
network::connection get_wesnoth_id() const
|
|
{
|
|
return wesnoth_id_;
|
|
}
|
|
|
|
private:
|
|
virtual void handle_receive (ana::error_code, ana::net_id, ana::read_buffer);
|
|
virtual void handle_disconnect(ana::error_code, ana::net_id);
|
|
|
|
void handle_timeout(ana::error_code error_code);
|
|
|
|
ana_component_set& components_;
|
|
|
|
boost::mutex mutex_;
|
|
boost::mutex handler_mutex_;
|
|
boost::mutex timeout_called_mutex_;
|
|
ana::error_code error_code_;
|
|
ana::read_buffer buffer_;
|
|
network::connection wesnoth_id_;
|
|
ana::timer* receive_timer_;
|
|
bool finished_;
|
|
};
|
|
|
|
|
|
|
|
/**
|
|
* To use the asynchronous library synchronously, objects of this
|
|
* type lock a mutex until enough calls have been made to the
|
|
* associated handler.
|
|
*/
|
|
class ana_connect_handler : public ana::connection_handler
|
|
{
|
|
public:
|
|
/**
|
|
* Constructs a connection handler.
|
|
*
|
|
* @param timer : A pointer to a running timer dealing with the timeout
|
|
* of this connect operation.
|
|
*/
|
|
ana_connect_handler( );
|
|
|
|
/** Destructor. */
|
|
~ana_connect_handler();
|
|
|
|
/**
|
|
* Checks if an error occurred during the connection procedure.
|
|
*
|
|
* @returns Error code of the operation.
|
|
*/
|
|
const ana::error_code& error() const;
|
|
|
|
/** Locks current thread until the connection attempt has finished. */
|
|
void wait_completion();
|
|
|
|
private:
|
|
virtual void handle_connect(ana::error_code error_code, ana::net_id /*client*/);
|
|
|
|
boost::mutex mutex_;
|
|
ana::error_code error_code_;
|
|
};
|
|
|
|
/**
|
|
* Provides network functionality for Wesnoth using the ana API and library.
|
|
*/
|
|
class ana_network_manager : public ana::listener_handler,
|
|
public ana::send_handler
|
|
{
|
|
public:
|
|
/** Constructor. */
|
|
ana_network_manager();
|
|
|
|
/**
|
|
* Create a server component and return it's ID.
|
|
*
|
|
* @returns The ID of the new created server.
|
|
*/
|
|
ana::net_id create_server( );
|
|
|
|
/**
|
|
* Create a client component and return it's network connection number.
|
|
*
|
|
* @returns The ID of the new created client, as a network::connection number.
|
|
*/
|
|
network::connection create_client_and_connect(std::string host, int port);
|
|
|
|
network::connection new_connection_id( );
|
|
|
|
/**
|
|
* Get the associated stats of a given component.
|
|
*
|
|
* @param connection_num : The ID of the network component.
|
|
*
|
|
* @returns A pointer to an ana::stats object of the given component.
|
|
*/
|
|
const ana::stats* get_stats( network::connection connection_num = 0,
|
|
ana::stat_type type = ana::ACCUMULATED);
|
|
|
|
/** Close all connections and clean up memory. */
|
|
void close_connections_and_cleanup();
|
|
|
|
/** Throw a Client Disconnected network::error if a disconnection hasn't been informed. */
|
|
void throw_if_pending_disconnection();
|
|
|
|
/**
|
|
* Start a server on a given port.
|
|
*
|
|
* @param id : The ID of the server component.
|
|
* @param port : The port on which to listen for new connections.
|
|
*/
|
|
void run_server(ana::net_id id, int port);
|
|
|
|
/** Get the IP address of a connected component by it's ID. */
|
|
std::string ip_address( network::connection id );
|
|
|
|
/** The amount of connected components to every server object created. */
|
|
size_t number_of_connections() const;
|
|
|
|
/** Send data to all created components. */
|
|
size_t send_all( const config& cfg );
|
|
|
|
/** Send data to the component with a given ID. */
|
|
size_t send( network::connection connection_num , const config& cfg );
|
|
|
|
size_t send_raw_data( const char*, size_t, network::connection);
|
|
|
|
void send_all_except(const config& cfg, network::connection connection_num);
|
|
|
|
/**
|
|
* Read a message from a given component or from every one.
|
|
*
|
|
* @param connection_num : The id of the network component, 0 to read from every component.
|
|
* @param cfg : The config input to place the read data.
|
|
* @param timeout_ms : Amount of milliseconds to wait for the data.
|
|
*
|
|
* @returns The network::connection number of the component that read
|
|
* the data or 0 if an error occurred.
|
|
*/
|
|
network::connection read_from( network::connection connection_num,
|
|
config& cfg,
|
|
size_t timeout_ms = 0 );
|
|
|
|
/**
|
|
* Read a message from a given component or from every one.
|
|
*
|
|
* @param it : The ana component to read from.
|
|
* @param cfg : The config input to place the read data.
|
|
* @param timeout_ms : Amount of milliseconds to wait for the data.
|
|
*
|
|
* @returns The network::connection number of the component that read
|
|
* the data or 0 if an error occurred.
|
|
*/
|
|
network::connection read_from( const ana_component_set::iterator& it,
|
|
config& cfg,
|
|
size_t timeout_ms = 0 );
|
|
|
|
network::connection read_from_all( std::vector<char>& );
|
|
|
|
/**
|
|
* Read a message from a given component or from every one.
|
|
*
|
|
* @param it : The ana component to read from.
|
|
* @param cfg : The config input to place the read data.
|
|
*
|
|
* @returns The network::connection number of the component that read
|
|
* the data or 0 if an error occurred.
|
|
*/
|
|
network::connection read_from_ready_buffer( const ana_component_set::iterator& it,
|
|
config& cfg);
|
|
|
|
/** Retrieve upload statistics on a given component. */
|
|
network::statistics get_send_stats(network::connection handle);
|
|
|
|
/** Retrieve download statistics on a given component. */
|
|
network::statistics get_receive_stats(network::connection handle);
|
|
|
|
/**
|
|
* Disconnect a given client.
|
|
*
|
|
* @param handle : The ID of the component (should be a client) to be disconnected.
|
|
*/
|
|
bool disconnect( network::connection handle);
|
|
|
|
//@{
|
|
/**
|
|
* Attempt to connect through a proxy (as opposed to directly.)
|
|
*
|
|
* Use the set_proxy_* methods to configure the connection options.
|
|
*/
|
|
void enable_connection_through_proxy();
|
|
|
|
/**
|
|
* Set the address of the proxy. Default: "localhost".
|
|
*
|
|
* @param address: Network address where the proxy server should be running.
|
|
*/
|
|
void set_proxy_address ( const std::string& address );
|
|
|
|
/**
|
|
* Set the port of the proxy. Default: "3128".
|
|
*
|
|
* @param port: Network port where the proxy server should be listening.
|
|
*/
|
|
void set_proxy_port ( const std::string& port );
|
|
|
|
/**
|
|
* Set the user to authenticate with the proxy. Default: "".
|
|
*
|
|
* @param user: User name to use for authentication purposes.
|
|
*/
|
|
void set_proxy_user ( const std::string& user );
|
|
|
|
/**
|
|
* Set the password to authenticate with the proxy. Default: "".
|
|
*
|
|
* @param password: Password to use for authentication purposes.
|
|
*/
|
|
void set_proxy_password( const std::string& password );
|
|
//@}
|
|
private:
|
|
virtual void handle_send(ana::error_code, ana::net_id, ana::operation_id);
|
|
|
|
virtual void handle_receive( ana::error_code error,
|
|
ana::net_id client,
|
|
ana::read_buffer buffer);
|
|
|
|
virtual void handle_disconnect(ana::error_code /*error_code*/, ana::net_id client);
|
|
|
|
struct proxy_settings
|
|
{
|
|
proxy_settings() :
|
|
enabled(false),
|
|
address(),
|
|
port(),
|
|
user(),
|
|
password()
|
|
{
|
|
}
|
|
|
|
bool enabled;
|
|
std::string address;
|
|
std::string port;
|
|
std::string user;
|
|
std::string password;
|
|
};
|
|
|
|
/**
|
|
* Pack a config object to an outpt stream using compression.
|
|
*
|
|
* @param cfg : The config object as input.
|
|
* @param out : The output stream as output.
|
|
*/
|
|
void compress_config( const config& cfg, std::ostringstream& out);
|
|
|
|
std::string compress_config( const config& cfg);
|
|
|
|
/**
|
|
* Read a config object from an input buffer.
|
|
*
|
|
* @param buffer : The buffer with the compressed stream as input.
|
|
* @param cfg : The config object as output.
|
|
*/
|
|
void read_config( const ana::read_buffer& buffer, config& cfg);
|
|
|
|
// Attributes
|
|
ana::timer* connect_timer_;
|
|
ana_component_set components_;
|
|
|
|
std::map< ana::server*, clients_manager* > server_manager_;
|
|
|
|
/** Clients that have disconnected from servers (used for client applications.) */
|
|
std::queue< ana_component* > disconnected_components_;
|
|
|
|
/** Client IDs that have disconnected from a serve (used in servers applications.) */
|
|
std::queue< ana::net_id > disconnected_ids_;
|
|
|
|
proxy_settings proxy_settings_;
|
|
};
|
|
|
|
#endif
|