Commit 7cb59e12 authored by louiz’'s avatar louiz’

Use protobuf, and clean some network stuf

fix #2351
parent 3db0c9ce
......@@ -43,6 +43,7 @@ option(BUILD_CLIENT "build the server" ${BUILD_CLIENT})
find_package(Boost 1.48.0 COMPONENTS filesystem system date_time iostreams locale serialization REQUIRED)
find_package(Cryptopp REQUIRED)
find_package(YamlCpp REQUIRED)
find_package(Protobuf REQUIRED)
if(BUILD_CLIENT)
find_package(SFML 2 REQUIRED system window graphics audio)
......@@ -59,6 +60,7 @@ include_directories("src/")
include_directories(${Boost_INCLUDE_DIR})
include_directories(${CRYPTO++_INCLUDE_DIR})
include_directories(${YAML_CPP_INCLUDE_DIRS})
include_directories(${PROTOBUF_INCLUDE_DIRS})
if(GTEST_FOUND)
include_directories(${GTEST_INCLUDE_DIRS})
endif()
......@@ -222,11 +224,14 @@ target_Link_libraries(world
#
## Serialization
#
file(GLOB source_serialization
src/serialization/*.[hc]pp
file(GLOB proto_files
src/proto/*.proto
)
PROTOBUF_GENERATE_CPP(PROTO_SRC PROTO_HDRS ${proto_files})
add_library(serialization STATIC ${source_serialization})
include_directories(${CMAKE_CURRENT_BINARY_DIR})
add_library(serialization STATIC ${PROTO_SRC})
target_link_libraries(serialization ${PROTOBUF_LIBRARIES})
#
......@@ -234,17 +239,7 @@ add_library(serialization STATIC ${source_serialization})
#
file(GLOB source_server
src/network/command_handler.*
src/network/remote_client_base.*
src/network/remote_client.*
src/network/remote_game_client.*
src/network/server.*
src/network/game_server.*
src/network/transfer_sender.*
src/network/command.*
src/network/timed_event.*
src/network/timed_event_handler.*
src/network/ping_handler.*
src/network/*.[hc]pp
)
add_library(server STATIC ${source_server})
......@@ -293,9 +288,11 @@ add_library(game STATIC ${source_game})
target_link_libraries(game
serialization
network
client
logging
config
world
)
#
......
......@@ -35,4 +35,3 @@ private:
};
#endif // BASE_SOCKET
......@@ -37,8 +37,8 @@ void Client::on_transfer_ended(const TransferReceiver* receiver)
for (it = this->receivers.begin(); it < this->receivers.end(); ++it)
if (*it == receiver)
{
this->receivers.erase(it);
break ;
this->receivers.erase(it);
break ;
}
delete receiver;
}
......
......@@ -8,11 +8,11 @@ Message::Message():
{
}
Message::Message(const Message& message)
Message::Message(const Message& message):
callback(message.callback),
header(message.header),
name(message.name)
{
this->callback = message.callback;
this->header = message.header;
this->name = message.name;
this->set_body(message.body, message.body_size);
}
......@@ -30,7 +30,17 @@ void Message::set_body(const char* body, int size)
this->set_body_size(size);
}
void Message::set_name(const std::string name)
void Message::set_body(const google::protobuf::Message& msg)
{
const int size = msg.ByteSize();
this->body = new char[size];
this->set_body_size(size);
const auto res = msg.SerializeToArray(this->body, size);
log_debug("Setting message body with protobuf: " << msg.ShortDebugString());
assert(res);
}
void Message::set_name(const std::string& name)
{
this->name = name;
}
......
......@@ -14,7 +14,7 @@
* To send a message, a Message object must be created anywhere and filled with
* the correct data and then passed to the MessageHandler::send() method.
* The object will be deleted by the send_handler, after it has been
* succesfully sent.
* successfully sent.
*
* A Message object is passed by a MessageHandler to the callback associated
* with a message name. This callback is responsible for deleting the message
......@@ -22,16 +22,20 @@
* @class Message
*/
#ifndef MESSAGE_HPP
# define MESSAGE_HPP
#include <google/protobuf/message.h>
#include "logging/logging.hpp"
#include <functional>
#include <string>
#include <iostream>
#include <cstring>
#include <fstream>
#include <sstream>
#include <functional>
#ifndef MESSAGE_HPP
# define MESSAGE_HPP
class Message
{
public:
......@@ -45,6 +49,11 @@ public:
* object, not both.
*/
void set_body(const char*, int size = -1);
/**
* Sets the body of the message with the content of given the
* protobuf::Message, serialized.
*/
void set_body(const google::protobuf::Message& msg);
/**
* If you manually set the content of the body member, use this method to
* set the proper body size. Do not use it after set_body() though.
......@@ -55,7 +64,7 @@ public:
* it will set the header correctly, using the body size etc.
*/
void pack();
void set_name(const std::string);
void set_name(const std::string& name);
std::string get_name() { return this->name; }
/**
* Use this member to manually set the body. For example you can pass it to
......@@ -67,9 +76,21 @@ public:
std::string name;
size_t body_size;
/**
* If not 0, will be called from the send_handler.
* If not empty, will be called from the send_handler.
*/
std::function<void(void)> callback;
/**
* Converts the body to a protobuf object. Does not check if it's valid
* nor complete.
*/
std::function< void(void) > callback;
template<typename ProtobufClass>
ProtobufClass parse_body_to_protobuf_object() const
{
ProtobufClass res;
res.ParseFromArray(this->body, this->body_size);
log_debug("parse_body_to_protobuf_object: " << res.ShortDebugString());
return res;
}
private:
Message& operator=(const Message&);
......
......@@ -16,40 +16,36 @@ void MessageHandler::install_callback(const std::string& message,
t_read_callback callback)
{
log_debug("installing callback for message " << message);
this->callbacks[message] = callback;
this->callbacks.emplace(message, callback);
}
void MessageHandler::install_callback_once(const std::string& message,
t_read_callback callback)
{
log_debug("installing ONCE callback for message " << message);
this->callbacks_once[message] = callback;
this->callbacks_once.emplace(message, callback);
}
void MessageHandler::remove_callback(const std::string& message)
{
auto it = this->callbacks.find(message);
if (it != this->callbacks.end())
this->callbacks.erase(it);
else
log_warning("Could not remove callback: " << message);
log_debug("remove_callback: " << message);
auto res = this->callbacks.erase(message);
log_warning("Removed " << res << " callbacks");
}
t_read_callback MessageHandler::get_callback(const std::string& message)
std::vector<t_read_callback> MessageHandler::get_callbacks(const std::string& message)
{
auto it = this->callbacks.find(message);
if (it != this->callbacks.end())
return it->second;
std::vector<t_read_callback> res;
it = this->callbacks_once.find(message);
if (it != this->callbacks_once.end())
{
log_debug("Removing callback for message " << message);
t_read_callback callback = it->second;
this->callbacks_once.erase(it);
return callback;
}
return 0;
auto its = this->callbacks.equal_range(message);
for (auto it = std::get<0>(its); it != std::get<1>(its); ++it)
res.push_back(it->second);
its = this->callbacks_once.equal_range(message);
for (auto it = std::get<0>(its); it != std::get<1>(its); ++it)
res.push_back(it->second);
this->callbacks_once.erase(std::get<0>(its), std::get<1>(its));
return res;
}
void MessageHandler::read_handler(const boost::system::error_code& error, const std::size_t bytes_transferred)
......@@ -96,7 +92,7 @@ void MessageHandler::read_handler(const boost::system::error_code& error, const
delete[] c;
// Find out if a callback was registered for that message.
t_read_callback callback = this->get_callback(message_name);
auto callbacks = this->get_callbacks(message_name);
// 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();
......@@ -106,13 +102,13 @@ void MessageHandler::read_handler(const boost::system::error_code& error, const
std::bind(&MessageHandler::binary_read_handler, this,
std::placeholders::_1,
message,
size, callback));
size, callbacks));
}
void MessageHandler::binary_read_handler(const boost::system::error_code& error,
Message* message,
std::size_t bytes_transferred,
t_read_callback callback)
std::vector<t_read_callback> callbacks)
{
if (error)
{
......@@ -124,10 +120,15 @@ void MessageHandler::binary_read_handler(const boost::system::error_code& error,
this->data.sgetn(message->body, bytes_transferred);
message->set_body_size(bytes_transferred);
if (callback)
callback(message);
if (callbacks.empty())
{
log_debug("no callback");
}
else
log_debug("no callback");
{
for (const auto& cb: callbacks)
cb(message);
}
delete message;
this->install_read_handler();
}
......@@ -177,8 +178,8 @@ void MessageHandler::actually_send(Message* message)
buffs.push_back(boost::asio::buffer(message->header.data(), message->header.length()));
buffs.push_back(boost::asio::buffer(message->body, message->body_size));
async_write(this->socket,
buffs,
std::bind(&MessageHandler::send_handler, this,
buffs,
std::bind(&MessageHandler::send_handler, this,
std::placeholders::_1,
std::placeholders::_2,
message));
......
......@@ -26,7 +26,6 @@ typedef std::function<void(Message*)> t_read_callback;
class MessageHandler: public BaseSocket
{
friend void TransferSender::send_next_chunk();
public:
explicit MessageHandler(boost::asio::io_service&);
virtual ~MessageHandler();
......@@ -42,7 +41,7 @@ public:
* Read the arguments after a message (can read 0 bytes too) and pass that
* to the callback that was associated with this message.
*/
void binary_read_handler(const boost::system::error_code&, Message*, std::size_t, t_read_callback);
void binary_read_handler(const boost::system::error_code&, Message*, std::size_t, std::vector<t_read_callback> callbacks);
/**
* Sends a message, and use install_callback_once to wait for the answer
* and call that callback to handle it.
......@@ -74,11 +73,10 @@ public:
protected:
/**
* Returns the callback associated with the passed message name.
* Returns 0 if nothing was found, in that case the execution of the
* return value cause a failure.
* Returns all the callbacks associated with the passed message name.
* Returns an empty vector if nothing was found.
*/
t_read_callback get_callback(const std::string&);
std::vector<t_read_callback> get_callbacks(const std::string&);
/**
* @todo Check if the data was correctly sent on the socket
*/
......@@ -107,8 +105,8 @@ private:
MessageHandler(const MessageHandler&);
MessageHandler& operator=(const MessageHandler&);
std::map<const std::string, t_read_callback > callbacks;
std::map<const std::string, t_read_callback > callbacks_once;
std::multimap<const std::string, t_read_callback > callbacks;
std::multimap<const std::string, t_read_callback > callbacks_once;
/**
* A queue of messages. If there's not async_write running, we pop one
* from it and we send it.
......
......@@ -9,7 +9,7 @@ RemoteClient::RemoteClient(boost::asio::io_service& io_service,
RemoteClient::~RemoteClient()
{
log_info("Deleting remote client " << this->number);
log_info("Deleting remote client " << this->id);
}
void RemoteClient::install_callbacks()
......
......@@ -5,19 +5,19 @@ unsigned long int RemoteClientBase::clients_number = 0;
RemoteClientBase::RemoteClientBase(boost::asio::io_service& io_service):
MessageHandler(io_service),
number(RemoteClientBase::clients_number++),
id(RemoteClientBase::clients_number++),
io_service(io_service)
{
}
RemoteClientBase::~RemoteClientBase()
{
log_info("Deleting remote client " << this->number);
log_info("Deleting remote client " << this->id);
}
void RemoteClientBase::start()
{
log_debug("Starting RemoteClientBase " << this->number);
log_debug("Starting RemoteClientBase " << this->id);
this->install_callbacks();
this->install_timed_event(this->io_service, std::bind(&RemoteClientBase::send_ping, this), 2);
MessageHandler::install_read_handler();
......
......@@ -12,12 +12,15 @@
* @class RemoteClientBase
*/
#include <boost/asio.hpp>
#include <functional>
#ifndef REMOTE_CLIENT_BASE
# define REMOTE_CLIENT_BASE
#include <cstdint>
#include <functional>
#include <boost/asio.hpp>
#include <network/message_handler.hpp>
#include <network/message.hpp>
#include <network/timed_event_handler.hpp>
......@@ -49,11 +52,7 @@ public:
/**
* Returns the client number (aka id).
*/
unsigned long int get_number() { return this->number; }
/**
* Returns the client number (aka id).
*/
unsigned long int get_id() { return this->get_number(); }
uint32_t get_id() const { return this->id; }
virtual void on_connection_closed() = 0;
......@@ -61,7 +60,7 @@ protected:
/**
* The client number (aka id).
*/
const unsigned long int number;
const uint32_t id;
/**
* Creates the default callbacks associated with a network message.
* It is executed whenever that message is received.
......
......@@ -205,10 +205,10 @@ private:
log_error("handle_accept failed: " << error);
exit(1);
}
client->start();
this->clients.push_back(client);
this->on_new_client(client);
this->install_accept_handler();
this->on_new_client(client);
this->clients.push_back(client);
this->install_accept_handler();
client->start();
}
void accept(void)
......
Markdown is supported
0% or .
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment