The Battle for Wesnoth  1.17.0-dev
server.hpp
Go to the documentation of this file.
1 /*
2  Copyright (C) 2015 - 2021
3  by Iris Morelle <shadowm2006@gmail.com>
4  Copyright (C) 2003 - 2018 by David White <dave@whitevine.net>
5  Part of the Battle for Wesnoth Project https://www.wesnoth.org/
6 
7  This program is free software; you can redistribute it and/or modify
8  it under the terms of the GNU General Public License as published by
9  the Free Software Foundation; either version 2 of the License, or
10  (at your option) any later version.
11  This program is distributed in the hope that it will be useful,
12  but WITHOUT ANY WARRANTY.
13 
14  See the COPYING file for more details.
15 */
16 
17 #pragma once
18 
19 #include "addon/validation.hpp"
24 
25 #include <boost/asio/basic_waitable_timer.hpp>
26 
27 #include <chrono>
28 #include <functional>
29 #include <iosfwd>
30 #include <set>
31 #include <unordered_map>
32 #include <unordered_set>
33 
34 namespace campaignd {
35 
36 /**
37  * Legacy add-ons server.
38  */
39 class server : public server_base
40 {
41 public:
42  explicit server(const std::string& cfg_file,
43  unsigned short port = 0);
44  server(const config& server) = delete;
45  ~server();
46 
47  server& operator=(const config& server) = delete;
48 
49  /**
50  * Client request information object.
51  *
52  * Contains data and metadata associated with a single request from a
53  * remote add-ons client, in a light-weight format for passing to request
54  * handlers.
55  */
56  struct request
57  {
58  const std::string& cmd;
59  const config& cfg;
60 
62  const std::string addr;
63 
64  /**
65  * context of the coroutine the request is executed in
66  * async operations on @a sock can use it instead of a handler.
67  */
68  boost::asio::yield_context yield;
69 
70  /**
71  * Constructor.
72  *
73  * @param reqcmd Request command.
74  * @param reqcfg Request WML body.
75  * @param reqsock Client socket that initiated the request.
76  * @param yield The function will suspend on write operation using this yield context
77  *
78  * @note Neither @a reqcmd nor @a reqcfg are copied into instances, so
79  * they are required to exist for as long as every @a request
80  * instance that uses them. Furthermore, @a reqcfg MUST NOT REFER
81  * TO A CONST OBJECT, since some code may modify it directly for
82  * performance reasons.
83  */
84  template<class Socket>
85  request(const std::string& reqcmd,
86  config& reqcfg,
87  Socket reqsock,
88  boost::asio::yield_context yield)
89  : cmd(reqcmd)
90  , cfg(reqcfg)
91  , sock(reqsock)
92  , addr(client_address(reqsock))
93  , yield(yield)
94  {}
95  };
96 
97  friend std::ostream& operator<<(std::ostream& o, const request& r);
98 
99 private:
100 
101  std::unique_ptr<user_handler> user_handler_;
102  typedef std::function<void (server*, const request& req)> request_handler;
103  typedef std::map<std::string, request_handler> request_handlers_table;
104 
105  std::set<std::string> capabilities_;
106 
107  /**The hash map of addons metadata*/
108  std::unordered_map<std::string, config> addons_;
109  /**The set of unique addon names with pending metadata updates*/
110  std::unordered_set<std::string> dirty_addons_;
111 
112  /**Server config*/
114  const std::string cfg_file_;
115 
117  int compress_level_; /**< Used for add-on archives. */
119 
121 
122  /** Default upload size limit in bytes. */
123  static const std::size_t default_document_size_limit = 100 * 1024 * 1024;
124 
125  std::map<std::string, std::string> hooks_;
126  request_handlers_table handlers_;
127 
128  std::string server_id_;
129 
130  std::string feedback_url_format_;
131 
132  std::string web_url_;
133  std::string license_notice_;
134 
136  std::string blacklist_file_;
137 
138  std::vector<std::string> stats_exempt_ips_;
139 
140  boost::asio::basic_waitable_timer<std::chrono::steady_clock> flush_timer_;
141 
142  void handle_new_client(socket_ptr socket);
143  void handle_new_client(tls_socket_ptr socket);
144 
145  template<class Socket>
146  void serve_requests(Socket socket, boost::asio::yield_context yield);
147 
148 #ifndef _WIN32
149  void handle_read_from_fifo(const boost::system::error_code& error, std::size_t bytes_transferred);
150 
151  void handle_sighup(const boost::system::error_code& error, int signal_number);
152 #endif
153 
154  /**
155  * Starts timer to write config to disk every ten minutes.
156  */
157  void flush_cfg();
158  void handle_flush(const boost::system::error_code& error);
159 
160  /**
161  * Reads the server configuration from WML.
162  */
163  void load_config();
164 
165  /**
166  * Writes the server configuration WML back to disk.
167  */
168  void write_config();
169 
170  /**
171  * Reads the add-ons upload blacklist from WML.
172  */
173  void load_blacklist();
174 
175  /**
176  * Fires a hook script.
177  */
178  void fire(const std::string& hook, const std::string& addon);
179 
180  /** Retrieves an addon by id if found, or a null config otherwise. */
181  config& get_addon(const std::string& id);
182 
183  void delete_addon(const std::string& id);
184 
185  void mark_dirty(const std::string& addon)
186  {
187  dirty_addons_.emplace(addon);
188  }
189 
190  /**
191  * Performs validation on an incoming add-on.
192  *
193  * @param req Server request info, containing either a full
194  * WML pack, or a delta update pack.
195  * @param existing_addon Used to store a pointer to the existing add-on
196  * WML on the server if the add-on already exists.
197  * nullptr is stored otherwise.
198  * @param error_data Used to store extra error data for status codes
199  * other than ADDON_CHECK_STATUS::SUCCESS. Cleared
200  * otherwise.
201  *
202  * @return ADDON_CHECK_STATUS::SUCCESS if the validation checks pass, a
203  * more relevant value otherwise.
204  */
206  config*& existing_addon,
207  std::string& error_data);
208 
209  /** Retrieves the contents of the [server_info] WML node. */
210  const config& server_info() const { return cfg_.child("server_info"); }
211 
212  /** Retrieves the contents of the [server_info] WML node. */
213  config& server_info() { return cfg_.child("server_info"); }
214 
215  /** Checks if the specified address should never bump download counts. */
216  bool ignore_address_stats(const std::string& addr) const;
217 
218  //
219  // Request handling.
220  //
221 
222  /**
223  * Registers client request handlers.
224  *
225  * This is called by the class constructor. Individual handlers must be
226  * methods of this class that take a single parameter of type @a request
227  * and they are registered using the @a register_handler method.
228  *
229  * When adding new handlers, make sure to update the implementation of
230  * this method accordingly so they are recognized and invoked at runtime.
231  */
232  void register_handlers();
233 
234  void handle_server_id(const request&);
235  void handle_request_campaign_list(const request&);//#TODO: rename with 'addon' later?
236  void handle_request_campaign(const request&);
238  void handle_request_terms(const request&);
239  void handle_upload(const request&);
240  void handle_delete(const request&);
241  void handle_change_passphrase(const request&);
242 
243  /**
244  * Send a client an informational message.
245  *
246  * The WML sent consists of a document containing a single @p [message]
247  * child with a @a message attribute holding the value of @a msg.
248  */
249  void send_message(const std::string& msg, const any_socket_ptr& sock);
250 
251  /**
252  * Send a client an error message.
253  *
254  * The WML sent consists of a document containing a single @p [error] child
255  * with a @a message attribute holding the value of @a msg. In addition to
256  * sending the error to the client, a line with the client IP and message
257  * is recorded to the server log.
258  */
259  void send_error(const std::string& msg, const any_socket_ptr& sock);
260 
261  /**
262  * Send a client an error message.
263  *
264  * The WML sent consists of a document containing a single @p [error] child
265  * with a @a message attribute holding the value of @a msg, an
266  * @a extra_data attribute holding the value of @a extra_data, and a
267  * @a status_code attribute holding the value of @a status_code. In
268  * addition to sending the error to the client, a line with the client IP
269  * and message is recorded to the server log.
270  */
271  void send_error(const std::string& msg, const std::string& extra_data, unsigned int status_code, const any_socket_ptr& sock);
272 };
273 
274 } // end namespace campaignd
time_t update_pack_lifespan_
Definition: server.hpp:118
std::string feedback_url_format_
Definition: server.hpp:130
bool strict_versions_
Definition: server.hpp:120
bool ignore_address_stats(const std::string &addr) const
Checks if the specified address should never bump download counts.
Definition: server.cpp:810
config & child(config_key_type key, int n=0)
Returns the nth child with the given key, or a reference to an invalid config if there is none...
Definition: config.cpp:402
request(const std::string &reqcmd, config &reqcfg, Socket reqsock, boost::asio::yield_context yield)
Constructor.
Definition: server.hpp:85
Legacy add-ons server.
Definition: server.hpp:39
void handle_request_terms(const request &)
Definition: server.cpp:1232
static const std::size_t default_document_size_limit
Default upload size limit in bytes.
Definition: server.hpp:123
void handle_flush(const boost::system::error_code &error)
Definition: server.cpp:717
void send_message(const std::string &msg, const any_socket_ptr &sock)
Send a client an informational message.
Definition: server.cpp:822
config & get_addon(const std::string &id)
Retrieves an addon by id if found, or a null config otherwise.
Definition: server.cpp:864
std::unordered_set< std::string > dirty_addons_
The set of unique addon names with pending metadata updates.
Definition: server.hpp:110
static l_noret error(LoadState *S, const char *why)
Definition: lundump.cpp:40
void handle_delete(const request &)
Definition: server.cpp:1773
Client request information object.
Definition: server.hpp:56
void load_config()
Reads the server configuration from WML.
Definition: server.cpp:320
server & operator=(const config &server)=delete
void fire(const std::string &hook, const std::string &addon)
Fires a hook script.
Definition: server.cpp:770
void handle_request_campaign_hash(const request &)
Definition: server.cpp:1184
static void msg(const char *act, debug_info &i, const char *to="", const char *result="")
Definition: debugger.cpp:110
request_handlers_table handlers_
Definition: server.hpp:126
Base class for implementing servers that use gzipped-WML network protocol.
Definition: server_base.hpp:78
std::map< std::string, std::string > hooks_
Definition: server.hpp:125
void load_blacklist()
Reads the add-ons upload blacklist from WML.
Definition: server.cpp:727
void register_handlers()
Registers client request handlers.
Definition: server.cpp:906
const any_socket_ptr sock
Definition: server.hpp:61
utils::variant< socket_ptr, tls_socket_ptr > any_socket_ptr
Definition: server_base.hpp:52
const std::string cfg_file_
Definition: server.hpp:114
std::map< std::string, request_handler > request_handlers_table
Definition: server.hpp:103
void handle_sighup(const boost::system::error_code &error, int signal_number)
Definition: server.cpp:698
boost::asio::basic_waitable_timer< std::chrono::steady_clock > flush_timer_
Definition: server.hpp:140
std::string client_address(const any_socket_ptr &sock)
Definition: server.cpp:830
std::string blacklist_file_
Definition: server.hpp:136
Add-on blacklist table.
Definition: blacklist.hpp:42
void handle_read_from_fifo(const boost::system::error_code &error, std::size_t bytes_transferred)
Definition: server.cpp:528
const std::string & cmd
Definition: server.hpp:58
void delete_addon(const std::string &id)
Definition: server.cpp:874
blacklist blacklist_
Definition: server.hpp:135
void handle_change_passphrase(const request &)
Definition: server.cpp:1816
const std::string addr
Definition: server.hpp:62
boost::asio::yield_context yield
context of the coroutine the request is executed in async operations on sock can use it instead of a ...
Definition: server.hpp:68
void write_config()
Writes the server configuration WML back to disk.
Definition: server.cpp:750
std::string web_url_
Definition: server.hpp:132
config & server_info()
Retrieves the contents of the [server_info] WML node.
Definition: server.hpp:213
void handle_new_client(socket_ptr socket)
Definition: server.cpp:487
const config & server_info() const
Retrieves the contents of the [server_info] WML node.
Definition: server.hpp:210
void handle_request_campaign(const request &)
Definition: server.cpp:1039
void send_error(const std::string &msg, const any_socket_ptr &sock)
Send a client an error message.
Definition: server.cpp:834
void handle_server_id(const request &)
Definition: server.cpp:918
std::vector< std::string > stats_exempt_ips_
Definition: server.hpp:138
friend std::ostream & operator<<(std::ostream &o, const request &r)
Definition: server.cpp:474
void handle_request_campaign_list(const request &)
Definition: server.cpp:938
std::function< void(server *, const request &req)> request_handler
Definition: server.hpp:102
ADDON_CHECK_STATUS validate_addon(const server::request &req, config *&existing_addon, std::string &error_data)
Performs validation on an incoming add-on.
Definition: server.cpp:1246
const config & cfg
Definition: server.hpp:59
std::shared_ptr< boost::asio::ssl::stream< socket_ptr::element_type > > tls_socket_ptr
Definition: server_base.hpp:51
void flush_cfg()
Starts timer to write config to disk every ten minutes.
Definition: server.cpp:711
std::shared_ptr< boost::asio::ip::tcp::socket > socket_ptr
Definition: server_base.hpp:48
config cfg_
Server config.
Definition: server.hpp:113
std::unordered_map< std::string, config > addons_
The hash map of addons metadata.
Definition: server.hpp:108
std::set< std::string > capabilities_
Definition: server.hpp:105
A config object defines a single node in a WML file, with access to child nodes.
Definition: config.hpp:61
server(const std::string &cfg_file, unsigned short port=0)
Definition: server.cpp:266
void handle_upload(const request &)
Definition: server.cpp:1423
void serve_requests(Socket socket, boost::asio::yield_context yield)
Definition: server.cpp:495
void mark_dirty(const std::string &addon)
Definition: server.hpp:185
Base class for servers using Wesnoth&#39;s WML over TCP protocol.
ADDON_CHECK_STATUS
Definition: validation.hpp:32
std::string license_notice_
Definition: server.hpp:133
std::unique_ptr< user_handler > user_handler_
Definition: server.hpp:101
int compress_level_
Used for add-on archives.
Definition: server.hpp:117
std::string server_id_
Definition: server.hpp:128