Skip to content

Commit

Permalink
Implement support in wesnothd to handle both unencrypted and TLS sockets
Browse files Browse the repository at this point in the history
  • Loading branch information
loonycyborg committed Mar 11, 2021
1 parent 909b5ee commit 329bbb4
Show file tree
Hide file tree
Showing 9 changed files with 132 additions and 105 deletions.
9 changes: 5 additions & 4 deletions src/server/common/forum_user_handler.cpp
Expand Up @@ -15,6 +15,7 @@
#ifdef HAVE_MYSQLPP

#include "server/common/forum_user_handler.hpp"
#include "server/wesnothd/server.hpp"
#include "hash.hpp"
#include "log.hpp"
#include "config.hpp"
Expand Down Expand Up @@ -207,10 +208,10 @@ std::string fuh::get_tournaments(){
return conn_.get_tournaments();
}

void fuh::async_get_and_send_game_history(boost::asio::io_service& io_service, server_base& s_base, socket_ptr player_socket, int player_id, int offset) {
boost::asio::post([this, &s_base, player_socket, player_id, offset, &io_service] {
boost::asio::post(io_service, [player_socket, &s_base, doc = conn_.get_game_history(player_id, offset)]{
s_base.async_send_doc_queued(player_socket, *doc);
void fuh::async_get_and_send_game_history(boost::asio::io_service& io_service, wesnothd::server& s, wesnothd::player_iterator player, int player_id, int offset) {
boost::asio::post([this, &s, player, player_id, offset, &io_service] {
boost::asio::post(io_service, [player, &s, doc = conn_.get_game_history(player_id, offset)]{
s.send_to_player(player, *doc);
});
});
}
Expand Down
2 changes: 1 addition & 1 deletion src/server/common/forum_user_handler.hpp
Expand Up @@ -130,7 +130,7 @@ class fuh : public user_handler
* @param player_id The forum ID of the player to get the game history for.
* @param offset Where to start returning rows to the client from the query results.
*/
void async_get_and_send_game_history(boost::asio::io_service& io_service, server_base& s_base, socket_ptr player_socket, int player_id, int offset);
void async_get_and_send_game_history(boost::asio::io_service& io_service, wesnothd::server& s, wesnothd::player_iterator player, int player_id, int offset);

/**
* Inserts game related information.
Expand Down
33 changes: 21 additions & 12 deletions src/server/common/server_base.cpp
Expand Up @@ -219,17 +219,17 @@ void server_base::run() {
}
}

std::string client_address(const socket_ptr socket)
template<class SocketPtr> std::string client_address(SocketPtr socket)
{
boost::system::error_code error;
std::string result = socket->remote_endpoint(error).address().to_string();
std::string result = socket->lowest_layer().remote_endpoint(error).address().to_string();
if(error)
return "<unknown address>";
else
return result;
}

bool check_error(const boost::system::error_code& error, socket_ptr socket)
template<class SocketPtr> bool check_error(const boost::system::error_code& error, SocketPtr socket)
{
if(error) {
if(error == boost::asio::error::eof)
Expand All @@ -240,6 +240,7 @@ bool check_error(const boost::system::error_code& error, socket_ptr socket)
}
return false;
}
template bool check_error<tls_socket_ptr>(const boost::system::error_code& error, tls_socket_ptr socket);

namespace {

Expand All @@ -263,7 +264,7 @@ void info_table_into_simple_wml(simple_wml::document& doc, const std::string& pa
* @param doc
* @param yield The function will suspend on write operation using this yield context
*/
void server_base::coro_send_doc(socket_ptr socket, simple_wml::document& doc, boost::asio::yield_context yield)
template<class SocketPtr> void server_base::coro_send_doc(SocketPtr socket, simple_wml::document& doc, boost::asio::yield_context yield)
{
if(dump_wml) {
std::cout << "Sending WML to " << client_address(socket) << ": \n" << doc.output() << std::endl;
Expand All @@ -290,10 +291,12 @@ void server_base::coro_send_doc(socket_ptr socket, simple_wml::document& doc, bo
throw;
}
}
template void server_base::coro_send_doc<socket_ptr>(socket_ptr socket, simple_wml::document& doc, boost::asio::yield_context yield);
template void server_base::coro_send_doc<tls_socket_ptr>(tls_socket_ptr socket, simple_wml::document& doc, boost::asio::yield_context yield);

#ifdef HAVE_SENDFILE

void server_base::coro_send_file(socket_ptr socket, const std::string& filename, boost::asio::yield_context yield)
template<class SocketPtr> void server_base::coro_send_file(SocketPtr socket, const std::string& filename, boost::asio::yield_context yield)
{
std::size_t filesize { std::size_t(filesystem::file_size(filename)) };
int in_file { open(filename.c_str(), O_RDONLY) };
Expand Down Expand Up @@ -350,7 +353,7 @@ void server_base::coro_send_file(socket_ptr socket, const std::string& filename,

#elif defined(_WIN32)

void server_base::coro_send_file(socket_ptr socket, const std::string& filename, boost::asio::yield_context yield)
template<class SocketPtr> void server_base::coro_send_file(SocketPtr socket, const std::string& filename, boost::asio::yield_context yield)
{

OVERLAPPED overlap;
Expand Down Expand Up @@ -411,15 +414,15 @@ void server_base::coro_send_file(socket_ptr socket, const std::string& filename,

#else

void server_base::coro_send_file(socket_ptr socket, const std::string& filename, boost::asio::yield_context yield)
template<class SocketPtr> void server_base::coro_send_file(SocketPtr socket, const std::string& filename, boost::asio::yield_context yield)
{
// TODO: Implement this for systems without sendfile()
assert(false && "Not implemented yet");
}

#endif

std::unique_ptr<simple_wml::document> server_base::coro_receive_doc(socket_ptr socket, boost::asio::yield_context yield)
template<class SocketPtr> std::unique_ptr<simple_wml::document> server_base::coro_receive_doc(SocketPtr socket, boost::asio::yield_context yield)
{
union DataSize
{
Expand Down Expand Up @@ -457,12 +460,14 @@ std::unique_ptr<simple_wml::document> server_base::coro_receive_doc(socket_ptr s
return {};
}
}
template std::unique_ptr<simple_wml::document> server_base::coro_receive_doc<socket_ptr>(socket_ptr socket, boost::asio::yield_context yield);
template std::unique_ptr<simple_wml::document> server_base::coro_receive_doc<tls_socket_ptr>(tls_socket_ptr socket, boost::asio::yield_context yield);

void server_base::async_send_doc_queued(socket_ptr socket, simple_wml::document& doc)
template<class SocketPtr> void server_base::async_send_doc_queued(SocketPtr socket, simple_wml::document& doc)
{
boost::asio::spawn(
io_service_, [this, doc_ptr = doc.clone(), socket](boost::asio::yield_context yield) mutable {
static std::map<socket_ptr, std::queue<std::unique_ptr<simple_wml::document>>> queues;
static std::map<SocketPtr, std::queue<std::unique_ptr<simple_wml::document>>> queues;

queues[socket].push(std::move(doc_ptr));
if(queues[socket].size() > 1) {
Expand All @@ -478,7 +483,7 @@ void server_base::async_send_doc_queued(socket_ptr socket, simple_wml::document&
);
}

void server_base::async_send_error(socket_ptr socket, const std::string& msg, const char* error_code, const info_table& info)
template<class SocketPtr> void server_base::async_send_error(SocketPtr socket, const std::string& msg, const char* error_code, const info_table& info)
{
simple_wml::document doc;
doc.root().add_child("error").set_attr_dup("message", msg.c_str());
Expand All @@ -489,8 +494,10 @@ void server_base::async_send_error(socket_ptr socket, const std::string& msg, co

async_send_doc_queued(socket, doc);
}
template void server_base::async_send_error<socket_ptr>(socket_ptr socket, const std::string& msg, const char* error_code, const info_table& info);
template void server_base::async_send_error<tls_socket_ptr>(tls_socket_ptr socket, const std::string& msg, const char* error_code, const info_table& info);

void server_base::async_send_warning(socket_ptr socket, const std::string& msg, const char* warning_code, const info_table& info)
template<class SocketPtr> void server_base::async_send_warning(SocketPtr socket, const std::string& msg, const char* warning_code, const info_table& info)
{
simple_wml::document doc;
doc.root().add_child("warning").set_attr_dup("message", msg.c_str());
Expand All @@ -501,6 +508,8 @@ void server_base::async_send_warning(socket_ptr socket, const std::string& msg,

async_send_doc_queued(socket, doc);
}
template void server_base::async_send_warning<socket_ptr>(socket_ptr socket, const std::string& msg, const char* warning_code, const info_table& info);
template void server_base::async_send_warning<tls_socket_ptr>(tls_socket_ptr socket, const std::string& msg, const char* warning_code, const info_table& info);

void server_base::load_tls_config(const config& cfg)
{
Expand Down
16 changes: 8 additions & 8 deletions src/server/common/server_base.hpp
Expand Up @@ -66,20 +66,20 @@ class server_base
* @param doc
* @param yield The function will suspend on write operation using this yield context
*/
void coro_send_doc(socket_ptr socket, simple_wml::document& doc, boost::asio::yield_context yield);
template<class SocketPtr> void coro_send_doc(SocketPtr socket, simple_wml::document& doc, boost::asio::yield_context yield);
/**
* Send contents of entire file directly to socket from within a coroutine
* @param socket
* @param filename
* @param yield The function will suspend on write operations using this yield context
*/
void coro_send_file(socket_ptr socket, const std::string& filename, boost::asio::yield_context yield);
template<class SocketPtr> void coro_send_file(SocketPtr socket, const std::string& filename, boost::asio::yield_context yield);
/**
* Receive WML document from a coroutine
* @param socket
* @param yield The function will suspend on read operation using this yield context
*/
std::unique_ptr<simple_wml::document> coro_receive_doc(socket_ptr socket, boost::asio::yield_context yield);
template<class SocketPtr> std::unique_ptr<simple_wml::document> coro_receive_doc(SocketPtr socket, boost::asio::yield_context yield);

/**
* High level wrapper for sending a WML document
Expand All @@ -89,11 +89,11 @@ class server_base
* @param socket
* @param doc Document to send. A copy of it will be made so there is no need to keep the reference live after the function returns.
*/
void async_send_doc_queued(socket_ptr socket, simple_wml::document& doc);
template<class SocketPtr> void async_send_doc_queued(SocketPtr socket, simple_wml::document& doc);

typedef std::map<std::string, std::string> info_table;
void async_send_error(socket_ptr socket, const std::string& msg, const char* error_code = "", const info_table& info = {});
void async_send_warning(socket_ptr socket, const std::string& msg, const char* warning_code = "", const info_table& info = {});
template<class SocketPtr> void async_send_error(SocketPtr socket, const std::string& msg, const char* error_code = "", const info_table& info = {});
template<class SocketPtr> void async_send_warning(SocketPtr socket, const std::string& msg, const char* warning_code = "", const info_table& info = {});

protected:
unsigned short port_;
Expand Down Expand Up @@ -135,5 +135,5 @@ class server_base
void handle_termination(const boost::system::error_code& error, int signal_number);
};

std::string client_address(socket_ptr socket);
bool check_error(const boost::system::error_code& error, socket_ptr socket);
template<class SocketPtr> std::string client_address(SocketPtr socket);
template<class SocketPtr> bool check_error(const boost::system::error_code& error, SocketPtr socket);
10 changes: 8 additions & 2 deletions src/server/common/user_handler.hpp
Expand Up @@ -17,13 +17,19 @@
class config;

#include "exceptions.hpp"
#include "server/common/server_base.hpp"

#include <ctime>
#include <string>

#include <boost/asio/io_service.hpp>

#include "server/wesnothd/player_connection.hpp"

namespace wesnothd
{
class server;
}

/**
* An interface class to handle nick registration
* To activate it put a [user_handler] section into the
Expand Down Expand Up @@ -135,7 +141,7 @@ class user_handler

virtual std::string get_uuid() = 0;
virtual std::string get_tournaments() = 0;
virtual void async_get_and_send_game_history(boost::asio::io_service& io_service, server_base& s_base, socket_ptr player_socket, int player_id, int offset) =0;
virtual void async_get_and_send_game_history(boost::asio::io_service& io_service, wesnothd::server& s, wesnothd::player_iterator player, int player_id, int offset) =0;
virtual void db_insert_game_info(const std::string& uuid, int game_id, const std::string& version, const std::string& name, int reload, int observers, int is_public, int has_password) = 0;
virtual void db_update_game_end(const std::string& uuid, int game_id, const std::string& replay_location) = 0;
virtual void db_insert_game_player_info(const std::string& uuid, int game_id, const std::string& username, int side_number, int is_host, const std::string& faction, const std::string& version, const std::string& source, const std::string& current_user) = 0;
Expand Down

0 comments on commit 329bbb4

Please sign in to comment.