The Battle for Wesnoth  1.17.0-dev
network_asio.hpp
Go to the documentation of this file.
1 /*
2  Copyright (C) 2011 - 2021
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
33 
34 #include "exceptions.hpp"
35 #include "utils/variant.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 class config;
43 
44 namespace network_asio
45 {
46 struct error : public game::error
47 {
48  error(const boost::system::error_code& error)
49  : game::error(error.message())
50  {
51  }
52 };
53 
54 /** A class that represents a TCP/IP connection. */
56 {
57 public:
58  /**
59  * Constructor.
60  *
61  * @param host Name of the host to connect to
62  * @param service Service identifier such as "80" or "http"
63  */
64  connection(const std::string& host, const std::string& service);
65  ~connection();
66 
67  void transfer(const config& request, config& response);
68 
69  /** Handle all pending asynchronous events and return */
70  std::size_t poll()
71  {
72  try {
73  return io_context_.poll();
74  } catch(const boost::system::system_error& err) {
75  if(err.code() == boost::asio::error::operation_aborted) {
76  return 1;
77  }
78 
79  throw error(err.code());
80  }
81  }
82 
83  /**
84  * Run asio's event loop
85  *
86  * Handle asynchronous events blocking until all asynchronous operations have finished.
87  */
88  void run()
89  {
90  io_context_.run();
91  }
92 
93  void cancel();
94 
95  /** True if connected and no high-level operation is in progress */
96  bool done() const
97  {
98  return done_;
99  }
100 
101  /** True if connection is currently using TLS and thus is allowed to send cleartext passwords or auth tokens */
102  bool using_tls() const
103  {
104  // Calling this function before connection is ready may return wrong result
105  assert(done_);
106  return utils::holds_alternative<tls_socket>(socket_);
107  }
108 
109  std::size_t bytes_to_write() const
110  {
111  return bytes_to_write_;
112  }
113 
114  std::size_t bytes_written() const
115  {
116  return bytes_written_;
117  }
118 
119  std::size_t bytes_to_read() const
120  {
121  return bytes_to_read_;
122  }
123 
124  std::size_t bytes_read() const
125  {
126  return bytes_read_;
127  }
128 
129 private:
130  boost::asio::io_context io_context_;
131 
132  std::string host_;
133  const std::string service_;
134  typedef boost::asio::ip::tcp::resolver resolver;
135  resolver resolver_;
136 
137  boost::asio::ssl::context tls_context_ { boost::asio::ssl::context::sslv23 };
138 
139  typedef std::unique_ptr<boost::asio::ip::tcp::socket> raw_socket;
140  typedef std::unique_ptr<boost::asio::ssl::stream<raw_socket::element_type>> tls_socket;
141  typedef utils::variant<raw_socket, tls_socket> any_socket;
142  bool use_tls_;
143  any_socket socket_;
144 
145  bool done_;
146 
147  std::unique_ptr<boost::asio::streambuf> write_buf_;
148  std::unique_ptr<boost::asio::streambuf> read_buf_;
149 
150  using results_type = resolver::results_type;
151  using endpoint = const boost::asio::ip::tcp::endpoint&;
152 
153  void handle_resolve(const boost::system::error_code& ec, results_type results);
154  void handle_connect(const boost::system::error_code& ec, endpoint endpoint);
155 
156  void handshake();
157  void handle_handshake(const boost::system::error_code& ec);
158 
160 
161  void fallback_to_unencrypted();
162 
163  std::size_t is_write_complete(const boost::system::error_code& error, std::size_t bytes_transferred);
164  void handle_write(const boost::system::error_code& ec, std::size_t bytes_transferred);
165 
166  std::size_t is_read_complete(const boost::system::error_code& error, std::size_t bytes_transferred);
167  void handle_read(const boost::system::error_code& ec, std::size_t bytes_transferred, config& response);
168 
169  uint32_t payload_size_;
170 
171  std::size_t bytes_to_write_;
172  std::size_t bytes_written_;
173  std::size_t bytes_to_read_;
174  std::size_t bytes_read_;
175 };
176 }
std::size_t bytes_read() const
utils::variant< raw_socket, tls_socket > any_socket
const std::string service_
boost::asio::ip::tcp::resolver resolver
boost::asio::io_context io_context_
std::size_t bytes_to_read() const
A class that represents a TCP/IP connection.
error(const boost::system::error_code &error)
bool done() const
True if connected and no high-level operation is in progress.
const boost::asio::ip::tcp::endpoint & endpoint
bool using_tls() const
True if connection is currently using TLS and thus is allowed to send cleartext passwords or auth tok...
logger & err()
Definition: log.cpp:77
void run()
Run asio&#39;s event loop.
resolver::results_type results_type
std::unique_ptr< boost::asio::streambuf > read_buf_
Base class for all the errors encountered by the engine.
Definition: exceptions.hpp:28
std::unique_ptr< boost::asio::streambuf > write_buf_
std::string message
Definition: exceptions.hpp:30
std::size_t bytes_written() const
MacOS doesn&#39;t support std::visit when targing MacOS < 10.14 (currently we target 10.11).
std::size_t poll()
Handle all pending asynchronous events and return.
std::unique_ptr< boost::asio::ssl::stream< raw_socket::element_type > > tls_socket
std::unique_ptr< boost::asio::ip::tcp::socket > raw_socket
A config object defines a single node in a WML file, with access to child nodes.
Definition: config.hpp:61
std::size_t bytes_to_write() const