The Battle for Wesnoth  1.17.23+dev
wesnothd_connection.hpp
Go to the documentation of this file.
1 /*
2  Copyright (C) 2011 - 2023
3  by Sergey Popov <loonycyborg@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 #ifdef _WIN32
19 
20 #ifdef INADDR_ANY
21 #undef INADDR_ANY
22 #endif
23 
24 #ifdef INADDR_BROADCAST
25 #undef INADDR_BROADCAST
26 #endif
27 
28 #ifdef INADDR_NONE
29 #undef INADDR_NONE
30 #endif
31 
32 #endif // endif _WIN32
33 
34 #include "configr_assign.hpp"
36 
37 #include <boost/asio/io_context.hpp>
38 #include <boost/asio/ip/tcp.hpp>
39 #include <boost/asio/streambuf.hpp>
40 #include <boost/asio/ssl.hpp>
41 
42 #include <condition_variable>
43 #include <deque>
44 #include <future>
45 #include <list>
46 #include <mutex>
47 #include <queue>
48 #include <thread>
49 
50 class config;
51 
52 /** A class that represents a TCP/IP connection to the wesnothd server. */
54 {
55 public:
57 
60 
62 
63  /**
64  * Constructor.
65  *
66  * @param host Name of the host to connect to
67  * @param service Service identifier such as "80" or "http"
68  */
69  wesnothd_connection(const std::string& host, const std::string& service);
70 
71  /**
72  * Queues the given data to be sent to the server.
73  *
74  * @param request The data to send
75  */
76  void send_data(const configr_of& request);
77 
78  /**
79  * Receives the next pending data pack from the server, if available.
80  *
81  * @param result The object to which the received data will be written.
82  * @returns True if any data was available, false otherwise.
83  */
84  bool receive_data(config& result);
85 
86  /**
87  * Unlike @ref receive_data, waits until data is available instead of returning immediately.
88  *
89  * @param data Config object passed to @ref receive_data
90  * @returns True, since data will always be available.
91  */
93 
94  /** Waits until the server handshake is complete. */
95  void wait_for_handshake();
96 
97  /** True if connection is currently using TLS and thus is allowed to send cleartext passwords or auth tokens */
98  bool using_tls() const
99  {
100  return utils::holds_alternative<tls_socket>(socket_);
101  }
102 
103  void cancel();
104 
105  void stop();
106 
107  std::size_t bytes_to_write() const
108  {
109  return bytes_to_write_;
110  }
111 
112  std::size_t bytes_written() const
113  {
114  return bytes_written_;
115  }
116 
117  std::size_t bytes_to_read() const
118  {
119  return bytes_to_read_;
120  }
121 
122  std::size_t bytes_read() const
123  {
124  return bytes_read_;
125  }
126 
127  bool has_data_received() const
128  {
129  return !recv_queue_.empty();
130  }
131 
132  bool is_sending_data() const
133  {
134  return !send_queue_.empty();
135  }
136 
137 private:
138  std::thread worker_thread_;
139 
140  boost::asio::io_context io_context_;
141 
142  typedef boost::asio::ip::tcp::resolver resolver;
144 
145  boost::asio::ssl::context tls_context_;
146 
147  std::string host_;
148  std::string service_;
149  typedef std::unique_ptr<boost::asio::ip::tcp::socket> raw_socket;
150  typedef std::unique_ptr<boost::asio::ssl::stream<raw_socket::element_type>> tls_socket;
151  typedef utils::variant<raw_socket, tls_socket> any_socket;
152  bool use_tls_;
154 
155  boost::system::error_code last_error_;
156 
157  std::mutex last_error_mutex_;
158 
159  std::promise<void> handshake_finished_;
160 
161  boost::asio::streambuf read_buf_;
162 
163  using results_type = resolver::results_type;
164  using endpoint = const boost::asio::ip::tcp::endpoint&;
165 
166  void handle_resolve(const boost::system::error_code& ec, results_type results);
167  void handle_connect(const boost::system::error_code& ec, endpoint endpoint);
168 
169  void handshake();
170  void handle_handshake(const boost::system::error_code& ec);
171 
173 
175 
176  std::size_t is_write_complete(const boost::system::error_code& error, std::size_t bytes_transferred);
177  void handle_write(const boost::system::error_code& ec, std::size_t bytes_transferred);
178 
179  std::size_t is_read_complete(const boost::system::error_code& error, std::size_t bytes_transferred);
180  void handle_read(const boost::system::error_code& ec, std::size_t bytes_transferred);
181 
182  void send();
183  void recv();
184 
185  void set_keepalive(int seconds);
186 
187  template<typename T>
188  using data_queue = std::queue<T, std::list<T>>;
189 
192 
193  std::mutex recv_queue_mutex_;
194 
195  std::condition_variable recv_queue_lock_;
196 
197  uint32_t payload_size_;
198 
199  // TODO: do i need to guard the following 4 values with a mutex?
200  std::size_t bytes_to_write_;
201  std::size_t bytes_written_;
202  std::size_t bytes_to_read_;
203  std::size_t bytes_read_;
204 };
A config object defines a single node in a WML file, with access to child nodes.
Definition: config.hpp:161
A class that represents a TCP/IP connection to the wesnothd server.
bool using_tls() const
True if connection is currently using TLS and thus is allowed to send cleartext passwords or auth tok...
boost::asio::ssl::context tls_context_
void handle_handshake(const boost::system::error_code &ec)
const boost::asio::ip::tcp::endpoint & endpoint
std::size_t bytes_to_read() const
void handle_connect(const boost::system::error_code &ec, endpoint endpoint)
void handle_resolve(const boost::system::error_code &ec, results_type results)
data_queue< std::unique_ptr< boost::asio::streambuf > > send_queue_
std::condition_variable recv_queue_lock_
std::size_t is_write_complete(const boost::system::error_code &error, std::size_t bytes_transferred)
std::size_t bytes_to_write() const
wesnothd_connection(const wesnothd_connection &)=delete
data_queue< config > recv_queue_
void wait_for_handshake()
Waits until the server handshake is complete.
boost::asio::io_context io_context_
wesnothd_connection & operator=(const wesnothd_connection &)=delete
bool receive_data(config &result)
Receives the next pending data pack from the server, if available.
void handle_write(const boost::system::error_code &ec, std::size_t bytes_transferred)
void send_data(const configr_of &request)
Queues the given data to be sent to the server.
void set_keepalive(int seconds)
resolver::results_type results_type
boost::asio::streambuf read_buf_
bool wait_and_receive_data(config &data)
Unlike receive_data, waits until data is available instead of returning immediately.
void handle_read(const boost::system::error_code &ec, std::size_t bytes_transferred)
std::size_t bytes_written() const
std::queue< T, std::list< T > > data_queue
boost::asio::ip::tcp::resolver resolver
std::size_t bytes_read() const
std::unique_ptr< boost::asio::ip::tcp::socket > raw_socket
boost::system::error_code last_error_
std::unique_ptr< boost::asio::ssl::stream< raw_socket::element_type > > tls_socket
std::promise< void > handshake_finished_
std::size_t is_read_complete(const boost::system::error_code &error, std::size_t bytes_transferred)
utils::variant< raw_socket, tls_socket > any_socket
std::string_view data
Definition: picture.cpp:199
An error occurred inside the underlying network communication code (boost asio) TODO: find a short na...