Skip to content

Commit a31b067

Browse files
Boost.Asio compatibility (#2273)
* Disable using bundled standalone Asio in boost-asio workflow * Add BOOST_ROOT to boost-asio workflow * Add install-boost id * Fix Boost_ROOT casing * Fix Boost_ROOT casing on the proper variable * Fix http_client asio include * Fix compilation errors --------- Co-authored-by: Stephen Berry <stephenberry.developer@gmail.com>
1 parent b7e4e04 commit a31b067

File tree

11 files changed

+66
-49
lines changed

11 files changed

+66
-49
lines changed

.github/workflows/boost-asio.yml

Lines changed: 5 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -45,6 +45,7 @@ jobs:
4545
echo "PATH=/usr/lib/llvm-${{ matrix.compiler.version }}/bin:$PATH" >> $GITHUB_ENV
4646
4747
- name: Install Boost
48+
id: install-boost
4849
uses: MarkusJx/install-boost@v2
4950
with:
5051
boost_version: ${{ matrix.boost_version }}
@@ -61,7 +62,10 @@ jobs:
6162
-DCMAKE_BUILD_TYPE=Debug \
6263
-DCMAKE_CXX_STANDARD=23 \
6364
-DCMAKE_CXX_FLAGS="$CMAKE_CXX_FLAGS" \
64-
-DCMAKE_EXE_LINKER_FLAGS="$CMAKE_EXE_LINKER_FLAGS"
65+
-DCMAKE_EXE_LINKER_FLAGS="$CMAKE_EXE_LINKER_FLAGS" \
66+
-Dglaze_USE_BUNDLED_ASIO=OFF
67+
env:
68+
Boost_ROOT: ${{ steps.install-boost.outputs.BOOST_ROOT }}
6569

6670
- name: Build
6771
# Only build networking tests that actually use Asio

include/glaze/ext/glaze_asio.hpp

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -6,12 +6,18 @@
66
#if __has_include(<asio.hpp>) && !defined(GLZ_USE_BOOST_ASIO)
77
#include <asio.hpp>
88
#include <asio/signal_set.hpp>
9+
#ifdef GLZ_ENABLE_SSL
10+
#include <asio/ssl.hpp>
11+
#endif
912
#elif __has_include(<boost/asio.hpp>)
1013
#ifndef GLZ_USING_BOOST_ASIO
1114
#define GLZ_USING_BOOST_ASIO
1215
#endif
1316
#include <boost/asio.hpp>
1417
#include <boost/asio/signal_set.hpp>
18+
#ifdef GLZ_ENABLE_SSL
19+
#include <boost/asio/ssl.hpp>
20+
#endif
1521
#else
1622
static_assert(false, "standalone or boost asio must be included to use glaze/ext/glaze_asio.hpp");
1723
#endif

include/glaze/net/http_client.hpp

Lines changed: 10 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -3,7 +3,6 @@
33

44
#pragma once
55

6-
#include <asio.hpp>
76
#include <atomic>
87
#include <chrono>
98
#include <expected>
@@ -18,6 +17,7 @@
1817
#include <unordered_map>
1918
#include <vector>
2019

20+
#include "glaze/ext/glaze_asio.hpp"
2121
#include "glaze/net/http_router.hpp"
2222
#include "glaze/util/key_transformers.hpp"
2323

@@ -240,7 +240,7 @@ namespace glz
240240
bool expected = false;
241241
if (should_stop.compare_exchange_strong(expected, true)) {
242242
if (socket && socket->is_open()) {
243-
std::error_code ec;
243+
asio::error_code ec;
244244
// This cancels pending async operations on the socket, triggering their handlers
245245
// with asio::error::operation_aborted.
246246
socket->cancel(ec);
@@ -813,7 +813,7 @@ namespace glz
813813
asio::async_read_until(
814814
*connection->socket, *connection->buffer, "\r\n",
815815
[this, connection, on_data = std::move(on_data), on_error = std::move(on_error),
816-
on_disconnect = std::move(on_disconnect)](std::error_code ec, std::size_t bytes_transferred) mutable {
816+
on_disconnect = std::move(on_disconnect)](asio::error_code ec, std::size_t bytes_transferred) mutable {
817817
if (ec || connection->should_stop) {
818818
if (ec != asio::error::eof && ec != asio::error::operation_aborted && !connection->should_stop)
819819
on_error(ec);
@@ -881,7 +881,7 @@ namespace glz
881881
*connection->socket, *connection->buffer,
882882
asio::transfer_exactly(total_to_read - connection->buffer->size()),
883883
[this, connection, chunk_size, on_data = std::move(on_data), on_error = std::move(on_error),
884-
on_disconnect = std::move(on_disconnect)](std::error_code ec, std::size_t) mutable {
884+
on_disconnect = std::move(on_disconnect)](asio::error_code ec, std::size_t) mutable {
885885
if (ec || connection->should_stop) {
886886
if (ec != asio::error::eof && ec != asio::error::operation_aborted && !connection->should_stop)
887887
on_error(ec);
@@ -931,7 +931,7 @@ namespace glz
931931
// Use async_read with transfer_at_least(1) - may read more data for efficiency
932932
asio::async_read(
933933
*connection->socket, *connection->buffer, asio::transfer_at_least(1),
934-
[this, connection, on_data, on_error, on_disconnect](std::error_code ec,
934+
[this, connection, on_data, on_error, on_disconnect](asio::error_code ec,
935935
std::size_t /*bytes_transferred*/) {
936936
if (ec || connection->should_stop) {
937937
if (ec != asio::error::eof && ec != asio::error::operation_aborted && !connection->should_stop) {
@@ -966,7 +966,7 @@ namespace glz
966966
constexpr size_t read_size = 8192;
967967
connection->socket->async_read_some(
968968
connection->buffer->prepare(read_size),
969-
[this, connection, on_data, on_error, on_disconnect](std::error_code ec, std::size_t bytes_transferred) {
969+
[this, connection, on_data, on_error, on_disconnect](asio::error_code ec, std::size_t bytes_transferred) {
970970
if (ec || connection->should_stop) {
971971
if (ec != asio::error::eof && ec != asio::error::operation_aborted && !connection->should_stop) {
972972
on_error(ec);
@@ -1033,11 +1033,11 @@ namespace glz
10331033

10341034
// Read response headers synchronously
10351035
asio::streambuf response_buffer;
1036-
std::error_code ec;
1036+
asio::error_code ec;
10371037
size_t header_bytes = asio::read_until(*socket, response_buffer, "\r\n\r\n", ec);
10381038
if (ec) {
10391039
socket->close();
1040-
return std::unexpected(ec);
1040+
return std::unexpected<std::error_code>(ec);
10411041
}
10421042

10431043
// Create a zero-copy view of the header data
@@ -1096,7 +1096,7 @@ namespace glz
10961096
size_t body_in_buffer = response_buffer.size();
10971097
if (content_length > body_in_buffer) {
10981098
size_t remaining_to_read = content_length - body_in_buffer;
1099-
std::error_code read_ec;
1099+
asio::error_code read_ec;
11001100
asio::read(*socket, response_buffer, asio::transfer_exactly(remaining_to_read), read_ec);
11011101
if (read_ec) {
11021102
socket->close(); // Don't reuse a failed connection
@@ -1304,7 +1304,7 @@ namespace glz
13041304
*socket, *buffer, asio::transfer_exactly(remaining_to_read),
13051305
[this, socket, buffer, url, status_code = parsed_status->status_code,
13061306
response_headers = std::move(response_headers),
1307-
handler = std::forward<CompletionHandler>(handler)](std::error_code ec, std::size_t) mutable {
1307+
handler = std::forward<CompletionHandler>(handler)](asio::error_code ec, std::size_t) mutable {
13081308
// EOF is expected if the server closes the connection.
13091309
if (ec && ec != asio::error::eof) {
13101310
handler(std::unexpected(ec));

include/glaze/net/http_server.hpp

Lines changed: 4 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -29,11 +29,6 @@
2929
#include "glaze/net/websocket_connection.hpp"
3030
#include "glaze/util/key_transformers.hpp"
3131

32-
// Conditionally include SSL headers only when needed
33-
#ifdef GLZ_ENABLE_SSL
34-
#include <asio/ssl.hpp>
35-
#endif
36-
3732
// To deconflict Windows.h
3833
#ifdef DELETE
3934
#undef DELETE
@@ -1513,10 +1508,10 @@ namespace glz
15131508
}
15141509

15151510
conn->idle_timer->expires_after(std::chrono::seconds(conn_config_.keep_alive_timeout));
1516-
conn->idle_timer->async_wait([conn](std::error_code ec) {
1511+
conn->idle_timer->async_wait([conn](asio::error_code ec) {
15171512
if (!ec) {
15181513
// Timer expired - close the connection
1519-
std::error_code close_ec;
1514+
asio::error_code close_ec;
15201515
conn->socket->lowest_layer().shutdown(asio::ip::tcp::socket::shutdown_both, close_ec);
15211516
conn->socket->lowest_layer().close(close_ec);
15221517
}
@@ -2016,15 +2011,15 @@ namespace glz
20162011
auto response_buffer = std::make_shared<std::string>(std::move(response_str));
20172012

20182013
asio::async_write(*conn->socket, asio::buffer(*response_buffer),
2019-
[this, conn, response_buffer](std::error_code ec, std::size_t /*bytes_transferred*/) {
2014+
[this, conn, response_buffer](asio::error_code ec, std::size_t /*bytes_transferred*/) {
20202015
if (ec) {
20212016
// Write error - connection is dead
20222017
return;
20232018
}
20242019

20252020
if (conn->should_close) {
20262021
// Close the connection gracefully
2027-
std::error_code close_ec;
2022+
asio::error_code close_ec;
20282023
conn->socket->lowest_layer().shutdown(asio::ip::tcp::socket::shutdown_both, close_ec);
20292024
conn->socket->lowest_layer().close(close_ec);
20302025
}

include/glaze/net/websocket_client.hpp

Lines changed: 0 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -8,10 +8,6 @@
88
#include "glaze/net/http_client.hpp"
99
#include "glaze/net/websocket_connection.hpp"
1010

11-
#ifdef GLZ_ENABLE_SSL
12-
#include <asio/ssl.hpp>
13-
#endif
14-
1511
namespace glz
1612
{
1713
struct websocket_client

include/glaze/net/websocket_connection.hpp

Lines changed: 0 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -35,10 +35,6 @@
3535
#include "glaze/net/http_router.hpp"
3636
#include "glaze/util/parse.hpp"
3737

38-
#ifdef GLZ_ENABLE_SSL
39-
#include <asio/ssl.hpp>
40-
#endif
41-
4238
namespace glz
4339
{
4440
// WebSocket opcode constants

tests/networking_tests/http_client_test/http_client_test.cpp

Lines changed: 6 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -136,7 +136,8 @@ class working_test_server
136136
// Set up custom error handler to suppress expected shutdown errors
137137
server_.on_error([this](std::error_code ec, std::source_location loc) {
138138
// Only log unexpected errors, not normal shutdown errors
139-
if (running_ && ec != asio::error::eof && ec != asio::error::operation_aborted) {
139+
if (running_ && ec != make_error_code(asio::error::eof) &&
140+
ec != make_error_code(asio::error::operation_aborted)) {
140141
std::fprintf(stderr, "Server error at %s:%d: %s\n", loc.file_name(), static_cast<int>(loc.line()),
141142
ec.message().c_str());
142143
}
@@ -260,7 +261,7 @@ class working_test_server
260261
asio::ip::tcp::socket socket(io);
261262
asio::ip::tcp::endpoint endpoint(asio::ip::make_address("127.0.0.1"), port_);
262263

263-
std::error_code ec;
264+
asio::error_code ec;
264265
socket.connect(endpoint, ec);
265266
if (!ec) {
266267
socket.close();
@@ -408,7 +409,7 @@ class simple_test_client
408409
}
409410

410411
// Read body
411-
std::error_code ec;
412+
asio::error_code ec;
412413
asio::read(socket, response_buffer, asio::transfer_all(), ec);
413414

414415
std::string response_body{std::istreambuf_iterator<char>(&response_buffer),
@@ -830,7 +831,7 @@ suite glz_http_client_tests = [] {
830831
received_data.append(data);
831832
};
832833
auto on_error = [&](std::error_code ec) {
833-
if (ec && ec != asio::error::eof && ec != asio::error::operation_aborted) {
834+
if (ec && ec != make_error_code(asio::error::eof) && ec != make_error_code(asio::error::operation_aborted)) {
834835
error_count++;
835836
}
836837
};
@@ -886,7 +887,7 @@ suite glz_http_client_tests = [] {
886887
data_chunks_received++;
887888
};
888889
auto on_error = [&](std::error_code ec) {
889-
if (ec && ec != asio::error::eof && ec != asio::error::operation_aborted) {
890+
if (ec && ec != make_error_code(asio::error::eof) && ec != make_error_code(asio::error::operation_aborted)) {
890891
error_count++;
891892
}
892893
};

tests/networking_tests/http_server_api_tests/http_server_api_tests.cpp

Lines changed: 11 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -18,6 +18,14 @@
1818
#include "glaze/net/http_server.hpp"
1919
#include "ut/ut.hpp"
2020

21+
#if defined(GLZ_USING_BOOST_ASIO)
22+
namespace asio
23+
{
24+
using namespace boost::asio;
25+
using error_code = boost::system::error_code;
26+
}
27+
#endif
28+
2129
using namespace ut;
2230

2331
// Test data structures
@@ -1073,7 +1081,7 @@ struct raw_http_client
10731081

10741082
void close()
10751083
{
1076-
std::error_code ec;
1084+
asio::error_code ec;
10771085
socket_.shutdown(asio::ip::tcp::socket::shutdown_both, ec);
10781086
socket_.close(ec);
10791087
}
@@ -1254,7 +1262,8 @@ struct keepalive_test_server
12541262
void setup_routes()
12551263
{
12561264
server_.on_error([this](std::error_code ec, std::source_location) {
1257-
if (running_ && ec != asio::error::eof && ec != asio::error::operation_aborted) {
1265+
if (running_ && ec != make_error_code(asio::error::eof) &&
1266+
ec != make_error_code(asio::error::operation_aborted)) {
12581267
// Suppress expected errors during tests
12591268
}
12601269
});

tests/networking_tests/http_server_post_test/http_server_post_test.cpp

Lines changed: 12 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -6,10 +6,16 @@
66
#include <thread>
77
#include <ut/ut.hpp>
88

9-
#include "asio.hpp"
10-
#include "asio/io_context.hpp"
119
#include "glaze/net/http_server.hpp"
1210

11+
#if defined(GLZ_USING_BOOST_ASIO)
12+
namespace asio
13+
{
14+
using namespace boost::asio;
15+
using error_code = boost::system::error_code;
16+
}
17+
#endif
18+
1319
namespace
1420
{
1521
using namespace ut;
@@ -38,7 +44,7 @@ namespace
3844
asio::io_context io_ctx;
3945
asio::ip::tcp::socket sock(io_ctx);
4046
asio::ip::tcp::endpoint endpoint(asio::ip::make_address(test_host), uint16_t(port));
41-
std::error_code ec;
47+
asio::error_code ec;
4248
sock.connect(endpoint, ec);
4349
if (ec != asio::error::connection_refused) {
4450
return;
@@ -80,7 +86,7 @@ namespace
8086
{
8187
std::string resp;
8288
std::array<char, 4096> buf{};
83-
std::error_code ec;
89+
asio::error_code ec;
8490
for (;;) {
8591
std::size_t n = socket.read_some(asio::buffer(buf), ec);
8692
if (n == 0 || ec) break;
@@ -96,7 +102,7 @@ namespace
96102
asio::io_context io_ctx;
97103
asio::ip::tcp::socket socket(io_ctx);
98104
asio::ip::tcp::endpoint endpoint(asio::ip::make_address(test_host), uint16_t(test_port));
99-
std::error_code ec;
105+
asio::error_code ec;
100106
socket.connect(endpoint, ec);
101107
if (ec) {
102108
return "";
@@ -117,7 +123,7 @@ namespace
117123
asio::io_context io_ctx;
118124
asio::ip::tcp::socket socket(io_ctx);
119125
asio::ip::tcp::endpoint endpoint(asio::ip::make_address(test_host), uint16_t(test_port));
120-
std::error_code ec;
126+
asio::error_code ec;
121127
socket.connect(endpoint, ec);
122128
if (ec) {
123129
return "";

tests/networking_tests/https_test/https_test.cpp

Lines changed: 10 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -10,8 +10,6 @@
1010
#include <memory>
1111
#include <thread>
1212

13-
#include "asio/io_context.hpp"
14-
1513
#ifndef GLZ_ENABLE_SSL
1614
#define GLZ_ENABLE_SSL
1715
#endif
@@ -35,7 +33,13 @@
3533
#undef DELETE
3634
#endif
3735

38-
#include <asio.hpp>
36+
#if defined(GLZ_USING_BOOST_ASIO)
37+
namespace asio
38+
{
39+
using namespace boost::asio;
40+
using error_code = boost::system::error_code;
41+
}
42+
#endif
3943

4044
using namespace ut;
4145

@@ -308,7 +312,7 @@ struct TestUser
308312
};
309313

310314
// Helper function to check if an error should be suppressed
311-
bool should_suppress_error(const std::error_code& ec)
315+
bool should_suppress_error(const asio::error_code& ec)
312316
{
313317
// Common errors that are expected during normal operation
314318
if (ec == asio::error::eof) return true; // Client disconnected normally
@@ -686,7 +690,7 @@ suite server_lifecycle_external_context_tests = [] {
686690
asio::ip::tcp::socket socket(client_io);
687691
asio::ip::tcp::endpoint endpoint(asio::ip::make_address("127.0.0.1"), 8443);
688692

689-
std::error_code ec;
693+
asio::error_code ec;
690694
socket.connect(endpoint, ec);
691695
connection_successful = !ec;
692696
if (!ec) {
@@ -713,7 +717,7 @@ suite server_lifecycle_external_context_tests = [] {
713717
asio::ip::tcp::socket socket(client_io);
714718
asio::ip::tcp::endpoint endpoint(asio::ip::make_address("127.0.0.1"), 8443);
715719

716-
std::error_code ec;
720+
asio::error_code ec;
717721
socket.connect(endpoint, ec);
718722
connection_refused = (ec == asio::error::connection_refused);
719723
if (!ec) {

0 commit comments

Comments
 (0)