Commit 6a2b8d31 authored by louiz’'s avatar louiz’

Far better architecturing in network module

- Renamed interface_* files and classes
- io_service is correctly owned by the correct classes and initialized first
- No more pointer used for sockets to work around the previous bad design
parent d8cc3d68
/**
* A very simple base class that must be inherited by all network object
* that needs their own ioservice (for example anything that has a socket,
* or a timer, etc). But not by class that need to share a io_service that
* was created earlier. Basically, this means only Server, Client and
* GameClient should inherite this. All remote_client etc need to share the
* Server's io_service.
*/
#ifndef BASE_IOSERVICE
# define BASE_IOSERVICE
#include <boost/asio.hpp>
class BaseIoservice
{
public:
explicit BaseIoservice() {}
~BaseIoservice() {}
/**
* Returns a reference to the io_service object, so other affiliated
* objects can use it to create some io-related objects.
*/
boost::asio::io_service& get_io_service()
{
return this->io_service;
}
protected:
boost::asio::io_service io_service;
private:
BaseIoservice(const BaseIoservice&) = delete;
BaseIoservice(BaseIoservice&&) = delete;
BaseIoservice& operator=(const BaseIoservice&) = delete;
BaseIoservice& operator=(BaseIoservice&&) = delete;
};
#endif // BASE_IOSERVICE
/**
* A very simple base class that must be inherited by all network object
* that needs a socket.
* If an io_service is provided, we use it. Otherwise we use our own
* io_service.
*/
#ifndef BASE_SOCKET
# define BASE_SOCKET
#include <boost/asio.hpp>
class BaseSocket
{
public:
explicit BaseSocket(boost::asio::io_service& io_service):
socket(io_service) {}
const boost::asio::ip::tcp::socket& get_socket() const
{
return this->socket;
}
boost::asio::ip::tcp::socket& get_socket()
{
return this->socket;
}
~BaseSocket() {}
protected:
boost::asio::ip::tcp::socket socket;
private:
BaseSocket(const BaseSocket&) = delete;
BaseSocket(BaseSocket&&) = delete;
BaseSocket& operator=(const BaseSocket&) = delete;
BaseSocket& operator=(BaseSocket&&) = delete;
};
#endif // BASE_SOCKET
...@@ -9,12 +9,12 @@ ...@@ -9,12 +9,12 @@
#ifndef __CLIENT_HPP__ #ifndef __CLIENT_HPP__
# define __CLIENT_HPP__ # define __CLIENT_HPP__
#include <network/interface_client.hpp> #include <network/client_base.hpp>
#include <network/transfer_receiver.hpp> #include <network/transfer_receiver.hpp>
using boost::asio::ip::tcp; using boost::asio::ip::tcp;
class Client: public InterfaceClient class Client: public ClientBase
{ {
public: public:
Client(); Client();
......
#include <logging/logging.hpp> #include <logging/logging.hpp>
#include <network/interface_client.hpp> #include <network/client_base.hpp>
#include <boost/algorithm/string.hpp> #include <boost/algorithm/string.hpp>
#if defined(_WIN32) || defined(_WIN64) #if defined(_WIN32) || defined(_WIN64)
# include <WinBase.h> # include <WinBase.h>
...@@ -13,59 +13,59 @@ static void poll_timeout_handler(const boost::system::error_code&) ...@@ -13,59 +13,59 @@ static void poll_timeout_handler(const boost::system::error_code&)
{ {
} }
InterfaceClient::InterfaceClient(): ClientBase::ClientBase():
BaseIoservice(),
CommandHandler(io_service),
timeout(io_service) timeout(io_service)
{ {
this->socket = new tcp::socket(io_service);
} }
InterfaceClient::~InterfaceClient() ClientBase::~ClientBase()
{ {
if (this->socket->is_open()) if (this->socket.is_open())
{ {
log_debug("Closing connection"); log_debug("Closing connection");
this->socket->close(); this->socket.close();
} }
delete this->socket;
} }
// Connect, asyncly, and call one of the given callbacks // Connect, asyncly, and call one of the given callbacks
void InterfaceClient::connect(const std::string& host, void ClientBase::connect(const std::string& host,
const short& port, const short& port,
std::function< void(void) > on_success, std::function< void(void) > on_success,
std::function< void(void) > on_failure) std::function< void(void) > on_failure)
{ {
// TODO use resolve and DNS // TODO use resolve and DNS
tcp::endpoint endpoint(boost::asio::ip::address::from_string(host), port); boost::asio::ip::tcp::endpoint endpoint(boost::asio::ip::address::from_string(host), port);
this->socket->async_connect(endpoint, this->socket.async_connect(endpoint,
std::bind(&InterfaceClient::connect_handler, this, std::bind(&ClientBase::connect_handler, this,
on_success, on_failure, on_success, on_failure,
std::placeholders::_1)); std::placeholders::_1));
log_info("Connecting to " << host << ":" << port); log_info("Connecting to " << host << ":" << port);
} }
void InterfaceClient::connect_handler(std::function< void(void) > on_success, void ClientBase::connect_handler(std::function< void(void) > on_success,
std::function< void(void) > on_failure, std::function< void(void) > on_failure,
const boost::system::error_code& error) const boost::system::error_code& error)
{ {
if (error) if (error)
{ {
log_info("Connection failed: " << error); log_info("Connection failed: " << error);
if (on_failure) if (on_failure)
on_failure(); on_failure();
} }
else else
{ {
log_info("Connected."); log_info("Connected.");
this->install_callback("PING", std::bind(&InterfaceClient::ping_callback, this, std::placeholders::_1)); this->install_callback("PING", std::bind(&ClientBase::ping_callback, this, std::placeholders::_1));
this->install_callbacks(); this->install_callbacks();
this->install_read_handler(); this->install_read_handler();
if (on_success) if (on_success)
on_success(); on_success();
} }
} }
void InterfaceClient::ping_callback(Command*) void ClientBase::ping_callback(Command*)
{ {
log_debug("Received PING"); log_debug("Received PING");
...@@ -74,12 +74,7 @@ void InterfaceClient::ping_callback(Command*) ...@@ -74,12 +74,7 @@ void InterfaceClient::ping_callback(Command*)
this->send(command); this->send(command);
} }
boost::asio::io_service& InterfaceClient::get_io_service() void ClientBase::poll(long timeout)
{
return this->io_service;
}
void InterfaceClient::poll(long timeout)
{ {
if (timeout == 0) if (timeout == 0)
{ {
......
...@@ -7,30 +7,29 @@ ...@@ -7,30 +7,29 @@
* Connects to the remote server, sends requests to it and * Connects to the remote server, sends requests to it and
* calls the appropriate callbacks when the answer is received (or * calls the appropriate callbacks when the answer is received (or
* when a standalone command is received from the server) * when a standalone command is received from the server)
* @class InterfaceClient * @class ClientBase
*/ */
#include <boost/asio.hpp>
#include <functional> #include <functional>
#include <string> #include <string>
#include <cstdlib> #include <cstdlib>
#ifndef __INTERFACE_CLIENT_HPP__ #ifndef __CLIENT_BASE_HPP__
# define __INTERFACE_CLIENT_HPP__ # define __CLIENT_BASE_HPP__
#include <network/base_ioservice.hpp>
#include <network/command_handler.hpp> #include <network/command_handler.hpp>
#include <network/ping_handler.hpp> #include <network/ping_handler.hpp>
#include <network/timed_event_handler.hpp> #include <network/timed_event_handler.hpp>
#include <network/command.hpp> #include <network/command.hpp>
#include <network/timed_event.hpp> #include <network/timed_event.hpp>
using boost::asio::ip::tcp; class ClientBase: public BaseIoservice, public CommandHandler,
public TimedEventHandler, public PingHandler
class InterfaceClient: public CommandHandler, public TimedEventHandler, public PingHandler
{ {
public: public:
InterfaceClient(); ClientBase();
~InterfaceClient(); ~ClientBase();
/** /**
* Tries to connect to the remote server. Calls one of the given callbacks, if it * Tries to connect to the remote server. Calls one of the given callbacks, if it
* succeeds or fails. * succeeds or fails.
...@@ -52,7 +51,6 @@ public: ...@@ -52,7 +51,6 @@ public:
void poll(long timeout = 0); void poll(long timeout = 0);
virtual void on_connection_closed() = 0; virtual void on_connection_closed() = 0;
virtual boost::asio::io_service& get_io_service();
private: private:
void connect_handler(std::function< void(void) >, void connect_handler(std::function< void(void) >,
...@@ -63,7 +61,6 @@ private: ...@@ -63,7 +61,6 @@ private:
*/ */
void ping_callback(Command*); void ping_callback(Command*);
boost::asio::io_service io_service;
boost::asio::deadline_timer timeout; boost::asio::deadline_timer timeout;
}; };
......
...@@ -2,7 +2,8 @@ ...@@ -2,7 +2,8 @@
#include <network/command_handler.hpp> #include <network/command_handler.hpp>
#include <network/command.hpp> #include <network/command.hpp>
CommandHandler::CommandHandler(): CommandHandler::CommandHandler(boost::asio::io_service& io_service):
BaseSocket(io_service),
writing(false) writing(false)
{ {
} }
...@@ -103,7 +104,7 @@ void CommandHandler::read_handler(const boost::system::error_code& error, const ...@@ -103,7 +104,7 @@ void CommandHandler::read_handler(const boost::system::error_code& error, const
// We check what we need to read on the socket to have the rest of the binary datas // We check what we need to read on the socket to have the rest of the binary datas
const std::size_t length_to_read = this->data.size() >= size ? 0 : size - this->data.size(); const std::size_t length_to_read = this->data.size() >= size ? 0 : size - this->data.size();
boost::asio::async_read(*this->socket, boost::asio::async_read(this->socket,
this->data, this->data,
boost::asio::transfer_at_least(length_to_read), boost::asio::transfer_at_least(length_to_read),
std::bind(&CommandHandler::binary_read_handler, this, std::bind(&CommandHandler::binary_read_handler, this,
...@@ -137,7 +138,7 @@ void CommandHandler::binary_read_handler(const boost::system::error_code& error, ...@@ -137,7 +138,7 @@ void CommandHandler::binary_read_handler(const boost::system::error_code& error,
void CommandHandler::install_read_handler(void) void CommandHandler::install_read_handler(void)
{ {
boost::asio::async_read_until(*this->socket, boost::asio::async_read_until(this->socket,
this->data, this->data,
':', ':',
std::bind(&CommandHandler::read_handler, this, std::bind(&CommandHandler::read_handler, this,
...@@ -179,7 +180,7 @@ void CommandHandler::actually_send(Command* command) ...@@ -179,7 +180,7 @@ void CommandHandler::actually_send(Command* command)
std::vector<boost::asio::const_buffer> buffs; std::vector<boost::asio::const_buffer> buffs;
buffs.push_back(boost::asio::buffer(command->header.data(), command->header.length())); buffs.push_back(boost::asio::buffer(command->header.data(), command->header.length()));
buffs.push_back(boost::asio::buffer(command->body, command->body_size)); buffs.push_back(boost::asio::buffer(command->body, command->body_size));
async_write(*this->socket, async_write(this->socket,
buffs, buffs,
std::bind(&CommandHandler::send_handler, this, std::bind(&CommandHandler::send_handler, this,
std::placeholders::_1, std::placeholders::_1,
......
...@@ -9,27 +9,27 @@ ...@@ -9,27 +9,27 @@
* @class CommandHandler * @class CommandHandler
*/ */
#ifndef __COMMAND_HANDLER_HPP__
# define __COMMAND_HANDLER_HPP__
#include <deque> #include <deque>
#include <map> #include <map>
#include <functional> #include <functional>
#include <boost/asio.hpp>
#ifndef __COMMAND_HANDLER_HPP__ #include <boost/asio.hpp>
# define __COMMAND_HANDLER_HPP__
#include <network/transfer_sender.hpp> #include <network/transfer_sender.hpp>
#include <network/base_socket.hpp>
#include <network/command.hpp> #include <network/command.hpp>
using boost::asio::ip::tcp;
typedef std::function<void(Command*)> t_read_callback; typedef std::function<void(Command*)> t_read_callback;
typedef std::deque<Command*> command_queue; typedef std::deque<Command*> command_queue;
class CommandHandler class CommandHandler: public BaseSocket
{ {
friend void TransferSender::send_next_chunk(); friend void TransferSender::send_next_chunk();
public: public:
CommandHandler(); explicit CommandHandler(boost::asio::io_service&);
virtual ~CommandHandler(); virtual ~CommandHandler();
void install_read_handler(); void install_read_handler();
...@@ -104,8 +104,6 @@ protected: ...@@ -104,8 +104,6 @@ protected:
*/ */
virtual void on_connection_closed() = 0; virtual void on_connection_closed() = 0;
tcp::socket* socket;
private: private:
CommandHandler(const CommandHandler&); CommandHandler(const CommandHandler&);
CommandHandler& operator=(const CommandHandler&); CommandHandler& operator=(const CommandHandler&);
......
...@@ -11,11 +11,11 @@ ...@@ -11,11 +11,11 @@
#ifndef __GAME_CLIENT_HPP__ #ifndef __GAME_CLIENT_HPP__
# define __GAME_CLIENT_HPP__ # define __GAME_CLIENT_HPP__
#include <network/interface_client.hpp> #include <network/client_base.hpp>
using boost::asio::ip::tcp; using boost::asio::ip::tcp;
class GameClient: public InterfaceClient class GameClient: public ClientBase
{ {
public: public:
GameClient(); GameClient();
...@@ -32,7 +32,6 @@ private: ...@@ -32,7 +32,6 @@ private:
void connect_handler(std::function< void(void) >, void connect_handler(std::function< void(void) >,
std::function< void(void) >, std::function< void(void) >,
const boost::system::error_code&); const boost::system::error_code&);
boost::asio::io_service io_service;
}; };
#endif /*__CLIENT_HPP__ */ #endif /*__CLIENT_HPP__ */
......
...@@ -3,8 +3,8 @@ ...@@ -3,8 +3,8 @@
#include <database/db_object.hpp> #include <database/db_object.hpp>
RemoteClient::RemoteClient(boost::asio::io_service& io_service, RemoteClient::RemoteClient(boost::asio::io_service& io_service,
Server<RemoteClient>* server): Server<RemoteClient>* server):
InterfaceRemoteClient(io_service), RemoteClientBase(io_service),
server(server), server(server),
user(nullptr) user(nullptr)
{ {
...@@ -114,11 +114,6 @@ void RemoteClient::on_connection_closed() ...@@ -114,11 +114,6 @@ void RemoteClient::on_connection_closed()
this->server->remove_client(this); this->server->remove_client(this);
} }
boost::asio::io_service& RemoteClient::get_io_service()
{
return this->server->io_service;
}
void RemoteClient::on_transfer_ended(const TransferSender* transfer) void RemoteClient::on_transfer_ended(const TransferSender* transfer)
{ {
log_debug("on_transfer_ended"); log_debug("on_transfer_ended");
......
...@@ -14,21 +14,18 @@ ...@@ -14,21 +14,18 @@
#include <boost/asio.hpp> #include <boost/asio.hpp>
#include <functional> #include <functional>
#include <network/interface_remote_client.hpp> #include <network/remote_client_base.hpp>
#include <network/transfer_sender.hpp> #include <network/transfer_sender.hpp>
#include <network/server.hpp> #include <network/server.hpp>
#include <database/user.hpp> #include <database/user.hpp>
using boost::asio::ip::tcp; class RemoteClient: public RemoteClientBase
class RemoteClient: public InterfaceRemoteClient
{ {
public: public:
RemoteClient(boost::asio::io_service&, Server<RemoteClient>*); explicit RemoteClient(boost::asio::io_service&, Server<RemoteClient>*);
~RemoteClient(); ~RemoteClient();
virtual void on_connection_closed(); virtual void on_connection_closed();
virtual boost::asio::io_service& get_io_service();
/** /**
* Sends a file to the remote client. * Sends a file to the remote client.
* @param filename The file to send. * @param filename The file to send.
......
#include <logging/logging.hpp> #include <logging/logging.hpp>
#include <network/interface_remote_client.hpp> #include <network/remote_client_base.hpp>
#include <database/database.hpp> #include <database/database.hpp>
#include <database/db_object.hpp> #include <database/db_object.hpp>
unsigned long int InterfaceRemoteClient::clients_number = 0; unsigned long int RemoteClientBase::clients_number = 0;
InterfaceRemoteClient::InterfaceRemoteClient(boost::asio::io_service& io_service): RemoteClientBase::RemoteClientBase(boost::asio::io_service& io_service):
number(InterfaceRemoteClient::clients_number++) CommandHandler(io_service),
number(RemoteClientBase::clients_number++),
io_service(io_service)
{ {
this->socket = new tcp::socket(io_service);
} }
InterfaceRemoteClient::~InterfaceRemoteClient() RemoteClientBase::~RemoteClientBase()
{ {
log_info("Deleting remote client " << this->number); log_info("Deleting remote client " << this->number);
delete this->socket;
} }
tcp::socket& InterfaceRemoteClient::get_socket(void) void RemoteClientBase::start()
{ {
return *this->socket; log_debug("Starting RemoteClientBase " << this->number);
}
void InterfaceRemoteClient::start()
{
log_debug("Starting InterfaceRemoteClient " << this->number);
this->install_callbacks(); this->install_callbacks();
this->install_timed_event(std::bind(&InterfaceRemoteClient::send_ping, this), 2); this->install_timed_event(this->io_service, std::bind(&RemoteClientBase::send_ping, this), 2);
CommandHandler::install_read_handler(); CommandHandler::install_read_handler();
} }
void InterfaceRemoteClient::send_ping() void RemoteClientBase::send_ping()
{ {
Command* command = new Command; Command* command = new Command;
command->set_name("PING"); command->set_name("PING");
this->request_answer(command, std::bind(&InterfaceRemoteClient::on_pong, this, std::placeholders::_1), "PONG"); this->request_answer(command, std::bind(&RemoteClientBase::on_pong, this, std::placeholders::_1), "PONG");
this->ping_sent(); this->ping_sent();
} }
void InterfaceRemoteClient::on_pong(Command*) void RemoteClientBase::on_pong(Command*)
{ {
this->pong_received(); this->pong_received();
log_debug("Current ping: " << this->get_latency() << "micro seconds."); log_debug("Current ping: " << this->get_latency() << "micro seconds.");
this->install_timed_event(std::bind(&InterfaceRemoteClient::send_ping, this), 2); this->install_timed_event(this->io_service, std::bind(&RemoteClientBase::send_ping, this), 2);
} }
...@@ -9,14 +9,14 @@ ...@@ -9,14 +9,14 @@
* we need to communicate something to it. * we need to communicate something to it.
* The derived classes must install their own callback, install a transfer handler * The derived classes must install their own callback, install a transfer handler
* in it or not, etc. * in it or not, etc.
* @class InterfaceRemoteClient * @class RemoteClientBase
*/ */
#include <boost/asio.hpp> #include <boost/asio.hpp>
#include <functional> #include <functional>