-
-
Notifications
You must be signed in to change notification settings - Fork 988
/
wesnothd_connection.hpp
218 lines (166 loc) · 5.13 KB
/
wesnothd_connection.hpp
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
/*
Copyright (C) 2011 - 2018 by Sergey Popov <loonycyborg@gmail.com>
Part of the Battle for Wesnoth Project https://www.wesnoth.org/
This program is free software; you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation; either version 2 of the License, or
(at your option) any later version.
This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY.
See the COPYING file for more details.
*/
#pragma once
#ifdef _WIN32
#ifdef INADDR_ANY
#undef INADDR_ANY
#endif
#ifdef INADDR_BROADCAST
#undef INADDR_BROADCAST
#endif
#ifdef INADDR_NONE
#undef INADDR_NONE
#endif
#endif // endif _WIN32
#include "configr_assign.hpp"
#include "wesnothd_connection_error.hpp"
#if BOOST_VERSION >= 106600
#include <boost/asio/io_context.hpp>
#else
#include <boost/asio/io_service.hpp>
#endif
#include <boost/asio/ip/tcp.hpp>
#include <boost/asio/streambuf.hpp>
#include <boost/asio/ssl.hpp>
#include <condition_variable>
#include <deque>
#include <future>
#include <list>
#include <mutex>
#include <queue>
#include <thread>
class config;
union data_union {
char binary[4];
uint32_t num;
};
/** A class that represents a TCP/IP connection to the wesnothd server. */
class wesnothd_connection
{
public:
using error = wesnothd_connection_error;
wesnothd_connection(const wesnothd_connection&) = delete;
wesnothd_connection& operator=(const wesnothd_connection&) = delete;
~wesnothd_connection();
/**
* Constructor.
*
* @param host Name of the host to connect to
* @param service Service identifier such as "80" or "http"
* @param tls Whether we want to use TLS to make connection encrypted
*/
wesnothd_connection(const std::string& host, const std::string& service, bool tls);
/**
* Queues the given data to be sent to the server.
*
* @param request The data to send
*/
void send_data(const configr_of& request);
/**
* Receives the next pending data pack from the server, if available.
*
* @param result The object to which the received data will be written.
* @returns True if any data was available, false otherwise.
*/
bool receive_data(config& result);
/**
* Unlike @ref receive_data, waits until data is available instead of returning immediately.
*
* @param data Config object passed to @ref receive_data
* @returns True, since data will always be available.
*/
bool wait_and_receive_data(config& data);
/** Waits until the server handshake is complete. */
void wait_for_handshake();
void cancel();
void stop();
std::size_t bytes_to_write() const
{
return bytes_to_write_;
}
std::size_t bytes_written() const
{
return bytes_written_;
}
std::size_t bytes_to_read() const
{
return bytes_to_read_;
}
std::size_t bytes_read() const
{
return bytes_read_;
}
bool has_data_received() const
{
return !recv_queue_.empty();
}
bool is_sending_data() const
{
return !send_queue_.empty();
}
private:
std::thread worker_thread_;
#if BOOST_VERSION >= 106600
boost::asio::io_context io_context_;
#else
boost::asio::io_service io_context_;
#endif
typedef boost::asio::ip::tcp::resolver resolver;
resolver resolver_;
boost::asio::ssl::context tls_context_;
std::string host_;
std::string service_;
typedef boost::asio::ip::tcp::socket raw_socket;
typedef boost::asio::ssl::stream<raw_socket> tls_socket;
typedef utils::variant<raw_socket, tls_socket> any_socket;
bool use_tls_;
any_socket socket_;
boost::system::error_code last_error_;
std::mutex last_error_mutex_;
std::promise<void> handshake_finished_;
boost::asio::streambuf read_buf_;
#if BOOST_VERSION >= 106600
using results_type = resolver::results_type;
using endpoint = const boost::asio::ip::tcp::endpoint&;
#else
using results_type = resolver::iterator;
using endpoint = resolver::iterator;
#endif
void handle_resolve(const boost::system::error_code& ec, results_type results);
void handle_connect(const boost::system::error_code& ec, endpoint endpoint);
void handshake();
void handle_handshake(const boost::system::error_code& ec);
data_union handshake_response_;
void fallback_to_unencrypted();
std::size_t is_write_complete(const boost::system::error_code& error, std::size_t bytes_transferred);
void handle_write(const boost::system::error_code& ec, std::size_t bytes_transferred);
std::size_t is_read_complete(const boost::system::error_code& error, std::size_t bytes_transferred);
void handle_read(const boost::system::error_code& ec, std::size_t bytes_transferred);
void send();
void recv();
template<typename T>
using data_queue = std::queue<T, std::list<T>>;
#if BOOST_VERSION >= 106600
data_queue<std::unique_ptr<boost::asio::streambuf>> send_queue_;
#else
data_queue<std::shared_ptr<boost::asio::streambuf>> send_queue_;
#endif
data_queue<config> recv_queue_;
std::mutex recv_queue_mutex_;
std::condition_variable recv_queue_lock_;
uint32_t payload_size_;
// TODO: do i need to guard the following 4 values with a mutex?
std::size_t bytes_to_write_;
std::size_t bytes_written_;
std::size_t bytes_to_read_;
std::size_t bytes_read_;
};