The Battle for Wesnoth  1.13.10+dev
 All Classes Namespaces Files Functions Variables Typedefs Enumerations Enumerator Friends Macros Modules Pages
campaign_server.hpp
Go to the documentation of this file.
1 /*
2  Copyright (C) 2003 - 2017 by David White <dave@whitevine.net>
3  Part of the Battle for Wesnoth Project http://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 
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 
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 size_t default_document_size_limit = 100 * 1024 * 1024;
89 
90  std::map<std::string, std::string> hooks_;
91  request_handlers_table handlers_;
92 
94 
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  /** Retrieves the contents of the [server_info] WML node. */
147  const config& server_info() const { return cfg_.child("server_info"); }
148 
149  /** Retrieves the contents of the [server_info] WML node. */
150  config& server_info() { return cfg_.child("server_info"); }
151 
152  /** Checks if the specified address should never bump download counts. */
153  bool ignore_address_stats(const std::string& addr) const;
154 
155  //
156  // Request handling.
157  //
158 
159  /**
160  * Registers client request handlers.
161  *
162  * This is called by the class constructor. Individual handlers must be
163  * methods of this class that take a single parameter of type @a request
164  * and they are registered using the @a register_handler method.
165  *
166  * When adding new handlers, make sure to update the implementation of
167  * this method accordingly so they are recognized and invoked at runtime.
168  */
169  void register_handlers();
170 
171  void handle_request_campaign_list(const request&);
172  void handle_request_campaign(const request&);
173  void handle_request_terms(const request&);
174  void handle_upload(const request&);
175  void handle_delete(const request&);
176  void handle_change_passphrase(const request&);
177 
178  /**
179  * Send a client an informational message.
180  *
181  * The WML sent consists of a document containing a single @p [message]
182  * child with a @a message attribute holding the value of @a msg.
183  */
184  void send_message(const std::string& msg, socket_ptr sock);
185 
186  /**
187  * Send a client an error message.
188  *
189  * The WML sent consists of a document containing a single @p [error] child
190  * with a @a message attribute holding the value of @a msg. In addition to
191  * sending the error to the client, a line with the client IP and message
192  * is recorded to the server log.
193  */
194  void send_error(const std::string& msg, socket_ptr sock);
195 
196  /**
197  * Send a client an error message.
198  *
199  * The WML sent consists of a document containing a single @p [error] child
200  * with a @a message attribute holding the value of @a msg, and an
201  * @a extra_data attribute holding the value of @a extra_data. In addition
202  * to sending the error to the client, a line with the client IP and
203  * message is recorded to the server log.
204  */
205  void send_error(const std::string& msg, const std::string& extra_data, socket_ptr sock);
206 };
207 
208 } // end namespace campaignd
std::string feedback_url_format_
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:400
bool ignore_address_stats(const std::string &addr) const
Checks if the specified address should never bump download counts.
std::vector< char_t > string
Legacy add-ons server.
void handle_request_terms(const request &)
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:763
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.
const config & server_info() const
Retrieves the contents of the [server_info] WML node.
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:110
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::string client_address(socket_ptr socket)
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_
const config & campaigns() const
Retrieves the contents of the [campaigns] WML node.
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)
void handle_request_campaign(const request &)
std::vector< std::string > stats_exempt_ips_
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
static const size_t default_document_size_limit
Default upload size limit in bytes.
A config object defines a single node in a WML file, with access to child nodes.
Definition: config.hpp:93
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's WML over TCP protocol.
int compress_level_
Used for add-on archives.