The Battle for Wesnoth  1.15.0-dev
campaign_server.hpp
Go to the documentation of this file.
1 /*
2  Copyright (C) 2003 - 2018 by David White <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 as published by
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 #pragma once
16 
18 #include "server/server_base.hpp"
19 #include "server/simple_wml.hpp"
20 
21 #include "utils/functional.hpp"
22 #include <boost/unordered_map.hpp>
23 #include <boost/asio/steady_timer.hpp>
24 
25 #include <chrono>
26 
27 namespace campaignd {
28 
29 /**
30  * Legacy add-ons server.
31  */
32 class server : public server_base
33 {
34 public:
35  explicit server(const std::string& cfg_file);
36  server(const config& server) = delete;
37  ~server();
38 
39  server& operator=(const config& server) = delete;
40 
41 private:
42  /**
43  * Client request information object.
44  *
45  * Contains data and metadata associated with a single request from a
46  * remote add-ons client, in a light-weight format for passing to request
47  * handlers.
48  */
49  struct request
50  {
51  const std::string& cmd;
52  const config& cfg;
53 
55  const std::string addr;
56 
57  /**
58  * Constructor.
59  *
60  * @param reqcmd Request command.
61  * @param reqcfg Request WML body.
62  * @param reqsock Client socket that initiated the request.
63  *
64  * @note Neither @a reqcmd nor @a reqcfg are copied into instances, so
65  * they are required to exist for as long as every @a request
66  * instance that uses them.
67  */
68  request(const std::string& reqcmd,
69  const config& reqcfg,
70  socket_ptr reqsock)
71  : cmd(reqcmd)
72  , cfg(reqcfg)
73  , sock(reqsock)
74  , addr(client_address(sock))
75  {}
76  };
77 
78  typedef std::function<void (server*, const request& req)> request_handler;
79  typedef std::map<std::string, request_handler> request_handlers_table;
80 
82  const std::string cfg_file_;
83 
84  bool read_only_;
85  int compress_level_; /**< Used for add-on archives. */
86 
87  /** Default upload size limit in bytes. */
88  static const std::size_t default_document_size_limit = 100 * 1024 * 1024;
89 
90  std::map<std::string, std::string> hooks_;
91  request_handlers_table handlers_;
92 
93  std::string feedback_url_format_;
94 
96  std::string blacklist_file_;
97 
98  std::vector<std::string> stats_exempt_ips_;
99 
100  boost::asio::basic_waitable_timer<std::chrono::steady_clock> flush_timer_;
101 
102  void handle_new_client(socket_ptr socket);
103  void handle_request(socket_ptr socket, std::shared_ptr<simple_wml::document> doc);
104 
105 #ifndef _WIN32
106  void handle_read_from_fifo(const boost::system::error_code& error, std::size_t bytes_transferred);
107 
108  void handle_sighup(const boost::system::error_code& error, int signal_number);
109 #endif
110 
111  /**
112  * Starts timer to write config to disk every ten minutes.
113  */
114  void flush_cfg();
115  void handle_flush(const boost::system::error_code& error);
116 
117  /**
118  * Reads the server configuration from WML.
119  */
120  void load_config();
121 
122  /**
123  * Writes the server configuration WML back to disk.
124  */
125  void write_config();
126 
127  /**
128  * Reads the add-ons upload blacklist from WML.
129  */
130  void load_blacklist();
131 
132  /**
133  * Fires a hook script.
134  */
135  void fire(const std::string& hook, const std::string& addon);
136 
137  /** Retrieves the contents of the [campaigns] WML node. */
138  const config& campaigns() const { return cfg_.child("campaigns"); }
139 
140  /** Retrieves the contents of the [campaigns] WML node. */
141  config& campaigns() { return cfg_.child("campaigns"); }
142 
143  /** Retrieves a campaign by id if found, or a null config otherwise. */
144  config& get_campaign(const std::string& id) { return campaigns().find_child("campaign", "name", id); }
145 
146  void delete_campaign(const std::string& id);
147 
148  /** Retrieves the contents of the [server_info] WML node. */
149  const config& server_info() const { return cfg_.child("server_info"); }
150 
151  /** Retrieves the contents of the [server_info] WML node. */
152  config& server_info() { return cfg_.child("server_info"); }
153 
154  /** Checks if the specified address should never bump download counts. */
155  bool ignore_address_stats(const std::string& addr) const;
156 
157  //
158  // Request handling.
159  //
160 
161  /**
162  * Registers client request handlers.
163  *
164  * This is called by the class constructor. Individual handlers must be
165  * methods of this class that take a single parameter of type @a request
166  * and they are registered using the @a register_handler method.
167  *
168  * When adding new handlers, make sure to update the implementation of
169  * this method accordingly so they are recognized and invoked at runtime.
170  */
171  void register_handlers();
172 
174  void handle_request_campaign(const request&);
175  void handle_request_terms(const request&);
176  void handle_upload(const request&);
177  void handle_delete(const request&);
178  void handle_change_passphrase(const request&);
179 
180  /**
181  * Send a client an informational message.
182  *
183  * The WML sent consists of a document containing a single @p [message]
184  * child with a @a message attribute holding the value of @a msg.
185  */
186  void send_message(const std::string& msg, socket_ptr sock);
187 
188  /**
189  * Send a client an error message.
190  *
191  * The WML sent consists of a document containing a single @p [error] child
192  * with a @a message attribute holding the value of @a msg. In addition to
193  * sending the error to the client, a line with the client IP and message
194  * is recorded to the server log.
195  */
196  void send_error(const std::string& msg, socket_ptr sock);
197 
198  /**
199  * Send a client an error message.
200  *
201  * The WML sent consists of a document containing a single @p [error] child
202  * with a @a message attribute holding the value of @a msg, and an
203  * @a extra_data attribute holding the value of @a extra_data. In addition
204  * to sending the error to the client, a line with the client IP and
205  * message is recorded to the server log.
206  */
207  void send_error(const std::string& msg, const std::string& extra_data, socket_ptr sock);
208 };
209 
210 } // end namespace campaignd
std::string feedback_url_format_
bool ignore_address_stats(const std::string &addr) const
Checks if the specified address should never bump download counts.
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:423
Legacy add-ons server.
void handle_request_terms(const request &)
static const std::size_t default_document_size_limit
Default upload size limit in bytes.
void handle_flush(const boost::system::error_code &error)
config & find_child(config_key_type key, const std::string &name, const std::string &value)
Returns the first child of tag key with a name attribute containing value.
Definition: config.cpp:838
void handle_request(socket_ptr socket, std::shared_ptr< simple_wml::document > doc)
static l_noret error(LoadState *S, const char *why)
Definition: lundump.cpp:39
void handle_delete(const request &)
Client request information object.
void load_config()
Reads the server configuration from WML.
request(const std::string &reqcmd, const config &reqcfg, socket_ptr reqsock)
Constructor.
config & campaigns()
Retrieves the contents of the [campaigns] WML node.
void delete_campaign(const std::string &id)
server & operator=(const config &server)=delete
void fire(const std::string &hook, const std::string &addon)
Fires a hook script.
static void msg(const char *act, debug_info &i, const char *to="", const char *result="")
Definition: debugger.cpp:109
request_handlers_table handlers_
std::map< std::string, std::string > hooks_
void load_blacklist()
Reads the add-ons upload blacklist from WML.
void register_handlers()
Registers client request handlers.
const std::string cfg_file_
std::map< std::string, request_handler > request_handlers_table
void handle_sighup(const boost::system::error_code &error, int signal_number)
boost::asio::basic_waitable_timer< std::chrono::steady_clock > flush_timer_
std::string blacklist_file_
Add-on blacklist table.
Definition: blacklist.hpp:41
void handle_read_from_fifo(const boost::system::error_code &error, std::size_t bytes_transferred)
void handle_change_passphrase(const request &)
void write_config()
Writes the server configuration WML back to disk.
config & server_info()
Retrieves the contents of the [server_info] WML node.
void handle_new_client(socket_ptr socket)
const config & server_info() const
Retrieves the contents of the [server_info] WML node.
void handle_request_campaign(const request &)
std::string client_address(const socket_ptr socket)
std::vector< std::string > stats_exempt_ips_
const config & campaigns() const
Retrieves the contents of the [campaigns] WML node.
void handle_request_campaign_list(const request &)
std::function< void(server *, const request &req)> request_handler
void flush_cfg()
Starts timer to write config to disk every ten minutes.
std::shared_ptr< boost::asio::ip::tcp::socket > socket_ptr
Definition: server_base.hpp:28
A config object defines a single node in a WML file, with access to child nodes.
Definition: config.hpp:92
void send_message(const std::string &msg, socket_ptr sock)
Send a client an informational message.
void send_error(const std::string &msg, socket_ptr sock)
Send a client an error message.
void handle_upload(const request &)
server(const std::string &cfg_file)
config & get_campaign(const std::string &id)
Retrieves a campaign by id if found, or a null config otherwise.
Base class for servers using Wesnoth&#39;s WML over TCP protocol.
int compress_level_
Used for add-on archives.