The Battle for Wesnoth  1.15.9+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"
22 
23 #include <boost/asio/basic_waitable_timer.hpp>
24 
25 #include <chrono>
26 #include <functional>
27 #include <iosfwd>
28 #include <set>
29 #include <unordered_map>
30 #include <unordered_set>
31 
32 namespace campaignd {
33 
34 /**
35  * Legacy add-ons server.
36  */
37 class server : public server_base
38 {
39 public:
40  explicit server(const std::string& cfg_file,
41  unsigned short port = 0);
42  server(const config& server) = delete;
43  ~server();
44 
45  server& operator=(const config& server) = delete;
46 
47  /**
48  * Client request information object.
49  *
50  * Contains data and metadata associated with a single request from a
51  * remote add-ons client, in a light-weight format for passing to request
52  * handlers.
53  */
54  struct request
55  {
56  const std::string& cmd;
57  const config& cfg;
58 
60  const std::string addr;
61 
62  /**
63  * context of the coroutine the request is executed in
64  * async operations on @a sock can use it instead of a handler.
65  */
66  boost::asio::yield_context yield;
67 
68  /**
69  * Constructor.
70  *
71  * @param reqcmd Request command.
72  * @param reqcfg Request WML body.
73  * @param reqsock Client socket that initiated the request.
74  * @param yield The function will suspend on write operation using this yield context
75  *
76  * @note Neither @a reqcmd nor @a reqcfg are copied into instances, so
77  * they are required to exist for as long as every @a request
78  * instance that uses them. Furthermore, @a reqcfg MUST NOT REFER
79  * TO A CONST OBJECT, since some code may modify it directly for
80  * performance reasons.
81  */
82  request(const std::string& reqcmd,
83  config& reqcfg,
84  socket_ptr reqsock,
85  boost::asio::yield_context yield)
86  : cmd(reqcmd)
87  , cfg(reqcfg)
88  , sock(reqsock)
89  , addr(client_address(sock))
90  , yield(yield)
91  {}
92  };
93 
94  friend std::ostream& operator<<(std::ostream& o, const request& r);
95 
96 private:
97 
98  typedef std::function<void (server*, const request& req)> request_handler;
99  typedef std::map<std::string, request_handler> request_handlers_table;
100 
101  std::set<std::string> capabilities_;
102 
103  /**The hash map of addons metadata*/
104  std::unordered_map<std::string, config> addons_;
105  /**The set of unique addon names with pending metadata updates*/
106  std::unordered_set<std::string> dirty_addons_;
107 
108  /**Server config*/
110  const std::string cfg_file_;
111 
113  int compress_level_; /**< Used for add-on archives. */
115 
117 
118  /** Default upload size limit in bytes. */
119  static const std::size_t default_document_size_limit = 100 * 1024 * 1024;
120 
121  std::map<std::string, std::string> hooks_;
122  request_handlers_table handlers_;
123 
124  std::string feedback_url_format_;
125 
126  std::string web_url_;
127  std::string license_notice_;
128 
130  std::string blacklist_file_;
131 
132  std::vector<std::string> stats_exempt_ips_;
133 
134  boost::asio::basic_waitable_timer<std::chrono::steady_clock> flush_timer_;
135 
136  void handle_new_client(socket_ptr socket);
137 
138 #ifndef _WIN32
139  void handle_read_from_fifo(const boost::system::error_code& error, std::size_t bytes_transferred);
140 
141  void handle_sighup(const boost::system::error_code& error, int signal_number);
142 #endif
143 
144  /**
145  * Starts timer to write config to disk every ten minutes.
146  */
147  void flush_cfg();
148  void handle_flush(const boost::system::error_code& error);
149 
150  /**
151  * Reads the server configuration from WML.
152  */
153  void load_config();
154 
155  /**
156  * Writes the server configuration WML back to disk.
157  */
158  void write_config();
159 
160  /**
161  * Reads the add-ons upload blacklist from WML.
162  */
163  void load_blacklist();
164 
165  /**
166  * Fires a hook script.
167  */
168  void fire(const std::string& hook, const std::string& addon);
169 
170  /** Retrieves an addon by id if found, or a null config otherwise. */
171  config& get_addon(const std::string& id);
172 
173  void delete_addon(const std::string& id);
174 
175  void mark_dirty(const std::string& addon)
176  {
177  dirty_addons_.emplace(addon);
178  }
179 
180  /**
181  * Performs validation on an incoming add-on.
182  *
183  * @param req Server request info, containing either a full
184  * WML pack, or a delta update pack.
185  * @param existing_addon Used to store a pointer to the existing add-on
186  * WML on the server if the add-on already exists.
187  * nullptr is stored otherwise.
188  * @param error_data Used to store extra error data for status codes
189  * other than ADDON_CHECK_STATUS::SUCCESS. Cleared
190  * otherwise.
191  *
192  * @return ADDON_CHECK_STATUS::SUCCESS if the validation checks pass, a
193  * more relevant value otherwise.
194  */
196  config*& existing_addon,
197  std::string& error_data);
198 
199  /** Retrieves the contents of the [server_info] WML node. */
200  const config& server_info() const { return cfg_.child("server_info"); }
201 
202  /** Retrieves the contents of the [server_info] WML node. */
203  config& server_info() { return cfg_.child("server_info"); }
204 
205  /** Checks if the specified address should never bump download counts. */
206  bool ignore_address_stats(const std::string& addr) const;
207 
208  //
209  // Request handling.
210  //
211 
212  /**
213  * Registers client request handlers.
214  *
215  * This is called by the class constructor. Individual handlers must be
216  * methods of this class that take a single parameter of type @a request
217  * and they are registered using the @a register_handler method.
218  *
219  * When adding new handlers, make sure to update the implementation of
220  * this method accordingly so they are recognized and invoked at runtime.
221  */
222  void register_handlers();
223 
224  void handle_server_id(const request&);
225  void handle_request_campaign_list(const request&);//#TODO: rename with 'addon' later?
226  void handle_request_campaign(const request&);
228  void handle_request_terms(const request&);
229  void handle_upload(const request&);
230  void handle_delete(const request&);
231  void handle_change_passphrase(const request&);
232 
233  /**
234  * Send a client an informational message.
235  *
236  * The WML sent consists of a document containing a single @p [message]
237  * child with a @a message attribute holding the value of @a msg.
238  */
239  void send_message(const std::string& msg, socket_ptr sock);
240 
241  /**
242  * Send a client an error message.
243  *
244  * The WML sent consists of a document containing a single @p [error] child
245  * with a @a message attribute holding the value of @a msg. In addition to
246  * sending the error to the client, a line with the client IP and message
247  * is recorded to the server log.
248  */
249  void send_error(const std::string& msg, 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, an
256  * @a extra_data attribute holding the value of @a extra_data, and a
257  * @a status_code attribute holding the value of @a status_code. In
258  * addition to sending the error to the client, a line with the client IP
259  * and message is recorded to the server log.
260  */
261  void send_error(const std::string& msg, const std::string& extra_data, unsigned int status_code, socket_ptr sock);
262 };
263 
264 } // end namespace campaignd
time_t update_pack_lifespan_
Definition: server.hpp:114
std::string feedback_url_format_
Definition: server.hpp:124
bool strict_versions_
Definition: server.hpp:116
bool ignore_address_stats(const std::string &addr) const
Checks if the specified address should never bump download counts.
Definition: server.cpp:749
request(const std::string &reqcmd, config &reqcfg, socket_ptr reqsock, boost::asio::yield_context yield)
Constructor.
Definition: server.hpp:82
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:415
Legacy add-ons server.
Definition: server.hpp:37
void handle_request_terms(const request &)
Definition: server.cpp:1151
static const std::size_t default_document_size_limit
Default upload size limit in bytes.
Definition: server.hpp:119
void handle_flush(const boost::system::error_code &error)
Definition: server.cpp:655
config & get_addon(const std::string &id)
Retrieves an addon by id if found, or a null config otherwise.
Definition: server.cpp:799
std::unordered_set< std::string > dirty_addons_
The set of unique addon names with pending metadata updates.
Definition: server.hpp:106
static l_noret error(LoadState *S, const char *why)
Definition: lundump.cpp:39
void handle_delete(const request &)
Definition: server.cpp:1672
Client request information object.
Definition: server.hpp:54
void load_config()
Reads the server configuration from WML.
Definition: server.cpp:329
server & operator=(const config &server)=delete
void fire(const std::string &hook, const std::string &addon)
Fires a hook script.
Definition: server.cpp:708
void handle_request_campaign_hash(const request &)
Definition: server.cpp:1105
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:122
std::map< std::string, std::string > hooks_
Definition: server.hpp:121
void load_blacklist()
Reads the add-ons upload blacklist from WML.
Definition: server.cpp:665
void register_handlers()
Registers client request handlers.
Definition: server.cpp:841
const std::string cfg_file_
Definition: server.hpp:110
std::map< std::string, request_handler > request_handlers_table
Definition: server.hpp:99
void handle_sighup(const boost::system::error_code &error, int signal_number)
Definition: server.cpp:636
boost::asio::basic_waitable_timer< std::chrono::steady_clock > flush_timer_
Definition: server.hpp:134
std::string blacklist_file_
Definition: server.hpp:130
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:511
const std::string & cmd
Definition: server.hpp:56
void delete_addon(const std::string &id)
Definition: server.cpp:809
blacklist blacklist_
Definition: server.hpp:129
void handle_change_passphrase(const request &)
Definition: server.cpp:1715
const std::string addr
Definition: server.hpp:60
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:66
void write_config()
Writes the server configuration WML back to disk.
Definition: server.cpp:688
std::string web_url_
Definition: server.hpp:126
config & server_info()
Retrieves the contents of the [server_info] WML node.
Definition: server.hpp:203
void handle_new_client(socket_ptr socket)
Definition: server.cpp:476
const config & server_info() const
Retrieves the contents of the [server_info] WML node.
Definition: server.hpp:200
void handle_request_campaign(const request &)
Definition: server.cpp:973
const socket_ptr sock
Definition: server.hpp:59
std::string client_address(const socket_ptr socket)
void handle_server_id(const request &)
Definition: server.cpp:853
std::vector< std::string > stats_exempt_ips_
Definition: server.hpp:132
friend std::ostream & operator<<(std::ostream &o, const request &r)
Definition: server.cpp:470
void handle_request_campaign_list(const request &)
Definition: server.cpp:872
std::function< void(server *, const request &req)> request_handler
Definition: server.hpp:98
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:1165
const config & cfg
Definition: server.hpp:57
void flush_cfg()
Starts timer to write config to disk every ten minutes.
Definition: server.cpp:649
std::shared_ptr< boost::asio::ip::tcp::socket > socket_ptr
Definition: server_base.hpp:43
config cfg_
Server config.
Definition: server.hpp:109
std::unordered_map< std::string, config > addons_
The hash map of addons metadata.
Definition: server.hpp:104
std::set< std::string > capabilities_
Definition: server.hpp:101
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:761
server(const std::string &cfg_file, unsigned short port=0)
Definition: server.cpp:277
void send_error(const std::string &msg, socket_ptr sock)
Send a client an error message.
Definition: server.cpp:769
void handle_upload(const request &)
Definition: server.cpp:1329
void mark_dirty(const std::string &addon)
Definition: server.hpp:175
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:127
int compress_level_
Used for add-on archives.
Definition: server.hpp:113