The Battle for Wesnoth  1.15.12+dev
server_base.hpp
Go to the documentation of this file.
1 /*
2  Copyright (C) 2016 - 2018 by Sergey Popov <dave@whitevine.net>
3  Part of the Battle for Wesnoth Project https://www.wesnoth.org
4 
5  This program is free software; you can redistribute it and/or modify
6  it under the terms of the GNU General Public License 2
7  the Free Software Foundation; either version 2 of the License, or
8  (at your option) any later version.
9  This program is distributed in the hope that it will be useful,
10  but WITHOUT ANY WARRANTY.
11 
12  See the COPYING file for more details.
13 */
14 
15 /**
16  * @file
17  * Base class for servers using Wesnoth's WML over TCP protocol.
18  */
19 
20 #pragma once
21 
22 #include "exceptions.hpp"
24 
25 #ifdef _WIN32
27 #endif
28 
29 #include <boost/asio/io_service.hpp>
30 #include <boost/asio/ip/tcp.hpp>
31 #ifndef _WIN32
32 #include <boost/asio/posix/stream_descriptor.hpp>
33 #endif
34 #include <boost/asio/signal_set.hpp>
35 #include <boost/asio/streambuf.hpp>
36 #include <boost/asio/spawn.hpp>
37 #include <boost/shared_array.hpp>
38 
39 #include <map>
40 
41 extern bool dump_wml;
42 
43 typedef std::shared_ptr<boost::asio::ip::tcp::socket> socket_ptr;
44 
46 {
47  server_shutdown(const std::string& msg) : game::error(msg) {}
48 };
49 
51 {
52 public:
53  server_base(unsigned short port, bool keep_alive);
54  virtual ~server_base() {}
55  void run();
56 
57  /**
58  * Send a WML document from within a coroutine
59  * @param socket
60  * @param doc
61  * @param yield The function will suspend on write operation using this yield context
62  */
63  void coro_send_doc(socket_ptr socket, simple_wml::document& doc, boost::asio::yield_context yield);
64  /**
65  * Send contents of entire file directly to socket from within a coroutine
66  * @param socket
67  * @param filename
68  * @param yield The function will suspend on write operations using this yield context
69  */
70  void coro_send_file(socket_ptr socket, const std::string& filename, boost::asio::yield_context yield);
71  /**
72  * Receive WML document from a coroutine
73  * @param socket
74  * @param yield The function will suspend on read operation using this yield context
75  */
76  std::unique_ptr<simple_wml::document> coro_receive_doc(socket_ptr socket, boost::asio::yield_context yield);
77 
78  /**
79  * High level wrapper for sending a WML document
80  *
81  * This function returns before send is finished. This function can be called again on same socket before previous send was finished.
82  * WML documents are kept in internal queue and sent in FIFO order.
83  * @param socket
84  * @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.
85  */
86  void async_send_doc_queued(socket_ptr socket, simple_wml::document& doc);
87 
88  typedef std::map<std::string, std::string> info_table;
89  void async_send_error(socket_ptr socket, const std::string& msg, const char* error_code = "", const info_table& info = {});
90  void async_send_warning(socket_ptr socket, const std::string& msg, const char* warning_code = "", const info_table& info = {});
91 
92 protected:
93  unsigned short port_;
95  boost::asio::io_service io_service_;
96  boost::asio::ip::tcp::acceptor acceptor_v6_;
97  boost::asio::ip::tcp::acceptor acceptor_v4_;
98  void start_server();
99  void serve(boost::asio::yield_context yield, boost::asio::ip::tcp::acceptor& acceptor, boost::asio::ip::tcp::endpoint endpoint);
100 
101  union {
102  uint32_t connection_num;
103  char buf[4];
104  } handshake_response_;
105 
106  virtual void handle_new_client(socket_ptr socket) = 0;
107 
108  virtual bool accepting_connections() const { return true; }
109  virtual std::string is_ip_banned(const std::string&) { return std::string(); }
110  virtual bool ip_exceeds_connection_limit(const std::string&) const { return false; }
111 
112 #ifndef _WIN32
113  boost::asio::posix::stream_descriptor input_;
114  std::string fifo_path_;
115  void read_from_fifo();
116  virtual void handle_read_from_fifo(const boost::system::error_code& error, std::size_t bytes_transferred) = 0;
117  boost::asio::streambuf admin_cmd_;
118 
119  boost::asio::signal_set sighup_;
120  virtual void handle_sighup(const boost::system::error_code& error, int signal_number) = 0;
121 #endif
122  boost::asio::signal_set sigs_;
123  void handle_termination(const boost::system::error_code& error, int signal_number);
124 };
125 
126 std::string client_address(socket_ptr socket);
127 bool check_error(const boost::system::error_code& error, socket_ptr socket);
boost::asio::ip::tcp::acceptor acceptor_v4_
Definition: server_base.hpp:97
server_shutdown(const std::string &msg)
Definition: server_base.hpp:47
boost::asio::signal_set sighup_
logger & info()
Definition: log.cpp:88
static void msg(const char *act, debug_info &i, const char *to="", const char *result="")
Definition: debugger.cpp:109
unsigned short port_
Definition: server_base.hpp:93
uint32_t connection_num
bool keep_alive_
Definition: server_base.hpp:94
boost::asio::streambuf admin_cmd_
boost::asio::io_service io_service_
Definition: server_base.hpp:95
bool dump_wml
Definition: server_base.cpp:53
boost::asio::ip::tcp::acceptor acceptor_v6_
Definition: server_base.hpp:96
virtual bool accepting_connections() const
virtual bool ip_exceeds_connection_limit(const std::string &) const
virtual ~server_base()
Definition: server_base.hpp:54
std::map< std::string, std::string > info_table
Definition: server_base.hpp:88
bool check_error(const boost::system::error_code &error, socket_ptr socket)
virtual std::string is_ip_banned(const std::string &)
boost::asio::posix::stream_descriptor input_
Base class for all the errors encountered by the engine.
Definition: exceptions.hpp:27
std::string fifo_path_
std::string client_address(socket_ptr socket)
std::shared_ptr< boost::asio::ip::tcp::socket > socket_ptr
Definition: server_base.hpp:43
boost::asio::signal_set sigs_