16 #define BOOST_ASIO_NO_DEPRECATED
24 #include <boost/asio/connect.hpp>
25 #include <boost/asio/read.hpp>
33 #define DBG_NW LOG_STREAM(debug, log_network)
34 #define LOG_NW LOG_STREAM(info, log_network)
35 #define WRN_NW LOG_STREAM(warn, log_network)
36 #define ERR_NW LOG_STREAM(err, log_network)
40 std::deque<boost::asio::const_buffer> split_buffer(boost::asio::streambuf::const_buffers_type source_buffer)
42 const unsigned int chunk_size = 4096;
44 std::deque<boost::asio::const_buffer> buffers;
45 unsigned int remaining_size = boost::asio::buffer_size(source_buffer);
47 const uint8_t*
data =
static_cast<const uint8_t*
>(source_buffer.data());
49 while(remaining_size > 0u) {
50 unsigned int size = std::min(remaining_size, chunk_size);
53 remaining_size -=
size;
62 using boost::system::system_error;
68 , resolver_(io_context_)
74 , handshake_response_()
81 boost::system::error_code ec;
82 auto result =
resolver_.resolve(host, service, boost::asio::ip::resolver_query_base::numeric_host, ec);
91 LOG_NW <<
"Resolving hostname: " << host;
96 if(
auto socket = utils::get_if<tls_socket>(&
socket_)) {
97 boost::system::error_code ec;
99 (*socket)->async_shutdown([](
const boost::system::error_code&) {} );
100 const char buffer[] =
"";
109 throw system_error(ec);
112 boost::asio::async_connect(*utils::get<raw_socket>(
socket_), results,
119 ERR_NW <<
"Tried all IPs. Giving up";
120 throw system_error(ec);
131 static const uint32_t tls_handshake = htonl(uint32_t(1));
133 boost::asio::async_write(
134 *utils::get<raw_socket>(
socket_),
135 boost::asio::buffer(
use_tls_ ?
reinterpret_cast<const char*
>(&tls_handshake) :
reinterpret_cast<const char*
>(&
handshake), 4),
139 boost::asio::async_read(*utils::get<raw_socket>(
socket_), boost::asio::buffer(
reinterpret_cast<std::byte*
>(&
handshake_response_), 4),
145 return [verifier](
bool preverified, boost::asio::ssl::verify_context& ctx) {
146 char subject_name[256];
147 X509* cert = X509_STORE_CTX_get_current_cert(ctx.native_handle());
148 X509_NAME_oneline(X509_get_subject_name(cert), subject_name, 256);
149 bool verified = verifier(preverified, ctx);
150 DBG_NW <<
"Verifying TLS certificate: " << subject_name <<
": " <<
151 (verified ?
"verified" :
"failed");
152 BIO* bio = BIO_new(BIO_s_mem());
154 X509_print(bio, cert);
155 while(BIO_read(bio, buffer, 1024) > 0)
167 if(ec == boost::asio::error::eof &&
use_tls_) {
173 throw system_error(ec);
189 auto& socket { *utils::get<tls_socket>(
socket_) };
191 socket.set_verify_mode(
192 boost::asio::ssl::verify_peer |
193 boost::asio::ssl::verify_fail_if_no_peer_cert
196 #if BOOST_VERSION >= 107300
197 socket.set_verify_callback(
verbose_verify(boost::asio::ssl::host_name_verification(
host_)));
202 socket.async_handshake(boost::asio::ssl::stream_base::client, [
this](
const boost::system::error_code& ec) {
204 throw system_error(ec);
223 boost::asio::ip::tcp::endpoint
endpoint { utils::get<raw_socket>(
socket_)->remote_endpoint() };
224 utils::get<raw_socket>(
socket_)->close();
236 read_buf_.reset(
new boost::asio::streambuf);
245 bufs.push_front(boost::asio::buffer(
reinterpret_cast<const char*
>(&
payload_size_), 4));
247 utils::visit([
this, &bufs, &response](
auto&& socket) {
248 boost::asio::async_write(*socket, bufs,
252 boost::asio::async_read(*socket, *
read_buf_,
260 utils::visit([](
auto&& socket) {
261 if(socket->lowest_layer().is_open()) {
262 boost::system::error_code ec;
267 #pragma warning(push)
268 #pragma warning(disable:4996)
270 socket->lowest_layer().cancel(ec);
276 WRN_NW <<
"Failed to cancel network operations: " << ec.message();
286 std::size_t connection::is_write_complete(
const boost::system::error_code& ec, std::size_t bytes_transferred)
289 throw system_error(ec);
292 bytes_written_ = bytes_transferred;
293 return bytes_to_write_ - bytes_transferred;
296 void connection::handle_write(
const boost::system::error_code& ec, std::size_t bytes_transferred)
298 DBG_NW <<
"Written " << bytes_transferred <<
" bytes.";
300 write_buf_->consume(bytes_transferred);
303 throw system_error(ec);
307 std::size_t connection::is_read_complete(
const boost::system::error_code& ec, std::size_t bytes_transferred)
310 throw system_error(ec);
313 bytes_read_ = bytes_transferred;
314 if(bytes_transferred < 4) {
318 if(!bytes_to_read_) {
319 std::istream is(read_buf_.get());
322 is.read(
reinterpret_cast<char*
>(&data_size), 4);
323 bytes_to_read_ = ntohl(data_size) + 4;
326 if(bytes_to_read_ < 4) {
327 bytes_to_read_ = bytes_transferred;
331 return bytes_to_read_ - bytes_transferred;
334 void connection::handle_read(
const boost::system::error_code& ec, std::size_t bytes_transferred,
config& response)
336 DBG_NW <<
"Read " << bytes_transferred <<
" bytes.";
342 if(ec && ec != boost::asio::error::eof) {
343 throw system_error(ec);
346 std::istream is(read_buf_.get());
A config object defines a single node in a WML file, with access to child nodes.
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 transfer(const config &request, config &response)
std::unique_ptr< boost::asio::ssl::stream< raw_socket::element_type > > tls_socket
uint32_t handshake_response_
void fallback_to_unencrypted()
resolver::results_type results_type
std::size_t is_write_complete(const boost::system::error_code &error, std::size_t bytes_transferred)
boost::asio::io_context io_context_
std::unique_ptr< boost::asio::ip::tcp::socket > raw_socket
void handle_read(const boost::system::error_code &ec, std::size_t bytes_transferred, config &response)
std::unique_ptr< boost::asio::streambuf > write_buf_
void handle_handshake(const boost::system::error_code &ec)
void handle_connect(const boost::system::error_code &ec, endpoint endpoint)
connection(const std::string &host, const std::string &service)
Constructor.
std::size_t bytes_to_write_
std::size_t bytes_written_
boost::asio::ssl::context tls_context_
void handle_resolve(const boost::system::error_code &ec, results_type results)
const boost::asio::ip::tcp::endpoint & endpoint
std::unique_ptr< boost::asio::streambuf > read_buf_
Standard logging facilities (interface).
void load_tls_root_certs(boost::asio::ssl::context &ctx)
auto verbose_verify(Verifier &&verifier)
std::size_t size(const std::string &str)
Length in characters of a UTF-8 string.
static lg::log_domain log_network("network")
void write_gz(std::ostream &out, const configr_of &cfg)
void write(std::ostream &out, const configr_of &cfg, unsigned int level)
void read_gz(config &cfg, std::istream &file, abstract_validator *validator)
Might throw a std::ios_base::failure especially a gzip_error.
static map_location::direction s