16 #define BOOST_ASIO_NO_DEPRECATED 24 #include <boost/asio/connect.hpp> 25 #include <boost/asio/read.hpp> 26 #include <boost/asio/write.hpp> 34 #define DBG_NW LOG_STREAM(debug, log_network) 35 #define LOG_NW LOG_STREAM(info, log_network) 36 #define WRN_NW LOG_STREAM(warn, log_network) 37 #define ERR_NW LOG_STREAM(err, log_network) 41 std::deque<boost::asio::const_buffer> split_buffer(boost::asio::streambuf::const_buffers_type source_buffer)
43 const unsigned int chunk_size = 4096;
45 std::deque<boost::asio::const_buffer> buffers;
46 unsigned int remaining_size = boost::asio::buffer_size(source_buffer);
48 const uint8_t*
data =
static_cast<const uint8_t*
>(source_buffer.data());
50 while(remaining_size > 0u) {
51 unsigned int size = std::min(remaining_size, chunk_size);
52 buffers.emplace_back(data, size);
54 remaining_size -=
size;
63 using boost::system::system_error;
69 , resolver_(io_context_)
82 boost::system::error_code ec;
83 auto result =
resolver_.resolve(host, service, boost::asio::ip::resolver_query_base::numeric_host, ec);
92 LOG_NW <<
"Resolving hostname: " << host;
97 if(
auto socket = utils::get_if<tls_socket>(&
socket_)) {
98 boost::system::error_code ec;
100 (*socket)->async_shutdown([](
const boost::system::error_code&) {} );
101 const char buffer[] =
"";
110 throw system_error(ec);
113 boost::asio::async_connect(*utils::get<raw_socket>(
socket_), results,
120 ERR_NW <<
"Tried all IPs. Giving up";
121 throw system_error(ec);
123 LOG_NW <<
"Connected to " << endpoint.address();
125 if(endpoint.address().is_loopback()) {
135 static const uint32_t tls_handshake = htonl(uint32_t(1));
137 boost::asio::async_write(
138 *utils::get<raw_socket>(
socket_),
139 boost::asio::buffer(
use_tls_ ? reinterpret_cast<const char*>(&tls_handshake) : reinterpret_cast<const char*>(&handshake), 4),
143 boost::asio::async_read(*utils::get<raw_socket>(
socket_), boost::asio::buffer(reinterpret_cast<std::byte*>(&
handshake_response_), 4),
149 return [verifier](
bool preverified, boost::asio::ssl::verify_context& ctx) {
150 char subject_name[256];
151 X509* cert = X509_STORE_CTX_get_current_cert(ctx.native_handle());
152 X509_NAME_oneline(X509_get_subject_name(cert), subject_name, 256);
153 bool verified = verifier(preverified, ctx);
154 DBG_NW <<
"Verifying TLS certificate: " << subject_name <<
": " <<
155 (verified ?
"verified" :
"failed");
156 BIO* bio = BIO_new(BIO_s_mem());
158 X509_print(bio, cert);
159 while(BIO_read(bio, buffer, 1024) > 0)
171 if(ec == boost::asio::error::eof &&
use_tls_) {
177 throw system_error(ec);
193 auto& socket { *utils::get<tls_socket>(
socket_) };
195 socket.set_verify_mode(
196 boost::asio::ssl::verify_peer |
197 boost::asio::ssl::verify_fail_if_no_peer_cert
200 #if BOOST_VERSION >= 107300 201 socket.set_verify_callback(
verbose_verify(boost::asio::ssl::host_name_verification(
host_)));
206 socket.async_handshake(boost::asio::ssl::stream_base::client, [
this](
const boost::system::error_code& ec) {
208 throw system_error(ec);
227 boost::asio::ip::tcp::endpoint
endpoint { utils::get<raw_socket>(
socket_)->remote_endpoint() };
228 utils::get<raw_socket>(
socket_)->close();
240 read_buf_.reset(
new boost::asio::streambuf);
249 bufs.push_front(boost::asio::buffer(reinterpret_cast<const char*>(&
payload_size_), 4));
251 utils::visit([
this, &bufs, &response](
auto&& socket) {
252 boost::asio::async_write(*socket, bufs,
256 boost::asio::async_read(*socket, *
read_buf_,
264 utils::visit([](
auto&& socket) {
265 if(socket->lowest_layer().is_open()) {
266 boost::system::error_code ec;
271 #pragma warning(push) 272 #pragma warning(disable:4996) 274 socket->lowest_layer().cancel(ec);
280 WRN_NW <<
"Failed to cancel network operations: " << ec.message();
293 throw system_error(ec);
302 DBG_NW <<
"Written " << bytes_transferred <<
" bytes.";
307 throw system_error(ec);
314 throw system_error(ec);
318 if(bytes_transferred < 4) {
326 is.read(reinterpret_cast<char*>(&data_size), 4);
340 DBG_NW <<
"Read " << bytes_transferred <<
" bytes.";
346 if(ec && ec != boost::asio::error::eof) {
347 throw system_error(ec);
void handle_read(const boost::system::error_code &ec, std::size_t bytes_transferred, config &response)
connection(const std::string &host, const std::string &service)
Constructor.
uint32_t handshake_response_
std::size_t bytes_to_read_
void load_tls_root_certs(boost::asio::ssl::context &ctx)
void read_gz(config &cfg, std::istream &file, abstract_validator *validator)
Might throw a std::ios_base::failure especially a gzip_error.
auto verbose_verify(Verifier &&verifier)
std::size_t is_write_complete(const boost::system::error_code &error, std::size_t bytes_transferred)
void write(std::ostream &out, const configr_of &cfg, unsigned int level)
boost::asio::io_context io_context_
std::size_t size(const std::string &str)
Length in characters of a UTF-8 string.
void handle_resolve(const boost::system::error_code &ec, results_type results)
std::size_t bytes_to_write_
void write_gz(std::ostream &out, const configr_of &cfg)
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)
const boost::asio::ip::tcp::endpoint & endpoint
static lg::log_domain log_network("network")
void transfer(const config &request, config &response)
boost::asio::ssl::context tls_context_
static map_location::DIRECTION s
std::size_t bytes_written_
resolver::results_type results_type
std::unique_ptr< boost::asio::streambuf > read_buf_
void fallback_to_unencrypted()
std::unique_ptr< boost::asio::streambuf > write_buf_
Standard logging facilities (interface).
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.
void handle_handshake(const boost::system::error_code &ec)
void handle_connect(const boost::system::error_code &ec, endpoint endpoint)