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