Bug Summary

File:usr/include/boost/asio/detail/impl/socket_ops.ipp
Warning:line 876, column 29
Call to blocking function 'recv' inside of critical section

Annotated Source Code

Press '?' to see keyboard shortcuts

clang -cc1 -cc1 -triple x86_64-redhat-linux-gnu -O2 -analyze -disable-free -clear-ast-before-backend -disable-llvm-verifier -discard-value-names -main-file-name mt_tcp_listener_mgr_unittests.cc -analyzer-checker=core -analyzer-checker=apiModeling -analyzer-checker=unix -analyzer-checker=deadcode -analyzer-checker=cplusplus -analyzer-checker=security.insecureAPI.UncheckedReturn -analyzer-checker=security.insecureAPI.getpw -analyzer-checker=security.insecureAPI.gets -analyzer-checker=security.insecureAPI.mktemp -analyzer-checker=security.insecureAPI.mkstemp -analyzer-checker=security.insecureAPI.vfork -analyzer-checker=nullability.NullPassedToNonnull -analyzer-checker=nullability.NullReturnedFromNonnull -analyzer-output plist -w -setup-static-analyzer -mrelocation-model pic -pic-level 2 -pic-is-pie -mframe-pointer=none -fmath-errno -ffp-contract=on -fno-rounding-math -mconstructor-aliases -funwind-tables=2 -target-cpu x86-64 -tune-cpu generic -debugger-tuning=gdb -fdebug-compilation-dir=/home/fedora/workspace/kea-dev/clang-static-analyzer/build/meson-private/tmpz0p224zs -fcoverage-compilation-dir=/home/fedora/workspace/kea-dev/clang-static-analyzer/build/meson-private/tmpz0p224zs -resource-dir /usr/bin/../lib/clang/22 -I src/lib/tcp/tests/kea-tcp-tests.p -I src/lib/tcp/tests -I ../../../src/lib/tcp/tests -I . -I ../../.. -I src -I ../../../src -I src/bin -I ../../../src/bin -I src/lib -I ../../../src/lib -I /usr/src/googletest/googletest -I /usr/src/googletest/googletest/include -I /usr/include -D _GLIBCXX_ASSERTIONS=1 -D _FILE_OFFSET_BITS=64 -D BOOST_ALL_NO_LIB -D TEST_CA_DIR="/home/fedora/workspace/kea-dev/clang-static-analyzer/src/lib/asiolink/testutils/ca" -internal-isystem /usr/bin/../lib/gcc/x86_64-redhat-linux/16/../../../../include/c++/16 -internal-isystem /usr/bin/../lib/gcc/x86_64-redhat-linux/16/../../../../include/c++/16/x86_64-redhat-linux -internal-isystem /usr/bin/../lib/gcc/x86_64-redhat-linux/16/../../../../include/c++/16/backward -internal-isystem /usr/bin/../lib/clang/22/include -internal-isystem /usr/local/include -internal-isystem /usr/bin/../lib/gcc/x86_64-redhat-linux/16/../../../../x86_64-redhat-linux/include -internal-externc-isystem /include -internal-externc-isystem /usr/include -Wwrite-strings -Wno-missing-field-initializers -fdeprecated-macro -ferror-limit 19 -fgnuc-version=4.2.1 -fskip-odr-check-in-gmf -fcxx-exceptions -fexceptions -fcolor-diagnostics -vectorize-loops -vectorize-slp -analyzer-output=html -faddrsig -fdwarf2-cfi-asm -o /home/fedora/workspace/kea-dev/clang-static-analyzer/build/meson-logs/scanbuild/2026-06-18-163926-5114-1 -x c++ ../../../src/lib/tcp/tests/mt_tcp_listener_mgr_unittests.cc

../../../src/lib/tcp/tests/mt_tcp_listener_mgr_unittests.cc

1// Copyright (C) 2022-2025 Internet Systems Consortium, Inc. ("ISC")
2//
3// This Source Code Form is subject to the terms of the Mozilla Public
4// License, v. 2.0. If a copy of the MPL was not distributed with this
5// file, You can obtain one at http://mozilla.org/MPL/2.0/.
6#include <config.h>
7
8#include <asiolink/asio_wrapper.h>
9#include <asiolink/interval_timer.h>
10#include <asiolink/testutils/test_tls.h>
11#include <cc/data.h>
12#include <cc/command_interpreter.h>
13#include <tcp/mt_tcp_listener_mgr.h>
14#include <tcp_test_listener.h>
15#include <tcp_test_client.h>
16#include <util/multi_threading_mgr.h>
17#include <testutils/gtest_utils.h>
18
19#include <gtest/gtest.h>
20
21#include <thread>
22#include <list>
23#include <sstream>
24
25using namespace isc;
26using namespace isc::asiolink;
27using namespace isc::asiolink::test;
28using namespace isc::config;
29using namespace isc::data;
30using namespace boost::asio::ip;
31using namespace isc::tcp;
32using namespace isc::util;
33namespace ph = std::placeholders;
34
35namespace {
36
37/// @brief IP address to which TCP service is bound.
38const std::string SERVER_ADDRESS = "127.0.0.1";
39
40/// @brief Port number to which TCP service is bound.
41const unsigned short SERVER_PORT = 18123;
42
43/// @brief Test timeout (ms).
44const long TEST_TIMEOUT = 10000;
45
46/// @brief Test fixture class for @ref MtTcpListenerMgr.
47class MtTcpListenerMgrTest : public ::testing::Test {
48public:
49
50 /// @brief Constructor.
51 ///
52 /// Starts test timer which detects timeouts, and enables multi-threading mode.
53 MtTcpListenerMgrTest()
54 : mt_listener_mgr_(), io_service_(new IOService()), test_timer_(io_service_),
55 run_io_service_timer_(io_service_), clients_(), num_threads_(),
56 num_clients_(), num_in_progress_(0), num_finished_(0), chunk_size_(0),
57 pause_cnt_(0), response_handler_(0) {
58 test_timer_.setup(std::bind(&MtTcpListenerMgrTest::timeoutHandler, this, true),
59 TEST_TIMEOUT, IntervalTimer::ONE_SHOT);
60
61 // Enable multi-threading.
62 MultiThreadingMgr::instance().setMode(true);
63 }
64
65 /// @brief Destructor.
66 ///
67 /// Removes TCP clients and disables MT.
68 virtual ~MtTcpListenerMgrTest() {
69 // Wipe out the listener.
70 mt_listener_mgr_.reset();
71
72 // Destroy all remaining clients.
73 for (auto const& client : clients_) {
74 client->close();
75 }
76
77 test_timer_.cancel();
78 io_service_->stopAndPoll();
79
80 // Disable multi-threading.
81 MultiThreadingMgr::instance().setMode(false);
82 }
83
84 /// @brief Replaces the test's listener with a new listener
85 ///
86 /// @param num_threads Number of threads the listener should use.
87 /// @param response_handler Response handler connections should use
88 void createMtTcpListenerMgr(size_t num_threads,
89 TcpTestConnection::ResponseHandler response_handler = 0) {
90 // Create a listener with prescribed number of threads.
91 ASSERT_NO_THROW_LOG(mt_listener_mgr_.reset(new MtTcpListenerMgr({ try { mt_listener_mgr_.reset(new MtTcpListenerMgr( std::bind
(&MtTcpListenerMgrTest::listenerFactory, this, ph::_1, ph
::_2, ph::_3, ph::_4, ph::_5, ph::_6), IOAddress(SERVER_ADDRESS
), SERVER_PORT, num_threads)); } catch (const std::exception&
ex) { return ::testing::internal::AssertHelper(::testing::TestPartResult
::kFatalFailure, "../../../src/lib/tcp/tests/mt_tcp_listener_mgr_unittests.cc"
, 95, "Failed") = ::testing::Message() << "mt_listener_mgr_.reset(new MtTcpListenerMgr( std::bind(&MtTcpListenerMgrTest::listenerFactory, this, ph::_1, ph::_2, ph::_3, ph::_4, ph::_5, ph::_6), IOAddress(SERVER_ADDRESS), SERVER_PORT, num_threads))"
<< " threw type: " << typeid(ex).name() <<
", what: " << ex.what(); } catch (...) { return ::testing
::internal::AssertHelper(::testing::TestPartResult::kFatalFailure
, "../../../src/lib/tcp/tests/mt_tcp_listener_mgr_unittests.cc"
, 95, "Failed") = ::testing::Message() << "mt_listener_mgr_.reset(new MtTcpListenerMgr( std::bind(&MtTcpListenerMgrTest::listenerFactory, this, ph::_1, ph::_2, ph::_3, ph::_4, ph::_5, ph::_6), IOAddress(SERVER_ADDRESS), SERVER_PORT, num_threads))"
<< " threw non-std::exception"; } }
92 std::bind(&MtTcpListenerMgrTest::listenerFactory, this,{ try { mt_listener_mgr_.reset(new MtTcpListenerMgr( std::bind
(&MtTcpListenerMgrTest::listenerFactory, this, ph::_1, ph
::_2, ph::_3, ph::_4, ph::_5, ph::_6), IOAddress(SERVER_ADDRESS
), SERVER_PORT, num_threads)); } catch (const std::exception&
ex) { return ::testing::internal::AssertHelper(::testing::TestPartResult
::kFatalFailure, "../../../src/lib/tcp/tests/mt_tcp_listener_mgr_unittests.cc"
, 95, "Failed") = ::testing::Message() << "mt_listener_mgr_.reset(new MtTcpListenerMgr( std::bind(&MtTcpListenerMgrTest::listenerFactory, this, ph::_1, ph::_2, ph::_3, ph::_4, ph::_5, ph::_6), IOAddress(SERVER_ADDRESS), SERVER_PORT, num_threads))"
<< " threw type: " << typeid(ex).name() <<
", what: " << ex.what(); } catch (...) { return ::testing
::internal::AssertHelper(::testing::TestPartResult::kFatalFailure
, "../../../src/lib/tcp/tests/mt_tcp_listener_mgr_unittests.cc"
, 95, "Failed") = ::testing::Message() << "mt_listener_mgr_.reset(new MtTcpListenerMgr( std::bind(&MtTcpListenerMgrTest::listenerFactory, this, ph::_1, ph::_2, ph::_3, ph::_4, ph::_5, ph::_6), IOAddress(SERVER_ADDRESS), SERVER_PORT, num_threads))"
<< " threw non-std::exception"; } }
93 ph::_1, ph::_2, ph::_3, ph::_4, ph::_5, ph::_6),{ try { mt_listener_mgr_.reset(new MtTcpListenerMgr( std::bind
(&MtTcpListenerMgrTest::listenerFactory, this, ph::_1, ph
::_2, ph::_3, ph::_4, ph::_5, ph::_6), IOAddress(SERVER_ADDRESS
), SERVER_PORT, num_threads)); } catch (const std::exception&
ex) { return ::testing::internal::AssertHelper(::testing::TestPartResult
::kFatalFailure, "../../../src/lib/tcp/tests/mt_tcp_listener_mgr_unittests.cc"
, 95, "Failed") = ::testing::Message() << "mt_listener_mgr_.reset(new MtTcpListenerMgr( std::bind(&MtTcpListenerMgrTest::listenerFactory, this, ph::_1, ph::_2, ph::_3, ph::_4, ph::_5, ph::_6), IOAddress(SERVER_ADDRESS), SERVER_PORT, num_threads))"
<< " threw type: " << typeid(ex).name() <<
", what: " << ex.what(); } catch (...) { return ::testing
::internal::AssertHelper(::testing::TestPartResult::kFatalFailure
, "../../../src/lib/tcp/tests/mt_tcp_listener_mgr_unittests.cc"
, 95, "Failed") = ::testing::Message() << "mt_listener_mgr_.reset(new MtTcpListenerMgr( std::bind(&MtTcpListenerMgrTest::listenerFactory, this, ph::_1, ph::_2, ph::_3, ph::_4, ph::_5, ph::_6), IOAddress(SERVER_ADDRESS), SERVER_PORT, num_threads))"
<< " threw non-std::exception"; } }
94 IOAddress(SERVER_ADDRESS),{ try { mt_listener_mgr_.reset(new MtTcpListenerMgr( std::bind
(&MtTcpListenerMgrTest::listenerFactory, this, ph::_1, ph
::_2, ph::_3, ph::_4, ph::_5, ph::_6), IOAddress(SERVER_ADDRESS
), SERVER_PORT, num_threads)); } catch (const std::exception&
ex) { return ::testing::internal::AssertHelper(::testing::TestPartResult
::kFatalFailure, "../../../src/lib/tcp/tests/mt_tcp_listener_mgr_unittests.cc"
, 95, "Failed") = ::testing::Message() << "mt_listener_mgr_.reset(new MtTcpListenerMgr( std::bind(&MtTcpListenerMgrTest::listenerFactory, this, ph::_1, ph::_2, ph::_3, ph::_4, ph::_5, ph::_6), IOAddress(SERVER_ADDRESS), SERVER_PORT, num_threads))"
<< " threw type: " << typeid(ex).name() <<
", what: " << ex.what(); } catch (...) { return ::testing
::internal::AssertHelper(::testing::TestPartResult::kFatalFailure
, "../../../src/lib/tcp/tests/mt_tcp_listener_mgr_unittests.cc"
, 95, "Failed") = ::testing::Message() << "mt_listener_mgr_.reset(new MtTcpListenerMgr( std::bind(&MtTcpListenerMgrTest::listenerFactory, this, ph::_1, ph::_2, ph::_3, ph::_4, ph::_5, ph::_6), IOAddress(SERVER_ADDRESS), SERVER_PORT, num_threads))"
<< " threw non-std::exception"; } }
95 SERVER_PORT, num_threads))){ try { mt_listener_mgr_.reset(new MtTcpListenerMgr( std::bind
(&MtTcpListenerMgrTest::listenerFactory, this, ph::_1, ph
::_2, ph::_3, ph::_4, ph::_5, ph::_6), IOAddress(SERVER_ADDRESS
), SERVER_PORT, num_threads)); } catch (const std::exception&
ex) { return ::testing::internal::AssertHelper(::testing::TestPartResult
::kFatalFailure, "../../../src/lib/tcp/tests/mt_tcp_listener_mgr_unittests.cc"
, 95, "Failed") = ::testing::Message() << "mt_listener_mgr_.reset(new MtTcpListenerMgr( std::bind(&MtTcpListenerMgrTest::listenerFactory, this, ph::_1, ph::_2, ph::_3, ph::_4, ph::_5, ph::_6), IOAddress(SERVER_ADDRESS), SERVER_PORT, num_threads))"
<< " threw type: " << typeid(ex).name() <<
", what: " << ex.what(); } catch (...) { return ::testing
::internal::AssertHelper(::testing::TestPartResult::kFatalFailure
, "../../../src/lib/tcp/tests/mt_tcp_listener_mgr_unittests.cc"
, 95, "Failed") = ::testing::Message() << "mt_listener_mgr_.reset(new MtTcpListenerMgr( std::bind(&MtTcpListenerMgrTest::listenerFactory, this, ph::_1, ph::_2, ph::_3, ph::_4, ph::_5, ph::_6), IOAddress(SERVER_ADDRESS), SERVER_PORT, num_threads))"
<< " threw non-std::exception"; } }
;
96
97 ASSERT_TRUE(mt_listener_mgr_)switch (0) case 0: default: if (const ::testing::AssertionResult
gtest_ar_ = ::testing::AssertionResult(mt_listener_mgr_)) ; else
return ::testing::internal::AssertHelper(::testing::TestPartResult
::kFatalFailure, "../../../src/lib/tcp/tests/mt_tcp_listener_mgr_unittests.cc"
, 97, ::testing::internal::GetBoolAssertionFailureMessage( gtest_ar_
, "mt_listener_mgr_", "false", "true") .c_str()) = ::testing::
Message()
;
98 setResponseHandler(response_handler);
99 }
100
101 /// @brief Return the inner TcpTestListener's audit trail
102 AuditTrailPtr getAuditTrail() {
103 TcpListenerPtr l = mt_listener_mgr_->getTcpListener();
104 if (!l) {
105 isc_throw(Unexpected, "Test is broken? Listener is null?")do { std::ostringstream oss__; oss__ << "Test is broken? Listener is null?"
; throw Unexpected("../../../src/lib/tcp/tests/mt_tcp_listener_mgr_unittests.cc"
, 105, oss__.str().c_str()); } while (1)
;
106 }
107
108 TcpTestListenerPtr listener = boost::dynamic_pointer_cast<TcpTestListener>(
109 mt_listener_mgr_->getTcpListener());
110 if (!listener) {
111 isc_throw(Unexpected, "Test is broken? Listener is not a TcpTestListener")do { std::ostringstream oss__; oss__ << "Test is broken? Listener is not a TcpTestListener"
; throw Unexpected("../../../src/lib/tcp/tests/mt_tcp_listener_mgr_unittests.cc"
, 111, oss__.str().c_str()); } while (1)
;
112 }
113
114 return (listener->audit_trail_);
115 }
116
117 /// @brief TcpListener factory for MtTcpListener to instantiate new listeners.
118 TcpListenerPtr listenerFactory(const asiolink::IOServicePtr& io_service,
119 const asiolink::IOAddress& server_address,
120 const unsigned short server_port,
121 const asiolink::TlsContextPtr& tls_context,
122 const TcpListener::IdleTimeout& idle_timeout,
123 const TcpConnectionFilterCallback& connection_filter) {
124 TcpTestListenerPtr listener(new TcpTestListener(io_service,
125 server_address,
126 server_port,
127 tls_context,
128 idle_timeout,
129 connection_filter));
130 // Set the response handler the listener will pass into each connection.
131 listener->setResponseHandler(response_handler_);
132 return (listener);
133 }
134
135 /// @brief Callback function each client invokes when done.
136 ///
137 /// It stops the IO service
138 ///
139 /// @param fail_on_timeout Specifies if test failure should be reported.
140 void clientDone() {
141 io_service_->stop();
142 }
143
144 /// @brief Initiates a command via a new TCP client.
145 ///
146 /// This method creates a TcpTestClient instance, adds the
147 /// client to the list of clients, and starts a request.
148 /// The client will run on the main thread and be driven by
149 /// the test's IOService instance.
150 ///
151 /// @param request_str String containing the request
152 /// to be sent.
153 void startRequest(const std::string& request_str) {
154 // Instantiate the client.
155 TcpTestClientPtr client(new TcpTestClient(io_service_,
156 std::bind(&MtTcpListenerMgrTest::clientDone, this),
157 TlsContextPtr(),
158 SERVER_ADDRESS, SERVER_PORT));
159 // Add it to the list of clients.
160 clients_.push_back(client);
161
162 // Start the request. Note, nothing happens until the IOService runs.
163 client->startRequest(request_str);
164 }
165
166 /// @brief Initiates a "thread" command via a new TCP client.
167 ///
168 /// This method creates a TcpTestClient instance, adds the
169 /// client to the list of clients, and starts a request based
170 /// on the given command. The client will run on the main
171 /// thread and be driven by the test's IOService instance.
172 ///
173 /// The command has a single argument, "client-ptr". The function creates
174 /// the value for this argument from the pointer address of client instance
175 /// it creates. This argument should be echoed back in the response, along
176 /// with the thread-id of the MtTcpListener thread which handled the
177 /// command. The response body should look this:
178 ///
179 /// ```
180 /// [ { "arguments": { "client-ptr": "xxxxx", "thread-id": "zzzzz" }, "result": 0} ]
181 /// ```
182 void startThreadCommand(std::string request_str) {
183 // Create a new client.
184 TcpTestClientPtr client(new TcpTestClient(io_service_,
21
Calling constructor for 'TcpTestClient'
76
Returning from constructor for 'TcpTestClient'
185 std::bind(&MtTcpListenerMgrTest::clientDone, this),
186 TlsContextPtr(),
187 SERVER_ADDRESS, SERVER_PORT));
188
189 // Construct the "thread" command post including the argument,
190 // "client-ptr", whose value is the stringified pointer to the
191 // newly created client.
192 std::stringstream request_body;
193 request_body << "{\"command\": \"thread\", \"arguments\": { \"client-ptr\": \""
194 << client << "\", \"request\": \"" << request_str << "\" } }";
195
196 // Add it to the list of clients.
197 clients_.push_back(client);
198
199 // Start the request. Note, nothing happens until the IOService runs.
200 ASSERT_NO_THROW_LOG(client->startRequest(request_body.str())){ try { client->startRequest(request_body.str()); } catch (
const std::exception& ex) { return ::testing::internal::AssertHelper
(::testing::TestPartResult::kFatalFailure, "../../../src/lib/tcp/tests/mt_tcp_listener_mgr_unittests.cc"
, 200, "Failed") = ::testing::Message() << "client->startRequest(request_body.str())"
<< " threw type: " << typeid(ex).name() <<
", what: " << ex.what(); } catch (...) { return ::testing
::internal::AssertHelper(::testing::TestPartResult::kFatalFailure
, "../../../src/lib/tcp/tests/mt_tcp_listener_mgr_unittests.cc"
, 200, "Failed") = ::testing::Message() << "client->startRequest(request_body.str())"
<< " threw non-std::exception"; } }
;
77
Calling 'TcpTestClient::startRequest'
201 }
202
203 /// @brief Callback function invoke upon test timeout.
204 ///
205 /// It stops the IO service and reports test timeout.
206 ///
207 /// @param fail_on_timeout Specifies if test failure should be reported.
208 void timeoutHandler(const bool fail_on_timeout) {
209 if (fail_on_timeout) {
210 ADD_FAILURE()::testing::internal::AssertHelper(::testing::TestPartResult::
kNonFatalFailure, "../../../src/lib/tcp/tests/mt_tcp_listener_mgr_unittests.cc"
, 210, "Failed") = ::testing::Message()
<< "Timeout occurred while running the test!";
211 }
212 io_service_->stop();
213 }
214
215 /// @brief Runs IO service with optional timeout.
216 ///
217 /// We iterate over calls to asio::io_context.run(), until
218 /// all the clients have completed their requests. We do it this way
219 /// because the test clients stop the io_service when they're
220 /// through with a request.
221 ///
222 /// @param request_limit Desired number of requests the function should wait
223 /// to be processed before returning.
224 void runIOService(size_t request_limit = 0) {
225 if (!request_limit) {
226 request_limit = clients_.size();
227 }
228
229 // Loop until the clients are done, an error occurs, or the time runs out.
230 size_t num_done = 0;
231 while (num_done != request_limit) {
232 io_service_->stop();
233 io_service_->restart();
234
235 // Run until a client stops the service.
236 io_service_->run();
237
238 // If all the clients are done receiving, the test is done.
239 num_done = 0;
240 for (auto const& client : clients_) {
241 if (client->receiveDone()) {
242 ++num_done;
243 }
244 }
245 }
246 }
247
248 /// @brief Set the response handler use by each connection.
249 ///
250 /// Sets the response handler invoked by requestReceived.
251 ///
252 /// @param response_handler Handler function to invoke
253 void setResponseHandler(TcpTestConnection::ResponseHandler response_handler) {
254 response_handler_ = response_handler;
255 };
256
257 /// @brief Response handler for the 'thread' command.
258 ///
259 /// @param request JSON text containing thread command and arguments
260 /// which should contain one string element, "client-ptr", whose value is
261 /// the stringified pointer to the client that issued the command.
262 ///
263 /// @return Returns JSON text containing the response which should include
264 /// a string value 'thread-id': <thread id>
265 std::string synchronizedCommandHandler(const std::string& request) {
266 // If the number of in progress commands is less than the number
267 // of threads, then wait here until we're notified. Otherwise,
268 // notify everyone and finish. The idea is to force each thread
269 // to handle the same number of requests over the course of the
270 // test, making verification reliable.
271 {
272 std::unique_lock<std::mutex> lck(mutex_);
273 ++num_in_progress_;
274 if (num_in_progress_ == chunk_size_) {
275 num_finished_ = 0;
276 cv_.notify_all();
277 } else {
278 bool ret = cv_.wait_for(lck, std::chrono::seconds(10),
279 [&]() { return (num_in_progress_ == chunk_size_); });
280 if (!ret) {
281 ADD_FAILURE()::testing::internal::AssertHelper(::testing::TestPartResult::
kNonFatalFailure, "../../../src/lib/tcp/tests/mt_tcp_listener_mgr_unittests.cc"
, 281, "Failed") = ::testing::Message()
<< "clients failed to start work";
282 }
283 }
284 }
285
286 // Create the map of response arguments.
287 ElementPtr arguments = Element::createMap();
288
289 // Parse the command.
290 ConstElementPtr command = Element::fromJSON(request);
291 ConstElementPtr command_arguments;
292 std::string command_str = parseCommand(command_arguments, command);
293
294 // First we echo the client-ptr command argument.
295 ConstElementPtr client_ptr = command_arguments->get("client-ptr");
296 if (!client_ptr) {
297 return (createAnswerString(CONTROL_RESULT_ERROR, "missing client-ptr"));
298 }
299
300 arguments->set("client-ptr", client_ptr);
301
302 // Now we add the thread-id.
303 std::stringstream ss;
304 ss << std::this_thread::get_id();
305 arguments->set("thread-id", Element::create(ss.str()));
306 arguments->set("sign-off", Element::create("good bye"));
307
308 {
309 std::unique_lock<std::mutex> lck(mutex_);
310 num_finished_++;
311 if (num_finished_ == chunk_size_) {
312 // We're all done, notify the others and finish.
313 num_in_progress_ = 0;
314 cv_.notify_all();
315 } else {
316 // I'm done but others aren't wait here.
317 bool ret = cv_.wait_for(lck, std::chrono::seconds(10),
318 [&]() { return (num_finished_ == chunk_size_); });
319 if (!ret) {
320 ADD_FAILURE()::testing::internal::AssertHelper(::testing::TestPartResult::
kNonFatalFailure, "../../../src/lib/tcp/tests/mt_tcp_listener_mgr_unittests.cc"
, 320, "Failed") = ::testing::Message()
<< "clients failed to finish work";
321 }
322 }
323 }
324
325 EXPECT_THROW(mt_listener_mgr_->start(), InvalidOperation)switch (0) case 0: default: if (::testing::internal::TrueWithString
gtest_msg{}) { bool gtest_caught_expected = false; try { if (
::testing::internal::AlwaysTrue()) { mt_listener_mgr_->start
(); } else static_assert(true, ""); } catch (InvalidOperation
const&) { gtest_caught_expected = true; } catch (typename
std::conditional< std::is_same<typename std::remove_cv
<typename std::remove_reference< InvalidOperation>::
type>::type, std::exception>::value, const ::testing::internal
::NeverThrown&, const std::exception&>::type e) { gtest_msg
.value = "Expected: " "mt_listener_mgr_->start()" " throws an exception of type "
"InvalidOperation" ".\n Actual: it throws "; gtest_msg.value
+= ::testing::internal::GetTypeName(typeid(e)); gtest_msg.value
+= " with description \""; gtest_msg.value += e.what(); gtest_msg
.value += "\"."; goto gtest_label_testthrow_325; } catch (...
) { gtest_msg.value = "Expected: " "mt_listener_mgr_->start()"
" throws an exception of type " "InvalidOperation" ".\n Actual: it throws a different type."
; goto gtest_label_testthrow_325; } if (!gtest_caught_expected
) { gtest_msg.value = "Expected: " "mt_listener_mgr_->start()"
" throws an exception of type " "InvalidOperation" ".\n Actual: it throws nothing."
; goto gtest_label_testthrow_325; } } else gtest_label_testthrow_325
: ::testing::internal::AssertHelper(::testing::TestPartResult
::kNonFatalFailure, "../../../src/lib/tcp/tests/mt_tcp_listener_mgr_unittests.cc"
, 325, gtest_msg.value.c_str()) = ::testing::Message()
;
326 EXPECT_THROW(mt_listener_mgr_->pause(), MultiThreadingInvalidOperation)switch (0) case 0: default: if (::testing::internal::TrueWithString
gtest_msg{}) { bool gtest_caught_expected = false; try { if (
::testing::internal::AlwaysTrue()) { mt_listener_mgr_->pause
(); } else static_assert(true, ""); } catch (MultiThreadingInvalidOperation
const&) { gtest_caught_expected = true; } catch (typename
std::conditional< std::is_same<typename std::remove_cv
<typename std::remove_reference< MultiThreadingInvalidOperation
>::type>::type, std::exception>::value, const ::testing
::internal::NeverThrown&, const std::exception&>::
type e) { gtest_msg.value = "Expected: " "mt_listener_mgr_->pause()"
" throws an exception of type " "MultiThreadingInvalidOperation"
".\n Actual: it throws "; gtest_msg.value += ::testing::internal
::GetTypeName(typeid(e)); gtest_msg.value += " with description \""
; gtest_msg.value += e.what(); gtest_msg.value += "\"."; goto
gtest_label_testthrow_326; } catch (...) { gtest_msg.value =
"Expected: " "mt_listener_mgr_->pause()" " throws an exception of type "
"MultiThreadingInvalidOperation" ".\n Actual: it throws a different type."
; goto gtest_label_testthrow_326; } if (!gtest_caught_expected
) { gtest_msg.value = "Expected: " "mt_listener_mgr_->pause()"
" throws an exception of type " "MultiThreadingInvalidOperation"
".\n Actual: it throws nothing."; goto gtest_label_testthrow_326
; } } else gtest_label_testthrow_326 : ::testing::internal::AssertHelper
(::testing::TestPartResult::kNonFatalFailure, "../../../src/lib/tcp/tests/mt_tcp_listener_mgr_unittests.cc"
, 326, gtest_msg.value.c_str()) = ::testing::Message()
;
327 EXPECT_THROW(mt_listener_mgr_->resume(), MultiThreadingInvalidOperation)switch (0) case 0: default: if (::testing::internal::TrueWithString
gtest_msg{}) { bool gtest_caught_expected = false; try { if (
::testing::internal::AlwaysTrue()) { mt_listener_mgr_->resume
(); } else static_assert(true, ""); } catch (MultiThreadingInvalidOperation
const&) { gtest_caught_expected = true; } catch (typename
std::conditional< std::is_same<typename std::remove_cv
<typename std::remove_reference< MultiThreadingInvalidOperation
>::type>::type, std::exception>::value, const ::testing
::internal::NeverThrown&, const std::exception&>::
type e) { gtest_msg.value = "Expected: " "mt_listener_mgr_->resume()"
" throws an exception of type " "MultiThreadingInvalidOperation"
".\n Actual: it throws "; gtest_msg.value += ::testing::internal
::GetTypeName(typeid(e)); gtest_msg.value += " with description \""
; gtest_msg.value += e.what(); gtest_msg.value += "\"."; goto
gtest_label_testthrow_327; } catch (...) { gtest_msg.value =
"Expected: " "mt_listener_mgr_->resume()" " throws an exception of type "
"MultiThreadingInvalidOperation" ".\n Actual: it throws a different type."
; goto gtest_label_testthrow_327; } if (!gtest_caught_expected
) { gtest_msg.value = "Expected: " "mt_listener_mgr_->resume()"
" throws an exception of type " "MultiThreadingInvalidOperation"
".\n Actual: it throws nothing."; goto gtest_label_testthrow_327
; } } else gtest_label_testthrow_327 : ::testing::internal::AssertHelper
(::testing::TestPartResult::kNonFatalFailure, "../../../src/lib/tcp/tests/mt_tcp_listener_mgr_unittests.cc"
, 327, gtest_msg.value.c_str()) = ::testing::Message()
;
328 EXPECT_THROW(mt_listener_mgr_->stop(), MultiThreadingInvalidOperation)switch (0) case 0: default: if (::testing::internal::TrueWithString
gtest_msg{}) { bool gtest_caught_expected = false; try { if (
::testing::internal::AlwaysTrue()) { mt_listener_mgr_->stop
(); } else static_assert(true, ""); } catch (MultiThreadingInvalidOperation
const&) { gtest_caught_expected = true; } catch (typename
std::conditional< std::is_same<typename std::remove_cv
<typename std::remove_reference< MultiThreadingInvalidOperation
>::type>::type, std::exception>::value, const ::testing
::internal::NeverThrown&, const std::exception&>::
type e) { gtest_msg.value = "Expected: " "mt_listener_mgr_->stop()"
" throws an exception of type " "MultiThreadingInvalidOperation"
".\n Actual: it throws "; gtest_msg.value += ::testing::internal
::GetTypeName(typeid(e)); gtest_msg.value += " with description \""
; gtest_msg.value += e.what(); gtest_msg.value += "\"."; goto
gtest_label_testthrow_328; } catch (...) { gtest_msg.value =
"Expected: " "mt_listener_mgr_->stop()" " throws an exception of type "
"MultiThreadingInvalidOperation" ".\n Actual: it throws a different type."
; goto gtest_label_testthrow_328; } if (!gtest_caught_expected
) { gtest_msg.value = "Expected: " "mt_listener_mgr_->stop()"
" throws an exception of type " "MultiThreadingInvalidOperation"
".\n Actual: it throws nothing."; goto gtest_label_testthrow_328
; } } else gtest_label_testthrow_328 : ::testing::internal::AssertHelper
(::testing::TestPartResult::kNonFatalFailure, "../../../src/lib/tcp/tests/mt_tcp_listener_mgr_unittests.cc"
, 328, gtest_msg.value.c_str()) = ::testing::Message()
;
329
330 // We're done, ship it!
331 std::string str = createAnswerString(CONTROL_RESULT_SUCCESS, arguments);
332 return (str);
333 }
334
335 /// @brief Create a response string of JSON
336 ///
337 /// @param status_code Indicates outcome of the command
338 /// @param arguments Element tree of response arguments
339 ///
340 /// @return JSON text containing the response
341 std::string createAnswerString(const int status_code, std::string text) {
342 ConstElementPtr answer = createAnswer(status_code, text);
343 std::stringstream os;
344 answer->toJSON(os);
345 return(os.str());
346 }
347
348 /// @brief Create a response string of JSON
349 ///
350 /// @param status_code Indicates outcome of the command
351 /// @param arguments Element tree of response arguments
352 ///
353 /// @return JSON text containing the response
354 std::string createAnswerString(const int status_code,
355 ConstElementPtr arguments) {
356 ConstElementPtr answer = createAnswer(status_code, arguments);
357 std::stringstream os;
358 answer->toJSON(os);
359 return(os.str());
360 }
361
362 /// @brief Simple response handler for the 'thread' command.
363 ///
364 /// @param command_name Command name, i.e. 'thread'.
365 /// @param command_arguments Command arguments should contain
366 /// one string element, "client-ptr", whose value is the stringified
367 /// pointer to the client that issued the command.
368 ///
369 /// @return Returns response with map of arguments containing
370 /// a string value 'thread-id': <thread id>
371 std::string simpleCommandHandler(const std::string& request) {
372 // Create the map of response arguments.
373 ElementPtr arguments = Element::createMap();
374
375 // Parse the command.
376 ConstElementPtr command = Element::fromJSON(request);
377 ConstElementPtr command_arguments;
378 std::string command_str = parseCommand(command_arguments, command);
379
380 // First we echo the client-ptr command argument.
381 ConstElementPtr client_ptr = command_arguments->get("client-ptr");
382 if (!client_ptr) {
383 return (createAnswerString(CONTROL_RESULT_ERROR, "missing client-ptr"));
384 }
385
386 arguments->set("client-ptr", client_ptr);
387
388 // Now we add the thread-id.
389 std::stringstream ss;
390 ss << std::this_thread::get_id();
391 arguments->set("thread-id", Element::create(ss.str()));
392 arguments->set("sign-off", Element::create("good bye"));
393
394 // We're done, ship it!
395 std::string str = createAnswerString(CONTROL_RESULT_SUCCESS, arguments);
396 return (str);
397 }
398
399 /// @brief Submits one or more thread commands to a MtTcpListener.
400 ///
401 /// This function command will create a MtTcpListener
402 /// with the given number of threads, initiates the given
403 /// number of clients, each requesting the "thread" command,
404 /// and then iteratively runs the test's IOService until all
405 /// the clients have received their responses or an error occurs.
406 ///
407 /// It requires that the number of clients, when greater than the
408 /// number of threads, be a multiple of the number of threads. The
409 /// thread command handler is structured in such a way as to ensure
410 /// (we hope) that each thread handles the same number of commands.
411 ///
412 /// @param num_threads - the number of threads the MtTcpListener
413 /// should use. Must be greater than 0.
414 /// @param num_clients - the number of clients that should issue the
415 /// thread command. Each client is used to carry out a single thread
416 /// command request. Must be greater than 0 and a multiple of num_threads
417 /// if it is greater than num_threads.
418 void threadListenAndRespond(size_t num_threads, size_t num_clients) {
419 // First we makes sure the parameter rules apply.
420 ASSERT_TRUE(num_threads)switch (0) case 0: default: if (const ::testing::AssertionResult
gtest_ar_ = ::testing::AssertionResult(num_threads)) ; else return
::testing::internal::AssertHelper(::testing::TestPartResult::
kFatalFailure, "../../../src/lib/tcp/tests/mt_tcp_listener_mgr_unittests.cc"
, 420, ::testing::internal::GetBoolAssertionFailureMessage( gtest_ar_
, "num_threads", "false", "true") .c_str()) = ::testing::Message
()
;
421 ASSERT_TRUE(num_clients)switch (0) case 0: default: if (const ::testing::AssertionResult
gtest_ar_ = ::testing::AssertionResult(num_clients)) ; else return
::testing::internal::AssertHelper(::testing::TestPartResult::
kFatalFailure, "../../../src/lib/tcp/tests/mt_tcp_listener_mgr_unittests.cc"
, 421, ::testing::internal::GetBoolAssertionFailureMessage( gtest_ar_
, "num_clients", "false", "true") .c_str()) = ::testing::Message
()
;
422 ASSERT_TRUE((num_clients < num_threads) || (num_clients % num_threads == 0))switch (0) case 0: default: if (const ::testing::AssertionResult
gtest_ar_ = ::testing::AssertionResult((num_clients < num_threads
) || (num_clients % num_threads == 0))) ; else return ::testing
::internal::AssertHelper(::testing::TestPartResult::kFatalFailure
, "../../../src/lib/tcp/tests/mt_tcp_listener_mgr_unittests.cc"
, 422, ::testing::internal::GetBoolAssertionFailureMessage( gtest_ar_
, "(num_clients < num_threads) || (num_clients % num_threads == 0)"
, "false", "true") .c_str()) = ::testing::Message()
;
423
424 num_threads_ = num_threads;
425 num_clients_ = num_clients;
426 chunk_size_ = num_threads_;
427 if (num_clients_ < chunk_size_) {
428 chunk_size_ = num_clients_;
429 }
430
431 // Create an MtTcpListenerMgr with prescribed number of threads.
432 createMtTcpListenerMgr(num_threads,
433 std::bind(&MtTcpListenerMgrTest::synchronizedCommandHandler,
434 this, ph::_1));
435
436 // Start it and verify it is running.
437 ASSERT_NO_THROW_LOG(mt_listener_mgr_->start()){ try { mt_listener_mgr_->start(); } catch (const std::exception
& ex) { return ::testing::internal::AssertHelper(::testing
::TestPartResult::kFatalFailure, "../../../src/lib/tcp/tests/mt_tcp_listener_mgr_unittests.cc"
, 437, "Failed") = ::testing::Message() << "mt_listener_mgr_->start()"
<< " threw type: " << typeid(ex).name() <<
", what: " << ex.what(); } catch (...) { return ::testing
::internal::AssertHelper(::testing::TestPartResult::kFatalFailure
, "../../../src/lib/tcp/tests/mt_tcp_listener_mgr_unittests.cc"
, 437, "Failed") = ::testing::Message() << "mt_listener_mgr_->start()"
<< " threw non-std::exception"; } }
;
438 ASSERT_TRUE(mt_listener_mgr_->isRunning())switch (0) case 0: default: if (const ::testing::AssertionResult
gtest_ar_ = ::testing::AssertionResult(mt_listener_mgr_->
isRunning())) ; else return ::testing::internal::AssertHelper
(::testing::TestPartResult::kFatalFailure, "../../../src/lib/tcp/tests/mt_tcp_listener_mgr_unittests.cc"
, 438, ::testing::internal::GetBoolAssertionFailureMessage( gtest_ar_
, "mt_listener_mgr_->isRunning()", "false", "true") .c_str
()) = ::testing::Message()
;
439 EXPECT_EQ(mt_listener_mgr_->getThreadCount(), num_threads)switch (0) case 0: default: if (const ::testing::AssertionResult
gtest_ar = (::testing::internal::EqHelper::Compare("mt_listener_mgr_->getThreadCount()"
, "num_threads", mt_listener_mgr_->getThreadCount(), num_threads
))) ; else ::testing::internal::AssertHelper(::testing::TestPartResult
::kNonFatalFailure, "../../../src/lib/tcp/tests/mt_tcp_listener_mgr_unittests.cc"
, 439, gtest_ar.failure_message()) = ::testing::Message()
;
440
441 // Maps the number of clients served by a given thread-id.
442 std::map<std::string, int> clients_per_thread;
443
444 // Initiate the prescribed number of command requests.
445 num_in_progress_ = 0;
446 while (clients_.size() < num_clients) {
447 ASSERT_NO_THROW_LOG(startThreadCommand("I am done")){ try { startThreadCommand("I am done"); } catch (const std::
exception& ex) { return ::testing::internal::AssertHelper
(::testing::TestPartResult::kFatalFailure, "../../../src/lib/tcp/tests/mt_tcp_listener_mgr_unittests.cc"
, 447, "Failed") = ::testing::Message() << "startThreadCommand(\"I am done\")"
<< " threw type: " << typeid(ex).name() <<
", what: " << ex.what(); } catch (...) { return ::testing
::internal::AssertHelper(::testing::TestPartResult::kFatalFailure
, "../../../src/lib/tcp/tests/mt_tcp_listener_mgr_unittests.cc"
, 447, "Failed") = ::testing::Message() << "startThreadCommand(\"I am done\")"
<< " threw non-std::exception"; } }
;
448 }
449
450 // Now we run the client-side IOService until all requests are done,
451 // errors occur or the test times out.
452 ASSERT_NO_FATAL_FAILURE(runIOService())switch (0) case 0: default: if (::testing::internal::AlwaysTrue
()) { const ::testing::internal::HasNewFatalFailureHelper gtest_fatal_failure_checker
; if (::testing::internal::AlwaysTrue()) { runIOService(); } else
static_assert(true, ""); if (gtest_fatal_failure_checker.has_new_fatal_failure
()) { goto gtest_label_testnofatal_452; } } else gtest_label_testnofatal_452
: return ::testing::internal::AssertHelper(::testing::TestPartResult
::kFatalFailure, "../../../src/lib/tcp/tests/mt_tcp_listener_mgr_unittests.cc"
, 452, "Expected: " "runIOService()" " doesn't generate new fatal "
"failures in the current thread.\n" " Actual: it does.") = ::
testing::Message()
;
453
454 // Stop the listener and then verify it has stopped.
455 ASSERT_NO_THROW_LOG(mt_listener_mgr_->stop()){ try { mt_listener_mgr_->stop(); } catch (const std::exception
& ex) { return ::testing::internal::AssertHelper(::testing
::TestPartResult::kFatalFailure, "../../../src/lib/tcp/tests/mt_tcp_listener_mgr_unittests.cc"
, 455, "Failed") = ::testing::Message() << "mt_listener_mgr_->stop()"
<< " threw type: " << typeid(ex).name() <<
", what: " << ex.what(); } catch (...) { return ::testing
::internal::AssertHelper(::testing::TestPartResult::kFatalFailure
, "../../../src/lib/tcp/tests/mt_tcp_listener_mgr_unittests.cc"
, 455, "Failed") = ::testing::Message() << "mt_listener_mgr_->stop()"
<< " threw non-std::exception"; } }
;
456 ASSERT_TRUE(mt_listener_mgr_->isStopped())switch (0) case 0: default: if (const ::testing::AssertionResult
gtest_ar_ = ::testing::AssertionResult(mt_listener_mgr_->
isStopped())) ; else return ::testing::internal::AssertHelper
(::testing::TestPartResult::kFatalFailure, "../../../src/lib/tcp/tests/mt_tcp_listener_mgr_unittests.cc"
, 456, ::testing::internal::GetBoolAssertionFailureMessage( gtest_ar_
, "mt_listener_mgr_->isStopped()", "false", "true") .c_str
()) = ::testing::Message()
;
457 EXPECT_EQ(mt_listener_mgr_->getThreadCount(), 0U)switch (0) case 0: default: if (const ::testing::AssertionResult
gtest_ar = (::testing::internal::EqHelper::Compare("mt_listener_mgr_->getThreadCount()"
, "0U", mt_listener_mgr_->getThreadCount(), 0U))) ; else ::
testing::internal::AssertHelper(::testing::TestPartResult::kNonFatalFailure
, "../../../src/lib/tcp/tests/mt_tcp_listener_mgr_unittests.cc"
, 457, gtest_ar.failure_message()) = ::testing::Message()
;
458
459 // Iterate over the clients, checking their outcomes.
460 size_t total_responses = 0;
461 for (auto const& client : clients_) {
462 // Client should have completed its receive successfully.
463 ASSERT_TRUE(client->receiveDone())switch (0) case 0: default: if (const ::testing::AssertionResult
gtest_ar_ = ::testing::AssertionResult(client->receiveDone
())) ; else return ::testing::internal::AssertHelper(::testing
::TestPartResult::kFatalFailure, "../../../src/lib/tcp/tests/mt_tcp_listener_mgr_unittests.cc"
, 463, ::testing::internal::GetBoolAssertionFailureMessage( gtest_ar_
, "client->receiveDone()", "false", "true") .c_str()) = ::
testing::Message()
;
464
465 // Now we walk the element tree to get the response data. It should look
466 // this:
467 //
468 // {
469 // "arguments": { "client-ptr": "xxxxx",
470 // "thread-id": "zzzzz" },
471 // "result": 0
472 // ]
473 //
474 // We expect 1 response.
475 auto responses = client->getResponses();
476 ASSERT_EQ(responses.size(), 1U)switch (0) case 0: default: if (const ::testing::AssertionResult
gtest_ar = (::testing::internal::EqHelper::Compare("responses.size()"
, "1U", responses.size(), 1U))) ; else return ::testing::internal
::AssertHelper(::testing::TestPartResult::kFatalFailure, "../../../src/lib/tcp/tests/mt_tcp_listener_mgr_unittests.cc"
, 476, gtest_ar.failure_message()) = ::testing::Message()
;
477
478 // First we turn it into an Element tree.
479 ConstElementPtr answer;
480 ASSERT_NO_THROW_LOG(answer = Element::fromJSON(responses.front())){ try { answer = Element::fromJSON(responses.front()); } catch
(const std::exception& ex) { return ::testing::internal::
AssertHelper(::testing::TestPartResult::kFatalFailure, "../../../src/lib/tcp/tests/mt_tcp_listener_mgr_unittests.cc"
, 480, "Failed") = ::testing::Message() << "answer = Element::fromJSON(responses.front())"
<< " threw type: " << typeid(ex).name() <<
", what: " << ex.what(); } catch (...) { return ::testing
::internal::AssertHelper(::testing::TestPartResult::kFatalFailure
, "../../../src/lib/tcp/tests/mt_tcp_listener_mgr_unittests.cc"
, 480, "Failed") = ::testing::Message() << "answer = Element::fromJSON(responses.front())"
<< " threw non-std::exception"; } }
;
481
482 // Answer should be a map containing "arguments" and "results".
483 ASSERT_EQ(answer->getType(), Element::map)switch (0) case 0: default: if (const ::testing::AssertionResult
gtest_ar = (::testing::internal::EqHelper::Compare("answer->getType()"
, "Element::map", answer->getType(), Element::map))) ; else
return ::testing::internal::AssertHelper(::testing::TestPartResult
::kFatalFailure, "../../../src/lib/tcp/tests/mt_tcp_listener_mgr_unittests.cc"
, 483, gtest_ar.failure_message()) = ::testing::Message()
;
484
485 // "result" should be 0.
486 ConstElementPtr result = answer->get("result");
487 ASSERT_TRUE(result)switch (0) case 0: default: if (const ::testing::AssertionResult
gtest_ar_ = ::testing::AssertionResult(result)) ; else return
::testing::internal::AssertHelper(::testing::TestPartResult::
kFatalFailure, "../../../src/lib/tcp/tests/mt_tcp_listener_mgr_unittests.cc"
, 487, ::testing::internal::GetBoolAssertionFailureMessage( gtest_ar_
, "result", "false", "true") .c_str()) = ::testing::Message()
;
488 ASSERT_EQ(result->getType(), Element::integer)switch (0) case 0: default: if (const ::testing::AssertionResult
gtest_ar = (::testing::internal::EqHelper::Compare("result->getType()"
, "Element::integer", result->getType(), Element::integer)
)) ; else return ::testing::internal::AssertHelper(::testing::
TestPartResult::kFatalFailure, "../../../src/lib/tcp/tests/mt_tcp_listener_mgr_unittests.cc"
, 488, gtest_ar.failure_message()) = ::testing::Message()
;
489 ASSERT_EQ(result->intValue(), 0)switch (0) case 0: default: if (const ::testing::AssertionResult
gtest_ar = (::testing::internal::EqHelper::Compare("result->intValue()"
, "0", result->intValue(), 0))) ; else return ::testing::internal
::AssertHelper(::testing::TestPartResult::kFatalFailure, "../../../src/lib/tcp/tests/mt_tcp_listener_mgr_unittests.cc"
, 489, gtest_ar.failure_message()) = ::testing::Message()
;
490
491 // "arguments" is a map containing "client-ptr" and "thread-id".
492 ConstElementPtr arguments = answer->get("arguments");
493 ASSERT_TRUE(arguments)switch (0) case 0: default: if (const ::testing::AssertionResult
gtest_ar_ = ::testing::AssertionResult(arguments)) ; else return
::testing::internal::AssertHelper(::testing::TestPartResult::
kFatalFailure, "../../../src/lib/tcp/tests/mt_tcp_listener_mgr_unittests.cc"
, 493, ::testing::internal::GetBoolAssertionFailureMessage( gtest_ar_
, "arguments", "false", "true") .c_str()) = ::testing::Message
()
;
494 ASSERT_EQ(arguments->getType(), Element::map)switch (0) case 0: default: if (const ::testing::AssertionResult
gtest_ar = (::testing::internal::EqHelper::Compare("arguments->getType()"
, "Element::map", arguments->getType(), Element::map))) ; else
return ::testing::internal::AssertHelper(::testing::TestPartResult
::kFatalFailure, "../../../src/lib/tcp/tests/mt_tcp_listener_mgr_unittests.cc"
, 494, gtest_ar.failure_message()) = ::testing::Message()
;
495
496 // "client-ptr" is a string.
497 ConstElementPtr client_ptr = arguments->get("client-ptr");
498 ASSERT_TRUE(client_ptr)switch (0) case 0: default: if (const ::testing::AssertionResult
gtest_ar_ = ::testing::AssertionResult(client_ptr)) ; else return
::testing::internal::AssertHelper(::testing::TestPartResult::
kFatalFailure, "../../../src/lib/tcp/tests/mt_tcp_listener_mgr_unittests.cc"
, 498, ::testing::internal::GetBoolAssertionFailureMessage( gtest_ar_
, "client_ptr", "false", "true") .c_str()) = ::testing::Message
()
;
499 ASSERT_EQ(client_ptr->getType(), Element::string)switch (0) case 0: default: if (const ::testing::AssertionResult
gtest_ar = (::testing::internal::EqHelper::Compare("client_ptr->getType()"
, "Element::string", client_ptr->getType(), Element::string
))) ; else return ::testing::internal::AssertHelper(::testing
::TestPartResult::kFatalFailure, "../../../src/lib/tcp/tests/mt_tcp_listener_mgr_unittests.cc"
, 499, gtest_ar.failure_message()) = ::testing::Message()
;
500
501 // "thread-id" is a string.
502 ConstElementPtr thread_id = arguments->get("thread-id");
503 ASSERT_TRUE(thread_id)switch (0) case 0: default: if (const ::testing::AssertionResult
gtest_ar_ = ::testing::AssertionResult(thread_id)) ; else return
::testing::internal::AssertHelper(::testing::TestPartResult::
kFatalFailure, "../../../src/lib/tcp/tests/mt_tcp_listener_mgr_unittests.cc"
, 503, ::testing::internal::GetBoolAssertionFailureMessage( gtest_ar_
, "thread_id", "false", "true") .c_str()) = ::testing::Message
()
;
504 ASSERT_EQ(thread_id->getType(), Element::string)switch (0) case 0: default: if (const ::testing::AssertionResult
gtest_ar = (::testing::internal::EqHelper::Compare("thread_id->getType()"
, "Element::string", thread_id->getType(), Element::string
))) ; else return ::testing::internal::AssertHelper(::testing
::TestPartResult::kFatalFailure, "../../../src/lib/tcp/tests/mt_tcp_listener_mgr_unittests.cc"
, 504, gtest_ar.failure_message()) = ::testing::Message()
;
505 std::string thread_id_str = thread_id->stringValue();
506
507 // Make sure the response received was for this client.
508 std::stringstream ss;
509 ss << client;
510 ASSERT_EQ(client_ptr->stringValue(), ss.str())switch (0) case 0: default: if (const ::testing::AssertionResult
gtest_ar = (::testing::internal::EqHelper::Compare("client_ptr->stringValue()"
, "ss.str()", client_ptr->stringValue(), ss.str()))) ; else
return ::testing::internal::AssertHelper(::testing::TestPartResult
::kFatalFailure, "../../../src/lib/tcp/tests/mt_tcp_listener_mgr_unittests.cc"
, 510, gtest_ar.failure_message()) = ::testing::Message()
;
511
512 // Bump the client count for the given thread-id.
513 auto it = clients_per_thread.find(thread_id_str);
514 if (it != clients_per_thread.end()) {
515 clients_per_thread[thread_id_str] = it->second + 1;
516 } else {
517 clients_per_thread[thread_id_str] = 1;
518 }
519 ++total_responses;
520 }
521
522 // We should have responses for all our clients.
523 EXPECT_EQ(total_responses, num_clients)switch (0) case 0: default: if (const ::testing::AssertionResult
gtest_ar = (::testing::internal::EqHelper::Compare("total_responses"
, "num_clients", total_responses, num_clients))) ; else ::testing
::internal::AssertHelper(::testing::TestPartResult::kNonFatalFailure
, "../../../src/lib/tcp/tests/mt_tcp_listener_mgr_unittests.cc"
, 523, gtest_ar.failure_message()) = ::testing::Message()
;
524
525 // Verify we have the expected number of entries in our map.
526 size_t expected_thread_count = (num_clients < num_threads ?
527 num_clients : num_threads);
528
529 ASSERT_EQ(clients_per_thread.size(), expected_thread_count)switch (0) case 0: default: if (const ::testing::AssertionResult
gtest_ar = (::testing::internal::EqHelper::Compare("clients_per_thread.size()"
, "expected_thread_count", clients_per_thread.size(), expected_thread_count
))) ; else return ::testing::internal::AssertHelper(::testing
::TestPartResult::kFatalFailure, "../../../src/lib/tcp/tests/mt_tcp_listener_mgr_unittests.cc"
, 529, gtest_ar.failure_message()) = ::testing::Message()
;
530
531 // Each thread-id ought to have handled the same number of clients.
532 for (auto const& it : clients_per_thread) {
533 EXPECT_EQ(it.second,switch (0) case 0: default: if (const ::testing::AssertionResult
gtest_ar = (::testing::internal::EqHelper::Compare("it.second"
, "static_cast<long>(num_clients / clients_per_thread.size())"
, it.second, static_cast<long>(num_clients / clients_per_thread
.size())))) ; else ::testing::internal::AssertHelper(::testing
::TestPartResult::kNonFatalFailure, "../../../src/lib/tcp/tests/mt_tcp_listener_mgr_unittests.cc"
, 534, gtest_ar.failure_message()) = ::testing::Message()
534 static_cast<long>(num_clients / clients_per_thread.size()))switch (0) case 0: default: if (const ::testing::AssertionResult
gtest_ar = (::testing::internal::EqHelper::Compare("it.second"
, "static_cast<long>(num_clients / clients_per_thread.size())"
, it.second, static_cast<long>(num_clients / clients_per_thread
.size())))) ; else ::testing::internal::AssertHelper(::testing
::TestPartResult::kNonFatalFailure, "../../../src/lib/tcp/tests/mt_tcp_listener_mgr_unittests.cc"
, 534, gtest_ar.failure_message()) = ::testing::Message()
535 << "thread-id: " << it.first
536 << ", clients: " << it.second << std::endl;
537 }
538 }
539
540 /// @brief Pauses and resumes a MtTcpListener while it processes command
541 /// requests.
542 ///
543 /// This function command will create a MtTcpListenerMgr
544 /// with the given number of threads, initiates the given
545 /// number of clients, each requesting the "thread" command,
546 /// and then iteratively runs the test's IOService until all
547 /// the clients have received their responses or an error occurs.
548 /// It will pause and resume the listener at intervals governed
549 /// by the given number of pauses.
550 ///
551 /// @param num_threads - the number of threads the MtTcpListener
552 /// should use. Must be greater than 0.
553 /// @param num_clients - the number of clients that should issue the
554 /// thread command. Each client is used to carry out a single thread
555 /// command request. Must be greater than 0.
556 /// @param num_pauses Desired number of times the listener should be
557 /// paused during the test. Must be greater than 0.
558 void workPauseAndResume(size_t num_threads, size_t num_clients,
559 size_t num_pauses) {
560 // First we makes sure the parameter rules apply.
561 ASSERT_TRUE(num_threads)switch (0) case 0: default: if (const ::testing::AssertionResult
gtest_ar_ = ::testing::AssertionResult(num_threads)) ; else return
::testing::internal::AssertHelper(::testing::TestPartResult::
kFatalFailure, "../../../src/lib/tcp/tests/mt_tcp_listener_mgr_unittests.cc"
, 561, ::testing::internal::GetBoolAssertionFailureMessage( gtest_ar_
, "num_threads", "false", "true") .c_str()) = ::testing::Message
()
;
1
Control jumps to 'case 0:' at line 561
2
Assuming the condition is true
3
Taking true branch
562 ASSERT_TRUE(num_clients)switch (0) case 0: default: if (const ::testing::AssertionResult
gtest_ar_ = ::testing::AssertionResult(num_clients)) ; else return
::testing::internal::AssertHelper(::testing::TestPartResult::
kFatalFailure, "../../../src/lib/tcp/tests/mt_tcp_listener_mgr_unittests.cc"
, 562, ::testing::internal::GetBoolAssertionFailureMessage( gtest_ar_
, "num_clients", "false", "true") .c_str()) = ::testing::Message
()
;
4
Control jumps to 'case 0:' at line 562
5
Assuming the condition is true
6
Taking true branch
563 ASSERT_TRUE(num_pauses)switch (0) case 0: default: if (const ::testing::AssertionResult
gtest_ar_ = ::testing::AssertionResult(num_pauses)) ; else return
::testing::internal::AssertHelper(::testing::TestPartResult::
kFatalFailure, "../../../src/lib/tcp/tests/mt_tcp_listener_mgr_unittests.cc"
, 563, ::testing::internal::GetBoolAssertionFailureMessage( gtest_ar_
, "num_pauses", "false", "true") .c_str()) = ::testing::Message
()
;
7
Control jumps to 'case 0:' at line 563
8
Assuming the condition is true
9
Taking true branch
564 num_threads_ = num_threads;
565 num_clients_ = num_clients;
566
567 // Create an MtTcpListenerMgr with prescribed number of threads and the
568 // simple handler.
569 createMtTcpListenerMgr(num_threads,
570 std::bind(&MtTcpListenerMgrTest::simpleCommandHandler,
571 this, ph::_1));
572
573 ASSERT_TRUE(mt_listener_mgr_)switch (0) case 0: default: if (const ::testing::AssertionResult
gtest_ar_ = ::testing::AssertionResult(mt_listener_mgr_)) ; else
return ::testing::internal::AssertHelper(::testing::TestPartResult
::kFatalFailure, "../../../src/lib/tcp/tests/mt_tcp_listener_mgr_unittests.cc"
, 573, ::testing::internal::GetBoolAssertionFailureMessage( gtest_ar_
, "mt_listener_mgr_", "false", "true") .c_str()) = ::testing::
Message()
;
10
Control jumps to 'case 0:' at line 573
11
Taking true branch
574
575 // Start it and verify it is running.
576 ASSERT_NO_THROW_LOG(mt_listener_mgr_->start()){ try { mt_listener_mgr_->start(); } catch (const std::exception
& ex) { return ::testing::internal::AssertHelper(::testing
::TestPartResult::kFatalFailure, "../../../src/lib/tcp/tests/mt_tcp_listener_mgr_unittests.cc"
, 576, "Failed") = ::testing::Message() << "mt_listener_mgr_->start()"
<< " threw type: " << typeid(ex).name() <<
", what: " << ex.what(); } catch (...) { return ::testing
::internal::AssertHelper(::testing::TestPartResult::kFatalFailure
, "../../../src/lib/tcp/tests/mt_tcp_listener_mgr_unittests.cc"
, 576, "Failed") = ::testing::Message() << "mt_listener_mgr_->start()"
<< " threw non-std::exception"; } }
;
577 ASSERT_TRUE(mt_listener_mgr_->isRunning())switch (0) case 0: default: if (const ::testing::AssertionResult
gtest_ar_ = ::testing::AssertionResult(mt_listener_mgr_->
isRunning())) ; else return ::testing::internal::AssertHelper
(::testing::TestPartResult::kFatalFailure, "../../../src/lib/tcp/tests/mt_tcp_listener_mgr_unittests.cc"
, 577, ::testing::internal::GetBoolAssertionFailureMessage( gtest_ar_
, "mt_listener_mgr_->isRunning()", "false", "true") .c_str
()) = ::testing::Message()
;
12
Control jumps to 'case 0:' at line 577
13
Assuming the condition is true
14
Taking true branch
578 EXPECT_EQ(mt_listener_mgr_->getThreadCount(), num_threads)switch (0) case 0: default: if (const ::testing::AssertionResult
gtest_ar = (::testing::internal::EqHelper::Compare("mt_listener_mgr_->getThreadCount()"
, "num_threads", mt_listener_mgr_->getThreadCount(), num_threads
))) ; else ::testing::internal::AssertHelper(::testing::TestPartResult
::kNonFatalFailure, "../../../src/lib/tcp/tests/mt_tcp_listener_mgr_unittests.cc"
, 578, gtest_ar.failure_message()) = ::testing::Message()
;
15
Control jumps to 'case 0:' at line 578
16
Assuming the condition is false
17
Taking false branch
579
580 // Initiate the prescribed number of command requests.
581 num_in_progress_ = 0;
582 while (clients_.size() < num_clients) {
18
Assuming the condition is true
19
Loop condition is true. Entering loop body
583 ASSERT_NO_THROW_LOG(startThreadCommand("I am done")){ try { startThreadCommand("I am done"); } catch (const std::
exception& ex) { return ::testing::internal::AssertHelper
(::testing::TestPartResult::kFatalFailure, "../../../src/lib/tcp/tests/mt_tcp_listener_mgr_unittests.cc"
, 583, "Failed") = ::testing::Message() << "startThreadCommand(\"I am done\")"
<< " threw type: " << typeid(ex).name() <<
", what: " << ex.what(); } catch (...) { return ::testing
::internal::AssertHelper(::testing::TestPartResult::kFatalFailure
, "../../../src/lib/tcp/tests/mt_tcp_listener_mgr_unittests.cc"
, 583, "Failed") = ::testing::Message() << "startThreadCommand(\"I am done\")"
<< " threw non-std::exception"; } }
;
20
Calling 'MtTcpListenerMgrTest::startThreadCommand'
584 }
585
586 // Now we run the client-side IOService until all requests are done,
587 // errors occur or the test times out. We'll pause and resume the
588 // number of times given by num_pauses.
589 size_t num_done = 0;
590 size_t total_requests = clients_.size();
591 while (num_done < total_requests) {
592 // Calculate how many more requests to process before we pause again.
593 // We divide the number of outstanding requests by the number of pauses
594 // and stop after we've done at least that many more requests.
595 size_t request_limit = (pause_cnt_ < num_pauses ?
596 (num_done + ((total_requests - num_done) / num_pauses))
597 : total_requests);
598
599 // Run test IOService until we hit the limit.
600 runIOService(request_limit);
601
602 // If we've done all our pauses we should be through.
603 if (pause_cnt_ == num_pauses) {
604 break;
605 }
606
607 // Pause the client.
608 ASSERT_NO_THROW(mt_listener_mgr_->pause())switch (0) case 0: default: if (::testing::internal::TrueWithString
gtest_msg{}) { try { if (::testing::internal::AlwaysTrue()) {
mt_listener_mgr_->pause(); } else static_assert(true, "")
; } catch (std::exception const& e) { gtest_msg.value = "it throws "
; gtest_msg.value += ::testing::internal::GetTypeName(typeid(
e)); gtest_msg.value += " with description \""; gtest_msg.value
+= e.what(); gtest_msg.value += "\"."; goto gtest_label_testnothrow_608
; } catch (...) { gtest_msg.value = "it throws."; goto gtest_label_testnothrow_608
; } } else gtest_label_testnothrow_608 : return ::testing::internal
::AssertHelper(::testing::TestPartResult::kFatalFailure, "../../../src/lib/tcp/tests/mt_tcp_listener_mgr_unittests.cc"
, 608, ("Expected: " "mt_listener_mgr_->pause()" " doesn't throw an exception.\n"
" Actual: " + gtest_msg.value) .c_str()) = ::testing::Message
()
;
609 ASSERT_TRUE(mt_listener_mgr_->isPaused())switch (0) case 0: default: if (const ::testing::AssertionResult
gtest_ar_ = ::testing::AssertionResult(mt_listener_mgr_->
isPaused())) ; else return ::testing::internal::AssertHelper(
::testing::TestPartResult::kFatalFailure, "../../../src/lib/tcp/tests/mt_tcp_listener_mgr_unittests.cc"
, 609, ::testing::internal::GetBoolAssertionFailureMessage( gtest_ar_
, "mt_listener_mgr_->isPaused()", "false", "true") .c_str(
)) = ::testing::Message()
;
610 ++pause_cnt_;
611
612 // Check our progress.
613 num_done = 0;
614 for (auto const& client : clients_) {
615 if (client->receiveDone()) {
616 ++num_done;
617 }
618 }
619
620 // We should completed at least as many as our
621 // target limit.
622 ASSERT_GE(num_done, request_limit)switch (0) case 0: default: if (const ::testing::AssertionResult
gtest_ar = (::testing::internal::CmpHelperGE("num_done", "request_limit"
, num_done, request_limit))) ; else return ::testing::internal
::AssertHelper(::testing::TestPartResult::kFatalFailure, "../../../src/lib/tcp/tests/mt_tcp_listener_mgr_unittests.cc"
, 622, gtest_ar.failure_message()) = ::testing::Message()
;
623
624 // Resume the listener.
625 ASSERT_NO_THROW(mt_listener_mgr_->resume())switch (0) case 0: default: if (::testing::internal::TrueWithString
gtest_msg{}) { try { if (::testing::internal::AlwaysTrue()) {
mt_listener_mgr_->resume(); } else static_assert(true, ""
); } catch (std::exception const& e) { gtest_msg.value = "it throws "
; gtest_msg.value += ::testing::internal::GetTypeName(typeid(
e)); gtest_msg.value += " with description \""; gtest_msg.value
+= e.what(); gtest_msg.value += "\"."; goto gtest_label_testnothrow_625
; } catch (...) { gtest_msg.value = "it throws."; goto gtest_label_testnothrow_625
; } } else gtest_label_testnothrow_625 : return ::testing::internal
::AssertHelper(::testing::TestPartResult::kFatalFailure, "../../../src/lib/tcp/tests/mt_tcp_listener_mgr_unittests.cc"
, 625, ("Expected: " "mt_listener_mgr_->resume()" " doesn't throw an exception.\n"
" Actual: " + gtest_msg.value) .c_str()) = ::testing::Message
()
;
626 ASSERT_TRUE(mt_listener_mgr_->isRunning())switch (0) case 0: default: if (const ::testing::AssertionResult
gtest_ar_ = ::testing::AssertionResult(mt_listener_mgr_->
isRunning())) ; else return ::testing::internal::AssertHelper
(::testing::TestPartResult::kFatalFailure, "../../../src/lib/tcp/tests/mt_tcp_listener_mgr_unittests.cc"
, 626, ::testing::internal::GetBoolAssertionFailureMessage( gtest_ar_
, "mt_listener_mgr_->isRunning()", "false", "true") .c_str
()) = ::testing::Message()
;
627 }
628
629 // Stop the listener and then verify it has stopped.
630 ASSERT_NO_THROW_LOG(mt_listener_mgr_->stop()){ try { mt_listener_mgr_->stop(); } catch (const std::exception
& ex) { return ::testing::internal::AssertHelper(::testing
::TestPartResult::kFatalFailure, "../../../src/lib/tcp/tests/mt_tcp_listener_mgr_unittests.cc"
, 630, "Failed") = ::testing::Message() << "mt_listener_mgr_->stop()"
<< " threw type: " << typeid(ex).name() <<
", what: " << ex.what(); } catch (...) { return ::testing
::internal::AssertHelper(::testing::TestPartResult::kFatalFailure
, "../../../src/lib/tcp/tests/mt_tcp_listener_mgr_unittests.cc"
, 630, "Failed") = ::testing::Message() << "mt_listener_mgr_->stop()"
<< " threw non-std::exception"; } }
;
631 ASSERT_TRUE(mt_listener_mgr_->isStopped())switch (0) case 0: default: if (const ::testing::AssertionResult
gtest_ar_ = ::testing::AssertionResult(mt_listener_mgr_->
isStopped())) ; else return ::testing::internal::AssertHelper
(::testing::TestPartResult::kFatalFailure, "../../../src/lib/tcp/tests/mt_tcp_listener_mgr_unittests.cc"
, 631, ::testing::internal::GetBoolAssertionFailureMessage( gtest_ar_
, "mt_listener_mgr_->isStopped()", "false", "true") .c_str
()) = ::testing::Message()
;
632 EXPECT_EQ(mt_listener_mgr_->getThreadCount(), 0U)switch (0) case 0: default: if (const ::testing::AssertionResult
gtest_ar = (::testing::internal::EqHelper::Compare("mt_listener_mgr_->getThreadCount()"
, "0U", mt_listener_mgr_->getThreadCount(), 0U))) ; else ::
testing::internal::AssertHelper(::testing::TestPartResult::kNonFatalFailure
, "../../../src/lib/tcp/tests/mt_tcp_listener_mgr_unittests.cc"
, 632, gtest_ar.failure_message()) = ::testing::Message()
;
633
634 // Iterate over the clients, checking their outcomes.
635 size_t total_responses = 0;
636 for (auto const& client : clients_) {
637 // Client should have completed its receive successfully.
638 ASSERT_TRUE(client->receiveDone())switch (0) case 0: default: if (const ::testing::AssertionResult
gtest_ar_ = ::testing::AssertionResult(client->receiveDone
())) ; else return ::testing::internal::AssertHelper(::testing
::TestPartResult::kFatalFailure, "../../../src/lib/tcp/tests/mt_tcp_listener_mgr_unittests.cc"
, 638, ::testing::internal::GetBoolAssertionFailureMessage( gtest_ar_
, "client->receiveDone()", "false", "true") .c_str()) = ::
testing::Message()
;
639
640 // Now we walk the element tree to get the response data. It should look
641 // this:
642 //
643 // {
644 // "arguments": { "client-ptr": "xxxxx",
645 // "sign-off": "good bye",
646 // "thread-id": "zzzzz" },
647 // "result": 0
648 // }
649 //
650 // We expect one response.
651 auto responses = client->getResponses();
652 ASSERT_EQ(responses.size(), 1U)switch (0) case 0: default: if (const ::testing::AssertionResult
gtest_ar = (::testing::internal::EqHelper::Compare("responses.size()"
, "1U", responses.size(), 1U))) ; else return ::testing::internal
::AssertHelper(::testing::TestPartResult::kFatalFailure, "../../../src/lib/tcp/tests/mt_tcp_listener_mgr_unittests.cc"
, 652, gtest_ar.failure_message()) = ::testing::Message()
;
653
654 // First we turn it into an Element tree.
655 ConstElementPtr answer;
656 ASSERT_NO_THROW_LOG(answer = Element::fromJSON(responses.front())){ try { answer = Element::fromJSON(responses.front()); } catch
(const std::exception& ex) { return ::testing::internal::
AssertHelper(::testing::TestPartResult::kFatalFailure, "../../../src/lib/tcp/tests/mt_tcp_listener_mgr_unittests.cc"
, 656, "Failed") = ::testing::Message() << "answer = Element::fromJSON(responses.front())"
<< " threw type: " << typeid(ex).name() <<
", what: " << ex.what(); } catch (...) { return ::testing
::internal::AssertHelper(::testing::TestPartResult::kFatalFailure
, "../../../src/lib/tcp/tests/mt_tcp_listener_mgr_unittests.cc"
, 656, "Failed") = ::testing::Message() << "answer = Element::fromJSON(responses.front())"
<< " threw non-std::exception"; } }
;
657
658 // Answer should be a map containing "arguments" and "results".
659 ASSERT_EQ(answer->getType(), Element::map)switch (0) case 0: default: if (const ::testing::AssertionResult
gtest_ar = (::testing::internal::EqHelper::Compare("answer->getType()"
, "Element::map", answer->getType(), Element::map))) ; else
return ::testing::internal::AssertHelper(::testing::TestPartResult
::kFatalFailure, "../../../src/lib/tcp/tests/mt_tcp_listener_mgr_unittests.cc"
, 659, gtest_ar.failure_message()) = ::testing::Message()
;
660
661 // "result" should be 0.
662 ConstElementPtr result = answer->get("result");
663 ASSERT_TRUE(result)switch (0) case 0: default: if (const ::testing::AssertionResult
gtest_ar_ = ::testing::AssertionResult(result)) ; else return
::testing::internal::AssertHelper(::testing::TestPartResult::
kFatalFailure, "../../../src/lib/tcp/tests/mt_tcp_listener_mgr_unittests.cc"
, 663, ::testing::internal::GetBoolAssertionFailureMessage( gtest_ar_
, "result", "false", "true") .c_str()) = ::testing::Message()
;
664 ASSERT_EQ(result->getType(), Element::integer)switch (0) case 0: default: if (const ::testing::AssertionResult
gtest_ar = (::testing::internal::EqHelper::Compare("result->getType()"
, "Element::integer", result->getType(), Element::integer)
)) ; else return ::testing::internal::AssertHelper(::testing::
TestPartResult::kFatalFailure, "../../../src/lib/tcp/tests/mt_tcp_listener_mgr_unittests.cc"
, 664, gtest_ar.failure_message()) = ::testing::Message()
;
665 ASSERT_EQ(result->intValue(), 0)switch (0) case 0: default: if (const ::testing::AssertionResult
gtest_ar = (::testing::internal::EqHelper::Compare("result->intValue()"
, "0", result->intValue(), 0))) ; else return ::testing::internal
::AssertHelper(::testing::TestPartResult::kFatalFailure, "../../../src/lib/tcp/tests/mt_tcp_listener_mgr_unittests.cc"
, 665, gtest_ar.failure_message()) = ::testing::Message()
;
666
667 // "arguments" is a map containing "client-ptr" and "thread-id".
668 ConstElementPtr arguments = answer->get("arguments");
669 ASSERT_TRUE(arguments)switch (0) case 0: default: if (const ::testing::AssertionResult
gtest_ar_ = ::testing::AssertionResult(arguments)) ; else return
::testing::internal::AssertHelper(::testing::TestPartResult::
kFatalFailure, "../../../src/lib/tcp/tests/mt_tcp_listener_mgr_unittests.cc"
, 669, ::testing::internal::GetBoolAssertionFailureMessage( gtest_ar_
, "arguments", "false", "true") .c_str()) = ::testing::Message
()
;
670 ASSERT_EQ(arguments->getType(), Element::map)switch (0) case 0: default: if (const ::testing::AssertionResult
gtest_ar = (::testing::internal::EqHelper::Compare("arguments->getType()"
, "Element::map", arguments->getType(), Element::map))) ; else
return ::testing::internal::AssertHelper(::testing::TestPartResult
::kFatalFailure, "../../../src/lib/tcp/tests/mt_tcp_listener_mgr_unittests.cc"
, 670, gtest_ar.failure_message()) = ::testing::Message()
;
671
672 // "client-ptr" is a string.
673 ConstElementPtr client_ptr = arguments->get("client-ptr");
674 ASSERT_TRUE(client_ptr)switch (0) case 0: default: if (const ::testing::AssertionResult
gtest_ar_ = ::testing::AssertionResult(client_ptr)) ; else return
::testing::internal::AssertHelper(::testing::TestPartResult::
kFatalFailure, "../../../src/lib/tcp/tests/mt_tcp_listener_mgr_unittests.cc"
, 674, ::testing::internal::GetBoolAssertionFailureMessage( gtest_ar_
, "client_ptr", "false", "true") .c_str()) = ::testing::Message
()
;
675 ASSERT_EQ(client_ptr->getType(), Element::string)switch (0) case 0: default: if (const ::testing::AssertionResult
gtest_ar = (::testing::internal::EqHelper::Compare("client_ptr->getType()"
, "Element::string", client_ptr->getType(), Element::string
))) ; else return ::testing::internal::AssertHelper(::testing
::TestPartResult::kFatalFailure, "../../../src/lib/tcp/tests/mt_tcp_listener_mgr_unittests.cc"
, 675, gtest_ar.failure_message()) = ::testing::Message()
;
676
677 // "thread-id" is a string.
678 ConstElementPtr thread_id = arguments->get("thread-id");
679 ASSERT_TRUE(thread_id)switch (0) case 0: default: if (const ::testing::AssertionResult
gtest_ar_ = ::testing::AssertionResult(thread_id)) ; else return
::testing::internal::AssertHelper(::testing::TestPartResult::
kFatalFailure, "../../../src/lib/tcp/tests/mt_tcp_listener_mgr_unittests.cc"
, 679, ::testing::internal::GetBoolAssertionFailureMessage( gtest_ar_
, "thread_id", "false", "true") .c_str()) = ::testing::Message
()
;
680 ASSERT_EQ(thread_id->getType(), Element::string)switch (0) case 0: default: if (const ::testing::AssertionResult
gtest_ar = (::testing::internal::EqHelper::Compare("thread_id->getType()"
, "Element::string", thread_id->getType(), Element::string
))) ; else return ::testing::internal::AssertHelper(::testing
::TestPartResult::kFatalFailure, "../../../src/lib/tcp/tests/mt_tcp_listener_mgr_unittests.cc"
, 680, gtest_ar.failure_message()) = ::testing::Message()
;
681 std::string thread_id_str = thread_id->stringValue();
682
683 // Make sure the response received was for this client.
684 std::stringstream ss;
685 ss << client;
686 ASSERT_EQ(client_ptr->stringValue(), ss.str())switch (0) case 0: default: if (const ::testing::AssertionResult
gtest_ar = (::testing::internal::EqHelper::Compare("client_ptr->stringValue()"
, "ss.str()", client_ptr->stringValue(), ss.str()))) ; else
return ::testing::internal::AssertHelper(::testing::TestPartResult
::kFatalFailure, "../../../src/lib/tcp/tests/mt_tcp_listener_mgr_unittests.cc"
, 686, gtest_ar.failure_message()) = ::testing::Message()
;
687
688 ++total_responses;
689 }
690
691 // We should have responses for all our clients.
692 EXPECT_EQ(total_responses, num_clients)switch (0) case 0: default: if (const ::testing::AssertionResult
gtest_ar = (::testing::internal::EqHelper::Compare("total_responses"
, "num_clients", total_responses, num_clients))) ; else ::testing
::internal::AssertHelper(::testing::TestPartResult::kNonFatalFailure
, "../../../src/lib/tcp/tests/mt_tcp_listener_mgr_unittests.cc"
, 692, gtest_ar.failure_message()) = ::testing::Message()
;
693
694 // We should have had the expected number of pauses.
695 if (!num_pauses) {
696 ASSERT_EQ(pause_cnt_, 0U)switch (0) case 0: default: if (const ::testing::AssertionResult
gtest_ar = (::testing::internal::EqHelper::Compare("pause_cnt_"
, "0U", pause_cnt_, 0U))) ; else return ::testing::internal::
AssertHelper(::testing::TestPartResult::kFatalFailure, "../../../src/lib/tcp/tests/mt_tcp_listener_mgr_unittests.cc"
, 696, gtest_ar.failure_message()) = ::testing::Message()
;
697 } else {
698 // We allow a range on pauses of +-1.
699 ASSERT_TRUE((num_pauses - 1) <= pause_cnt_ &&switch (0) case 0: default: if (const ::testing::AssertionResult
gtest_ar_ = ::testing::AssertionResult((num_pauses - 1) <=
pause_cnt_ && (pause_cnt_ <= (num_pauses + 1)))) ;
else return ::testing::internal::AssertHelper(::testing::TestPartResult
::kFatalFailure, "../../../src/lib/tcp/tests/mt_tcp_listener_mgr_unittests.cc"
, 700, ::testing::internal::GetBoolAssertionFailureMessage( gtest_ar_
, "(num_pauses - 1) <= pause_cnt_ && (pause_cnt_ <= (num_pauses + 1))"
, "false", "true") .c_str()) = ::testing::Message()
700 (pause_cnt_ <= (num_pauses + 1)))switch (0) case 0: default: if (const ::testing::AssertionResult
gtest_ar_ = ::testing::AssertionResult((num_pauses - 1) <=
pause_cnt_ && (pause_cnt_ <= (num_pauses + 1)))) ;
else return ::testing::internal::AssertHelper(::testing::TestPartResult
::kFatalFailure, "../../../src/lib/tcp/tests/mt_tcp_listener_mgr_unittests.cc"
, 700, ::testing::internal::GetBoolAssertionFailureMessage( gtest_ar_
, "(num_pauses - 1) <= pause_cnt_ && (pause_cnt_ <= (num_pauses + 1))"
, "false", "true") .c_str()) = ::testing::Message()
701 << " num_pauses: " << num_pauses
702 << ", pause_cnt_" << pause_cnt_;
703 }
704 }
705
706 /// @brief MtTcpListenerMgr instance under test.
707 MtTcpListenerMgrPtr mt_listener_mgr_;
708
709 /// @brief IO service used in drive the test and test clients.
710 IOServicePtr io_service_;
711
712 /// @brief Asynchronous timer service to detect timeouts.
713 IntervalTimer test_timer_;
714
715 /// @brief Asynchronous timer for running IO service for a specified amount
716 /// of time.
717 IntervalTimer run_io_service_timer_;
718
719 /// @brief List of client connections.
720 std::list<TcpTestClientPtr> clients_;
721
722 /// @brief Number of threads the listener should use for the test.
723 size_t num_threads_;
724
725 /// @brief Number of client requests to make during the test.
726 size_t num_clients_;
727
728 /// @brief Number of requests currently in progress.
729 size_t num_in_progress_;
730
731 /// @brief Number of requests that have finished.
732 size_t num_finished_;
733
734 /// @brief Chunk size of requests that need to be processed in parallel.
735 ///
736 /// This can either be the number of threads (if the number of requests is
737 /// greater than the number of threads) or the number of requests (if the
738 /// number of threads is greater than the number of requests).
739 size_t chunk_size_;
740
741 /// @brief Mutex used to lock during thread coordination.
742 std::mutex mutex_;
743
744 /// @brief Condition variable used to coordinate threads.
745 std::condition_variable cv_;
746
747 /// @brief Number of times client has been paused during the test.
748 size_t pause_cnt_;
749
750 /// @brief Number of clients that have completed their assignment or
751 /// failed
752 size_t clients_done_;
753
754 /// @brief Response Handler passed down to each connection.
755 TcpTestConnection::ResponseHandler response_handler_;
756};
757
758/// Verifies the construction, starting, stopping, pausing, resuming,
759/// and destruction of MtTcpListener.
760TEST_F(MtTcpListenerMgrTest, basics)static_assert(sizeof("MtTcpListenerMgrTest") > 1, "test_suite_name must not be empty"
); static_assert(sizeof("basics") > 1, "test_name must not be empty"
); class MtTcpListenerMgrTest_basics_Test : public MtTcpListenerMgrTest
{ public: MtTcpListenerMgrTest_basics_Test() = default; ~MtTcpListenerMgrTest_basics_Test
() override = default; MtTcpListenerMgrTest_basics_Test (const
MtTcpListenerMgrTest_basics_Test &) = delete; MtTcpListenerMgrTest_basics_Test
& operator=( const MtTcpListenerMgrTest_basics_Test &
) = delete; MtTcpListenerMgrTest_basics_Test (MtTcpListenerMgrTest_basics_Test
&&) noexcept = delete; MtTcpListenerMgrTest_basics_Test
& operator=( MtTcpListenerMgrTest_basics_Test &&
) noexcept = delete; private: void TestBody() override; [[maybe_unused
]] static ::testing::TestInfo* const test_info_; }; ::testing
::TestInfo* const MtTcpListenerMgrTest_basics_Test::test_info_
= ::testing::internal::MakeAndRegisterTestInfo( "MtTcpListenerMgrTest"
, "basics", nullptr, nullptr, ::testing::internal::CodeLocation
("../../../src/lib/tcp/tests/mt_tcp_listener_mgr_unittests.cc"
, 760), (::testing::internal::GetTypeId<MtTcpListenerMgrTest
>()), ::testing::internal::SuiteApiResolver< MtTcpListenerMgrTest
>::GetSetUpCaseOrSuite("../../../src/lib/tcp/tests/mt_tcp_listener_mgr_unittests.cc"
, 760), ::testing::internal::SuiteApiResolver< MtTcpListenerMgrTest
>::GetTearDownCaseOrSuite("../../../src/lib/tcp/tests/mt_tcp_listener_mgr_unittests.cc"
, 760), new ::testing::internal::TestFactoryImpl<MtTcpListenerMgrTest_basics_Test
>); void MtTcpListenerMgrTest_basics_Test::TestBody()
{
761 // Make sure multi-threading is off.
762 MultiThreadingMgr::instance().setMode(false);
763 IOAddress address(SERVER_ADDRESS);
764 uint16_t port = SERVER_PORT;
765
766 // Make sure we can create one.
767 ASSERT_NO_THROW_LOG(mt_listener_mgr_.reset({ try { mt_listener_mgr_.reset( new MtTcpListenerMgr( std::bind
(&MtTcpListenerMgrTest::listenerFactory, this, ph::_1, ph
::_2, ph::_3, ph::_4, ph::_5, ph::_6), address, port)); } catch
(const std::exception& ex) { return ::testing::internal::
AssertHelper(::testing::TestPartResult::kFatalFailure, "../../../src/lib/tcp/tests/mt_tcp_listener_mgr_unittests.cc"
, 771, "Failed") = ::testing::Message() << "mt_listener_mgr_.reset( new MtTcpListenerMgr( std::bind(&MtTcpListenerMgrTest::listenerFactory, this, ph::_1, ph::_2, ph::_3, ph::_4, ph::_5, ph::_6), address, port))"
<< " threw type: " << typeid(ex).name() <<
", what: " << ex.what(); } catch (...) { return ::testing
::internal::AssertHelper(::testing::TestPartResult::kFatalFailure
, "../../../src/lib/tcp/tests/mt_tcp_listener_mgr_unittests.cc"
, 771, "Failed") = ::testing::Message() << "mt_listener_mgr_.reset( new MtTcpListenerMgr( std::bind(&MtTcpListenerMgrTest::listenerFactory, this, ph::_1, ph::_2, ph::_3, ph::_4, ph::_5, ph::_6), address, port))"
<< " threw non-std::exception"; } }
768 new MtTcpListenerMgr({ try { mt_listener_mgr_.reset( new MtTcpListenerMgr( std::bind
(&MtTcpListenerMgrTest::listenerFactory, this, ph::_1, ph
::_2, ph::_3, ph::_4, ph::_5, ph::_6), address, port)); } catch
(const std::exception& ex) { return ::testing::internal::
AssertHelper(::testing::TestPartResult::kFatalFailure, "../../../src/lib/tcp/tests/mt_tcp_listener_mgr_unittests.cc"
, 771, "Failed") = ::testing::Message() << "mt_listener_mgr_.reset( new MtTcpListenerMgr( std::bind(&MtTcpListenerMgrTest::listenerFactory, this, ph::_1, ph::_2, ph::_3, ph::_4, ph::_5, ph::_6), address, port))"
<< " threw type: " << typeid(ex).name() <<
", what: " << ex.what(); } catch (...) { return ::testing
::internal::AssertHelper(::testing::TestPartResult::kFatalFailure
, "../../../src/lib/tcp/tests/mt_tcp_listener_mgr_unittests.cc"
, 771, "Failed") = ::testing::Message() << "mt_listener_mgr_.reset( new MtTcpListenerMgr( std::bind(&MtTcpListenerMgrTest::listenerFactory, this, ph::_1, ph::_2, ph::_3, ph::_4, ph::_5, ph::_6), address, port))"
<< " threw non-std::exception"; } }
769 std::bind(&MtTcpListenerMgrTest::listenerFactory, this,{ try { mt_listener_mgr_.reset( new MtTcpListenerMgr( std::bind
(&MtTcpListenerMgrTest::listenerFactory, this, ph::_1, ph
::_2, ph::_3, ph::_4, ph::_5, ph::_6), address, port)); } catch
(const std::exception& ex) { return ::testing::internal::
AssertHelper(::testing::TestPartResult::kFatalFailure, "../../../src/lib/tcp/tests/mt_tcp_listener_mgr_unittests.cc"
, 771, "Failed") = ::testing::Message() << "mt_listener_mgr_.reset( new MtTcpListenerMgr( std::bind(&MtTcpListenerMgrTest::listenerFactory, this, ph::_1, ph::_2, ph::_3, ph::_4, ph::_5, ph::_6), address, port))"
<< " threw type: " << typeid(ex).name() <<
", what: " << ex.what(); } catch (...) { return ::testing
::internal::AssertHelper(::testing::TestPartResult::kFatalFailure
, "../../../src/lib/tcp/tests/mt_tcp_listener_mgr_unittests.cc"
, 771, "Failed") = ::testing::Message() << "mt_listener_mgr_.reset( new MtTcpListenerMgr( std::bind(&MtTcpListenerMgrTest::listenerFactory, this, ph::_1, ph::_2, ph::_3, ph::_4, ph::_5, ph::_6), address, port))"
<< " threw non-std::exception"; } }
770 ph::_1, ph::_2, ph::_3, ph::_4, ph::_5, ph::_6),{ try { mt_listener_mgr_.reset( new MtTcpListenerMgr( std::bind
(&MtTcpListenerMgrTest::listenerFactory, this, ph::_1, ph
::_2, ph::_3, ph::_4, ph::_5, ph::_6), address, port)); } catch
(const std::exception& ex) { return ::testing::internal::
AssertHelper(::testing::TestPartResult::kFatalFailure, "../../../src/lib/tcp/tests/mt_tcp_listener_mgr_unittests.cc"
, 771, "Failed") = ::testing::Message() << "mt_listener_mgr_.reset( new MtTcpListenerMgr( std::bind(&MtTcpListenerMgrTest::listenerFactory, this, ph::_1, ph::_2, ph::_3, ph::_4, ph::_5, ph::_6), address, port))"
<< " threw type: " << typeid(ex).name() <<
", what: " << ex.what(); } catch (...) { return ::testing
::internal::AssertHelper(::testing::TestPartResult::kFatalFailure
, "../../../src/lib/tcp/tests/mt_tcp_listener_mgr_unittests.cc"
, 771, "Failed") = ::testing::Message() << "mt_listener_mgr_.reset( new MtTcpListenerMgr( std::bind(&MtTcpListenerMgrTest::listenerFactory, this, ph::_1, ph::_2, ph::_3, ph::_4, ph::_5, ph::_6), address, port))"
<< " threw non-std::exception"; } }
771 address, port))){ try { mt_listener_mgr_.reset( new MtTcpListenerMgr( std::bind
(&MtTcpListenerMgrTest::listenerFactory, this, ph::_1, ph
::_2, ph::_3, ph::_4, ph::_5, ph::_6), address, port)); } catch
(const std::exception& ex) { return ::testing::internal::
AssertHelper(::testing::TestPartResult::kFatalFailure, "../../../src/lib/tcp/tests/mt_tcp_listener_mgr_unittests.cc"
, 771, "Failed") = ::testing::Message() << "mt_listener_mgr_.reset( new MtTcpListenerMgr( std::bind(&MtTcpListenerMgrTest::listenerFactory, this, ph::_1, ph::_2, ph::_3, ph::_4, ph::_5, ph::_6), address, port))"
<< " threw type: " << typeid(ex).name() <<
", what: " << ex.what(); } catch (...) { return ::testing
::internal::AssertHelper(::testing::TestPartResult::kFatalFailure
, "../../../src/lib/tcp/tests/mt_tcp_listener_mgr_unittests.cc"
, 771, "Failed") = ::testing::Message() << "mt_listener_mgr_.reset( new MtTcpListenerMgr( std::bind(&MtTcpListenerMgrTest::listenerFactory, this, ph::_1, ph::_2, ph::_3, ph::_4, ph::_5, ph::_6), address, port))"
<< " threw non-std::exception"; } }
;
772
773 ASSERT_TRUE(mt_listener_mgr_)switch (0) case 0: default: if (const ::testing::AssertionResult
gtest_ar_ = ::testing::AssertionResult(mt_listener_mgr_)) ; else
return ::testing::internal::AssertHelper(::testing::TestPartResult
::kFatalFailure, "../../../src/lib/tcp/tests/mt_tcp_listener_mgr_unittests.cc"
, 773, ::testing::internal::GetBoolAssertionFailureMessage( gtest_ar_
, "mt_listener_mgr_", "false", "true") .c_str()) = ::testing::
Message()
;
774
775 // Verify the getters do what we expect.
776 EXPECT_EQ(mt_listener_mgr_->getAddress(), address)switch (0) case 0: default: if (const ::testing::AssertionResult
gtest_ar = (::testing::internal::EqHelper::Compare("mt_listener_mgr_->getAddress()"
, "address", mt_listener_mgr_->getAddress(), address))) ; else
::testing::internal::AssertHelper(::testing::TestPartResult::
kNonFatalFailure, "../../../src/lib/tcp/tests/mt_tcp_listener_mgr_unittests.cc"
, 776, gtest_ar.failure_message()) = ::testing::Message()
;
777 EXPECT_EQ(mt_listener_mgr_->getPort(), port)switch (0) case 0: default: if (const ::testing::AssertionResult
gtest_ar = (::testing::internal::EqHelper::Compare("mt_listener_mgr_->getPort()"
, "port", mt_listener_mgr_->getPort(), port))) ; else ::testing
::internal::AssertHelper(::testing::TestPartResult::kNonFatalFailure
, "../../../src/lib/tcp/tests/mt_tcp_listener_mgr_unittests.cc"
, 777, gtest_ar.failure_message()) = ::testing::Message()
;
778 EXPECT_EQ(mt_listener_mgr_->getThreadPoolSize(), 1U)switch (0) case 0: default: if (const ::testing::AssertionResult
gtest_ar = (::testing::internal::EqHelper::Compare("mt_listener_mgr_->getThreadPoolSize()"
, "1U", mt_listener_mgr_->getThreadPoolSize(), 1U))) ; else
::testing::internal::AssertHelper(::testing::TestPartResult::
kNonFatalFailure, "../../../src/lib/tcp/tests/mt_tcp_listener_mgr_unittests.cc"
, 778, gtest_ar.failure_message()) = ::testing::Message()
;
779 EXPECT_FALSE(mt_listener_mgr_->getTlsContext())switch (0) case 0: default: if (const ::testing::AssertionResult
gtest_ar_ = ::testing::AssertionResult(!(mt_listener_mgr_->
getTlsContext()))) ; else ::testing::internal::AssertHelper(::
testing::TestPartResult::kNonFatalFailure, "../../../src/lib/tcp/tests/mt_tcp_listener_mgr_unittests.cc"
, 779, ::testing::internal::GetBoolAssertionFailureMessage( gtest_ar_
, "mt_listener_mgr_->getTlsContext()", "true", "false") .c_str
()) = ::testing::Message()
;
780
781 // It should not have an IOService, should not be listening and
782 // should have no threads.
783 ASSERT_FALSE(mt_listener_mgr_->getThreadIOService())switch (0) case 0: default: if (const ::testing::AssertionResult
gtest_ar_ = ::testing::AssertionResult(!(mt_listener_mgr_->
getThreadIOService()))) ; else return ::testing::internal::AssertHelper
(::testing::TestPartResult::kFatalFailure, "../../../src/lib/tcp/tests/mt_tcp_listener_mgr_unittests.cc"
, 783, ::testing::internal::GetBoolAssertionFailureMessage( gtest_ar_
, "mt_listener_mgr_->getThreadIOService()", "true", "false"
) .c_str()) = ::testing::Message()
;
784 EXPECT_TRUE(mt_listener_mgr_->isStopped())switch (0) case 0: default: if (const ::testing::AssertionResult
gtest_ar_ = ::testing::AssertionResult(mt_listener_mgr_->
isStopped())) ; else ::testing::internal::AssertHelper(::testing
::TestPartResult::kNonFatalFailure, "../../../src/lib/tcp/tests/mt_tcp_listener_mgr_unittests.cc"
, 784, ::testing::internal::GetBoolAssertionFailureMessage( gtest_ar_
, "mt_listener_mgr_->isStopped()", "false", "true") .c_str
()) = ::testing::Message()
;
785 EXPECT_EQ(mt_listener_mgr_->getThreadCount(), 0U)switch (0) case 0: default: if (const ::testing::AssertionResult
gtest_ar = (::testing::internal::EqHelper::Compare("mt_listener_mgr_->getThreadCount()"
, "0U", mt_listener_mgr_->getThreadCount(), 0U))) ; else ::
testing::internal::AssertHelper(::testing::TestPartResult::kNonFatalFailure
, "../../../src/lib/tcp/tests/mt_tcp_listener_mgr_unittests.cc"
, 785, gtest_ar.failure_message()) = ::testing::Message()
;
786
787 // Verify that we cannot start it when multi-threading is disabled.
788 ASSERT_FALSE(MultiThreadingMgr::instance().getMode())switch (0) case 0: default: if (const ::testing::AssertionResult
gtest_ar_ = ::testing::AssertionResult(!(MultiThreadingMgr::
instance().getMode()))) ; else return ::testing::internal::AssertHelper
(::testing::TestPartResult::kFatalFailure, "../../../src/lib/tcp/tests/mt_tcp_listener_mgr_unittests.cc"
, 788, ::testing::internal::GetBoolAssertionFailureMessage( gtest_ar_
, "MultiThreadingMgr::instance().getMode()", "true", "false")
.c_str()) = ::testing::Message()
;
789 ASSERT_THROW_MSG(mt_listener_mgr_->start(), InvalidOperation,{ try { mt_listener_mgr_->start(); return ::testing::internal
::AssertHelper(::testing::TestPartResult::kFatalFailure, "../../../src/lib/tcp/tests/mt_tcp_listener_mgr_unittests.cc"
, 791, "Failed") = ::testing::Message() << "no exception, expected: "
<< "InvalidOperation"; } catch (const InvalidOperation
& ex) { switch (0) case 0: default: if (const ::testing::
AssertionResult gtest_ar = (::testing::internal::EqHelper::Compare
("std::string(ex.what())", "\"MtTcpListenerMgr cannot be started\" \" when multi-threading is disabled\""
, std::string(ex.what()), "MtTcpListenerMgr cannot be started"
" when multi-threading is disabled"))) ; else return ::testing
::internal::AssertHelper(::testing::TestPartResult::kFatalFailure
, "../../../src/lib/tcp/tests/mt_tcp_listener_mgr_unittests.cc"
, 791, gtest_ar.failure_message()) = ::testing::Message(); } catch
(...) { return ::testing::internal::AssertHelper(::testing::
TestPartResult::kFatalFailure, "../../../src/lib/tcp/tests/mt_tcp_listener_mgr_unittests.cc"
, 791, "Failed") = ::testing::Message() << "wrong exception type thrown, expected: "
<< "InvalidOperation"; } }
790 "MtTcpListenerMgr cannot be started"{ try { mt_listener_mgr_->start(); return ::testing::internal
::AssertHelper(::testing::TestPartResult::kFatalFailure, "../../../src/lib/tcp/tests/mt_tcp_listener_mgr_unittests.cc"
, 791, "Failed") = ::testing::Message() << "no exception, expected: "
<< "InvalidOperation"; } catch (const InvalidOperation
& ex) { switch (0) case 0: default: if (const ::testing::
AssertionResult gtest_ar = (::testing::internal::EqHelper::Compare
("std::string(ex.what())", "\"MtTcpListenerMgr cannot be started\" \" when multi-threading is disabled\""
, std::string(ex.what()), "MtTcpListenerMgr cannot be started"
" when multi-threading is disabled"))) ; else return ::testing
::internal::AssertHelper(::testing::TestPartResult::kFatalFailure
, "../../../src/lib/tcp/tests/mt_tcp_listener_mgr_unittests.cc"
, 791, gtest_ar.failure_message()) = ::testing::Message(); } catch
(...) { return ::testing::internal::AssertHelper(::testing::
TestPartResult::kFatalFailure, "../../../src/lib/tcp/tests/mt_tcp_listener_mgr_unittests.cc"
, 791, "Failed") = ::testing::Message() << "wrong exception type thrown, expected: "
<< "InvalidOperation"; } }
791 " when multi-threading is disabled"){ try { mt_listener_mgr_->start(); return ::testing::internal
::AssertHelper(::testing::TestPartResult::kFatalFailure, "../../../src/lib/tcp/tests/mt_tcp_listener_mgr_unittests.cc"
, 791, "Failed") = ::testing::Message() << "no exception, expected: "
<< "InvalidOperation"; } catch (const InvalidOperation
& ex) { switch (0) case 0: default: if (const ::testing::
AssertionResult gtest_ar = (::testing::internal::EqHelper::Compare
("std::string(ex.what())", "\"MtTcpListenerMgr cannot be started\" \" when multi-threading is disabled\""
, std::string(ex.what()), "MtTcpListenerMgr cannot be started"
" when multi-threading is disabled"))) ; else return ::testing
::internal::AssertHelper(::testing::TestPartResult::kFatalFailure
, "../../../src/lib/tcp/tests/mt_tcp_listener_mgr_unittests.cc"
, 791, gtest_ar.failure_message()) = ::testing::Message(); } catch
(...) { return ::testing::internal::AssertHelper(::testing::
TestPartResult::kFatalFailure, "../../../src/lib/tcp/tests/mt_tcp_listener_mgr_unittests.cc"
, 791, "Failed") = ::testing::Message() << "wrong exception type thrown, expected: "
<< "InvalidOperation"; } }
;
792
793 // It should still not be listening and have no threads.
794 EXPECT_TRUE(mt_listener_mgr_->isStopped())switch (0) case 0: default: if (const ::testing::AssertionResult
gtest_ar_ = ::testing::AssertionResult(mt_listener_mgr_->
isStopped())) ; else ::testing::internal::AssertHelper(::testing
::TestPartResult::kNonFatalFailure, "../../../src/lib/tcp/tests/mt_tcp_listener_mgr_unittests.cc"
, 794, ::testing::internal::GetBoolAssertionFailureMessage( gtest_ar_
, "mt_listener_mgr_->isStopped()", "false", "true") .c_str
()) = ::testing::Message()
;
795 EXPECT_EQ(mt_listener_mgr_->getThreadCount(), 0U)switch (0) case 0: default: if (const ::testing::AssertionResult
gtest_ar = (::testing::internal::EqHelper::Compare("mt_listener_mgr_->getThreadCount()"
, "0U", mt_listener_mgr_->getThreadCount(), 0U))) ; else ::
testing::internal::AssertHelper(::testing::TestPartResult::kNonFatalFailure
, "../../../src/lib/tcp/tests/mt_tcp_listener_mgr_unittests.cc"
, 795, gtest_ar.failure_message()) = ::testing::Message()
;
796
797 // Enable multi-threading.
798 MultiThreadingMgr::instance().setMode(true);
799
800 // Make sure we can start it and it's listening with 1 thread.
801 ASSERT_NO_THROW_LOG(mt_listener_mgr_->start()){ try { mt_listener_mgr_->start(); } catch (const std::exception
& ex) { return ::testing::internal::AssertHelper(::testing
::TestPartResult::kFatalFailure, "../../../src/lib/tcp/tests/mt_tcp_listener_mgr_unittests.cc"
, 801, "Failed") = ::testing::Message() << "mt_listener_mgr_->start()"
<< " threw type: " << typeid(ex).name() <<
", what: " << ex.what(); } catch (...) { return ::testing
::internal::AssertHelper(::testing::TestPartResult::kFatalFailure
, "../../../src/lib/tcp/tests/mt_tcp_listener_mgr_unittests.cc"
, 801, "Failed") = ::testing::Message() << "mt_listener_mgr_->start()"
<< " threw non-std::exception"; } }
;
802 ASSERT_TRUE(mt_listener_mgr_->isRunning())switch (0) case 0: default: if (const ::testing::AssertionResult
gtest_ar_ = ::testing::AssertionResult(mt_listener_mgr_->
isRunning())) ; else return ::testing::internal::AssertHelper
(::testing::TestPartResult::kFatalFailure, "../../../src/lib/tcp/tests/mt_tcp_listener_mgr_unittests.cc"
, 802, ::testing::internal::GetBoolAssertionFailureMessage( gtest_ar_
, "mt_listener_mgr_->isRunning()", "false", "true") .c_str
()) = ::testing::Message()
;
803 EXPECT_EQ(mt_listener_mgr_->getThreadCount(), 1U)switch (0) case 0: default: if (const ::testing::AssertionResult
gtest_ar = (::testing::internal::EqHelper::Compare("mt_listener_mgr_->getThreadCount()"
, "1U", mt_listener_mgr_->getThreadCount(), 1U))) ; else ::
testing::internal::AssertHelper(::testing::TestPartResult::kNonFatalFailure
, "../../../src/lib/tcp/tests/mt_tcp_listener_mgr_unittests.cc"
, 803, gtest_ar.failure_message()) = ::testing::Message()
;
804 ASSERT_TRUE(mt_listener_mgr_->getThreadIOService())switch (0) case 0: default: if (const ::testing::AssertionResult
gtest_ar_ = ::testing::AssertionResult(mt_listener_mgr_->
getThreadIOService())) ; else return ::testing::internal::AssertHelper
(::testing::TestPartResult::kFatalFailure, "../../../src/lib/tcp/tests/mt_tcp_listener_mgr_unittests.cc"
, 804, ::testing::internal::GetBoolAssertionFailureMessage( gtest_ar_
, "mt_listener_mgr_->getThreadIOService()", "false", "true"
) .c_str()) = ::testing::Message()
;
805 EXPECT_FALSE(mt_listener_mgr_->getThreadIOService()->stopped())switch (0) case 0: default: if (const ::testing::AssertionResult
gtest_ar_ = ::testing::AssertionResult(!(mt_listener_mgr_->
getThreadIOService()->stopped()))) ; else ::testing::internal
::AssertHelper(::testing::TestPartResult::kNonFatalFailure, "../../../src/lib/tcp/tests/mt_tcp_listener_mgr_unittests.cc"
, 805, ::testing::internal::GetBoolAssertionFailureMessage( gtest_ar_
, "mt_listener_mgr_->getThreadIOService()->stopped()", "true"
, "false") .c_str()) = ::testing::Message()
;
806
807 // Trying to start it again should fail.
808 ASSERT_THROW_MSG(mt_listener_mgr_->start(), InvalidOperation,{ try { mt_listener_mgr_->start(); return ::testing::internal
::AssertHelper(::testing::TestPartResult::kFatalFailure, "../../../src/lib/tcp/tests/mt_tcp_listener_mgr_unittests.cc"
, 809, "Failed") = ::testing::Message() << "no exception, expected: "
<< "InvalidOperation"; } catch (const InvalidOperation
& ex) { switch (0) case 0: default: if (const ::testing::
AssertionResult gtest_ar = (::testing::internal::EqHelper::Compare
("std::string(ex.what())", "\"MtTcpListenerMgr already started!\""
, std::string(ex.what()), "MtTcpListenerMgr already started!"
))) ; else return ::testing::internal::AssertHelper(::testing
::TestPartResult::kFatalFailure, "../../../src/lib/tcp/tests/mt_tcp_listener_mgr_unittests.cc"
, 809, gtest_ar.failure_message()) = ::testing::Message(); } catch
(...) { return ::testing::internal::AssertHelper(::testing::
TestPartResult::kFatalFailure, "../../../src/lib/tcp/tests/mt_tcp_listener_mgr_unittests.cc"
, 809, "Failed") = ::testing::Message() << "wrong exception type thrown, expected: "
<< "InvalidOperation"; } }
809 "MtTcpListenerMgr already started!"){ try { mt_listener_mgr_->start(); return ::testing::internal
::AssertHelper(::testing::TestPartResult::kFatalFailure, "../../../src/lib/tcp/tests/mt_tcp_listener_mgr_unittests.cc"
, 809, "Failed") = ::testing::Message() << "no exception, expected: "
<< "InvalidOperation"; } catch (const InvalidOperation
& ex) { switch (0) case 0: default: if (const ::testing::
AssertionResult gtest_ar = (::testing::internal::EqHelper::Compare
("std::string(ex.what())", "\"MtTcpListenerMgr already started!\""
, std::string(ex.what()), "MtTcpListenerMgr already started!"
))) ; else return ::testing::internal::AssertHelper(::testing
::TestPartResult::kFatalFailure, "../../../src/lib/tcp/tests/mt_tcp_listener_mgr_unittests.cc"
, 809, gtest_ar.failure_message()) = ::testing::Message(); } catch
(...) { return ::testing::internal::AssertHelper(::testing::
TestPartResult::kFatalFailure, "../../../src/lib/tcp/tests/mt_tcp_listener_mgr_unittests.cc"
, 809, "Failed") = ::testing::Message() << "wrong exception type thrown, expected: "
<< "InvalidOperation"; } }
;
810
811 // Stop it and verify we're no longer listening.
812 ASSERT_NO_THROW_LOG(mt_listener_mgr_->stop()){ try { mt_listener_mgr_->stop(); } catch (const std::exception
& ex) { return ::testing::internal::AssertHelper(::testing
::TestPartResult::kFatalFailure, "../../../src/lib/tcp/tests/mt_tcp_listener_mgr_unittests.cc"
, 812, "Failed") = ::testing::Message() << "mt_listener_mgr_->stop()"
<< " threw type: " << typeid(ex).name() <<
", what: " << ex.what(); } catch (...) { return ::testing
::internal::AssertHelper(::testing::TestPartResult::kFatalFailure
, "../../../src/lib/tcp/tests/mt_tcp_listener_mgr_unittests.cc"
, 812, "Failed") = ::testing::Message() << "mt_listener_mgr_->stop()"
<< " threw non-std::exception"; } }
;
813 ASSERT_TRUE(mt_listener_mgr_->isStopped())switch (0) case 0: default: if (const ::testing::AssertionResult
gtest_ar_ = ::testing::AssertionResult(mt_listener_mgr_->
isStopped())) ; else return ::testing::internal::AssertHelper
(::testing::TestPartResult::kFatalFailure, "../../../src/lib/tcp/tests/mt_tcp_listener_mgr_unittests.cc"
, 813, ::testing::internal::GetBoolAssertionFailureMessage( gtest_ar_
, "mt_listener_mgr_->isStopped()", "false", "true") .c_str
()) = ::testing::Message()
;
814 EXPECT_EQ(mt_listener_mgr_->getThreadCount(), 0U)switch (0) case 0: default: if (const ::testing::AssertionResult
gtest_ar = (::testing::internal::EqHelper::Compare("mt_listener_mgr_->getThreadCount()"
, "0U", mt_listener_mgr_->getThreadCount(), 0U))) ; else ::
testing::internal::AssertHelper(::testing::TestPartResult::kNonFatalFailure
, "../../../src/lib/tcp/tests/mt_tcp_listener_mgr_unittests.cc"
, 814, gtest_ar.failure_message()) = ::testing::Message()
;
815 ASSERT_FALSE(mt_listener_mgr_->getThreadIOService())switch (0) case 0: default: if (const ::testing::AssertionResult
gtest_ar_ = ::testing::AssertionResult(!(mt_listener_mgr_->
getThreadIOService()))) ; else return ::testing::internal::AssertHelper
(::testing::TestPartResult::kFatalFailure, "../../../src/lib/tcp/tests/mt_tcp_listener_mgr_unittests.cc"
, 815, ::testing::internal::GetBoolAssertionFailureMessage( gtest_ar_
, "mt_listener_mgr_->getThreadIOService()", "true", "false"
) .c_str()) = ::testing::Message()
;
816
817 // Make sure we can call stop again without problems.
818 ASSERT_NO_THROW_LOG(mt_listener_mgr_->stop()){ try { mt_listener_mgr_->stop(); } catch (const std::exception
& ex) { return ::testing::internal::AssertHelper(::testing
::TestPartResult::kFatalFailure, "../../../src/lib/tcp/tests/mt_tcp_listener_mgr_unittests.cc"
, 818, "Failed") = ::testing::Message() << "mt_listener_mgr_->stop()"
<< " threw type: " << typeid(ex).name() <<
", what: " << ex.what(); } catch (...) { return ::testing
::internal::AssertHelper(::testing::TestPartResult::kFatalFailure
, "../../../src/lib/tcp/tests/mt_tcp_listener_mgr_unittests.cc"
, 818, "Failed") = ::testing::Message() << "mt_listener_mgr_->stop()"
<< " threw non-std::exception"; } }
;
819
820 // We should be able to restart it.
821 ASSERT_NO_THROW_LOG(mt_listener_mgr_->start()){ try { mt_listener_mgr_->start(); } catch (const std::exception
& ex) { return ::testing::internal::AssertHelper(::testing
::TestPartResult::kFatalFailure, "../../../src/lib/tcp/tests/mt_tcp_listener_mgr_unittests.cc"
, 821, "Failed") = ::testing::Message() << "mt_listener_mgr_->start()"
<< " threw type: " << typeid(ex).name() <<
", what: " << ex.what(); } catch (...) { return ::testing
::internal::AssertHelper(::testing::TestPartResult::kFatalFailure
, "../../../src/lib/tcp/tests/mt_tcp_listener_mgr_unittests.cc"
, 821, "Failed") = ::testing::Message() << "mt_listener_mgr_->start()"
<< " threw non-std::exception"; } }
;
822 ASSERT_TRUE(mt_listener_mgr_->isRunning())switch (0) case 0: default: if (const ::testing::AssertionResult
gtest_ar_ = ::testing::AssertionResult(mt_listener_mgr_->
isRunning())) ; else return ::testing::internal::AssertHelper
(::testing::TestPartResult::kFatalFailure, "../../../src/lib/tcp/tests/mt_tcp_listener_mgr_unittests.cc"
, 822, ::testing::internal::GetBoolAssertionFailureMessage( gtest_ar_
, "mt_listener_mgr_->isRunning()", "false", "true") .c_str
()) = ::testing::Message()
;
823 EXPECT_EQ(mt_listener_mgr_->getThreadCount(), 1U)switch (0) case 0: default: if (const ::testing::AssertionResult
gtest_ar = (::testing::internal::EqHelper::Compare("mt_listener_mgr_->getThreadCount()"
, "1U", mt_listener_mgr_->getThreadCount(), 1U))) ; else ::
testing::internal::AssertHelper(::testing::TestPartResult::kNonFatalFailure
, "../../../src/lib/tcp/tests/mt_tcp_listener_mgr_unittests.cc"
, 823, gtest_ar.failure_message()) = ::testing::Message()
;
824 ASSERT_TRUE(mt_listener_mgr_->getThreadIOService())switch (0) case 0: default: if (const ::testing::AssertionResult
gtest_ar_ = ::testing::AssertionResult(mt_listener_mgr_->
getThreadIOService())) ; else return ::testing::internal::AssertHelper
(::testing::TestPartResult::kFatalFailure, "../../../src/lib/tcp/tests/mt_tcp_listener_mgr_unittests.cc"
, 824, ::testing::internal::GetBoolAssertionFailureMessage( gtest_ar_
, "mt_listener_mgr_->getThreadIOService()", "false", "true"
) .c_str()) = ::testing::Message()
;
825 EXPECT_FALSE(mt_listener_mgr_->getThreadIOService()->stopped())switch (0) case 0: default: if (const ::testing::AssertionResult
gtest_ar_ = ::testing::AssertionResult(!(mt_listener_mgr_->
getThreadIOService()->stopped()))) ; else ::testing::internal
::AssertHelper(::testing::TestPartResult::kNonFatalFailure, "../../../src/lib/tcp/tests/mt_tcp_listener_mgr_unittests.cc"
, 825, ::testing::internal::GetBoolAssertionFailureMessage( gtest_ar_
, "mt_listener_mgr_->getThreadIOService()->stopped()", "true"
, "false") .c_str()) = ::testing::Message()
;
826
827 // Destroying it should also stop it.
828 // If the test timeouts we know it didn't!
829 ASSERT_NO_THROW_LOG(mt_listener_mgr_.reset()){ try { mt_listener_mgr_.reset(); } catch (const std::exception
& ex) { return ::testing::internal::AssertHelper(::testing
::TestPartResult::kFatalFailure, "../../../src/lib/tcp/tests/mt_tcp_listener_mgr_unittests.cc"
, 829, "Failed") = ::testing::Message() << "mt_listener_mgr_.reset()"
<< " threw type: " << typeid(ex).name() <<
", what: " << ex.what(); } catch (...) { return ::testing
::internal::AssertHelper(::testing::TestPartResult::kFatalFailure
, "../../../src/lib/tcp/tests/mt_tcp_listener_mgr_unittests.cc"
, 829, "Failed") = ::testing::Message() << "mt_listener_mgr_.reset()"
<< " threw non-std::exception"; } }
;
830
831 // Verify we can construct with more than one thread.
832 ASSERT_NO_THROW_LOG(mt_listener_mgr_.reset({ try { mt_listener_mgr_.reset( new MtTcpListenerMgr( std::bind
(&MtTcpListenerMgrTest::listenerFactory, this, ph::_1, ph
::_2, ph::_3, ph::_4, ph::_5, ph::_6), address, port, 4)); } catch
(const std::exception& ex) { return ::testing::internal::
AssertHelper(::testing::TestPartResult::kFatalFailure, "../../../src/lib/tcp/tests/mt_tcp_listener_mgr_unittests.cc"
, 836, "Failed") = ::testing::Message() << "mt_listener_mgr_.reset( new MtTcpListenerMgr( std::bind(&MtTcpListenerMgrTest::listenerFactory, this, ph::_1, ph::_2, ph::_3, ph::_4, ph::_5, ph::_6), address, port, 4))"
<< " threw type: " << typeid(ex).name() <<
", what: " << ex.what(); } catch (...) { return ::testing
::internal::AssertHelper(::testing::TestPartResult::kFatalFailure
, "../../../src/lib/tcp/tests/mt_tcp_listener_mgr_unittests.cc"
, 836, "Failed") = ::testing::Message() << "mt_listener_mgr_.reset( new MtTcpListenerMgr( std::bind(&MtTcpListenerMgrTest::listenerFactory, this, ph::_1, ph::_2, ph::_3, ph::_4, ph::_5, ph::_6), address, port, 4))"
<< " threw non-std::exception"; } }
833 new MtTcpListenerMgr({ try { mt_listener_mgr_.reset( new MtTcpListenerMgr( std::bind
(&MtTcpListenerMgrTest::listenerFactory, this, ph::_1, ph
::_2, ph::_3, ph::_4, ph::_5, ph::_6), address, port, 4)); } catch
(const std::exception& ex) { return ::testing::internal::
AssertHelper(::testing::TestPartResult::kFatalFailure, "../../../src/lib/tcp/tests/mt_tcp_listener_mgr_unittests.cc"
, 836, "Failed") = ::testing::Message() << "mt_listener_mgr_.reset( new MtTcpListenerMgr( std::bind(&MtTcpListenerMgrTest::listenerFactory, this, ph::_1, ph::_2, ph::_3, ph::_4, ph::_5, ph::_6), address, port, 4))"
<< " threw type: " << typeid(ex).name() <<
", what: " << ex.what(); } catch (...) { return ::testing
::internal::AssertHelper(::testing::TestPartResult::kFatalFailure
, "../../../src/lib/tcp/tests/mt_tcp_listener_mgr_unittests.cc"
, 836, "Failed") = ::testing::Message() << "mt_listener_mgr_.reset( new MtTcpListenerMgr( std::bind(&MtTcpListenerMgrTest::listenerFactory, this, ph::_1, ph::_2, ph::_3, ph::_4, ph::_5, ph::_6), address, port, 4))"
<< " threw non-std::exception"; } }
834 std::bind(&MtTcpListenerMgrTest::listenerFactory, this,{ try { mt_listener_mgr_.reset( new MtTcpListenerMgr( std::bind
(&MtTcpListenerMgrTest::listenerFactory, this, ph::_1, ph
::_2, ph::_3, ph::_4, ph::_5, ph::_6), address, port, 4)); } catch
(const std::exception& ex) { return ::testing::internal::
AssertHelper(::testing::TestPartResult::kFatalFailure, "../../../src/lib/tcp/tests/mt_tcp_listener_mgr_unittests.cc"
, 836, "Failed") = ::testing::Message() << "mt_listener_mgr_.reset( new MtTcpListenerMgr( std::bind(&MtTcpListenerMgrTest::listenerFactory, this, ph::_1, ph::_2, ph::_3, ph::_4, ph::_5, ph::_6), address, port, 4))"
<< " threw type: " << typeid(ex).name() <<
", what: " << ex.what(); } catch (...) { return ::testing
::internal::AssertHelper(::testing::TestPartResult::kFatalFailure
, "../../../src/lib/tcp/tests/mt_tcp_listener_mgr_unittests.cc"
, 836, "Failed") = ::testing::Message() << "mt_listener_mgr_.reset( new MtTcpListenerMgr( std::bind(&MtTcpListenerMgrTest::listenerFactory, this, ph::_1, ph::_2, ph::_3, ph::_4, ph::_5, ph::_6), address, port, 4))"
<< " threw non-std::exception"; } }
835 ph::_1, ph::_2, ph::_3, ph::_4, ph::_5, ph::_6),{ try { mt_listener_mgr_.reset( new MtTcpListenerMgr( std::bind
(&MtTcpListenerMgrTest::listenerFactory, this, ph::_1, ph
::_2, ph::_3, ph::_4, ph::_5, ph::_6), address, port, 4)); } catch
(const std::exception& ex) { return ::testing::internal::
AssertHelper(::testing::TestPartResult::kFatalFailure, "../../../src/lib/tcp/tests/mt_tcp_listener_mgr_unittests.cc"
, 836, "Failed") = ::testing::Message() << "mt_listener_mgr_.reset( new MtTcpListenerMgr( std::bind(&MtTcpListenerMgrTest::listenerFactory, this, ph::_1, ph::_2, ph::_3, ph::_4, ph::_5, ph::_6), address, port, 4))"
<< " threw type: " << typeid(ex).name() <<
", what: " << ex.what(); } catch (...) { return ::testing
::internal::AssertHelper(::testing::TestPartResult::kFatalFailure
, "../../../src/lib/tcp/tests/mt_tcp_listener_mgr_unittests.cc"
, 836, "Failed") = ::testing::Message() << "mt_listener_mgr_.reset( new MtTcpListenerMgr( std::bind(&MtTcpListenerMgrTest::listenerFactory, this, ph::_1, ph::_2, ph::_3, ph::_4, ph::_5, ph::_6), address, port, 4))"
<< " threw non-std::exception"; } }
836 address, port, 4))){ try { mt_listener_mgr_.reset( new MtTcpListenerMgr( std::bind
(&MtTcpListenerMgrTest::listenerFactory, this, ph::_1, ph
::_2, ph::_3, ph::_4, ph::_5, ph::_6), address, port, 4)); } catch
(const std::exception& ex) { return ::testing::internal::
AssertHelper(::testing::TestPartResult::kFatalFailure, "../../../src/lib/tcp/tests/mt_tcp_listener_mgr_unittests.cc"
, 836, "Failed") = ::testing::Message() << "mt_listener_mgr_.reset( new MtTcpListenerMgr( std::bind(&MtTcpListenerMgrTest::listenerFactory, this, ph::_1, ph::_2, ph::_3, ph::_4, ph::_5, ph::_6), address, port, 4))"
<< " threw type: " << typeid(ex).name() <<
", what: " << ex.what(); } catch (...) { return ::testing
::internal::AssertHelper(::testing::TestPartResult::kFatalFailure
, "../../../src/lib/tcp/tests/mt_tcp_listener_mgr_unittests.cc"
, 836, "Failed") = ::testing::Message() << "mt_listener_mgr_.reset( new MtTcpListenerMgr( std::bind(&MtTcpListenerMgrTest::listenerFactory, this, ph::_1, ph::_2, ph::_3, ph::_4, ph::_5, ph::_6), address, port, 4))"
<< " threw non-std::exception"; } }
;
837
838 ASSERT_NO_THROW_LOG(mt_listener_mgr_->start()){ try { mt_listener_mgr_->start(); } catch (const std::exception
& ex) { return ::testing::internal::AssertHelper(::testing
::TestPartResult::kFatalFailure, "../../../src/lib/tcp/tests/mt_tcp_listener_mgr_unittests.cc"
, 838, "Failed") = ::testing::Message() << "mt_listener_mgr_->start()"
<< " threw type: " << typeid(ex).name() <<
", what: " << ex.what(); } catch (...) { return ::testing
::internal::AssertHelper(::testing::TestPartResult::kFatalFailure
, "../../../src/lib/tcp/tests/mt_tcp_listener_mgr_unittests.cc"
, 838, "Failed") = ::testing::Message() << "mt_listener_mgr_->start()"
<< " threw non-std::exception"; } }
;
839 EXPECT_EQ(mt_listener_mgr_->getAddress(), address)switch (0) case 0: default: if (const ::testing::AssertionResult
gtest_ar = (::testing::internal::EqHelper::Compare("mt_listener_mgr_->getAddress()"
, "address", mt_listener_mgr_->getAddress(), address))) ; else
::testing::internal::AssertHelper(::testing::TestPartResult::
kNonFatalFailure, "../../../src/lib/tcp/tests/mt_tcp_listener_mgr_unittests.cc"
, 839, gtest_ar.failure_message()) = ::testing::Message()
;
840 EXPECT_EQ(mt_listener_mgr_->getPort(), port)switch (0) case 0: default: if (const ::testing::AssertionResult
gtest_ar = (::testing::internal::EqHelper::Compare("mt_listener_mgr_->getPort()"
, "port", mt_listener_mgr_->getPort(), port))) ; else ::testing
::internal::AssertHelper(::testing::TestPartResult::kNonFatalFailure
, "../../../src/lib/tcp/tests/mt_tcp_listener_mgr_unittests.cc"
, 840, gtest_ar.failure_message()) = ::testing::Message()
;
841 EXPECT_EQ(mt_listener_mgr_->getThreadCount(), 4U)switch (0) case 0: default: if (const ::testing::AssertionResult
gtest_ar = (::testing::internal::EqHelper::Compare("mt_listener_mgr_->getThreadCount()"
, "4U", mt_listener_mgr_->getThreadCount(), 4U))) ; else ::
testing::internal::AssertHelper(::testing::TestPartResult::kNonFatalFailure
, "../../../src/lib/tcp/tests/mt_tcp_listener_mgr_unittests.cc"
, 841, gtest_ar.failure_message()) = ::testing::Message()
;
842 EXPECT_EQ(mt_listener_mgr_->getThreadPoolSize(), 4U)switch (0) case 0: default: if (const ::testing::AssertionResult
gtest_ar = (::testing::internal::EqHelper::Compare("mt_listener_mgr_->getThreadPoolSize()"
, "4U", mt_listener_mgr_->getThreadPoolSize(), 4U))) ; else
::testing::internal::AssertHelper(::testing::TestPartResult::
kNonFatalFailure, "../../../src/lib/tcp/tests/mt_tcp_listener_mgr_unittests.cc"
, 842, gtest_ar.failure_message()) = ::testing::Message()
;
843 ASSERT_TRUE(mt_listener_mgr_->isRunning())switch (0) case 0: default: if (const ::testing::AssertionResult
gtest_ar_ = ::testing::AssertionResult(mt_listener_mgr_->
isRunning())) ; else return ::testing::internal::AssertHelper
(::testing::TestPartResult::kFatalFailure, "../../../src/lib/tcp/tests/mt_tcp_listener_mgr_unittests.cc"
, 843, ::testing::internal::GetBoolAssertionFailureMessage( gtest_ar_
, "mt_listener_mgr_->isRunning()", "false", "true") .c_str
()) = ::testing::Message()
;
844 ASSERT_TRUE(mt_listener_mgr_->getThreadIOService())switch (0) case 0: default: if (const ::testing::AssertionResult
gtest_ar_ = ::testing::AssertionResult(mt_listener_mgr_->
getThreadIOService())) ; else return ::testing::internal::AssertHelper
(::testing::TestPartResult::kFatalFailure, "../../../src/lib/tcp/tests/mt_tcp_listener_mgr_unittests.cc"
, 844, ::testing::internal::GetBoolAssertionFailureMessage( gtest_ar_
, "mt_listener_mgr_->getThreadIOService()", "false", "true"
) .c_str()) = ::testing::Message()
;
845 EXPECT_FALSE(mt_listener_mgr_->getThreadIOService()->stopped())switch (0) case 0: default: if (const ::testing::AssertionResult
gtest_ar_ = ::testing::AssertionResult(!(mt_listener_mgr_->
getThreadIOService()->stopped()))) ; else ::testing::internal
::AssertHelper(::testing::TestPartResult::kNonFatalFailure, "../../../src/lib/tcp/tests/mt_tcp_listener_mgr_unittests.cc"
, 845, ::testing::internal::GetBoolAssertionFailureMessage( gtest_ar_
, "mt_listener_mgr_->getThreadIOService()->stopped()", "true"
, "false") .c_str()) = ::testing::Message()
;
846
847 // Verify we can pause it. We should still be listening, threads intact,
848 // IOService stopped, state set to PAUSED.
849 ASSERT_NO_THROW_LOG(mt_listener_mgr_->pause()){ try { mt_listener_mgr_->pause(); } catch (const std::exception
& ex) { return ::testing::internal::AssertHelper(::testing
::TestPartResult::kFatalFailure, "../../../src/lib/tcp/tests/mt_tcp_listener_mgr_unittests.cc"
, 849, "Failed") = ::testing::Message() << "mt_listener_mgr_->pause()"
<< " threw type: " << typeid(ex).name() <<
", what: " << ex.what(); } catch (...) { return ::testing
::internal::AssertHelper(::testing::TestPartResult::kFatalFailure
, "../../../src/lib/tcp/tests/mt_tcp_listener_mgr_unittests.cc"
, 849, "Failed") = ::testing::Message() << "mt_listener_mgr_->pause()"
<< " threw non-std::exception"; } }
;
850 ASSERT_TRUE(mt_listener_mgr_->isPaused())switch (0) case 0: default: if (const ::testing::AssertionResult
gtest_ar_ = ::testing::AssertionResult(mt_listener_mgr_->
isPaused())) ; else return ::testing::internal::AssertHelper(
::testing::TestPartResult::kFatalFailure, "../../../src/lib/tcp/tests/mt_tcp_listener_mgr_unittests.cc"
, 850, ::testing::internal::GetBoolAssertionFailureMessage( gtest_ar_
, "mt_listener_mgr_->isPaused()", "false", "true") .c_str(
)) = ::testing::Message()
;
851 EXPECT_EQ(mt_listener_mgr_->getThreadCount(), 4U)switch (0) case 0: default: if (const ::testing::AssertionResult
gtest_ar = (::testing::internal::EqHelper::Compare("mt_listener_mgr_->getThreadCount()"
, "4U", mt_listener_mgr_->getThreadCount(), 4U))) ; else ::
testing::internal::AssertHelper(::testing::TestPartResult::kNonFatalFailure
, "../../../src/lib/tcp/tests/mt_tcp_listener_mgr_unittests.cc"
, 851, gtest_ar.failure_message()) = ::testing::Message()
;
852 EXPECT_EQ(mt_listener_mgr_->getThreadPoolSize(), 4U)switch (0) case 0: default: if (const ::testing::AssertionResult
gtest_ar = (::testing::internal::EqHelper::Compare("mt_listener_mgr_->getThreadPoolSize()"
, "4U", mt_listener_mgr_->getThreadPoolSize(), 4U))) ; else
::testing::internal::AssertHelper(::testing::TestPartResult::
kNonFatalFailure, "../../../src/lib/tcp/tests/mt_tcp_listener_mgr_unittests.cc"
, 852, gtest_ar.failure_message()) = ::testing::Message()
;
853 ASSERT_TRUE(mt_listener_mgr_->getThreadIOService())switch (0) case 0: default: if (const ::testing::AssertionResult
gtest_ar_ = ::testing::AssertionResult(mt_listener_mgr_->
getThreadIOService())) ; else return ::testing::internal::AssertHelper
(::testing::TestPartResult::kFatalFailure, "../../../src/lib/tcp/tests/mt_tcp_listener_mgr_unittests.cc"
, 853, ::testing::internal::GetBoolAssertionFailureMessage( gtest_ar_
, "mt_listener_mgr_->getThreadIOService()", "false", "true"
) .c_str()) = ::testing::Message()
;
854 EXPECT_TRUE(mt_listener_mgr_->getThreadIOService()->stopped())switch (0) case 0: default: if (const ::testing::AssertionResult
gtest_ar_ = ::testing::AssertionResult(mt_listener_mgr_->
getThreadIOService()->stopped())) ; else ::testing::internal
::AssertHelper(::testing::TestPartResult::kNonFatalFailure, "../../../src/lib/tcp/tests/mt_tcp_listener_mgr_unittests.cc"
, 854, ::testing::internal::GetBoolAssertionFailureMessage( gtest_ar_
, "mt_listener_mgr_->getThreadIOService()->stopped()", "false"
, "true") .c_str()) = ::testing::Message()
;
855
856 // Verify we can resume it.
857 ASSERT_NO_THROW_LOG(mt_listener_mgr_->resume()){ try { mt_listener_mgr_->resume(); } catch (const std::exception
& ex) { return ::testing::internal::AssertHelper(::testing
::TestPartResult::kFatalFailure, "../../../src/lib/tcp/tests/mt_tcp_listener_mgr_unittests.cc"
, 857, "Failed") = ::testing::Message() << "mt_listener_mgr_->resume()"
<< " threw type: " << typeid(ex).name() <<
", what: " << ex.what(); } catch (...) { return ::testing
::internal::AssertHelper(::testing::TestPartResult::kFatalFailure
, "../../../src/lib/tcp/tests/mt_tcp_listener_mgr_unittests.cc"
, 857, "Failed") = ::testing::Message() << "mt_listener_mgr_->resume()"
<< " threw non-std::exception"; } }
;
858 ASSERT_TRUE(mt_listener_mgr_->isRunning())switch (0) case 0: default: if (const ::testing::AssertionResult
gtest_ar_ = ::testing::AssertionResult(mt_listener_mgr_->
isRunning())) ; else return ::testing::internal::AssertHelper
(::testing::TestPartResult::kFatalFailure, "../../../src/lib/tcp/tests/mt_tcp_listener_mgr_unittests.cc"
, 858, ::testing::internal::GetBoolAssertionFailureMessage( gtest_ar_
, "mt_listener_mgr_->isRunning()", "false", "true") .c_str
()) = ::testing::Message()
;
859 EXPECT_EQ(mt_listener_mgr_->getThreadCount(), 4U)switch (0) case 0: default: if (const ::testing::AssertionResult
gtest_ar = (::testing::internal::EqHelper::Compare("mt_listener_mgr_->getThreadCount()"
, "4U", mt_listener_mgr_->getThreadCount(), 4U))) ; else ::
testing::internal::AssertHelper(::testing::TestPartResult::kNonFatalFailure
, "../../../src/lib/tcp/tests/mt_tcp_listener_mgr_unittests.cc"
, 859, gtest_ar.failure_message()) = ::testing::Message()
;
860 EXPECT_EQ(mt_listener_mgr_->getThreadPoolSize(), 4U)switch (0) case 0: default: if (const ::testing::AssertionResult
gtest_ar = (::testing::internal::EqHelper::Compare("mt_listener_mgr_->getThreadPoolSize()"
, "4U", mt_listener_mgr_->getThreadPoolSize(), 4U))) ; else
::testing::internal::AssertHelper(::testing::TestPartResult::
kNonFatalFailure, "../../../src/lib/tcp/tests/mt_tcp_listener_mgr_unittests.cc"
, 860, gtest_ar.failure_message()) = ::testing::Message()
;
861 ASSERT_TRUE(mt_listener_mgr_->getThreadIOService())switch (0) case 0: default: if (const ::testing::AssertionResult
gtest_ar_ = ::testing::AssertionResult(mt_listener_mgr_->
getThreadIOService())) ; else return ::testing::internal::AssertHelper
(::testing::TestPartResult::kFatalFailure, "../../../src/lib/tcp/tests/mt_tcp_listener_mgr_unittests.cc"
, 861, ::testing::internal::GetBoolAssertionFailureMessage( gtest_ar_
, "mt_listener_mgr_->getThreadIOService()", "false", "true"
) .c_str()) = ::testing::Message()
;
862 EXPECT_FALSE(mt_listener_mgr_->getThreadIOService()->stopped())switch (0) case 0: default: if (const ::testing::AssertionResult
gtest_ar_ = ::testing::AssertionResult(!(mt_listener_mgr_->
getThreadIOService()->stopped()))) ; else ::testing::internal
::AssertHelper(::testing::TestPartResult::kNonFatalFailure, "../../../src/lib/tcp/tests/mt_tcp_listener_mgr_unittests.cc"
, 862, ::testing::internal::GetBoolAssertionFailureMessage( gtest_ar_
, "mt_listener_mgr_->getThreadIOService()->stopped()", "true"
, "false") .c_str()) = ::testing::Message()
;
863
864 // Stop it and verify we're no longer listening.
865 ASSERT_NO_THROW_LOG(mt_listener_mgr_->stop()){ try { mt_listener_mgr_->stop(); } catch (const std::exception
& ex) { return ::testing::internal::AssertHelper(::testing
::TestPartResult::kFatalFailure, "../../../src/lib/tcp/tests/mt_tcp_listener_mgr_unittests.cc"
, 865, "Failed") = ::testing::Message() << "mt_listener_mgr_->stop()"
<< " threw type: " << typeid(ex).name() <<
", what: " << ex.what(); } catch (...) { return ::testing
::internal::AssertHelper(::testing::TestPartResult::kFatalFailure
, "../../../src/lib/tcp/tests/mt_tcp_listener_mgr_unittests.cc"
, 865, "Failed") = ::testing::Message() << "mt_listener_mgr_->stop()"
<< " threw non-std::exception"; } }
;
866 ASSERT_TRUE(mt_listener_mgr_->isStopped())switch (0) case 0: default: if (const ::testing::AssertionResult
gtest_ar_ = ::testing::AssertionResult(mt_listener_mgr_->
isStopped())) ; else return ::testing::internal::AssertHelper
(::testing::TestPartResult::kFatalFailure, "../../../src/lib/tcp/tests/mt_tcp_listener_mgr_unittests.cc"
, 866, ::testing::internal::GetBoolAssertionFailureMessage( gtest_ar_
, "mt_listener_mgr_->isStopped()", "false", "true") .c_str
()) = ::testing::Message()
;
867 EXPECT_EQ(mt_listener_mgr_->getThreadCount(), 0U)switch (0) case 0: default: if (const ::testing::AssertionResult
gtest_ar = (::testing::internal::EqHelper::Compare("mt_listener_mgr_->getThreadCount()"
, "0U", mt_listener_mgr_->getThreadCount(), 0U))) ; else ::
testing::internal::AssertHelper(::testing::TestPartResult::kNonFatalFailure
, "../../../src/lib/tcp/tests/mt_tcp_listener_mgr_unittests.cc"
, 867, gtest_ar.failure_message()) = ::testing::Message()
;
868 EXPECT_EQ(mt_listener_mgr_->getThreadPoolSize(), 4U)switch (0) case 0: default: if (const ::testing::AssertionResult
gtest_ar = (::testing::internal::EqHelper::Compare("mt_listener_mgr_->getThreadPoolSize()"
, "4U", mt_listener_mgr_->getThreadPoolSize(), 4U))) ; else
::testing::internal::AssertHelper(::testing::TestPartResult::
kNonFatalFailure, "../../../src/lib/tcp/tests/mt_tcp_listener_mgr_unittests.cc"
, 868, gtest_ar.failure_message()) = ::testing::Message()
;
869 ASSERT_FALSE(mt_listener_mgr_->getThreadIOService())switch (0) case 0: default: if (const ::testing::AssertionResult
gtest_ar_ = ::testing::AssertionResult(!(mt_listener_mgr_->
getThreadIOService()))) ; else return ::testing::internal::AssertHelper
(::testing::TestPartResult::kFatalFailure, "../../../src/lib/tcp/tests/mt_tcp_listener_mgr_unittests.cc"
, 869, ::testing::internal::GetBoolAssertionFailureMessage( gtest_ar_
, "mt_listener_mgr_->getThreadIOService()", "true", "false"
) .c_str()) = ::testing::Message()
;
870 EXPECT_TRUE(mt_listener_mgr_->isStopped())switch (0) case 0: default: if (const ::testing::AssertionResult
gtest_ar_ = ::testing::AssertionResult(mt_listener_mgr_->
isStopped())) ; else ::testing::internal::AssertHelper(::testing
::TestPartResult::kNonFatalFailure, "../../../src/lib/tcp/tests/mt_tcp_listener_mgr_unittests.cc"
, 870, ::testing::internal::GetBoolAssertionFailureMessage( gtest_ar_
, "mt_listener_mgr_->isStopped()", "false", "true") .c_str
()) = ::testing::Message()
;
871}
872
873// Now we'll run some permutations of the number of listener threads
874// and the number of client requests.
875
876// One thread, one client.
877TEST_F(MtTcpListenerMgrTest, oneByOne)static_assert(sizeof("MtTcpListenerMgrTest") > 1, "test_suite_name must not be empty"
); static_assert(sizeof("oneByOne") > 1, "test_name must not be empty"
); class MtTcpListenerMgrTest_oneByOne_Test : public MtTcpListenerMgrTest
{ public: MtTcpListenerMgrTest_oneByOne_Test() = default; ~MtTcpListenerMgrTest_oneByOne_Test
() override = default; MtTcpListenerMgrTest_oneByOne_Test (const
MtTcpListenerMgrTest_oneByOne_Test &) = delete; MtTcpListenerMgrTest_oneByOne_Test
& operator=( const MtTcpListenerMgrTest_oneByOne_Test &
) = delete; MtTcpListenerMgrTest_oneByOne_Test (MtTcpListenerMgrTest_oneByOne_Test
&&) noexcept = delete; MtTcpListenerMgrTest_oneByOne_Test
& operator=( MtTcpListenerMgrTest_oneByOne_Test &&
) noexcept = delete; private: void TestBody() override; [[maybe_unused
]] static ::testing::TestInfo* const test_info_; }; ::testing
::TestInfo* const MtTcpListenerMgrTest_oneByOne_Test::test_info_
= ::testing::internal::MakeAndRegisterTestInfo( "MtTcpListenerMgrTest"
, "oneByOne", nullptr, nullptr, ::testing::internal::CodeLocation
("../../../src/lib/tcp/tests/mt_tcp_listener_mgr_unittests.cc"
, 877), (::testing::internal::GetTypeId<MtTcpListenerMgrTest
>()), ::testing::internal::SuiteApiResolver< MtTcpListenerMgrTest
>::GetSetUpCaseOrSuite("../../../src/lib/tcp/tests/mt_tcp_listener_mgr_unittests.cc"
, 877), ::testing::internal::SuiteApiResolver< MtTcpListenerMgrTest
>::GetTearDownCaseOrSuite("../../../src/lib/tcp/tests/mt_tcp_listener_mgr_unittests.cc"
, 877), new ::testing::internal::TestFactoryImpl<MtTcpListenerMgrTest_oneByOne_Test
>); void MtTcpListenerMgrTest_oneByOne_Test::TestBody()
{
878 size_t num_threads = 1;
879 size_t num_clients = 1;
880 threadListenAndRespond(num_threads, num_clients);
881}
882
883// One thread, four clients.
884TEST_F(MtTcpListenerMgrTest, oneByFour)static_assert(sizeof("MtTcpListenerMgrTest") > 1, "test_suite_name must not be empty"
); static_assert(sizeof("oneByFour") > 1, "test_name must not be empty"
); class MtTcpListenerMgrTest_oneByFour_Test : public MtTcpListenerMgrTest
{ public: MtTcpListenerMgrTest_oneByFour_Test() = default; ~
MtTcpListenerMgrTest_oneByFour_Test() override = default; MtTcpListenerMgrTest_oneByFour_Test
(const MtTcpListenerMgrTest_oneByFour_Test &) = delete; MtTcpListenerMgrTest_oneByFour_Test
& operator=( const MtTcpListenerMgrTest_oneByFour_Test &
) = delete; MtTcpListenerMgrTest_oneByFour_Test (MtTcpListenerMgrTest_oneByFour_Test
&&) noexcept = delete; MtTcpListenerMgrTest_oneByFour_Test
& operator=( MtTcpListenerMgrTest_oneByFour_Test &&
) noexcept = delete; private: void TestBody() override; [[maybe_unused
]] static ::testing::TestInfo* const test_info_; }; ::testing
::TestInfo* const MtTcpListenerMgrTest_oneByFour_Test::test_info_
= ::testing::internal::MakeAndRegisterTestInfo( "MtTcpListenerMgrTest"
, "oneByFour", nullptr, nullptr, ::testing::internal::CodeLocation
("../../../src/lib/tcp/tests/mt_tcp_listener_mgr_unittests.cc"
, 884), (::testing::internal::GetTypeId<MtTcpListenerMgrTest
>()), ::testing::internal::SuiteApiResolver< MtTcpListenerMgrTest
>::GetSetUpCaseOrSuite("../../../src/lib/tcp/tests/mt_tcp_listener_mgr_unittests.cc"
, 884), ::testing::internal::SuiteApiResolver< MtTcpListenerMgrTest
>::GetTearDownCaseOrSuite("../../../src/lib/tcp/tests/mt_tcp_listener_mgr_unittests.cc"
, 884), new ::testing::internal::TestFactoryImpl<MtTcpListenerMgrTest_oneByFour_Test
>); void MtTcpListenerMgrTest_oneByFour_Test::TestBody()
{
885 size_t num_threads = 1;
886 size_t num_clients = 4;
887 threadListenAndRespond(num_threads, num_clients);
888}
889
890// Four threads, one clients.
891TEST_F(MtTcpListenerMgrTest, fourByOne)static_assert(sizeof("MtTcpListenerMgrTest") > 1, "test_suite_name must not be empty"
); static_assert(sizeof("fourByOne") > 1, "test_name must not be empty"
); class MtTcpListenerMgrTest_fourByOne_Test : public MtTcpListenerMgrTest
{ public: MtTcpListenerMgrTest_fourByOne_Test() = default; ~
MtTcpListenerMgrTest_fourByOne_Test() override = default; MtTcpListenerMgrTest_fourByOne_Test
(const MtTcpListenerMgrTest_fourByOne_Test &) = delete; MtTcpListenerMgrTest_fourByOne_Test
& operator=( const MtTcpListenerMgrTest_fourByOne_Test &
) = delete; MtTcpListenerMgrTest_fourByOne_Test (MtTcpListenerMgrTest_fourByOne_Test
&&) noexcept = delete; MtTcpListenerMgrTest_fourByOne_Test
& operator=( MtTcpListenerMgrTest_fourByOne_Test &&
) noexcept = delete; private: void TestBody() override; [[maybe_unused
]] static ::testing::TestInfo* const test_info_; }; ::testing
::TestInfo* const MtTcpListenerMgrTest_fourByOne_Test::test_info_
= ::testing::internal::MakeAndRegisterTestInfo( "MtTcpListenerMgrTest"
, "fourByOne", nullptr, nullptr, ::testing::internal::CodeLocation
("../../../src/lib/tcp/tests/mt_tcp_listener_mgr_unittests.cc"
, 891), (::testing::internal::GetTypeId<MtTcpListenerMgrTest
>()), ::testing::internal::SuiteApiResolver< MtTcpListenerMgrTest
>::GetSetUpCaseOrSuite("../../../src/lib/tcp/tests/mt_tcp_listener_mgr_unittests.cc"
, 891), ::testing::internal::SuiteApiResolver< MtTcpListenerMgrTest
>::GetTearDownCaseOrSuite("../../../src/lib/tcp/tests/mt_tcp_listener_mgr_unittests.cc"
, 891), new ::testing::internal::TestFactoryImpl<MtTcpListenerMgrTest_fourByOne_Test
>); void MtTcpListenerMgrTest_fourByOne_Test::TestBody()
{
892 size_t num_threads = 4;
893 size_t num_clients = 1;
894 threadListenAndRespond(num_threads, num_clients);
895}
896
897// Four threads, four clients.
898TEST_F(MtTcpListenerMgrTest, fourByFour)static_assert(sizeof("MtTcpListenerMgrTest") > 1, "test_suite_name must not be empty"
); static_assert(sizeof("fourByFour") > 1, "test_name must not be empty"
); class MtTcpListenerMgrTest_fourByFour_Test : public MtTcpListenerMgrTest
{ public: MtTcpListenerMgrTest_fourByFour_Test() = default; ~
MtTcpListenerMgrTest_fourByFour_Test() override = default; MtTcpListenerMgrTest_fourByFour_Test
(const MtTcpListenerMgrTest_fourByFour_Test &) = delete;
MtTcpListenerMgrTest_fourByFour_Test & operator=( const MtTcpListenerMgrTest_fourByFour_Test
&) = delete; MtTcpListenerMgrTest_fourByFour_Test (MtTcpListenerMgrTest_fourByFour_Test
&&) noexcept = delete; MtTcpListenerMgrTest_fourByFour_Test
& operator=( MtTcpListenerMgrTest_fourByFour_Test &&
) noexcept = delete; private: void TestBody() override; [[maybe_unused
]] static ::testing::TestInfo* const test_info_; }; ::testing
::TestInfo* const MtTcpListenerMgrTest_fourByFour_Test::test_info_
= ::testing::internal::MakeAndRegisterTestInfo( "MtTcpListenerMgrTest"
, "fourByFour", nullptr, nullptr, ::testing::internal::CodeLocation
("../../../src/lib/tcp/tests/mt_tcp_listener_mgr_unittests.cc"
, 898), (::testing::internal::GetTypeId<MtTcpListenerMgrTest
>()), ::testing::internal::SuiteApiResolver< MtTcpListenerMgrTest
>::GetSetUpCaseOrSuite("../../../src/lib/tcp/tests/mt_tcp_listener_mgr_unittests.cc"
, 898), ::testing::internal::SuiteApiResolver< MtTcpListenerMgrTest
>::GetTearDownCaseOrSuite("../../../src/lib/tcp/tests/mt_tcp_listener_mgr_unittests.cc"
, 898), new ::testing::internal::TestFactoryImpl<MtTcpListenerMgrTest_fourByFour_Test
>); void MtTcpListenerMgrTest_fourByFour_Test::TestBody()
{
899 size_t num_threads = 4;
900 size_t num_clients = 4;
901 threadListenAndRespond(num_threads, num_clients);
902}
903
904// Four threads, eight clients.
905TEST_F(MtTcpListenerMgrTest, fourByEight)static_assert(sizeof("MtTcpListenerMgrTest") > 1, "test_suite_name must not be empty"
); static_assert(sizeof("fourByEight") > 1, "test_name must not be empty"
); class MtTcpListenerMgrTest_fourByEight_Test : public MtTcpListenerMgrTest
{ public: MtTcpListenerMgrTest_fourByEight_Test() = default;
~MtTcpListenerMgrTest_fourByEight_Test() override = default;
MtTcpListenerMgrTest_fourByEight_Test (const MtTcpListenerMgrTest_fourByEight_Test
&) = delete; MtTcpListenerMgrTest_fourByEight_Test &
operator=( const MtTcpListenerMgrTest_fourByEight_Test &
) = delete; MtTcpListenerMgrTest_fourByEight_Test (MtTcpListenerMgrTest_fourByEight_Test
&&) noexcept = delete; MtTcpListenerMgrTest_fourByEight_Test
& operator=( MtTcpListenerMgrTest_fourByEight_Test &&
) noexcept = delete; private: void TestBody() override; [[maybe_unused
]] static ::testing::TestInfo* const test_info_; }; ::testing
::TestInfo* const MtTcpListenerMgrTest_fourByEight_Test::test_info_
= ::testing::internal::MakeAndRegisterTestInfo( "MtTcpListenerMgrTest"
, "fourByEight", nullptr, nullptr, ::testing::internal::CodeLocation
("../../../src/lib/tcp/tests/mt_tcp_listener_mgr_unittests.cc"
, 905), (::testing::internal::GetTypeId<MtTcpListenerMgrTest
>()), ::testing::internal::SuiteApiResolver< MtTcpListenerMgrTest
>::GetSetUpCaseOrSuite("../../../src/lib/tcp/tests/mt_tcp_listener_mgr_unittests.cc"
, 905), ::testing::internal::SuiteApiResolver< MtTcpListenerMgrTest
>::GetTearDownCaseOrSuite("../../../src/lib/tcp/tests/mt_tcp_listener_mgr_unittests.cc"
, 905), new ::testing::internal::TestFactoryImpl<MtTcpListenerMgrTest_fourByEight_Test
>); void MtTcpListenerMgrTest_fourByEight_Test::TestBody()
{
906 size_t num_threads = 4;
907 size_t num_clients = 8;
908 threadListenAndRespond(num_threads, num_clients);
909}
910
911// Six threads, eighteen clients.
912TEST_F(MtTcpListenerMgrTest, sixByEighteen)static_assert(sizeof("MtTcpListenerMgrTest") > 1, "test_suite_name must not be empty"
); static_assert(sizeof("sixByEighteen") > 1, "test_name must not be empty"
); class MtTcpListenerMgrTest_sixByEighteen_Test : public MtTcpListenerMgrTest
{ public: MtTcpListenerMgrTest_sixByEighteen_Test() = default
; ~MtTcpListenerMgrTest_sixByEighteen_Test() override = default
; MtTcpListenerMgrTest_sixByEighteen_Test (const MtTcpListenerMgrTest_sixByEighteen_Test
&) = delete; MtTcpListenerMgrTest_sixByEighteen_Test &
operator=( const MtTcpListenerMgrTest_sixByEighteen_Test &
) = delete; MtTcpListenerMgrTest_sixByEighteen_Test (MtTcpListenerMgrTest_sixByEighteen_Test
&&) noexcept = delete; MtTcpListenerMgrTest_sixByEighteen_Test
& operator=( MtTcpListenerMgrTest_sixByEighteen_Test &&
) noexcept = delete; private: void TestBody() override; [[maybe_unused
]] static ::testing::TestInfo* const test_info_; }; ::testing
::TestInfo* const MtTcpListenerMgrTest_sixByEighteen_Test::test_info_
= ::testing::internal::MakeAndRegisterTestInfo( "MtTcpListenerMgrTest"
, "sixByEighteen", nullptr, nullptr, ::testing::internal::CodeLocation
("../../../src/lib/tcp/tests/mt_tcp_listener_mgr_unittests.cc"
, 912), (::testing::internal::GetTypeId<MtTcpListenerMgrTest
>()), ::testing::internal::SuiteApiResolver< MtTcpListenerMgrTest
>::GetSetUpCaseOrSuite("../../../src/lib/tcp/tests/mt_tcp_listener_mgr_unittests.cc"
, 912), ::testing::internal::SuiteApiResolver< MtTcpListenerMgrTest
>::GetTearDownCaseOrSuite("../../../src/lib/tcp/tests/mt_tcp_listener_mgr_unittests.cc"
, 912), new ::testing::internal::TestFactoryImpl<MtTcpListenerMgrTest_sixByEighteen_Test
>); void MtTcpListenerMgrTest_sixByEighteen_Test::TestBody
()
{
913 size_t num_threads = 6;
914 size_t num_clients = 18;
915 threadListenAndRespond(num_threads, num_clients);
916}
917
918// Pauses and resumes the listener while it is processing
919// requests.
920TEST_F(MtTcpListenerMgrTest, pauseAndResume)static_assert(sizeof("MtTcpListenerMgrTest") > 1, "test_suite_name must not be empty"
); static_assert(sizeof("pauseAndResume") > 1, "test_name must not be empty"
); class MtTcpListenerMgrTest_pauseAndResume_Test : public MtTcpListenerMgrTest
{ public: MtTcpListenerMgrTest_pauseAndResume_Test() = default
; ~MtTcpListenerMgrTest_pauseAndResume_Test() override = default
; MtTcpListenerMgrTest_pauseAndResume_Test (const MtTcpListenerMgrTest_pauseAndResume_Test
&) = delete; MtTcpListenerMgrTest_pauseAndResume_Test &
operator=( const MtTcpListenerMgrTest_pauseAndResume_Test &
) = delete; MtTcpListenerMgrTest_pauseAndResume_Test (MtTcpListenerMgrTest_pauseAndResume_Test
&&) noexcept = delete; MtTcpListenerMgrTest_pauseAndResume_Test
& operator=( MtTcpListenerMgrTest_pauseAndResume_Test &&
) noexcept = delete; private: void TestBody() override; [[maybe_unused
]] static ::testing::TestInfo* const test_info_; }; ::testing
::TestInfo* const MtTcpListenerMgrTest_pauseAndResume_Test::test_info_
= ::testing::internal::MakeAndRegisterTestInfo( "MtTcpListenerMgrTest"
, "pauseAndResume", nullptr, nullptr, ::testing::internal::CodeLocation
("../../../src/lib/tcp/tests/mt_tcp_listener_mgr_unittests.cc"
, 920), (::testing::internal::GetTypeId<MtTcpListenerMgrTest
>()), ::testing::internal::SuiteApiResolver< MtTcpListenerMgrTest
>::GetSetUpCaseOrSuite("../../../src/lib/tcp/tests/mt_tcp_listener_mgr_unittests.cc"
, 920), ::testing::internal::SuiteApiResolver< MtTcpListenerMgrTest
>::GetTearDownCaseOrSuite("../../../src/lib/tcp/tests/mt_tcp_listener_mgr_unittests.cc"
, 920), new ::testing::internal::TestFactoryImpl<MtTcpListenerMgrTest_pauseAndResume_Test
>); void MtTcpListenerMgrTest_pauseAndResume_Test::TestBody
()
{
921 size_t num_threads = 6;
922 size_t num_clients = 18;
923 size_t num_pauses = 3;
924 workPauseAndResume(num_threads, num_clients, num_pauses);
925}
926
927// Check if a TLS listener can be created.
928TEST_F(MtTcpListenerMgrTest, tls)static_assert(sizeof("MtTcpListenerMgrTest") > 1, "test_suite_name must not be empty"
); static_assert(sizeof("tls") > 1, "test_name must not be empty"
); class MtTcpListenerMgrTest_tls_Test : public MtTcpListenerMgrTest
{ public: MtTcpListenerMgrTest_tls_Test() = default; ~MtTcpListenerMgrTest_tls_Test
() override = default; MtTcpListenerMgrTest_tls_Test (const MtTcpListenerMgrTest_tls_Test
&) = delete; MtTcpListenerMgrTest_tls_Test & operator
=( const MtTcpListenerMgrTest_tls_Test &) = delete; MtTcpListenerMgrTest_tls_Test
(MtTcpListenerMgrTest_tls_Test &&) noexcept = delete
; MtTcpListenerMgrTest_tls_Test & operator=( MtTcpListenerMgrTest_tls_Test
&&) noexcept = delete; private: void TestBody() override
; [[maybe_unused]] static ::testing::TestInfo* const test_info_
; }; ::testing::TestInfo* const MtTcpListenerMgrTest_tls_Test
::test_info_ = ::testing::internal::MakeAndRegisterTestInfo( "MtTcpListenerMgrTest"
, "tls", nullptr, nullptr, ::testing::internal::CodeLocation(
"../../../src/lib/tcp/tests/mt_tcp_listener_mgr_unittests.cc"
, 928), (::testing::internal::GetTypeId<MtTcpListenerMgrTest
>()), ::testing::internal::SuiteApiResolver< MtTcpListenerMgrTest
>::GetSetUpCaseOrSuite("../../../src/lib/tcp/tests/mt_tcp_listener_mgr_unittests.cc"
, 928), ::testing::internal::SuiteApiResolver< MtTcpListenerMgrTest
>::GetTearDownCaseOrSuite("../../../src/lib/tcp/tests/mt_tcp_listener_mgr_unittests.cc"
, 928), new ::testing::internal::TestFactoryImpl<MtTcpListenerMgrTest_tls_Test
>); void MtTcpListenerMgrTest_tls_Test::TestBody()
{
929 IOAddress address(SERVER_ADDRESS);
930 uint16_t port = SERVER_PORT;
931 TlsContextPtr context;
932 configServer(context);
933
934 // Make sure we can create the listener.
935 ASSERT_NO_THROW_LOG({ try { mt_listener_mgr_.reset(new MtTcpListenerMgr( std::bind
(&MtTcpListenerMgrTest::listenerFactory, this, ph::_1, ph
::_2, ph::_3, ph::_4, ph::_5, ph::_6), IOAddress(SERVER_ADDRESS
), SERVER_PORT, 1, context)); } catch (const std::exception&
ex) { return ::testing::internal::AssertHelper(::testing::TestPartResult
::kFatalFailure, "../../../src/lib/tcp/tests/mt_tcp_listener_mgr_unittests.cc"
, 941, "Failed") = ::testing::Message() << "mt_listener_mgr_.reset(new MtTcpListenerMgr( std::bind(&MtTcpListenerMgrTest::listenerFactory, this, ph::_1, ph::_2, ph::_3, ph::_4, ph::_5, ph::_6), IOAddress(SERVER_ADDRESS), SERVER_PORT, 1, context))"
<< " threw type: " << typeid(ex).name() <<
", what: " << ex.what(); } catch (...) { return ::testing
::internal::AssertHelper(::testing::TestPartResult::kFatalFailure
, "../../../src/lib/tcp/tests/mt_tcp_listener_mgr_unittests.cc"
, 941, "Failed") = ::testing::Message() << "mt_listener_mgr_.reset(new MtTcpListenerMgr( std::bind(&MtTcpListenerMgrTest::listenerFactory, this, ph::_1, ph::_2, ph::_3, ph::_4, ph::_5, ph::_6), IOAddress(SERVER_ADDRESS), SERVER_PORT, 1, context))"
<< " threw non-std::exception"; } }
936 mt_listener_mgr_.reset(new MtTcpListenerMgr({ try { mt_listener_mgr_.reset(new MtTcpListenerMgr( std::bind
(&MtTcpListenerMgrTest::listenerFactory, this, ph::_1, ph
::_2, ph::_3, ph::_4, ph::_5, ph::_6), IOAddress(SERVER_ADDRESS
), SERVER_PORT, 1, context)); } catch (const std::exception&
ex) { return ::testing::internal::AssertHelper(::testing::TestPartResult
::kFatalFailure, "../../../src/lib/tcp/tests/mt_tcp_listener_mgr_unittests.cc"
, 941, "Failed") = ::testing::Message() << "mt_listener_mgr_.reset(new MtTcpListenerMgr( std::bind(&MtTcpListenerMgrTest::listenerFactory, this, ph::_1, ph::_2, ph::_3, ph::_4, ph::_5, ph::_6), IOAddress(SERVER_ADDRESS), SERVER_PORT, 1, context))"
<< " threw type: " << typeid(ex).name() <<
", what: " << ex.what(); } catch (...) { return ::testing
::internal::AssertHelper(::testing::TestPartResult::kFatalFailure
, "../../../src/lib/tcp/tests/mt_tcp_listener_mgr_unittests.cc"
, 941, "Failed") = ::testing::Message() << "mt_listener_mgr_.reset(new MtTcpListenerMgr( std::bind(&MtTcpListenerMgrTest::listenerFactory, this, ph::_1, ph::_2, ph::_3, ph::_4, ph::_5, ph::_6), IOAddress(SERVER_ADDRESS), SERVER_PORT, 1, context))"
<< " threw non-std::exception"; } }
937 std::bind(&MtTcpListenerMgrTest::listenerFactory,{ try { mt_listener_mgr_.reset(new MtTcpListenerMgr( std::bind
(&MtTcpListenerMgrTest::listenerFactory, this, ph::_1, ph
::_2, ph::_3, ph::_4, ph::_5, ph::_6), IOAddress(SERVER_ADDRESS
), SERVER_PORT, 1, context)); } catch (const std::exception&
ex) { return ::testing::internal::AssertHelper(::testing::TestPartResult
::kFatalFailure, "../../../src/lib/tcp/tests/mt_tcp_listener_mgr_unittests.cc"
, 941, "Failed") = ::testing::Message() << "mt_listener_mgr_.reset(new MtTcpListenerMgr( std::bind(&MtTcpListenerMgrTest::listenerFactory, this, ph::_1, ph::_2, ph::_3, ph::_4, ph::_5, ph::_6), IOAddress(SERVER_ADDRESS), SERVER_PORT, 1, context))"
<< " threw type: " << typeid(ex).name() <<
", what: " << ex.what(); } catch (...) { return ::testing
::internal::AssertHelper(::testing::TestPartResult::kFatalFailure
, "../../../src/lib/tcp/tests/mt_tcp_listener_mgr_unittests.cc"
, 941, "Failed") = ::testing::Message() << "mt_listener_mgr_.reset(new MtTcpListenerMgr( std::bind(&MtTcpListenerMgrTest::listenerFactory, this, ph::_1, ph::_2, ph::_3, ph::_4, ph::_5, ph::_6), IOAddress(SERVER_ADDRESS), SERVER_PORT, 1, context))"
<< " threw non-std::exception"; } }
938 this,{ try { mt_listener_mgr_.reset(new MtTcpListenerMgr( std::bind
(&MtTcpListenerMgrTest::listenerFactory, this, ph::_1, ph
::_2, ph::_3, ph::_4, ph::_5, ph::_6), IOAddress(SERVER_ADDRESS
), SERVER_PORT, 1, context)); } catch (const std::exception&
ex) { return ::testing::internal::AssertHelper(::testing::TestPartResult
::kFatalFailure, "../../../src/lib/tcp/tests/mt_tcp_listener_mgr_unittests.cc"
, 941, "Failed") = ::testing::Message() << "mt_listener_mgr_.reset(new MtTcpListenerMgr( std::bind(&MtTcpListenerMgrTest::listenerFactory, this, ph::_1, ph::_2, ph::_3, ph::_4, ph::_5, ph::_6), IOAddress(SERVER_ADDRESS), SERVER_PORT, 1, context))"
<< " threw type: " << typeid(ex).name() <<
", what: " << ex.what(); } catch (...) { return ::testing
::internal::AssertHelper(::testing::TestPartResult::kFatalFailure
, "../../../src/lib/tcp/tests/mt_tcp_listener_mgr_unittests.cc"
, 941, "Failed") = ::testing::Message() << "mt_listener_mgr_.reset(new MtTcpListenerMgr( std::bind(&MtTcpListenerMgrTest::listenerFactory, this, ph::_1, ph::_2, ph::_3, ph::_4, ph::_5, ph::_6), IOAddress(SERVER_ADDRESS), SERVER_PORT, 1, context))"
<< " threw non-std::exception"; } }
939 ph::_1, ph::_2, ph::_3, ph::_4, ph::_5, ph::_6),{ try { mt_listener_mgr_.reset(new MtTcpListenerMgr( std::bind
(&MtTcpListenerMgrTest::listenerFactory, this, ph::_1, ph
::_2, ph::_3, ph::_4, ph::_5, ph::_6), IOAddress(SERVER_ADDRESS
), SERVER_PORT, 1, context)); } catch (const std::exception&
ex) { return ::testing::internal::AssertHelper(::testing::TestPartResult
::kFatalFailure, "../../../src/lib/tcp/tests/mt_tcp_listener_mgr_unittests.cc"
, 941, "Failed") = ::testing::Message() << "mt_listener_mgr_.reset(new MtTcpListenerMgr( std::bind(&MtTcpListenerMgrTest::listenerFactory, this, ph::_1, ph::_2, ph::_3, ph::_4, ph::_5, ph::_6), IOAddress(SERVER_ADDRESS), SERVER_PORT, 1, context))"
<< " threw type: " << typeid(ex).name() <<
", what: " << ex.what(); } catch (...) { return ::testing
::internal::AssertHelper(::testing::TestPartResult::kFatalFailure
, "../../../src/lib/tcp/tests/mt_tcp_listener_mgr_unittests.cc"
, 941, "Failed") = ::testing::Message() << "mt_listener_mgr_.reset(new MtTcpListenerMgr( std::bind(&MtTcpListenerMgrTest::listenerFactory, this, ph::_1, ph::_2, ph::_3, ph::_4, ph::_5, ph::_6), IOAddress(SERVER_ADDRESS), SERVER_PORT, 1, context))"
<< " threw non-std::exception"; } }
940 IOAddress(SERVER_ADDRESS), SERVER_PORT, 1, context)){ try { mt_listener_mgr_.reset(new MtTcpListenerMgr( std::bind
(&MtTcpListenerMgrTest::listenerFactory, this, ph::_1, ph
::_2, ph::_3, ph::_4, ph::_5, ph::_6), IOAddress(SERVER_ADDRESS
), SERVER_PORT, 1, context)); } catch (const std::exception&
ex) { return ::testing::internal::AssertHelper(::testing::TestPartResult
::kFatalFailure, "../../../src/lib/tcp/tests/mt_tcp_listener_mgr_unittests.cc"
, 941, "Failed") = ::testing::Message() << "mt_listener_mgr_.reset(new MtTcpListenerMgr( std::bind(&MtTcpListenerMgrTest::listenerFactory, this, ph::_1, ph::_2, ph::_3, ph::_4, ph::_5, ph::_6), IOAddress(SERVER_ADDRESS), SERVER_PORT, 1, context))"
<< " threw type: " << typeid(ex).name() <<
", what: " << ex.what(); } catch (...) { return ::testing
::internal::AssertHelper(::testing::TestPartResult::kFatalFailure
, "../../../src/lib/tcp/tests/mt_tcp_listener_mgr_unittests.cc"
, 941, "Failed") = ::testing::Message() << "mt_listener_mgr_.reset(new MtTcpListenerMgr( std::bind(&MtTcpListenerMgrTest::listenerFactory, this, ph::_1, ph::_2, ph::_3, ph::_4, ph::_5, ph::_6), IOAddress(SERVER_ADDRESS), SERVER_PORT, 1, context))"
<< " threw non-std::exception"; } }
941 ){ try { mt_listener_mgr_.reset(new MtTcpListenerMgr( std::bind
(&MtTcpListenerMgrTest::listenerFactory, this, ph::_1, ph
::_2, ph::_3, ph::_4, ph::_5, ph::_6), IOAddress(SERVER_ADDRESS
), SERVER_PORT, 1, context)); } catch (const std::exception&
ex) { return ::testing::internal::AssertHelper(::testing::TestPartResult
::kFatalFailure, "../../../src/lib/tcp/tests/mt_tcp_listener_mgr_unittests.cc"
, 941, "Failed") = ::testing::Message() << "mt_listener_mgr_.reset(new MtTcpListenerMgr( std::bind(&MtTcpListenerMgrTest::listenerFactory, this, ph::_1, ph::_2, ph::_3, ph::_4, ph::_5, ph::_6), IOAddress(SERVER_ADDRESS), SERVER_PORT, 1, context))"
<< " threw type: " << typeid(ex).name() <<
", what: " << ex.what(); } catch (...) { return ::testing
::internal::AssertHelper(::testing::TestPartResult::kFatalFailure
, "../../../src/lib/tcp/tests/mt_tcp_listener_mgr_unittests.cc"
, 941, "Failed") = ::testing::Message() << "mt_listener_mgr_.reset(new MtTcpListenerMgr( std::bind(&MtTcpListenerMgrTest::listenerFactory, this, ph::_1, ph::_2, ph::_3, ph::_4, ph::_5, ph::_6), IOAddress(SERVER_ADDRESS), SERVER_PORT, 1, context))"
<< " threw non-std::exception"; } }
;
942
943 EXPECT_EQ(mt_listener_mgr_->getAddress(), address)switch (0) case 0: default: if (const ::testing::AssertionResult
gtest_ar = (::testing::internal::EqHelper::Compare("mt_listener_mgr_->getAddress()"
, "address", mt_listener_mgr_->getAddress(), address))) ; else
::testing::internal::AssertHelper(::testing::TestPartResult::
kNonFatalFailure, "../../../src/lib/tcp/tests/mt_tcp_listener_mgr_unittests.cc"
, 943, gtest_ar.failure_message()) = ::testing::Message()
;
944 EXPECT_EQ(mt_listener_mgr_->getPort(), port)switch (0) case 0: default: if (const ::testing::AssertionResult
gtest_ar = (::testing::internal::EqHelper::Compare("mt_listener_mgr_->getPort()"
, "port", mt_listener_mgr_->getPort(), port))) ; else ::testing
::internal::AssertHelper(::testing::TestPartResult::kNonFatalFailure
, "../../../src/lib/tcp/tests/mt_tcp_listener_mgr_unittests.cc"
, 944, gtest_ar.failure_message()) = ::testing::Message()
;
945 EXPECT_EQ(mt_listener_mgr_->getThreadPoolSize(), 1U)switch (0) case 0: default: if (const ::testing::AssertionResult
gtest_ar = (::testing::internal::EqHelper::Compare("mt_listener_mgr_->getThreadPoolSize()"
, "1U", mt_listener_mgr_->getThreadPoolSize(), 1U))) ; else
::testing::internal::AssertHelper(::testing::TestPartResult::
kNonFatalFailure, "../../../src/lib/tcp/tests/mt_tcp_listener_mgr_unittests.cc"
, 945, gtest_ar.failure_message()) = ::testing::Message()
;
946 EXPECT_EQ(mt_listener_mgr_->getTlsContext(), context)switch (0) case 0: default: if (const ::testing::AssertionResult
gtest_ar = (::testing::internal::EqHelper::Compare("mt_listener_mgr_->getTlsContext()"
, "context", mt_listener_mgr_->getTlsContext(), context)))
; else ::testing::internal::AssertHelper(::testing::TestPartResult
::kNonFatalFailure, "../../../src/lib/tcp/tests/mt_tcp_listener_mgr_unittests.cc"
, 946, gtest_ar.failure_message()) = ::testing::Message()
;
947 EXPECT_TRUE(mt_listener_mgr_->isStopped())switch (0) case 0: default: if (const ::testing::AssertionResult
gtest_ar_ = ::testing::AssertionResult(mt_listener_mgr_->
isStopped())) ; else ::testing::internal::AssertHelper(::testing
::TestPartResult::kNonFatalFailure, "../../../src/lib/tcp/tests/mt_tcp_listener_mgr_unittests.cc"
, 947, ::testing::internal::GetBoolAssertionFailureMessage( gtest_ar_
, "mt_listener_mgr_->isStopped()", "false", "true") .c_str
()) = ::testing::Message()
;
948 EXPECT_EQ(mt_listener_mgr_->getThreadCount(), 0U)switch (0) case 0: default: if (const ::testing::AssertionResult
gtest_ar = (::testing::internal::EqHelper::Compare("mt_listener_mgr_->getThreadCount()"
, "0U", mt_listener_mgr_->getThreadCount(), 0U))) ; else ::
testing::internal::AssertHelper(::testing::TestPartResult::kNonFatalFailure
, "../../../src/lib/tcp/tests/mt_tcp_listener_mgr_unittests.cc"
, 948, gtest_ar.failure_message()) = ::testing::Message()
;
949
950 // Make sure we can start it and it's listening with 1 thread.
951 ASSERT_NO_THROW_LOG(mt_listener_mgr_->start()){ try { mt_listener_mgr_->start(); } catch (const std::exception
& ex) { return ::testing::internal::AssertHelper(::testing
::TestPartResult::kFatalFailure, "../../../src/lib/tcp/tests/mt_tcp_listener_mgr_unittests.cc"
, 951, "Failed") = ::testing::Message() << "mt_listener_mgr_->start()"
<< " threw type: " << typeid(ex).name() <<
", what: " << ex.what(); } catch (...) { return ::testing
::internal::AssertHelper(::testing::TestPartResult::kFatalFailure
, "../../../src/lib/tcp/tests/mt_tcp_listener_mgr_unittests.cc"
, 951, "Failed") = ::testing::Message() << "mt_listener_mgr_->start()"
<< " threw non-std::exception"; } }
;
952 ASSERT_TRUE(mt_listener_mgr_->isRunning())switch (0) case 0: default: if (const ::testing::AssertionResult
gtest_ar_ = ::testing::AssertionResult(mt_listener_mgr_->
isRunning())) ; else return ::testing::internal::AssertHelper
(::testing::TestPartResult::kFatalFailure, "../../../src/lib/tcp/tests/mt_tcp_listener_mgr_unittests.cc"
, 952, ::testing::internal::GetBoolAssertionFailureMessage( gtest_ar_
, "mt_listener_mgr_->isRunning()", "false", "true") .c_str
()) = ::testing::Message()
;
953 EXPECT_EQ(mt_listener_mgr_->getThreadCount(), 1U)switch (0) case 0: default: if (const ::testing::AssertionResult
gtest_ar = (::testing::internal::EqHelper::Compare("mt_listener_mgr_->getThreadCount()"
, "1U", mt_listener_mgr_->getThreadCount(), 1U))) ; else ::
testing::internal::AssertHelper(::testing::TestPartResult::kNonFatalFailure
, "../../../src/lib/tcp/tests/mt_tcp_listener_mgr_unittests.cc"
, 953, gtest_ar.failure_message()) = ::testing::Message()
;
954 ASSERT_TRUE(mt_listener_mgr_->getThreadIOService())switch (0) case 0: default: if (const ::testing::AssertionResult
gtest_ar_ = ::testing::AssertionResult(mt_listener_mgr_->
getThreadIOService())) ; else return ::testing::internal::AssertHelper
(::testing::TestPartResult::kFatalFailure, "../../../src/lib/tcp/tests/mt_tcp_listener_mgr_unittests.cc"
, 954, ::testing::internal::GetBoolAssertionFailureMessage( gtest_ar_
, "mt_listener_mgr_->getThreadIOService()", "false", "true"
) .c_str()) = ::testing::Message()
;
955 EXPECT_FALSE(mt_listener_mgr_->getThreadIOService()->stopped())switch (0) case 0: default: if (const ::testing::AssertionResult
gtest_ar_ = ::testing::AssertionResult(!(mt_listener_mgr_->
getThreadIOService()->stopped()))) ; else ::testing::internal
::AssertHelper(::testing::TestPartResult::kNonFatalFailure, "../../../src/lib/tcp/tests/mt_tcp_listener_mgr_unittests.cc"
, 955, ::testing::internal::GetBoolAssertionFailureMessage( gtest_ar_
, "mt_listener_mgr_->getThreadIOService()->stopped()", "true"
, "false") .c_str()) = ::testing::Message()
;
956
957 // Stop it.
958 ASSERT_NO_THROW_LOG(mt_listener_mgr_->stop()){ try { mt_listener_mgr_->stop(); } catch (const std::exception
& ex) { return ::testing::internal::AssertHelper(::testing
::TestPartResult::kFatalFailure, "../../../src/lib/tcp/tests/mt_tcp_listener_mgr_unittests.cc"
, 958, "Failed") = ::testing::Message() << "mt_listener_mgr_->stop()"
<< " threw type: " << typeid(ex).name() <<
", what: " << ex.what(); } catch (...) { return ::testing
::internal::AssertHelper(::testing::TestPartResult::kFatalFailure
, "../../../src/lib/tcp/tests/mt_tcp_listener_mgr_unittests.cc"
, 958, "Failed") = ::testing::Message() << "mt_listener_mgr_->stop()"
<< " threw non-std::exception"; } }
;
959 ASSERT_TRUE(mt_listener_mgr_->isStopped())switch (0) case 0: default: if (const ::testing::AssertionResult
gtest_ar_ = ::testing::AssertionResult(mt_listener_mgr_->
isStopped())) ; else return ::testing::internal::AssertHelper
(::testing::TestPartResult::kFatalFailure, "../../../src/lib/tcp/tests/mt_tcp_listener_mgr_unittests.cc"
, 959, ::testing::internal::GetBoolAssertionFailureMessage( gtest_ar_
, "mt_listener_mgr_->isStopped()", "false", "true") .c_str
()) = ::testing::Message()
;
960 EXPECT_EQ(mt_listener_mgr_->getThreadCount(), 0U)switch (0) case 0: default: if (const ::testing::AssertionResult
gtest_ar = (::testing::internal::EqHelper::Compare("mt_listener_mgr_->getThreadCount()"
, "0U", mt_listener_mgr_->getThreadCount(), 0U))) ; else ::
testing::internal::AssertHelper(::testing::TestPartResult::kNonFatalFailure
, "../../../src/lib/tcp/tests/mt_tcp_listener_mgr_unittests.cc"
, 960, gtest_ar.failure_message()) = ::testing::Message()
;
961 EXPECT_EQ(mt_listener_mgr_->getThreadPoolSize(), 1U)switch (0) case 0: default: if (const ::testing::AssertionResult
gtest_ar = (::testing::internal::EqHelper::Compare("mt_listener_mgr_->getThreadPoolSize()"
, "1U", mt_listener_mgr_->getThreadPoolSize(), 1U))) ; else
::testing::internal::AssertHelper(::testing::TestPartResult::
kNonFatalFailure, "../../../src/lib/tcp/tests/mt_tcp_listener_mgr_unittests.cc"
, 961, gtest_ar.failure_message()) = ::testing::Message()
;
962 ASSERT_FALSE(mt_listener_mgr_->getThreadIOService())switch (0) case 0: default: if (const ::testing::AssertionResult
gtest_ar_ = ::testing::AssertionResult(!(mt_listener_mgr_->
getThreadIOService()))) ; else return ::testing::internal::AssertHelper
(::testing::TestPartResult::kFatalFailure, "../../../src/lib/tcp/tests/mt_tcp_listener_mgr_unittests.cc"
, 962, ::testing::internal::GetBoolAssertionFailureMessage( gtest_ar_
, "mt_listener_mgr_->getThreadIOService()", "true", "false"
) .c_str()) = ::testing::Message()
;
963 EXPECT_TRUE(mt_listener_mgr_->isStopped())switch (0) case 0: default: if (const ::testing::AssertionResult
gtest_ar_ = ::testing::AssertionResult(mt_listener_mgr_->
isStopped())) ; else ::testing::internal::AssertHelper(::testing
::TestPartResult::kNonFatalFailure, "../../../src/lib/tcp/tests/mt_tcp_listener_mgr_unittests.cc"
, 963, ::testing::internal::GetBoolAssertionFailureMessage( gtest_ar_
, "mt_listener_mgr_->isStopped()", "false", "true") .c_str
()) = ::testing::Message()
;
964}
965
966/// Verifies that idle timeout can be passed down to the internal listener.
967TEST_F(MtTcpListenerMgrTest, idleTimeout)static_assert(sizeof("MtTcpListenerMgrTest") > 1, "test_suite_name must not be empty"
); static_assert(sizeof("idleTimeout") > 1, "test_name must not be empty"
); class MtTcpListenerMgrTest_idleTimeout_Test : public MtTcpListenerMgrTest
{ public: MtTcpListenerMgrTest_idleTimeout_Test() = default;
~MtTcpListenerMgrTest_idleTimeout_Test() override = default;
MtTcpListenerMgrTest_idleTimeout_Test (const MtTcpListenerMgrTest_idleTimeout_Test
&) = delete; MtTcpListenerMgrTest_idleTimeout_Test &
operator=( const MtTcpListenerMgrTest_idleTimeout_Test &
) = delete; MtTcpListenerMgrTest_idleTimeout_Test (MtTcpListenerMgrTest_idleTimeout_Test
&&) noexcept = delete; MtTcpListenerMgrTest_idleTimeout_Test
& operator=( MtTcpListenerMgrTest_idleTimeout_Test &&
) noexcept = delete; private: void TestBody() override; [[maybe_unused
]] static ::testing::TestInfo* const test_info_; }; ::testing
::TestInfo* const MtTcpListenerMgrTest_idleTimeout_Test::test_info_
= ::testing::internal::MakeAndRegisterTestInfo( "MtTcpListenerMgrTest"
, "idleTimeout", nullptr, nullptr, ::testing::internal::CodeLocation
("../../../src/lib/tcp/tests/mt_tcp_listener_mgr_unittests.cc"
, 967), (::testing::internal::GetTypeId<MtTcpListenerMgrTest
>()), ::testing::internal::SuiteApiResolver< MtTcpListenerMgrTest
>::GetSetUpCaseOrSuite("../../../src/lib/tcp/tests/mt_tcp_listener_mgr_unittests.cc"
, 967), ::testing::internal::SuiteApiResolver< MtTcpListenerMgrTest
>::GetTearDownCaseOrSuite("../../../src/lib/tcp/tests/mt_tcp_listener_mgr_unittests.cc"
, 967), new ::testing::internal::TestFactoryImpl<MtTcpListenerMgrTest_idleTimeout_Test
>); void MtTcpListenerMgrTest_idleTimeout_Test::TestBody()
{
968 // Create an MtTcpListenerMgr.
969 createMtTcpListenerMgr(1, std::bind(&MtTcpListenerMgrTest::synchronizedCommandHandler,
970 this, ph::_1));
971 // Verify the default timeout value.
972 EXPECT_EQ(TCP_IDLE_CONNECTION_TIMEOUT, mt_listener_mgr_->getIdleTimeout())switch (0) case 0: default: if (const ::testing::AssertionResult
gtest_ar = (::testing::internal::EqHelper::Compare("TCP_IDLE_CONNECTION_TIMEOUT"
, "mt_listener_mgr_->getIdleTimeout()", TCP_IDLE_CONNECTION_TIMEOUT
, mt_listener_mgr_->getIdleTimeout()))) ; else ::testing::
internal::AssertHelper(::testing::TestPartResult::kNonFatalFailure
, "../../../src/lib/tcp/tests/mt_tcp_listener_mgr_unittests.cc"
, 972, gtest_ar.failure_message()) = ::testing::Message()
;
973
974 // Set a new timeout value.
975 mt_listener_mgr_->setIdleTimeout(200);
976 EXPECT_EQ(200, mt_listener_mgr_->getIdleTimeout())switch (0) case 0: default: if (const ::testing::AssertionResult
gtest_ar = (::testing::internal::EqHelper::Compare("200", "mt_listener_mgr_->getIdleTimeout()"
, 200, mt_listener_mgr_->getIdleTimeout()))) ; else ::testing
::internal::AssertHelper(::testing::TestPartResult::kNonFatalFailure
, "../../../src/lib/tcp/tests/mt_tcp_listener_mgr_unittests.cc"
, 976, gtest_ar.failure_message()) = ::testing::Message()
;
977
978 // Start the listener, which should instantiate the internal listener.
979 ASSERT_NO_THROW_LOG(mt_listener_mgr_->start()){ try { mt_listener_mgr_->start(); } catch (const std::exception
& ex) { return ::testing::internal::AssertHelper(::testing
::TestPartResult::kFatalFailure, "../../../src/lib/tcp/tests/mt_tcp_listener_mgr_unittests.cc"
, 979, "Failed") = ::testing::Message() << "mt_listener_mgr_->start()"
<< " threw type: " << typeid(ex).name() <<
", what: " << ex.what(); } catch (...) { return ::testing
::internal::AssertHelper(::testing::TestPartResult::kFatalFailure
, "../../../src/lib/tcp/tests/mt_tcp_listener_mgr_unittests.cc"
, 979, "Failed") = ::testing::Message() << "mt_listener_mgr_->start()"
<< " threw non-std::exception"; } }
;
980 ASSERT_TRUE(mt_listener_mgr_->isRunning())switch (0) case 0: default: if (const ::testing::AssertionResult
gtest_ar_ = ::testing::AssertionResult(mt_listener_mgr_->
isRunning())) ; else return ::testing::internal::AssertHelper
(::testing::TestPartResult::kFatalFailure, "../../../src/lib/tcp/tests/mt_tcp_listener_mgr_unittests.cc"
, 980, ::testing::internal::GetBoolAssertionFailureMessage( gtest_ar_
, "mt_listener_mgr_->isRunning()", "false", "true") .c_str
()) = ::testing::Message()
;
981
982 // Verify the internal listener's timeout value.
983 auto tcp_listener = mt_listener_mgr_->getTcpListener();
984 ASSERT_TRUE(tcp_listener)switch (0) case 0: default: if (const ::testing::AssertionResult
gtest_ar_ = ::testing::AssertionResult(tcp_listener)) ; else
return ::testing::internal::AssertHelper(::testing::TestPartResult
::kFatalFailure, "../../../src/lib/tcp/tests/mt_tcp_listener_mgr_unittests.cc"
, 984, ::testing::internal::GetBoolAssertionFailureMessage( gtest_ar_
, "tcp_listener", "false", "true") .c_str()) = ::testing::Message
()
;
985 EXPECT_EQ(200, tcp_listener->getIdleTimeout())switch (0) case 0: default: if (const ::testing::AssertionResult
gtest_ar = (::testing::internal::EqHelper::Compare("200", "tcp_listener->getIdleTimeout()"
, 200, tcp_listener->getIdleTimeout()))) ; else ::testing::
internal::AssertHelper(::testing::TestPartResult::kNonFatalFailure
, "../../../src/lib/tcp/tests/mt_tcp_listener_mgr_unittests.cc"
, 985, gtest_ar.failure_message()) = ::testing::Message()
;
986}
987
988} // end of anonymous namespace

../../../src/lib/tcp/tests/tcp_test_client.h

1// Copyright (C) 2022-2025 Internet Systems Consortium, Inc. ("ISC")
2//
3// This Source Code Form is subject to the terms of the Mozilla Public
4// License, v. 2.0. If a copy of the MPL was not distributed with this
5// file, You can obtain one at http://mozilla.org/MPL/2.0/.
6
7#ifndef TCP_TEST_CLIENT_H
8#define TCP_TEST_CLIENT_H
9
10#include <cc/data.h>
11#include <asiolink/tcp_socket.h>
12#include <asiolink/tls_socket.h>
13#include <asiolink/testutils/test_tls.h>
14#include <tcp/tcp_connection.h>
15#include <tcp/tcp_stream_msg.h>
16#include <boost/asio/read.hpp>
17#include <boost/asio/buffer.hpp>
18#include <boost/asio/ip/tcp.hpp>
19#include <gtest/gtest.h>
20
21/// @brief Entity which can connect to the TCP server endpoint with or
22/// or without TLS.
23class TcpTestClient : public boost::noncopyable {
24
25private:
26 /// @brief Type of the function implementing a callback invoked by the
27 /// @c SocketCallback functor.
28 typedef std::function<void(boost::system::error_code ec, size_t length)>
29 SocketCallbackFunction;
30
31 /// @brief Functor associated with the socket object.
32 ///
33 /// This functor calls a callback function specified in the constructor.
34 class SocketCallback {
35 public:
36
37 /// @brief Constructor.
38 ///
39 /// @param socket_callback Callback to be invoked by the functor upon
40 /// an event associated with the socket.
41 SocketCallback(SocketCallbackFunction socket_callback)
42 : callback_(socket_callback) {
43 }
44
45 /// @brief Operator called when event associated with a socket occurs.
46 ///
47 /// This operator returns immediately when received error code is
48 /// @c boost::system::error_code is equal to
49 /// @c boost::asio::error::operation_aborted, i.e. the callback is not
50 /// invoked.
51 ///
52 /// @param ec Error code.
53 /// @param length Data length.
54 void operator()(boost::system::error_code ec, size_t length = 0) {
55 if (ec.value() == boost::asio::error::operation_aborted) {
56 return;
57 }
58
59 callback_(ec, length);
60 }
61
62 private:
63 /// @brief Supplied callback.
64 SocketCallbackFunction callback_;
65 };
66
67public:
68
69 /// @brief Constructor.
70 ///
71 /// This constructor creates new socket instance. It doesn't connect. Call
72 /// start() to connect to the server.
73 ///
74 /// @param io_service IO service to be stopped on error or completion.
75 /// @param done_callback Function cient should invoke when it has finished
76 /// all its requests or failed.
77 /// @param tls_context
78 /// @param server_address string containing the IP address of the server.
79 /// @param port port number of the server.
80 explicit TcpTestClient(const isc::asiolink::IOServicePtr& io_service,
81 std::function<void()> done_callback,
82 isc::asiolink::TlsContextPtr tls_context =
83 isc::asiolink::TlsContextPtr(),
84 const std::string& server_address = "127.0.0.1",
85 uint16_t port = 18123)
86 : io_service_(io_service),
87 tls_context_(tls_context),
88 tcp_socket_(), tls_socket_(),
89 done_callback_(done_callback),
90 server_address_(server_address), server_port_(port),
91 buf_(), response_(),
92 receive_done_(false), expected_eof_(false), handshake_failed_(false) {
93 if (!tls_context_) {
22
Taking true branch
94 tcp_socket_.reset(new isc::asiolink::TCPSocket<SocketCallback>(io_service));
23
Calling constructor for 'TCPSocket<TcpTestClient::SocketCallback>'
75
Returning from constructor for 'TCPSocket<TcpTestClient::SocketCallback>'
95 } else {
96 tls_socket_.reset(new isc::asiolink::TLSSocket<SocketCallback>(io_service,
97 tls_context));
98 }
99 }
100
101 bool useTls() {
102 return (!!tls_context_);
103 }
104
105 /// @brief Destructor.
106 ///
107 /// Closes the underlying socket if it is open.
108 virtual ~TcpTestClient() {
109 close();
110 }
111
112 /// @brief Connect to the listener and initiate request processing.
113 ///
114 /// Upon successful connection, carry out the TLS handshake. If the handshake
115 /// completes successful start sending requests.
116 void start() {
117 isc::asiolink::TCPEndpoint endpoint(boost::asio::ip::make_address(server_address_), server_port_);
118 SocketCallback socket_cb(
119 [this](boost::system::error_code ec, size_t /*length */) {
120 receive_done_ = false;
121 expected_eof_ = false;
122 handshake_failed_ = false;
123 if (ec) {
124 // One would expect that open wouldn't return
125 // EINPROGRESS error code, but simply wait for the connection
126 // to get established before the handler is invoked. It turns out,
127 // however, that on some OSes the connect handler may receive this
128 // error code which doesn't necessarily indicate a problem.
129 // Making an attempt to write and read from this socket will
130 // typically succeed. So, we ignore this error.
131 if (ec.value() != boost::asio::error::in_progress) {
132 ADD_FAILURE()::testing::internal::AssertHelper(::testing::TestPartResult::
kNonFatalFailure, "../../../src/lib/tcp/tests/tcp_test_client.h"
, 132, "Failed") = ::testing::Message()
<< "error occurred while connecting: "
133 << ec.message();
134 done_callback_();
135 }
136 }
137
138 if (useTls()) {
139 SocketCallback tls_socket_cb(
140 [this](boost::system::error_code erc, size_t /*length */) {
141 if (erc) {
142 handshake_failed_ = true;
143 done_callback_();
144 } else {
145 sendNextRequest();
146 }
147 });
148
149 tls_socket_->handshake(tls_socket_cb);
150 } else {
151 sendNextRequest();
152 }
153 });
154
155 if (useTls()) {
79
Taking false branch
156 tls_socket_->open(&endpoint, socket_cb);
157 } else {
158 tcp_socket_->open(&endpoint, socket_cb);
80
Calling 'TCPSocket::open'
159 }
160 }
161
162 /// @brief Send request specified in textual format.
163 ///
164 /// @param request request in the textual format.
165 void startRequest(const std::string& request) {
166 requests_to_send_.push_back(request);
167 start();
78
Calling 'TcpTestClient::start'
168 }
169
170 /// @brief Send request specified in textual format.
171 ///
172 /// @param request request in the textual format.
173 void startRequests(const std::list<std::string>& requests) {
174 requests_to_send_ = requests;
175 start();
176 }
177
178 /// @brief Sends the next request from the list of requests to send.
179 void sendNextRequest() {
180 // If there are any requests left to send, send them.
181 if (!requests_to_send_.empty()) {
182 std::string request = requests_to_send_.front();
183 requests_to_send_.pop_front();
184 if (request.empty()) {
185 waitForEof();
186 } else {
187 sendRequest(request);
188 }
189 }
190 }
191
192 /// @brief Send a stream request.
193 ///
194 /// @param request request data to send textual format.
195 /// @param send_length number of bytes to send. If not zero, can be used
196 /// to truncate the amount of data sent.
197 void sendRequest(const std::string& request, const size_t send_length = 0) {
198 // Prepend the length of the request.
199 uint16_t size = static_cast<uint16_t>(request.size());
200 isc::tcp::WireData wire_request;
201 if (!request.empty()) {
202 wire_request.push_back(static_cast<uint8_t>((size & 0xff00U) >> 8));
203 wire_request.push_back(static_cast<uint8_t>(size & 0x00ffU));
204 wire_request.insert(wire_request.end(), request.begin(), request.end());
205 }
206
207 sendPartialRequest(wire_request, send_length);
208 }
209
210 /// @brief Wait for a server to close the connection.
211 void waitForEof() {
212 stream_response_.reset(new isc::tcp::TcpStreamRequest());
213 receivePartialResponse(true);
214 }
215
216 /// @brief Send part of the request.
217 ///
218 /// @param request part of the request to be sent.
219 /// @param send_length number of bytes to send. If not zero, can be used
220 /// to truncate the amount of data sent.
221 void sendPartialRequest(isc::tcp::WireData& wire_request, size_t send_length = 0) {
222 if (!send_length) {
223 send_length = wire_request.size();
224 } else {
225 ASSERT_LE(send_length, wire_request.size())switch (0) case 0: default: if (const ::testing::AssertionResult
gtest_ar = (::testing::internal::CmpHelperLE("send_length", "wire_request.size()"
, send_length, wire_request.size()))) ; else return ::testing
::internal::AssertHelper(::testing::TestPartResult::kFatalFailure
, "../../../src/lib/tcp/tests/tcp_test_client.h", 225, gtest_ar
.failure_message()) = ::testing::Message()
226 << "broken test, send_length exceeds wire size";
227 }
228
229 SocketCallback socket_cb(
230 [this, wire_request](boost::system::error_code ec, size_t bytes_transferred) mutable {
231 if (ec) {
232 if (ec.value() == boost::asio::error::operation_aborted) {
233 return;
234
235 } else if ((ec.value() == boost::asio::error::try_again) ||
236 (ec.value() == boost::asio::error::would_block)) {
237 // If we should try again make sure there is no garbage in the
238 // bytes_transferred.
239 bytes_transferred = 0;
240 } else {
241 ADD_FAILURE()::testing::internal::AssertHelper(::testing::TestPartResult::
kNonFatalFailure, "../../../src/lib/tcp/tests/tcp_test_client.h"
, 241, "Failed") = ::testing::Message()
<< "error occurred while connecting: "
242 << ec.message();
243 done_callback_();
244 return;
245 }
246 }
247
248 // Remove the part of the request which has been sent.
249 if (bytes_transferred > 0 && (wire_request.size() <= bytes_transferred)) {
250 wire_request.erase(wire_request.begin(),
251 (wire_request.begin() + bytes_transferred));
252 }
253
254 // Continue sending request data if there are still some data to be
255 // sent.
256 if (!wire_request.empty()) {
257 sendPartialRequest(wire_request);
258 } else {
259 // Request has been sent. Start receiving response.
260 receivePartialResponse();
261 }
262 });
263
264 if (useTls()) {
265 tls_socket_->asyncSend(static_cast<const void *>(wire_request.data()),
266 send_length, socket_cb);
267 } else {
268 tcp_socket_->asyncSend(static_cast<const void *>(wire_request.data()),
269 send_length, socket_cb);
270 }
271 }
272
273 /// @brief Receive response from the server.
274 void receivePartialResponse(bool expect_eof = false) {
275 SocketCallback socket_cb(
276 [this, expect_eof](const boost::system::error_code& ec,
277 std::size_t bytes_transferred) {
278 if (!stream_response_) {
279 stream_response_.reset(new isc::tcp::TcpStreamRequest());
280 }
281
282 if (ec) {
283 // IO service stopped so simply return.
284 if (ec.value() == boost::asio::error::operation_aborted) {
285 return;
286 } else if ((ec.value() == boost::asio::error::try_again) ||
287 (ec.value() == boost::asio::error::would_block)) {
288 // If we should try again, make sure that there is no garbage
289 // in the bytes_transferred.
290 bytes_transferred = 0;
291 } else if (expect_eof) {
292 expected_eof_ = true;
293 done_callback_();
294 return;
295 } else {
296 // Error occurred, bail...
297 ADD_FAILURE()::testing::internal::AssertHelper(::testing::TestPartResult::
kNonFatalFailure, "../../../src/lib/tcp/tests/tcp_test_client.h"
, 297, "Failed") = ::testing::Message()
<< "client: " << this
298 << " error occurred while receiving TCP"
299 << " response from the server: " << ec.message();
300 done_callback_();
301 return;
302 }
303 }
304
305 // Post received data to the current response.
306 if (bytes_transferred > 0) {
307 stream_response_->postBuffer(buf_.data(), bytes_transferred);
308 }
309
310 if (stream_response_->needData()) {
311 // Response is incomplete, keep reading.
312 receivePartialResponse();
313 } else {
314 // Response is complete, process it.
315 responseReceived();
316 }
317 });
318
319 isc::asiolink::TCPEndpoint from;
320 if (useTls()) {
321 tls_socket_->asyncReceive(static_cast<void*>(buf_.data()), buf_.size(), 0,
322 &from, socket_cb);
323 } else {
324 tcp_socket_->asyncReceive(static_cast<void*>(buf_.data()), buf_.size(), 0,
325 &from, socket_cb);
326 }
327 }
328
329 /// @brief Process a completed response received from the server.
330 virtual void responseReceived() {
331 /// Unpack wire data into a string.
332 ASSERT_NO_THROW(stream_response_->unpack())switch (0) case 0: default: if (::testing::internal::TrueWithString
gtest_msg{}) { try { if (::testing::internal::AlwaysTrue()) {
stream_response_->unpack(); } else static_assert(true, ""
); } catch (std::exception const& e) { gtest_msg.value = "it throws "
; gtest_msg.value += ::testing::internal::GetTypeName(typeid(
e)); gtest_msg.value += " with description \""; gtest_msg.value
+= e.what(); gtest_msg.value += "\"."; goto gtest_label_testnothrow_332
; } catch (...) { gtest_msg.value = "it throws."; goto gtest_label_testnothrow_332
; } } else gtest_label_testnothrow_332 : return ::testing::internal
::AssertHelper(::testing::TestPartResult::kFatalFailure, "../../../src/lib/tcp/tests/tcp_test_client.h"
, 332, ("Expected: " "stream_response_->unpack()" " doesn't throw an exception.\n"
" Actual: " + gtest_msg.value) .c_str()) = ::testing::Message
()
;
333 std::string response = stream_response_->getRequestString();
334 responses_received_.push_back(response);
335
336 // Quit if server tells us "good bye".
337 if (response.find("good bye", 0) != std::string::npos) {
338 receive_done_ = true;
339 done_callback_();
340 return;
341 }
342
343 // Clear out for the next one.
344 stream_response_.reset();
345 sendNextRequest();
346 }
347
348 /// @brief Close connection.
349 void close() {
350 if (useTls()) {
351 tls_socket_->close();
352 } else {
353 tcp_socket_->close();
354 }
355 }
356
357 /// @brief Returns true if the receive completed without error.
358 ///
359 /// @return True if the receive completed successfully, false
360 /// otherwise.
361 bool receiveDone() {
362 return (receive_done_);
363 }
364
365 /// @brief Returns true if the receive ended with expected EOF
366 ///
367 /// @return True if the receive ended with EOF, false otherwise
368 bool expectedEof() {
369 return (expected_eof_);
370 }
371
372 /// @brief Returns the list of received responses.
373 ///
374 /// @return list of string responses.
375 const std::list<std::string>& getResponses() {
376 return (responses_received_);
377 }
378
379 bool handshakeFailed() {
380 return(handshake_failed_);
381 }
382
383private:
384
385 /// @brief Holds pointer to the IO service.
386 isc::asiolink::IOServicePtr io_service_;
387
388 /// @brief TLS context.
389 isc::asiolink::TlsContextPtr tls_context_;
390
391 /// @brief TCP socket used by this connection.
392 std::unique_ptr<isc::asiolink::TCPSocket<SocketCallback> > tcp_socket_;
393
394 /// @brief TLS socket used by this connection.
395 std::unique_ptr<isc::asiolink::TLSSocket<SocketCallback> > tls_socket_;
396
397 /// @brief Callback to invoke when the client has finished its work or
398 /// failed.
399 std::function<void()> done_callback_;
400
401 /// @brief IP address of the server.
402 std::string server_address_;
403
404 /// @brief IP port of the server.
405 uint16_t server_port_;
406
407 /// @brief Buffer into which response is written.
408 std::array<char, 8192> buf_;
409
410 /// @brief Response in the textual format.
411 std::string response_;
412
413 /// @brief Set to true when the receive has completed successfully.
414 bool receive_done_;
415
416 /// @brief Set to true when the receive ended in EOF as expected. In other
417 /// words, the server closed the connection while we were reading as we
418 /// expected it to do.
419 bool expected_eof_;
420
421 /// @brief Set to true if the TLS handshake failed.
422 bool handshake_failed_;
423
424 /// @brief Pointer to the server response currently being received.
425 isc::tcp::TcpStreamRequestPtr stream_response_;
426
427 /// @brief List of string requests to send.
428 std::list<std::string> requests_to_send_;
429
430 /// @brief List of string responses received.
431 std::list<std::string> responses_received_;
432};
433
434/// @brief Pointer to the TcpTestClient.
435typedef boost::shared_ptr<TcpTestClient> TcpTestClientPtr;
436
437#endif

../../../src/lib/asiolink/tcp_socket.h

1// Copyright (C) 2011-2025 Internet Systems Consortium, Inc. ("ISC")
2//
3// This Source Code Form is subject to the terms of the Mozilla Public
4// License, v. 2.0. If a copy of the MPL was not distributed with this
5// file, You can obtain one at http://mozilla.org/MPL/2.0/.
6
7#ifndef TCP_SOCKET_H
8#define TCP_SOCKET_H
9
10#ifndef BOOST_ASIO_HPP
11#error "asio.hpp must be included before including this, see asiolink.h as to why"
12#endif
13
14#include <asiolink/io_asio_socket.h>
15#include <asiolink/io_endpoint.h>
16#include <asiolink/io_service.h>
17#include <asiolink/tcp_endpoint.h>
18#include <exceptions/isc_assert.h>
19#include <util/buffer.h>
20#include <util/io.h>
21
22#include <algorithm>
23#include <cstddef>
24
25#include <boost/numeric/conversion/cast.hpp>
26
27#include <netinet/in.h>
28#include <sys/socket.h>
29#include <unistd.h> // for some IPC/network system calls
30
31namespace isc {
32namespace asiolink {
33
34/// \brief Buffer Too Large
35///
36/// Thrown on an attempt to send a buffer > 64k
37class BufferTooLarge : public IOError {
38public:
39 BufferTooLarge(const char* file, size_t line, const char* what) :
40 IOError(file, line, what) {}
41};
42
43/// \brief The \c TCPSocket class is a concrete derived class of \c IOAsioSocket
44/// that represents a TCP socket.
45///
46/// \param C Callback type
47template <typename C>
48class TCPSocket : public IOAsioSocket<C> {
49private:
50 /// \brief Class is non-copyable
51 TCPSocket(const TCPSocket&);
52 TCPSocket& operator=(const TCPSocket&);
53
54public:
55
56 /// \brief Constructor from an ASIO TCP socket.
57 ///
58 /// \param socket The ASIO representation of the TCP socket. It is assumed
59 /// that the caller will open and close the socket, so these
60 /// operations are a no-op for that socket.
61 TCPSocket(boost::asio::ip::tcp::socket& socket);
62
63 /// \brief Constructor
64 ///
65 /// Used when the TCPSocket is being asked to manage its own internal
66 /// socket. In this case, the open() and close() methods are used.
67 ///
68 /// \param service I/O Service object used to manage the socket.
69 TCPSocket(const IOServicePtr& service);
70
71 /// \brief Destructor
72 virtual ~TCPSocket();
73
74 /// \brief Return file descriptor of underlying socket
75 virtual int getNative() const {
76 return (socket_.native_handle());
77 }
78
79 /// \brief Return protocol of socket
80 virtual int getProtocol() const {
81 return (IPPROTO_TCPIPPROTO_TCP);
82 }
83
84 /// \brief Is "open()" synchronous?
85 ///
86 /// Indicates that the opening of a TCP socket is asynchronous.
87 virtual bool isOpenSynchronous() const {
88 return (false);
89 }
90
91 /// \brief Checks if the connection is usable.
92 ///
93 /// The connection is usable if the socket is open and the peer has not
94 /// closed its connection.
95 ///
96 /// \return true if the connection is usable.
97 bool isUsable() const {
98 // If the socket is open it doesn't mean that it is still usable. The connection
99 // could have been closed on the other end. We have to check if we can still
100 // use this socket.
101 if (socket_.is_open()) {
82
Taking true branch
102 // Remember the current non blocking setting.
103 const bool non_blocking_orig = socket_.non_blocking();
104 // Set the socket to non blocking mode. We're going to test if the socket
105 // returns would_block status on the attempt to read from it.
106 socket_.non_blocking(true);
107
108 boost::system::error_code ec;
109 char data[2];
110
111 // Use receive with message peek flag to avoid removing the data awaiting
112 // to be read.
113 static_cast<void>(
114 socket_.receive(boost::asio::buffer(data, sizeof(data)),
83
Calling 'basic_stream_socket::receive'
115 boost::asio::socket_base::message_peek,
116 ec));
117
118 // Revert the original non_blocking flag on the socket.
119 socket_.non_blocking(non_blocking_orig);
120
121 // If the connection is alive we'd typically get would_block status code.
122 // If there are any data that haven't been read we may also get success
123 // status. We're guessing that try_again may also be returned by some
124 // implementations in some situations. Any other error code indicates a
125 // problem with the connection so we assume that the connection has been
126 // closed.
127 return (!ec || (ec.value() == boost::asio::error::try_again) ||
128 (ec.value() == boost::asio::error::would_block));
129 }
130
131 return (false);
132 }
133
134 /// \brief Open Socket
135 ///
136 /// Opens the TCP socket. This is an asynchronous operation, completion of
137 /// which will be signalled via a call to the callback function.
138 ///
139 /// \param endpoint Endpoint to which the socket will connect.
140 /// \param callback Callback object.
141 virtual void open(const IOEndpoint* endpoint, C& callback);
142
143 /// \brief Send Asynchronously
144 ///
145 /// Calls the underlying socket's async_send() method to send a packet of
146 /// data asynchronously to the remote endpoint. The callback will be called
147 /// on completion.
148 ///
149 /// \param data Data to send
150 /// \param length Length of data to send
151 /// \param endpoint Target of the send. (Unused for a TCP socket because
152 /// that was determined when the connection was opened.)
153 /// \param callback Callback object.
154 /// \throw BufferTooLarge on attempt to send a buffer larger than 64kB.
155 virtual void asyncSend(const void* data, size_t length,
156 const IOEndpoint* endpoint, C& callback);
157
158 /// \brief Send Asynchronously without count.
159 ///
160 /// This variant of the method sends data over the TCP socket without
161 /// preceding the data with a data count. Eventually, we should migrate
162 /// the virtual method to not insert the count but there are existing
163 /// classes using the count. Once this migration is done, the existing
164 /// virtual method should be replaced by this method.
165 ///
166 /// \param data Data to send
167 /// \param length Length of data to send
168 /// \param callback Callback object.
169 /// \throw BufferTooLarge on attempt to send a buffer larger than 64kB.
170 void asyncSend(const void* data, size_t length, C& callback);
171
172 /// \brief Receive Asynchronously
173 ///
174 /// Calls the underlying socket's async_receive() method to read a packet
175 /// of data from a remote endpoint. Arrival of the data is signalled via a
176 /// call to the callback function.
177 ///
178 /// \param data Buffer to receive incoming message
179 /// \param length Length of the data buffer
180 /// \param offset Offset into buffer where data is to be put
181 /// \param endpoint Source of the communication
182 /// \param callback Callback object
183 virtual void asyncReceive(void* data, size_t length, size_t offset,
184 IOEndpoint* endpoint, C& callback);
185
186 /// \brief Process received data packet
187 ///
188 /// See the description of IOAsioSocket::receiveComplete for a complete
189 /// description of this method.
190 ///
191 /// \param staging Pointer to the start of the staging buffer.
192 /// \param length Amount of data in the staging buffer.
193 /// \param cumulative Amount of data received before the staging buffer is
194 /// processed.
195 /// \param offset Unused.
196 /// \param expected unused.
197 /// \param buff Output buffer. Data in the staging buffer is be copied
198 /// to this output buffer in the call.
199 ///
200 /// \return Always true
201 virtual bool processReceivedData(const void* staging, size_t length,
202 size_t& cumulative, size_t& offset,
203 size_t& expected,
204 isc::util::OutputBufferPtr& buff);
205
206 /// \brief Cancel I/O On Socket
207 virtual void cancel();
208
209 /// \brief Close socket
210 virtual void close();
211
212 /// \brief Returns reference to the underlying ASIO socket.
213 ///
214 /// \return Reference to underlying ASIO socket.
215 virtual boost::asio::ip::tcp::socket& getASIOSocket() const {
216 return (socket_);
217 }
218
219private:
220
221 /// @brief The IO service used to handle events.
222 IOServicePtr io_service_;
223
224 /// Two variables to hold the socket - a socket and a pointer to it. This
225 /// handles the case where a socket is passed to the TCPSocket on
226 /// construction, or where it is asked to manage its own socket.
227
228 /// Pointer to own socket
229 std::unique_ptr<boost::asio::ip::tcp::socket> socket_ptr_;
230
231 /// Socket
232 boost::asio::ip::tcp::socket& socket_;
233
234 /// @todo Remove temporary buffer
235 /// The current implementation copies the buffer passed to asyncSend() into
236 /// a temporary buffer and precedes it with a two-byte count field. As
237 /// ASIO should really be just about sending and receiving data, the TCP
238 /// code should not do this. If the protocol using this requires a two-byte
239 /// count, it should add it before calling this code. (This may be best
240 /// achieved by altering isc::dns::buffer to have pairs of methods:
241 /// getLength()/getTCPLength(), getData()/getTCPData(), with the getTCPXxx()
242 /// methods taking into account a two-byte count field.)
243 ///
244 /// The option of sending the data in two operations, the count followed by
245 /// the data was discounted as that would lead to two callbacks which would
246 /// cause problems with the stackless coroutine code.
247
248 /// Send buffer
249 isc::util::OutputBufferPtr send_buffer_;
250};
251
252// Constructor - caller manages socket
253
254template <typename C>
255TCPSocket<C>::TCPSocket(boost::asio::ip::tcp::socket& socket) :
256 socket_ptr_(), socket_(socket), send_buffer_() {
257}
258
259// Constructor - create socket on the fly
260
261template <typename C>
262TCPSocket<C>::TCPSocket(const IOServicePtr& io_service) : io_service_(io_service),
263 socket_ptr_(new boost::asio::ip::tcp::socket(io_service_->getInternalIOService())),
24
Calling constructor for 'basic_stream_socket<boost::asio::ip::tcp, boost::asio::any_io_executor>'
74
Returning from constructor for 'basic_stream_socket<boost::asio::ip::tcp, boost::asio::any_io_executor>'
264 socket_(*socket_ptr_) {
265}
266
267// Destructor.
268
269template <typename C>
270TCPSocket<C>::~TCPSocket() {
271 TCPSocket<C>::close();
272}
273
274// Open the socket.
275
276template <typename C> void
277TCPSocket<C>::open(const IOEndpoint* endpoint, C& callback) {
278 // If socket is open on this end but has been closed by the peer,
279 // we need to reconnect.
280 if (socket_.is_open() && !isUsable()) {
81
Calling 'TCPSocket::isUsable'
281 close();
282 }
283 // Ignore opens on already-open socket. Don't throw a failure because
284 // of uncertainties as to what precedes when using asynchronous I/O.
285 // Also allows us a treat a passed-in socket as a self-managed socket.
286 if (!socket_.is_open()) {
287 if (endpoint->getFamily() == AF_INET2) {
288 socket_.open(boost::asio::ip::tcp::v4());
289 } else {
290 socket_.open(boost::asio::ip::tcp::v6());
291 }
292
293 // Set options on the socket:
294
295 // Reuse address - allow the socket to bind to a port even if the port
296 // is in the TIMED_WAIT state.
297 socket_.set_option(boost::asio::socket_base::reuse_address(true));
298 }
299
300 // Upconvert to a TCPEndpoint. We need to do this because although
301 // IOEndpoint is the base class of UDPEndpoint and TCPEndpoint, it does not
302 // contain a method for getting at the underlying endpoint type - that is in
303 /// the derived class and the two classes differ on return type.
304 isc_throw_assert(endpoint->getProtocol() == IPPROTO_TCP){ if(!(static_cast<bool>(endpoint->getProtocol() == IPPROTO_TCP
))) { do { std::ostringstream oss__; oss__ << "../../../src/lib/asiolink/tcp_socket.h"
<< ":" << 304 << " (" << "endpoint->getProtocol() == IPPROTO_TCP"
<< ") failed"; throw isc::Unexpected("../../../src/lib/asiolink/tcp_socket.h"
, 304, oss__.str().c_str()); } while (1); }}
;
305 const TCPEndpoint* tcp_endpoint =
306 static_cast<const TCPEndpoint*>(endpoint);
307
308 // Connect to the remote endpoint. On success, the handler will be
309 // called (with one argument - the length argument will default to
310 // zero).
311 socket_.async_connect(tcp_endpoint->getASIOEndpoint(), callback);
312}
313
314// Send a message. Should never do this if the socket is not open, so throw
315// an exception if this is the case.
316
317template <typename C> void
318TCPSocket<C>::asyncSend(const void* data, size_t length, C& callback) {
319 if (socket_.is_open()) {
320
321 try {
322 send_buffer_.reset(new isc::util::OutputBuffer(length));
323 send_buffer_->writeData(data, length);
324
325 // Send the data.
326 socket_.async_send(boost::asio::buffer(send_buffer_->getData(),
327 send_buffer_->getLength()),
328 callback);
329 } catch (const boost::numeric::bad_numeric_cast&) {
330 isc_throw(BufferTooLarge,do { std::ostringstream oss__; oss__ << "attempt to send buffer larger than 64kB"
; throw BufferTooLarge("../../../src/lib/asiolink/tcp_socket.h"
, 331, oss__.str().c_str()); } while (1)
331 "attempt to send buffer larger than 64kB")do { std::ostringstream oss__; oss__ << "attempt to send buffer larger than 64kB"
; throw BufferTooLarge("../../../src/lib/asiolink/tcp_socket.h"
, 331, oss__.str().c_str()); } while (1)
;
332 }
333
334 } else {
335 isc_throw(SocketNotOpen,do { std::ostringstream oss__; oss__ << "attempt to send on a TCP socket that is not open"
; throw SocketNotOpen("../../../src/lib/asiolink/tcp_socket.h"
, 336, oss__.str().c_str()); } while (1)
336 "attempt to send on a TCP socket that is not open")do { std::ostringstream oss__; oss__ << "attempt to send on a TCP socket that is not open"
; throw SocketNotOpen("../../../src/lib/asiolink/tcp_socket.h"
, 336, oss__.str().c_str()); } while (1)
;
337 }
338}
339
340template <typename C> void
341TCPSocket<C>::asyncSend(const void* data, size_t length,
342 const IOEndpoint*, C& callback) {
343 if (socket_.is_open()) {
344
345 /// Need to copy the data into a temporary buffer and precede it with
346 /// a two-byte count field.
347 /// @todo arrange for the buffer passed to be preceded by the count
348 try {
349 /// Ensure it fits into 16 bits
350 uint16_t count = boost::numeric_cast<uint16_t>(length);
351
352 /// Copy data into a buffer preceded by the count field.
353 send_buffer_.reset(new isc::util::OutputBuffer(length + 2));
354 send_buffer_->writeUint16(count);
355 send_buffer_->writeData(data, length);
356
357 /// ... and send it
358 socket_.async_send(boost::asio::buffer(send_buffer_->getData(),
359 send_buffer_->getLength()), callback);
360 } catch (const boost::numeric::bad_numeric_cast&) {
361 isc_throw(BufferTooLarge,do { std::ostringstream oss__; oss__ << "attempt to send buffer larger than 64kB"
; throw BufferTooLarge("../../../src/lib/asiolink/tcp_socket.h"
, 362, oss__.str().c_str()); } while (1)
362 "attempt to send buffer larger than 64kB")do { std::ostringstream oss__; oss__ << "attempt to send buffer larger than 64kB"
; throw BufferTooLarge("../../../src/lib/asiolink/tcp_socket.h"
, 362, oss__.str().c_str()); } while (1)
;
363 }
364
365 } else {
366 isc_throw(SocketNotOpen,do { std::ostringstream oss__; oss__ << "attempt to send on a TCP socket that is not open"
; throw SocketNotOpen("../../../src/lib/asiolink/tcp_socket.h"
, 367, oss__.str().c_str()); } while (1)
367 "attempt to send on a TCP socket that is not open")do { std::ostringstream oss__; oss__ << "attempt to send on a TCP socket that is not open"
; throw SocketNotOpen("../../../src/lib/asiolink/tcp_socket.h"
, 367, oss__.str().c_str()); } while (1)
;
368 }
369}
370
371// Receive a message. Note that the "offset" argument is used as an index
372// into the buffer in order to decide where to put the data. It is up to the
373// caller to initialize the data to zero
374template <typename C> void
375TCPSocket<C>::asyncReceive(void* data, size_t length, size_t offset,
376 IOEndpoint* endpoint, C& callback) {
377 if (socket_.is_open()) {
378 // Upconvert to a TCPEndpoint. We need to do this because although
379 // IOEndpoint is the base class of UDPEndpoint and TCPEndpoint, it
380 // does not contain a method for getting at the underlying endpoint
381 // type - that is in the derived class and the two classes differ on
382 // return type.
383 isc_throw_assert(endpoint->getProtocol() == IPPROTO_TCP){ if(!(static_cast<bool>(endpoint->getProtocol() == IPPROTO_TCP
))) { do { std::ostringstream oss__; oss__ << "../../../src/lib/asiolink/tcp_socket.h"
<< ":" << 383 << " (" << "endpoint->getProtocol() == IPPROTO_TCP"
<< ") failed"; throw isc::Unexpected("../../../src/lib/asiolink/tcp_socket.h"
, 383, oss__.str().c_str()); } while (1); }}
;
384 TCPEndpoint* tcp_endpoint = static_cast<TCPEndpoint*>(endpoint);
385
386 // Write the endpoint details from the communications link. Ideally
387 // we should make IOEndpoint assignable, but this runs in to all sorts
388 // of problems concerning the management of the underlying Boost
389 // endpoint (e.g. if it is not self-managed, is the copied one
390 // self-managed?) The most pragmatic solution is to let Boost take care
391 // of everything and copy details of the underlying endpoint.
392 tcp_endpoint->getASIOEndpoint() = socket_.remote_endpoint();
393
394 // Ensure we can write into the buffer and if so, set the pointer to
395 // where the data will be written.
396 if (offset >= length) {
397 isc_throw(BufferOverflow, "attempt to read into area beyond end of "do { std::ostringstream oss__; oss__ << "attempt to read into area beyond end of "
"TCP receive buffer"; throw BufferOverflow("../../../src/lib/asiolink/tcp_socket.h"
, 398, oss__.str().c_str()); } while (1)
398 "TCP receive buffer")do { std::ostringstream oss__; oss__ << "attempt to read into area beyond end of "
"TCP receive buffer"; throw BufferOverflow("../../../src/lib/asiolink/tcp_socket.h"
, 398, oss__.str().c_str()); } while (1)
;
399 }
400 void* buffer_start = static_cast<void*>(static_cast<uint8_t*>(data) + offset);
401
402 // ... and kick off the read.
403 socket_.async_receive(boost::asio::buffer(buffer_start, length - offset), callback);
404
405 } else {
406 isc_throw(SocketNotOpen,do { std::ostringstream oss__; oss__ << "attempt to receive from a TCP socket that is not open"
; throw SocketNotOpen("../../../src/lib/asiolink/tcp_socket.h"
, 407, oss__.str().c_str()); } while (1)
407 "attempt to receive from a TCP socket that is not open")do { std::ostringstream oss__; oss__ << "attempt to receive from a TCP socket that is not open"
; throw SocketNotOpen("../../../src/lib/asiolink/tcp_socket.h"
, 407, oss__.str().c_str()); } while (1)
;
408 }
409}
410
411// Is the receive complete?
412
413template <typename C> bool
414TCPSocket<C>::processReceivedData(const void* staging, size_t length,
415 size_t& cumulative, size_t& offset,
416 size_t& expected,
417 isc::util::OutputBufferPtr& outbuff) {
418 // Point to the data in the staging buffer and note how much there is.
419 const uint8_t* data = static_cast<const uint8_t*>(staging);
420 size_t data_length = length;
421
422 // Is the number is "expected" valid? It won't be unless we have received
423 // at least two bytes of data in total for this set of receives.
424 if (cumulative < 2) {
425
426 // "expected" is not valid. Did this read give us enough data to
427 // work it out?
428 cumulative += length;
429 if (cumulative < 2) {
430
431 // Nope, still not valid. This must have been the first packet and
432 // was only one byte long. Tell the fetch code to read the next
433 // packet into the staging buffer beyond the data that is already
434 // there so that the next time we are called we have a complete
435 // TCP count.
436 offset = cumulative;
437 return (false);
438 }
439
440 // Have enough data to interpret the packet count, so do so now.
441 expected = isc::util::readUint16(data, cumulative);
442
443 // We have two bytes less of data to process. Point to the start of the
444 // data and adjust the packet size. Note that at this point,
445 // "cumulative" is the true amount of data in the staging buffer, not
446 // "length".
447 data += 2;
448 data_length = cumulative - 2;
449 } else {
450
451 // Update total amount of data received.
452 cumulative += length;
453 }
454
455 // Regardless of anything else, the next read goes into the start of the
456 // staging buffer.
457 offset = 0;
458
459 // Work out how much data we still have to put in the output buffer. (This
460 // could be zero if we have just interpreted the TCP count and that was
461 // set to zero.)
462 if (expected >= outbuff->getLength()) {
463
464 // Still need data in the output packet. Copy what we can from the
465 // staging buffer to the output buffer.
466 size_t copy_amount = std::min(expected - outbuff->getLength(), data_length);
467 outbuff->writeData(data, copy_amount);
468 }
469
470 // We can now say if we have all the data.
471 return (expected == outbuff->getLength());
472}
473
474// Cancel I/O on the socket. No-op if the socket is not open.
475
476template <typename C> void
477TCPSocket<C>::cancel() {
478 if (socket_.is_open()) {
479 socket_.cancel();
480 }
481}
482
483// Close the socket down. Can only do this if the socket is open and we are
484// managing it ourself.
485
486template <typename C> void
487TCPSocket<C>::close() {
488 if (socket_.is_open() && socket_ptr_) {
489 socket_.close();
490 }
491}
492
493} // namespace asiolink
494} // namespace isc
495
496#endif // TCP_SOCKET_H

/usr/include/boost/asio/basic_stream_socket.hpp

1//
2// basic_stream_socket.hpp
3// ~~~~~~~~~~~~~~~~~~~~~~~
4//
5// Copyright (c) 2003-2025 Christopher M. Kohlhoff (chris at kohlhoff dot com)
6//
7// Distributed under the Boost Software License, Version 1.0. (See accompanying
8// file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt)
9//
10
11#ifndef BOOST_ASIO_BASIC_STREAM_SOCKET_HPP
12#define BOOST_ASIO_BASIC_STREAM_SOCKET_HPP
13
14#if defined(_MSC_VER) && (_MSC_VER >= 1200)
15# pragma once
16#endif // defined(_MSC_VER) && (_MSC_VER >= 1200)
17
18#include <boost/asio/detail/config.hpp>
19#include <cstddef>
20#include <boost/asio/async_result.hpp>
21#include <boost/asio/basic_socket.hpp>
22#include <boost/asio/detail/handler_type_requirements.hpp>
23#include <boost/asio/detail/non_const_lvalue.hpp>
24#include <boost/asio/detail/throw_error.hpp>
25#include <boost/asio/error.hpp>
26
27#include <boost/asio/detail/push_options.hpp>
28
29namespace boost {
30namespace asio {
31
32#if !defined(BOOST_ASIO_BASIC_STREAM_SOCKET_FWD_DECL)
33#define BOOST_ASIO_BASIC_STREAM_SOCKET_FWD_DECL
34
35// Forward declaration with defaulted arguments.
36template <typename Protocol, typename Executor = any_io_executor>
37class basic_stream_socket;
38
39#endif // !defined(BOOST_ASIO_BASIC_STREAM_SOCKET_FWD_DECL)
40
41/// Provides stream-oriented socket functionality.
42/**
43 * The basic_stream_socket class template provides asynchronous and blocking
44 * stream-oriented socket functionality.
45 *
46 * @par Thread Safety
47 * @e Distinct @e objects: Safe.@n
48 * @e Shared @e objects: Unsafe.
49 *
50 * Synchronous @c send, @c receive, @c connect, and @c shutdown operations are
51 * thread safe with respect to each other, if the underlying operating system
52 * calls are also thread safe. This means that it is permitted to perform
53 * concurrent calls to these synchronous operations on a single socket object.
54 * Other synchronous operations, such as @c open or @c close, are not thread
55 * safe.
56 *
57 * @par Concepts:
58 * AsyncReadStream, AsyncWriteStream, Stream, SyncReadStream, SyncWriteStream.
59 */
60template <typename Protocol, typename Executor>
61class basic_stream_socket
62 : public basic_socket<Protocol, Executor>
63{
64private:
65 class initiate_async_send;
66 class initiate_async_receive;
67
68public:
69 /// The type of the executor associated with the object.
70 typedef Executor executor_type;
71
72 /// Rebinds the socket type to another executor.
73 template <typename Executor1>
74 struct rebind_executor
75 {
76 /// The socket type when rebound to the specified executor.
77 typedef basic_stream_socket<Protocol, Executor1> other;
78 };
79
80 /// The native representation of a socket.
81#if defined(GENERATING_DOCUMENTATION)
82 typedef implementation_defined native_handle_type;
83#else
84 typedef typename basic_socket<Protocol,
85 Executor>::native_handle_type native_handle_type;
86#endif
87
88 /// The protocol type.
89 typedef Protocol protocol_type;
90
91 /// The endpoint type.
92 typedef typename Protocol::endpoint endpoint_type;
93
94 /// Construct a basic_stream_socket without opening it.
95 /**
96 * This constructor creates a stream socket without opening it. The socket
97 * needs to be opened and then connected or accepted before data can be sent
98 * or received on it.
99 *
100 * @param ex The I/O executor that the socket will use, by default, to
101 * dispatch handlers for any asynchronous operations performed on the socket.
102 */
103 explicit basic_stream_socket(const executor_type& ex)
104 : basic_socket<Protocol, Executor>(ex)
105 {
106 }
107
108 /// Construct a basic_stream_socket without opening it.
109 /**
110 * This constructor creates a stream socket without opening it. The socket
111 * needs to be opened and then connected or accepted before data can be sent
112 * or received on it.
113 *
114 * @param context An execution context which provides the I/O executor that
115 * the socket will use, by default, to dispatch handlers for any asynchronous
116 * operations performed on the socket.
117 */
118 template <typename ExecutionContext>
119 explicit basic_stream_socket(ExecutionContext& context,
120 constraint_t<
121 is_convertible<ExecutionContext&, execution_context&>::value
122 > = 0)
123 : basic_socket<Protocol, Executor>(context)
25
Calling constructor for 'basic_socket<boost::asio::ip::tcp, boost::asio::any_io_executor>'
73
Returning from constructor for 'basic_socket<boost::asio::ip::tcp, boost::asio::any_io_executor>'
124 {
125 }
126
127 /// Construct and open a basic_stream_socket.
128 /**
129 * This constructor creates and opens a stream socket. The socket needs to be
130 * connected or accepted before data can be sent or received on it.
131 *
132 * @param ex The I/O executor that the socket will use, by default, to
133 * dispatch handlers for any asynchronous operations performed on the socket.
134 *
135 * @param protocol An object specifying protocol parameters to be used.
136 *
137 * @throws boost::system::system_error Thrown on failure.
138 */
139 basic_stream_socket(const executor_type& ex, const protocol_type& protocol)
140 : basic_socket<Protocol, Executor>(ex, protocol)
141 {
142 }
143
144 /// Construct and open a basic_stream_socket.
145 /**
146 * This constructor creates and opens a stream socket. The socket needs to be
147 * connected or accepted before data can be sent or received on it.
148 *
149 * @param context An execution context which provides the I/O executor that
150 * the socket will use, by default, to dispatch handlers for any asynchronous
151 * operations performed on the socket.
152 *
153 * @param protocol An object specifying protocol parameters to be used.
154 *
155 * @throws boost::system::system_error Thrown on failure.
156 */
157 template <typename ExecutionContext>
158 basic_stream_socket(ExecutionContext& context, const protocol_type& protocol,
159 constraint_t<
160 is_convertible<ExecutionContext&, execution_context&>::value,
161 defaulted_constraint
162 > = defaulted_constraint())
163 : basic_socket<Protocol, Executor>(context, protocol)
164 {
165 }
166
167 /// Construct a basic_stream_socket, opening it and binding it to the given
168 /// local endpoint.
169 /**
170 * This constructor creates a stream socket and automatically opens it bound
171 * to the specified endpoint on the local machine. The protocol used is the
172 * protocol associated with the given endpoint.
173 *
174 * @param ex The I/O executor that the socket will use, by default, to
175 * dispatch handlers for any asynchronous operations performed on the socket.
176 *
177 * @param endpoint An endpoint on the local machine to which the stream
178 * socket will be bound.
179 *
180 * @throws boost::system::system_error Thrown on failure.
181 */
182 basic_stream_socket(const executor_type& ex, const endpoint_type& endpoint)
183 : basic_socket<Protocol, Executor>(ex, endpoint)
184 {
185 }
186
187 /// Construct a basic_stream_socket, opening it and binding it to the given
188 /// local endpoint.
189 /**
190 * This constructor creates a stream socket and automatically opens it bound
191 * to the specified endpoint on the local machine. The protocol used is the
192 * protocol associated with the given endpoint.
193 *
194 * @param context An execution context which provides the I/O executor that
195 * the socket will use, by default, to dispatch handlers for any asynchronous
196 * operations performed on the socket.
197 *
198 * @param endpoint An endpoint on the local machine to which the stream
199 * socket will be bound.
200 *
201 * @throws boost::system::system_error Thrown on failure.
202 */
203 template <typename ExecutionContext>
204 basic_stream_socket(ExecutionContext& context, const endpoint_type& endpoint,
205 constraint_t<
206 is_convertible<ExecutionContext&, execution_context&>::value
207 > = 0)
208 : basic_socket<Protocol, Executor>(context, endpoint)
209 {
210 }
211
212 /// Construct a basic_stream_socket on an existing native socket.
213 /**
214 * This constructor creates a stream socket object to hold an existing native
215 * socket.
216 *
217 * @param ex The I/O executor that the socket will use, by default, to
218 * dispatch handlers for any asynchronous operations performed on the socket.
219 *
220 * @param protocol An object specifying protocol parameters to be used.
221 *
222 * @param native_socket The new underlying socket implementation.
223 *
224 * @throws boost::system::system_error Thrown on failure.
225 */
226 basic_stream_socket(const executor_type& ex,
227 const protocol_type& protocol, const native_handle_type& native_socket)
228 : basic_socket<Protocol, Executor>(ex, protocol, native_socket)
229 {
230 }
231
232 /// Construct a basic_stream_socket on an existing native socket.
233 /**
234 * This constructor creates a stream socket object to hold an existing native
235 * socket.
236 *
237 * @param context An execution context which provides the I/O executor that
238 * the socket will use, by default, to dispatch handlers for any asynchronous
239 * operations performed on the socket.
240 *
241 * @param protocol An object specifying protocol parameters to be used.
242 *
243 * @param native_socket The new underlying socket implementation.
244 *
245 * @throws boost::system::system_error Thrown on failure.
246 */
247 template <typename ExecutionContext>
248 basic_stream_socket(ExecutionContext& context,
249 const protocol_type& protocol, const native_handle_type& native_socket,
250 constraint_t<
251 is_convertible<ExecutionContext&, execution_context&>::value
252 > = 0)
253 : basic_socket<Protocol, Executor>(context, protocol, native_socket)
254 {
255 }
256
257 /// Move-construct a basic_stream_socket from another.
258 /**
259 * This constructor moves a stream socket from one object to another.
260 *
261 * @param other The other basic_stream_socket object from which the move
262 * will occur.
263 *
264 * @note Following the move, the moved-from object is in the same state as if
265 * constructed using the @c basic_stream_socket(const executor_type&)
266 * constructor.
267 */
268 basic_stream_socket(basic_stream_socket&& other) noexcept
269 : basic_socket<Protocol, Executor>(std::move(other))
270 {
271 }
272
273 /// Move-assign a basic_stream_socket from another.
274 /**
275 * This assignment operator moves a stream socket from one object to another.
276 *
277 * @param other The other basic_stream_socket object from which the move
278 * will occur.
279 *
280 * @note Following the move, the moved-from object is in the same state as if
281 * constructed using the @c basic_stream_socket(const executor_type&)
282 * constructor.
283 */
284 basic_stream_socket& operator=(basic_stream_socket&& other)
285 {
286 basic_socket<Protocol, Executor>::operator=(std::move(other));
287 return *this;
288 }
289
290 /// Move-construct a basic_stream_socket from a socket of another protocol
291 /// type.
292 /**
293 * This constructor moves a stream socket from one object to another.
294 *
295 * @param other The other basic_stream_socket object from which the move
296 * will occur.
297 *
298 * @note Following the move, the moved-from object is in the same state as if
299 * constructed using the @c basic_stream_socket(const executor_type&)
300 * constructor.
301 */
302 template <typename Protocol1, typename Executor1>
303 basic_stream_socket(basic_stream_socket<Protocol1, Executor1>&& other,
304 constraint_t<
305 is_convertible<Protocol1, Protocol>::value
306 && is_convertible<Executor1, Executor>::value
307 > = 0)
308 : basic_socket<Protocol, Executor>(std::move(other))
309 {
310 }
311
312 /// Move-assign a basic_stream_socket from a socket of another protocol type.
313 /**
314 * This assignment operator moves a stream socket from one object to another.
315 *
316 * @param other The other basic_stream_socket object from which the move
317 * will occur.
318 *
319 * @note Following the move, the moved-from object is in the same state as if
320 * constructed using the @c basic_stream_socket(const executor_type&)
321 * constructor.
322 */
323 template <typename Protocol1, typename Executor1>
324 constraint_t<
325 is_convertible<Protocol1, Protocol>::value
326 && is_convertible<Executor1, Executor>::value,
327 basic_stream_socket&
328 > operator=(basic_stream_socket<Protocol1, Executor1>&& other)
329 {
330 basic_socket<Protocol, Executor>::operator=(std::move(other));
331 return *this;
332 }
333
334 /// Destroys the socket.
335 /**
336 * This function destroys the socket, cancelling any outstanding asynchronous
337 * operations associated with the socket as if by calling @c cancel.
338 */
339 ~basic_stream_socket()
340 {
341 }
342
343 /// Send some data on the socket.
344 /**
345 * This function is used to send data on the stream socket. The function
346 * call will block until one or more bytes of the data has been sent
347 * successfully, or an until error occurs.
348 *
349 * @param buffers One or more data buffers to be sent on the socket.
350 *
351 * @returns The number of bytes sent.
352 *
353 * @throws boost::system::system_error Thrown on failure.
354 *
355 * @note The send operation may not transmit all of the data to the peer.
356 * Consider using the @ref write function if you need to ensure that all data
357 * is written before the blocking operation completes.
358 *
359 * @par Example
360 * To send a single data buffer use the @ref buffer function as follows:
361 * @code
362 * socket.send(boost::asio::buffer(data, size));
363 * @endcode
364 * See the @ref buffer documentation for information on sending multiple
365 * buffers in one go, and how to use it with arrays, boost::array or
366 * std::vector.
367 */
368 template <typename ConstBufferSequence>
369 std::size_t send(const ConstBufferSequence& buffers)
370 {
371 boost::system::error_code ec;
372 std::size_t s = this->impl_.get_service().send(
373 this->impl_.get_implementation(), buffers, 0, ec);
374 boost::asio::detail::throw_error(ec, "send");
375 return s;
376 }
377
378 /// Send some data on the socket.
379 /**
380 * This function is used to send data on the stream socket. The function
381 * call will block until one or more bytes of the data has been sent
382 * successfully, or an until error occurs.
383 *
384 * @param buffers One or more data buffers to be sent on the socket.
385 *
386 * @param flags Flags specifying how the send call is to be made.
387 *
388 * @returns The number of bytes sent.
389 *
390 * @throws boost::system::system_error Thrown on failure.
391 *
392 * @note The send operation may not transmit all of the data to the peer.
393 * Consider using the @ref write function if you need to ensure that all data
394 * is written before the blocking operation completes.
395 *
396 * @par Example
397 * To send a single data buffer use the @ref buffer function as follows:
398 * @code
399 * socket.send(boost::asio::buffer(data, size), 0);
400 * @endcode
401 * See the @ref buffer documentation for information on sending multiple
402 * buffers in one go, and how to use it with arrays, boost::array or
403 * std::vector.
404 */
405 template <typename ConstBufferSequence>
406 std::size_t send(const ConstBufferSequence& buffers,
407 socket_base::message_flags flags)
408 {
409 boost::system::error_code ec;
410 std::size_t s = this->impl_.get_service().send(
411 this->impl_.get_implementation(), buffers, flags, ec);
412 boost::asio::detail::throw_error(ec, "send");
413 return s;
414 }
415
416 /// Send some data on the socket.
417 /**
418 * This function is used to send data on the stream socket. The function
419 * call will block until one or more bytes of the data has been sent
420 * successfully, or an until error occurs.
421 *
422 * @param buffers One or more data buffers to be sent on the socket.
423 *
424 * @param flags Flags specifying how the send call is to be made.
425 *
426 * @param ec Set to indicate what error occurred, if any.
427 *
428 * @returns The number of bytes sent. Returns 0 if an error occurred.
429 *
430 * @note The send operation may not transmit all of the data to the peer.
431 * Consider using the @ref write function if you need to ensure that all data
432 * is written before the blocking operation completes.
433 */
434 template <typename ConstBufferSequence>
435 std::size_t send(const ConstBufferSequence& buffers,
436 socket_base::message_flags flags, boost::system::error_code& ec)
437 {
438 return this->impl_.get_service().send(
439 this->impl_.get_implementation(), buffers, flags, ec);
440 }
441
442 /// Start an asynchronous send.
443 /**
444 * This function is used to asynchronously send data on the stream socket.
445 * It is an initiating function for an @ref asynchronous_operation, and always
446 * returns immediately.
447 *
448 * @param buffers One or more data buffers to be sent on the socket. Although
449 * the buffers object may be copied as necessary, ownership of the underlying
450 * memory blocks is retained by the caller, which must guarantee that they
451 * remain valid until the completion handler is called.
452 *
453 * @param token The @ref completion_token that will be used to produce a
454 * completion handler, which will be called when the send completes.
455 * Potential completion tokens include @ref use_future, @ref use_awaitable,
456 * @ref yield_context, or a function object with the correct completion
457 * signature. The function signature of the completion handler must be:
458 * @code void handler(
459 * const boost::system::error_code& error, // Result of operation.
460 * std::size_t bytes_transferred // Number of bytes sent.
461 * ); @endcode
462 * Regardless of whether the asynchronous operation completes immediately or
463 * not, the completion handler will not be invoked from within this function.
464 * On immediate completion, invocation of the handler will be performed in a
465 * manner equivalent to using boost::asio::async_immediate().
466 *
467 * @par Completion Signature
468 * @code void(boost::system::error_code, std::size_t) @endcode
469 *
470 * @note The send operation may not transmit all of the data to the peer.
471 * Consider using the @ref async_write function if you need to ensure that all
472 * data is written before the asynchronous operation completes.
473 *
474 * @par Example
475 * To send a single data buffer use the @ref buffer function as follows:
476 * @code
477 * socket.async_send(boost::asio::buffer(data, size), handler);
478 * @endcode
479 * See the @ref buffer documentation for information on sending multiple
480 * buffers in one go, and how to use it with arrays, boost::array or
481 * std::vector.
482 *
483 * @par Per-Operation Cancellation
484 * On POSIX or Windows operating systems, this asynchronous operation supports
485 * cancellation for the following boost::asio::cancellation_type values:
486 *
487 * @li @c cancellation_type::terminal
488 *
489 * @li @c cancellation_type::partial
490 *
491 * @li @c cancellation_type::total
492 */
493 template <typename ConstBufferSequence,
494 BOOST_ASIO_COMPLETION_TOKEN_FOR(void (boost::system::error_code,typename
495 std::size_t))typename WriteToken = default_completion_token_t<executor_type>>
496 auto async_send(const ConstBufferSequence& buffers,
497 WriteToken&& token = default_completion_token_t<executor_type>())
498 -> decltype(
499 async_initiate<WriteToken,
500 void (boost::system::error_code, std::size_t)>(
501 declval<initiate_async_send>(), token,
502 buffers, socket_base::message_flags(0)))
503 {
504 return async_initiate<WriteToken,
505 void (boost::system::error_code, std::size_t)>(
506 initiate_async_send(this), token,
507 buffers, socket_base::message_flags(0));
508 }
509
510 /// Start an asynchronous send.
511 /**
512 * This function is used to asynchronously send data on the stream socket.
513 * It is an initiating function for an @ref asynchronous_operation, and always
514 * returns immediately.
515 *
516 * @param buffers One or more data buffers to be sent on the socket. Although
517 * the buffers object may be copied as necessary, ownership of the underlying
518 * memory blocks is retained by the caller, which must guarantee that they
519 * remain valid until the completion handler is called.
520 *
521 * @param flags Flags specifying how the send call is to be made.
522 *
523 * @param token The @ref completion_token that will be used to produce a
524 * completion handler, which will be called when the send completes.
525 * Potential completion tokens include @ref use_future, @ref use_awaitable,
526 * @ref yield_context, or a function object with the correct completion
527 * signature. The function signature of the completion handler must be:
528 * @code void handler(
529 * const boost::system::error_code& error, // Result of operation.
530 * std::size_t bytes_transferred // Number of bytes sent.
531 * ); @endcode
532 * Regardless of whether the asynchronous operation completes immediately or
533 * not, the completion handler will not be invoked from within this function.
534 * On immediate completion, invocation of the handler will be performed in a
535 * manner equivalent to using boost::asio::async_immediate().
536 *
537 * @par Completion Signature
538 * @code void(boost::system::error_code, std::size_t) @endcode
539 *
540 * @note The send operation may not transmit all of the data to the peer.
541 * Consider using the @ref async_write function if you need to ensure that all
542 * data is written before the asynchronous operation completes.
543 *
544 * @par Example
545 * To send a single data buffer use the @ref buffer function as follows:
546 * @code
547 * socket.async_send(boost::asio::buffer(data, size), 0, handler);
548 * @endcode
549 * See the @ref buffer documentation for information on sending multiple
550 * buffers in one go, and how to use it with arrays, boost::array or
551 * std::vector.
552 *
553 * @par Per-Operation Cancellation
554 * On POSIX or Windows operating systems, this asynchronous operation supports
555 * cancellation for the following boost::asio::cancellation_type values:
556 *
557 * @li @c cancellation_type::terminal
558 *
559 * @li @c cancellation_type::partial
560 *
561 * @li @c cancellation_type::total
562 */
563 template <typename ConstBufferSequence,
564 BOOST_ASIO_COMPLETION_TOKEN_FOR(void (boost::system::error_code,typename
565 std::size_t))typename WriteToken = default_completion_token_t<executor_type>>
566 auto async_send(const ConstBufferSequence& buffers,
567 socket_base::message_flags flags,
568 WriteToken&& token = default_completion_token_t<executor_type>())
569 -> decltype(
570 async_initiate<WriteToken,
571 void (boost::system::error_code, std::size_t)>(
572 declval<initiate_async_send>(), token, buffers, flags))
573 {
574 return async_initiate<WriteToken,
575 void (boost::system::error_code, std::size_t)>(
576 initiate_async_send(this), token, buffers, flags);
577 }
578
579 /// Receive some data on the socket.
580 /**
581 * This function is used to receive data on the stream socket. The function
582 * call will block until one or more bytes of data has been received
583 * successfully, or until an error occurs.
584 *
585 * @param buffers One or more buffers into which the data will be received.
586 *
587 * @returns The number of bytes received.
588 *
589 * @throws boost::system::system_error Thrown on failure. An error code of
590 * boost::asio::error::eof indicates that the connection was closed by the
591 * peer.
592 *
593 * @note The receive operation may not receive all of the requested number of
594 * bytes. Consider using the @ref read function if you need to ensure that the
595 * requested amount of data is read before the blocking operation completes.
596 *
597 * @par Example
598 * To receive into a single data buffer use the @ref buffer function as
599 * follows:
600 * @code
601 * socket.receive(boost::asio::buffer(data, size));
602 * @endcode
603 * See the @ref buffer documentation for information on receiving into
604 * multiple buffers in one go, and how to use it with arrays, boost::array or
605 * std::vector.
606 */
607 template <typename MutableBufferSequence>
608 std::size_t receive(const MutableBufferSequence& buffers)
609 {
610 boost::system::error_code ec;
611 std::size_t s = this->impl_.get_service().receive(
612 this->impl_.get_implementation(), buffers, 0, ec);
613 boost::asio::detail::throw_error(ec, "receive");
614 return s;
615 }
616
617 /// Receive some data on the socket.
618 /**
619 * This function is used to receive data on the stream socket. The function
620 * call will block until one or more bytes of data has been received
621 * successfully, or until an error occurs.
622 *
623 * @param buffers One or more buffers into which the data will be received.
624 *
625 * @param flags Flags specifying how the receive call is to be made.
626 *
627 * @returns The number of bytes received.
628 *
629 * @throws boost::system::system_error Thrown on failure. An error code of
630 * boost::asio::error::eof indicates that the connection was closed by the
631 * peer.
632 *
633 * @note The receive operation may not receive all of the requested number of
634 * bytes. Consider using the @ref read function if you need to ensure that the
635 * requested amount of data is read before the blocking operation completes.
636 *
637 * @par Example
638 * To receive into a single data buffer use the @ref buffer function as
639 * follows:
640 * @code
641 * socket.receive(boost::asio::buffer(data, size), 0);
642 * @endcode
643 * See the @ref buffer documentation for information on receiving into
644 * multiple buffers in one go, and how to use it with arrays, boost::array or
645 * std::vector.
646 */
647 template <typename MutableBufferSequence>
648 std::size_t receive(const MutableBufferSequence& buffers,
649 socket_base::message_flags flags)
650 {
651 boost::system::error_code ec;
652 std::size_t s = this->impl_.get_service().receive(
653 this->impl_.get_implementation(), buffers, flags, ec);
654 boost::asio::detail::throw_error(ec, "receive");
655 return s;
656 }
657
658 /// Receive some data on a connected socket.
659 /**
660 * This function is used to receive data on the stream socket. The function
661 * call will block until one or more bytes of data has been received
662 * successfully, or until an error occurs.
663 *
664 * @param buffers One or more buffers into which the data will be received.
665 *
666 * @param flags Flags specifying how the receive call is to be made.
667 *
668 * @param ec Set to indicate what error occurred, if any.
669 *
670 * @returns The number of bytes received. Returns 0 if an error occurred.
671 *
672 * @note The receive operation may not receive all of the requested number of
673 * bytes. Consider using the @ref read function if you need to ensure that the
674 * requested amount of data is read before the blocking operation completes.
675 */
676 template <typename MutableBufferSequence>
677 std::size_t receive(const MutableBufferSequence& buffers,
678 socket_base::message_flags flags, boost::system::error_code& ec)
679 {
680 return this->impl_.get_service().receive(
84
Calling 'reactive_socket_service_base::receive'
681 this->impl_.get_implementation(), buffers, flags, ec);
682 }
683
684 /// Start an asynchronous receive.
685 /**
686 * This function is used to asynchronously receive data from the stream
687 * socket. It is an initiating function for an @ref asynchronous_operation,
688 * and always returns immediately.
689 *
690 * @param buffers One or more buffers into which the data will be received.
691 * Although the buffers object may be copied as necessary, ownership of the
692 * underlying memory blocks is retained by the caller, which must guarantee
693 * that they remain valid until the completion handler is called.
694 *
695 * @param token The @ref completion_token that will be used to produce a
696 * completion handler, which will be called when the receive completes.
697 * Potential completion tokens include @ref use_future, @ref use_awaitable,
698 * @ref yield_context, or a function object with the correct completion
699 * signature. The function signature of the completion handler must be:
700 * @code void handler(
701 * const boost::system::error_code& error, // Result of operation.
702 * std::size_t bytes_transferred // Number of bytes received.
703 * ); @endcode
704 * Regardless of whether the asynchronous operation completes immediately or
705 * not, the completion handler will not be invoked from within this function.
706 * On immediate completion, invocation of the handler will be performed in a
707 * manner equivalent to using boost::asio::async_immediate().
708 *
709 * @par Completion Signature
710 * @code void(boost::system::error_code, std::size_t) @endcode
711 *
712 * @note The receive operation may not receive all of the requested number of
713 * bytes. Consider using the @ref async_read function if you need to ensure
714 * that the requested amount of data is received before the asynchronous
715 * operation completes.
716 *
717 * @par Example
718 * To receive into a single data buffer use the @ref buffer function as
719 * follows:
720 * @code
721 * socket.async_receive(boost::asio::buffer(data, size), handler);
722 * @endcode
723 * See the @ref buffer documentation for information on receiving into
724 * multiple buffers in one go, and how to use it with arrays, boost::array or
725 * std::vector.
726 *
727 * @par Per-Operation Cancellation
728 * On POSIX or Windows operating systems, this asynchronous operation supports
729 * cancellation for the following boost::asio::cancellation_type values:
730 *
731 * @li @c cancellation_type::terminal
732 *
733 * @li @c cancellation_type::partial
734 *
735 * @li @c cancellation_type::total
736 */
737 template <typename MutableBufferSequence,
738 BOOST_ASIO_COMPLETION_TOKEN_FOR(void (boost::system::error_code,typename
739 std::size_t))typename ReadToken = default_completion_token_t<executor_type>>
740 auto async_receive(const MutableBufferSequence& buffers,
741 ReadToken&& token = default_completion_token_t<executor_type>())
742 -> decltype(
743 async_initiate<ReadToken,
744 void (boost::system::error_code, std::size_t)>(
745 declval<initiate_async_receive>(), token,
746 buffers, socket_base::message_flags(0)))
747 {
748 return async_initiate<ReadToken,
749 void (boost::system::error_code, std::size_t)>(
750 initiate_async_receive(this), token,
751 buffers, socket_base::message_flags(0));
752 }
753
754 /// Start an asynchronous receive.
755 /**
756 * This function is used to asynchronously receive data from the stream
757 * socket. It is an initiating function for an @ref asynchronous_operation,
758 * and always returns immediately.
759 *
760 * @param buffers One or more buffers into which the data will be received.
761 * Although the buffers object may be copied as necessary, ownership of the
762 * underlying memory blocks is retained by the caller, which must guarantee
763 * that they remain valid until the completion handler is called.
764 *
765 * @param flags Flags specifying how the receive call is to be made.
766 *
767 * @param token The @ref completion_token that will be used to produce a
768 * completion handler, which will be called when the receive completes.
769 * Potential completion tokens include @ref use_future, @ref use_awaitable,
770 * @ref yield_context, or a function object with the correct completion
771 * signature. The function signature of the completion handler must be:
772 * @code void handler(
773 * const boost::system::error_code& error, // Result of operation.
774 * std::size_t bytes_transferred // Number of bytes received.
775 * ); @endcode
776 * Regardless of whether the asynchronous operation completes immediately or
777 * not, the completion handler will not be invoked from within this function.
778 * On immediate completion, invocation of the handler will be performed in a
779 * manner equivalent to using boost::asio::async_immediate().
780 *
781 * @par Completion Signature
782 * @code void(boost::system::error_code, std::size_t) @endcode
783 *
784 * @note The receive operation may not receive all of the requested number of
785 * bytes. Consider using the @ref async_read function if you need to ensure
786 * that the requested amount of data is received before the asynchronous
787 * operation completes.
788 *
789 * @par Example
790 * To receive into a single data buffer use the @ref buffer function as
791 * follows:
792 * @code
793 * socket.async_receive(boost::asio::buffer(data, size), 0, handler);
794 * @endcode
795 * See the @ref buffer documentation for information on receiving into
796 * multiple buffers in one go, and how to use it with arrays, boost::array or
797 * std::vector.
798 *
799 * @par Per-Operation Cancellation
800 * On POSIX or Windows operating systems, this asynchronous operation supports
801 * cancellation for the following boost::asio::cancellation_type values:
802 *
803 * @li @c cancellation_type::terminal
804 *
805 * @li @c cancellation_type::partial
806 *
807 * @li @c cancellation_type::total
808 */
809 template <typename MutableBufferSequence,
810 BOOST_ASIO_COMPLETION_TOKEN_FOR(void (boost::system::error_code,typename
811 std::size_t))typename ReadToken = default_completion_token_t<executor_type>>
812 auto async_receive(const MutableBufferSequence& buffers,
813 socket_base::message_flags flags,
814 ReadToken&& token = default_completion_token_t<executor_type>())
815 -> decltype(
816 async_initiate<ReadToken,
817 void (boost::system::error_code, std::size_t)>(
818 declval<initiate_async_receive>(), token, buffers, flags))
819 {
820 return async_initiate<ReadToken,
821 void (boost::system::error_code, std::size_t)>(
822 initiate_async_receive(this), token, buffers, flags);
823 }
824
825 /// Write some data to the socket.
826 /**
827 * This function is used to write data to the stream socket. The function call
828 * will block until one or more bytes of the data has been written
829 * successfully, or until an error occurs.
830 *
831 * @param buffers One or more data buffers to be written to the socket.
832 *
833 * @returns The number of bytes written.
834 *
835 * @throws boost::system::system_error Thrown on failure. An error code of
836 * boost::asio::error::eof indicates that the connection was closed by the
837 * peer.
838 *
839 * @note The write_some operation may not transmit all of the data to the
840 * peer. Consider using the @ref write function if you need to ensure that
841 * all data is written before the blocking operation completes.
842 *
843 * @par Example
844 * To write a single data buffer use the @ref buffer function as follows:
845 * @code
846 * socket.write_some(boost::asio::buffer(data, size));
847 * @endcode
848 * See the @ref buffer documentation for information on writing multiple
849 * buffers in one go, and how to use it with arrays, boost::array or
850 * std::vector.
851 */
852 template <typename ConstBufferSequence>
853 std::size_t write_some(const ConstBufferSequence& buffers)
854 {
855 boost::system::error_code ec;
856 std::size_t s = this->impl_.get_service().send(
857 this->impl_.get_implementation(), buffers, 0, ec);
858 boost::asio::detail::throw_error(ec, "write_some");
859 return s;
860 }
861
862 /// Write some data to the socket.
863 /**
864 * This function is used to write data to the stream socket. The function call
865 * will block until one or more bytes of the data has been written
866 * successfully, or until an error occurs.
867 *
868 * @param buffers One or more data buffers to be written to the socket.
869 *
870 * @param ec Set to indicate what error occurred, if any.
871 *
872 * @returns The number of bytes written. Returns 0 if an error occurred.
873 *
874 * @note The write_some operation may not transmit all of the data to the
875 * peer. Consider using the @ref write function if you need to ensure that
876 * all data is written before the blocking operation completes.
877 */
878 template <typename ConstBufferSequence>
879 std::size_t write_some(const ConstBufferSequence& buffers,
880 boost::system::error_code& ec)
881 {
882 return this->impl_.get_service().send(
883 this->impl_.get_implementation(), buffers, 0, ec);
884 }
885
886 /// Start an asynchronous write.
887 /**
888 * This function is used to asynchronously write data to the stream socket.
889 * It is an initiating function for an @ref asynchronous_operation, and always
890 * returns immediately.
891 *
892 * @param buffers One or more data buffers to be written to the socket.
893 * Although the buffers object may be copied as necessary, ownership of the
894 * underlying memory blocks is retained by the caller, which must guarantee
895 * that they remain valid until the completion handler is called.
896 *
897 * @param token The @ref completion_token that will be used to produce a
898 * completion handler, which will be called when the write completes.
899 * Potential completion tokens include @ref use_future, @ref use_awaitable,
900 * @ref yield_context, or a function object with the correct completion
901 * signature. The function signature of the completion handler must be:
902 * @code void handler(
903 * const boost::system::error_code& error, // Result of operation.
904 * std::size_t bytes_transferred // Number of bytes written.
905 * ); @endcode
906 * Regardless of whether the asynchronous operation completes immediately or
907 * not, the completion handler will not be invoked from within this function.
908 * On immediate completion, invocation of the handler will be performed in a
909 * manner equivalent to using boost::asio::async_immediate().
910 *
911 * @par Completion Signature
912 * @code void(boost::system::error_code, std::size_t) @endcode
913 *
914 * @note The write operation may not transmit all of the data to the peer.
915 * Consider using the @ref async_write function if you need to ensure that all
916 * data is written before the asynchronous operation completes.
917 *
918 * @par Example
919 * To write a single data buffer use the @ref buffer function as follows:
920 * @code
921 * socket.async_write_some(boost::asio::buffer(data, size), handler);
922 * @endcode
923 * See the @ref buffer documentation for information on writing multiple
924 * buffers in one go, and how to use it with arrays, boost::array or
925 * std::vector.
926 *
927 * @par Per-Operation Cancellation
928 * On POSIX or Windows operating systems, this asynchronous operation supports
929 * cancellation for the following boost::asio::cancellation_type values:
930 *
931 * @li @c cancellation_type::terminal
932 *
933 * @li @c cancellation_type::partial
934 *
935 * @li @c cancellation_type::total
936 */
937 template <typename ConstBufferSequence,
938 BOOST_ASIO_COMPLETION_TOKEN_FOR(void (boost::system::error_code,typename
939 std::size_t))typename WriteToken = default_completion_token_t<executor_type>>
940 auto async_write_some(const ConstBufferSequence& buffers,
941 WriteToken&& token = default_completion_token_t<executor_type>())
942 -> decltype(
943 async_initiate<WriteToken,
944 void (boost::system::error_code, std::size_t)>(
945 declval<initiate_async_send>(), token,
946 buffers, socket_base::message_flags(0)))
947 {
948 return async_initiate<WriteToken,
949 void (boost::system::error_code, std::size_t)>(
950 initiate_async_send(this), token,
951 buffers, socket_base::message_flags(0));
952 }
953
954 /// Read some data from the socket.
955 /**
956 * This function is used to read data from the stream socket. The function
957 * call will block until one or more bytes of data has been read successfully,
958 * or until an error occurs.
959 *
960 * @param buffers One or more buffers into which the data will be read.
961 *
962 * @returns The number of bytes read.
963 *
964 * @throws boost::system::system_error Thrown on failure. An error code of
965 * boost::asio::error::eof indicates that the connection was closed by the
966 * peer.
967 *
968 * @note The read_some operation may not read all of the requested number of
969 * bytes. Consider using the @ref read function if you need to ensure that
970 * the requested amount of data is read before the blocking operation
971 * completes.
972 *
973 * @par Example
974 * To read into a single data buffer use the @ref buffer function as follows:
975 * @code
976 * socket.read_some(boost::asio::buffer(data, size));
977 * @endcode
978 * See the @ref buffer documentation for information on reading into multiple
979 * buffers in one go, and how to use it with arrays, boost::array or
980 * std::vector.
981 */
982 template <typename MutableBufferSequence>
983 std::size_t read_some(const MutableBufferSequence& buffers)
984 {
985 boost::system::error_code ec;
986 std::size_t s = this->impl_.get_service().receive(
987 this->impl_.get_implementation(), buffers, 0, ec);
988 boost::asio::detail::throw_error(ec, "read_some");
989 return s;
990 }
991
992 /// Read some data from the socket.
993 /**
994 * This function is used to read data from the stream socket. The function
995 * call will block until one or more bytes of data has been read successfully,
996 * or until an error occurs.
997 *
998 * @param buffers One or more buffers into which the data will be read.
999 *
1000 * @param ec Set to indicate what error occurred, if any.
1001 *
1002 * @returns The number of bytes read. Returns 0 if an error occurred.
1003 *
1004 * @note The read_some operation may not read all of the requested number of
1005 * bytes. Consider using the @ref read function if you need to ensure that
1006 * the requested amount of data is read before the blocking operation
1007 * completes.
1008 */
1009 template <typename MutableBufferSequence>
1010 std::size_t read_some(const MutableBufferSequence& buffers,
1011 boost::system::error_code& ec)
1012 {
1013 return this->impl_.get_service().receive(
1014 this->impl_.get_implementation(), buffers, 0, ec);
1015 }
1016
1017 /// Start an asynchronous read.
1018 /**
1019 * This function is used to asynchronously read data from the stream socket.
1020 * socket. It is an initiating function for an @ref asynchronous_operation,
1021 * and always returns immediately.
1022 *
1023 * @param buffers One or more buffers into which the data will be read.
1024 * Although the buffers object may be copied as necessary, ownership of the
1025 * underlying memory blocks is retained by the caller, which must guarantee
1026 * that they remain valid until the completion handler is called.
1027 *
1028 * @param token The @ref completion_token that will be used to produce a
1029 * completion handler, which will be called when the read completes.
1030 * Potential completion tokens include @ref use_future, @ref use_awaitable,
1031 * @ref yield_context, or a function object with the correct completion
1032 * signature. The function signature of the completion handler must be:
1033 * @code void handler(
1034 * const boost::system::error_code& error, // Result of operation.
1035 * std::size_t bytes_transferred // Number of bytes read.
1036 * ); @endcode
1037 * Regardless of whether the asynchronous operation completes immediately or
1038 * not, the completion handler will not be invoked from within this function.
1039 * On immediate completion, invocation of the handler will be performed in a
1040 * manner equivalent to using boost::asio::async_immediate().
1041 *
1042 * @par Completion Signature
1043 * @code void(boost::system::error_code, std::size_t) @endcode
1044 *
1045 * @note The read operation may not read all of the requested number of bytes.
1046 * Consider using the @ref async_read function if you need to ensure that the
1047 * requested amount of data is read before the asynchronous operation
1048 * completes.
1049 *
1050 * @par Example
1051 * To read into a single data buffer use the @ref buffer function as follows:
1052 * @code
1053 * socket.async_read_some(boost::asio::buffer(data, size), handler);
1054 * @endcode
1055 * See the @ref buffer documentation for information on reading into multiple
1056 * buffers in one go, and how to use it with arrays, boost::array or
1057 * std::vector.
1058 *
1059 * @par Per-Operation Cancellation
1060 * On POSIX or Windows operating systems, this asynchronous operation supports
1061 * cancellation for the following boost::asio::cancellation_type values:
1062 *
1063 * @li @c cancellation_type::terminal
1064 *
1065 * @li @c cancellation_type::partial
1066 *
1067 * @li @c cancellation_type::total
1068 */
1069 template <typename MutableBufferSequence,
1070 BOOST_ASIO_COMPLETION_TOKEN_FOR(void (boost::system::error_code,typename
1071 std::size_t))typename ReadToken = default_completion_token_t<executor_type>>
1072 auto async_read_some(const MutableBufferSequence& buffers,
1073 ReadToken&& token = default_completion_token_t<executor_type>())
1074 -> decltype(
1075 async_initiate<ReadToken,
1076 void (boost::system::error_code, std::size_t)>(
1077 declval<initiate_async_receive>(), token,
1078 buffers, socket_base::message_flags(0)))
1079 {
1080 return async_initiate<ReadToken,
1081 void (boost::system::error_code, std::size_t)>(
1082 initiate_async_receive(this), token,
1083 buffers, socket_base::message_flags(0));
1084 }
1085
1086private:
1087 // Disallow copying and assignment.
1088 basic_stream_socket(const basic_stream_socket&) = delete;
1089 basic_stream_socket& operator=(const basic_stream_socket&) = delete;
1090
1091 class initiate_async_send
1092 {
1093 public:
1094 typedef Executor executor_type;
1095
1096 explicit initiate_async_send(basic_stream_socket* self)
1097 : self_(self)
1098 {
1099 }
1100
1101 const executor_type& get_executor() const noexcept
1102 {
1103 return self_->get_executor();
1104 }
1105
1106 template <typename WriteHandler, typename ConstBufferSequence>
1107 void operator()(WriteHandler&& handler,
1108 const ConstBufferSequence& buffers,
1109 socket_base::message_flags flags) const
1110 {
1111 // If you get an error on the following line it means that your handler
1112 // does not meet the documented type requirements for a WriteHandler.
1113 BOOST_ASIO_WRITE_HANDLER_CHECK(WriteHandler, handler)typedef typename ::boost::asio::async_result< typename ::boost
::asio::decay<WriteHandler>::type, void(boost::system::
error_code, std::size_t)>::completion_handler_type asio_true_handler_type
; static_assert(sizeof(boost::asio::detail::two_arg_handler_test
( boost::asio::detail::rvref< asio_true_handler_type>()
, static_cast<const boost::system::error_code*>(0), static_cast
<const std::size_t*>(0))) == 1, "WriteHandler type requirements not met"
); typedef boost::asio::detail::handler_type_requirements<
sizeof( boost::asio::detail::argbyv( boost::asio::detail::rvref
< asio_true_handler_type>())) + sizeof( boost::asio::detail
::rorlvref< asio_true_handler_type>()( boost::asio::detail
::lvref<const boost::system::error_code>(), boost::asio
::detail::lvref<const std::size_t>()), char(0))> __attribute__
((__unused__))
type_check;
1114
1115 detail::non_const_lvalue<WriteHandler> handler2(handler);
1116 self_->impl_.get_service().async_send(
1117 self_->impl_.get_implementation(), buffers, flags,
1118 handler2.value, self_->impl_.get_executor());
1119 }
1120
1121 private:
1122 basic_stream_socket* self_;
1123 };
1124
1125 class initiate_async_receive
1126 {
1127 public:
1128 typedef Executor executor_type;
1129
1130 explicit initiate_async_receive(basic_stream_socket* self)
1131 : self_(self)
1132 {
1133 }
1134
1135 const executor_type& get_executor() const noexcept
1136 {
1137 return self_->get_executor();
1138 }
1139
1140 template <typename ReadHandler, typename MutableBufferSequence>
1141 void operator()(ReadHandler&& handler,
1142 const MutableBufferSequence& buffers,
1143 socket_base::message_flags flags) const
1144 {
1145 // If you get an error on the following line it means that your handler
1146 // does not meet the documented type requirements for a ReadHandler.
1147 BOOST_ASIO_READ_HANDLER_CHECK(ReadHandler, handler)typedef typename ::boost::asio::async_result< typename ::boost
::asio::decay<ReadHandler>::type, void(boost::system::error_code
, std::size_t)>::completion_handler_type asio_true_handler_type
; static_assert(sizeof(boost::asio::detail::two_arg_handler_test
( boost::asio::detail::rvref< asio_true_handler_type>()
, static_cast<const boost::system::error_code*>(0), static_cast
<const std::size_t*>(0))) == 1, "ReadHandler type requirements not met"
); typedef boost::asio::detail::handler_type_requirements<
sizeof( boost::asio::detail::argbyv( boost::asio::detail::rvref
< asio_true_handler_type>())) + sizeof( boost::asio::detail
::rorlvref< asio_true_handler_type>()( boost::asio::detail
::lvref<const boost::system::error_code>(), boost::asio
::detail::lvref<const std::size_t>()), char(0))> __attribute__
((__unused__))
type_check;
1148
1149 detail::non_const_lvalue<ReadHandler> handler2(handler);
1150 self_->impl_.get_service().async_receive(
1151 self_->impl_.get_implementation(), buffers, flags,
1152 handler2.value, self_->impl_.get_executor());
1153 }
1154
1155 private:
1156 basic_stream_socket* self_;
1157 };
1158};
1159
1160} // namespace asio
1161} // namespace boost
1162
1163#include <boost/asio/detail/pop_options.hpp>
1164
1165#endif // BOOST_ASIO_BASIC_STREAM_SOCKET_HPP

/usr/include/boost/asio/basic_socket.hpp

1//
2// basic_socket.hpp
3// ~~~~~~~~~~~~~~~~
4//
5// Copyright (c) 2003-2025 Christopher M. Kohlhoff (chris at kohlhoff dot com)
6//
7// Distributed under the Boost Software License, Version 1.0. (See accompanying
8// file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt)
9//
10
11#ifndef BOOST_ASIO_BASIC_SOCKET_HPP
12#define BOOST_ASIO_BASIC_SOCKET_HPP
13
14#if defined(_MSC_VER) && (_MSC_VER >= 1200)
15# pragma once
16#endif // defined(_MSC_VER) && (_MSC_VER >= 1200)
17
18#include <utility>
19#include <boost/asio/any_io_executor.hpp>
20#include <boost/asio/detail/config.hpp>
21#include <boost/asio/async_result.hpp>
22#include <boost/asio/detail/handler_type_requirements.hpp>
23#include <boost/asio/detail/io_object_impl.hpp>
24#include <boost/asio/detail/non_const_lvalue.hpp>
25#include <boost/asio/detail/throw_error.hpp>
26#include <boost/asio/detail/type_traits.hpp>
27#include <boost/asio/error.hpp>
28#include <boost/asio/execution_context.hpp>
29#include <boost/asio/post.hpp>
30#include <boost/asio/socket_base.hpp>
31
32#if defined(BOOST_ASIO_WINDOWS_RUNTIME)
33# include <boost/asio/detail/null_socket_service.hpp>
34#elif defined(BOOST_ASIO_HAS_IOCP)
35# include <boost/asio/detail/win_iocp_socket_service.hpp>
36#elif defined(BOOST_ASIO_HAS_IO_URING_AS_DEFAULT)
37# include <boost/asio/detail/io_uring_socket_service.hpp>
38#else
39# include <boost/asio/detail/reactive_socket_service.hpp>
40#endif
41
42#include <boost/asio/detail/push_options.hpp>
43
44namespace boost {
45namespace asio {
46
47#if !defined(BOOST_ASIO_BASIC_SOCKET_FWD_DECL)
48#define BOOST_ASIO_BASIC_SOCKET_FWD_DECL
49
50// Forward declaration with defaulted arguments.
51template <typename Protocol, typename Executor = any_io_executor>
52class basic_socket;
53
54#endif // !defined(BOOST_ASIO_BASIC_SOCKET_FWD_DECL)
55
56/// Provides socket functionality.
57/**
58 * The basic_socket class template provides functionality that is common to both
59 * stream-oriented and datagram-oriented sockets.
60 *
61 * @par Thread Safety
62 * @e Distinct @e objects: Safe.@n
63 * @e Shared @e objects: Unsafe.
64 */
65template <typename Protocol, typename Executor>
66class basic_socket
67 : public socket_base
68{
69private:
70 class initiate_async_connect;
71 class initiate_async_wait;
72
73public:
74 /// The type of the executor associated with the object.
75 typedef Executor executor_type;
76
77 /// Rebinds the socket type to another executor.
78 template <typename Executor1>
79 struct rebind_executor
80 {
81 /// The socket type when rebound to the specified executor.
82 typedef basic_socket<Protocol, Executor1> other;
83 };
84
85 /// The native representation of a socket.
86#if defined(GENERATING_DOCUMENTATION)
87 typedef implementation_defined native_handle_type;
88#elif defined(BOOST_ASIO_WINDOWS_RUNTIME)
89 typedef typename detail::null_socket_service<
90 Protocol>::native_handle_type native_handle_type;
91#elif defined(BOOST_ASIO_HAS_IOCP)
92 typedef typename detail::win_iocp_socket_service<
93 Protocol>::native_handle_type native_handle_type;
94#elif defined(BOOST_ASIO_HAS_IO_URING_AS_DEFAULT)
95 typedef typename detail::io_uring_socket_service<
96 Protocol>::native_handle_type native_handle_type;
97#else
98 typedef typename detail::reactive_socket_service<
99 Protocol>::native_handle_type native_handle_type;
100#endif
101
102 /// The protocol type.
103 typedef Protocol protocol_type;
104
105 /// The endpoint type.
106 typedef typename Protocol::endpoint endpoint_type;
107
108#if !defined(BOOST_ASIO_NO_EXTENSIONS)
109 /// A basic_socket is always the lowest layer.
110 typedef basic_socket<Protocol, Executor> lowest_layer_type;
111#endif // !defined(BOOST_ASIO_NO_EXTENSIONS)
112
113 /// Construct a basic_socket without opening it.
114 /**
115 * This constructor creates a socket without opening it.
116 *
117 * @param ex The I/O executor that the socket will use, by default, to
118 * dispatch handlers for any asynchronous operations performed on the socket.
119 */
120 explicit basic_socket(const executor_type& ex)
121 : impl_(0, ex)
122 {
123 }
124
125 /// Construct a basic_socket without opening it.
126 /**
127 * This constructor creates a socket without opening it.
128 *
129 * @param context An execution context which provides the I/O executor that
130 * the socket will use, by default, to dispatch handlers for any asynchronous
131 * operations performed on the socket.
132 */
133 template <typename ExecutionContext>
134 explicit basic_socket(ExecutionContext& context,
135 constraint_t<
136 is_convertible<ExecutionContext&, execution_context&>::value
137 > = 0)
138 : impl_(0, 0, context)
26
Calling constructor for 'io_object_impl<boost::asio::detail::reactive_socket_service<boost::asio::ip::tcp>, boost::asio::any_io_executor>'
72
Returning from constructor for 'io_object_impl<boost::asio::detail::reactive_socket_service<boost::asio::ip::tcp>, boost::asio::any_io_executor>'
139 {
140 }
141
142 /// Construct and open a basic_socket.
143 /**
144 * This constructor creates and opens a socket.
145 *
146 * @param ex The I/O executor that the socket will use, by default, to
147 * dispatch handlers for any asynchronous operations performed on the socket.
148 *
149 * @param protocol An object specifying protocol parameters to be used.
150 *
151 * @throws boost::system::system_error Thrown on failure.
152 */
153 basic_socket(const executor_type& ex, const protocol_type& protocol)
154 : impl_(0, ex)
155 {
156 boost::system::error_code ec;
157 impl_.get_service().open(impl_.get_implementation(), protocol, ec);
158 boost::asio::detail::throw_error(ec, "open");
159 }
160
161 /// Construct and open a basic_socket.
162 /**
163 * This constructor creates and opens a socket.
164 *
165 * @param context An execution context which provides the I/O executor that
166 * the socket will use, by default, to dispatch handlers for any asynchronous
167 * operations performed on the socket.
168 *
169 * @param protocol An object specifying protocol parameters to be used.
170 *
171 * @throws boost::system::system_error Thrown on failure.
172 */
173 template <typename ExecutionContext>
174 basic_socket(ExecutionContext& context, const protocol_type& protocol,
175 constraint_t<
176 is_convertible<ExecutionContext&, execution_context&>::value,
177 defaulted_constraint
178 > = defaulted_constraint())
179 : impl_(0, 0, context)
180 {
181 boost::system::error_code ec;
182 impl_.get_service().open(impl_.get_implementation(), protocol, ec);
183 boost::asio::detail::throw_error(ec, "open");
184 }
185
186 /// Construct a basic_socket, opening it and binding it to the given local
187 /// endpoint.
188 /**
189 * This constructor creates a socket and automatically opens it bound to the
190 * specified endpoint on the local machine. The protocol used is the protocol
191 * associated with the given endpoint.
192 *
193 * @param ex The I/O executor that the socket will use, by default, to
194 * dispatch handlers for any asynchronous operations performed on the socket.
195 *
196 * @param endpoint An endpoint on the local machine to which the socket will
197 * be bound.
198 *
199 * @throws boost::system::system_error Thrown on failure.
200 */
201 basic_socket(const executor_type& ex, const endpoint_type& endpoint)
202 : impl_(0, ex)
203 {
204 boost::system::error_code ec;
205 const protocol_type protocol = endpoint.protocol();
206 impl_.get_service().open(impl_.get_implementation(), protocol, ec);
207 boost::asio::detail::throw_error(ec, "open");
208 impl_.get_service().bind(impl_.get_implementation(), endpoint, ec);
209 boost::asio::detail::throw_error(ec, "bind");
210 }
211
212 /// Construct a basic_socket, opening it and binding it to the given local
213 /// endpoint.
214 /**
215 * This constructor creates a socket and automatically opens it bound to the
216 * specified endpoint on the local machine. The protocol used is the protocol
217 * associated with the given endpoint.
218 *
219 * @param context An execution context which provides the I/O executor that
220 * the socket will use, by default, to dispatch handlers for any asynchronous
221 * operations performed on the socket.
222 *
223 * @param endpoint An endpoint on the local machine to which the socket will
224 * be bound.
225 *
226 * @throws boost::system::system_error Thrown on failure.
227 */
228 template <typename ExecutionContext>
229 basic_socket(ExecutionContext& context, const endpoint_type& endpoint,
230 constraint_t<
231 is_convertible<ExecutionContext&, execution_context&>::value
232 > = 0)
233 : impl_(0, 0, context)
234 {
235 boost::system::error_code ec;
236 const protocol_type protocol = endpoint.protocol();
237 impl_.get_service().open(impl_.get_implementation(), protocol, ec);
238 boost::asio::detail::throw_error(ec, "open");
239 impl_.get_service().bind(impl_.get_implementation(), endpoint, ec);
240 boost::asio::detail::throw_error(ec, "bind");
241 }
242
243 /// Construct a basic_socket on an existing native socket.
244 /**
245 * This constructor creates a socket object to hold an existing native socket.
246 *
247 * @param ex The I/O executor that the socket will use, by default, to
248 * dispatch handlers for any asynchronous operations performed on the socket.
249 *
250 * @param protocol An object specifying protocol parameters to be used.
251 *
252 * @param native_socket A native socket.
253 *
254 * @throws boost::system::system_error Thrown on failure.
255 */
256 basic_socket(const executor_type& ex, const protocol_type& protocol,
257 const native_handle_type& native_socket)
258 : impl_(0, ex)
259 {
260 boost::system::error_code ec;
261 impl_.get_service().assign(impl_.get_implementation(),
262 protocol, native_socket, ec);
263 boost::asio::detail::throw_error(ec, "assign");
264 }
265
266 /// Construct a basic_socket on an existing native socket.
267 /**
268 * This constructor creates a socket object to hold an existing native socket.
269 *
270 * @param context An execution context which provides the I/O executor that
271 * the socket will use, by default, to dispatch handlers for any asynchronous
272 * operations performed on the socket.
273 *
274 * @param protocol An object specifying protocol parameters to be used.
275 *
276 * @param native_socket A native socket.
277 *
278 * @throws boost::system::system_error Thrown on failure.
279 */
280 template <typename ExecutionContext>
281 basic_socket(ExecutionContext& context, const protocol_type& protocol,
282 const native_handle_type& native_socket,
283 constraint_t<
284 is_convertible<ExecutionContext&, execution_context&>::value
285 > = 0)
286 : impl_(0, 0, context)
287 {
288 boost::system::error_code ec;
289 impl_.get_service().assign(impl_.get_implementation(),
290 protocol, native_socket, ec);
291 boost::asio::detail::throw_error(ec, "assign");
292 }
293
294 /// Move-construct a basic_socket from another.
295 /**
296 * This constructor moves a socket from one object to another.
297 *
298 * @param other The other basic_socket object from which the move will
299 * occur.
300 *
301 * @note Following the move, the moved-from object is in the same state as if
302 * constructed using the @c basic_socket(const executor_type&) constructor.
303 */
304 basic_socket(basic_socket&& other) noexcept
305 : impl_(std::move(other.impl_))
306 {
307 }
308
309 /// Move-assign a basic_socket from another.
310 /**
311 * This assignment operator moves a socket from one object to another.
312 *
313 * @param other The other basic_socket object from which the move will
314 * occur.
315 *
316 * @note Following the move, the moved-from object is in the same state as if
317 * constructed using the @c basic_socket(const executor_type&) constructor.
318 */
319 basic_socket& operator=(basic_socket&& other)
320 {
321 impl_ = std::move(other.impl_);
322 return *this;
323 }
324
325 // All sockets have access to each other's implementations.
326 template <typename Protocol1, typename Executor1>
327 friend class basic_socket;
328
329 /// Move-construct a basic_socket from a socket of another protocol type.
330 /**
331 * This constructor moves a socket from one object to another.
332 *
333 * @param other The other basic_socket object from which the move will
334 * occur.
335 *
336 * @note Following the move, the moved-from object is in the same state as if
337 * constructed using the @c basic_socket(const executor_type&) constructor.
338 */
339 template <typename Protocol1, typename Executor1>
340 basic_socket(basic_socket<Protocol1, Executor1>&& other,
341 constraint_t<
342 is_convertible<Protocol1, Protocol>::value
343 && is_convertible<Executor1, Executor>::value
344 > = 0)
345 : impl_(std::move(other.impl_))
346 {
347 }
348
349 /// Move-assign a basic_socket from a socket of another protocol type.
350 /**
351 * This assignment operator moves a socket from one object to another.
352 *
353 * @param other The other basic_socket object from which the move will
354 * occur.
355 *
356 * @note Following the move, the moved-from object is in the same state as if
357 * constructed using the @c basic_socket(const executor_type&) constructor.
358 */
359 template <typename Protocol1, typename Executor1>
360 constraint_t<
361 is_convertible<Protocol1, Protocol>::value
362 && is_convertible<Executor1, Executor>::value,
363 basic_socket&
364 > operator=(basic_socket<Protocol1, Executor1>&& other)
365 {
366 basic_socket tmp(std::move(other));
367 impl_ = std::move(tmp.impl_);
368 return *this;
369 }
370
371 /// Get the executor associated with the object.
372 const executor_type& get_executor() noexcept
373 {
374 return impl_.get_executor();
375 }
376
377#if !defined(BOOST_ASIO_NO_EXTENSIONS)
378 /// Get a reference to the lowest layer.
379 /**
380 * This function returns a reference to the lowest layer in a stack of
381 * layers. Since a basic_socket cannot contain any further layers, it simply
382 * returns a reference to itself.
383 *
384 * @return A reference to the lowest layer in the stack of layers. Ownership
385 * is not transferred to the caller.
386 */
387 lowest_layer_type& lowest_layer()
388 {
389 return *this;
390 }
391
392 /// Get a const reference to the lowest layer.
393 /**
394 * This function returns a const reference to the lowest layer in a stack of
395 * layers. Since a basic_socket cannot contain any further layers, it simply
396 * returns a reference to itself.
397 *
398 * @return A const reference to the lowest layer in the stack of layers.
399 * Ownership is not transferred to the caller.
400 */
401 const lowest_layer_type& lowest_layer() const
402 {
403 return *this;
404 }
405#endif // !defined(BOOST_ASIO_NO_EXTENSIONS)
406
407 /// Open the socket using the specified protocol.
408 /**
409 * This function opens the socket so that it will use the specified protocol.
410 *
411 * @param protocol An object specifying protocol parameters to be used.
412 *
413 * @throws boost::system::system_error Thrown on failure.
414 *
415 * @par Example
416 * @code
417 * boost::asio::ip::tcp::socket socket(my_context);
418 * socket.open(boost::asio::ip::tcp::v4());
419 * @endcode
420 */
421 void open(const protocol_type& protocol = protocol_type())
422 {
423 boost::system::error_code ec;
424 impl_.get_service().open(impl_.get_implementation(), protocol, ec);
425 boost::asio::detail::throw_error(ec, "open");
426 }
427
428 /// Open the socket using the specified protocol.
429 /**
430 * This function opens the socket so that it will use the specified protocol.
431 *
432 * @param protocol An object specifying which protocol is to be used.
433 *
434 * @param ec Set to indicate what error occurred, if any.
435 *
436 * @par Example
437 * @code
438 * boost::asio::ip::tcp::socket socket(my_context);
439 * boost::system::error_code ec;
440 * socket.open(boost::asio::ip::tcp::v4(), ec);
441 * if (ec)
442 * {
443 * // An error occurred.
444 * }
445 * @endcode
446 */
447 BOOST_ASIO_SYNC_OP_VOIDboost::system::error_code open(const protocol_type& protocol,
448 boost::system::error_code& ec)
449 {
450 impl_.get_service().open(impl_.get_implementation(), protocol, ec);
451 BOOST_ASIO_SYNC_OP_VOID_RETURN(ec)return ec;
452 }
453
454 /// Assign an existing native socket to the socket.
455 /*
456 * This function opens the socket to hold an existing native socket.
457 *
458 * @param protocol An object specifying which protocol is to be used.
459 *
460 * @param native_socket A native socket.
461 *
462 * @throws boost::system::system_error Thrown on failure.
463 */
464 void assign(const protocol_type& protocol,
465 const native_handle_type& native_socket)
466 {
467 boost::system::error_code ec;
468 impl_.get_service().assign(impl_.get_implementation(),
469 protocol, native_socket, ec);
470 boost::asio::detail::throw_error(ec, "assign");
471 }
472
473 /// Assign an existing native socket to the socket.
474 /*
475 * This function opens the socket to hold an existing native socket.
476 *
477 * @param protocol An object specifying which protocol is to be used.
478 *
479 * @param native_socket A native socket.
480 *
481 * @param ec Set to indicate what error occurred, if any.
482 */
483 BOOST_ASIO_SYNC_OP_VOIDboost::system::error_code assign(const protocol_type& protocol,
484 const native_handle_type& native_socket, boost::system::error_code& ec)
485 {
486 impl_.get_service().assign(impl_.get_implementation(),
487 protocol, native_socket, ec);
488 BOOST_ASIO_SYNC_OP_VOID_RETURN(ec)return ec;
489 }
490
491 /// Determine whether the socket is open.
492 bool is_open() const
493 {
494 return impl_.get_service().is_open(impl_.get_implementation());
495 }
496
497 /// Close the socket.
498 /**
499 * This function is used to close the socket. Any asynchronous send, receive
500 * or connect operations will be cancelled immediately, and will complete
501 * with the boost::asio::error::operation_aborted error.
502 *
503 * @throws boost::system::system_error Thrown on failure. Note that, even if
504 * the function indicates an error, the underlying descriptor is closed.
505 *
506 * @note For portable behaviour with respect to graceful closure of a
507 * connected socket, call shutdown() before closing the socket.
508 */
509 void close()
510 {
511 boost::system::error_code ec;
512 impl_.get_service().close(impl_.get_implementation(), ec);
513 boost::asio::detail::throw_error(ec, "close");
514 }
515
516 /// Close the socket.
517 /**
518 * This function is used to close the socket. Any asynchronous send, receive
519 * or connect operations will be cancelled immediately, and will complete
520 * with the boost::asio::error::operation_aborted error.
521 *
522 * @param ec Set to indicate what error occurred, if any. Note that, even if
523 * the function indicates an error, the underlying descriptor is closed.
524 *
525 * @par Example
526 * @code
527 * boost::asio::ip::tcp::socket socket(my_context);
528 * ...
529 * boost::system::error_code ec;
530 * socket.close(ec);
531 * if (ec)
532 * {
533 * // An error occurred.
534 * }
535 * @endcode
536 *
537 * @note For portable behaviour with respect to graceful closure of a
538 * connected socket, call shutdown() before closing the socket.
539 */
540 BOOST_ASIO_SYNC_OP_VOIDboost::system::error_code close(boost::system::error_code& ec)
541 {
542 impl_.get_service().close(impl_.get_implementation(), ec);
543 BOOST_ASIO_SYNC_OP_VOID_RETURN(ec)return ec;
544 }
545
546 /// Release ownership of the underlying native socket.
547 /**
548 * This function causes all outstanding asynchronous connect, send and receive
549 * operations to finish immediately, and the handlers for cancelled operations
550 * will be passed the boost::asio::error::operation_aborted error. Ownership
551 * of the native socket is then transferred to the caller.
552 *
553 * @throws boost::system::system_error Thrown on failure.
554 *
555 * @note This function is unsupported on Windows versions prior to Windows
556 * 8.1, and will fail with boost::asio::error::operation_not_supported on
557 * these platforms.
558 */
559#if defined(BOOST_ASIO_MSVC) && (BOOST_ASIO_MSVC >= 1400) \
560 && (!defined(_WIN32_WINNT) || _WIN32_WINNT < 0x0603)
561 __declspec(deprecated("This function always fails with "
562 "operation_not_supported when used on Windows versions "
563 "prior to Windows 8.1."))
564#endif
565 native_handle_type release()
566 {
567 boost::system::error_code ec;
568 native_handle_type s = impl_.get_service().release(
569 impl_.get_implementation(), ec);
570 boost::asio::detail::throw_error(ec, "release");
571 return s;
572 }
573
574 /// Release ownership of the underlying native socket.
575 /**
576 * This function causes all outstanding asynchronous connect, send and receive
577 * operations to finish immediately, and the handlers for cancelled operations
578 * will be passed the boost::asio::error::operation_aborted error. Ownership
579 * of the native socket is then transferred to the caller.
580 *
581 * @param ec Set to indicate what error occurred, if any.
582 *
583 * @note This function is unsupported on Windows versions prior to Windows
584 * 8.1, and will fail with boost::asio::error::operation_not_supported on
585 * these platforms.
586 */
587#if defined(BOOST_ASIO_MSVC) && (BOOST_ASIO_MSVC >= 1400) \
588 && (!defined(_WIN32_WINNT) || _WIN32_WINNT < 0x0603)
589 __declspec(deprecated("This function always fails with "
590 "operation_not_supported when used on Windows versions "
591 "prior to Windows 8.1."))
592#endif
593 native_handle_type release(boost::system::error_code& ec)
594 {
595 return impl_.get_service().release(impl_.get_implementation(), ec);
596 }
597
598 /// Get the native socket representation.
599 /**
600 * This function may be used to obtain the underlying representation of the
601 * socket. This is intended to allow access to native socket functionality
602 * that is not otherwise provided.
603 */
604 native_handle_type native_handle()
605 {
606 return impl_.get_service().native_handle(impl_.get_implementation());
607 }
608
609 /// Cancel all asynchronous operations associated with the socket.
610 /**
611 * This function causes all outstanding asynchronous connect, send and receive
612 * operations to finish immediately, and the handlers for cancelled operations
613 * will be passed the boost::asio::error::operation_aborted error.
614 *
615 * @throws boost::system::system_error Thrown on failure.
616 *
617 * @note Calls to cancel() will always fail with
618 * boost::asio::error::operation_not_supported when run on Windows XP, Windows
619 * Server 2003, and earlier versions of Windows, unless
620 * BOOST_ASIO_ENABLE_CANCELIO is defined. However, the CancelIo function has
621 * two issues that should be considered before enabling its use:
622 *
623 * @li It will only cancel asynchronous operations that were initiated in the
624 * current thread.
625 *
626 * @li It can appear to complete without error, but the request to cancel the
627 * unfinished operations may be silently ignored by the operating system.
628 * Whether it works or not seems to depend on the drivers that are installed.
629 *
630 * For portable cancellation, consider using one of the following
631 * alternatives:
632 *
633 * @li Disable asio's I/O completion port backend by defining
634 * BOOST_ASIO_DISABLE_IOCP.
635 *
636 * @li Use the close() function to simultaneously cancel the outstanding
637 * operations and close the socket.
638 *
639 * When running on Windows Vista, Windows Server 2008, and later, the
640 * CancelIoEx function is always used. This function does not have the
641 * problems described above.
642 */
643#if defined(BOOST_ASIO_MSVC) && (BOOST_ASIO_MSVC >= 1400) \
644 && (!defined(_WIN32_WINNT) || _WIN32_WINNT < 0x0600) \
645 && !defined(BOOST_ASIO_ENABLE_CANCELIO)
646 __declspec(deprecated("By default, this function always fails with "
647 "operation_not_supported when used on Windows XP, Windows Server 2003, "
648 "or earlier. Consult documentation for details."))
649#endif
650 void cancel()
651 {
652 boost::system::error_code ec;
653 impl_.get_service().cancel(impl_.get_implementation(), ec);
654 boost::asio::detail::throw_error(ec, "cancel");
655 }
656
657 /// Cancel all asynchronous operations associated with the socket.
658 /**
659 * This function causes all outstanding asynchronous connect, send and receive
660 * operations to finish immediately, and the handlers for cancelled operations
661 * will be passed the boost::asio::error::operation_aborted error.
662 *
663 * @param ec Set to indicate what error occurred, if any.
664 *
665 * @note Calls to cancel() will always fail with
666 * boost::asio::error::operation_not_supported when run on Windows XP, Windows
667 * Server 2003, and earlier versions of Windows, unless
668 * BOOST_ASIO_ENABLE_CANCELIO is defined. However, the CancelIo function has
669 * two issues that should be considered before enabling its use:
670 *
671 * @li It will only cancel asynchronous operations that were initiated in the
672 * current thread.
673 *
674 * @li It can appear to complete without error, but the request to cancel the
675 * unfinished operations may be silently ignored by the operating system.
676 * Whether it works or not seems to depend on the drivers that are installed.
677 *
678 * For portable cancellation, consider using one of the following
679 * alternatives:
680 *
681 * @li Disable asio's I/O completion port backend by defining
682 * BOOST_ASIO_DISABLE_IOCP.
683 *
684 * @li Use the close() function to simultaneously cancel the outstanding
685 * operations and close the socket.
686 *
687 * When running on Windows Vista, Windows Server 2008, and later, the
688 * CancelIoEx function is always used. This function does not have the
689 * problems described above.
690 */
691#if defined(BOOST_ASIO_MSVC) && (BOOST_ASIO_MSVC >= 1400) \
692 && (!defined(_WIN32_WINNT) || _WIN32_WINNT < 0x0600) \
693 && !defined(BOOST_ASIO_ENABLE_CANCELIO)
694 __declspec(deprecated("By default, this function always fails with "
695 "operation_not_supported when used on Windows XP, Windows Server 2003, "
696 "or earlier. Consult documentation for details."))
697#endif
698 BOOST_ASIO_SYNC_OP_VOIDboost::system::error_code cancel(boost::system::error_code& ec)
699 {
700 impl_.get_service().cancel(impl_.get_implementation(), ec);
701 BOOST_ASIO_SYNC_OP_VOID_RETURN(ec)return ec;
702 }
703
704 /// Determine whether the socket is at the out-of-band data mark.
705 /**
706 * This function is used to check whether the socket input is currently
707 * positioned at the out-of-band data mark.
708 *
709 * @return A bool indicating whether the socket is at the out-of-band data
710 * mark.
711 *
712 * @throws boost::system::system_error Thrown on failure.
713 */
714 bool at_mark() const
715 {
716 boost::system::error_code ec;
717 bool b = impl_.get_service().at_mark(impl_.get_implementation(), ec);
718 boost::asio::detail::throw_error(ec, "at_mark");
719 return b;
720 }
721
722 /// Determine whether the socket is at the out-of-band data mark.
723 /**
724 * This function is used to check whether the socket input is currently
725 * positioned at the out-of-band data mark.
726 *
727 * @param ec Set to indicate what error occurred, if any.
728 *
729 * @return A bool indicating whether the socket is at the out-of-band data
730 * mark.
731 */
732 bool at_mark(boost::system::error_code& ec) const
733 {
734 return impl_.get_service().at_mark(impl_.get_implementation(), ec);
735 }
736
737 /// Determine the number of bytes available for reading.
738 /**
739 * This function is used to determine the number of bytes that may be read
740 * without blocking.
741 *
742 * @return The number of bytes that may be read without blocking, or 0 if an
743 * error occurs.
744 *
745 * @throws boost::system::system_error Thrown on failure.
746 */
747 std::size_t available() const
748 {
749 boost::system::error_code ec;
750 std::size_t s = impl_.get_service().available(
751 impl_.get_implementation(), ec);
752 boost::asio::detail::throw_error(ec, "available");
753 return s;
754 }
755
756 /// Determine the number of bytes available for reading.
757 /**
758 * This function is used to determine the number of bytes that may be read
759 * without blocking.
760 *
761 * @param ec Set to indicate what error occurred, if any.
762 *
763 * @return The number of bytes that may be read without blocking, or 0 if an
764 * error occurs.
765 */
766 std::size_t available(boost::system::error_code& ec) const
767 {
768 return impl_.get_service().available(impl_.get_implementation(), ec);
769 }
770
771 /// Bind the socket to the given local endpoint.
772 /**
773 * This function binds the socket to the specified endpoint on the local
774 * machine.
775 *
776 * @param endpoint An endpoint on the local machine to which the socket will
777 * be bound.
778 *
779 * @throws boost::system::system_error Thrown on failure.
780 *
781 * @par Example
782 * @code
783 * boost::asio::ip::tcp::socket socket(my_context);
784 * socket.open(boost::asio::ip::tcp::v4());
785 * socket.bind(boost::asio::ip::tcp::endpoint(
786 * boost::asio::ip::tcp::v4(), 12345));
787 * @endcode
788 */
789 void bind(const endpoint_type& endpoint)
790 {
791 boost::system::error_code ec;
792 impl_.get_service().bind(impl_.get_implementation(), endpoint, ec);
793 boost::asio::detail::throw_error(ec, "bind");
794 }
795
796 /// Bind the socket to the given local endpoint.
797 /**
798 * This function binds the socket to the specified endpoint on the local
799 * machine.
800 *
801 * @param endpoint An endpoint on the local machine to which the socket will
802 * be bound.
803 *
804 * @param ec Set to indicate what error occurred, if any.
805 *
806 * @par Example
807 * @code
808 * boost::asio::ip::tcp::socket socket(my_context);
809 * socket.open(boost::asio::ip::tcp::v4());
810 * boost::system::error_code ec;
811 * socket.bind(boost::asio::ip::tcp::endpoint(
812 * boost::asio::ip::tcp::v4(), 12345), ec);
813 * if (ec)
814 * {
815 * // An error occurred.
816 * }
817 * @endcode
818 */
819 BOOST_ASIO_SYNC_OP_VOIDboost::system::error_code bind(const endpoint_type& endpoint,
820 boost::system::error_code& ec)
821 {
822 impl_.get_service().bind(impl_.get_implementation(), endpoint, ec);
823 BOOST_ASIO_SYNC_OP_VOID_RETURN(ec)return ec;
824 }
825
826 /// Connect the socket to the specified endpoint.
827 /**
828 * This function is used to connect a socket to the specified remote endpoint.
829 * The function call will block until the connection is successfully made or
830 * an error occurs.
831 *
832 * The socket is automatically opened if it is not already open. If the
833 * connect fails, and the socket was automatically opened, the socket is
834 * not returned to the closed state.
835 *
836 * @param peer_endpoint The remote endpoint to which the socket will be
837 * connected.
838 *
839 * @throws boost::system::system_error Thrown on failure.
840 *
841 * @par Example
842 * @code
843 * boost::asio::ip::tcp::socket socket(my_context);
844 * boost::asio::ip::tcp::endpoint endpoint(
845 * boost::asio::ip::address::from_string("1.2.3.4"), 12345);
846 * socket.connect(endpoint);
847 * @endcode
848 */
849 void connect(const endpoint_type& peer_endpoint)
850 {
851 boost::system::error_code ec;
852 if (!is_open())
853 {
854 impl_.get_service().open(impl_.get_implementation(),
855 peer_endpoint.protocol(), ec);
856 boost::asio::detail::throw_error(ec, "connect");
857 }
858 impl_.get_service().connect(impl_.get_implementation(), peer_endpoint, ec);
859 boost::asio::detail::throw_error(ec, "connect");
860 }
861
862 /// Connect the socket to the specified endpoint.
863 /**
864 * This function is used to connect a socket to the specified remote endpoint.
865 * The function call will block until the connection is successfully made or
866 * an error occurs.
867 *
868 * The socket is automatically opened if it is not already open. If the
869 * connect fails, and the socket was automatically opened, the socket is
870 * not returned to the closed state.
871 *
872 * @param peer_endpoint The remote endpoint to which the socket will be
873 * connected.
874 *
875 * @param ec Set to indicate what error occurred, if any.
876 *
877 * @par Example
878 * @code
879 * boost::asio::ip::tcp::socket socket(my_context);
880 * boost::asio::ip::tcp::endpoint endpoint(
881 * boost::asio::ip::address::from_string("1.2.3.4"), 12345);
882 * boost::system::error_code ec;
883 * socket.connect(endpoint, ec);
884 * if (ec)
885 * {
886 * // An error occurred.
887 * }
888 * @endcode
889 */
890 BOOST_ASIO_SYNC_OP_VOIDboost::system::error_code connect(const endpoint_type& peer_endpoint,
891 boost::system::error_code& ec)
892 {
893 if (!is_open())
894 {
895 impl_.get_service().open(impl_.get_implementation(),
896 peer_endpoint.protocol(), ec);
897 if (ec)
898 {
899 BOOST_ASIO_SYNC_OP_VOID_RETURN(ec)return ec;
900 }
901 }
902
903 impl_.get_service().connect(impl_.get_implementation(), peer_endpoint, ec);
904 BOOST_ASIO_SYNC_OP_VOID_RETURN(ec)return ec;
905 }
906
907 /// Start an asynchronous connect.
908 /**
909 * This function is used to asynchronously connect a socket to the specified
910 * remote endpoint. It is an initiating function for an @ref
911 * asynchronous_operation, and always returns immediately.
912 *
913 * The socket is automatically opened if it is not already open. If the
914 * connect fails, and the socket was automatically opened, the socket is
915 * not returned to the closed state.
916 *
917 * @param peer_endpoint The remote endpoint to which the socket will be
918 * connected. Copies will be made of the endpoint object as required.
919 *
920 * @param token The @ref completion_token that will be used to produce a
921 * completion handler, which will be called when the connect completes.
922 * Potential completion tokens include @ref use_future, @ref use_awaitable,
923 * @ref yield_context, or a function object with the correct completion
924 * signature. The function signature of the completion handler must be:
925 * @code void handler(
926 * const boost::system::error_code& error // Result of operation.
927 * ); @endcode
928 * Regardless of whether the asynchronous operation completes immediately or
929 * not, the completion handler will not be invoked from within this function.
930 * On immediate completion, invocation of the handler will be performed in a
931 * manner equivalent to using boost::asio::async_immediate().
932 *
933 * @par Completion Signature
934 * @code void(boost::system::error_code) @endcode
935 *
936 * @par Example
937 * @code
938 * void connect_handler(const boost::system::error_code& error)
939 * {
940 * if (!error)
941 * {
942 * // Connect succeeded.
943 * }
944 * }
945 *
946 * ...
947 *
948 * boost::asio::ip::tcp::socket socket(my_context);
949 * boost::asio::ip::tcp::endpoint endpoint(
950 * boost::asio::ip::address::from_string("1.2.3.4"), 12345);
951 * socket.async_connect(endpoint, connect_handler);
952 * @endcode
953 *
954 * @par Per-Operation Cancellation
955 * On POSIX or Windows operating systems, this asynchronous operation supports
956 * cancellation for the following boost::asio::cancellation_type values:
957 *
958 * @li @c cancellation_type::terminal
959 *
960 * @li @c cancellation_type::partial
961 *
962 * @li @c cancellation_type::total
963 */
964 template <
965 BOOST_ASIO_COMPLETION_TOKEN_FOR(void (boost::system::error_code))typename
966 ConnectToken = default_completion_token_t<executor_type>>
967 auto async_connect(const endpoint_type& peer_endpoint,
968 ConnectToken&& token = default_completion_token_t<executor_type>())
969 -> decltype(
970 async_initiate<ConnectToken, void (boost::system::error_code)>(
971 declval<initiate_async_connect>(), token,
972 peer_endpoint, declval<boost::system::error_code&>()))
973 {
974 boost::system::error_code open_ec;
975 if (!is_open())
976 {
977 const protocol_type protocol = peer_endpoint.protocol();
978 impl_.get_service().open(impl_.get_implementation(), protocol, open_ec);
979 }
980
981 return async_initiate<ConnectToken, void (boost::system::error_code)>(
982 initiate_async_connect(this), token, peer_endpoint, open_ec);
983 }
984
985 /// Set an option on the socket.
986 /**
987 * This function is used to set an option on the socket.
988 *
989 * @param option The new option value to be set on the socket.
990 *
991 * @throws boost::system::system_error Thrown on failure.
992 *
993 * @sa SettableSocketOption @n
994 * boost::asio::socket_base::broadcast @n
995 * boost::asio::socket_base::do_not_route @n
996 * boost::asio::socket_base::keep_alive @n
997 * boost::asio::socket_base::linger @n
998 * boost::asio::socket_base::receive_buffer_size @n
999 * boost::asio::socket_base::receive_low_watermark @n
1000 * boost::asio::socket_base::reuse_address @n
1001 * boost::asio::socket_base::send_buffer_size @n
1002 * boost::asio::socket_base::send_low_watermark @n
1003 * boost::asio::ip::multicast::join_group @n
1004 * boost::asio::ip::multicast::leave_group @n
1005 * boost::asio::ip::multicast::enable_loopback @n
1006 * boost::asio::ip::multicast::outbound_interface @n
1007 * boost::asio::ip::multicast::hops @n
1008 * boost::asio::ip::tcp::no_delay
1009 *
1010 * @par Example
1011 * Setting the IPPROTO_TCP/TCP_NODELAY option:
1012 * @code
1013 * boost::asio::ip::tcp::socket socket(my_context);
1014 * ...
1015 * boost::asio::ip::tcp::no_delay option(true);
1016 * socket.set_option(option);
1017 * @endcode
1018 */
1019 template <typename SettableSocketOption>
1020 void set_option(const SettableSocketOption& option)
1021 {
1022 boost::system::error_code ec;
1023 impl_.get_service().set_option(impl_.get_implementation(), option, ec);
1024 boost::asio::detail::throw_error(ec, "set_option");
1025 }
1026
1027 /// Set an option on the socket.
1028 /**
1029 * This function is used to set an option on the socket.
1030 *
1031 * @param option The new option value to be set on the socket.
1032 *
1033 * @param ec Set to indicate what error occurred, if any.
1034 *
1035 * @sa SettableSocketOption @n
1036 * boost::asio::socket_base::broadcast @n
1037 * boost::asio::socket_base::do_not_route @n
1038 * boost::asio::socket_base::keep_alive @n
1039 * boost::asio::socket_base::linger @n
1040 * boost::asio::socket_base::receive_buffer_size @n
1041 * boost::asio::socket_base::receive_low_watermark @n
1042 * boost::asio::socket_base::reuse_address @n
1043 * boost::asio::socket_base::send_buffer_size @n
1044 * boost::asio::socket_base::send_low_watermark @n
1045 * boost::asio::ip::multicast::join_group @n
1046 * boost::asio::ip::multicast::leave_group @n
1047 * boost::asio::ip::multicast::enable_loopback @n
1048 * boost::asio::ip::multicast::outbound_interface @n
1049 * boost::asio::ip::multicast::hops @n
1050 * boost::asio::ip::tcp::no_delay
1051 *
1052 * @par Example
1053 * Setting the IPPROTO_TCP/TCP_NODELAY option:
1054 * @code
1055 * boost::asio::ip::tcp::socket socket(my_context);
1056 * ...
1057 * boost::asio::ip::tcp::no_delay option(true);
1058 * boost::system::error_code ec;
1059 * socket.set_option(option, ec);
1060 * if (ec)
1061 * {
1062 * // An error occurred.
1063 * }
1064 * @endcode
1065 */
1066 template <typename SettableSocketOption>
1067 BOOST_ASIO_SYNC_OP_VOIDboost::system::error_code set_option(const SettableSocketOption& option,
1068 boost::system::error_code& ec)
1069 {
1070 impl_.get_service().set_option(impl_.get_implementation(), option, ec);
1071 BOOST_ASIO_SYNC_OP_VOID_RETURN(ec)return ec;
1072 }
1073
1074 /// Get an option from the socket.
1075 /**
1076 * This function is used to get the current value of an option on the socket.
1077 *
1078 * @param option The option value to be obtained from the socket.
1079 *
1080 * @throws boost::system::system_error Thrown on failure.
1081 *
1082 * @sa GettableSocketOption @n
1083 * boost::asio::socket_base::broadcast @n
1084 * boost::asio::socket_base::do_not_route @n
1085 * boost::asio::socket_base::keep_alive @n
1086 * boost::asio::socket_base::linger @n
1087 * boost::asio::socket_base::receive_buffer_size @n
1088 * boost::asio::socket_base::receive_low_watermark @n
1089 * boost::asio::socket_base::reuse_address @n
1090 * boost::asio::socket_base::send_buffer_size @n
1091 * boost::asio::socket_base::send_low_watermark @n
1092 * boost::asio::ip::multicast::join_group @n
1093 * boost::asio::ip::multicast::leave_group @n
1094 * boost::asio::ip::multicast::enable_loopback @n
1095 * boost::asio::ip::multicast::outbound_interface @n
1096 * boost::asio::ip::multicast::hops @n
1097 * boost::asio::ip::tcp::no_delay
1098 *
1099 * @par Example
1100 * Getting the value of the SOL_SOCKET/SO_KEEPALIVE option:
1101 * @code
1102 * boost::asio::ip::tcp::socket socket(my_context);
1103 * ...
1104 * boost::asio::ip::tcp::socket::keep_alive option;
1105 * socket.get_option(option);
1106 * bool is_set = option.value();
1107 * @endcode
1108 */
1109 template <typename GettableSocketOption>
1110 void get_option(GettableSocketOption& option) const
1111 {
1112 boost::system::error_code ec;
1113 impl_.get_service().get_option(impl_.get_implementation(), option, ec);
1114 boost::asio::detail::throw_error(ec, "get_option");
1115 }
1116
1117 /// Get an option from the socket.
1118 /**
1119 * This function is used to get the current value of an option on the socket.
1120 *
1121 * @param option The option value to be obtained from the socket.
1122 *
1123 * @param ec Set to indicate what error occurred, if any.
1124 *
1125 * @sa GettableSocketOption @n
1126 * boost::asio::socket_base::broadcast @n
1127 * boost::asio::socket_base::do_not_route @n
1128 * boost::asio::socket_base::keep_alive @n
1129 * boost::asio::socket_base::linger @n
1130 * boost::asio::socket_base::receive_buffer_size @n
1131 * boost::asio::socket_base::receive_low_watermark @n
1132 * boost::asio::socket_base::reuse_address @n
1133 * boost::asio::socket_base::send_buffer_size @n
1134 * boost::asio::socket_base::send_low_watermark @n
1135 * boost::asio::ip::multicast::join_group @n
1136 * boost::asio::ip::multicast::leave_group @n
1137 * boost::asio::ip::multicast::enable_loopback @n
1138 * boost::asio::ip::multicast::outbound_interface @n
1139 * boost::asio::ip::multicast::hops @n
1140 * boost::asio::ip::tcp::no_delay
1141 *
1142 * @par Example
1143 * Getting the value of the SOL_SOCKET/SO_KEEPALIVE option:
1144 * @code
1145 * boost::asio::ip::tcp::socket socket(my_context);
1146 * ...
1147 * boost::asio::ip::tcp::socket::keep_alive option;
1148 * boost::system::error_code ec;
1149 * socket.get_option(option, ec);
1150 * if (ec)
1151 * {
1152 * // An error occurred.
1153 * }
1154 * bool is_set = option.value();
1155 * @endcode
1156 */
1157 template <typename GettableSocketOption>
1158 BOOST_ASIO_SYNC_OP_VOIDboost::system::error_code get_option(GettableSocketOption& option,
1159 boost::system::error_code& ec) const
1160 {
1161 impl_.get_service().get_option(impl_.get_implementation(), option, ec);
1162 BOOST_ASIO_SYNC_OP_VOID_RETURN(ec)return ec;
1163 }
1164
1165 /// Perform an IO control command on the socket.
1166 /**
1167 * This function is used to execute an IO control command on the socket.
1168 *
1169 * @param command The IO control command to be performed on the socket.
1170 *
1171 * @throws boost::system::system_error Thrown on failure.
1172 *
1173 * @sa IoControlCommand @n
1174 * boost::asio::socket_base::bytes_readable @n
1175 * boost::asio::socket_base::non_blocking_io
1176 *
1177 * @par Example
1178 * Getting the number of bytes ready to read:
1179 * @code
1180 * boost::asio::ip::tcp::socket socket(my_context);
1181 * ...
1182 * boost::asio::ip::tcp::socket::bytes_readable command;
1183 * socket.io_control(command);
1184 * std::size_t bytes_readable = command.get();
1185 * @endcode
1186 */
1187 template <typename IoControlCommand>
1188 void io_control(IoControlCommand& command)
1189 {
1190 boost::system::error_code ec;
1191 impl_.get_service().io_control(impl_.get_implementation(), command, ec);
1192 boost::asio::detail::throw_error(ec, "io_control");
1193 }
1194
1195 /// Perform an IO control command on the socket.
1196 /**
1197 * This function is used to execute an IO control command on the socket.
1198 *
1199 * @param command The IO control command to be performed on the socket.
1200 *
1201 * @param ec Set to indicate what error occurred, if any.
1202 *
1203 * @sa IoControlCommand @n
1204 * boost::asio::socket_base::bytes_readable @n
1205 * boost::asio::socket_base::non_blocking_io
1206 *
1207 * @par Example
1208 * Getting the number of bytes ready to read:
1209 * @code
1210 * boost::asio::ip::tcp::socket socket(my_context);
1211 * ...
1212 * boost::asio::ip::tcp::socket::bytes_readable command;
1213 * boost::system::error_code ec;
1214 * socket.io_control(command, ec);
1215 * if (ec)
1216 * {
1217 * // An error occurred.
1218 * }
1219 * std::size_t bytes_readable = command.get();
1220 * @endcode
1221 */
1222 template <typename IoControlCommand>
1223 BOOST_ASIO_SYNC_OP_VOIDboost::system::error_code io_control(IoControlCommand& command,
1224 boost::system::error_code& ec)
1225 {
1226 impl_.get_service().io_control(impl_.get_implementation(), command, ec);
1227 BOOST_ASIO_SYNC_OP_VOID_RETURN(ec)return ec;
1228 }
1229
1230 /// Gets the non-blocking mode of the socket.
1231 /**
1232 * @returns @c true if the socket's synchronous operations will fail with
1233 * boost::asio::error::would_block if they are unable to perform the requested
1234 * operation immediately. If @c false, synchronous operations will block
1235 * until complete.
1236 *
1237 * @note The non-blocking mode has no effect on the behaviour of asynchronous
1238 * operations. Asynchronous operations will never fail with the error
1239 * boost::asio::error::would_block.
1240 */
1241 bool non_blocking() const
1242 {
1243 return impl_.get_service().non_blocking(impl_.get_implementation());
1244 }
1245
1246 /// Sets the non-blocking mode of the socket.
1247 /**
1248 * @param mode If @c true, the socket's synchronous operations will fail with
1249 * boost::asio::error::would_block if they are unable to perform the requested
1250 * operation immediately. If @c false, synchronous operations will block
1251 * until complete.
1252 *
1253 * @throws boost::system::system_error Thrown on failure.
1254 *
1255 * @note The non-blocking mode has no effect on the behaviour of asynchronous
1256 * operations. Asynchronous operations will never fail with the error
1257 * boost::asio::error::would_block.
1258 */
1259 void non_blocking(bool mode)
1260 {
1261 boost::system::error_code ec;
1262 impl_.get_service().non_blocking(impl_.get_implementation(), mode, ec);
1263 boost::asio::detail::throw_error(ec, "non_blocking");
1264 }
1265
1266 /// Sets the non-blocking mode of the socket.
1267 /**
1268 * @param mode If @c true, the socket's synchronous operations will fail with
1269 * boost::asio::error::would_block if they are unable to perform the requested
1270 * operation immediately. If @c false, synchronous operations will block
1271 * until complete.
1272 *
1273 * @param ec Set to indicate what error occurred, if any.
1274 *
1275 * @note The non-blocking mode has no effect on the behaviour of asynchronous
1276 * operations. Asynchronous operations will never fail with the error
1277 * boost::asio::error::would_block.
1278 */
1279 BOOST_ASIO_SYNC_OP_VOIDboost::system::error_code non_blocking(
1280 bool mode, boost::system::error_code& ec)
1281 {
1282 impl_.get_service().non_blocking(impl_.get_implementation(), mode, ec);
1283 BOOST_ASIO_SYNC_OP_VOID_RETURN(ec)return ec;
1284 }
1285
1286 /// Gets the non-blocking mode of the native socket implementation.
1287 /**
1288 * This function is used to retrieve the non-blocking mode of the underlying
1289 * native socket. This mode has no effect on the behaviour of the socket
1290 * object's synchronous operations.
1291 *
1292 * @returns @c true if the underlying socket is in non-blocking mode and
1293 * direct system calls may fail with boost::asio::error::would_block (or the
1294 * equivalent system error).
1295 *
1296 * @note The current non-blocking mode is cached by the socket object.
1297 * Consequently, the return value may be incorrect if the non-blocking mode
1298 * was set directly on the native socket.
1299 *
1300 * @par Example
1301 * This function is intended to allow the encapsulation of arbitrary
1302 * non-blocking system calls as asynchronous operations, in a way that is
1303 * transparent to the user of the socket object. The following example
1304 * illustrates how Linux's @c sendfile system call might be encapsulated:
1305 * @code template <typename Handler>
1306 * struct sendfile_op
1307 * {
1308 * tcp::socket& sock_;
1309 * int fd_;
1310 * Handler handler_;
1311 * off_t offset_;
1312 * std::size_t total_bytes_transferred_;
1313 *
1314 * // Function call operator meeting WriteHandler requirements.
1315 * // Used as the handler for the async_write_some operation.
1316 * void operator()(boost::system::error_code ec, std::size_t)
1317 * {
1318 * // Put the underlying socket into non-blocking mode.
1319 * if (!ec)
1320 * if (!sock_.native_non_blocking())
1321 * sock_.native_non_blocking(true, ec);
1322 *
1323 * if (!ec)
1324 * {
1325 * for (;;)
1326 * {
1327 * // Try the system call.
1328 * errno = 0;
1329 * int n = ::sendfile(sock_.native_handle(), fd_, &offset_, 65536);
1330 * ec = boost::system::error_code(n < 0 ? errno : 0,
1331 * boost::asio::error::get_system_category());
1332 * total_bytes_transferred_ += ec ? 0 : n;
1333 *
1334 * // Retry operation immediately if interrupted by signal.
1335 * if (ec == boost::asio::error::interrupted)
1336 * continue;
1337 *
1338 * // Check if we need to run the operation again.
1339 * if (ec == boost::asio::error::would_block
1340 * || ec == boost::asio::error::try_again)
1341 * {
1342 * // We have to wait for the socket to become ready again.
1343 * sock_.async_wait(tcp::socket::wait_write, *this);
1344 * return;
1345 * }
1346 *
1347 * if (ec || n == 0)
1348 * {
1349 * // An error occurred, or we have reached the end of the file.
1350 * // Either way we must exit the loop so we can call the handler.
1351 * break;
1352 * }
1353 *
1354 * // Loop around to try calling sendfile again.
1355 * }
1356 * }
1357 *
1358 * // Pass result back to user's handler.
1359 * handler_(ec, total_bytes_transferred_);
1360 * }
1361 * };
1362 *
1363 * template <typename Handler>
1364 * void async_sendfile(tcp::socket& sock, int fd, Handler h)
1365 * {
1366 * sendfile_op<Handler> op = { sock, fd, h, 0, 0 };
1367 * sock.async_wait(tcp::socket::wait_write, op);
1368 * } @endcode
1369 */
1370 bool native_non_blocking() const
1371 {
1372 return impl_.get_service().native_non_blocking(impl_.get_implementation());
1373 }
1374
1375 /// Sets the non-blocking mode of the native socket implementation.
1376 /**
1377 * This function is used to modify the non-blocking mode of the underlying
1378 * native socket. It has no effect on the behaviour of the socket object's
1379 * synchronous operations.
1380 *
1381 * @param mode If @c true, the underlying socket is put into non-blocking
1382 * mode and direct system calls may fail with boost::asio::error::would_block
1383 * (or the equivalent system error).
1384 *
1385 * @throws boost::system::system_error Thrown on failure. If the @c mode is
1386 * @c false, but the current value of @c non_blocking() is @c true, this
1387 * function fails with boost::asio::error::invalid_argument, as the
1388 * combination does not make sense.
1389 *
1390 * @par Example
1391 * This function is intended to allow the encapsulation of arbitrary
1392 * non-blocking system calls as asynchronous operations, in a way that is
1393 * transparent to the user of the socket object. The following example
1394 * illustrates how Linux's @c sendfile system call might be encapsulated:
1395 * @code template <typename Handler>
1396 * struct sendfile_op
1397 * {
1398 * tcp::socket& sock_;
1399 * int fd_;
1400 * Handler handler_;
1401 * off_t offset_;
1402 * std::size_t total_bytes_transferred_;
1403 *
1404 * // Function call operator meeting WriteHandler requirements.
1405 * // Used as the handler for the async_write_some operation.
1406 * void operator()(boost::system::error_code ec, std::size_t)
1407 * {
1408 * // Put the underlying socket into non-blocking mode.
1409 * if (!ec)
1410 * if (!sock_.native_non_blocking())
1411 * sock_.native_non_blocking(true, ec);
1412 *
1413 * if (!ec)
1414 * {
1415 * for (;;)
1416 * {
1417 * // Try the system call.
1418 * errno = 0;
1419 * int n = ::sendfile(sock_.native_handle(), fd_, &offset_, 65536);
1420 * ec = boost::system::error_code(n < 0 ? errno : 0,
1421 * boost::asio::error::get_system_category());
1422 * total_bytes_transferred_ += ec ? 0 : n;
1423 *
1424 * // Retry operation immediately if interrupted by signal.
1425 * if (ec == boost::asio::error::interrupted)
1426 * continue;
1427 *
1428 * // Check if we need to run the operation again.
1429 * if (ec == boost::asio::error::would_block
1430 * || ec == boost::asio::error::try_again)
1431 * {
1432 * // We have to wait for the socket to become ready again.
1433 * sock_.async_wait(tcp::socket::wait_write, *this);
1434 * return;
1435 * }
1436 *
1437 * if (ec || n == 0)
1438 * {
1439 * // An error occurred, or we have reached the end of the file.
1440 * // Either way we must exit the loop so we can call the handler.
1441 * break;
1442 * }
1443 *
1444 * // Loop around to try calling sendfile again.
1445 * }
1446 * }
1447 *
1448 * // Pass result back to user's handler.
1449 * handler_(ec, total_bytes_transferred_);
1450 * }
1451 * };
1452 *
1453 * template <typename Handler>
1454 * void async_sendfile(tcp::socket& sock, int fd, Handler h)
1455 * {
1456 * sendfile_op<Handler> op = { sock, fd, h, 0, 0 };
1457 * sock.async_wait(tcp::socket::wait_write, op);
1458 * } @endcode
1459 */
1460 void native_non_blocking(bool mode)
1461 {
1462 boost::system::error_code ec;
1463 impl_.get_service().native_non_blocking(
1464 impl_.get_implementation(), mode, ec);
1465 boost::asio::detail::throw_error(ec, "native_non_blocking");
1466 }
1467
1468 /// Sets the non-blocking mode of the native socket implementation.
1469 /**
1470 * This function is used to modify the non-blocking mode of the underlying
1471 * native socket. It has no effect on the behaviour of the socket object's
1472 * synchronous operations.
1473 *
1474 * @param mode If @c true, the underlying socket is put into non-blocking
1475 * mode and direct system calls may fail with boost::asio::error::would_block
1476 * (or the equivalent system error).
1477 *
1478 * @param ec Set to indicate what error occurred, if any. If the @c mode is
1479 * @c false, but the current value of @c non_blocking() is @c true, this
1480 * function fails with boost::asio::error::invalid_argument, as the
1481 * combination does not make sense.
1482 *
1483 * @par Example
1484 * This function is intended to allow the encapsulation of arbitrary
1485 * non-blocking system calls as asynchronous operations, in a way that is
1486 * transparent to the user of the socket object. The following example
1487 * illustrates how Linux's @c sendfile system call might be encapsulated:
1488 * @code template <typename Handler>
1489 * struct sendfile_op
1490 * {
1491 * tcp::socket& sock_;
1492 * int fd_;
1493 * Handler handler_;
1494 * off_t offset_;
1495 * std::size_t total_bytes_transferred_;
1496 *
1497 * // Function call operator meeting WriteHandler requirements.
1498 * // Used as the handler for the async_write_some operation.
1499 * void operator()(boost::system::error_code ec, std::size_t)
1500 * {
1501 * // Put the underlying socket into non-blocking mode.
1502 * if (!ec)
1503 * if (!sock_.native_non_blocking())
1504 * sock_.native_non_blocking(true, ec);
1505 *
1506 * if (!ec)
1507 * {
1508 * for (;;)
1509 * {
1510 * // Try the system call.
1511 * errno = 0;
1512 * int n = ::sendfile(sock_.native_handle(), fd_, &offset_, 65536);
1513 * ec = boost::system::error_code(n < 0 ? errno : 0,
1514 * boost::asio::error::get_system_category());
1515 * total_bytes_transferred_ += ec ? 0 : n;
1516 *
1517 * // Retry operation immediately if interrupted by signal.
1518 * if (ec == boost::asio::error::interrupted)
1519 * continue;
1520 *
1521 * // Check if we need to run the operation again.
1522 * if (ec == boost::asio::error::would_block
1523 * || ec == boost::asio::error::try_again)
1524 * {
1525 * // We have to wait for the socket to become ready again.
1526 * sock_.async_wait(tcp::socket::wait_write, *this);
1527 * return;
1528 * }
1529 *
1530 * if (ec || n == 0)
1531 * {
1532 * // An error occurred, or we have reached the end of the file.
1533 * // Either way we must exit the loop so we can call the handler.
1534 * break;
1535 * }
1536 *
1537 * // Loop around to try calling sendfile again.
1538 * }
1539 * }
1540 *
1541 * // Pass result back to user's handler.
1542 * handler_(ec, total_bytes_transferred_);
1543 * }
1544 * };
1545 *
1546 * template <typename Handler>
1547 * void async_sendfile(tcp::socket& sock, int fd, Handler h)
1548 * {
1549 * sendfile_op<Handler> op = { sock, fd, h, 0, 0 };
1550 * sock.async_wait(tcp::socket::wait_write, op);
1551 * } @endcode
1552 */
1553 BOOST_ASIO_SYNC_OP_VOIDboost::system::error_code native_non_blocking(
1554 bool mode, boost::system::error_code& ec)
1555 {
1556 impl_.get_service().native_non_blocking(
1557 impl_.get_implementation(), mode, ec);
1558 BOOST_ASIO_SYNC_OP_VOID_RETURN(ec)return ec;
1559 }
1560
1561 /// Get the local endpoint of the socket.
1562 /**
1563 * This function is used to obtain the locally bound endpoint of the socket.
1564 *
1565 * @returns An object that represents the local endpoint of the socket.
1566 *
1567 * @throws boost::system::system_error Thrown on failure.
1568 *
1569 * @par Example
1570 * @code
1571 * boost::asio::ip::tcp::socket socket(my_context);
1572 * ...
1573 * boost::asio::ip::tcp::endpoint endpoint = socket.local_endpoint();
1574 * @endcode
1575 */
1576 endpoint_type local_endpoint() const
1577 {
1578 boost::system::error_code ec;
1579 endpoint_type ep = impl_.get_service().local_endpoint(
1580 impl_.get_implementation(), ec);
1581 boost::asio::detail::throw_error(ec, "local_endpoint");
1582 return ep;
1583 }
1584
1585 /// Get the local endpoint of the socket.
1586 /**
1587 * This function is used to obtain the locally bound endpoint of the socket.
1588 *
1589 * @param ec Set to indicate what error occurred, if any.
1590 *
1591 * @returns An object that represents the local endpoint of the socket.
1592 * Returns a default-constructed endpoint object if an error occurred.
1593 *
1594 * @par Example
1595 * @code
1596 * boost::asio::ip::tcp::socket socket(my_context);
1597 * ...
1598 * boost::system::error_code ec;
1599 * boost::asio::ip::tcp::endpoint endpoint = socket.local_endpoint(ec);
1600 * if (ec)
1601 * {
1602 * // An error occurred.
1603 * }
1604 * @endcode
1605 */
1606 endpoint_type local_endpoint(boost::system::error_code& ec) const
1607 {
1608 return impl_.get_service().local_endpoint(impl_.get_implementation(), ec);
1609 }
1610
1611 /// Get the remote endpoint of the socket.
1612 /**
1613 * This function is used to obtain the remote endpoint of the socket.
1614 *
1615 * @returns An object that represents the remote endpoint of the socket.
1616 *
1617 * @throws boost::system::system_error Thrown on failure.
1618 *
1619 * @par Example
1620 * @code
1621 * boost::asio::ip::tcp::socket socket(my_context);
1622 * ...
1623 * boost::asio::ip::tcp::endpoint endpoint = socket.remote_endpoint();
1624 * @endcode
1625 */
1626 endpoint_type remote_endpoint() const
1627 {
1628 boost::system::error_code ec;
1629 endpoint_type ep = impl_.get_service().remote_endpoint(
1630 impl_.get_implementation(), ec);
1631 boost::asio::detail::throw_error(ec, "remote_endpoint");
1632 return ep;
1633 }
1634
1635 /// Get the remote endpoint of the socket.
1636 /**
1637 * This function is used to obtain the remote endpoint of the socket.
1638 *
1639 * @param ec Set to indicate what error occurred, if any.
1640 *
1641 * @returns An object that represents the remote endpoint of the socket.
1642 * Returns a default-constructed endpoint object if an error occurred.
1643 *
1644 * @par Example
1645 * @code
1646 * boost::asio::ip::tcp::socket socket(my_context);
1647 * ...
1648 * boost::system::error_code ec;
1649 * boost::asio::ip::tcp::endpoint endpoint = socket.remote_endpoint(ec);
1650 * if (ec)
1651 * {
1652 * // An error occurred.
1653 * }
1654 * @endcode
1655 */
1656 endpoint_type remote_endpoint(boost::system::error_code& ec) const
1657 {
1658 return impl_.get_service().remote_endpoint(impl_.get_implementation(), ec);
1659 }
1660
1661 /// Disable sends or receives on the socket.
1662 /**
1663 * This function is used to disable send operations, receive operations, or
1664 * both.
1665 *
1666 * @param what Determines what types of operation will no longer be allowed.
1667 *
1668 * @throws boost::system::system_error Thrown on failure.
1669 *
1670 * @par Example
1671 * Shutting down the send side of the socket:
1672 * @code
1673 * boost::asio::ip::tcp::socket socket(my_context);
1674 * ...
1675 * socket.shutdown(boost::asio::ip::tcp::socket::shutdown_send);
1676 * @endcode
1677 */
1678 void shutdown(shutdown_type what)
1679 {
1680 boost::system::error_code ec;
1681 impl_.get_service().shutdown(impl_.get_implementation(), what, ec);
1682 boost::asio::detail::throw_error(ec, "shutdown");
1683 }
1684
1685 /// Disable sends or receives on the socket.
1686 /**
1687 * This function is used to disable send operations, receive operations, or
1688 * both.
1689 *
1690 * @param what Determines what types of operation will no longer be allowed.
1691 *
1692 * @param ec Set to indicate what error occurred, if any.
1693 *
1694 * @par Example
1695 * Shutting down the send side of the socket:
1696 * @code
1697 * boost::asio::ip::tcp::socket socket(my_context);
1698 * ...
1699 * boost::system::error_code ec;
1700 * socket.shutdown(boost::asio::ip::tcp::socket::shutdown_send, ec);
1701 * if (ec)
1702 * {
1703 * // An error occurred.
1704 * }
1705 * @endcode
1706 */
1707 BOOST_ASIO_SYNC_OP_VOIDboost::system::error_code shutdown(shutdown_type what,
1708 boost::system::error_code& ec)
1709 {
1710 impl_.get_service().shutdown(impl_.get_implementation(), what, ec);
1711 BOOST_ASIO_SYNC_OP_VOID_RETURN(ec)return ec;
1712 }
1713
1714 /// Wait for the socket to become ready to read, ready to write, or to have
1715 /// pending error conditions.
1716 /**
1717 * This function is used to perform a blocking wait for a socket to enter
1718 * a ready to read, write or error condition state.
1719 *
1720 * @param w Specifies the desired socket state.
1721 *
1722 * @par Example
1723 * Waiting for a socket to become readable.
1724 * @code
1725 * boost::asio::ip::tcp::socket socket(my_context);
1726 * ...
1727 * socket.wait(boost::asio::ip::tcp::socket::wait_read);
1728 * @endcode
1729 */
1730 void wait(wait_type w)
1731 {
1732 boost::system::error_code ec;
1733 impl_.get_service().wait(impl_.get_implementation(), w, ec);
1734 boost::asio::detail::throw_error(ec, "wait");
1735 }
1736
1737 /// Wait for the socket to become ready to read, ready to write, or to have
1738 /// pending error conditions.
1739 /**
1740 * This function is used to perform a blocking wait for a socket to enter
1741 * a ready to read, write or error condition state.
1742 *
1743 * @param w Specifies the desired socket state.
1744 *
1745 * @param ec Set to indicate what error occurred, if any.
1746 *
1747 * @par Example
1748 * Waiting for a socket to become readable.
1749 * @code
1750 * boost::asio::ip::tcp::socket socket(my_context);
1751 * ...
1752 * boost::system::error_code ec;
1753 * socket.wait(boost::asio::ip::tcp::socket::wait_read, ec);
1754 * @endcode
1755 */
1756 BOOST_ASIO_SYNC_OP_VOIDboost::system::error_code wait(wait_type w, boost::system::error_code& ec)
1757 {
1758 impl_.get_service().wait(impl_.get_implementation(), w, ec);
1759 BOOST_ASIO_SYNC_OP_VOID_RETURN(ec)return ec;
1760 }
1761
1762 /// Asynchronously wait for the socket to become ready to read, ready to
1763 /// write, or to have pending error conditions.
1764 /**
1765 * This function is used to perform an asynchronous wait for a socket to enter
1766 * a ready to read, write or error condition state. It is an initiating
1767 * function for an @ref asynchronous_operation, and always returns
1768 * immediately.
1769 *
1770 * @param w Specifies the desired socket state.
1771 *
1772 * @param token The @ref completion_token that will be used to produce a
1773 * completion handler, which will be called when the wait completes. Potential
1774 * completion tokens include @ref use_future, @ref use_awaitable, @ref
1775 * yield_context, or a function object with the correct completion signature.
1776 * The function signature of the completion handler must be:
1777 * @code void handler(
1778 * const boost::system::error_code& error // Result of operation.
1779 * ); @endcode
1780 * Regardless of whether the asynchronous operation completes immediately or
1781 * not, the completion handler will not be invoked from within this function.
1782 * On immediate completion, invocation of the handler will be performed in a
1783 * manner equivalent to using boost::asio::async_immediate().
1784 *
1785 * @par Completion Signature
1786 * @code void(boost::system::error_code) @endcode
1787 *
1788 * @par Example
1789 * @code
1790 * void wait_handler(const boost::system::error_code& error)
1791 * {
1792 * if (!error)
1793 * {
1794 * // Wait succeeded.
1795 * }
1796 * }
1797 *
1798 * ...
1799 *
1800 * boost::asio::ip::tcp::socket socket(my_context);
1801 * ...
1802 * socket.async_wait(boost::asio::ip::tcp::socket::wait_read, wait_handler);
1803 * @endcode
1804 *
1805 * @par Per-Operation Cancellation
1806 * On POSIX or Windows operating systems, this asynchronous operation supports
1807 * cancellation for the following boost::asio::cancellation_type values:
1808 *
1809 * @li @c cancellation_type::terminal
1810 *
1811 * @li @c cancellation_type::partial
1812 *
1813 * @li @c cancellation_type::total
1814 */
1815 template <
1816 BOOST_ASIO_COMPLETION_TOKEN_FOR(void (boost::system::error_code))typename
1817 WaitToken = default_completion_token_t<executor_type>>
1818 auto async_wait(wait_type w,
1819 WaitToken&& token = default_completion_token_t<executor_type>())
1820 -> decltype(
1821 async_initiate<WaitToken, void (boost::system::error_code)>(
1822 declval<initiate_async_wait>(), token, w))
1823 {
1824 return async_initiate<WaitToken, void (boost::system::error_code)>(
1825 initiate_async_wait(this), token, w);
1826 }
1827
1828protected:
1829 /// Protected destructor to prevent deletion through this type.
1830 /**
1831 * This function destroys the socket, cancelling any outstanding asynchronous
1832 * operations associated with the socket as if by calling @c cancel.
1833 */
1834 ~basic_socket()
1835 {
1836 }
1837
1838#if defined(BOOST_ASIO_WINDOWS_RUNTIME)
1839 detail::io_object_impl<
1840 detail::null_socket_service<Protocol>, Executor> impl_;
1841#elif defined(BOOST_ASIO_HAS_IOCP)
1842 detail::io_object_impl<
1843 detail::win_iocp_socket_service<Protocol>, Executor> impl_;
1844#elif defined(BOOST_ASIO_HAS_IO_URING_AS_DEFAULT)
1845 detail::io_object_impl<
1846 detail::io_uring_socket_service<Protocol>, Executor> impl_;
1847#else
1848 detail::io_object_impl<
1849 detail::reactive_socket_service<Protocol>, Executor> impl_;
1850#endif
1851
1852private:
1853 // Disallow copying and assignment.
1854 basic_socket(const basic_socket&) = delete;
1855 basic_socket& operator=(const basic_socket&) = delete;
1856
1857 class initiate_async_connect
1858 {
1859 public:
1860 typedef Executor executor_type;
1861
1862 explicit initiate_async_connect(basic_socket* self)
1863 : self_(self)
1864 {
1865 }
1866
1867 const executor_type& get_executor() const noexcept
1868 {
1869 return self_->get_executor();
1870 }
1871
1872 template <typename ConnectHandler>
1873 void operator()(ConnectHandler&& handler,
1874 const endpoint_type& peer_endpoint,
1875 const boost::system::error_code& open_ec) const
1876 {
1877 // If you get an error on the following line it means that your handler
1878 // does not meet the documented type requirements for a ConnectHandler.
1879 BOOST_ASIO_CONNECT_HANDLER_CHECK(ConnectHandler, handler)typedef typename ::boost::asio::async_result< typename ::boost
::asio::decay<ConnectHandler>::type, void(boost::system
::error_code)>::completion_handler_type asio_true_handler_type
; static_assert(sizeof(boost::asio::detail::one_arg_handler_test
( boost::asio::detail::rvref< asio_true_handler_type>()
, static_cast<const boost::system::error_code*>(0))) ==
1, "ConnectHandler type requirements not met"); typedef boost
::asio::detail::handler_type_requirements< sizeof( boost::
asio::detail::argbyv( boost::asio::detail::rvref< asio_true_handler_type
>())) + sizeof( boost::asio::detail::rorlvref< asio_true_handler_type
>()( boost::asio::detail::lvref<const boost::system::error_code
>()), char(0))> __attribute__((__unused__))
type_check;
1880
1881 if (open_ec)
1882 {
1883 boost::asio::post(self_->impl_.get_executor(),
1884 boost::asio::detail::bind_handler(
1885 static_cast<ConnectHandler&&>(handler), open_ec));
1886 }
1887 else
1888 {
1889 detail::non_const_lvalue<ConnectHandler> handler2(handler);
1890 self_->impl_.get_service().async_connect(
1891 self_->impl_.get_implementation(), peer_endpoint,
1892 handler2.value, self_->impl_.get_executor());
1893 }
1894 }
1895
1896 private:
1897 basic_socket* self_;
1898 };
1899
1900 class initiate_async_wait
1901 {
1902 public:
1903 typedef Executor executor_type;
1904
1905 explicit initiate_async_wait(basic_socket* self)
1906 : self_(self)
1907 {
1908 }
1909
1910 const executor_type& get_executor() const noexcept
1911 {
1912 return self_->get_executor();
1913 }
1914
1915 template <typename WaitHandler>
1916 void operator()(WaitHandler&& handler, wait_type w) const
1917 {
1918 // If you get an error on the following line it means that your handler
1919 // does not meet the documented type requirements for a WaitHandler.
1920 BOOST_ASIO_WAIT_HANDLER_CHECK(WaitHandler, handler)typedef typename ::boost::asio::async_result< typename ::boost
::asio::decay<WaitHandler>::type, void(boost::system::error_code
)>::completion_handler_type asio_true_handler_type; static_assert
(sizeof(boost::asio::detail::one_arg_handler_test( boost::asio
::detail::rvref< asio_true_handler_type>(), static_cast
<const boost::system::error_code*>(0))) == 1, "WaitHandler type requirements not met"
); typedef boost::asio::detail::handler_type_requirements<
sizeof( boost::asio::detail::argbyv( boost::asio::detail::rvref
< asio_true_handler_type>())) + sizeof( boost::asio::detail
::rorlvref< asio_true_handler_type>()( boost::asio::detail
::lvref<const boost::system::error_code>()), char(0))>
__attribute__((__unused__))
type_check;
1921
1922 detail::non_const_lvalue<WaitHandler> handler2(handler);
1923 self_->impl_.get_service().async_wait(
1924 self_->impl_.get_implementation(), w,
1925 handler2.value, self_->impl_.get_executor());
1926 }
1927
1928 private:
1929 basic_socket* self_;
1930 };
1931};
1932
1933} // namespace asio
1934} // namespace boost
1935
1936#include <boost/asio/detail/pop_options.hpp>
1937
1938#endif // BOOST_ASIO_BASIC_SOCKET_HPP

/usr/include/boost/asio/detail/io_object_impl.hpp

1//
2// detail/io_object_impl.hpp
3// ~~~~~~~~~~~~~~~~~~~~~~~~~
4//
5// Copyright (c) 2003-2025 Christopher M. Kohlhoff (chris at kohlhoff dot com)
6//
7// Distributed under the Boost Software License, Version 1.0. (See accompanying
8// file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt)
9//
10
11#ifndef BOOST_ASIO_DETAIL_IO_OBJECT_IMPL_HPP
12#define BOOST_ASIO_DETAIL_IO_OBJECT_IMPL_HPP
13
14#if defined(_MSC_VER) && (_MSC_VER >= 1200)
15# pragma once
16#endif // defined(_MSC_VER) && (_MSC_VER >= 1200)
17
18#include <new>
19#include <boost/asio/detail/config.hpp>
20#include <boost/asio/detail/type_traits.hpp>
21#include <boost/asio/execution/executor.hpp>
22#include <boost/asio/execution/context.hpp>
23#include <boost/asio/io_context.hpp>
24#include <boost/asio/query.hpp>
25
26#include <boost/asio/detail/push_options.hpp>
27
28namespace boost {
29namespace asio {
30namespace detail {
31
32template <typename IoObjectService,
33 typename Executor = io_context::executor_type>
34class io_object_impl
35{
36public:
37 // The type of the service that will be used to provide I/O operations.
38 typedef IoObjectService service_type;
39
40 // The underlying implementation type of I/O object.
41 typedef typename service_type::implementation_type implementation_type;
42
43 // The type of the executor associated with the object.
44 typedef Executor executor_type;
45
46 // Construct an I/O object using an executor.
47 explicit io_object_impl(int, const executor_type& ex)
48 : service_(&boost::asio::use_service<IoObjectService>(
49 io_object_impl::get_context(ex))),
50 executor_(ex)
51 {
52 service_->construct(implementation_);
53 }
54
55 // Construct an I/O object using an execution context.
56 template <typename ExecutionContext>
57 explicit io_object_impl(int, int, ExecutionContext& context)
58 : service_(&boost::asio::use_service<IoObjectService>(context)),
27
Calling 'use_service<boost::asio::detail::reactive_socket_service<boost::asio::ip::tcp>>'
71
Returning from 'use_service<boost::asio::detail::reactive_socket_service<boost::asio::ip::tcp>>'
59 executor_(context.get_executor())
60 {
61 service_->construct(implementation_);
62 }
63
64 // Move-construct an I/O object.
65 io_object_impl(io_object_impl&& other)
66 : service_(&other.get_service()),
67 executor_(other.get_executor())
68 {
69 service_->move_construct(implementation_, other.implementation_);
70 }
71
72 // Perform converting move-construction of an I/O object on the same service.
73 template <typename Executor1>
74 io_object_impl(io_object_impl<IoObjectService, Executor1>&& other)
75 : service_(&other.get_service()),
76 executor_(other.get_executor())
77 {
78 service_->move_construct(implementation_, other.get_implementation());
79 }
80
81 // Perform converting move-construction of an I/O object on another service.
82 template <typename IoObjectService1, typename Executor1>
83 io_object_impl(io_object_impl<IoObjectService1, Executor1>&& other)
84 : service_(&boost::asio::use_service<IoObjectService>(
85 io_object_impl::get_context(other.get_executor()))),
86 executor_(other.get_executor())
87 {
88 service_->converting_move_construct(implementation_,
89 other.get_service(), other.get_implementation());
90 }
91
92 // Destructor.
93 ~io_object_impl()
94 {
95 service_->destroy(implementation_);
96 }
97
98 // Move-assign an I/O object.
99 io_object_impl& operator=(io_object_impl&& other)
100 {
101 if (this != &other)
102 {
103 service_->move_assign(implementation_,
104 *other.service_, other.implementation_);
105 executor_.~executor_type();
106 new (&executor_) executor_type(other.executor_);
107 service_ = other.service_;
108 }
109 return *this;
110 }
111
112 // Get the executor associated with the object.
113 const executor_type& get_executor() noexcept
114 {
115 return executor_;
116 }
117
118 // Get the service associated with the I/O object.
119 service_type& get_service()
120 {
121 return *service_;
122 }
123
124 // Get the service associated with the I/O object.
125 const service_type& get_service() const
126 {
127 return *service_;
128 }
129
130 // Get the underlying implementation of the I/O object.
131 implementation_type& get_implementation()
132 {
133 return implementation_;
134 }
135
136 // Get the underlying implementation of the I/O object.
137 const implementation_type& get_implementation() const
138 {
139 return implementation_;
140 }
141
142private:
143 // Helper function to get an executor's context.
144 template <typename T>
145 static execution_context& get_context(const T& t,
146 enable_if_t<execution::is_executor<T>::value>* = 0)
147 {
148 return boost::asio::query(t, execution::context);
149 }
150
151 // Helper function to get an executor's context.
152 template <typename T>
153 static execution_context& get_context(const T& t,
154 enable_if_t<!execution::is_executor<T>::value>* = 0)
155 {
156 return t.context();
157 }
158
159 // Disallow copying and copy assignment.
160 io_object_impl(const io_object_impl&);
161 io_object_impl& operator=(const io_object_impl&);
162
163 // The service associated with the I/O object.
164 service_type* service_;
165
166 // The underlying implementation of the I/O object.
167 implementation_type implementation_;
168
169 // The associated executor.
170 executor_type executor_;
171};
172
173} // namespace detail
174} // namespace asio
175} // namespace boost
176
177#include <boost/asio/detail/pop_options.hpp>
178
179#endif // BOOST_ASIO_DETAIL_IO_OBJECT_IMPL_HPP

/usr/include/boost/asio/impl/io_context.hpp

1//
2// impl/io_context.hpp
3// ~~~~~~~~~~~~~~~~~~~
4//
5// Copyright (c) 2003-2025 Christopher M. Kohlhoff (chris at kohlhoff dot com)
6//
7// Distributed under the Boost Software License, Version 1.0. (See accompanying
8// file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt)
9//
10
11#ifndef BOOST_ASIO_IMPL_IO_CONTEXT_HPP
12#define BOOST_ASIO_IMPL_IO_CONTEXT_HPP
13
14#if defined(_MSC_VER) && (_MSC_VER >= 1200)
15# pragma once
16#endif // defined(_MSC_VER) && (_MSC_VER >= 1200)
17
18#include <boost/asio/config.hpp>
19#include <boost/asio/detail/completion_handler.hpp>
20#include <boost/asio/detail/executor_op.hpp>
21#include <boost/asio/detail/fenced_block.hpp>
22#include <boost/asio/detail/handler_type_requirements.hpp>
23#include <boost/asio/detail/non_const_lvalue.hpp>
24#include <boost/asio/detail/service_registry.hpp>
25#include <boost/asio/detail/throw_error.hpp>
26#include <boost/asio/detail/type_traits.hpp>
27
28#include <boost/asio/detail/push_options.hpp>
29
30namespace boost {
31namespace asio {
32
33template <typename Allocator>
34io_context::io_context(allocator_arg_t, const Allocator& a)
35 : execution_context(std::allocator_arg, a, config_from_concurrency_hint()),
36 impl_(boost::asio::make_service<impl_type>(*this, false))
37{
38}
39
40template <typename Allocator>
41io_context::io_context(allocator_arg_t,
42 const Allocator& a, int concurrency_hint)
43 : execution_context(std::allocator_arg, a,
44 config_from_concurrency_hint(concurrency_hint)),
45 impl_(boost::asio::make_service<impl_type>(*this, false))
46{
47}
48
49template <typename Allocator>
50io_context::io_context(allocator_arg_t, const Allocator& a,
51 const execution_context::service_maker& initial_services)
52 : execution_context(std::allocator_arg, a, initial_services),
53 impl_(boost::asio::make_service<impl_type>(*this, false))
54{
55}
56
57#if !defined(GENERATING_DOCUMENTATION)
58
59template <typename Service>
60inline Service& use_service(io_context& ioc)
61{
62 // Check that Service meets the necessary type requirements.
63 (void)static_cast<execution_context::service*>(static_cast<Service*>(0));
64 (void)static_cast<const execution_context::id*>(&Service::id);
65
66 return ioc.service_registry_->template use_service<Service>(ioc);
28
Calling 'service_registry::use_service'
70
Returning from 'service_registry::use_service'
67}
68
69template <>
70inline detail::io_context_impl& use_service<detail::io_context_impl>(
71 io_context& ioc)
72{
73 return ioc.impl_;
74}
75
76#endif // !defined(GENERATING_DOCUMENTATION)
77
78inline io_context::executor_type
79io_context::get_executor() noexcept
80{
81 return executor_type(*this);
82}
83
84template <typename Rep, typename Period>
85std::size_t io_context::run_for(
86 const chrono::duration<Rep, Period>& rel_time)
87{
88 return this->run_until(chrono::steady_clock::now() + rel_time);
89}
90
91template <typename Clock, typename Duration>
92std::size_t io_context::run_until(
93 const chrono::time_point<Clock, Duration>& abs_time)
94{
95 std::size_t n = 0;
96 while (this->run_one_until(abs_time))
97 if (n != (std::numeric_limits<std::size_t>::max)())
98 ++n;
99 return n;
100}
101
102template <typename Rep, typename Period>
103std::size_t io_context::run_one_for(
104 const chrono::duration<Rep, Period>& rel_time)
105{
106 return this->run_one_until(chrono::steady_clock::now() + rel_time);
107}
108
109template <typename Clock, typename Duration>
110std::size_t io_context::run_one_until(
111 const chrono::time_point<Clock, Duration>& abs_time)
112{
113 typename Clock::time_point now = Clock::now();
114 while (now < abs_time)
115 {
116 typename Clock::duration rel_time = abs_time - now;
117 if (rel_time > chrono::seconds(1))
118 rel_time = chrono::seconds(1);
119
120 boost::system::error_code ec;
121 std::size_t s = impl_.wait_one(
122 static_cast<long>(chrono::duration_cast<
123 chrono::microseconds>(rel_time).count()), ec);
124 boost::asio::detail::throw_error(ec);
125
126 if (s || impl_.stopped())
127 return s;
128
129 now = Clock::now();
130 }
131
132 return 0;
133}
134
135#if !defined(BOOST_ASIO_NO_DEPRECATED)
136
137template <typename Handler>
138#if defined(GENERATING_DOCUMENTATION)
139unspecified
140#else
141inline detail::wrapped_handler<io_context&, Handler>
142#endif
143io_context::wrap(Handler handler)
144{
145 return detail::wrapped_handler<io_context&, Handler>(*this, handler);
146}
147
148#endif // !defined(BOOST_ASIO_NO_DEPRECATED)
149
150template <typename Allocator, uintptr_t Bits>
151io_context::basic_executor_type<Allocator, Bits>&
152io_context::basic_executor_type<Allocator, Bits>::operator=(
153 const basic_executor_type& other) noexcept
154{
155 if (this != &other)
156 {
157 static_cast<Allocator&>(*this) = static_cast<const Allocator&>(other);
158 io_context* old_io_context = context_ptr();
159 target_ = other.target_;
160 if (Bits & outstanding_work_tracked)
161 {
162 if (context_ptr())
163 context_ptr()->impl_.work_started();
164 if (old_io_context)
165 old_io_context->impl_.work_finished();
166 }
167 }
168 return *this;
169}
170
171template <typename Allocator, uintptr_t Bits>
172io_context::basic_executor_type<Allocator, Bits>&
173io_context::basic_executor_type<Allocator, Bits>::operator=(
174 basic_executor_type&& other) noexcept
175{
176 if (this != &other)
177 {
178 static_cast<Allocator&>(*this) = static_cast<Allocator&&>(other);
179 io_context* old_io_context = context_ptr();
180 target_ = other.target_;
181 if (Bits & outstanding_work_tracked)
182 {
183 other.target_ = 0;
184 if (old_io_context)
185 old_io_context->impl_.work_finished();
186 }
187 }
188 return *this;
189}
190
191template <typename Allocator, uintptr_t Bits>
192inline bool io_context::basic_executor_type<Allocator,
193 Bits>::running_in_this_thread() const noexcept
194{
195 return context_ptr()->impl_.can_dispatch();
196}
197
198template <typename Allocator, uintptr_t Bits>
199template <typename Function>
200void io_context::basic_executor_type<Allocator, Bits>::execute(
201 Function&& f) const
202{
203 typedef decay_t<Function> function_type;
204
205 // Invoke immediately if the blocking.possibly property is enabled and we are
206 // already inside the thread pool.
207 if ((bits() & blocking_never) == 0 && context_ptr()->impl_.can_dispatch())
208 {
209 // Make a local, non-const copy of the function.
210 function_type tmp(static_cast<Function&&>(f));
211
212#if !defined(BOOST_ASIO_NO_EXCEPTIONS)
213 try
214 {
215#endif // !defined(BOOST_ASIO_NO_EXCEPTIONS)
216 detail::fenced_block b(detail::fenced_block::full);
217 static_cast<function_type&&>(tmp)();
218 return;
219#if !defined(BOOST_ASIO_NO_EXCEPTIONS)
220 }
221 catch (...)
222 {
223 context_ptr()->impl_.capture_current_exception();
224 return;
225 }
226#endif // !defined(BOOST_ASIO_NO_EXCEPTIONS)
227 }
228
229 // Allocate and construct an operation to wrap the function.
230 typedef detail::executor_op<function_type, Allocator, detail::operation> op;
231 typename op::ptr p = {
232 detail::addressof(static_cast<const Allocator&>(*this)),
233 op::ptr::allocate(static_cast<const Allocator&>(*this)), 0 };
234 p.p = new (p.v) op(static_cast<Function&&>(f),
235 static_cast<const Allocator&>(*this));
236
237 BOOST_ASIO_HANDLER_CREATION((*context_ptr(), *p.p,(void)0
238 "io_context", context_ptr(), 0, "execute"))(void)0;
239
240 context_ptr()->impl_.post_immediate_completion(p.p,
241 (bits() & relationship_continuation) != 0);
242 p.v = p.p = 0;
243}
244
245#if !defined(BOOST_ASIO_NO_TS_EXECUTORS)
246template <typename Allocator, uintptr_t Bits>
247inline io_context& io_context::basic_executor_type<
248 Allocator, Bits>::context() const noexcept
249{
250 return *context_ptr();
251}
252
253template <typename Allocator, uintptr_t Bits>
254inline void io_context::basic_executor_type<Allocator,
255 Bits>::on_work_started() const noexcept
256{
257 context_ptr()->impl_.work_started();
258}
259
260template <typename Allocator, uintptr_t Bits>
261inline void io_context::basic_executor_type<Allocator,
262 Bits>::on_work_finished() const noexcept
263{
264 context_ptr()->impl_.work_finished();
265}
266
267template <typename Allocator, uintptr_t Bits>
268template <typename Function, typename OtherAllocator>
269void io_context::basic_executor_type<Allocator, Bits>::dispatch(
270 Function&& f, const OtherAllocator& a) const
271{
272 typedef decay_t<Function> function_type;
273
274 // Invoke immediately if we are already inside the thread pool.
275 if (context_ptr()->impl_.can_dispatch())
276 {
277 // Make a local, non-const copy of the function.
278 function_type tmp(static_cast<Function&&>(f));
279
280 detail::fenced_block b(detail::fenced_block::full);
281 static_cast<function_type&&>(tmp)();
282 return;
283 }
284
285 // Allocate and construct an operation to wrap the function.
286 typedef detail::executor_op<function_type,
287 OtherAllocator, detail::operation> op;
288 typename op::ptr p = { detail::addressof(a), op::ptr::allocate(a), 0 };
289 p.p = new (p.v) op(static_cast<Function&&>(f), a);
290
291 BOOST_ASIO_HANDLER_CREATION((*context_ptr(), *p.p,(void)0
292 "io_context", context_ptr(), 0, "dispatch"))(void)0;
293
294 context_ptr()->impl_.post_immediate_completion(p.p, false);
295 p.v = p.p = 0;
296}
297
298template <typename Allocator, uintptr_t Bits>
299template <typename Function, typename OtherAllocator>
300void io_context::basic_executor_type<Allocator, Bits>::post(
301 Function&& f, const OtherAllocator& a) const
302{
303 // Allocate and construct an operation to wrap the function.
304 typedef detail::executor_op<decay_t<Function>,
305 OtherAllocator, detail::operation> op;
306 typename op::ptr p = { detail::addressof(a), op::ptr::allocate(a), 0 };
307 p.p = new (p.v) op(static_cast<Function&&>(f), a);
308
309 BOOST_ASIO_HANDLER_CREATION((*context_ptr(), *p.p,(void)0
310 "io_context", context_ptr(), 0, "post"))(void)0;
311
312 context_ptr()->impl_.post_immediate_completion(p.p, false);
313 p.v = p.p = 0;
314}
315
316template <typename Allocator, uintptr_t Bits>
317template <typename Function, typename OtherAllocator>
318void io_context::basic_executor_type<Allocator, Bits>::defer(
319 Function&& f, const OtherAllocator& a) const
320{
321 // Allocate and construct an operation to wrap the function.
322 typedef detail::executor_op<decay_t<Function>,
323 OtherAllocator, detail::operation> op;
324 typename op::ptr p = { detail::addressof(a), op::ptr::allocate(a), 0 };
325 p.p = new (p.v) op(static_cast<Function&&>(f), a);
326
327 BOOST_ASIO_HANDLER_CREATION((*context_ptr(), *p.p,(void)0
328 "io_context", context_ptr(), 0, "defer"))(void)0;
329
330 context_ptr()->impl_.post_immediate_completion(p.p, true);
331 p.v = p.p = 0;
332}
333#endif // !defined(BOOST_ASIO_NO_TS_EXECUTORS)
334
335inline boost::asio::io_context& io_context::service::get_io_context()
336{
337 return static_cast<boost::asio::io_context&>(context());
338}
339
340} // namespace asio
341} // namespace boost
342
343#include <boost/asio/detail/pop_options.hpp>
344
345#endif // BOOST_ASIO_IMPL_IO_CONTEXT_HPP

/usr/include/boost/asio/detail/impl/service_registry.hpp

1//
2// detail/impl/service_registry.hpp
3// ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
4//
5// Copyright (c) 2003-2025 Christopher M. Kohlhoff (chris at kohlhoff dot com)
6//
7// Distributed under the Boost Software License, Version 1.0. (See accompanying
8// file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt)
9//
10
11#ifndef BOOST_ASIO_DETAIL_IMPL_SERVICE_REGISTRY_HPP
12#define BOOST_ASIO_DETAIL_IMPL_SERVICE_REGISTRY_HPP
13
14#if defined(_MSC_VER) && (_MSC_VER >= 1200)
15# pragma once
16#endif // defined(_MSC_VER) && (_MSC_VER >= 1200)
17
18#include <boost/asio/detail/push_options.hpp>
19
20namespace boost {
21namespace asio {
22namespace detail {
23
24template <typename Service>
25Service& service_registry::use_service()
26{
27 execution_context::service::key key;
28 init_key<Service>(key, 0);
29 factory_type factory = &service_registry::create<Service, execution_context>;
30 return *static_cast<Service*>(do_use_service(key, factory, &owner_));
37
Calling 'service_registry::do_use_service'
45
Returning from 'service_registry::do_use_service'
51
Calling 'service_registry::do_use_service'
59
Returning from 'service_registry::do_use_service'
31}
32
33template <typename Service>
34Service& service_registry::use_service(io_context& owner)
35{
36 execution_context::service::key key;
37 init_key<Service>(key, 0);
38 factory_type factory = &service_registry::create<Service, io_context>;
39 return *static_cast<Service*>(do_use_service(key, factory, &owner));
29
Calling 'service_registry::do_use_service'
69
Returning from 'service_registry::do_use_service'
40}
41
42template <typename Service, typename... Args>
43Service& service_registry::make_service(Args&&... args)
44{
45 auto_service_ptr new_service =
46 { create<Service, execution_context>(owner_,
47 &owner_, static_cast<Args&&>(args)...) };
48 add_service(static_cast<Service*>(new_service.ptr_));
49 Service& result = *static_cast<Service*>(new_service.ptr_);
50 new_service.ptr_ = 0;
51 return result;
52}
53
54template <typename Service>
55void service_registry::add_service(Service* new_service)
56{
57 execution_context::service::key key;
58 init_key<Service>(key, 0);
59 return do_add_service(key, new_service);
60}
61
62template <typename Service>
63bool service_registry::has_service() const
64{
65 execution_context::service::key key;
66 init_key<Service>(key, 0);
67 return do_has_service(key);
68}
69
70template <typename Service>
71inline void service_registry::init_key(
72 execution_context::service::key& key, ...)
73{
74 init_key_from_id(key, Service::id);
75}
76
77#if !defined(BOOST_ASIO_NO_TYPEID)
78template <typename Service>
79void service_registry::init_key(execution_context::service::key& key,
80 enable_if_t<is_base_of<typename Service::key_type, Service>::value>*)
81{
82 key.type_info_ = &typeid(typeid_wrapper<Service>);
83 key.id_ = 0;
84}
85
86template <typename Service>
87void service_registry::init_key_from_id(execution_context::service::key& key,
88 const service_id<Service>& /*id*/)
89{
90 key.type_info_ = &typeid(typeid_wrapper<Service>);
91 key.id_ = 0;
92}
93#endif // !defined(BOOST_ASIO_NO_TYPEID)
94
95template <typename Service, typename Owner, typename... Args>
96execution_context::service* service_registry::create(
97 execution_context& context, void* owner, Args&&... args)
98{
99 Service* svc = allocate_object<Service>(
32
Calling 'allocate_object<boost::asio::detail::reactive_socket_service<boost::asio::ip::tcp>, boost::asio::execution_context::allocator<void>, boost::asio::io_context &>'
66
Returning from 'allocate_object<boost::asio::detail::reactive_socket_service<boost::asio::ip::tcp>, boost::asio::execution_context::allocator<void>, boost::asio::io_context &>'
100 execution_context::allocator<void>(context),
101 *static_cast<Owner*>(owner), static_cast<Args&&>(args)...);
102 svc->destroy_ = &service_registry::destroy_allocated<Service>;
103 return svc;
104}
105
106template <typename Service>
107void service_registry::destroy_allocated(execution_context::service* service)
108{
109 deallocate_object(execution_context::allocator<void>(service->owner_),
110 static_cast<Service*>(service));
111}
112
113} // namespace detail
114} // namespace asio
115} // namespace boost
116
117#include <boost/asio/detail/pop_options.hpp>
118
119#endif // BOOST_ASIO_DETAIL_IMPL_SERVICE_REGISTRY_HPP

/usr/include/boost/asio/detail/impl/service_registry.ipp

1//
2// detail/impl/service_registry.ipp
3// ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
4//
5// Copyright (c) 2003-2025 Christopher M. Kohlhoff (chris at kohlhoff dot com)
6//
7// Distributed under the Boost Software License, Version 1.0. (See accompanying
8// file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt)
9//
10
11#ifndef BOOST_ASIO_DETAIL_IMPL_SERVICE_REGISTRY_IPP
12#define BOOST_ASIO_DETAIL_IMPL_SERVICE_REGISTRY_IPP
13
14#if defined(_MSC_VER) && (_MSC_VER >= 1200)
15# pragma once
16#endif // defined(_MSC_VER) && (_MSC_VER >= 1200)
17
18#include <boost/asio/detail/config.hpp>
19#include <vector>
20#include <boost/asio/detail/service_registry.hpp>
21#include <boost/asio/detail/throw_exception.hpp>
22
23#include <boost/asio/detail/push_options.hpp>
24
25namespace boost {
26namespace asio {
27namespace detail {
28
29service_registry::service_registry(execution_context& owner)
30 : owner_(owner),
31 first_service_(0)
32{
33}
34
35service_registry::~service_registry()
36{
37}
38
39void service_registry::shutdown_services()
40{
41 execution_context::service* service = first_service_;
42 while (service)
43 {
44 service->shutdown();
45 service = service->next_;
46 }
47}
48
49void service_registry::destroy_services()
50{
51 while (first_service_)
52 {
53 execution_context::service* next_service = first_service_->next_;
54 first_service_->destroy_(first_service_);
55 first_service_ = next_service;
56 }
57}
58
59void service_registry::notify_fork(execution_context::fork_event fork_ev)
60{
61 // Make a copy of all of the services while holding the lock. We don't want
62 // to hold the lock while calling into each service, as it may try to call
63 // back into this class.
64 std::vector<execution_context::service*> services;
65 {
66 boost::asio::detail::mutex::scoped_lock lock(mutex_);
67 execution_context::service* service = first_service_;
68 while (service)
69 {
70 services.push_back(service);
71 service = service->next_;
72 }
73 }
74
75 // If processing the fork_prepare event, we want to go in reverse order of
76 // service registration, which happens to be the existing order of the
77 // services in the vector. For the other events we want to go in the other
78 // direction.
79 std::size_t num_services = services.size();
80 if (fork_ev == execution_context::fork_prepare)
81 for (std::size_t i = 0; i < num_services; ++i)
82 services[i]->notify_fork(fork_ev);
83 else
84 for (std::size_t i = num_services; i > 0; --i)
85 services[i - 1]->notify_fork(fork_ev);
86}
87
88void service_registry::init_key_from_id(execution_context::service::key& key,
89 const execution_context::id& id)
90{
91 key.type_info_ = 0;
92 key.id_ = &id;
93}
94
95bool service_registry::keys_match(
96 const execution_context::service::key& key1,
97 const execution_context::service::key& key2)
98{
99 if (key1.id_ && key2.id_)
100 if (key1.id_ == key2.id_)
101 return true;
102 if (key1.type_info_ && key2.type_info_)
103 if (*key1.type_info_ == *key2.type_info_)
104 return true;
105 return false;
106}
107
108void service_registry::destroy_added(execution_context::service* service)
109{
110 delete service;
111}
112
113service_registry::auto_service_ptr::~auto_service_ptr()
114{
115 if (ptr_)
116 ptr_->destroy_(ptr_);
117}
118
119execution_context::service* service_registry::do_use_service(
120 const execution_context::service::key& key,
121 factory_type factory, void* owner)
122{
123 boost::asio::detail::mutex::scoped_lock lock(mutex_);
38
Calling constructor for 'scoped_lock<boost::asio::detail::posix_mutex>'
42
Returning from constructor for 'scoped_lock<boost::asio::detail::posix_mutex>'
52
Calling constructor for 'scoped_lock<boost::asio::detail::posix_mutex>'
56
Returning from constructor for 'scoped_lock<boost::asio::detail::posix_mutex>'
124
125 // First see if there is an existing service object with the given key.
126 execution_context::service* service = first_service_;
127 while (service)
30
Loop condition is false. Execution continues on line 137
43
Loop condition is false. Execution continues on line 137
57
Loop condition is false. Execution continues on line 137
128 {
129 if (keys_match(service->key_, key))
130 return service;
131 service = service->next_;
132 }
133
134 // Create a new service object. The service registry's mutex is not locked
135 // at this time to allow for nested calls into this function from the new
136 // service's constructor.
137 lock.unlock();
138 auto_service_ptr new_service = { factory(owner_, owner) };
31
Calling 'service_registry::create'
67
Returning from 'service_registry::create'
139 new_service.ptr_->key_ = key;
140 lock.lock();
141
142 // Check that nobody else created another service object of the same type
143 // while the lock was released.
144 service = first_service_;
145 while (service)
44
Loop condition is false. Execution continues on line 153
58
Loop condition is false. Execution continues on line 153
68
Loop condition is false. Execution continues on line 153
146 {
147 if (keys_match(service->key_, key))
148 return service;
149 service = service->next_;
150 }
151
152 // Service was successfully initialised, pass ownership to registry.
153 new_service.ptr_->next_ = first_service_;
154 first_service_ = new_service.ptr_;
155 new_service.ptr_ = 0;
156 return first_service_;
157}
158
159void service_registry::do_add_service(
160 const execution_context::service::key& key,
161 execution_context::service* new_service)
162{
163 if (&owner_ != &new_service->context())
164 boost::asio::detail::throw_exception(invalid_service_owner());
165
166 boost::asio::detail::mutex::scoped_lock lock(mutex_);
167
168 // Check if there is an existing service object with the given key.
169 execution_context::service* service = first_service_;
170 while (service)
171 {
172 if (keys_match(service->key_, key))
173 boost::asio::detail::throw_exception(service_already_exists());
174 service = service->next_;
175 }
176
177 // Take ownership of the service object.
178 if (!new_service->destroy_)
179 new_service->destroy_ = &service_registry::destroy_added;
180 new_service->key_ = key;
181 new_service->next_ = first_service_;
182 first_service_ = new_service;
183}
184
185bool service_registry::do_has_service(
186 const execution_context::service::key& key) const
187{
188 boost::asio::detail::mutex::scoped_lock lock(mutex_);
189
190 execution_context::service* service = first_service_;
191 while (service)
192 {
193 if (keys_match(service->key_, key))
194 return true;
195 service = service->next_;
196 }
197
198 return false;
199}
200
201} // namespace detail
202} // namespace asio
203} // namespace boost
204
205#include <boost/asio/detail/pop_options.hpp>
206
207#endif // BOOST_ASIO_DETAIL_IMPL_SERVICE_REGISTRY_IPP

/usr/include/boost/asio/detail/memory.hpp

1//
2// detail/memory.hpp
3// ~~~~~~~~~~~~~~~~~
4//
5// Copyright (c) 2003-2025 Christopher M. Kohlhoff (chris at kohlhoff dot com)
6//
7// Distributed under the Boost Software License, Version 1.0. (See accompanying
8// file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt)
9//
10
11#ifndef BOOST_ASIO_DETAIL_MEMORY_HPP
12#define BOOST_ASIO_DETAIL_MEMORY_HPP
13
14#if defined(_MSC_VER) && (_MSC_VER >= 1200)
15# pragma once
16#endif // defined(_MSC_VER) && (_MSC_VER >= 1200)
17
18#include <boost/asio/detail/config.hpp>
19#include <cstddef>
20#include <cstdlib>
21#include <memory>
22#include <new>
23#include <boost/asio/detail/cstdint.hpp>
24#include <boost/asio/detail/throw_exception.hpp>
25
26#if !defined(BOOST_ASIO_HAS_STD_ALIGNED_ALLOC1) \
27 && defined(BOOST_ASIO_HAS_BOOST_ALIGN1)
28# include <boost/align/aligned_alloc.hpp>
29#endif // !defined(BOOST_ASIO_HAS_STD_ALIGNED_ALLOC)
30 // && defined(BOOST_ASIO_HAS_BOOST_ALIGN)
31
32namespace boost {
33namespace asio {
34namespace detail {
35
36using std::allocate_shared;
37using std::make_shared;
38using std::shared_ptr;
39using std::weak_ptr;
40using std::addressof;
41
42#if defined(BOOST_ASIO_HAS_STD_TO_ADDRESS)
43using std::to_address;
44#else // defined(BOOST_ASIO_HAS_STD_TO_ADDRESS)
45template <typename T>
46inline T* to_address(T* p) { return p; }
47template <typename T>
48inline const T* to_address(const T* p) { return p; }
49template <typename T>
50inline volatile T* to_address(volatile T* p) { return p; }
51template <typename T>
52inline const volatile T* to_address(const volatile T* p) { return p; }
53#endif // defined(BOOST_ASIO_HAS_STD_TO_ADDRESS)
54
55inline void* align(std::size_t alignment,
56 std::size_t size, void*& ptr, std::size_t& space)
57{
58 return std::align(alignment, size, ptr, space);
59}
60
61template <typename T, typename Allocator, typename... Args>
62T* allocate_object(const Allocator& a, Args&&... args)
63{
64 typename std::allocator_traits<Allocator>::template rebind_alloc<T> alloc(a);
65 T* raw = std::allocator_traits<decltype(alloc)>::allocate(alloc, 1);
66#if !defined(BOOST_ASIO_NO_EXCEPTIONS)
67 try
68#endif // !defined(BOOST_ASIO_NO_EXCEPTIONS)
69 {
70 return new (raw) T(static_cast<Args&&>(args)...);
33
Calling constructor for 'reactive_socket_service<boost::asio::ip::tcp>'
65
Returning from constructor for 'reactive_socket_service<boost::asio::ip::tcp>'
71 }
72#if !defined(BOOST_ASIO_NO_EXCEPTIONS)
73 catch (...)
74 {
75 std::allocator_traits<decltype(alloc)>::deallocate(alloc, raw, 1);
76 throw;
77 }
78#endif // !defined(BOOST_ASIO_NO_EXCEPTIONS)
79}
80
81template <typename Allocator, typename T>
82void deallocate_object(const Allocator& a, T* ptr)
83{
84 typename std::allocator_traits<Allocator>::template rebind_alloc<T> alloc(a);
85 std::allocator_traits<decltype(alloc)>::destroy(alloc, ptr);
86 std::allocator_traits<decltype(alloc)>::deallocate(alloc, ptr, 1);
87}
88
89} // namespace detail
90
91using std::allocator_arg_t;
92# define BOOST_ASIO_USES_ALLOCATOR(t)namespace std { template <typename Allocator> struct uses_allocator
<t, Allocator> : true_type {}; }
\
93 namespace std { \
94 template <typename Allocator> \
95 struct uses_allocator<t, Allocator> : true_type {}; \
96 } \
97 /**/
98# define BOOST_ASIO_REBIND_ALLOC(alloc, t)typename std::allocator_traits<alloc>::template rebind_alloc
<t>
\
99 typename std::allocator_traits<alloc>::template rebind_alloc<t>
100 /**/
101
102inline void* aligned_new(std::size_t align, std::size_t size)
103{
104#if defined(BOOST_ASIO_HAS_STD_ALIGNED_ALLOC1)
105 align = (align < BOOST_ASIO_DEFAULT_ALIGN16UL) ? BOOST_ASIO_DEFAULT_ALIGN16UL : align;
106 size = (size % align == 0) ? size : size + (align - size % align);
107 void* ptr = std::aligned_alloc(align, size);
108 if (!ptr)
109 {
110 std::bad_alloc ex;
111 boost::asio::detail::throw_exception(ex);
112 }
113 return ptr;
114#elif defined(BOOST_ASIO_HAS_BOOST_ALIGN1)
115 align = (align < BOOST_ASIO_DEFAULT_ALIGN16UL) ? BOOST_ASIO_DEFAULT_ALIGN16UL : align;
116 size = (size % align == 0) ? size : size + (align - size % align);
117 void* ptr = boost::alignment::aligned_alloc(align, size);
118 if (!ptr)
119 {
120 std::bad_alloc ex;
121 boost::asio::detail::throw_exception(ex);
122 }
123 return ptr;
124#elif defined(BOOST_ASIO_MSVC)
125 align = (align < BOOST_ASIO_DEFAULT_ALIGN16UL) ? BOOST_ASIO_DEFAULT_ALIGN16UL : align;
126 size = (size % align == 0) ? size : size + (align - size % align);
127 void* ptr = _aligned_malloc(size, align);
128 if (!ptr)
129 {
130 std::bad_alloc ex;
131 boost::asio::detail::throw_exception(ex);
132 }
133 return ptr;
134#else // defined(BOOST_ASIO_MSVC)
135 (void)align;
136 return ::operator new(size);
137#endif // defined(BOOST_ASIO_MSVC)
138}
139
140inline void aligned_delete(void* ptr)
141{
142#if defined(BOOST_ASIO_HAS_STD_ALIGNED_ALLOC1)
143 std::free(ptr);
144#elif defined(BOOST_ASIO_HAS_BOOST_ALIGN1)
145 boost::alignment::aligned_free(ptr);
146#elif defined(BOOST_ASIO_MSVC)
147 _aligned_free(ptr);
148#else // defined(BOOST_ASIO_MSVC)
149 ::operator delete(ptr);
150#endif // defined(BOOST_ASIO_MSVC)
151}
152
153} // namespace asio
154} // namespace boost
155
156#endif // BOOST_ASIO_DETAIL_MEMORY_HPP

/usr/include/boost/asio/detail/reactive_socket_service.hpp

1//
2// detail/reactive_socket_service.hpp
3// ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
4//
5// Copyright (c) 2003-2025 Christopher M. Kohlhoff (chris at kohlhoff dot com)
6//
7// Distributed under the Boost Software License, Version 1.0. (See accompanying
8// file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt)
9//
10
11#ifndef BOOST_ASIO_DETAIL_REACTIVE_SOCKET_SERVICE_HPP
12#define BOOST_ASIO_DETAIL_REACTIVE_SOCKET_SERVICE_HPP
13
14#if defined(_MSC_VER) && (_MSC_VER >= 1200)
15# pragma once
16#endif // defined(_MSC_VER) && (_MSC_VER >= 1200)
17
18#include <boost/asio/detail/config.hpp>
19
20#if !defined(BOOST_ASIO_HAS_IOCP) \
21 && !defined(BOOST_ASIO_HAS_IO_URING_AS_DEFAULT)
22
23#include <boost/asio/buffer.hpp>
24#include <boost/asio/error.hpp>
25#include <boost/asio/execution_context.hpp>
26#include <boost/asio/socket_base.hpp>
27#include <boost/asio/detail/buffer_sequence_adapter.hpp>
28#include <boost/asio/detail/memory.hpp>
29#include <boost/asio/detail/noncopyable.hpp>
30#include <boost/asio/detail/reactive_null_buffers_op.hpp>
31#include <boost/asio/detail/reactive_socket_accept_op.hpp>
32#include <boost/asio/detail/reactive_socket_connect_op.hpp>
33#include <boost/asio/detail/reactive_socket_recvfrom_op.hpp>
34#include <boost/asio/detail/reactive_socket_sendto_op.hpp>
35#include <boost/asio/detail/reactive_socket_service_base.hpp>
36#include <boost/asio/detail/reactor.hpp>
37#include <boost/asio/detail/reactor_op.hpp>
38#include <boost/asio/detail/socket_holder.hpp>
39#include <boost/asio/detail/socket_ops.hpp>
40#include <boost/asio/detail/socket_types.hpp>
41
42#include <boost/asio/detail/push_options.hpp>
43
44namespace boost {
45namespace asio {
46namespace detail {
47
48template <typename Protocol>
49class reactive_socket_service :
50 public execution_context_service_base<reactive_socket_service<Protocol>>,
51 public reactive_socket_service_base
52{
53public:
54 // The protocol type.
55 typedef Protocol protocol_type;
56
57 // The endpoint type.
58 typedef typename Protocol::endpoint endpoint_type;
59
60 // The native type of a socket.
61 typedef socket_type native_handle_type;
62
63 // The implementation type of the socket.
64 struct implementation_type :
65 reactive_socket_service_base::base_implementation_type
66 {
67 // Default constructor.
68 implementation_type()
69 : protocol_(endpoint_type().protocol())
70 {
71 }
72
73 // The protocol associated with the socket.
74 protocol_type protocol_;
75 };
76
77 // Constructor.
78 reactive_socket_service(execution_context& context)
79 : execution_context_service_base<
80 reactive_socket_service<Protocol>>(context),
81 reactive_socket_service_base(context)
34
Calling constructor for 'reactive_socket_service_base'
64
Returning from constructor for 'reactive_socket_service_base'
82 {
83 }
84
85 // Destroy all user-defined handler objects owned by the service.
86 void shutdown()
87 {
88 this->base_shutdown();
89 }
90
91 // Move-construct a new socket implementation.
92 void move_construct(implementation_type& impl,
93 implementation_type& other_impl) noexcept
94 {
95 this->base_move_construct(impl, other_impl);
96
97 impl.protocol_ = other_impl.protocol_;
98 other_impl.protocol_ = endpoint_type().protocol();
99 }
100
101 // Move-assign from another socket implementation.
102 void move_assign(implementation_type& impl,
103 reactive_socket_service_base& other_service,
104 implementation_type& other_impl)
105 {
106 this->base_move_assign(impl, other_service, other_impl);
107
108 impl.protocol_ = other_impl.protocol_;
109 other_impl.protocol_ = endpoint_type().protocol();
110 }
111
112 // Move-construct a new socket implementation from another protocol type.
113 template <typename Protocol1>
114 void converting_move_construct(implementation_type& impl,
115 reactive_socket_service<Protocol1>&,
116 typename reactive_socket_service<
117 Protocol1>::implementation_type& other_impl)
118 {
119 this->base_move_construct(impl, other_impl);
120
121 impl.protocol_ = protocol_type(other_impl.protocol_);
122 other_impl.protocol_ = typename Protocol1::endpoint().protocol();
123 }
124
125 // Open a new socket implementation.
126 boost::system::error_code open(implementation_type& impl,
127 const protocol_type& protocol, boost::system::error_code& ec)
128 {
129 if (!do_open(impl, protocol.family(),
130 protocol.type(), protocol.protocol(), ec))
131 impl.protocol_ = protocol;
132
133 BOOST_ASIO_ERROR_LOCATION(ec)do { static constexpr boost::source_location loc = ::boost::source_location
(__builtin_FILE(), __builtin_LINE(), __builtin_FUNCTION(), __builtin_COLUMN
()); (ec).assign((ec), &loc); } while (false)
;
134 return ec;
135 }
136
137 // Assign a native socket to a socket implementation.
138 boost::system::error_code assign(implementation_type& impl,
139 const protocol_type& protocol, const native_handle_type& native_socket,
140 boost::system::error_code& ec)
141 {
142 if (!do_assign(impl, protocol.type(), native_socket, ec))
143 impl.protocol_ = protocol;
144
145 BOOST_ASIO_ERROR_LOCATION(ec)do { static constexpr boost::source_location loc = ::boost::source_location
(__builtin_FILE(), __builtin_LINE(), __builtin_FUNCTION(), __builtin_COLUMN
()); (ec).assign((ec), &loc); } while (false)
;
146 return ec;
147 }
148
149 // Get the native socket representation.
150 native_handle_type native_handle(implementation_type& impl)
151 {
152 return impl.socket_;
153 }
154
155 // Bind the socket to the specified local endpoint.
156 boost::system::error_code bind(implementation_type& impl,
157 const endpoint_type& endpoint, boost::system::error_code& ec)
158 {
159 socket_ops::bind(impl.socket_, endpoint.data(), endpoint.size(), ec);
160
161 BOOST_ASIO_ERROR_LOCATION(ec)do { static constexpr boost::source_location loc = ::boost::source_location
(__builtin_FILE(), __builtin_LINE(), __builtin_FUNCTION(), __builtin_COLUMN
()); (ec).assign((ec), &loc); } while (false)
;
162 return ec;
163 }
164
165 // Set a socket option.
166 template <typename Option>
167 boost::system::error_code set_option(implementation_type& impl,
168 const Option& option, boost::system::error_code& ec)
169 {
170 socket_ops::setsockopt(impl.socket_, impl.state_,
171 option.level(impl.protocol_), option.name(impl.protocol_),
172 option.data(impl.protocol_), option.size(impl.protocol_), ec);
173
174 BOOST_ASIO_ERROR_LOCATION(ec)do { static constexpr boost::source_location loc = ::boost::source_location
(__builtin_FILE(), __builtin_LINE(), __builtin_FUNCTION(), __builtin_COLUMN
()); (ec).assign((ec), &loc); } while (false)
;
175 return ec;
176 }
177
178 // Set a socket option.
179 template <typename Option>
180 boost::system::error_code get_option(const implementation_type& impl,
181 Option& option, boost::system::error_code& ec) const
182 {
183 std::size_t size = option.size(impl.protocol_);
184 socket_ops::getsockopt(impl.socket_, impl.state_,
185 option.level(impl.protocol_), option.name(impl.protocol_),
186 option.data(impl.protocol_), &size, ec);
187 if (!ec)
188 option.resize(impl.protocol_, size);
189
190 BOOST_ASIO_ERROR_LOCATION(ec)do { static constexpr boost::source_location loc = ::boost::source_location
(__builtin_FILE(), __builtin_LINE(), __builtin_FUNCTION(), __builtin_COLUMN
()); (ec).assign((ec), &loc); } while (false)
;
191 return ec;
192 }
193
194 // Get the local endpoint.
195 endpoint_type local_endpoint(const implementation_type& impl,
196 boost::system::error_code& ec) const
197 {
198 endpoint_type endpoint;
199 std::size_t addr_len = endpoint.capacity();
200 if (socket_ops::getsockname(impl.socket_, endpoint.data(), &addr_len, ec))
201 {
202 BOOST_ASIO_ERROR_LOCATION(ec)do { static constexpr boost::source_location loc = ::boost::source_location
(__builtin_FILE(), __builtin_LINE(), __builtin_FUNCTION(), __builtin_COLUMN
()); (ec).assign((ec), &loc); } while (false)
;
203 return endpoint_type();
204 }
205 endpoint.resize(addr_len);
206 return endpoint;
207 }
208
209 // Get the remote endpoint.
210 endpoint_type remote_endpoint(const implementation_type& impl,
211 boost::system::error_code& ec) const
212 {
213 endpoint_type endpoint;
214 std::size_t addr_len = endpoint.capacity();
215 if (socket_ops::getpeername(impl.socket_,
216 endpoint.data(), &addr_len, false, ec))
217 {
218 BOOST_ASIO_ERROR_LOCATION(ec)do { static constexpr boost::source_location loc = ::boost::source_location
(__builtin_FILE(), __builtin_LINE(), __builtin_FUNCTION(), __builtin_COLUMN
()); (ec).assign((ec), &loc); } while (false)
;
219 return endpoint_type();
220 }
221 endpoint.resize(addr_len);
222 return endpoint;
223 }
224
225 // Disable sends or receives on the socket.
226 boost::system::error_code shutdown(base_implementation_type& impl,
227 socket_base::shutdown_type what, boost::system::error_code& ec)
228 {
229 socket_ops::shutdown(impl.socket_, what, ec);
230
231 BOOST_ASIO_ERROR_LOCATION(ec)do { static constexpr boost::source_location loc = ::boost::source_location
(__builtin_FILE(), __builtin_LINE(), __builtin_FUNCTION(), __builtin_COLUMN
()); (ec).assign((ec), &loc); } while (false)
;
232 return ec;
233 }
234
235 // Send a datagram to the specified endpoint. Returns the number of bytes
236 // sent.
237 template <typename ConstBufferSequence>
238 size_t send_to(implementation_type& impl, const ConstBufferSequence& buffers,
239 const endpoint_type& destination, socket_base::message_flags flags,
240 boost::system::error_code& ec)
241 {
242 typedef buffer_sequence_adapter<boost::asio::const_buffer,
243 ConstBufferSequence> bufs_type;
244
245 size_t n;
246 if (bufs_type::is_single_buffer)
247 {
248 n = socket_ops::sync_sendto1(impl.socket_, impl.state_,
249 bufs_type::first(buffers).data(),
250 bufs_type::first(buffers).size(), flags,
251 destination.data(), destination.size(), ec);
252 }
253 else
254 {
255 bufs_type bufs(buffers);
256 n = socket_ops::sync_sendto(impl.socket_, impl.state_,
257 bufs.buffers(), bufs.count(), flags,
258 destination.data(), destination.size(), ec);
259 }
260
261 BOOST_ASIO_ERROR_LOCATION(ec)do { static constexpr boost::source_location loc = ::boost::source_location
(__builtin_FILE(), __builtin_LINE(), __builtin_FUNCTION(), __builtin_COLUMN
()); (ec).assign((ec), &loc); } while (false)
;
262 return n;
263 }
264
265 // Wait until data can be sent without blocking.
266 size_t send_to(implementation_type& impl, const null_buffers&,
267 const endpoint_type&, socket_base::message_flags,
268 boost::system::error_code& ec)
269 {
270 // Wait for socket to become ready.
271 socket_ops::poll_write(impl.socket_, impl.state_, -1, ec);
272
273 BOOST_ASIO_ERROR_LOCATION(ec)do { static constexpr boost::source_location loc = ::boost::source_location
(__builtin_FILE(), __builtin_LINE(), __builtin_FUNCTION(), __builtin_COLUMN
()); (ec).assign((ec), &loc); } while (false)
;
274 return 0;
275 }
276
277 // Start an asynchronous send. The data being sent must be valid for the
278 // lifetime of the asynchronous operation.
279 template <typename ConstBufferSequence, typename Handler, typename IoExecutor>
280 void async_send_to(implementation_type& impl,
281 const ConstBufferSequence& buffers,
282 const endpoint_type& destination, socket_base::message_flags flags,
283 Handler& handler, const IoExecutor& io_ex)
284 {
285 bool is_continuation =
286 boost_asio_handler_cont_helpers::is_continuation(handler);
287
288 associated_cancellation_slot_t<Handler> slot
289 = boost::asio::get_associated_cancellation_slot(handler);
290
291 // Allocate and construct an operation to wrap the handler.
292 typedef reactive_socket_sendto_op<ConstBufferSequence,
293 endpoint_type, Handler, IoExecutor> op;
294 typename op::ptr p = { boost::asio::detail::addressof(handler),
295 op::ptr::allocate(handler), 0 };
296 p.p = new (p.v) op(success_ec_, impl.socket_,
297 buffers, destination, flags, handler, io_ex);
298
299 // Optionally register for per-operation cancellation.
300 if (slot.is_connected())
301 {
302 p.p->cancellation_key_ =
303 &slot.template emplace<reactor_op_cancellation>(
304 &reactor_, &impl.reactor_data_, impl.socket_, reactor::write_op);
305 }
306
307 BOOST_ASIO_HANDLER_CREATION((reactor_.context(), *p.p, "socket",(void)0
308 &impl, impl.socket_, "async_send_to"))(void)0;
309
310 start_op(impl, reactor::write_op, p.p,
311 is_continuation, true, false, true, &io_ex, 0);
312 p.v = p.p = 0;
313 }
314
315 // Start an asynchronous wait until data can be sent without blocking.
316 template <typename Handler, typename IoExecutor>
317 void async_send_to(implementation_type& impl, const null_buffers&,
318 const endpoint_type&, socket_base::message_flags,
319 Handler& handler, const IoExecutor& io_ex)
320 {
321 bool is_continuation =
322 boost_asio_handler_cont_helpers::is_continuation(handler);
323
324 associated_cancellation_slot_t<Handler> slot
325 = boost::asio::get_associated_cancellation_slot(handler);
326
327 // Allocate and construct an operation to wrap the handler.
328 typedef reactive_null_buffers_op<Handler, IoExecutor> op;
329 typename op::ptr p = { boost::asio::detail::addressof(handler),
330 op::ptr::allocate(handler), 0 };
331 p.p = new (p.v) op(success_ec_, handler, io_ex);
332
333 // Optionally register for per-operation cancellation.
334 if (slot.is_connected())
335 {
336 p.p->cancellation_key_ =
337 &slot.template emplace<reactor_op_cancellation>(
338 &reactor_, &impl.reactor_data_, impl.socket_, reactor::write_op);
339 }
340
341 BOOST_ASIO_HANDLER_CREATION((reactor_.context(), *p.p, "socket",(void)0
342 &impl, impl.socket_, "async_send_to(null_buffers)"))(void)0;
343
344 start_op(impl, reactor::write_op, p.p,
345 is_continuation, false, false, false, &io_ex, 0);
346 p.v = p.p = 0;
347 }
348
349 // Receive a datagram with the endpoint of the sender. Returns the number of
350 // bytes received.
351 template <typename MutableBufferSequence>
352 size_t receive_from(implementation_type& impl,
353 const MutableBufferSequence& buffers,
354 endpoint_type& sender_endpoint, socket_base::message_flags flags,
355 boost::system::error_code& ec)
356 {
357 typedef buffer_sequence_adapter<boost::asio::mutable_buffer,
358 MutableBufferSequence> bufs_type;
359
360 std::size_t addr_len = sender_endpoint.capacity();
361 std::size_t n;
362 if (bufs_type::is_single_buffer)
363 {
364 n = socket_ops::sync_recvfrom1(impl.socket_, impl.state_,
365 bufs_type::first(buffers).data(), bufs_type::first(buffers).size(),
366 flags, sender_endpoint.data(), &addr_len, ec);
367 }
368 else
369 {
370 bufs_type bufs(buffers);
371 n = socket_ops::sync_recvfrom(impl.socket_, impl.state_, bufs.buffers(),
372 bufs.count(), flags, sender_endpoint.data(), &addr_len, ec);
373 }
374
375 if (!ec)
376 sender_endpoint.resize(addr_len);
377
378 BOOST_ASIO_ERROR_LOCATION(ec)do { static constexpr boost::source_location loc = ::boost::source_location
(__builtin_FILE(), __builtin_LINE(), __builtin_FUNCTION(), __builtin_COLUMN
()); (ec).assign((ec), &loc); } while (false)
;
379 return n;
380 }
381
382 // Wait until data can be received without blocking.
383 size_t receive_from(implementation_type& impl, const null_buffers&,
384 endpoint_type& sender_endpoint, socket_base::message_flags,
385 boost::system::error_code& ec)
386 {
387 // Wait for socket to become ready.
388 socket_ops::poll_read(impl.socket_, impl.state_, -1, ec);
389
390 // Reset endpoint since it can be given no sensible value at this time.
391 sender_endpoint = endpoint_type();
392
393 BOOST_ASIO_ERROR_LOCATION(ec)do { static constexpr boost::source_location loc = ::boost::source_location
(__builtin_FILE(), __builtin_LINE(), __builtin_FUNCTION(), __builtin_COLUMN
()); (ec).assign((ec), &loc); } while (false)
;
394 return 0;
395 }
396
397 // Start an asynchronous receive. The buffer for the data being received and
398 // the sender_endpoint object must both be valid for the lifetime of the
399 // asynchronous operation.
400 template <typename MutableBufferSequence,
401 typename Handler, typename IoExecutor>
402 void async_receive_from(implementation_type& impl,
403 const MutableBufferSequence& buffers, endpoint_type& sender_endpoint,
404 socket_base::message_flags flags, Handler& handler,
405 const IoExecutor& io_ex)
406 {
407 bool is_continuation =
408 boost_asio_handler_cont_helpers::is_continuation(handler);
409
410 associated_cancellation_slot_t<Handler> slot
411 = boost::asio::get_associated_cancellation_slot(handler);
412
413 // Allocate and construct an operation to wrap the handler.
414 typedef reactive_socket_recvfrom_op<MutableBufferSequence,
415 endpoint_type, Handler, IoExecutor> op;
416 typename op::ptr p = { boost::asio::detail::addressof(handler),
417 op::ptr::allocate(handler), 0 };
418 int protocol = impl.protocol_.type();
419 p.p = new (p.v) op(success_ec_, impl.socket_, protocol,
420 buffers, sender_endpoint, flags, handler, io_ex);
421
422 // Optionally register for per-operation cancellation.
423 if (slot.is_connected())
424 {
425 p.p->cancellation_key_ =
426 &slot.template emplace<reactor_op_cancellation>(
427 &reactor_, &impl.reactor_data_, impl.socket_, reactor::read_op);
428 }
429
430 BOOST_ASIO_HANDLER_CREATION((reactor_.context(), *p.p, "socket",(void)0
431 &impl, impl.socket_, "async_receive_from"))(void)0;
432
433 start_op(impl,
434 (flags & socket_base::message_out_of_band)
435 ? reactor::except_op : reactor::read_op,
436 p.p, is_continuation, true, false, true, &io_ex, 0);
437 p.v = p.p = 0;
438 }
439
440 // Wait until data can be received without blocking.
441 template <typename Handler, typename IoExecutor>
442 void async_receive_from(implementation_type& impl, const null_buffers&,
443 endpoint_type& sender_endpoint, socket_base::message_flags flags,
444 Handler& handler, const IoExecutor& io_ex)
445 {
446 bool is_continuation =
447 boost_asio_handler_cont_helpers::is_continuation(handler);
448
449 associated_cancellation_slot_t<Handler> slot
450 = boost::asio::get_associated_cancellation_slot(handler);
451
452 // Allocate and construct an operation to wrap the handler.
453 typedef reactive_null_buffers_op<Handler, IoExecutor> op;
454 typename op::ptr p = { boost::asio::detail::addressof(handler),
455 op::ptr::allocate(handler), 0 };
456 p.p = new (p.v) op(success_ec_, handler, io_ex);
457
458 // Optionally register for per-operation cancellation.
459 if (slot.is_connected())
460 {
461 p.p->cancellation_key_ =
462 &slot.template emplace<reactor_op_cancellation>(
463 &reactor_, &impl.reactor_data_, impl.socket_, reactor::read_op);
464 }
465
466 BOOST_ASIO_HANDLER_CREATION((reactor_.context(), *p.p, "socket",(void)0
467 &impl, impl.socket_, "async_receive_from(null_buffers)"))(void)0;
468
469 // Reset endpoint since it can be given no sensible value at this time.
470 sender_endpoint = endpoint_type();
471
472 start_op(impl,
473 (flags & socket_base::message_out_of_band)
474 ? reactor::except_op : reactor::read_op,
475 p.p, is_continuation, false, false, false, &io_ex, 0);
476 p.v = p.p = 0;
477 }
478
479 // Accept a new connection.
480 template <typename Socket>
481 boost::system::error_code accept(implementation_type& impl,
482 Socket& peer, endpoint_type* peer_endpoint, boost::system::error_code& ec)
483 {
484 // We cannot accept a socket that is already open.
485 if (peer.is_open())
486 {
487 ec = boost::asio::error::already_open;
488 BOOST_ASIO_ERROR_LOCATION(ec)do { static constexpr boost::source_location loc = ::boost::source_location
(__builtin_FILE(), __builtin_LINE(), __builtin_FUNCTION(), __builtin_COLUMN
()); (ec).assign((ec), &loc); } while (false)
;
489 return ec;
490 }
491
492 std::size_t addr_len = peer_endpoint ? peer_endpoint->capacity() : 0;
493 socket_holder new_socket(socket_ops::sync_accept(impl.socket_,
494 impl.state_, peer_endpoint ? peer_endpoint->data() : 0,
495 peer_endpoint ? &addr_len : 0, ec));
496
497 // On success, assign new connection to peer socket object.
498 if (new_socket.get() != invalid_socket)
499 {
500 if (peer_endpoint)
501 peer_endpoint->resize(addr_len);
502 peer.assign(impl.protocol_, new_socket.get(), ec);
503 if (!ec)
504 new_socket.release();
505 }
506
507 BOOST_ASIO_ERROR_LOCATION(ec)do { static constexpr boost::source_location loc = ::boost::source_location
(__builtin_FILE(), __builtin_LINE(), __builtin_FUNCTION(), __builtin_COLUMN
()); (ec).assign((ec), &loc); } while (false)
;
508 return ec;
509 }
510
511 // Start an asynchronous accept. The peer and peer_endpoint objects must be
512 // valid until the accept's handler is invoked.
513 template <typename Socket, typename Handler, typename IoExecutor>
514 void async_accept(implementation_type& impl, Socket& peer,
515 endpoint_type* peer_endpoint, Handler& handler, const IoExecutor& io_ex)
516 {
517 bool is_continuation =
518 boost_asio_handler_cont_helpers::is_continuation(handler);
519
520 associated_cancellation_slot_t<Handler> slot
521 = boost::asio::get_associated_cancellation_slot(handler);
522
523 // Allocate and construct an operation to wrap the handler.
524 typedef reactive_socket_accept_op<Socket, Protocol, Handler, IoExecutor> op;
525 typename op::ptr p = { boost::asio::detail::addressof(handler),
526 op::ptr::allocate(handler), 0 };
527 p.p = new (p.v) op(success_ec_, impl.socket_, impl.state_,
528 peer, impl.protocol_, peer_endpoint, handler, io_ex);
529
530 // Optionally register for per-operation cancellation.
531 if (slot.is_connected() && !peer.is_open())
532 {
533 p.p->cancellation_key_ =
534 &slot.template emplace<reactor_op_cancellation>(
535 &reactor_, &impl.reactor_data_, impl.socket_, reactor::read_op);
536 }
537
538 BOOST_ASIO_HANDLER_CREATION((reactor_.context(), *p.p, "socket",(void)0
539 &impl, impl.socket_, "async_accept"))(void)0;
540
541 start_accept_op(impl, p.p, is_continuation, peer.is_open(), &io_ex, 0);
542 p.v = p.p = 0;
543 }
544
545 // Start an asynchronous accept. The peer_endpoint object must be valid until
546 // the accept's handler is invoked.
547 template <typename PeerIoExecutor, typename Handler, typename IoExecutor>
548 void async_move_accept(implementation_type& impl,
549 const PeerIoExecutor& peer_io_ex, endpoint_type* peer_endpoint,
550 Handler& handler, const IoExecutor& io_ex)
551 {
552 bool is_continuation =
553 boost_asio_handler_cont_helpers::is_continuation(handler);
554
555 associated_cancellation_slot_t<Handler> slot
556 = boost::asio::get_associated_cancellation_slot(handler);
557
558 // Allocate and construct an operation to wrap the handler.
559 typedef reactive_socket_move_accept_op<Protocol,
560 PeerIoExecutor, Handler, IoExecutor> op;
561 typename op::ptr p = { boost::asio::detail::addressof(handler),
562 op::ptr::allocate(handler), 0 };
563 p.p = new (p.v) op(success_ec_, peer_io_ex, impl.socket_,
564 impl.state_, impl.protocol_, peer_endpoint, handler, io_ex);
565
566 // Optionally register for per-operation cancellation.
567 if (slot.is_connected())
568 {
569 p.p->cancellation_key_ =
570 &slot.template emplace<reactor_op_cancellation>(
571 &reactor_, &impl.reactor_data_, impl.socket_, reactor::read_op);
572 }
573
574 BOOST_ASIO_HANDLER_CREATION((reactor_.context(), *p.p, "socket",(void)0
575 &impl, impl.socket_, "async_accept"))(void)0;
576
577 start_accept_op(impl, p.p, is_continuation, false, &io_ex, 0);
578 p.v = p.p = 0;
579 }
580
581 // Connect the socket to the specified endpoint.
582 boost::system::error_code connect(implementation_type& impl,
583 const endpoint_type& peer_endpoint, boost::system::error_code& ec)
584 {
585 socket_ops::sync_connect(impl.socket_,
586 peer_endpoint.data(), peer_endpoint.size(), ec);
587 BOOST_ASIO_ERROR_LOCATION(ec)do { static constexpr boost::source_location loc = ::boost::source_location
(__builtin_FILE(), __builtin_LINE(), __builtin_FUNCTION(), __builtin_COLUMN
()); (ec).assign((ec), &loc); } while (false)
;
588 return ec;
589 }
590
591 // Start an asynchronous connect.
592 template <typename Handler, typename IoExecutor>
593 void async_connect(implementation_type& impl,
594 const endpoint_type& peer_endpoint,
595 Handler& handler, const IoExecutor& io_ex)
596 {
597 bool is_continuation =
598 boost_asio_handler_cont_helpers::is_continuation(handler);
599
600 associated_cancellation_slot_t<Handler> slot
601 = boost::asio::get_associated_cancellation_slot(handler);
602
603 // Allocate and construct an operation to wrap the handler.
604 typedef reactive_socket_connect_op<Handler, IoExecutor> op;
605 typename op::ptr p = { boost::asio::detail::addressof(handler),
606 op::ptr::allocate(handler), 0 };
607 p.p = new (p.v) op(success_ec_, impl.socket_, handler, io_ex);
608
609 // Optionally register for per-operation cancellation.
610 if (slot.is_connected())
611 {
612 p.p->cancellation_key_ =
613 &slot.template emplace<reactor_op_cancellation>(
614 &reactor_, &impl.reactor_data_, impl.socket_, reactor::connect_op);
615 }
616
617 BOOST_ASIO_HANDLER_CREATION((reactor_.context(), *p.p, "socket",(void)0
618 &impl, impl.socket_, "async_connect"))(void)0;
619
620 start_connect_op(impl, p.p, is_continuation,
621 peer_endpoint.data(), peer_endpoint.size(), &io_ex, 0);
622 p.v = p.p = 0;
623 }
624};
625
626} // namespace detail
627} // namespace asio
628} // namespace boost
629
630#include <boost/asio/detail/pop_options.hpp>
631
632#endif // !defined(BOOST_ASIO_HAS_IOCP)
633 // && !defined(BOOST_ASIO_HAS_IO_URING_AS_DEFAULT)
634
635#endif // BOOST_ASIO_DETAIL_REACTIVE_SOCKET_SERVICE_HPP

/usr/include/boost/asio/detail/impl/reactive_socket_service_base.ipp

1//
2// detail/reactive_socket_service_base.ipp
3// ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
4//
5// Copyright (c) 2003-2025 Christopher M. Kohlhoff (chris at kohlhoff dot com)
6//
7// Distributed under the Boost Software License, Version 1.0. (See accompanying
8// file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt)
9//
10
11#ifndef BOOST_ASIO_DETAIL_IMPL_REACTIVE_SOCKET_SERVICE_BASE_IPP
12#define BOOST_ASIO_DETAIL_IMPL_REACTIVE_SOCKET_SERVICE_BASE_IPP
13
14#if defined(_MSC_VER) && (_MSC_VER >= 1200)
15# pragma once
16#endif // defined(_MSC_VER) && (_MSC_VER >= 1200)
17
18#include <boost/asio/detail/config.hpp>
19
20#if !defined(BOOST_ASIO_HAS_IOCP) \
21 && !defined(BOOST_ASIO_WINDOWS_RUNTIME) \
22 && !defined(BOOST_ASIO_HAS_IO_URING_AS_DEFAULT)
23
24#include <boost/asio/config.hpp>
25#include <boost/asio/detail/reactive_socket_service_base.hpp>
26
27#include <boost/asio/detail/push_options.hpp>
28
29namespace boost {
30namespace asio {
31namespace detail {
32
33reactive_socket_service_base::reactive_socket_service_base(
34 execution_context& context)
35 : reactor_(use_service<reactor>(context)),
35
Calling 'use_service<boost::asio::detail::epoll_reactor>'
47
Returning from 'use_service<boost::asio::detail::epoll_reactor>'
36 extra_state_(
37 boost::asio::config(context).get(
48
Calling constructor for 'config'
62
Returning from constructor for 'config'
63
'?' condition is false
38 "reactor", "reset_edge_on_partial_read", 0)
39 ? socket_ops::reset_edge_on_partial_read : 0)
40{
41 reactor_.init_task();
42}
43
44void reactive_socket_service_base::base_shutdown()
45{
46}
47
48void reactive_socket_service_base::construct(
49 reactive_socket_service_base::base_implementation_type& impl)
50{
51 impl.socket_ = invalid_socket;
52 impl.state_ = 0;
53 impl.reactor_data_ = reactor::per_descriptor_data();
54}
55
56void reactive_socket_service_base::base_move_construct(
57 reactive_socket_service_base::base_implementation_type& impl,
58 reactive_socket_service_base::base_implementation_type& other_impl)
59 noexcept
60{
61 impl.socket_ = other_impl.socket_;
62 other_impl.socket_ = invalid_socket;
63
64 impl.state_ = other_impl.state_;
65 other_impl.state_ = 0;
66
67 reactor_.move_descriptor(impl.socket_,
68 impl.reactor_data_, other_impl.reactor_data_);
69}
70
71void reactive_socket_service_base::base_move_assign(
72 reactive_socket_service_base::base_implementation_type& impl,
73 reactive_socket_service_base& other_service,
74 reactive_socket_service_base::base_implementation_type& other_impl)
75{
76 destroy(impl);
77
78 impl.socket_ = other_impl.socket_;
79 other_impl.socket_ = invalid_socket;
80
81 impl.state_ = other_impl.state_;
82 other_impl.state_ = 0;
83
84 other_service.reactor_.move_descriptor(impl.socket_,
85 impl.reactor_data_, other_impl.reactor_data_);
86}
87
88void reactive_socket_service_base::destroy(
89 reactive_socket_service_base::base_implementation_type& impl)
90{
91 if (impl.socket_ != invalid_socket)
92 {
93 BOOST_ASIO_HANDLER_OPERATION((reactor_.context(),(void)0
94 "socket", &impl, impl.socket_, "close"))(void)0;
95
96 reactor_.deregister_descriptor(impl.socket_, impl.reactor_data_,
97 (impl.state_ & socket_ops::possible_dup) == 0);
98
99 boost::system::error_code ignored_ec;
100 socket_ops::close(impl.socket_, impl.state_, true, ignored_ec);
101
102 reactor_.cleanup_descriptor_data(impl.reactor_data_);
103 }
104}
105
106boost::system::error_code reactive_socket_service_base::close(
107 reactive_socket_service_base::base_implementation_type& impl,
108 boost::system::error_code& ec)
109{
110 if (is_open(impl))
111 {
112 BOOST_ASIO_HANDLER_OPERATION((reactor_.context(),(void)0
113 "socket", &impl, impl.socket_, "close"))(void)0;
114
115 reactor_.deregister_descriptor(impl.socket_, impl.reactor_data_,
116 (impl.state_ & socket_ops::possible_dup) == 0);
117
118 socket_ops::close(impl.socket_, impl.state_, false, ec);
119
120 reactor_.cleanup_descriptor_data(impl.reactor_data_);
121 }
122 else
123 {
124 ec = boost::system::error_code();
125 }
126
127 // The descriptor is closed by the OS even if close() returns an error.
128 //
129 // (Actually, POSIX says the state of the descriptor is unspecified. On
130 // Linux the descriptor is apparently closed anyway; e.g. see
131 // http://lkml.org/lkml/2005/9/10/129
132 // We'll just have to assume that other OSes follow the same behaviour. The
133 // known exception is when Windows's closesocket() function fails with
134 // WSAEWOULDBLOCK, but this case is handled inside socket_ops::close().
135 construct(impl);
136
137 return ec;
138}
139
140socket_type reactive_socket_service_base::release(
141 reactive_socket_service_base::base_implementation_type& impl,
142 boost::system::error_code& ec)
143{
144 if (!is_open(impl))
145 {
146 ec = boost::asio::error::bad_descriptor;
147 return invalid_socket;
148 }
149
150 BOOST_ASIO_HANDLER_OPERATION((reactor_.context(),(void)0
151 "socket", &impl, impl.socket_, "release"))(void)0;
152
153 reactor_.deregister_descriptor(impl.socket_, impl.reactor_data_, false);
154 reactor_.cleanup_descriptor_data(impl.reactor_data_);
155 socket_type sock = impl.socket_;
156 construct(impl);
157 ec = boost::system::error_code();
158 return sock;
159}
160
161boost::system::error_code reactive_socket_service_base::cancel(
162 reactive_socket_service_base::base_implementation_type& impl,
163 boost::system::error_code& ec)
164{
165 if (!is_open(impl))
166 {
167 ec = boost::asio::error::bad_descriptor;
168 return ec;
169 }
170
171 BOOST_ASIO_HANDLER_OPERATION((reactor_.context(),(void)0
172 "socket", &impl, impl.socket_, "cancel"))(void)0;
173
174 reactor_.cancel_ops(impl.socket_, impl.reactor_data_);
175 ec = boost::system::error_code();
176 return ec;
177}
178
179boost::system::error_code reactive_socket_service_base::do_open(
180 reactive_socket_service_base::base_implementation_type& impl,
181 int af, int type, int protocol, boost::system::error_code& ec)
182{
183 if (is_open(impl))
184 {
185 ec = boost::asio::error::already_open;
186 return ec;
187 }
188
189 socket_holder sock(socket_ops::socket(af, type, protocol, ec));
190 if (sock.get() == invalid_socket)
191 return ec;
192
193 if (int err = reactor_.register_descriptor(sock.get(), impl.reactor_data_))
194 {
195 ec = boost::system::error_code(err,
196 boost::asio::error::get_system_category());
197 return ec;
198 }
199
200 impl.socket_ = sock.release();
201 switch (type)
202 {
203 case SOCK_STREAMSOCK_STREAM:
204 impl.state_ = socket_ops::stream_oriented | extra_state_;
205 break;
206 case SOCK_DGRAMSOCK_DGRAM:
207 impl.state_ = socket_ops::datagram_oriented | extra_state_;
208 break;
209 default:
210 impl.state_ = 0;
211 break;
212 }
213 ec = boost::system::error_code();
214 return ec;
215}
216
217boost::system::error_code reactive_socket_service_base::do_assign(
218 reactive_socket_service_base::base_implementation_type& impl, int type,
219 const reactive_socket_service_base::native_handle_type& native_socket,
220 boost::system::error_code& ec)
221{
222 if (is_open(impl))
223 {
224 ec = boost::asio::error::already_open;
225 return ec;
226 }
227
228 if (int err = reactor_.register_descriptor(
229 native_socket, impl.reactor_data_))
230 {
231 ec = boost::system::error_code(err,
232 boost::asio::error::get_system_category());
233 return ec;
234 }
235
236 impl.socket_ = native_socket;
237 switch (type)
238 {
239 case SOCK_STREAMSOCK_STREAM:
240 impl.state_ = socket_ops::stream_oriented | extra_state_;
241 break;
242 case SOCK_DGRAMSOCK_DGRAM:
243 impl.state_ = socket_ops::datagram_oriented | extra_state_;
244 break;
245 default:
246 impl.state_ = 0;
247 break;
248 }
249 impl.state_ |= socket_ops::possible_dup;
250 ec = boost::system::error_code();
251 return ec;
252}
253
254void reactive_socket_service_base::do_start_op(
255 reactive_socket_service_base::base_implementation_type& impl,
256 int op_type, reactor_op* op, bool is_continuation,
257 bool allow_speculative, bool noop, bool needs_non_blocking,
258 void (*on_immediate)(operation* op, bool, const void*),
259 const void* immediate_arg)
260{
261 if (!noop)
262 {
263 if ((impl.state_ & socket_ops::non_blocking)
264 || !needs_non_blocking
265 || socket_ops::set_internal_non_blocking(
266 impl.socket_, impl.state_, true, op->ec_))
267 {
268 reactor_.start_op(op_type, impl.socket_, impl.reactor_data_, op,
269 is_continuation, allow_speculative, on_immediate, immediate_arg);
270 return;
271 }
272 }
273
274 on_immediate(op, is_continuation, immediate_arg);
275}
276
277void reactive_socket_service_base::do_start_accept_op(
278 reactive_socket_service_base::base_implementation_type& impl,
279 reactor_op* op, bool is_continuation, bool peer_is_open,
280 void (*on_immediate)(operation* op, bool, const void*),
281 const void* immediate_arg)
282{
283 if (!peer_is_open)
284 {
285 do_start_op(impl, reactor::read_op, op, is_continuation,
286 true, false, true, on_immediate, immediate_arg);
287 }
288 else
289 {
290 op->ec_ = boost::asio::error::already_open;
291 on_immediate(op, is_continuation, immediate_arg);
292 }
293}
294
295void reactive_socket_service_base::do_start_connect_op(
296 reactive_socket_service_base::base_implementation_type& impl,
297 reactor_op* op, bool is_continuation, const void* addr, size_t addrlen,
298 void (*on_immediate)(operation* op, bool, const void*),
299 const void* immediate_arg)
300{
301 if ((impl.state_ & socket_ops::non_blocking)
302 || socket_ops::set_internal_non_blocking(
303 impl.socket_, impl.state_, true, op->ec_))
304 {
305 if (socket_ops::connect(impl.socket_, addr, addrlen, op->ec_) != 0)
306 {
307 if (op->ec_ == boost::asio::error::in_progress
308 || op->ec_ == boost::asio::error::would_block)
309 {
310 op->ec_ = boost::system::error_code();
311 reactor_.start_op(reactor::connect_op, impl.socket_, impl.reactor_data_,
312 op, is_continuation, false, on_immediate, immediate_arg);
313 return;
314 }
315 }
316 }
317
318 on_immediate(op, is_continuation, immediate_arg);
319}
320
321} // namespace detail
322} // namespace asio
323} // namespace boost
324
325#include <boost/asio/detail/pop_options.hpp>
326
327#endif // !defined(BOOST_ASIO_HAS_IOCP)
328 // && !defined(BOOST_ASIO_WINDOWS_RUNTIME)
329 // && !defined(BOOST_ASIO_HAS_IO_URING_AS_DEFAULT)
330
331#endif // BOOST_ASIO_DETAIL_IMPL_REACTIVE_SOCKET_SERVICE_BASE_IPP

/usr/include/boost/asio/impl/execution_context.hpp

1//
2// impl/execution_context.hpp
3// ~~~~~~~~~~~~~~~~~~~~~~~~~~
4//
5// Copyright (c) 2003-2025 Christopher M. Kohlhoff (chris at kohlhoff dot com)
6//
7// Distributed under the Boost Software License, Version 1.0. (See accompanying
8// file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt)
9//
10
11#ifndef BOOST_ASIO_IMPL_EXECUTION_CONTEXT_HPP
12#define BOOST_ASIO_IMPL_EXECUTION_CONTEXT_HPP
13
14#if defined(_MSC_VER) && (_MSC_VER >= 1200)
15# pragma once
16#endif // defined(_MSC_VER) && (_MSC_VER >= 1200)
17
18#include <cstring>
19#include <boost/asio/detail/handler_type_requirements.hpp>
20#include <boost/asio/detail/memory.hpp>
21#include <boost/asio/detail/service_registry.hpp>
22#include <boost/asio/detail/throw_exception.hpp>
23
24#include <boost/asio/detail/push_options.hpp>
25
26namespace boost {
27namespace asio {
28
29template <typename Allocator>
30execution_context::execution_context(allocator_arg_t, const Allocator& a)
31 : execution_context(detail::allocate_object<allocator_impl<Allocator>>(a, a))
32{
33}
34
35template <typename Allocator>
36execution_context::execution_context(allocator_arg_t, const Allocator& a,
37 const service_maker& initial_services)
38 : execution_context(detail::allocate_object<allocator_impl<Allocator>>(a, a),
39 initial_services)
40{
41}
42
43inline execution_context::auto_allocator_ptr::~auto_allocator_ptr()
44{
45 ptr_->destroy();
46}
47
48template <typename Allocator>
49void execution_context::allocator_impl<Allocator>::destroy()
50{
51 detail::deallocate_object(allocator_, this);
52}
53
54template <typename Allocator>
55void* execution_context::allocator_impl<Allocator>::allocate(
56 std::size_t size, std::size_t align)
57{
58 typename std::allocator_traits<Allocator>::template
59 rebind_alloc<unsigned char> alloc(allocator_);
60
61 std::size_t space = size + align - 1;
62 unsigned char* base = std::allocator_traits<decltype(alloc)>::allocate(
63 alloc, space + sizeof(std::ptrdiff_t));
64
65 void* p = base;
66 if (detail::align(align, size, p, space))
67 {
68 std::ptrdiff_t off = static_cast<unsigned char*>(p) - base;
69 std::memcpy(static_cast<unsigned char*>(p) + size, &off, sizeof(off));
70 return p;
71 }
72
73 std::bad_alloc ex;
74 boost::asio::detail::throw_exception(ex);
75 return 0;
76}
77
78template <typename Allocator>
79void execution_context::allocator_impl<Allocator>::deallocate(
80 void* ptr, std::size_t size, std::size_t align)
81{
82 if (ptr)
83 {
84 typename std::allocator_traits<Allocator>::template
85 rebind_alloc<unsigned char> alloc(allocator_);
86
87 std::ptrdiff_t off;
88 std::memcpy(&off, static_cast<unsigned char*>(ptr) + size, sizeof(off));
89 unsigned char* base = static_cast<unsigned char*>(ptr) - off;
90
91 std::allocator_traits<decltype(alloc)>::deallocate(
92 alloc, base, size + align - 1 + sizeof(std::ptrdiff_t));
93 }
94}
95
96#if !defined(GENERATING_DOCUMENTATION)
97
98template <typename Service>
99inline Service& use_service(execution_context& e)
100{
101 // Check that Service meets the necessary type requirements.
102 (void)static_cast<execution_context::service*>(static_cast<Service*>(0));
103
104 return e.service_registry_->template use_service<Service>();
36
Calling 'service_registry::use_service'
46
Returning from 'service_registry::use_service'
50
Calling 'service_registry::use_service'
60
Returning from 'service_registry::use_service'
105}
106
107template <typename Service, typename... Args>
108Service& make_service(execution_context& e, Args&&... args)
109{
110 // Check that Service meets the necessary type requirements.
111 (void)static_cast<execution_context::service*>(static_cast<Service*>(0));
112
113 return e.service_registry_->template make_service<Service>(
114 static_cast<Args&&>(args)...);
115}
116
117template <typename Service>
118BOOST_ASIO_DEPRECATED_MSG("Use make_service()")[[deprecated("Use make_service()")]]
119inline void add_service(execution_context& e, Service* svc)
120{
121 // Check that Service meets the necessary type requirements.
122 (void)static_cast<execution_context::service*>(static_cast<Service*>(0));
123
124 e.service_registry_->template add_service<Service>(svc);
125}
126
127template <typename Service>
128inline bool has_service(execution_context& e)
129{
130 // Check that Service meets the necessary type requirements.
131 (void)static_cast<execution_context::service*>(static_cast<Service*>(0));
132
133 return e.service_registry_->template has_service<Service>();
134}
135
136#endif // !defined(GENERATING_DOCUMENTATION)
137
138inline execution_context& execution_context::service::context()
139{
140 return owner_;
141}
142
143} // namespace asio
144} // namespace boost
145
146#include <boost/asio/detail/pop_options.hpp>
147
148#endif // BOOST_ASIO_IMPL_EXECUTION_CONTEXT_HPP

/usr/include/boost/asio/detail/scoped_lock.hpp

1//
2// detail/scoped_lock.hpp
3// ~~~~~~~~~~~~~~~~~~~~~~
4//
5// Copyright (c) 2003-2025 Christopher M. Kohlhoff (chris at kohlhoff dot com)
6//
7// Distributed under the Boost Software License, Version 1.0. (See accompanying
8// file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt)
9//
10
11#ifndef BOOST_ASIO_DETAIL_SCOPED_LOCK_HPP
12#define BOOST_ASIO_DETAIL_SCOPED_LOCK_HPP
13
14#if defined(_MSC_VER) && (_MSC_VER >= 1200)
15# pragma once
16#endif // defined(_MSC_VER) && (_MSC_VER >= 1200)
17
18#include <boost/asio/detail/noncopyable.hpp>
19
20#include <boost/asio/detail/push_options.hpp>
21
22namespace boost {
23namespace asio {
24namespace detail {
25
26// Helper class to lock and unlock a mutex automatically.
27template <typename Mutex>
28class scoped_lock
29 : private noncopyable
30{
31public:
32 // Tag type used to distinguish constructors.
33 enum adopt_lock_t { adopt_lock };
34
35 // Constructor adopts a lock that is already held.
36 scoped_lock(Mutex& m, adopt_lock_t)
37 : mutex_(m),
38 locked_(true)
39 {
40 }
41
42 // Constructor acquires the lock.
43 explicit scoped_lock(Mutex& m)
44 : mutex_(m)
45 {
46 mutex_.lock();
39
Calling 'posix_mutex::lock'
41
Returning from 'posix_mutex::lock'
53
Calling 'posix_mutex::lock'
55
Returning from 'posix_mutex::lock'
47 locked_ = true;
48 }
49
50 // Destructor releases the lock.
51 ~scoped_lock()
52 {
53 if (locked_)
54 mutex_.unlock();
55 }
56
57 // Explicitly acquire the lock.
58 void lock()
59 {
60 if (!locked_)
61 {
62 mutex_.lock();
63 locked_ = true;
64 }
65 }
66
67 // Explicitly release the lock.
68 void unlock()
69 {
70 if (locked_)
71 {
72 mutex_.unlock();
73 locked_ = false;
74 }
75 }
76
77 // Test whether the lock is held.
78 bool locked() const
79 {
80 return locked_;
81 }
82
83 // Get the underlying mutex.
84 Mutex& mutex()
85 {
86 return mutex_;
87 }
88
89private:
90 // The underlying mutex.
91 Mutex& mutex_;
92
93 // Whether the mutex is currently locked or unlocked.
94 bool locked_;
95};
96
97} // namespace detail
98} // namespace asio
99} // namespace boost
100
101#include <boost/asio/detail/pop_options.hpp>
102
103#endif // BOOST_ASIO_DETAIL_SCOPED_LOCK_HPP

/usr/include/boost/asio/detail/posix_mutex.hpp

1//
2// detail/posix_mutex.hpp
3// ~~~~~~~~~~~~~~~~~~~~~~
4//
5// Copyright (c) 2003-2025 Christopher M. Kohlhoff (chris at kohlhoff dot com)
6//
7// Distributed under the Boost Software License, Version 1.0. (See accompanying
8// file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt)
9//
10
11#ifndef BOOST_ASIO_DETAIL_POSIX_MUTEX_HPP
12#define BOOST_ASIO_DETAIL_POSIX_MUTEX_HPP
13
14#if defined(_MSC_VER) && (_MSC_VER >= 1200)
15# pragma once
16#endif // defined(_MSC_VER) && (_MSC_VER >= 1200)
17
18#include <boost/asio/detail/config.hpp>
19
20#if defined(BOOST_ASIO_HAS_PTHREADS1)
21
22#include <pthread.h>
23#include <boost/asio/detail/noncopyable.hpp>
24#include <boost/asio/detail/scoped_lock.hpp>
25
26#include <boost/asio/detail/push_options.hpp>
27
28namespace boost {
29namespace asio {
30namespace detail {
31
32class posix_event;
33
34class posix_mutex
35 : private noncopyable
36{
37public:
38 typedef boost::asio::detail::scoped_lock<posix_mutex> scoped_lock;
39
40 // Constructor.
41 BOOST_ASIO_DECLinline posix_mutex();
42
43 // Destructor.
44 ~posix_mutex()
45 {
46 ::pthread_mutex_destroy(&mutex_); // Ignore EBUSY.
47 }
48
49 // Try to lock the mutex.
50 bool try_lock()
51 {
52 return ::pthread_mutex_trylock(&mutex_) == 0; // Ignore EINVAL.
53 }
54
55 // Lock the mutex.
56 void lock()
57 {
58 (void)::pthread_mutex_lock(&mutex_); // Ignore EINVAL.
40
Entering critical section here
54
Entering critical section here
59 }
60
61 // Unlock the mutex.
62 void unlock()
63 {
64 (void)::pthread_mutex_unlock(&mutex_); // Ignore EINVAL.
65 }
66
67private:
68 friend class posix_event;
69 ::pthread_mutex_t mutex_;
70};
71
72} // namespace detail
73} // namespace asio
74} // namespace boost
75
76#include <boost/asio/detail/pop_options.hpp>
77
78#if defined(BOOST_ASIO_HEADER_ONLY1)
79# include <boost/asio/detail/impl/posix_mutex.ipp>
80#endif // defined(BOOST_ASIO_HEADER_ONLY)
81
82#endif // defined(BOOST_ASIO_HAS_PTHREADS)
83
84#endif // BOOST_ASIO_DETAIL_POSIX_MUTEX_HPP

/usr/include/boost/asio/config.hpp

1//
2// config.hpp
3// ~~~~~~~~~~
4//
5// Copyright (c) 2003-2025 Christopher M. Kohlhoff (chris at kohlhoff dot com)
6//
7// Distributed under the Boost Software License, Version 1.0. (See accompanying
8// file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt)
9//
10
11#ifndef BOOST_ASIO_CONFIG_HPP
12#define BOOST_ASIO_CONFIG_HPP
13
14#if defined(_MSC_VER) && (_MSC_VER >= 1200)
15# pragma once
16#endif // defined(_MSC_VER) && (_MSC_VER >= 1200)
17
18#include <boost/asio/detail/config.hpp>
19#include <boost/asio/detail/throw_exception.hpp>
20#include <boost/asio/detail/type_traits.hpp>
21#include <boost/asio/execution_context.hpp>
22#include <cstddef>
23#include <string>
24
25#include <boost/asio/detail/push_options.hpp>
26
27namespace boost {
28namespace asio {
29
30/// Base class for configuration implementations.
31class config_service :
32#if defined(GENERATING_DOCUMENTATION)
33 public execution_context::service
34#else // defined(GENERATING_DOCUMENTATION)
35 public detail::execution_context_service_base<config_service>
36#endif // defined(GENERATING_DOCUMENTATION)
37{
38public:
39#if defined(GENERATING_DOCUMENTATION)
40 typedef config_service key_type;
41#endif // defined(GENERATING_DOCUMENTATION)
42
43 /// Constructor.
44 BOOST_ASIO_DECLinline explicit config_service(execution_context& ctx);
45
46 /// Shutdown the service.
47 BOOST_ASIO_DECLinline void shutdown() override;
48
49 /// Retrieve a configuration value.
50 BOOST_ASIO_DECLinline virtual const char* get_value(const char* section,
51 const char* key_name, char* value, std::size_t value_len) const;
52};
53
54/// Provides access to the configuration values associated with an execution
55/// context.
56class config
57{
58public:
59 /// Constructor.
60 /**
61 * This constructor initialises a @c config object to retrieve configuration
62 * values associated with the specified execution context.
63 */
64 explicit config(execution_context& context)
65 : service_(use_service<config_service>(context))
49
Calling 'use_service<boost::asio::config_service>'
61
Returning from 'use_service<boost::asio::config_service>'
66 {
67 }
68
69 /// Copy constructor.
70 config(const config& other) noexcept
71 : service_(other.service_)
72 {
73 }
74
75 /// Retrieve an integral configuration value.
76 template <typename T>
77 constraint_t<is_integral<T>::value, T>
78 get(const char* section, const char* key_name, T default_value) const;
79
80private:
81 config_service& service_;
82};
83
84/// Configures an execution context based on a concurrency hint.
85/**
86 * This configuration service is provided for backwards compatibility with
87 * the existing concurrency hint mechanism.
88 *
89 * @par Example
90 * @code boost::asio::io_context my_io_context{
91 * boost::asio::config_from_concurrency_hint{1}}; @endcode
92 */
93class config_from_concurrency_hint : public execution_context::service_maker
94{
95public:
96 /// Construct with a default concurrency hint.
97 BOOST_ASIO_DECLinline config_from_concurrency_hint();
98
99 /// Construct with a specified concurrency hint.
100 explicit config_from_concurrency_hint(int concurrency_hint)
101 : concurrency_hint_(concurrency_hint)
102 {
103 }
104
105 /// Add a concrete service to the specified execution context.
106 BOOST_ASIO_DECLinline void make(execution_context& ctx) const override;
107
108private:
109 int concurrency_hint_;
110};
111
112/// Configures an execution context by reading variables from a string.
113/**
114 * Each variable must be on a line of its own, and of the form:
115 *
116 * <tt>section.key=value</tt>
117 *
118 * or, if an optional prefix is specified:
119 *
120 * <tt>prefix.section.key=value</tt>
121 *
122 * Blank lines and lines starting with <tt>#</tt> are ignored. It is also
123 * permitted to include a comment starting with <tt>#</tt> after the value.
124 *
125 * @par Example
126 * @code boost::asio::io_context my_io_context{
127 * boost::asio::config_from_string{
128 * "scheduler.concurrency_hint=10\n"
129 * "scheduler.locking=1"}}; @endcode
130 */
131class config_from_string : public execution_context::service_maker
132{
133public:
134 /// Construct with the default prefix "asio".
135 explicit config_from_string(std::string s)
136 : string_(static_cast<std::string&&>(s)),
137 prefix_()
138 {
139 }
140
141 /// Construct with a specified prefix.
142 config_from_string(std::string s, std::string prefix)
143 : string_(static_cast<std::string&&>(s)),
144 prefix_(static_cast<std::string&&>(prefix))
145 {
146 }
147
148 /// Add a concrete service to the specified execution context.
149 BOOST_ASIO_DECLinline void make(execution_context& ctx) const override;
150
151private:
152 std::string string_;
153 std::string prefix_;
154};
155
156/// Configures an execution context by reading environment variables.
157/**
158 * The environment variable names are formed by concatenating the prefix,
159 * section, and key, with underscore as delimiter, and then converting the
160 * resulting string to upper case.
161 *
162 * @par Example
163 * @code boost::asio::io_context my_io_context{
164 * boost::asio::config_from_env{"my_app"}}; @endcode
165 */
166class config_from_env : public execution_context::service_maker
167{
168public:
169 /// Construct with the default prefix "asio".
170 BOOST_ASIO_DECLinline config_from_env();
171
172 /// Construct with a specified prefix.
173 explicit config_from_env(std::string prefix)
174 : prefix_(static_cast<std::string&&>(prefix))
175 {
176 }
177
178 /// Add a concrete service to the specified execution context.
179 BOOST_ASIO_DECLinline void make(execution_context& ctx) const override;
180
181private:
182 std::string prefix_;
183};
184
185} // namespace asio
186} // namespace boost
187
188#include <boost/asio/detail/pop_options.hpp>
189
190#include <boost/asio/impl/config.hpp>
191#if defined(BOOST_ASIO_HEADER_ONLY1)
192# include <boost/asio/impl/config.ipp>
193#endif // defined(BOOST_ASIO_HEADER_ONLY)
194
195#endif // BOOST_ASIO_CONFIG_HPP

/usr/include/boost/asio/detail/reactive_socket_service_base.hpp

1//
2// detail/reactive_socket_service_base.hpp
3// ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
4//
5// Copyright (c) 2003-2025 Christopher M. Kohlhoff (chris at kohlhoff dot com)
6//
7// Distributed under the Boost Software License, Version 1.0. (See accompanying
8// file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt)
9//
10
11#ifndef BOOST_ASIO_DETAIL_REACTIVE_SOCKET_SERVICE_BASE_HPP
12#define BOOST_ASIO_DETAIL_REACTIVE_SOCKET_SERVICE_BASE_HPP
13
14#if defined(_MSC_VER) && (_MSC_VER >= 1200)
15# pragma once
16#endif // defined(_MSC_VER) && (_MSC_VER >= 1200)
17
18#include <boost/asio/detail/config.hpp>
19
20#if !defined(BOOST_ASIO_HAS_IOCP) \
21 && !defined(BOOST_ASIO_WINDOWS_RUNTIME) \
22 && !defined(BOOST_ASIO_HAS_IO_URING_AS_DEFAULT)
23
24#include <boost/asio/associated_cancellation_slot.hpp>
25#include <boost/asio/buffer.hpp>
26#include <boost/asio/cancellation_type.hpp>
27#include <boost/asio/error.hpp>
28#include <boost/asio/execution_context.hpp>
29#include <boost/asio/socket_base.hpp>
30#include <boost/asio/detail/buffer_sequence_adapter.hpp>
31#include <boost/asio/detail/memory.hpp>
32#include <boost/asio/detail/reactive_null_buffers_op.hpp>
33#include <boost/asio/detail/reactive_socket_recv_op.hpp>
34#include <boost/asio/detail/reactive_socket_recvmsg_op.hpp>
35#include <boost/asio/detail/reactive_socket_send_op.hpp>
36#include <boost/asio/detail/reactive_wait_op.hpp>
37#include <boost/asio/detail/reactor.hpp>
38#include <boost/asio/detail/reactor_op.hpp>
39#include <boost/asio/detail/socket_holder.hpp>
40#include <boost/asio/detail/socket_ops.hpp>
41#include <boost/asio/detail/socket_types.hpp>
42
43#include <boost/asio/detail/push_options.hpp>
44
45namespace boost {
46namespace asio {
47namespace detail {
48
49class reactive_socket_service_base
50{
51public:
52 // The native type of a socket.
53 typedef socket_type native_handle_type;
54
55 // The implementation type of the socket.
56 struct base_implementation_type
57 {
58 // The native socket representation.
59 socket_type socket_;
60
61 // The current state of the socket.
62 socket_ops::state_type state_;
63
64 // Per-descriptor data used by the reactor.
65 reactor::per_descriptor_data reactor_data_;
66 };
67
68 // Constructor.
69 BOOST_ASIO_DECLinline reactive_socket_service_base(execution_context& context);
70
71 // Destroy all user-defined handler objects owned by the service.
72 BOOST_ASIO_DECLinline void base_shutdown();
73
74 // Construct a new socket implementation.
75 BOOST_ASIO_DECLinline void construct(base_implementation_type& impl);
76
77 // Move-construct a new socket implementation.
78 BOOST_ASIO_DECLinline void base_move_construct(base_implementation_type& impl,
79 base_implementation_type& other_impl) noexcept;
80
81 // Move-assign from another socket implementation.
82 BOOST_ASIO_DECLinline void base_move_assign(base_implementation_type& impl,
83 reactive_socket_service_base& other_service,
84 base_implementation_type& other_impl);
85
86 // Destroy a socket implementation.
87 BOOST_ASIO_DECLinline void destroy(base_implementation_type& impl);
88
89 // Determine whether the socket is open.
90 bool is_open(const base_implementation_type& impl) const
91 {
92 return impl.socket_ != invalid_socket;
93 }
94
95 // Destroy a socket implementation.
96 BOOST_ASIO_DECLinline boost::system::error_code close(
97 base_implementation_type& impl, boost::system::error_code& ec);
98
99 // Release ownership of the socket.
100 BOOST_ASIO_DECLinline socket_type release(
101 base_implementation_type& impl, boost::system::error_code& ec);
102
103 // Get the native socket representation.
104 native_handle_type native_handle(base_implementation_type& impl)
105 {
106 return impl.socket_;
107 }
108
109 // Cancel all operations associated with the socket.
110 BOOST_ASIO_DECLinline boost::system::error_code cancel(
111 base_implementation_type& impl, boost::system::error_code& ec);
112
113 // Determine whether the socket is at the out-of-band data mark.
114 bool at_mark(const base_implementation_type& impl,
115 boost::system::error_code& ec) const
116 {
117 return socket_ops::sockatmark(impl.socket_, ec);
118 }
119
120 // Determine the number of bytes available for reading.
121 std::size_t available(const base_implementation_type& impl,
122 boost::system::error_code& ec) const
123 {
124 return socket_ops::available(impl.socket_, ec);
125 }
126
127 // Place the socket into the state where it will listen for new connections.
128 boost::system::error_code listen(base_implementation_type& impl,
129 int backlog, boost::system::error_code& ec)
130 {
131 socket_ops::listen(impl.socket_, backlog, ec);
132 return ec;
133 }
134
135 // Perform an IO control command on the socket.
136 template <typename IO_Control_Command>
137 boost::system::error_code io_control(base_implementation_type& impl,
138 IO_Control_Command& command, boost::system::error_code& ec)
139 {
140 socket_ops::ioctl(impl.socket_, impl.state_, command.name(),
141 static_cast<ioctl_arg_type*>(command.data()), ec);
142 return ec;
143 }
144
145 // Gets the non-blocking mode of the socket.
146 bool non_blocking(const base_implementation_type& impl) const
147 {
148 return (impl.state_ & socket_ops::user_set_non_blocking) != 0;
149 }
150
151 // Sets the non-blocking mode of the socket.
152 boost::system::error_code non_blocking(base_implementation_type& impl,
153 bool mode, boost::system::error_code& ec)
154 {
155 socket_ops::set_user_non_blocking(impl.socket_, impl.state_, mode, ec);
156 return ec;
157 }
158
159 // Gets the non-blocking mode of the native socket implementation.
160 bool native_non_blocking(const base_implementation_type& impl) const
161 {
162 return (impl.state_ & socket_ops::internal_non_blocking) != 0;
163 }
164
165 // Sets the non-blocking mode of the native socket implementation.
166 boost::system::error_code native_non_blocking(base_implementation_type& impl,
167 bool mode, boost::system::error_code& ec)
168 {
169 socket_ops::set_internal_non_blocking(impl.socket_, impl.state_, mode, ec);
170 return ec;
171 }
172
173 // Wait for the socket to become ready to read, ready to write, or to have
174 // pending error conditions.
175 boost::system::error_code wait(base_implementation_type& impl,
176 socket_base::wait_type w, boost::system::error_code& ec)
177 {
178 switch (w)
179 {
180 case socket_base::wait_read:
181 socket_ops::poll_read(impl.socket_, impl.state_, -1, ec);
182 break;
183 case socket_base::wait_write:
184 socket_ops::poll_write(impl.socket_, impl.state_, -1, ec);
185 break;
186 case socket_base::wait_error:
187 socket_ops::poll_error(impl.socket_, impl.state_, -1, ec);
188 break;
189 default:
190 ec = boost::asio::error::invalid_argument;
191 break;
192 }
193
194 return ec;
195 }
196
197 // Asynchronously wait for the socket to become ready to read, ready to
198 // write, or to have pending error conditions.
199 template <typename Handler, typename IoExecutor>
200 void async_wait(base_implementation_type& impl,
201 socket_base::wait_type w, Handler& handler, const IoExecutor& io_ex)
202 {
203 bool is_continuation =
204 boost_asio_handler_cont_helpers::is_continuation(handler);
205
206 associated_cancellation_slot_t<Handler> slot
207 = boost::asio::get_associated_cancellation_slot(handler);
208
209 // Allocate and construct an operation to wrap the handler.
210 typedef reactive_wait_op<Handler, IoExecutor> op;
211 typename op::ptr p = { boost::asio::detail::addressof(handler),
212 op::ptr::allocate(handler), 0 };
213 p.p = new (p.v) op(success_ec_, handler, io_ex);
214
215 BOOST_ASIO_HANDLER_CREATION((reactor_.context(), *p.p, "socket",(void)0
216 &impl, impl.socket_, "async_wait"))(void)0;
217
218 int op_type;
219 switch (w)
220 {
221 case socket_base::wait_read:
222 op_type = reactor::read_op;
223 break;
224 case socket_base::wait_write:
225 op_type = reactor::write_op;
226 break;
227 case socket_base::wait_error:
228 op_type = reactor::except_op;
229 break;
230 default:
231 p.p->ec_ = boost::asio::error::invalid_argument;
232 start_op(impl, reactor::read_op, p.p,
233 is_continuation, false, true, false, &io_ex, 0);
234 p.v = p.p = 0;
235 return;
236 }
237
238 // Optionally register for per-operation cancellation.
239 if (slot.is_connected())
240 {
241 p.p->cancellation_key_ =
242 &slot.template emplace<reactor_op_cancellation>(
243 &reactor_, &impl.reactor_data_, impl.socket_, op_type);
244 }
245
246 start_op(impl, op_type, p.p, is_continuation,
247 false, false, false, &io_ex, 0);
248 p.v = p.p = 0;
249 }
250
251 // Send the given data to the peer.
252 template <typename ConstBufferSequence>
253 size_t send(base_implementation_type& impl,
254 const ConstBufferSequence& buffers,
255 socket_base::message_flags flags, boost::system::error_code& ec)
256 {
257 typedef buffer_sequence_adapter<boost::asio::const_buffer,
258 ConstBufferSequence> bufs_type;
259
260 if (bufs_type::is_single_buffer)
261 {
262 return socket_ops::sync_send1(impl.socket_,
263 impl.state_, bufs_type::first(buffers).data(),
264 bufs_type::first(buffers).size(), flags, ec);
265 }
266 else
267 {
268 bufs_type bufs(buffers);
269 return socket_ops::sync_send(impl.socket_, impl.state_,
270 bufs.buffers(), bufs.count(), flags, bufs.all_empty(), ec);
271 }
272 }
273
274 // Wait until data can be sent without blocking.
275 size_t send(base_implementation_type& impl, const null_buffers&,
276 socket_base::message_flags, boost::system::error_code& ec)
277 {
278 // Wait for socket to become ready.
279 socket_ops::poll_write(impl.socket_, impl.state_, -1, ec);
280
281 return 0;
282 }
283
284 // Start an asynchronous send. The data being sent must be valid for the
285 // lifetime of the asynchronous operation.
286 template <typename ConstBufferSequence, typename Handler, typename IoExecutor>
287 void async_send(base_implementation_type& impl,
288 const ConstBufferSequence& buffers, socket_base::message_flags flags,
289 Handler& handler, const IoExecutor& io_ex)
290 {
291 bool is_continuation =
292 boost_asio_handler_cont_helpers::is_continuation(handler);
293
294 associated_cancellation_slot_t<Handler> slot
295 = boost::asio::get_associated_cancellation_slot(handler);
296
297 // Allocate and construct an operation to wrap the handler.
298 typedef reactive_socket_send_op<
299 ConstBufferSequence, Handler, IoExecutor> op;
300 typename op::ptr p = { boost::asio::detail::addressof(handler),
301 op::ptr::allocate(handler), 0 };
302 p.p = new (p.v) op(success_ec_, impl.socket_,
303 impl.state_, buffers, flags, handler, io_ex);
304
305 // Optionally register for per-operation cancellation.
306 if (slot.is_connected())
307 {
308 p.p->cancellation_key_ =
309 &slot.template emplace<reactor_op_cancellation>(
310 &reactor_, &impl.reactor_data_, impl.socket_, reactor::write_op);
311 }
312
313 BOOST_ASIO_HANDLER_CREATION((reactor_.context(), *p.p, "socket",(void)0
314 &impl, impl.socket_, "async_send"))(void)0;
315
316 start_op(impl, reactor::write_op, p.p, is_continuation, true,
317 ((impl.state_ & socket_ops::stream_oriented)
318 && buffer_sequence_adapter<boost::asio::const_buffer,
319 ConstBufferSequence>::all_empty(buffers)), true, &io_ex, 0);
320 p.v = p.p = 0;
321 }
322
323 // Start an asynchronous wait until data can be sent without blocking.
324 template <typename Handler, typename IoExecutor>
325 void async_send(base_implementation_type& impl, const null_buffers&,
326 socket_base::message_flags, Handler& handler, const IoExecutor& io_ex)
327 {
328 bool is_continuation =
329 boost_asio_handler_cont_helpers::is_continuation(handler);
330
331 associated_cancellation_slot_t<Handler> slot
332 = boost::asio::get_associated_cancellation_slot(handler);
333
334 // Allocate and construct an operation to wrap the handler.
335 typedef reactive_null_buffers_op<Handler, IoExecutor> op;
336 typename op::ptr p = { boost::asio::detail::addressof(handler),
337 op::ptr::allocate(handler), 0 };
338 p.p = new (p.v) op(success_ec_, handler, io_ex);
339
340 // Optionally register for per-operation cancellation.
341 if (slot.is_connected())
342 {
343 p.p->cancellation_key_ =
344 &slot.template emplace<reactor_op_cancellation>(
345 &reactor_, &impl.reactor_data_, impl.socket_, reactor::write_op);
346 }
347
348 BOOST_ASIO_HANDLER_CREATION((reactor_.context(), *p.p, "socket",(void)0
349 &impl, impl.socket_, "async_send(null_buffers)"))(void)0;
350
351 start_op(impl, reactor::write_op, p.p,
352 is_continuation, false, false, false, &io_ex, 0);
353 p.v = p.p = 0;
354 }
355
356 // Receive some data from the peer. Returns the number of bytes received.
357 template <typename MutableBufferSequence>
358 size_t receive(base_implementation_type& impl,
359 const MutableBufferSequence& buffers,
360 socket_base::message_flags flags, boost::system::error_code& ec)
361 {
362 typedef buffer_sequence_adapter<boost::asio::mutable_buffer,
363 MutableBufferSequence> bufs_type;
364
365 if (bufs_type::is_single_buffer)
85
Taking true branch
366 {
367 return socket_ops::sync_recv1(impl.socket_,
86
Calling 'sync_recv1'
368 impl.state_, bufs_type::first(buffers).data(),
369 bufs_type::first(buffers).size(), flags, ec);
370 }
371 else
372 {
373 bufs_type bufs(buffers);
374 return socket_ops::sync_recv(impl.socket_, impl.state_,
375 bufs.buffers(), bufs.count(), flags, bufs.all_empty(), ec);
376 }
377 }
378
379 // Wait until data can be received without blocking.
380 size_t receive(base_implementation_type& impl, const null_buffers&,
381 socket_base::message_flags, boost::system::error_code& ec)
382 {
383 // Wait for socket to become ready.
384 socket_ops::poll_read(impl.socket_, impl.state_, -1, ec);
385
386 return 0;
387 }
388
389 // Start an asynchronous receive. The buffer for the data being received
390 // must be valid for the lifetime of the asynchronous operation.
391 template <typename MutableBufferSequence,
392 typename Handler, typename IoExecutor>
393 void async_receive(base_implementation_type& impl,
394 const MutableBufferSequence& buffers, socket_base::message_flags flags,
395 Handler& handler, const IoExecutor& io_ex)
396 {
397 bool is_continuation =
398 boost_asio_handler_cont_helpers::is_continuation(handler);
399
400 associated_cancellation_slot_t<Handler> slot
401 = boost::asio::get_associated_cancellation_slot(handler);
402
403 // Allocate and construct an operation to wrap the handler.
404 typedef reactive_socket_recv_op<
405 MutableBufferSequence, Handler, IoExecutor> op;
406 typename op::ptr p = { boost::asio::detail::addressof(handler),
407 op::ptr::allocate(handler), 0 };
408 p.p = new (p.v) op(success_ec_, impl.socket_,
409 impl.state_, buffers, flags, handler, io_ex);
410
411 // Optionally register for per-operation cancellation.
412 if (slot.is_connected())
413 {
414 p.p->cancellation_key_ =
415 &slot.template emplace<reactor_op_cancellation>(
416 &reactor_, &impl.reactor_data_, impl.socket_, reactor::read_op);
417 }
418
419 BOOST_ASIO_HANDLER_CREATION((reactor_.context(), *p.p, "socket",(void)0
420 &impl, impl.socket_, "async_receive"))(void)0;
421
422 start_op(impl,
423 (flags & socket_base::message_out_of_band)
424 ? reactor::except_op : reactor::read_op,
425 p.p, is_continuation,
426 (flags & socket_base::message_out_of_band) == 0,
427 ((impl.state_ & socket_ops::stream_oriented)
428 && buffer_sequence_adapter<boost::asio::mutable_buffer,
429 MutableBufferSequence>::all_empty(buffers)), true, &io_ex, 0);
430 p.v = p.p = 0;
431 }
432
433 // Wait until data can be received without blocking.
434 template <typename Handler, typename IoExecutor>
435 void async_receive(base_implementation_type& impl,
436 const null_buffers&, socket_base::message_flags flags,
437 Handler& handler, const IoExecutor& io_ex)
438 {
439 bool is_continuation =
440 boost_asio_handler_cont_helpers::is_continuation(handler);
441
442 associated_cancellation_slot_t<Handler> slot
443 = boost::asio::get_associated_cancellation_slot(handler);
444
445 // Allocate and construct an operation to wrap the handler.
446 typedef reactive_null_buffers_op<Handler, IoExecutor> op;
447 typename op::ptr p = { boost::asio::detail::addressof(handler),
448 op::ptr::allocate(handler), 0 };
449 p.p = new (p.v) op(success_ec_, handler, io_ex);
450
451 // Optionally register for per-operation cancellation.
452 if (slot.is_connected())
453 {
454 p.p->cancellation_key_ =
455 &slot.template emplace<reactor_op_cancellation>(
456 &reactor_, &impl.reactor_data_, impl.socket_, reactor::read_op);
457 }
458
459 BOOST_ASIO_HANDLER_CREATION((reactor_.context(), *p.p, "socket",(void)0
460 &impl, impl.socket_, "async_receive(null_buffers)"))(void)0;
461
462 start_op(impl,
463 (flags & socket_base::message_out_of_band)
464 ? reactor::except_op : reactor::read_op,
465 p.p, is_continuation, false, false, false, &io_ex, 0);
466 p.v = p.p = 0;
467 }
468
469 // Receive some data with associated flags. Returns the number of bytes
470 // received.
471 template <typename MutableBufferSequence>
472 size_t receive_with_flags(base_implementation_type& impl,
473 const MutableBufferSequence& buffers,
474 socket_base::message_flags in_flags,
475 socket_base::message_flags& out_flags, boost::system::error_code& ec)
476 {
477 buffer_sequence_adapter<boost::asio::mutable_buffer,
478 MutableBufferSequence> bufs(buffers);
479
480 return socket_ops::sync_recvmsg(impl.socket_, impl.state_,
481 bufs.buffers(), bufs.count(), in_flags, out_flags, ec);
482 }
483
484 // Wait until data can be received without blocking.
485 size_t receive_with_flags(base_implementation_type& impl,
486 const null_buffers&, socket_base::message_flags,
487 socket_base::message_flags& out_flags, boost::system::error_code& ec)
488 {
489 // Wait for socket to become ready.
490 socket_ops::poll_read(impl.socket_, impl.state_, -1, ec);
491
492 // Clear out_flags, since we cannot give it any other sensible value when
493 // performing a null_buffers operation.
494 out_flags = 0;
495
496 return 0;
497 }
498
499 // Start an asynchronous receive. The buffer for the data being received
500 // must be valid for the lifetime of the asynchronous operation.
501 template <typename MutableBufferSequence,
502 typename Handler, typename IoExecutor>
503 void async_receive_with_flags(base_implementation_type& impl,
504 const MutableBufferSequence& buffers, socket_base::message_flags in_flags,
505 socket_base::message_flags& out_flags, Handler& handler,
506 const IoExecutor& io_ex)
507 {
508 bool is_continuation =
509 boost_asio_handler_cont_helpers::is_continuation(handler);
510
511 associated_cancellation_slot_t<Handler> slot
512 = boost::asio::get_associated_cancellation_slot(handler);
513
514 // Allocate and construct an operation to wrap the handler.
515 typedef reactive_socket_recvmsg_op<
516 MutableBufferSequence, Handler, IoExecutor> op;
517 typename op::ptr p = { boost::asio::detail::addressof(handler),
518 op::ptr::allocate(handler), 0 };
519 p.p = new (p.v) op(success_ec_, impl.socket_,
520 buffers, in_flags, out_flags, handler, io_ex);
521
522 // Optionally register for per-operation cancellation.
523 if (slot.is_connected())
524 {
525 p.p->cancellation_key_ =
526 &slot.template emplace<reactor_op_cancellation>(
527 &reactor_, &impl.reactor_data_, impl.socket_, reactor::read_op);
528 }
529
530 BOOST_ASIO_HANDLER_CREATION((reactor_.context(), *p.p, "socket",(void)0
531 &impl, impl.socket_, "async_receive_with_flags"))(void)0;
532
533 start_op(impl,
534 (in_flags & socket_base::message_out_of_band)
535 ? reactor::except_op : reactor::read_op,
536 p.p, is_continuation,
537 (in_flags & socket_base::message_out_of_band) == 0,
538 false, true, &io_ex, 0);
539 p.v = p.p = 0;
540 }
541
542 // Wait until data can be received without blocking.
543 template <typename Handler, typename IoExecutor>
544 void async_receive_with_flags(base_implementation_type& impl,
545 const null_buffers&, socket_base::message_flags in_flags,
546 socket_base::message_flags& out_flags, Handler& handler,
547 const IoExecutor& io_ex)
548 {
549 bool is_continuation =
550 boost_asio_handler_cont_helpers::is_continuation(handler);
551
552 associated_cancellation_slot_t<Handler> slot
553 = boost::asio::get_associated_cancellation_slot(handler);
554
555 // Allocate and construct an operation to wrap the handler.
556 typedef reactive_null_buffers_op<Handler, IoExecutor> op;
557 typename op::ptr p = { boost::asio::detail::addressof(handler),
558 op::ptr::allocate(handler), 0 };
559 p.p = new (p.v) op(success_ec_, handler, io_ex);
560
561 // Optionally register for per-operation cancellation.
562 if (slot.is_connected())
563 {
564 p.p->cancellation_key_ =
565 &slot.template emplace<reactor_op_cancellation>(
566 &reactor_, &impl.reactor_data_, impl.socket_, reactor::read_op);
567 }
568
569 BOOST_ASIO_HANDLER_CREATION((reactor_.context(), *p.p, "socket",(void)0
570 &impl, impl.socket_, "async_receive_with_flags(null_buffers)"))(void)0;
571
572 // Clear out_flags, since we cannot give it any other sensible value when
573 // performing a null_buffers operation.
574 out_flags = 0;
575
576 start_op(impl,
577 (in_flags & socket_base::message_out_of_band)
578 ? reactor::except_op : reactor::read_op,
579 p.p, is_continuation, false, false, false, &io_ex, 0);
580 p.v = p.p = 0;
581 }
582
583protected:
584 // Open a new socket implementation.
585 BOOST_ASIO_DECLinline boost::system::error_code do_open(
586 base_implementation_type& impl, int af,
587 int type, int protocol, boost::system::error_code& ec);
588
589 // Assign a native socket to a socket implementation.
590 BOOST_ASIO_DECLinline boost::system::error_code do_assign(
591 base_implementation_type& impl, int type,
592 const native_handle_type& native_socket, boost::system::error_code& ec);
593
594 // Start the asynchronous read or write operation.
595 BOOST_ASIO_DECLinline void do_start_op(base_implementation_type& impl,
596 int op_type, reactor_op* op, bool is_continuation,
597 bool allow_speculative, bool noop, bool needs_non_blocking,
598 void (*on_immediate)(operation* op, bool, const void*),
599 const void* immediate_arg);
600
601 // Start the asynchronous operation for handlers that are specialised for
602 // immediate completion.
603 template <typename Op>
604 void start_op(base_implementation_type& impl, int op_type, Op* op,
605 bool is_continuation, bool allow_speculative, bool noop,
606 bool needs_non_blocking, const void* io_ex, ...)
607 {
608 return do_start_op(impl, op_type, op, is_continuation, allow_speculative,
609 noop, needs_non_blocking, &Op::do_immediate, io_ex);
610 }
611
612 // Start the asynchronous operation for handlers that are not specialised for
613 // immediate completion.
614 template <typename Op>
615 void start_op(base_implementation_type& impl, int op_type,
616 Op* op, bool is_continuation, bool allow_speculative,
617 bool noop, bool needs_non_blocking, const void*,
618 enable_if_t<
619 is_same<
620 typename associated_immediate_executor<
621 typename Op::handler_type,
622 typename Op::io_executor_type
623 >::asio_associated_immediate_executor_is_unspecialised,
624 void
625 >::value
626 >*)
627 {
628 return do_start_op(impl, op_type, op, is_continuation,
629 allow_speculative, noop, needs_non_blocking,
630 &reactor::call_post_immediate_completion, &reactor_);
631 }
632
633 // Start the asynchronous accept operation.
634 BOOST_ASIO_DECLinline void do_start_accept_op(base_implementation_type& impl,
635 reactor_op* op, bool is_continuation, bool peer_is_open,
636 void (*on_immediate)(operation* op, bool, const void*),
637 const void* immediate_arg);
638
639 // Start the asynchronous accept operation for handlers that are specialised
640 // for immediate completion.
641 template <typename Op>
642 void start_accept_op(base_implementation_type& impl, Op* op,
643 bool is_continuation, bool peer_is_open, const void* io_ex, ...)
644 {
645 return do_start_accept_op(impl, op, is_continuation,
646 peer_is_open, &Op::do_immediate, io_ex);
647 }
648
649 // Start the asynchronous operation for handlers that are not specialised for
650 // immediate completion.
651 template <typename Op>
652 void start_accept_op(base_implementation_type& impl, Op* op,
653 bool is_continuation, bool peer_is_open, const void*,
654 enable_if_t<
655 is_same<
656 typename associated_immediate_executor<
657 typename Op::handler_type,
658 typename Op::io_executor_type
659 >::asio_associated_immediate_executor_is_unspecialised,
660 void
661 >::value
662 >*)
663 {
664 return do_start_accept_op(impl, op, is_continuation, peer_is_open,
665 &reactor::call_post_immediate_completion, &reactor_);
666 }
667
668 // Start the asynchronous connect operation.
669 BOOST_ASIO_DECLinline void do_start_connect_op(base_implementation_type& impl,
670 reactor_op* op, bool is_continuation, const void* addr, size_t addrlen,
671 void (*on_immediate)(operation* op, bool, const void*),
672 const void* immediate_arg);
673
674 // Start the asynchronous operation for handlers that are specialised for
675 // immediate completion.
676 template <typename Op>
677 void start_connect_op(base_implementation_type& impl,
678 Op* op, bool is_continuation, const void* addr,
679 size_t addrlen, const void* io_ex, ...)
680 {
681 return do_start_connect_op(impl, op, is_continuation,
682 addr, addrlen, &Op::do_immediate, io_ex);
683 }
684
685 // Start the asynchronous operation for handlers that are not specialised for
686 // immediate completion.
687 template <typename Op>
688 void start_connect_op(base_implementation_type& impl, Op* op,
689 bool is_continuation, const void* addr, size_t addrlen, const void*,
690 enable_if_t<
691 is_same<
692 typename associated_immediate_executor<
693 typename Op::handler_type,
694 typename Op::io_executor_type
695 >::asio_associated_immediate_executor_is_unspecialised,
696 void
697 >::value
698 >*)
699 {
700 return do_start_connect_op(impl, op, is_continuation, addr,
701 addrlen, &reactor::call_post_immediate_completion, &reactor_);
702 }
703
704 // Helper class used to implement per-operation cancellation
705 class reactor_op_cancellation
706 {
707 public:
708 reactor_op_cancellation(reactor* r,
709 reactor::per_descriptor_data* p, socket_type d, int o)
710 : reactor_(r),
711 reactor_data_(p),
712 descriptor_(d),
713 op_type_(o)
714 {
715 }
716
717 void operator()(cancellation_type_t type)
718 {
719 if (!!(type &
720 (cancellation_type::terminal
721 | cancellation_type::partial
722 | cancellation_type::total)))
723 {
724 reactor_->cancel_ops_by_key(descriptor_,
725 *reactor_data_, op_type_, this);
726 }
727 }
728
729 private:
730 reactor* reactor_;
731 reactor::per_descriptor_data* reactor_data_;
732 socket_type descriptor_;
733 int op_type_;
734 };
735
736 // The selector that performs event demultiplexing for the service.
737 reactor& reactor_;
738
739 // Cached success value to avoid accessing category singleton.
740 const boost::system::error_code success_ec_;
741
742 // Extra state flags to be applied to newly opened sockets.
743 socket_ops::state_type extra_state_;
744};
745
746} // namespace detail
747} // namespace asio
748} // namespace boost
749
750#include <boost/asio/detail/pop_options.hpp>
751
752#if defined(BOOST_ASIO_HEADER_ONLY1)
753# include <boost/asio/detail/impl/reactive_socket_service_base.ipp>
754#endif // defined(BOOST_ASIO_HEADER_ONLY)
755
756#endif // !defined(BOOST_ASIO_HAS_IOCP)
757 // && !defined(BOOST_ASIO_WINDOWS_RUNTIME)
758 // && !defined(BOOST_ASIO_HAS_IO_URING_AS_DEFAULT)
759
760#endif // BOOST_ASIO_DETAIL_REACTIVE_SOCKET_SERVICE_BASE_HPP

/usr/include/boost/asio/detail/impl/socket_ops.ipp

1//
2// detail/impl/socket_ops.ipp
3// ~~~~~~~~~~~~~~~~~~~~~~~~~~
4//
5// Copyright (c) 2003-2025 Christopher M. Kohlhoff (chris at kohlhoff dot com)
6//
7// Distributed under the Boost Software License, Version 1.0. (See accompanying
8// file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt)
9//
10
11#ifndef BOOST_ASIO_DETAIL_SOCKET_OPS_IPP
12#define BOOST_ASIO_DETAIL_SOCKET_OPS_IPP
13
14#if defined(_MSC_VER) && (_MSC_VER >= 1200)
15# pragma once
16#endif // defined(_MSC_VER) && (_MSC_VER >= 1200)
17
18#include <boost/asio/detail/config.hpp>
19
20#include <cctype>
21#include <cstdio>
22#include <cstdlib>
23#include <cstring>
24#include <cerrno>
25#include <new>
26#include <boost/asio/detail/assert.hpp>
27#include <boost/asio/detail/socket_ops.hpp>
28#include <boost/asio/error.hpp>
29
30#if defined(BOOST_ASIO_WINDOWS_RUNTIME)
31# include <codecvt>
32# include <locale>
33# include <string>
34#endif // defined(BOOST_ASIO_WINDOWS_RUNTIME)
35
36#if defined(BOOST_ASIO_WINDOWS) || defined(__CYGWIN__) \
37 || defined(__MACH__) && defined(__APPLE__)
38# if defined(BOOST_ASIO_HAS_PTHREADS1)
39# include <pthread.h>
40# endif // defined(BOOST_ASIO_HAS_PTHREADS)
41#endif // defined(BOOST_ASIO_WINDOWS) || defined(__CYGWIN__)
42 // || defined(__MACH__) && defined(__APPLE__)
43
44#if defined(_MSC_VER) && (_MSC_VER >= 1800)
45# include <malloc.h>
46#endif // defined(_MSC_VER) && (_MSC_VER >= 1800)
47
48#include <boost/asio/detail/push_options.hpp>
49
50namespace boost {
51namespace asio {
52namespace detail {
53namespace socket_ops {
54
55#if !defined(BOOST_ASIO_WINDOWS_RUNTIME)
56
57#if defined(BOOST_ASIO_WINDOWS) || defined(__CYGWIN__)
58struct msghdr { int msg_namelen; };
59#endif // defined(BOOST_ASIO_WINDOWS) || defined(__CYGWIN__)
60
61#if defined(__hpux)
62// HP-UX doesn't declare these functions extern "C", so they are declared again
63// here to avoid linker errors about undefined symbols.
64extern "C" char* if_indextoname(unsigned int, char*);
65extern "C" unsigned int if_nametoindex(const char*);
66#endif // defined(__hpux)
67
68#endif // !defined(BOOST_ASIO_WINDOWS_RUNTIME)
69
70inline void clear_last_error()
71{
72#if defined(BOOST_ASIO_WINDOWS) || defined(__CYGWIN__)
73 WSASetLastError(0);
74#else
75 errno(*__errno_location ()) = 0;
76#endif
77}
78
79#if !defined(BOOST_ASIO_WINDOWS_RUNTIME)
80
81inline void get_last_error(
82 boost::system::error_code& ec, bool is_error_condition)
83{
84 if (!is_error_condition)
85 {
86 boost::asio::error::clear(ec);
87 }
88 else
89 {
90#if defined(BOOST_ASIO_WINDOWS) || defined(__CYGWIN__)
91 ec = boost::system::error_code(WSAGetLastError(),
92 boost::asio::error::get_system_category());
93#else
94 ec = boost::system::error_code(errno(*__errno_location ()),
95 boost::asio::error::get_system_category());
96#endif
97 }
98}
99
100template <typename SockLenType>
101inline socket_type call_accept(SockLenType msghdr::*,
102 socket_type s, void* addr, std::size_t* addrlen)
103{
104 SockLenType tmp_addrlen = addrlen ? (SockLenType)*addrlen : 0;
105 socket_type result = ::accept(s,
106 static_cast<socket_addr_type*>(addr),
107 addrlen ? &tmp_addrlen : 0);
108 if (addrlen)
109 *addrlen = (std::size_t)tmp_addrlen;
110 return result;
111}
112
113socket_type accept(socket_type s, void* addr,
114 std::size_t* addrlen, boost::system::error_code& ec)
115{
116 if (s == invalid_socket)
117 {
118 ec = boost::asio::error::bad_descriptor;
119 return invalid_socket;
120 }
121
122 socket_type new_s = call_accept(&msghdr::msg_namelen, s, addr, addrlen);
123 get_last_error(ec, new_s == invalid_socket);
124 if (new_s == invalid_socket)
125 return new_s;
126
127#if defined(__MACH__) && defined(__APPLE__) || defined(__FreeBSD__)
128 int optval = 1;
129 int result = ::setsockopt(new_s, SOL_SOCKET1,
130 SO_NOSIGPIPE, &optval, sizeof(optval));
131 get_last_error(ec, result != 0);
132 if (result != 0)
133 {
134 ::close(new_s);
135 return invalid_socket;
136 }
137#endif
138
139 boost::asio::error::clear(ec);
140 return new_s;
141}
142
143socket_type sync_accept(socket_type s, state_type state,
144 void* addr, std::size_t* addrlen, boost::system::error_code& ec)
145{
146 // Accept a socket.
147 for (;;)
148 {
149 // Try to complete the operation without blocking.
150 socket_type new_socket = socket_ops::accept(s, addr, addrlen, ec);
151
152 // Check if operation succeeded.
153 if (new_socket != invalid_socket)
154 return new_socket;
155
156 // Operation failed.
157 if (ec == boost::asio::error::would_block
158 || ec == boost::asio::error::try_again)
159 {
160 if (state & user_set_non_blocking)
161 return invalid_socket;
162 // Fall through to retry operation.
163 }
164 else if (ec == boost::asio::error::connection_aborted)
165 {
166 if (state & enable_connection_aborted)
167 return invalid_socket;
168 // Fall through to retry operation.
169 }
170#if defined(EPROTO71)
171 else if (ec.value() == EPROTO71)
172 {
173 if (state & enable_connection_aborted)
174 return invalid_socket;
175 // Fall through to retry operation.
176 }
177#endif // defined(EPROTO)
178 else
179 return invalid_socket;
180
181 // Wait for socket to become ready.
182 if (socket_ops::poll_read(s, 0, -1, ec) < 0)
183 return invalid_socket;
184 }
185}
186
187#if defined(BOOST_ASIO_HAS_IOCP)
188
189void complete_iocp_accept(socket_type s, void* output_buffer,
190 DWORD address_length, void* addr, std::size_t* addrlen,
191 socket_type new_socket, boost::system::error_code& ec)
192{
193 // Map non-portable errors to their portable counterparts.
194 if (ec.value() == ERROR_NETNAME_DELETED)
195 ec = boost::asio::error::connection_aborted;
196
197 if (!ec)
198 {
199 // Get the address of the peer.
200 if (addr && addrlen)
201 {
202 LPSOCKADDR local_addr = 0;
203 int local_addr_length = 0;
204 LPSOCKADDR remote_addr = 0;
205 int remote_addr_length = 0;
206 GetAcceptExSockaddrs(output_buffer, 0, address_length,
207 address_length, &local_addr, &local_addr_length,
208 &remote_addr, &remote_addr_length);
209 if (static_cast<std::size_t>(remote_addr_length) > *addrlen)
210 {
211 ec = boost::asio::error::invalid_argument;
212 }
213 else
214 {
215 using namespace std; // For memcpy.
216 memcpy(addr, remote_addr, remote_addr_length);
217 *addrlen = static_cast<std::size_t>(remote_addr_length);
218 }
219 }
220
221 // Need to set the SO_UPDATE_ACCEPT_CONTEXT option so that getsockname
222 // and getpeername will work on the accepted socket.
223 SOCKET update_ctx_param = s;
224 socket_ops::state_type state = 0;
225 socket_ops::setsockopt(new_socket, state,
226 SOL_SOCKET1, SO_UPDATE_ACCEPT_CONTEXT,
227 &update_ctx_param, sizeof(SOCKET), ec);
228 }
229}
230
231#else // defined(BOOST_ASIO_HAS_IOCP)
232
233bool non_blocking_accept(socket_type s,
234 state_type state, void* addr, std::size_t* addrlen,
235 boost::system::error_code& ec, socket_type& new_socket)
236{
237 for (;;)
238 {
239 // Accept the waiting connection.
240 new_socket = socket_ops::accept(s, addr, addrlen, ec);
241
242 // Check if operation succeeded.
243 if (new_socket != invalid_socket)
244 return true;
245
246 // Retry operation if interrupted by signal.
247 if (ec == boost::asio::error::interrupted)
248 continue;
249
250 // Operation failed.
251 if (ec == boost::asio::error::would_block
252 || ec == boost::asio::error::try_again)
253 {
254 // Fall through to retry operation.
255 }
256 else if (ec == boost::asio::error::connection_aborted)
257 {
258 if (state & enable_connection_aborted)
259 return true;
260 // Fall through to retry operation.
261 }
262#if defined(EPROTO71)
263 else if (ec.value() == EPROTO71)
264 {
265 if (state & enable_connection_aborted)
266 return true;
267 // Fall through to retry operation.
268 }
269#endif // defined(EPROTO)
270 else
271 return true;
272
273 return false;
274 }
275}
276
277#endif // defined(BOOST_ASIO_HAS_IOCP)
278
279template <typename SockLenType>
280inline int call_bind(SockLenType msghdr::*,
281 socket_type s, const void* addr, std::size_t addrlen)
282{
283 return ::bind(s, static_cast<const socket_addr_type*>(addr),
284 (SockLenType)addrlen);
285}
286
287int bind(socket_type s, const void* addr,
288 std::size_t addrlen, boost::system::error_code& ec)
289{
290 if (s == invalid_socket)
291 {
292 ec = boost::asio::error::bad_descriptor;
293 return socket_error_retval;
294 }
295
296 int result = call_bind(&msghdr::msg_namelen, s, addr, addrlen);
297 get_last_error(ec, result != 0);
298 return result;
299}
300
301int close(socket_type s, state_type& state,
302 bool destruction, boost::system::error_code& ec)
303{
304 int result = 0;
305 if (s != invalid_socket)
306 {
307 // We don't want the destructor to block, so set the socket to linger in
308 // the background. If the user doesn't like this behaviour then they need
309 // to explicitly close the socket.
310 if (destruction && (state & user_set_linger))
311 {
312 ::linger opt;
313 opt.l_onoff = 0;
314 opt.l_linger = 0;
315 boost::system::error_code ignored_ec;
316 socket_ops::setsockopt(s, state, SOL_SOCKET1,
317 SO_LINGER13, &opt, sizeof(opt), ignored_ec);
318 }
319
320#if defined(BOOST_ASIO_WINDOWS) || defined(__CYGWIN__)
321 result = ::closesocket(s);
322#else // defined(BOOST_ASIO_WINDOWS) || defined(__CYGWIN__)
323 result = ::close(s);
324#endif // defined(BOOST_ASIO_WINDOWS) || defined(__CYGWIN__)
325 get_last_error(ec, result != 0);
326
327 if (result != 0
328 && (ec == boost::asio::error::would_block
329 || ec == boost::asio::error::try_again))
330 {
331 // According to UNIX Network Programming Vol. 1, it is possible for
332 // close() to fail with EWOULDBLOCK under certain circumstances. What
333 // isn't clear is the state of the descriptor after this error. The one
334 // current OS where this behaviour is seen, Windows, says that the socket
335 // remains open. Therefore we'll put the descriptor back into blocking
336 // mode and have another attempt at closing it.
337#if defined(BOOST_ASIO_WINDOWS) || defined(__CYGWIN__)
338 ioctl_arg_type arg = 0;
339 ::ioctlsocket(s, FIONBIO0x5421, &arg);
340#else // defined(BOOST_ASIO_WINDOWS) || defined(__CYGWIN__)
341# if defined(__SYMBIAN32__) || defined(__EMSCRIPTEN__)
342 int flags = ::fcntl(s, F_GETFL3, 0);
343 if (flags >= 0)
344 ::fcntl(s, F_SETFL4, flags & ~O_NONBLOCK04000);
345# else // defined(__SYMBIAN32__) || defined(__EMSCRIPTEN__)
346 ioctl_arg_type arg = 0;
347 if ((state & possible_dup) == 0)
348 {
349 result = ::ioctl(s, FIONBIO0x5421, &arg);
350 get_last_error(ec, result < 0);
351 }
352 if ((state & possible_dup) != 0
353# if defined(ENOTTY25)
354 || ec.value() == ENOTTY25
355# endif // defined(ENOTTY)
356# if defined(ENOTCAPABLE)
357 || ec.value() == ENOTCAPABLE
358# endif // defined(ENOTCAPABLE)
359 )
360 {
361 int flags = ::fcntl(s, F_GETFL3, 0);
362 if (flags >= 0)
363 ::fcntl(s, F_SETFL4, flags & ~O_NONBLOCK04000);
364 }
365# endif // defined(__SYMBIAN32__) || defined(__EMSCRIPTEN__)
366#endif // defined(BOOST_ASIO_WINDOWS) || defined(__CYGWIN__)
367 state &= ~non_blocking;
368
369#if defined(BOOST_ASIO_WINDOWS) || defined(__CYGWIN__)
370 result = ::closesocket(s);
371#else // defined(BOOST_ASIO_WINDOWS) || defined(__CYGWIN__)
372 result = ::close(s);
373#endif // defined(BOOST_ASIO_WINDOWS) || defined(__CYGWIN__)
374 get_last_error(ec, result != 0);
375 }
376 }
377
378 return result;
379}
380
381bool set_user_non_blocking(socket_type s,
382 state_type& state, bool value, boost::system::error_code& ec)
383{
384 if (s == invalid_socket)
385 {
386 ec = boost::asio::error::bad_descriptor;
387 return false;
388 }
389
390#if defined(BOOST_ASIO_WINDOWS) || defined(__CYGWIN__)
391 ioctl_arg_type arg = (value ? 1 : 0);
392 int result = ::ioctlsocket(s, FIONBIO0x5421, &arg);
393 get_last_error(ec, result < 0);
394#elif defined(__SYMBIAN32__) || defined(__EMSCRIPTEN__)
395 int result = ::fcntl(s, F_GETFL3, 0);
396 get_last_error(ec, result < 0);
397 if (result >= 0)
398 {
399 int flag = (value ? (result | O_NONBLOCK04000) : (result & ~O_NONBLOCK04000));
400 result = (flag != result) ? ::fcntl(s, F_SETFL4, flag) : 0;
401 get_last_error(ec, result < 0);
402 }
403#else // defined(__SYMBIAN32__) || defined(__EMSCRIPTEN__)
404 ioctl_arg_type arg = (value ? 1 : 0);
405 int result = 0;
406 if ((state & possible_dup) == 0)
407 {
408 result = ::ioctl(s, FIONBIO0x5421, &arg);
409 get_last_error(ec, result < 0);
410 }
411 if ((state & possible_dup) != 0
412# if defined(ENOTTY25)
413 || ec.value() == ENOTTY25
414# endif // defined(ENOTTY)
415# if defined(ENOTCAPABLE)
416 || ec.value() == ENOTCAPABLE
417# endif // defined(ENOTCAPABLE)
418 )
419 {
420 result = ::fcntl(s, F_GETFL3, 0);
421 get_last_error(ec, result < 0);
422 if (result >= 0)
423 {
424 int flag = (value ? (result | O_NONBLOCK04000) : (result & ~O_NONBLOCK04000));
425 result = (flag != result) ? ::fcntl(s, F_SETFL4, flag) : 0;
426 get_last_error(ec, result < 0);
427 }
428 }
429#endif // defined(__SYMBIAN32__) || defined(__EMSCRIPTEN__)
430
431 if (result >= 0)
432 {
433 if (value)
434 state |= user_set_non_blocking;
435 else
436 {
437 // Clearing the user-set non-blocking mode always overrides any
438 // internally-set non-blocking flag. Any subsequent asynchronous
439 // operations will need to re-enable non-blocking I/O.
440 state &= ~(user_set_non_blocking | internal_non_blocking);
441 }
442 return true;
443 }
444
445 return false;
446}
447
448bool set_internal_non_blocking(socket_type s,
449 state_type& state, bool value, boost::system::error_code& ec)
450{
451 if (s == invalid_socket)
452 {
453 ec = boost::asio::error::bad_descriptor;
454 return false;
455 }
456
457 if (!value && (state & user_set_non_blocking))
458 {
459 // It does not make sense to clear the internal non-blocking flag if the
460 // user still wants non-blocking behaviour. Return an error and let the
461 // caller figure out whether to update the user-set non-blocking flag.
462 ec = boost::asio::error::invalid_argument;
463 return false;
464 }
465
466#if defined(BOOST_ASIO_WINDOWS) || defined(__CYGWIN__)
467 ioctl_arg_type arg = (value ? 1 : 0);
468 int result = ::ioctlsocket(s, FIONBIO0x5421, &arg);
469 get_last_error(ec, result < 0);
470#elif defined(__SYMBIAN32__) || defined(__EMSCRIPTEN__)
471 int result = ::fcntl(s, F_GETFL3, 0);
472 get_last_error(ec, result < 0);
473 if (result >= 0)
474 {
475 int flag = (value ? (result | O_NONBLOCK04000) : (result & ~O_NONBLOCK04000));
476 result = (flag != result) ? ::fcntl(s, F_SETFL4, flag) : 0;
477 get_last_error(ec, result < 0);
478 }
479#else // defined(__SYMBIAN32__) || defined(__EMSCRIPTEN__)
480 ioctl_arg_type arg = (value ? 1 : 0);
481 int result = 0;
482 if ((state & possible_dup) == 0)
483 {
484 result = ::ioctl(s, FIONBIO0x5421, &arg);
485 get_last_error(ec, result < 0);
486 }
487 if ((state & possible_dup) != 0
488# if defined(ENOTTY25)
489 || ec.value() == ENOTTY25
490# endif // defined(ENOTTY)
491# if defined(ENOTCAPABLE)
492 || ec.value() == ENOTCAPABLE
493# endif // defined(ENOTCAPABLE)
494 )
495 {
496 result = ::fcntl(s, F_GETFL3, 0);
497 get_last_error(ec, result < 0);
498 if (result >= 0)
499 {
500 int flag = (value ? (result | O_NONBLOCK04000) : (result & ~O_NONBLOCK04000));
501 result = (flag != result) ? ::fcntl(s, F_SETFL4, flag) : 0;
502 get_last_error(ec, result < 0);
503 }
504 }
505#endif // defined(__SYMBIAN32__) || defined(__EMSCRIPTEN__)
506
507 if (result >= 0)
508 {
509 if (value)
510 state |= internal_non_blocking;
511 else
512 state &= ~internal_non_blocking;
513 return true;
514 }
515
516 return false;
517}
518
519int shutdown(socket_type s, int what, boost::system::error_code& ec)
520{
521 if (s == invalid_socket)
522 {
523 ec = boost::asio::error::bad_descriptor;
524 return socket_error_retval;
525 }
526
527 int result = ::shutdown(s, what);
528 get_last_error(ec, result != 0);
529 return result;
530}
531
532template <typename SockLenType>
533inline int call_connect(SockLenType msghdr::*,
534 socket_type s, const void* addr, std::size_t addrlen)
535{
536 return ::connect(s, static_cast<const socket_addr_type*>(addr),
537 (SockLenType)addrlen);
538}
539
540int connect(socket_type s, const void* addr,
541 std::size_t addrlen, boost::system::error_code& ec)
542{
543 if (s == invalid_socket)
544 {
545 ec = boost::asio::error::bad_descriptor;
546 return socket_error_retval;
547 }
548
549 int result = call_connect(&msghdr::msg_namelen, s, addr, addrlen);
550 get_last_error(ec, result != 0);
551#if defined(__linux__1)
552 if (result != 0 && ec == boost::asio::error::try_again)
553 {
554 if (static_cast<const socket_addr_type*>(addr)->sa_family == AF_UNIX1)
555 ec = boost::asio::error::in_progress;
556 else
557 ec = boost::asio::error::no_buffer_space;
558 }
559#endif // defined(__linux__)
560 return result;
561}
562
563void sync_connect(socket_type s, const void* addr,
564 std::size_t addrlen, boost::system::error_code& ec)
565{
566 // Perform the connect operation.
567 socket_ops::connect(s, addr, addrlen, ec);
568 if (ec != boost::asio::error::in_progress
569 && ec != boost::asio::error::would_block)
570 {
571 // The connect operation finished immediately.
572 return;
573 }
574
575 // Wait for socket to become ready.
576 if (socket_ops::poll_connect(s, -1, ec) < 0)
577 return;
578
579 // Get the error code from the connect operation.
580 int connect_error = 0;
581 size_t connect_error_len = sizeof(connect_error);
582 if (socket_ops::getsockopt(s, 0, SOL_SOCKET1, SO_ERROR4,
583 &connect_error, &connect_error_len, ec) == socket_error_retval)
584 return;
585
586 // Return the result of the connect operation.
587 ec = boost::system::error_code(connect_error,
588 boost::asio::error::get_system_category());
589}
590
591#if defined(BOOST_ASIO_HAS_IOCP)
592
593void complete_iocp_connect(socket_type s, boost::system::error_code& ec)
594{
595 // Map non-portable errors to their portable counterparts.
596 switch (ec.value())
597 {
598 case ERROR_CONNECTION_REFUSED:
599 ec = boost::asio::error::connection_refused;
600 break;
601 case ERROR_NETWORK_UNREACHABLE:
602 ec = boost::asio::error::network_unreachable;
603 break;
604 case ERROR_HOST_UNREACHABLE:
605 ec = boost::asio::error::host_unreachable;
606 break;
607 case ERROR_SEM_TIMEOUT:
608 ec = boost::asio::error::timed_out;
609 break;
610 default:
611 break;
612 }
613
614 if (!ec)
615 {
616 // Need to set the SO_UPDATE_CONNECT_CONTEXT option so that getsockname
617 // and getpeername will work on the connected socket.
618 socket_ops::state_type state = 0;
619 const int so_update_connect_context = 0x7010;
620 socket_ops::setsockopt(s, state, SOL_SOCKET1,
621 so_update_connect_context, 0, 0, ec);
622 }
623}
624
625#endif // defined(BOOST_ASIO_HAS_IOCP)
626
627bool non_blocking_connect(socket_type s, boost::system::error_code& ec)
628{
629 // Check if the connect operation has finished. This is required since we may
630 // get spurious readiness notifications from the reactor.
631#if defined(BOOST_ASIO_WINDOWS) \
632 || defined(__CYGWIN__) \
633 || defined(__SYMBIAN32__)
634 fd_set write_fds;
635 FD_ZERO(&write_fds)do { unsigned int __i; fd_set *__arr = (&write_fds); for (
__i = 0; __i < sizeof (fd_set) / sizeof (__fd_mask); ++__i
) ((__arr)->fds_bits)[__i] = 0; } while (0)
;
636 FD_SET(s, &write_fds)((void) (((&write_fds)->fds_bits)[((s) / (8 * (int) sizeof
(__fd_mask)))] |= ((__fd_mask) (1UL << ((s) % (8 * (int
) sizeof (__fd_mask)))))))
;
637 fd_set except_fds;
638 FD_ZERO(&except_fds)do { unsigned int __i; fd_set *__arr = (&except_fds); for
(__i = 0; __i < sizeof (fd_set) / sizeof (__fd_mask); ++__i
) ((__arr)->fds_bits)[__i] = 0; } while (0)
;
639 FD_SET(s, &except_fds)((void) (((&except_fds)->fds_bits)[((s) / (8 * (int) sizeof
(__fd_mask)))] |= ((__fd_mask) (1UL << ((s) % (8 * (int
) sizeof (__fd_mask)))))))
;
640 timeval zero_timeout;
641 zero_timeout.tv_sec = 0;
642 zero_timeout.tv_usec = 0;
643 int ready = ::select(s + 1, 0, &write_fds, &except_fds, &zero_timeout);
644#else // defined(BOOST_ASIO_WINDOWS)
645 // || defined(__CYGWIN__)
646 // || defined(__SYMBIAN32__)
647 pollfd fds;
648 fds.fd = s;
649 fds.events = POLLOUT0x004;
650 fds.revents = 0;
651 int ready = ::poll(&fds, 1, 0);
652#endif // defined(BOOST_ASIO_WINDOWS)
653 // || defined(__CYGWIN__)
654 // || defined(__SYMBIAN32__)
655 if (ready == 0)
656 {
657 // The asynchronous connect operation is still in progress.
658 return false;
659 }
660
661 // Get the error code from the connect operation.
662 int connect_error = 0;
663 size_t connect_error_len = sizeof(connect_error);
664 if (socket_ops::getsockopt(s, 0, SOL_SOCKET1, SO_ERROR4,
665 &connect_error, &connect_error_len, ec) == 0)
666 {
667 if (connect_error)
668 {
669 ec = boost::system::error_code(connect_error,
670 boost::asio::error::get_system_category());
671 }
672 else
673 boost::asio::error::clear(ec);
674 }
675
676 return true;
677}
678
679int socketpair(int af, int type, int protocol,
680 socket_type sv[2], boost::system::error_code& ec)
681{
682#if defined(BOOST_ASIO_WINDOWS) || defined(__CYGWIN__)
683 (void)(af);
684 (void)(type);
685 (void)(protocol);
686 (void)(sv);
687 ec = boost::asio::error::operation_not_supported;
688 return socket_error_retval;
689#else
690 int result = ::socketpair(af, type, protocol, sv);
691 get_last_error(ec, result != 0);
692 return result;
693#endif
694}
695
696bool sockatmark(socket_type s, boost::system::error_code& ec)
697{
698 if (s == invalid_socket)
699 {
700 ec = boost::asio::error::bad_descriptor;
701 return false;
702 }
703
704#if defined(SIOCATMARK0x8905)
705 ioctl_arg_type value = 0;
706# if defined(BOOST_ASIO_WINDOWS) || defined(__CYGWIN__)
707 int result = ::ioctlsocket(s, SIOCATMARK0x8905, &value);
708# else // defined(BOOST_ASIO_WINDOWS) || defined(__CYGWIN__)
709 int result = ::ioctl(s, SIOCATMARK0x8905, &value);
710# endif // defined(BOOST_ASIO_WINDOWS) || defined(__CYGWIN__)
711 get_last_error(ec, result < 0);
712# if defined(ENOTTY25)
713 if (ec.value() == ENOTTY25)
714 ec = boost::asio::error::not_socket;
715# endif // defined(ENOTTY)
716#else // defined(SIOCATMARK)
717 int value = ::sockatmark(s);
718 get_last_error(ec, value < 0);
719#endif // defined(SIOCATMARK)
720
721 return ec ? false : value != 0;
722}
723
724size_t available(socket_type s, boost::system::error_code& ec)
725{
726 if (s == invalid_socket)
727 {
728 ec = boost::asio::error::bad_descriptor;
729 return 0;
730 }
731
732 ioctl_arg_type value = 0;
733#if defined(BOOST_ASIO_WINDOWS) || defined(__CYGWIN__)
734 int result = ::ioctlsocket(s, FIONREAD0x541B, &value);
735#else // defined(BOOST_ASIO_WINDOWS) || defined(__CYGWIN__)
736 int result = ::ioctl(s, FIONREAD0x541B, &value);
737#endif // defined(BOOST_ASIO_WINDOWS) || defined(__CYGWIN__)
738 get_last_error(ec, result < 0);
739#if defined(ENOTTY25)
740 if (ec.value() == ENOTTY25)
741 ec = boost::asio::error::not_socket;
742#endif // defined(ENOTTY)
743
744 return ec ? static_cast<size_t>(0) : static_cast<size_t>(value);
745}
746
747int listen(socket_type s, int backlog, boost::system::error_code& ec)
748{
749 if (s == invalid_socket)
750 {
751 ec = boost::asio::error::bad_descriptor;
752 return socket_error_retval;
753 }
754
755 int result = ::listen(s, backlog);
756 get_last_error(ec, result != 0);
757 return result;
758}
759
760inline void init_buf_iov_base(void*& base, void* addr)
761{
762 base = addr;
763}
764
765template <typename T>
766inline void init_buf_iov_base(T& base, void* addr)
767{
768 base = static_cast<T>(addr);
769}
770
771#if defined(BOOST_ASIO_WINDOWS) || defined(__CYGWIN__)
772typedef WSABUF buf;
773#else // defined(BOOST_ASIO_WINDOWS) || defined(__CYGWIN__)
774typedef iovec buf;
775#endif // defined(BOOST_ASIO_WINDOWS) || defined(__CYGWIN__)
776
777void init_buf(buf& b, void* data, size_t size)
778{
779#if defined(BOOST_ASIO_WINDOWS) || defined(__CYGWIN__)
780 b.buf = static_cast<char*>(data);
781 b.len = static_cast<u_long>(size);
782#else // defined(BOOST_ASIO_WINDOWS) || defined(__CYGWIN__)
783 init_buf_iov_base(b.iov_base, data);
784 b.iov_len = size;
785#endif // defined(BOOST_ASIO_WINDOWS) || defined(__CYGWIN__)
786}
787
788void init_buf(buf& b, const void* data, size_t size)
789{
790#if defined(BOOST_ASIO_WINDOWS) || defined(__CYGWIN__)
791 b.buf = static_cast<char*>(const_cast<void*>(data));
792 b.len = static_cast<u_long>(size);
793#else // defined(BOOST_ASIO_WINDOWS) || defined(__CYGWIN__)
794 init_buf_iov_base(b.iov_base, const_cast<void*>(data));
795 b.iov_len = size;
796#endif // defined(BOOST_ASIO_WINDOWS) || defined(__CYGWIN__)
797}
798
799inline void init_msghdr_msg_name(void*& name, void* addr)
800{
801 name = static_cast<socket_addr_type*>(addr);
802}
803
804inline void init_msghdr_msg_name(void*& name, const socket_addr_type* addr)
805{
806 name = const_cast<socket_addr_type*>(addr);
807}
808
809template <typename T>
810inline void init_msghdr_msg_name(T& name, void* addr)
811{
812 name = static_cast<T>(addr);
813}
814
815template <typename T>
816inline void init_msghdr_msg_name(T& name, const void* addr)
817{
818 name = static_cast<T>(const_cast<void*>(addr));
819}
820
821signed_size_type recv(socket_type s, buf* bufs, size_t count,
822 int flags, boost::system::error_code& ec)
823{
824#if defined(BOOST_ASIO_WINDOWS) || defined(__CYGWIN__)
825 // Receive some data.
826 DWORD recv_buf_count = static_cast<DWORD>(count);
827 DWORD bytes_transferred = 0;
828 DWORD recv_flags = flags;
829 int result = ::WSARecv(s, bufs, recv_buf_count,
830 &bytes_transferred, &recv_flags, 0, 0);
831 get_last_error(ec, true);
832 if (ec.value() == ERROR_NETNAME_DELETED)
833 ec = boost::asio::error::connection_reset;
834 else if (ec.value() == ERROR_PORT_UNREACHABLE)
835 ec = boost::asio::error::connection_refused;
836 else if (ec.value() == WSAEMSGSIZE || ec.value() == ERROR_MORE_DATA)
837 result = 0;
838 if (result != 0)
839 return socket_error_retval;
840 boost::asio::error::clear(ec);
841 return bytes_transferred;
842#else // defined(BOOST_ASIO_WINDOWS) || defined(__CYGWIN__)
843 msghdr msg = msghdr();
844 msg.msg_iov = bufs;
845 msg.msg_iovlen = static_cast<int>(count);
846 signed_size_type result = ::recvmsg(s, &msg, flags);
847 get_last_error(ec, result < 0);
848 return result;
849#endif // defined(BOOST_ASIO_WINDOWS) || defined(__CYGWIN__)
850}
851
852signed_size_type recv1(socket_type s, void* data, size_t size,
853 int flags, boost::system::error_code& ec)
854{
855#if defined(BOOST_ASIO_WINDOWS) || defined(__CYGWIN__)
856 // Receive some data.
857 WSABUF buf;
858 buf.buf = const_cast<char*>(static_cast<const char*>(data));
859 buf.len = static_cast<ULONG>(size);
860 DWORD bytes_transferred = 0;
861 DWORD recv_flags = flags;
862 int result = ::WSARecv(s, &buf, 1,
863 &bytes_transferred, &recv_flags, 0, 0);
864 get_last_error(ec, true);
865 if (ec.value() == ERROR_NETNAME_DELETED)
866 ec = boost::asio::error::connection_reset;
867 else if (ec.value() == ERROR_PORT_UNREACHABLE)
868 ec = boost::asio::error::connection_refused;
869 else if (ec.value() == WSAEMSGSIZE || ec.value() == ERROR_MORE_DATA)
870 result = 0;
871 if (result != 0)
872 return socket_error_retval;
873 boost::asio::error::clear(ec);
874 return bytes_transferred;
875#else // defined(BOOST_ASIO_WINDOWS) || defined(__CYGWIN__)
876 signed_size_type result = ::recv(s, static_cast<char*>(data), size, flags);
89
Call to blocking function 'recv' inside of critical section
877 get_last_error(ec, result < 0);
878 return result;
879#endif // defined(BOOST_ASIO_WINDOWS) || defined(__CYGWIN__)
880}
881
882size_t sync_recv(socket_type s, state_type state, buf* bufs,
883 size_t count, int flags, bool all_empty, boost::system::error_code& ec)
884{
885 if (s == invalid_socket)
886 {
887 ec = boost::asio::error::bad_descriptor;
888 return 0;
889 }
890
891 // A request to read 0 bytes on a stream is a no-op.
892 if (all_empty && (state & stream_oriented))
893 {
894 boost::asio::error::clear(ec);
895 return 0;
896 }
897
898 // Read some data.
899 for (;;)
900 {
901 // Try to complete the operation without blocking.
902 signed_size_type bytes = socket_ops::recv(s, bufs, count, flags, ec);
903
904 // Check for EOF.
905 if ((state & stream_oriented) && bytes == 0)
906 {
907 ec = boost::asio::error::eof;
908 return 0;
909 }
910
911 // Check if operation succeeded.
912 if (bytes >= 0)
913 return bytes;
914
915 // Operation failed.
916 if ((state & user_set_non_blocking)
917 || (ec != boost::asio::error::would_block
918 && ec != boost::asio::error::try_again))
919 return 0;
920
921 // Wait for socket to become ready.
922 if (socket_ops::poll_read(s, 0, -1, ec) < 0)
923 return 0;
924 }
925}
926
927size_t sync_recv1(socket_type s, state_type state, void* data,
928 size_t size, int flags, boost::system::error_code& ec)
929{
930 if (s
86.1
's' is not equal to 'invalid_socket'
86.1
's' is not equal to 'invalid_socket'
86.1
's' is not equal to 'invalid_socket'
86.1
's' is not equal to 'invalid_socket'
86.1
's' is not equal to 'invalid_socket'
86.1
's' is not equal to 'invalid_socket'
86.1
's' is not equal to 'invalid_socket'
86.1
's' is not equal to 'invalid_socket'
86.1
's' is not equal to 'invalid_socket'
86.1
's' is not equal to 'invalid_socket'
86.1
's' is not equal to 'invalid_socket'
86.1
's' is not equal to 'invalid_socket'
86.1
's' is not equal to 'invalid_socket'
86.1
's' is not equal to 'invalid_socket'
86.1
's' is not equal to 'invalid_socket'
86.1
's' is not equal to 'invalid_socket'
86.1
's' is not equal to 'invalid_socket'
86.1
's' is not equal to 'invalid_socket'
== invalid_socket)
931 {
932 ec = boost::asio::error::bad_descriptor;
933 return 0;
934 }
935
936 // A request to read 0 bytes on a stream is a no-op.
937 if (size
86.2
'size' is not equal to 0
86.2
'size' is not equal to 0
86.2
'size' is not equal to 0
86.2
'size' is not equal to 0
86.2
'size' is not equal to 0
86.2
'size' is not equal to 0
86.2
'size' is not equal to 0
86.2
'size' is not equal to 0
86.2
'size' is not equal to 0
86.2
'size' is not equal to 0
86.2
'size' is not equal to 0
86.2
'size' is not equal to 0
86.2
'size' is not equal to 0
86.2
'size' is not equal to 0
86.2
'size' is not equal to 0
86.2
'size' is not equal to 0
86.2
'size' is not equal to 0
86.2
'size' is not equal to 0
== 0 && (state & stream_oriented))
938 {
939 boost::asio::error::clear(ec);
940 return 0;
941 }
942
943 // Read some data.
944 for (;;)
87
Loop condition is true. Entering loop body
945 {
946 // Try to complete the operation without blocking.
947 signed_size_type bytes = socket_ops::recv1(s, data, size, flags, ec);
88
Calling 'recv1'
948
949 // Check for EOF.
950 if ((state & stream_oriented) && bytes == 0)
951 {
952 ec = boost::asio::error::eof;
953 return 0;
954 }
955
956 // Check if operation succeeded.
957 if (bytes >= 0)
958 return bytes;
959
960 // Operation failed.
961 if ((state & user_set_non_blocking)
962 || (ec != boost::asio::error::would_block
963 && ec != boost::asio::error::try_again))
964 return 0;
965
966 // Wait for socket to become ready.
967 if (socket_ops::poll_read(s, 0, -1, ec) < 0)
968 return 0;
969 }
970}
971
972#if defined(BOOST_ASIO_HAS_IOCP)
973
974void complete_iocp_recv(state_type state,
975 const weak_cancel_token_type& cancel_token, bool all_empty,
976 boost::system::error_code& ec, size_t bytes_transferred)
977{
978 // Map non-portable errors to their portable counterparts.
979 if (ec.value() == ERROR_NETNAME_DELETED)
980 {
981 if (cancel_token.expired())
982 ec = boost::asio::error::operation_aborted;
983 else
984 ec = boost::asio::error::connection_reset;
985 }
986 else if (ec.value() == ERROR_PORT_UNREACHABLE)
987 {
988 ec = boost::asio::error::connection_refused;
989 }
990 else if (ec.value() == WSAEMSGSIZE || ec.value() == ERROR_MORE_DATA)
991 {
992 boost::asio::error::clear(ec);
993 }
994
995 // Check for connection closed.
996 else if (!ec && bytes_transferred == 0
997 && (state & stream_oriented) != 0
998 && !all_empty)
999 {
1000 ec = boost::asio::error::eof;
1001 }
1002}
1003
1004#else // defined(BOOST_ASIO_HAS_IOCP)
1005
1006bool non_blocking_recv(socket_type s,
1007 buf* bufs, size_t count, int flags, bool is_stream,
1008 boost::system::error_code& ec, size_t& bytes_transferred)
1009{
1010 for (;;)
1011 {
1012 // Read some data.
1013 signed_size_type bytes = socket_ops::recv(s, bufs, count, flags, ec);
1014
1015 // Check for end of stream.
1016 if (is_stream && bytes == 0)
1017 {
1018 ec = boost::asio::error::eof;
1019 return true;
1020 }
1021
1022 // Check if operation succeeded.
1023 if (bytes >= 0)
1024 {
1025 bytes_transferred = bytes;
1026 return true;
1027 }
1028
1029 // Retry operation if interrupted by signal.
1030 if (ec == boost::asio::error::interrupted)
1031 continue;
1032
1033 // Check if we need to run the operation again.
1034 if (ec == boost::asio::error::would_block
1035 || ec == boost::asio::error::try_again)
1036 return false;
1037
1038 // Operation failed.
1039 bytes_transferred = 0;
1040 return true;
1041 }
1042}
1043
1044bool non_blocking_recv1(socket_type s,
1045 void* data, size_t size, int flags, bool is_stream,
1046 boost::system::error_code& ec, size_t& bytes_transferred)
1047{
1048 for (;;)
1049 {
1050 // Read some data.
1051 signed_size_type bytes = socket_ops::recv1(s, data, size, flags, ec);
1052
1053 // Check for end of stream.
1054 if (is_stream && bytes == 0)
1055 {
1056 ec = boost::asio::error::eof;
1057 return true;
1058 }
1059
1060 // Check if operation succeeded.
1061 if (bytes >= 0)
1062 {
1063 bytes_transferred = bytes;
1064 return true;
1065 }
1066
1067 // Retry operation if interrupted by signal.
1068 if (ec == boost::asio::error::interrupted)
1069 continue;
1070
1071 // Check if we need to run the operation again.
1072 if (ec == boost::asio::error::would_block
1073 || ec == boost::asio::error::try_again)
1074 return false;
1075
1076 // Operation failed.
1077 bytes_transferred = 0;
1078 return true;
1079 }
1080}
1081
1082#endif // defined(BOOST_ASIO_HAS_IOCP)
1083
1084signed_size_type recvfrom(socket_type s, buf* bufs, size_t count,
1085 int flags, void* addr, std::size_t* addrlen, boost::system::error_code& ec)
1086{
1087#if defined(BOOST_ASIO_WINDOWS) || defined(__CYGWIN__)
1088 // Receive some data.
1089 DWORD recv_buf_count = static_cast<DWORD>(count);
1090 DWORD bytes_transferred = 0;
1091 DWORD recv_flags = flags;
1092 int tmp_addrlen = (int)*addrlen;
1093 int result = ::WSARecvFrom(s, bufs, recv_buf_count, &bytes_transferred,
1094 &recv_flags, static_cast<socket_addr_type*>(addr), &tmp_addrlen, 0, 0);
1095 get_last_error(ec, true);
1096 *addrlen = (std::size_t)tmp_addrlen;
1097 if (ec.value() == ERROR_NETNAME_DELETED)
1098 ec = boost::asio::error::connection_reset;
1099 else if (ec.value() == ERROR_PORT_UNREACHABLE)
1100 ec = boost::asio::error::connection_refused;
1101 else if (ec.value() == WSAEMSGSIZE || ec.value() == ERROR_MORE_DATA)
1102 result = 0;
1103 if (result != 0)
1104 return socket_error_retval;
1105 boost::asio::error::clear(ec);
1106 return bytes_transferred;
1107#else // defined(BOOST_ASIO_WINDOWS) || defined(__CYGWIN__)
1108 msghdr msg = msghdr();
1109 init_msghdr_msg_name(msg.msg_name, addr);
1110 msg.msg_namelen = static_cast<int>(*addrlen);
1111 msg.msg_iov = bufs;
1112 msg.msg_iovlen = static_cast<int>(count);
1113 signed_size_type result = ::recvmsg(s, &msg, flags);
1114 get_last_error(ec, result < 0);
1115 *addrlen = msg.msg_namelen;
1116 return result;
1117#endif // defined(BOOST_ASIO_WINDOWS) || defined(__CYGWIN__)
1118}
1119
1120template <typename SockLenType>
1121inline signed_size_type call_recvfrom(SockLenType msghdr::*, socket_type s,
1122 void* data, size_t size, int flags, void* addr, std::size_t* addrlen)
1123{
1124 SockLenType tmp_addrlen = addrlen ? (SockLenType)*addrlen : 0;
1125 signed_size_type result = ::recvfrom(s, static_cast<char*>(data), size,
1126 flags, static_cast<socket_addr_type*>(addr), addrlen ? &tmp_addrlen : 0);
1127 if (addrlen)
1128 *addrlen = (std::size_t)tmp_addrlen;
1129 return result;
1130}
1131
1132signed_size_type recvfrom1(socket_type s, void* data, size_t size,
1133 int flags, void* addr, std::size_t* addrlen, boost::system::error_code& ec)
1134{
1135#if defined(BOOST_ASIO_WINDOWS) || defined(__CYGWIN__)
1136 // Receive some data.
1137 WSABUF buf;
1138 buf.buf = static_cast<char*>(data);
1139 buf.len = static_cast<ULONG>(size);
1140 DWORD bytes_transferred = 0;
1141 DWORD recv_flags = flags;
1142 int tmp_addrlen = (int)*addrlen;
1143 int result = ::WSARecvFrom(s, &buf, 1, &bytes_transferred, &recv_flags,
1144 static_cast<socket_addr_type*>(addr), &tmp_addrlen, 0, 0);
1145 get_last_error(ec, true);
1146 *addrlen = (std::size_t)tmp_addrlen;
1147 if (ec.value() == ERROR_NETNAME_DELETED)
1148 ec = boost::asio::error::connection_reset;
1149 else if (ec.value() == ERROR_PORT_UNREACHABLE)
1150 ec = boost::asio::error::connection_refused;
1151 else if (ec.value() == WSAEMSGSIZE || ec.value() == ERROR_MORE_DATA)
1152 result = 0;
1153 if (result != 0)
1154 return socket_error_retval;
1155 boost::asio::error::clear(ec);
1156 return bytes_transferred;
1157#else // defined(BOOST_ASIO_WINDOWS) || defined(__CYGWIN__)
1158 signed_size_type result = call_recvfrom(&msghdr::msg_namelen,
1159 s, data, size, flags, addr, addrlen);
1160 get_last_error(ec, result < 0);
1161 return result;
1162#endif // defined(BOOST_ASIO_WINDOWS) || defined(__CYGWIN__)
1163}
1164
1165size_t sync_recvfrom(socket_type s, state_type state, buf* bufs, size_t count,
1166 int flags, void* addr, std::size_t* addrlen, boost::system::error_code& ec)
1167{
1168 if (s == invalid_socket)
1169 {
1170 ec = boost::asio::error::bad_descriptor;
1171 return 0;
1172 }
1173
1174 // Read some data.
1175 for (;;)
1176 {
1177 // Try to complete the operation without blocking.
1178 signed_size_type bytes = socket_ops::recvfrom(
1179 s, bufs, count, flags, addr, addrlen, ec);
1180
1181 // Check if operation succeeded.
1182 if (bytes >= 0)
1183 return bytes;
1184
1185 // Operation failed.
1186 if ((state & user_set_non_blocking)
1187 || (ec != boost::asio::error::would_block
1188 && ec != boost::asio::error::try_again))
1189 return 0;
1190
1191 // Wait for socket to become ready.
1192 if (socket_ops::poll_read(s, 0, -1, ec) < 0)
1193 return 0;
1194 }
1195}
1196
1197size_t sync_recvfrom1(socket_type s, state_type state, void* data, size_t size,
1198 int flags, void* addr, std::size_t* addrlen, boost::system::error_code& ec)
1199{
1200 if (s == invalid_socket)
1201 {
1202 ec = boost::asio::error::bad_descriptor;
1203 return 0;
1204 }
1205
1206 // Read some data.
1207 for (;;)
1208 {
1209 // Try to complete the operation without blocking.
1210 signed_size_type bytes = socket_ops::recvfrom1(
1211 s, data, size, flags, addr, addrlen, ec);
1212
1213 // Check if operation succeeded.
1214 if (bytes >= 0)
1215 return bytes;
1216
1217 // Operation failed.
1218 if ((state & user_set_non_blocking)
1219 || (ec != boost::asio::error::would_block
1220 && ec != boost::asio::error::try_again))
1221 return 0;
1222
1223 // Wait for socket to become ready.
1224 if (socket_ops::poll_read(s, 0, -1, ec) < 0)
1225 return 0;
1226 }
1227}
1228
1229#if defined(BOOST_ASIO_HAS_IOCP)
1230
1231void complete_iocp_recvfrom(
1232 const weak_cancel_token_type& cancel_token,
1233 boost::system::error_code& ec)
1234{
1235 // Map non-portable errors to their portable counterparts.
1236 if (ec.value() == ERROR_NETNAME_DELETED)
1237 {
1238 if (cancel_token.expired())
1239 ec = boost::asio::error::operation_aborted;
1240 else
1241 ec = boost::asio::error::connection_reset;
1242 }
1243 else if (ec.value() == ERROR_PORT_UNREACHABLE)
1244 {
1245 ec = boost::asio::error::connection_refused;
1246 }
1247 else if (ec.value() == WSAEMSGSIZE || ec.value() == ERROR_MORE_DATA)
1248 {
1249 boost::asio::error::clear(ec);
1250 }
1251}
1252
1253#else // defined(BOOST_ASIO_HAS_IOCP)
1254
1255bool non_blocking_recvfrom(socket_type s, buf* bufs,
1256 size_t count, int flags, void* addr, std::size_t* addrlen,
1257 boost::system::error_code& ec, size_t& bytes_transferred)
1258{
1259 for (;;)
1260 {
1261 // Read some data.
1262 signed_size_type bytes = socket_ops::recvfrom(
1263 s, bufs, count, flags, addr, addrlen, ec);
1264
1265 // Check if operation succeeded.
1266 if (bytes >= 0)
1267 {
1268 bytes_transferred = bytes;
1269 return true;
1270 }
1271
1272 // Retry operation if interrupted by signal.
1273 if (ec == boost::asio::error::interrupted)
1274 continue;
1275
1276 // Check if we need to run the operation again.
1277 if (ec == boost::asio::error::would_block
1278 || ec == boost::asio::error::try_again)
1279 return false;
1280
1281 // Operation failed.
1282 bytes_transferred = 0;
1283 return true;
1284 }
1285}
1286
1287bool non_blocking_recvfrom1(socket_type s, void* data,
1288 size_t size, int flags, void* addr, std::size_t* addrlen,
1289 boost::system::error_code& ec, size_t& bytes_transferred)
1290{
1291 for (;;)
1292 {
1293 // Read some data.
1294 signed_size_type bytes = socket_ops::recvfrom1(
1295 s, data, size, flags, addr, addrlen, ec);
1296
1297 // Check if operation succeeded.
1298 if (bytes >= 0)
1299 {
1300 bytes_transferred = bytes;
1301 return true;
1302 }
1303
1304 // Retry operation if interrupted by signal.
1305 if (ec == boost::asio::error::interrupted)
1306 continue;
1307
1308 // Check if we need to run the operation again.
1309 if (ec == boost::asio::error::would_block
1310 || ec == boost::asio::error::try_again)
1311 return false;
1312
1313 // Operation failed.
1314 bytes_transferred = 0;
1315 return true;
1316 }
1317}
1318
1319#endif // defined(BOOST_ASIO_HAS_IOCP)
1320
1321signed_size_type recvmsg(socket_type s, buf* bufs, size_t count,
1322 int in_flags, int& out_flags, boost::system::error_code& ec)
1323{
1324#if defined(BOOST_ASIO_WINDOWS) || defined(__CYGWIN__)
1325 out_flags = 0;
1326 return socket_ops::recv(s, bufs, count, in_flags, ec);
1327#else // defined(BOOST_ASIO_WINDOWS) || defined(__CYGWIN__)
1328 msghdr msg = msghdr();
1329 msg.msg_iov = bufs;
1330 msg.msg_iovlen = static_cast<int>(count);
1331 signed_size_type result = ::recvmsg(s, &msg, in_flags);
1332 get_last_error(ec, result < 0);
1333 if (result >= 0)
1334 out_flags = msg.msg_flags;
1335 else
1336 out_flags = 0;
1337 return result;
1338#endif // defined(BOOST_ASIO_WINDOWS) || defined(__CYGWIN__)
1339}
1340
1341size_t sync_recvmsg(socket_type s, state_type state,
1342 buf* bufs, size_t count, int in_flags, int& out_flags,
1343 boost::system::error_code& ec)
1344{
1345 if (s == invalid_socket)
1346 {
1347 ec = boost::asio::error::bad_descriptor;
1348 return 0;
1349 }
1350
1351 // Read some data.
1352 for (;;)
1353 {
1354 // Try to complete the operation without blocking.
1355 signed_size_type bytes = socket_ops::recvmsg(
1356 s, bufs, count, in_flags, out_flags, ec);
1357
1358 // Check if operation succeeded.
1359 if (bytes >= 0)
1360 return bytes;
1361
1362 // Operation failed.
1363 if ((state & user_set_non_blocking)
1364 || (ec != boost::asio::error::would_block
1365 && ec != boost::asio::error::try_again))
1366 return 0;
1367
1368 // Wait for socket to become ready.
1369 if (socket_ops::poll_read(s, 0, -1, ec) < 0)
1370 return 0;
1371 }
1372}
1373
1374#if defined(BOOST_ASIO_HAS_IOCP)
1375
1376void complete_iocp_recvmsg(
1377 const weak_cancel_token_type& cancel_token,
1378 boost::system::error_code& ec)
1379{
1380 // Map non-portable errors to their portable counterparts.
1381 if (ec.value() == ERROR_NETNAME_DELETED)
1382 {
1383 if (cancel_token.expired())
1384 ec = boost::asio::error::operation_aborted;
1385 else
1386 ec = boost::asio::error::connection_reset;
1387 }
1388 else if (ec.value() == ERROR_PORT_UNREACHABLE)
1389 {
1390 ec = boost::asio::error::connection_refused;
1391 }
1392 else if (ec.value() == WSAEMSGSIZE || ec.value() == ERROR_MORE_DATA)
1393 {
1394 boost::asio::error::clear(ec);
1395 }
1396}
1397
1398#else // defined(BOOST_ASIO_HAS_IOCP)
1399
1400bool non_blocking_recvmsg(socket_type s,
1401 buf* bufs, size_t count, int in_flags, int& out_flags,
1402 boost::system::error_code& ec, size_t& bytes_transferred)
1403{
1404 for (;;)
1405 {
1406 // Read some data.
1407 signed_size_type bytes = socket_ops::recvmsg(
1408 s, bufs, count, in_flags, out_flags, ec);
1409
1410 // Check if operation succeeded.
1411 if (bytes >= 0)
1412 {
1413 bytes_transferred = bytes;
1414 return true;
1415 }
1416
1417 // Retry operation if interrupted by signal.
1418 if (ec == boost::asio::error::interrupted)
1419 continue;
1420
1421 // Check if we need to run the operation again.
1422 if (ec == boost::asio::error::would_block
1423 || ec == boost::asio::error::try_again)
1424 return false;
1425
1426 // Operation failed.
1427 bytes_transferred = 0;
1428 return true;
1429 }
1430}
1431
1432#endif // defined(BOOST_ASIO_HAS_IOCP)
1433
1434signed_size_type send(socket_type s, const buf* bufs, size_t count,
1435 int flags, boost::system::error_code& ec)
1436{
1437#if defined(BOOST_ASIO_WINDOWS) || defined(__CYGWIN__)
1438 // Send the data.
1439 DWORD send_buf_count = static_cast<DWORD>(count);
1440 DWORD bytes_transferred = 0;
1441 DWORD send_flags = flags;
1442 int result = ::WSASend(s, const_cast<buf*>(bufs),
1443 send_buf_count, &bytes_transferred, send_flags, 0, 0);
1444 get_last_error(ec, true);
1445 if (ec.value() == ERROR_NETNAME_DELETED)
1446 ec = boost::asio::error::connection_reset;
1447 else if (ec.value() == ERROR_PORT_UNREACHABLE)
1448 ec = boost::asio::error::connection_refused;
1449 if (result != 0)
1450 return socket_error_retval;
1451 boost::asio::error::clear(ec);
1452 return bytes_transferred;
1453#else // defined(BOOST_ASIO_WINDOWS) || defined(__CYGWIN__)
1454 msghdr msg = msghdr();
1455 msg.msg_iov = const_cast<buf*>(bufs);
1456 msg.msg_iovlen = static_cast<int>(count);
1457#if defined(BOOST_ASIO_HAS_MSG_NOSIGNAL1)
1458 flags |= MSG_NOSIGNALMSG_NOSIGNAL;
1459#endif // defined(BOOST_ASIO_HAS_MSG_NOSIGNAL)
1460 signed_size_type result = ::sendmsg(s, &msg, flags);
1461 get_last_error(ec, result < 0);
1462 return result;
1463#endif // defined(BOOST_ASIO_WINDOWS) || defined(__CYGWIN__)
1464}
1465
1466signed_size_type send1(socket_type s, const void* data, size_t size,
1467 int flags, boost::system::error_code& ec)
1468{
1469#if defined(BOOST_ASIO_WINDOWS) || defined(__CYGWIN__)
1470 // Send the data.
1471 WSABUF buf;
1472 buf.buf = const_cast<char*>(static_cast<const char*>(data));
1473 buf.len = static_cast<ULONG>(size);
1474 DWORD bytes_transferred = 0;
1475 DWORD send_flags = flags;
1476 int result = ::WSASend(s, &buf, 1,
1477 &bytes_transferred, send_flags, 0, 0);
1478 get_last_error(ec, true);
1479 if (ec.value() == ERROR_NETNAME_DELETED)
1480 ec = boost::asio::error::connection_reset;
1481 else if (ec.value() == ERROR_PORT_UNREACHABLE)
1482 ec = boost::asio::error::connection_refused;
1483 if (result != 0)
1484 return socket_error_retval;
1485 boost::asio::error::clear(ec);
1486 return bytes_transferred;
1487#else // defined(BOOST_ASIO_WINDOWS) || defined(__CYGWIN__)
1488#if defined(BOOST_ASIO_HAS_MSG_NOSIGNAL1)
1489 flags |= MSG_NOSIGNALMSG_NOSIGNAL;
1490#endif // defined(BOOST_ASIO_HAS_MSG_NOSIGNAL)
1491 signed_size_type result = ::send(s,
1492 static_cast<const char*>(data), size, flags);
1493 get_last_error(ec, result < 0);
1494 return result;
1495#endif // defined(BOOST_ASIO_WINDOWS) || defined(__CYGWIN__)
1496}
1497
1498size_t sync_send(socket_type s, state_type state, const buf* bufs,
1499 size_t count, int flags, bool all_empty, boost::system::error_code& ec)
1500{
1501 if (s == invalid_socket)
1502 {
1503 ec = boost::asio::error::bad_descriptor;
1504 return 0;
1505 }
1506
1507 // A request to write 0 bytes to a stream is a no-op.
1508 if (all_empty && (state & stream_oriented))
1509 {
1510 boost::asio::error::clear(ec);
1511 return 0;
1512 }
1513
1514 // Read some data.
1515 for (;;)
1516 {
1517 // Try to complete the operation without blocking.
1518 signed_size_type bytes = socket_ops::send(s, bufs, count, flags, ec);
1519
1520 // Check if operation succeeded.
1521 if (bytes >= 0)
1522 return bytes;
1523
1524 // Operation failed.
1525 if ((state & user_set_non_blocking)
1526 || (ec != boost::asio::error::would_block
1527 && ec != boost::asio::error::try_again))
1528 return 0;
1529
1530 // Wait for socket to become ready.
1531 if (socket_ops::poll_write(s, 0, -1, ec) < 0)
1532 return 0;
1533 }
1534}
1535
1536size_t sync_send1(socket_type s, state_type state, const void* data,
1537 size_t size, int flags, boost::system::error_code& ec)
1538{
1539 if (s == invalid_socket)
1540 {
1541 ec = boost::asio::error::bad_descriptor;
1542 return 0;
1543 }
1544
1545 // A request to write 0 bytes to a stream is a no-op.
1546 if (size == 0 && (state & stream_oriented))
1547 {
1548 boost::asio::error::clear(ec);
1549 return 0;
1550 }
1551
1552 // Read some data.
1553 for (;;)
1554 {
1555 // Try to complete the operation without blocking.
1556 signed_size_type bytes = socket_ops::send1(s, data, size, flags, ec);
1557
1558 // Check if operation succeeded.
1559 if (bytes >= 0)
1560 return bytes;
1561
1562 // Operation failed.
1563 if ((state & user_set_non_blocking)
1564 || (ec != boost::asio::error::would_block
1565 && ec != boost::asio::error::try_again))
1566 return 0;
1567
1568 // Wait for socket to become ready.
1569 if (socket_ops::poll_write(s, 0, -1, ec) < 0)
1570 return 0;
1571 }
1572}
1573
1574#if defined(BOOST_ASIO_HAS_IOCP)
1575
1576void complete_iocp_send(
1577 const weak_cancel_token_type& cancel_token,
1578 boost::system::error_code& ec)
1579{
1580 // Map non-portable errors to their portable counterparts.
1581 if (ec.value() == ERROR_NETNAME_DELETED)
1582 {
1583 if (cancel_token.expired())
1584 ec = boost::asio::error::operation_aborted;
1585 else
1586 ec = boost::asio::error::connection_reset;
1587 }
1588 else if (ec.value() == ERROR_PORT_UNREACHABLE)
1589 {
1590 ec = boost::asio::error::connection_refused;
1591 }
1592}
1593
1594#else // defined(BOOST_ASIO_HAS_IOCP)
1595
1596bool non_blocking_send(socket_type s,
1597 const buf* bufs, size_t count, int flags,
1598 boost::system::error_code& ec, size_t& bytes_transferred)
1599{
1600 for (;;)
1601 {
1602 // Write some data.
1603 signed_size_type bytes = socket_ops::send(s, bufs, count, flags, ec);
1604
1605 // Check if operation succeeded.
1606 if (bytes >= 0)
1607 {
1608 bytes_transferred = bytes;
1609 return true;
1610 }
1611
1612 // Retry operation if interrupted by signal.
1613 if (ec == boost::asio::error::interrupted)
1614 continue;
1615
1616 // Check if we need to run the operation again.
1617 if (ec == boost::asio::error::would_block
1618 || ec == boost::asio::error::try_again)
1619 return false;
1620
1621 // Operation failed.
1622 bytes_transferred = 0;
1623 return true;
1624 }
1625}
1626
1627bool non_blocking_send1(socket_type s,
1628 const void* data, size_t size, int flags,
1629 boost::system::error_code& ec, size_t& bytes_transferred)
1630{
1631 for (;;)
1632 {
1633 // Write some data.
1634 signed_size_type bytes = socket_ops::send1(s, data, size, flags, ec);
1635
1636 // Check if operation succeeded.
1637 if (bytes >= 0)
1638 {
1639 bytes_transferred = bytes;
1640 return true;
1641 }
1642
1643 // Retry operation if interrupted by signal.
1644 if (ec == boost::asio::error::interrupted)
1645 continue;
1646
1647 // Check if we need to run the operation again.
1648 if (ec == boost::asio::error::would_block
1649 || ec == boost::asio::error::try_again)
1650 return false;
1651
1652 // Operation failed.
1653 bytes_transferred = 0;
1654 return true;
1655 }
1656}
1657
1658#endif // defined(BOOST_ASIO_HAS_IOCP)
1659
1660signed_size_type sendto(socket_type s, const buf* bufs,
1661 size_t count, int flags, const void* addr,
1662 std::size_t addrlen, boost::system::error_code& ec)
1663{
1664#if defined(BOOST_ASIO_WINDOWS) || defined(__CYGWIN__)
1665 // Send the data.
1666 DWORD send_buf_count = static_cast<DWORD>(count);
1667 DWORD bytes_transferred = 0;
1668 int result = ::WSASendTo(s, const_cast<buf*>(bufs),
1669 send_buf_count, &bytes_transferred, flags,
1670 static_cast<const socket_addr_type*>(addr),
1671 static_cast<int>(addrlen), 0, 0);
1672 get_last_error(ec, true);
1673 if (ec.value() == ERROR_NETNAME_DELETED)
1674 ec = boost::asio::error::connection_reset;
1675 else if (ec.value() == ERROR_PORT_UNREACHABLE)
1676 ec = boost::asio::error::connection_refused;
1677 if (result != 0)
1678 return socket_error_retval;
1679 boost::asio::error::clear(ec);
1680 return bytes_transferred;
1681#else // defined(BOOST_ASIO_WINDOWS) || defined(__CYGWIN__)
1682 msghdr msg = msghdr();
1683 init_msghdr_msg_name(msg.msg_name, addr);
1684 msg.msg_namelen = static_cast<int>(addrlen);
1685 msg.msg_iov = const_cast<buf*>(bufs);
1686 msg.msg_iovlen = static_cast<int>(count);
1687#if defined(BOOST_ASIO_HAS_MSG_NOSIGNAL1)
1688 flags |= MSG_NOSIGNALMSG_NOSIGNAL;
1689#endif // defined(BOOST_ASIO_HAS_MSG_NOSIGNAL)
1690 signed_size_type result = ::sendmsg(s, &msg, flags);
1691 get_last_error(ec, result < 0);
1692 return result;
1693#endif // defined(BOOST_ASIO_WINDOWS) || defined(__CYGWIN__)
1694}
1695
1696template <typename SockLenType>
1697inline signed_size_type call_sendto(SockLenType msghdr::*,
1698 socket_type s, const void* data, size_t size, int flags,
1699 const void* addr, std::size_t addrlen)
1700{
1701 return ::sendto(s, static_cast<char*>(const_cast<void*>(data)), size, flags,
1702 static_cast<const socket_addr_type*>(addr), (SockLenType)addrlen);
1703}
1704
1705signed_size_type sendto1(socket_type s, const void* data,
1706 size_t size, int flags, const void* addr,
1707 std::size_t addrlen, boost::system::error_code& ec)
1708{
1709#if defined(BOOST_ASIO_WINDOWS) || defined(__CYGWIN__)
1710 // Send the data.
1711 WSABUF buf;
1712 buf.buf = const_cast<char*>(static_cast<const char*>(data));
1713 buf.len = static_cast<ULONG>(size);
1714 DWORD bytes_transferred = 0;
1715 int result = ::WSASendTo(s, &buf, 1, &bytes_transferred, flags,
1716 static_cast<const socket_addr_type*>(addr),
1717 static_cast<int>(addrlen), 0, 0);
1718 get_last_error(ec, true);
1719 if (ec.value() == ERROR_NETNAME_DELETED)
1720 ec = boost::asio::error::connection_reset;
1721 else if (ec.value() == ERROR_PORT_UNREACHABLE)
1722 ec = boost::asio::error::connection_refused;
1723 if (result != 0)
1724 return socket_error_retval;
1725 boost::asio::error::clear(ec);
1726 return bytes_transferred;
1727#else // defined(BOOST_ASIO_WINDOWS) || defined(__CYGWIN__)
1728#if defined(BOOST_ASIO_HAS_MSG_NOSIGNAL1)
1729 flags |= MSG_NOSIGNALMSG_NOSIGNAL;
1730#endif // defined(BOOST_ASIO_HAS_MSG_NOSIGNAL)
1731 signed_size_type result = call_sendto(&msghdr::msg_namelen,
1732 s, data, size, flags, addr, addrlen);
1733 get_last_error(ec, result < 0);
1734 return result;
1735#endif // defined(BOOST_ASIO_WINDOWS) || defined(__CYGWIN__)
1736}
1737
1738size_t sync_sendto(socket_type s, state_type state,
1739 const buf* bufs, size_t count, int flags, const void* addr,
1740 std::size_t addrlen, boost::system::error_code& ec)
1741{
1742 if (s == invalid_socket)
1743 {
1744 ec = boost::asio::error::bad_descriptor;
1745 return 0;
1746 }
1747
1748 // Write some data.
1749 for (;;)
1750 {
1751 // Try to complete the operation without blocking.
1752 signed_size_type bytes = socket_ops::sendto(
1753 s, bufs, count, flags, addr, addrlen, ec);
1754
1755 // Check if operation succeeded.
1756 if (bytes >= 0)
1757 return bytes;
1758
1759 // Operation failed.
1760 if ((state & user_set_non_blocking)
1761 || (ec != boost::asio::error::would_block
1762 && ec != boost::asio::error::try_again))
1763 return 0;
1764
1765 // Wait for socket to become ready.
1766 if (socket_ops::poll_write(s, 0, -1, ec) < 0)
1767 return 0;
1768 }
1769}
1770
1771size_t sync_sendto1(socket_type s, state_type state,
1772 const void* data, size_t size, int flags, const void* addr,
1773 std::size_t addrlen, boost::system::error_code& ec)
1774{
1775 if (s == invalid_socket)
1776 {
1777 ec = boost::asio::error::bad_descriptor;
1778 return 0;
1779 }
1780
1781 // Write some data.
1782 for (;;)
1783 {
1784 // Try to complete the operation without blocking.
1785 signed_size_type bytes = socket_ops::sendto1(
1786 s, data, size, flags, addr, addrlen, ec);
1787
1788 // Check if operation succeeded.
1789 if (bytes >= 0)
1790 return bytes;
1791
1792 // Operation failed.
1793 if ((state & user_set_non_blocking)
1794 || (ec != boost::asio::error::would_block
1795 && ec != boost::asio::error::try_again))
1796 return 0;
1797
1798 // Wait for socket to become ready.
1799 if (socket_ops::poll_write(s, 0, -1, ec) < 0)
1800 return 0;
1801 }
1802}
1803
1804#if !defined(BOOST_ASIO_HAS_IOCP)
1805
1806bool non_blocking_sendto(socket_type s,
1807 const buf* bufs, size_t count, int flags,
1808 const void* addr, std::size_t addrlen,
1809 boost::system::error_code& ec, size_t& bytes_transferred)
1810{
1811 for (;;)
1812 {
1813 // Write some data.
1814 signed_size_type bytes = socket_ops::sendto(
1815 s, bufs, count, flags, addr, addrlen, ec);
1816
1817 // Check if operation succeeded.
1818 if (bytes >= 0)
1819 {
1820 bytes_transferred = bytes;
1821 return true;
1822 }
1823
1824 // Retry operation if interrupted by signal.
1825 if (ec == boost::asio::error::interrupted)
1826 continue;
1827
1828 // Check if we need to run the operation again.
1829 if (ec == boost::asio::error::would_block
1830 || ec == boost::asio::error::try_again)
1831 return false;
1832
1833 // Operation failed.
1834 bytes_transferred = 0;
1835 return true;
1836 }
1837}
1838
1839bool non_blocking_sendto1(socket_type s,
1840 const void* data, size_t size, int flags,
1841 const void* addr, std::size_t addrlen,
1842 boost::system::error_code& ec, size_t& bytes_transferred)
1843{
1844 for (;;)
1845 {
1846 // Write some data.
1847 signed_size_type bytes = socket_ops::sendto1(
1848 s, data, size, flags, addr, addrlen, ec);
1849
1850 // Check if operation succeeded.
1851 if (bytes >= 0)
1852 {
1853 bytes_transferred = bytes;
1854 return true;
1855 }
1856
1857 // Retry operation if interrupted by signal.
1858 if (ec == boost::asio::error::interrupted)
1859 continue;
1860
1861 // Check if we need to run the operation again.
1862 if (ec == boost::asio::error::would_block
1863 || ec == boost::asio::error::try_again)
1864 return false;
1865
1866 // Operation failed.
1867 bytes_transferred = 0;
1868 return true;
1869 }
1870}
1871
1872#endif // !defined(BOOST_ASIO_HAS_IOCP)
1873
1874socket_type socket(int af, int type, int protocol,
1875 boost::system::error_code& ec)
1876{
1877#if defined(BOOST_ASIO_WINDOWS) || defined(__CYGWIN__)
1878 socket_type s = ::WSASocketW(af, type, protocol, 0, 0, WSA_FLAG_OVERLAPPED);
1879 get_last_error(ec, s == invalid_socket);
1880 if (s == invalid_socket)
1881 return s;
1882
1883 if (af == BOOST_ASIO_OS_DEF(AF_INET6)10)
1884 {
1885 // Try to enable the POSIX default behaviour of having IPV6_V6ONLY set to
1886 // false. This will only succeed on Windows Vista and later versions of
1887 // Windows, where a dual-stack IPv4/v6 implementation is available.
1888 DWORD optval = 0;
1889 ::setsockopt(s, IPPROTO_IPV6IPPROTO_IPV6, IPV6_V6ONLY26,
1890 reinterpret_cast<const char*>(&optval), sizeof(optval));
1891 }
1892
1893 return s;
1894#elif defined(__MACH__) && defined(__APPLE__) || defined(__FreeBSD__)
1895 socket_type s = ::socket(af, type, protocol);
1896 get_last_error(ec, s == invalid_socket);
1897 if (s == invalid_socket)
1898 return s;
1899
1900 int optval = 1;
1901 int result = ::setsockopt(s, SOL_SOCKET1,
1902 SO_NOSIGPIPE, &optval, sizeof(optval));
1903 get_last_error(ec, result != 0);
1904 if (result != 0)
1905 {
1906 ::close(s);
1907 return invalid_socket;
1908 }
1909
1910 return s;
1911#else
1912 int s = ::socket(af, type, protocol);
1913 get_last_error(ec, s < 0);
1914 return s;
1915#endif
1916}
1917
1918template <typename SockLenType>
1919inline int call_setsockopt(SockLenType msghdr::*,
1920 socket_type s, int level, int optname,
1921 const void* optval, std::size_t optlen)
1922{
1923 return ::setsockopt(s, level, optname,
1924 (const char*)optval, (SockLenType)optlen);
1925}
1926
1927int setsockopt(socket_type s, state_type& state, int level, int optname,
1928 const void* optval, std::size_t optlen, boost::system::error_code& ec)
1929{
1930 if (s == invalid_socket)
1931 {
1932 ec = boost::asio::error::bad_descriptor;
1933 return socket_error_retval;
1934 }
1935
1936 if (level == custom_socket_option_level && optname == always_fail_option)
1937 {
1938 ec = boost::asio::error::invalid_argument;
1939 return socket_error_retval;
1940 }
1941
1942 if (level == custom_socket_option_level
1943 && optname == enable_connection_aborted_option)
1944 {
1945 if (optlen != sizeof(int))
1946 {
1947 ec = boost::asio::error::invalid_argument;
1948 return socket_error_retval;
1949 }
1950
1951 if (*static_cast<const int*>(optval))
1952 state |= enable_connection_aborted;
1953 else
1954 state &= ~enable_connection_aborted;
1955 boost::asio::error::clear(ec);
1956 return 0;
1957 }
1958
1959 if (level == SOL_SOCKET1 && optname == SO_LINGER13)
1960 state |= user_set_linger;
1961
1962#if defined(__BORLANDC__)
1963 // Mysteriously, using the getsockopt and setsockopt functions directly with
1964 // Borland C++ results in incorrect values being set and read. The bug can be
1965 // worked around by using function addresses resolved with GetProcAddress.
1966 if (HMODULE winsock_module = ::GetModuleHandleA("ws2_32"))
1967 {
1968 typedef int (WSAAPI *sso_t)(SOCKET, int, int, const char*, int);
1969 if (sso_t sso = (sso_t)::GetProcAddress(winsock_module, "setsockopt"))
1970 {
1971 int result = sso(s, level, optname,
1972 reinterpret_cast<const char*>(optval),
1973 static_cast<int>(optlen));
1974 get_last_error(ec, result != 0);
1975 return result;
1976 }
1977 }
1978 ec = boost::asio::error::fault;
1979 return socket_error_retval;
1980#else // defined(__BORLANDC__)
1981 int result = call_setsockopt(&msghdr::msg_namelen,
1982 s, level, optname, optval, optlen);
1983 get_last_error(ec, result != 0);
1984 if (result == 0)
1985 {
1986#if defined(__MACH__) && defined(__APPLE__) \
1987 || defined(__NetBSD__) || defined(__FreeBSD__) \
1988 || defined(__OpenBSD__) || defined(__QNX__)
1989 // To implement portable behaviour for SO_REUSEADDR with UDP sockets we
1990 // need to also set SO_REUSEPORT on BSD-based platforms.
1991 if ((state & datagram_oriented)
1992 && level == SOL_SOCKET1 && optname == SO_REUSEADDR2)
1993 {
1994 call_setsockopt(&msghdr::msg_namelen, s,
1995 SOL_SOCKET1, SO_REUSEPORT15, optval, optlen);
1996 }
1997#endif
1998 }
1999
2000 return result;
2001#endif // defined(__BORLANDC__)
2002}
2003
2004template <typename SockLenType>
2005inline int call_getsockopt(SockLenType msghdr::*,
2006 socket_type s, int level, int optname,
2007 void* optval, std::size_t* optlen)
2008{
2009 SockLenType tmp_optlen = (SockLenType)*optlen;
2010 int result = ::getsockopt(s, level, optname, (char*)optval, &tmp_optlen);
2011 *optlen = (std::size_t)tmp_optlen;
2012 return result;
2013}
2014
2015int getsockopt(socket_type s, state_type state, int level, int optname,
2016 void* optval, size_t* optlen, boost::system::error_code& ec)
2017{
2018 if (s == invalid_socket)
2019 {
2020 ec = boost::asio::error::bad_descriptor;
2021 return socket_error_retval;
2022 }
2023
2024 if (level == custom_socket_option_level && optname == always_fail_option)
2025 {
2026 ec = boost::asio::error::invalid_argument;
2027 return socket_error_retval;
2028 }
2029
2030 if (level == custom_socket_option_level
2031 && optname == enable_connection_aborted_option)
2032 {
2033 if (*optlen != sizeof(int))
2034 {
2035 ec = boost::asio::error::invalid_argument;
2036 return socket_error_retval;
2037 }
2038
2039 *static_cast<int*>(optval) = (state & enable_connection_aborted) ? 1 : 0;
2040 boost::asio::error::clear(ec);
2041 return 0;
2042 }
2043
2044#if defined(__BORLANDC__)
2045 // Mysteriously, using the getsockopt and setsockopt functions directly with
2046 // Borland C++ results in incorrect values being set and read. The bug can be
2047 // worked around by using function addresses resolved with GetProcAddress.
2048 if (HMODULE winsock_module = ::GetModuleHandleA("ws2_32"))
2049 {
2050 typedef int (WSAAPI *gso_t)(SOCKET, int, int, char*, int*);
2051 if (gso_t gso = (gso_t)::GetProcAddress(winsock_module, "getsockopt"))
2052 {
2053 int tmp_optlen = static_cast<int>(*optlen);
2054 int result = gso(s, level, optname,
2055 reinterpret_cast<char*>(optval), &tmp_optlen);
2056 get_last_error(ec, result != 0);
2057 *optlen = static_cast<size_t>(tmp_optlen);
2058 if (result != 0 && level == IPPROTO_IPV6IPPROTO_IPV6 && optname == IPV6_V6ONLY26
2059 && ec.value() == WSAENOPROTOOPT && *optlen == sizeof(DWORD))
2060 {
2061 // Dual-stack IPv4/v6 sockets, and the IPV6_V6ONLY socket option, are
2062 // only supported on Windows Vista and later. To simplify program logic
2063 // we will fake success of getting this option and specify that the
2064 // value is non-zero (i.e. true). This corresponds to the behavior of
2065 // IPv6 sockets on Windows platforms pre-Vista.
2066 *static_cast<DWORD*>(optval) = 1;
2067 boost::asio::error::clear(ec);
2068 }
2069 return result;
2070 }
2071 }
2072 ec = boost::asio::error::fault;
2073 return socket_error_retval;
2074#elif defined(BOOST_ASIO_WINDOWS) || defined(__CYGWIN__)
2075 int result = call_getsockopt(&msghdr::msg_namelen,
2076 s, level, optname, optval, optlen);
2077 get_last_error(ec, result != 0);
2078 if (result != 0 && level == IPPROTO_IPV6IPPROTO_IPV6 && optname == IPV6_V6ONLY26
2079 && ec.value() == WSAENOPROTOOPT && *optlen == sizeof(DWORD))
2080 {
2081 // Dual-stack IPv4/v6 sockets, and the IPV6_V6ONLY socket option, are only
2082 // supported on Windows Vista and later. To simplify program logic we will
2083 // fake success of getting this option and specify that the value is
2084 // non-zero (i.e. true). This corresponds to the behavior of IPv6 sockets
2085 // on Windows platforms pre-Vista.
2086 *static_cast<DWORD*>(optval) = 1;
2087 boost::asio::error::clear(ec);
2088 }
2089 return result;
2090#else // defined(BOOST_ASIO_WINDOWS) || defined(__CYGWIN__)
2091 int result = call_getsockopt(&msghdr::msg_namelen,
2092 s, level, optname, optval, optlen);
2093 get_last_error(ec, result != 0);
2094#if defined(__linux__1)
2095 if (result == 0 && level == SOL_SOCKET1 && *optlen == sizeof(int)
2096 && (optname == SO_SNDBUF7 || optname == SO_RCVBUF8))
2097 {
2098 // On Linux, setting SO_SNDBUF or SO_RCVBUF to N actually causes the kernel
2099 // to set the buffer size to N*2. Linux puts additional stuff into the
2100 // buffers so that only about half is actually available to the application.
2101 // The retrieved value is divided by 2 here to make it appear as though the
2102 // correct value has been set.
2103 *static_cast<int*>(optval) /= 2;
2104 }
2105#endif // defined(__linux__)
2106 return result;
2107#endif // defined(BOOST_ASIO_WINDOWS) || defined(__CYGWIN__)
2108}
2109
2110template <typename SockLenType>
2111inline int call_getpeername(SockLenType msghdr::*,
2112 socket_type s, void* addr, std::size_t* addrlen)
2113{
2114 SockLenType tmp_addrlen = (SockLenType)*addrlen;
2115 int result = ::getpeername(s,
2116 static_cast<socket_addr_type*>(addr), &tmp_addrlen);
2117 *addrlen = (std::size_t)tmp_addrlen;
2118 return result;
2119}
2120
2121int getpeername(socket_type s, void* addr, std::size_t* addrlen,
2122 bool cached, boost::system::error_code& ec)
2123{
2124 if (s == invalid_socket)
2125 {
2126 ec = boost::asio::error::bad_descriptor;
2127 return socket_error_retval;
2128 }
2129
2130#if defined(BOOST_ASIO_WINDOWS) && !defined(BOOST_ASIO_WINDOWS_APP) \
2131 || defined(__CYGWIN__)
2132 if (cached)
2133 {
2134 // Check if socket is still connected.
2135 DWORD connect_time = 0;
2136 size_t connect_time_len = sizeof(connect_time);
2137 if (socket_ops::getsockopt(s, 0, SOL_SOCKET1, SO_CONNECT_TIME,
2138 &connect_time, &connect_time_len, ec) == socket_error_retval)
2139 {
2140 return socket_error_retval;
2141 }
2142 if (connect_time == 0xFFFFFFFF)
2143 {
2144 ec = boost::asio::error::not_connected;
2145 return socket_error_retval;
2146 }
2147
2148 // The cached value is still valid.
2149 boost::asio::error::clear(ec);
2150 return 0;
2151 }
2152#else // defined(BOOST_ASIO_WINDOWS) && !defined(BOOST_ASIO_WINDOWS_APP)
2153 // || defined(__CYGWIN__)
2154 (void)cached;
2155#endif // defined(BOOST_ASIO_WINDOWS) && !defined(BOOST_ASIO_WINDOWS_APP)
2156 // || defined(__CYGWIN__)
2157
2158 int result = call_getpeername(&msghdr::msg_namelen, s, addr, addrlen);
2159 get_last_error(ec, result != 0);
2160 return result;
2161}
2162
2163template <typename SockLenType>
2164inline int call_getsockname(SockLenType msghdr::*,
2165 socket_type s, void* addr, std::size_t* addrlen)
2166{
2167 SockLenType tmp_addrlen = (SockLenType)*addrlen;
2168 int result = ::getsockname(s,
2169 static_cast<socket_addr_type*>(addr), &tmp_addrlen);
2170 *addrlen = (std::size_t)tmp_addrlen;
2171 return result;
2172}
2173
2174int getsockname(socket_type s, void* addr,
2175 std::size_t* addrlen, boost::system::error_code& ec)
2176{
2177 if (s == invalid_socket)
2178 {
2179 ec = boost::asio::error::bad_descriptor;
2180 return socket_error_retval;
2181 }
2182
2183 int result = call_getsockname(&msghdr::msg_namelen, s, addr, addrlen);
2184 get_last_error(ec, result != 0);
2185 return result;
2186}
2187
2188int ioctl(socket_type s, state_type& state, int cmd,
2189 ioctl_arg_type* arg, boost::system::error_code& ec)
2190{
2191 if (s == invalid_socket)
2192 {
2193 ec = boost::asio::error::bad_descriptor;
2194 return socket_error_retval;
2195 }
2196
2197#if defined(BOOST_ASIO_WINDOWS) || defined(__CYGWIN__)
2198 int result = ::ioctlsocket(s, cmd, arg);
2199#elif defined(__MACH__) && defined(__APPLE__) \
2200 || defined(__NetBSD__) || defined(__FreeBSD__) || defined(__OpenBSD__)
2201 int result = ::ioctl(s, static_cast<unsigned int>(cmd), arg);
2202#else
2203 int result = ::ioctl(s, cmd, arg);
2204#endif
2205 get_last_error(ec, result < 0);
2206 if (result >= 0)
2207 {
2208 // When updating the non-blocking mode we always perform the ioctl syscall,
2209 // even if the flags would otherwise indicate that the socket is already in
2210 // the correct state. This ensures that the underlying socket is put into
2211 // the state that has been requested by the user. If the ioctl syscall was
2212 // successful then we need to update the flags to match.
2213 if (cmd == static_cast<int>(FIONBIO0x5421))
2214 {
2215 if (*arg)
2216 {
2217 state |= user_set_non_blocking;
2218 }
2219 else
2220 {
2221 // Clearing the non-blocking mode always overrides any internally-set
2222 // non-blocking flag. Any subsequent asynchronous operations will need
2223 // to re-enable non-blocking I/O.
2224 state &= ~(user_set_non_blocking | internal_non_blocking);
2225 }
2226 }
2227 }
2228
2229 return result;
2230}
2231
2232int select(int nfds, fd_set* readfds, fd_set* writefds,
2233 fd_set* exceptfds, timeval* timeout, boost::system::error_code& ec)
2234{
2235#if defined(__EMSCRIPTEN__)
2236 exceptfds = 0;
2237#endif // defined(__EMSCRIPTEN__)
2238#if defined(BOOST_ASIO_WINDOWS) || defined(__CYGWIN__)
2239 if (!readfds && !writefds && !exceptfds && timeout)
2240 {
2241 DWORD milliseconds = timeout->tv_sec * 1000 + timeout->tv_usec / 1000;
2242 if (milliseconds == 0)
2243 milliseconds = 1; // Force context switch.
2244 ::Sleep(milliseconds);
2245 boost::asio::error::clear(ec);
2246 return 0;
2247 }
2248
2249 // The select() call allows timeout values measured in microseconds, but the
2250 // system clock (as wrapped by boost::posix_time::microsec_clock) typically
2251 // has a resolution of 10 milliseconds. This can lead to a spinning select
2252 // reactor, meaning increased CPU usage, when waiting for the earliest
2253 // scheduled timeout if it's less than 10 milliseconds away. To avoid a tight
2254 // spin we'll use a minimum timeout of 1 millisecond.
2255 if (timeout && timeout->tv_sec == 0
2256 && timeout->tv_usec > 0 && timeout->tv_usec < 1000)
2257 timeout->tv_usec = 1000;
2258#endif // defined(BOOST_ASIO_WINDOWS) || defined(__CYGWIN__)
2259
2260#if defined(__hpux) && defined(__SELECT)
2261 timespec ts;
2262 ts.tv_sec = timeout ? timeout->tv_sec : 0;
2263 ts.tv_nsec = timeout ? timeout->tv_usec * 1000 : 0;
2264 int result = ::pselect(nfds, readfds,
2265 writefds, exceptfds, timeout ? &ts : 0, 0);
2266#else
2267 int result = ::select(nfds, readfds, writefds, exceptfds, timeout);
2268#endif
2269 get_last_error(ec, result < 0);
2270 return result;
2271}
2272
2273int poll_read(socket_type s, state_type state,
2274 int msec, boost::system::error_code& ec)
2275{
2276 if (s == invalid_socket)
2277 {
2278 ec = boost::asio::error::bad_descriptor;
2279 return socket_error_retval;
2280 }
2281
2282#if defined(BOOST_ASIO_WINDOWS) \
2283 || defined(__CYGWIN__) \
2284 || defined(__SYMBIAN32__)
2285 fd_set fds;
2286 FD_ZERO(&fds)do { unsigned int __i; fd_set *__arr = (&fds); for (__i =
0; __i < sizeof (fd_set) / sizeof (__fd_mask); ++__i) ((__arr
)->fds_bits)[__i] = 0; } while (0)
;
2287 FD_SET(s, &fds)((void) (((&fds)->fds_bits)[((s) / (8 * (int) sizeof (
__fd_mask)))] |= ((__fd_mask) (1UL << ((s) % (8 * (int)
sizeof (__fd_mask)))))))
;
2288 timeval timeout_obj;
2289 timeval* timeout;
2290 if (state & user_set_non_blocking)
2291 {
2292 timeout_obj.tv_sec = 0;
2293 timeout_obj.tv_usec = 0;
2294 timeout = &timeout_obj;
2295 }
2296 else if (msec >= 0)
2297 {
2298 timeout_obj.tv_sec = msec / 1000;
2299 timeout_obj.tv_usec = (msec % 1000) * 1000;
2300 timeout = &timeout_obj;
2301 }
2302 else
2303 timeout = 0;
2304 int result = ::select(s + 1, &fds, 0, 0, timeout);
2305 get_last_error(ec, result < 0);
2306#else // defined(BOOST_ASIO_WINDOWS)
2307 // || defined(__CYGWIN__)
2308 // || defined(__SYMBIAN32__)
2309 pollfd fds;
2310 fds.fd = s;
2311 fds.events = POLLIN0x001;
2312 fds.revents = 0;
2313 int timeout = (state & user_set_non_blocking) ? 0 : msec;
2314 int result = ::poll(&fds, 1, timeout);
2315 get_last_error(ec, result < 0);
2316#endif // defined(BOOST_ASIO_WINDOWS)
2317 // || defined(__CYGWIN__)
2318 // || defined(__SYMBIAN32__)
2319 if (result == 0)
2320 if (state & user_set_non_blocking)
2321 ec = boost::asio::error::would_block;
2322 return result;
2323}
2324
2325int poll_write(socket_type s, state_type state,
2326 int msec, boost::system::error_code& ec)
2327{
2328 if (s == invalid_socket)
2329 {
2330 ec = boost::asio::error::bad_descriptor;
2331 return socket_error_retval;
2332 }
2333
2334#if defined(BOOST_ASIO_WINDOWS) \
2335 || defined(__CYGWIN__) \
2336 || defined(__SYMBIAN32__)
2337 fd_set fds;
2338 FD_ZERO(&fds)do { unsigned int __i; fd_set *__arr = (&fds); for (__i =
0; __i < sizeof (fd_set) / sizeof (__fd_mask); ++__i) ((__arr
)->fds_bits)[__i] = 0; } while (0)
;
2339 FD_SET(s, &fds)((void) (((&fds)->fds_bits)[((s) / (8 * (int) sizeof (
__fd_mask)))] |= ((__fd_mask) (1UL << ((s) % (8 * (int)
sizeof (__fd_mask)))))))
;
2340 timeval timeout_obj;
2341 timeval* timeout;
2342 if (state & user_set_non_blocking)
2343 {
2344 timeout_obj.tv_sec = 0;
2345 timeout_obj.tv_usec = 0;
2346 timeout = &timeout_obj;
2347 }
2348 else if (msec >= 0)
2349 {
2350 timeout_obj.tv_sec = msec / 1000;
2351 timeout_obj.tv_usec = (msec % 1000) * 1000;
2352 timeout = &timeout_obj;
2353 }
2354 else
2355 timeout = 0;
2356 int result = ::select(s + 1, 0, &fds, 0, timeout);
2357 get_last_error(ec, result < 0);
2358#else // defined(BOOST_ASIO_WINDOWS)
2359 // || defined(__CYGWIN__)
2360 // || defined(__SYMBIAN32__)
2361 pollfd fds;
2362 fds.fd = s;
2363 fds.events = POLLOUT0x004;
2364 fds.revents = 0;
2365 int timeout = (state & user_set_non_blocking) ? 0 : msec;
2366 int result = ::poll(&fds, 1, timeout);
2367 get_last_error(ec, result < 0);
2368#endif // defined(BOOST_ASIO_WINDOWS)
2369 // || defined(__CYGWIN__)
2370 // || defined(__SYMBIAN32__)
2371 if (result == 0)
2372 if (state & user_set_non_blocking)
2373 ec = boost::asio::error::would_block;
2374 return result;
2375}
2376
2377int poll_error(socket_type s, state_type state,
2378 int msec, boost::system::error_code& ec)
2379{
2380 if (s == invalid_socket)
2381 {
2382 ec = boost::asio::error::bad_descriptor;
2383 return socket_error_retval;
2384 }
2385
2386#if defined(BOOST_ASIO_WINDOWS) \
2387 || defined(__CYGWIN__) \
2388 || defined(__SYMBIAN32__)
2389 fd_set fds;
2390 FD_ZERO(&fds)do { unsigned int __i; fd_set *__arr = (&fds); for (__i =
0; __i < sizeof (fd_set) / sizeof (__fd_mask); ++__i) ((__arr
)->fds_bits)[__i] = 0; } while (0)
;
2391 FD_SET(s, &fds)((void) (((&fds)->fds_bits)[((s) / (8 * (int) sizeof (
__fd_mask)))] |= ((__fd_mask) (1UL << ((s) % (8 * (int)
sizeof (__fd_mask)))))))
;
2392 timeval timeout_obj;
2393 timeval* timeout;
2394 if (state & user_set_non_blocking)
2395 {
2396 timeout_obj.tv_sec = 0;
2397 timeout_obj.tv_usec = 0;
2398 timeout = &timeout_obj;
2399 }
2400 else if (msec >= 0)
2401 {
2402 timeout_obj.tv_sec = msec / 1000;
2403 timeout_obj.tv_usec = (msec % 1000) * 1000;
2404 timeout = &timeout_obj;
2405 }
2406 else
2407 timeout = 0;
2408 int result = ::select(s + 1, 0, 0, &fds, timeout);
2409 get_last_error(ec, result < 0);
2410#else // defined(BOOST_ASIO_WINDOWS)
2411 // || defined(__CYGWIN__)
2412 // || defined(__SYMBIAN32__)
2413 pollfd fds;
2414 fds.fd = s;
2415 fds.events = POLLPRI0x002 | POLLERR0x008 | POLLHUP0x010;
2416 fds.revents = 0;
2417 int timeout = (state & user_set_non_blocking) ? 0 : msec;
2418 int result = ::poll(&fds, 1, timeout);
2419 get_last_error(ec, result < 0);
2420#endif // defined(BOOST_ASIO_WINDOWS)
2421 // || defined(__CYGWIN__)
2422 // || defined(__SYMBIAN32__)
2423 if (result == 0)
2424 if (state & user_set_non_blocking)
2425 ec = boost::asio::error::would_block;
2426 return result;
2427}
2428
2429int poll_connect(socket_type s, int msec, boost::system::error_code& ec)
2430{
2431 if (s == invalid_socket)
2432 {
2433 ec = boost::asio::error::bad_descriptor;
2434 return socket_error_retval;
2435 }
2436
2437#if defined(BOOST_ASIO_WINDOWS) \
2438 || defined(__CYGWIN__) \
2439 || defined(__SYMBIAN32__)
2440 fd_set write_fds;
2441 FD_ZERO(&write_fds)do { unsigned int __i; fd_set *__arr = (&write_fds); for (
__i = 0; __i < sizeof (fd_set) / sizeof (__fd_mask); ++__i
) ((__arr)->fds_bits)[__i] = 0; } while (0)
;
2442 FD_SET(s, &write_fds)((void) (((&write_fds)->fds_bits)[((s) / (8 * (int) sizeof
(__fd_mask)))] |= ((__fd_mask) (1UL << ((s) % (8 * (int
) sizeof (__fd_mask)))))))
;
2443 fd_set except_fds;
2444 FD_ZERO(&except_fds)do { unsigned int __i; fd_set *__arr = (&except_fds); for
(__i = 0; __i < sizeof (fd_set) / sizeof (__fd_mask); ++__i
) ((__arr)->fds_bits)[__i] = 0; } while (0)
;
2445 FD_SET(s, &except_fds)((void) (((&except_fds)->fds_bits)[((s) / (8 * (int) sizeof
(__fd_mask)))] |= ((__fd_mask) (1UL << ((s) % (8 * (int
) sizeof (__fd_mask)))))))
;
2446 timeval timeout_obj;
2447 timeval* timeout;
2448 if (msec >= 0)
2449 {
2450 timeout_obj.tv_sec = msec / 1000;
2451 timeout_obj.tv_usec = (msec % 1000) * 1000;
2452 timeout = &timeout_obj;
2453 }
2454 else
2455 timeout = 0;
2456 int result = ::select(s + 1, 0, &write_fds, &except_fds, timeout);
2457 get_last_error(ec, result < 0);
2458 return result;
2459#else // defined(BOOST_ASIO_WINDOWS)
2460 // || defined(__CYGWIN__)
2461 // || defined(__SYMBIAN32__)
2462 pollfd fds;
2463 fds.fd = s;
2464 fds.events = POLLOUT0x004;
2465 fds.revents = 0;
2466 int result = ::poll(&fds, 1, msec);
2467 get_last_error(ec, result < 0);
2468 return result;
2469#endif // defined(BOOST_ASIO_WINDOWS)
2470 // || defined(__CYGWIN__)
2471 // || defined(__SYMBIAN32__)
2472}
2473
2474#endif // !defined(BOOST_ASIO_WINDOWS_RUNTIME)
2475
2476const char* inet_ntop(int af, const void* src, char* dest, size_t length,
2477 unsigned long scope_id, boost::system::error_code& ec)
2478{
2479 clear_last_error();
2480#if defined(BOOST_ASIO_WINDOWS_RUNTIME)
2481 using namespace std; // For sprintf.
2482 const unsigned char* bytes = static_cast<const unsigned char*>(src);
2483 if (af == BOOST_ASIO_OS_DEF(AF_INET)2)
2484 {
2485 sprintf_s(dest, length, "%u.%u.%u.%u",
2486 bytes[0], bytes[1], bytes[2], bytes[3]);
2487 return dest;
2488 }
2489 else if (af == BOOST_ASIO_OS_DEF(AF_INET6)10)
2490 {
2491 size_t n = 0, b = 0, z = 0;
2492 while (n < length && b < 16)
2493 {
2494 if (bytes[b] == 0 && bytes[b + 1] == 0 && z == 0)
2495 {
2496 do b += 2; while (b < 16 && bytes[b] == 0 && bytes[b + 1] == 0);
2497 n += sprintf_s(dest + n, length - n, ":%s", b < 16 ? "" : ":"), ++z;
2498 }
2499 else
2500 {
2501 n += sprintf_s(dest + n, length - n, "%s%x", b ? ":" : "",
2502 (static_cast<u_long_type>(bytes[b]) << 8) | bytes[b + 1]);
2503 b += 2;
2504 }
2505 }
2506 if (scope_id)
2507 n += sprintf_s(dest + n, length - n, "%%%lu", scope_id);
2508 return dest;
2509 }
2510 else
2511 {
2512 ec = boost::asio::error::address_family_not_supported;
2513 return 0;
2514 }
2515#elif defined(BOOST_ASIO_WINDOWS) || defined(__CYGWIN__)
2516 using namespace std; // For memcpy.
2517
2518 if (af != BOOST_ASIO_OS_DEF(AF_INET)2 && af != BOOST_ASIO_OS_DEF(AF_INET6)10)
2519 {
2520 ec = boost::asio::error::address_family_not_supported;
2521 return 0;
2522 }
2523
2524 union
2525 {
2526 socket_addr_type base;
2527 sockaddr_storage_type storage;
2528 sockaddr_in4_type v4;
2529 sockaddr_in6_type v6;
2530 } address;
2531 DWORD address_length;
2532 if (af == BOOST_ASIO_OS_DEF(AF_INET)2)
2533 {
2534 address_length = sizeof(sockaddr_in4_type);
2535 address.v4.sin_family = BOOST_ASIO_OS_DEF(AF_INET)2;
2536 address.v4.sin_port = 0;
2537 memcpy(&address.v4.sin_addr, src, sizeof(in4_addr_type));
2538 }
2539 else // AF_INET6
2540 {
2541 address_length = sizeof(sockaddr_in6_type);
2542 address.v6.sin6_family = BOOST_ASIO_OS_DEF(AF_INET6)10;
2543 address.v6.sin6_port = 0;
2544 address.v6.sin6_flowinfo = 0;
2545 address.v6.sin6_scope_id = scope_id;
2546 memcpy(&address.v6.sin6_addr, src, sizeof(in6_addr_type));
2547 }
2548
2549 DWORD string_length = static_cast<DWORD>(length);
2550#if defined(BOOST_NO_ANSI_APIS) || (defined(_MSC_VER) && (_MSC_VER >= 1800))
2551 LPWSTR string_buffer = (LPWSTR)_alloca(length * sizeof(WCHAR));
2552 int result = ::WSAAddressToStringW(&address.base,
2553 address_length, 0, string_buffer, &string_length);
2554 get_last_error(ec, true);
2555 ::WideCharToMultiByte(CP_ACP, 0, string_buffer, -1,
2556 dest, static_cast<int>(length), 0, 0);
2557#else
2558 int result = ::WSAAddressToStringA(&address.base,
2559 address_length, 0, dest, &string_length);
2560 get_last_error(ec, true);
2561#endif
2562
2563 // Windows may set error code on success.
2564 if (result != socket_error_retval)
2565 boost::asio::error::clear(ec);
2566
2567 // Windows may not set an error code on failure.
2568 else if (result == socket_error_retval && !ec)
2569 ec = boost::asio::error::invalid_argument;
2570
2571 return result == socket_error_retval ? 0 : dest;
2572#else // defined(BOOST_ASIO_WINDOWS) || defined(__CYGWIN__)
2573 const char* result = ::inet_ntop(af, src, dest, static_cast<int>(length));
2574 get_last_error(ec, true);
2575 if (result == 0 && !ec)
2576 ec = boost::asio::error::invalid_argument;
2577 if (result != 0 && af == BOOST_ASIO_OS_DEF(AF_INET6)10 && scope_id != 0)
2578 {
2579 using namespace std; // For strcat and sprintf.
2580 char if_name[(IF_NAMESIZE16 > 21 ? IF_NAMESIZE16 : 21) + 1] = "%";
2581 const in6_addr_type* ipv6_address = static_cast<const in6_addr_type*>(src);
2582 bool is_link_local = ((ipv6_address->s6_addr__in6_u.__u6_addr8[0] == 0xfe)
2583 && ((ipv6_address->s6_addr__in6_u.__u6_addr8[1] & 0xc0) == 0x80));
2584 bool is_multicast_link_local = ((ipv6_address->s6_addr__in6_u.__u6_addr8[0] == 0xff)
2585 && ((ipv6_address->s6_addr__in6_u.__u6_addr8[1] & 0x0f) == 0x02));
2586 if ((!is_link_local && !is_multicast_link_local)
2587 || if_indextoname(static_cast<unsigned>(scope_id), if_name + 1) == 0)
2588#if defined(BOOST_ASIO_HAS_SNPRINTF)
2589 snprintf(if_name + 1, sizeof(if_name) - 1, "%lu", scope_id);
2590#elif defined(BOOST_ASIO_HAS_SECURE_RTL)
2591 sprintf_s(if_name + 1, sizeof(if_name) -1, "%lu", scope_id);
2592#else // defined(BOOST_ASIO_HAS_SECURE_RTL)
2593 sprintf(if_name + 1, "%lu", scope_id);
2594#endif // defined(BOOST_ASIO_HAS_SECURE_RTL)
2595 strcat(dest, if_name);
2596 }
2597 return result;
2598#endif // defined(BOOST_ASIO_WINDOWS) || defined(__CYGWIN__)
2599}
2600
2601int inet_pton(int af, const char* src, void* dest,
2602 unsigned long* scope_id, boost::system::error_code& ec)
2603{
2604 clear_last_error();
2605#if defined(BOOST_ASIO_WINDOWS_RUNTIME)
2606 using namespace std; // For sscanf.
2607 unsigned char* bytes = static_cast<unsigned char*>(dest);
2608 if (af == BOOST_ASIO_OS_DEF(AF_INET)2)
2609 {
2610 unsigned int b0, b1, b2, b3;
2611 if (sscanf_s(src, "%u.%u.%u.%u", &b0, &b1, &b2, &b3) != 4)
2612 {
2613 ec = boost::asio::error::invalid_argument;
2614 return -1;
2615 }
2616 if (b0 > 255 || b1 > 255 || b2 > 255 || b3 > 255)
2617 {
2618 ec = boost::asio::error::invalid_argument;
2619 return -1;
2620 }
2621 bytes[0] = static_cast<unsigned char>(b0);
2622 bytes[1] = static_cast<unsigned char>(b1);
2623 bytes[2] = static_cast<unsigned char>(b2);
2624 bytes[3] = static_cast<unsigned char>(b3);
2625 boost::asio::error::clear(ec);
2626 return 1;
2627 }
2628 else if (af == BOOST_ASIO_OS_DEF(AF_INET6)10)
2629 {
2630 unsigned char* bytes = static_cast<unsigned char*>(dest);
2631 std::memset(bytes, 0, 16);
2632 unsigned char back_bytes[16] = { 0 };
2633 int num_front_bytes = 0, num_back_bytes = 0;
2634 const char* p = src;
2635
2636 enum { fword, fcolon, bword, scope, done } state = fword;
2637 unsigned long current_word = 0;
2638 while (state != done)
2639 {
2640 if (current_word > 0xFFFF)
2641 {
2642 ec = boost::asio::error::invalid_argument;
2643 return -1;
2644 }
2645
2646 switch (state)
2647 {
2648 case fword:
2649 if (*p >= '0' && *p <= '9')
2650 current_word = current_word * 16 + *p++ - '0';
2651 else if (*p >= 'a' && *p <= 'f')
2652 current_word = current_word * 16 + *p++ - 'a' + 10;
2653 else if (*p >= 'A' && *p <= 'F')
2654 current_word = current_word * 16 + *p++ - 'A' + 10;
2655 else
2656 {
2657 if (num_front_bytes == 16)
2658 {
2659 ec = boost::asio::error::invalid_argument;
2660 return -1;
2661 }
2662
2663 bytes[num_front_bytes++] = (current_word >> 8) & 0xFF;
2664 bytes[num_front_bytes++] = current_word & 0xFF;
2665 current_word = 0;
2666
2667 if (*p == ':')
2668 state = fcolon, ++p;
2669 else if (*p == '%')
2670 state = scope, ++p;
2671 else if (*p == 0)
2672 state = done;
2673 else
2674 {
2675 ec = boost::asio::error::invalid_argument;
2676 return -1;
2677 }
2678 }
2679 break;
2680
2681 case fcolon:
2682 if (*p == ':')
2683 state = bword, ++p;
2684 else
2685 state = fword;
2686 break;
2687
2688 case bword:
2689 if (*p >= '0' && *p <= '9')
2690 current_word = current_word * 16 + *p++ - '0';
2691 else if (*p >= 'a' && *p <= 'f')
2692 current_word = current_word * 16 + *p++ - 'a' + 10;
2693 else if (*p >= 'A' && *p <= 'F')
2694 current_word = current_word * 16 + *p++ - 'A' + 10;
2695 else
2696 {
2697 if (num_front_bytes + num_back_bytes == 16)
2698 {
2699 ec = boost::asio::error::invalid_argument;
2700 return -1;
2701 }
2702
2703 back_bytes[num_back_bytes++] = (current_word >> 8) & 0xFF;
2704 back_bytes[num_back_bytes++] = current_word & 0xFF;
2705 current_word = 0;
2706
2707 if (*p == ':')
2708 state = bword, ++p;
2709 else if (*p == '%')
2710 state = scope, ++p;
2711 else if (*p == 0)
2712 state = done;
2713 else
2714 {
2715 ec = boost::asio::error::invalid_argument;
2716 return -1;
2717 }
2718 }
2719 break;
2720
2721 case scope:
2722 if (*p >= '0' && *p <= '9')
2723 current_word = current_word * 10 + *p++ - '0';
2724 else if (*p == 0)
2725 *scope_id = current_word, state = done;
2726 else
2727 {
2728 ec = boost::asio::error::invalid_argument;
2729 return -1;
2730 }
2731 break;
2732
2733 default:
2734 break;
2735 }
2736 }
2737
2738 for (int i = 0; i < num_back_bytes; ++i)
2739 bytes[16 - num_back_bytes + i] = back_bytes[i];
2740
2741 boost::asio::error::clear(ec);
2742 return 1;
2743 }
2744 else
2745 {
2746 ec = boost::asio::error::address_family_not_supported;
2747 return -1;
2748 }
2749#elif defined(BOOST_ASIO_WINDOWS) || defined(__CYGWIN__)
2750 using namespace std; // For memcpy and strcmp.
2751
2752 if (af != BOOST_ASIO_OS_DEF(AF_INET)2 && af != BOOST_ASIO_OS_DEF(AF_INET6)10)
2753 {
2754 ec = boost::asio::error::address_family_not_supported;
2755 return -1;
2756 }
2757
2758 union
2759 {
2760 socket_addr_type base;
2761 sockaddr_storage_type storage;
2762 sockaddr_in4_type v4;
2763 sockaddr_in6_type v6;
2764 } address;
2765 int address_length = sizeof(sockaddr_storage_type);
2766#if defined(BOOST_NO_ANSI_APIS) || (defined(_MSC_VER) && (_MSC_VER >= 1800))
2767 int num_wide_chars = static_cast<int>(strlen(src)) + 1;
2768 LPWSTR wide_buffer = (LPWSTR)_alloca(num_wide_chars * sizeof(WCHAR));
2769 ::MultiByteToWideChar(CP_ACP, 0, src, -1, wide_buffer, num_wide_chars);
2770 int result = ::WSAStringToAddressW(wide_buffer,
2771 af, 0, &address.base, &address_length);
2772 get_last_error(ec, true);
2773#else
2774 int result = ::WSAStringToAddressA(const_cast<char*>(src),
2775 af, 0, &address.base, &address_length);
2776 get_last_error(ec, true);
2777#endif
2778
2779 if (af == BOOST_ASIO_OS_DEF(AF_INET)2)
2780 {
2781 if (result != socket_error_retval)
2782 {
2783 memcpy(dest, &address.v4.sin_addr, sizeof(in4_addr_type));
2784 boost::asio::error::clear(ec);
2785 }
2786 else if (strcmp(src, "255.255.255.255") == 0)
2787 {
2788 static_cast<in4_addr_type*>(dest)->s_addr = INADDR_NONE((in_addr_t) 0xffffffff);
2789 boost::asio::error::clear(ec);
2790 }
2791 }
2792 else // AF_INET6
2793 {
2794 if (result != socket_error_retval)
2795 {
2796 memcpy(dest, &address.v6.sin6_addr, sizeof(in6_addr_type));
2797 if (scope_id)
2798 *scope_id = address.v6.sin6_scope_id;
2799 boost::asio::error::clear(ec);
2800 }
2801 }
2802
2803 // Windows may not set an error code on failure.
2804 if (result == socket_error_retval && !ec)
2805 ec = boost::asio::error::invalid_argument;
2806
2807 if (result != socket_error_retval)
2808 boost::asio::error::clear(ec);
2809
2810 return result == socket_error_retval ? -1 : 1;
2811#else // defined(BOOST_ASIO_WINDOWS) || defined(__CYGWIN__)
2812 using namespace std; // For strchr, memcpy and atoi.
2813
2814 // On some platforms, inet_pton fails if an address string contains a scope
2815 // id. Detect and remove the scope id before passing the string to inet_pton.
2816 const bool is_v6 = (af == BOOST_ASIO_OS_DEF(AF_INET6)10);
2817 const char* if_name = is_v6 ? strchr(src, '%') : 0;
2818 char src_buf[max_addr_v6_str_len + 1];
2819 const char* src_ptr = src;
2820 if (if_name != 0)
2821 {
2822 if (if_name - src > max_addr_v6_str_len)
2823 {
2824 ec = boost::asio::error::invalid_argument;
2825 return 0;
2826 }
2827 memcpy(src_buf, src, if_name - src);
2828 src_buf[if_name - src] = 0;
2829 src_ptr = src_buf;
2830 }
2831
2832 int result = ::inet_pton(af, src_ptr, dest);
2833 get_last_error(ec, true);
2834 if (result <= 0 && !ec)
2835 ec = boost::asio::error::invalid_argument;
2836 if (result > 0 && is_v6 && scope_id)
2837 {
2838 using namespace std; // For strchr and atoi.
2839 *scope_id = 0;
2840 if (if_name != 0)
2841 {
2842 in6_addr_type* ipv6_address = static_cast<in6_addr_type*>(dest);
2843 bool is_link_local = ((ipv6_address->s6_addr__in6_u.__u6_addr8[0] == 0xfe)
2844 && ((ipv6_address->s6_addr__in6_u.__u6_addr8[1] & 0xc0) == 0x80));
2845 bool is_multicast_link_local = ((ipv6_address->s6_addr__in6_u.__u6_addr8[0] == 0xff)
2846 && ((ipv6_address->s6_addr__in6_u.__u6_addr8[1] & 0x0f) == 0x02));
2847 if (is_link_local || is_multicast_link_local)
2848 *scope_id = if_nametoindex(if_name + 1);
2849 if (*scope_id == 0)
2850 *scope_id = atoi(if_name + 1);
2851 }
2852 }
2853 return result;
2854#endif // defined(BOOST_ASIO_WINDOWS) || defined(__CYGWIN__)
2855}
2856
2857int gethostname(char* name, int namelen, boost::system::error_code& ec)
2858{
2859#if defined(BOOST_ASIO_WINDOWS_RUNTIME)
2860 try
2861 {
2862 using namespace Windows::Foundation::Collections;
2863 using namespace Windows::Networking;
2864 using namespace Windows::Networking::Connectivity;
2865 IVectorView<HostName^>^ hostnames = NetworkInformation::GetHostNames();
2866 for (unsigned i = 0; i < hostnames->Size; ++i)
2867 {
2868 HostName^ hostname = hostnames->GetAt(i);
2869 if (hostname->Type == HostNameType::DomainName)
2870 {
2871 std::wstring_convert<std::codecvt_utf8<wchar_t>> converter;
2872 std::string raw_name = converter.to_bytes(hostname->RawName->Data());
2873 if (namelen > 0 && raw_name.size() < static_cast<std::size_t>(namelen))
2874 {
2875 strcpy_s(name, namelen, raw_name.c_str());
2876 return 0;
2877 }
2878 }
2879 }
2880 return -1;
2881 }
2882 catch (Platform::Exception^ e)
2883 {
2884 ec = boost::system::error_code(e->HResult,
2885 boost::system::system_category());
2886 return -1;
2887 }
2888#else // defined(BOOST_ASIO_WINDOWS_RUNTIME)
2889 int result = ::gethostname(name, namelen);
2890 get_last_error(ec, result != 0);
2891 return result;
2892#endif // defined(BOOST_ASIO_WINDOWS_RUNTIME)
2893}
2894
2895#if !defined(BOOST_ASIO_WINDOWS_RUNTIME)
2896
2897#if !defined(BOOST_ASIO_HAS_GETADDRINFO1)
2898
2899// The following functions are only needed for emulation of getaddrinfo and
2900// getnameinfo.
2901
2902inline boost::system::error_code translate_netdb_error(int error)
2903{
2904 switch (error)
2905 {
2906 case 0:
2907 return boost::system::error_code();
2908 case HOST_NOT_FOUND1:
2909 return boost::asio::error::host_not_found;
2910 case TRY_AGAIN2:
2911 return boost::asio::error::host_not_found_try_again;
2912 case NO_RECOVERY3:
2913 return boost::asio::error::no_recovery;
2914 case NO_DATA4:
2915 return boost::asio::error::no_data;
2916 default:
2917 BOOST_ASIO_ASSERT(false)(static_cast <bool> (false) ? void (0) : __assert_fail (
"false", __builtin_FILE (), __builtin_LINE (), __extension__ __PRETTY_FUNCTION__
))
;
2918 return boost::asio::error::invalid_argument;
2919 }
2920}
2921
2922inline hostent* gethostbyaddr(const char* addr, int length, int af,
2923 hostent* result, char* buffer, int buflength, boost::system::error_code& ec)
2924{
2925#if defined(BOOST_ASIO_WINDOWS) || defined(__CYGWIN__)
2926 (void)(buffer);
2927 (void)(buflength);
2928 hostent* retval = ::gethostbyaddr(addr, length, af);
2929 get_last_error(ec, !retval);
2930 if (!retval)
2931 return 0;
2932 *result = *retval;
2933 return retval;
2934#elif defined(__sun) || defined(__QNX__)
2935 int error = 0;
2936 hostent* retval = ::gethostbyaddr_r(addr, length,
2937 af, result, buffer, buflength, &error);
2938 get_last_error(ec, !retval);
2939 if (error)
2940 ec = translate_netdb_error(error);
2941 return retval;
2942#elif defined(__MACH__) && defined(__APPLE__)
2943 (void)(buffer);
2944 (void)(buflength);
2945 int error = 0;
2946 hostent* retval = ::getipnodebyaddr(addr, length, af, &error);
2947 get_last_error(ec, !retval);
2948 if (error)
2949 ec = translate_netdb_error(error);
2950 if (!retval)
2951 return 0;
2952 *result = *retval;
2953 return retval;
2954#else
2955 hostent* retval = 0;
2956 int error = 0;
2957 clear_last_error();
2958 ::gethostbyaddr_r(addr, length, af, result,
2959 buffer, buflength, &retval, &error);
2960 get_last_error(ec, true);
2961 if (error)
2962 ec = translate_netdb_error(error);
2963 return retval;
2964#endif
2965}
2966
2967inline hostent* gethostbyname(const char* name, int af, struct hostent* result,
2968 char* buffer, int buflength, int ai_flags, boost::system::error_code& ec)
2969{
2970#if defined(BOOST_ASIO_WINDOWS) || defined(__CYGWIN__)
2971 (void)(buffer);
2972 (void)(buflength);
2973 (void)(ai_flags);
2974 if (af != BOOST_ASIO_OS_DEF(AF_INET)2)
2975 {
2976 ec = boost::asio::error::address_family_not_supported;
2977 return 0;
2978 }
2979 hostent* retval = ::gethostbyname(name);
2980 get_last_error(ec, !retval);
2981 if (!retval)
2982 return 0;
2983 *result = *retval;
2984 return result;
2985#elif defined(__sun) || defined(__QNX__)
2986 (void)(ai_flags);
2987 if (af != BOOST_ASIO_OS_DEF(AF_INET)2)
2988 {
2989 ec = boost::asio::error::address_family_not_supported;
2990 return 0;
2991 }
2992 int error = 0;
2993 hostent* retval = ::gethostbyname_r(name, result, buffer, buflength, &error);
2994 get_last_error(ec, !retval);
2995 if (error)
2996 ec = translate_netdb_error(error);
2997 return retval;
2998#elif defined(__MACH__) && defined(__APPLE__)
2999 (void)(buffer);
3000 (void)(buflength);
3001 int error = 0;
3002 hostent* retval = ::getipnodebyname(name, af, ai_flags, &error);
3003 get_last_error(ec, !retval);
3004 if (error)
3005 ec = translate_netdb_error(error);
3006 if (!retval)
3007 return 0;
3008 *result = *retval;
3009 return retval;
3010#else
3011 (void)(ai_flags);
3012 if (af != BOOST_ASIO_OS_DEF(AF_INET)2)
3013 {
3014 ec = boost::asio::error::address_family_not_supported;
3015 return 0;
3016 }
3017 hostent* retval = 0;
3018 int error = 0;
3019 clear_last_error();
3020 ::gethostbyname_r(name, result, buffer, buflength, &retval, &error);
3021 get_last_error(ec, true);
3022 if (error)
3023 ec = translate_netdb_error(error);
3024 return retval;
3025#endif
3026}
3027
3028inline void freehostent(hostent* h)
3029{
3030#if defined(__MACH__) && defined(__APPLE__)
3031 if (h)
3032 ::freehostent(h);
3033#else
3034 (void)(h);
3035#endif
3036}
3037
3038// Emulation of getaddrinfo based on implementation in:
3039// Stevens, W. R., UNIX Network Programming Vol. 1, 2nd Ed., Prentice-Hall 1998.
3040
3041struct gai_search
3042{
3043 const char* host;
3044 int family;
3045};
3046
3047inline int gai_nsearch(const char* host,
3048 const addrinfo_type* hints, gai_search (&search)[2])
3049{
3050 int search_count = 0;
3051 if (host == 0 || host[0] == '\0')
3052 {
3053 if (hints->ai_flags & AI_PASSIVE0x0001)
3054 {
3055 // No host and AI_PASSIVE implies wildcard bind.
3056 switch (hints->ai_family)
3057 {
3058 case BOOST_ASIO_OS_DEF(AF_INET)2:
3059 search[search_count].host = "0.0.0.0";
3060 search[search_count].family = BOOST_ASIO_OS_DEF(AF_INET)2;
3061 ++search_count;
3062 break;
3063 case BOOST_ASIO_OS_DEF(AF_INET6)10:
3064 search[search_count].host = "0::0";
3065 search[search_count].family = BOOST_ASIO_OS_DEF(AF_INET6)10;
3066 ++search_count;
3067 break;
3068 case BOOST_ASIO_OS_DEF(AF_UNSPEC)0:
3069 search[search_count].host = "0::0";
3070 search[search_count].family = BOOST_ASIO_OS_DEF(AF_INET6)10;
3071 ++search_count;
3072 search[search_count].host = "0.0.0.0";
3073 search[search_count].family = BOOST_ASIO_OS_DEF(AF_INET)2;
3074 ++search_count;
3075 break;
3076 default:
3077 break;
3078 }
3079 }
3080 else
3081 {
3082 // No host and not AI_PASSIVE means connect to local host.
3083 switch (hints->ai_family)
3084 {
3085 case BOOST_ASIO_OS_DEF(AF_INET)2:
3086 search[search_count].host = "localhost";
3087 search[search_count].family = BOOST_ASIO_OS_DEF(AF_INET)2;
3088 ++search_count;
3089 break;
3090 case BOOST_ASIO_OS_DEF(AF_INET6)10:
3091 search[search_count].host = "localhost";
3092 search[search_count].family = BOOST_ASIO_OS_DEF(AF_INET6)10;
3093 ++search_count;
3094 break;
3095 case BOOST_ASIO_OS_DEF(AF_UNSPEC)0:
3096 search[search_count].host = "localhost";
3097 search[search_count].family = BOOST_ASIO_OS_DEF(AF_INET6)10;
3098 ++search_count;
3099 search[search_count].host = "localhost";
3100 search[search_count].family = BOOST_ASIO_OS_DEF(AF_INET)2;
3101 ++search_count;
3102 break;
3103 default:
3104 break;
3105 }
3106 }
3107 }
3108 else
3109 {
3110 // Host is specified.
3111 switch (hints->ai_family)
3112 {
3113 case BOOST_ASIO_OS_DEF(AF_INET)2:
3114 search[search_count].host = host;
3115 search[search_count].family = BOOST_ASIO_OS_DEF(AF_INET)2;
3116 ++search_count;
3117 break;
3118 case BOOST_ASIO_OS_DEF(AF_INET6)10:
3119 search[search_count].host = host;
3120 search[search_count].family = BOOST_ASIO_OS_DEF(AF_INET6)10;
3121 ++search_count;
3122 break;
3123 case BOOST_ASIO_OS_DEF(AF_UNSPEC)0:
3124 search[search_count].host = host;
3125 search[search_count].family = BOOST_ASIO_OS_DEF(AF_INET6)10;
3126 ++search_count;
3127 search[search_count].host = host;
3128 search[search_count].family = BOOST_ASIO_OS_DEF(AF_INET)2;
3129 ++search_count;
3130 break;
3131 default:
3132 break;
3133 }
3134 }
3135 return search_count;
3136}
3137
3138template <typename T>
3139inline T* gai_alloc(std::size_t size = sizeof(T))
3140{
3141 using namespace std;
3142 T* p = static_cast<T*>(::operator new(size, std::nothrow));
3143 if (p)
3144 memset(p, 0, size);
3145 return p;
3146}
3147
3148inline void gai_free(void* p)
3149{
3150 ::operator delete(p);
3151}
3152
3153inline void gai_strcpy(char* target, const char* source, std::size_t max_size)
3154{
3155 using namespace std;
3156#if defined(BOOST_ASIO_HAS_SECURE_RTL)
3157 strcpy_s(target, max_size, source);
3158#else // defined(BOOST_ASIO_HAS_SECURE_RTL)
3159 *target = 0;
3160 if (max_size > 0)
3161 strncat(target, source, max_size - 1);
3162#endif // defined(BOOST_ASIO_HAS_SECURE_RTL)
3163}
3164
3165enum { gai_clone_flag = 1 << 30 };
3166
3167inline int gai_aistruct(addrinfo_type*** next, const addrinfo_type* hints,
3168 const void* addr, int family)
3169{
3170 using namespace std;
3171
3172 addrinfo_type* ai = gai_alloc<addrinfo_type>();
3173 if (ai == 0)
3174 return EAI_MEMORY-10;
3175
3176 ai->ai_next = 0;
3177 **next = ai;
3178 *next = &ai->ai_next;
3179
3180 ai->ai_canonname = 0;
3181 ai->ai_socktype = hints->ai_socktype;
3182 if (ai->ai_socktype == 0)
3183 ai->ai_flags |= gai_clone_flag;
3184 ai->ai_protocol = hints->ai_protocol;
3185 ai->ai_family = family;
3186
3187 switch (ai->ai_family)
3188 {
3189 case BOOST_ASIO_OS_DEF(AF_INET)2:
3190 {
3191 sockaddr_in4_type* sinptr = gai_alloc<sockaddr_in4_type>();
3192 if (sinptr == 0)
3193 return EAI_MEMORY-10;
3194 sinptr->sin_family = BOOST_ASIO_OS_DEF(AF_INET)2;
3195 memcpy(&sinptr->sin_addr, addr, sizeof(in4_addr_type));
3196 ai->ai_addr = reinterpret_cast<sockaddr*>(sinptr);
3197 ai->ai_addrlen = sizeof(sockaddr_in4_type);
3198 break;
3199 }
3200 case BOOST_ASIO_OS_DEF(AF_INET6)10:
3201 {
3202 sockaddr_in6_type* sin6ptr = gai_alloc<sockaddr_in6_type>();
3203 if (sin6ptr == 0)
3204 return EAI_MEMORY-10;
3205 sin6ptr->sin6_family = BOOST_ASIO_OS_DEF(AF_INET6)10;
3206 memcpy(&sin6ptr->sin6_addr, addr, sizeof(in6_addr_type));
3207 ai->ai_addr = reinterpret_cast<sockaddr*>(sin6ptr);
3208 ai->ai_addrlen = sizeof(sockaddr_in6_type);
3209 break;
3210 }
3211 default:
3212 break;
3213 }
3214
3215 return 0;
3216}
3217
3218inline addrinfo_type* gai_clone(addrinfo_type* ai)
3219{
3220 using namespace std;
3221
3222 addrinfo_type* new_ai = gai_alloc<addrinfo_type>();
3223 if (new_ai == 0)
3224 return new_ai;
3225
3226 new_ai->ai_next = ai->ai_next;
3227 ai->ai_next = new_ai;
3228
3229 new_ai->ai_flags = 0;
3230 new_ai->ai_family = ai->ai_family;
3231 new_ai->ai_socktype = ai->ai_socktype;
3232 new_ai->ai_protocol = ai->ai_protocol;
3233 new_ai->ai_canonname = 0;
3234 new_ai->ai_addrlen = ai->ai_addrlen;
3235 new_ai->ai_addr = gai_alloc<sockaddr>(ai->ai_addrlen);
3236 memcpy(new_ai->ai_addr, ai->ai_addr, ai->ai_addrlen);
3237
3238 return new_ai;
3239}
3240
3241inline int gai_port(addrinfo_type* aihead, int port, int socktype)
3242{
3243 int num_found = 0;
3244
3245 for (addrinfo_type* ai = aihead; ai; ai = ai->ai_next)
3246 {
3247 if (ai->ai_flags & gai_clone_flag)
3248 {
3249 if (ai->ai_socktype != 0)
3250 {
3251 ai = gai_clone(ai);
3252 if (ai == 0)
3253 return -1;
3254 // ai now points to newly cloned entry.
3255 }
3256 }
3257 else if (ai->ai_socktype != socktype)
3258 {
3259 // Ignore if mismatch on socket type.
3260 continue;
3261 }
3262
3263 ai->ai_socktype = socktype;
3264
3265 switch (ai->ai_family)
3266 {
3267 case BOOST_ASIO_OS_DEF(AF_INET)2:
3268 {
3269 sockaddr_in4_type* sinptr =
3270 reinterpret_cast<sockaddr_in4_type*>(ai->ai_addr);
3271 sinptr->sin_port = port;
3272 ++num_found;
3273 break;
3274 }
3275 case BOOST_ASIO_OS_DEF(AF_INET6)10:
3276 {
3277 sockaddr_in6_type* sin6ptr =
3278 reinterpret_cast<sockaddr_in6_type*>(ai->ai_addr);
3279 sin6ptr->sin6_port = port;
3280 ++num_found;
3281 break;
3282 }
3283 default:
3284 break;
3285 }
3286 }
3287
3288 return num_found;
3289}
3290
3291inline int gai_serv(addrinfo_type* aihead,
3292 const addrinfo_type* hints, const char* serv)
3293{
3294 using namespace std;
3295
3296 int num_found = 0;
3297
3298 if (
3299#if defined(AI_NUMERICSERV0x0400)
3300 (hints->ai_flags & AI_NUMERICSERV0x0400) ||
3301#endif
3302 isdigit(static_cast<unsigned char>(serv[0])))
3303 {
3304 int port = htons(atoi(serv))__bswap_16 (atoi(serv));
3305 if (hints->ai_socktype)
3306 {
3307 // Caller specifies socket type.
3308 int rc = gai_port(aihead, port, hints->ai_socktype);
3309 if (rc < 0)
3310 return EAI_MEMORY-10;
3311 num_found += rc;
3312 }
3313 else
3314 {
3315 // Caller does not specify socket type.
3316 int rc = gai_port(aihead, port, SOCK_STREAMSOCK_STREAM);
3317 if (rc < 0)
3318 return EAI_MEMORY-10;
3319 num_found += rc;
3320 rc = gai_port(aihead, port, SOCK_DGRAMSOCK_DGRAM);
3321 if (rc < 0)
3322 return EAI_MEMORY-10;
3323 num_found += rc;
3324 }
3325 }
3326 else
3327 {
3328 // Try service name with TCP first, then UDP.
3329 if (hints->ai_socktype == 0 || hints->ai_socktype == SOCK_STREAMSOCK_STREAM)
3330 {
3331 servent* sptr = getservbyname(serv, "tcp");
3332 if (sptr != 0)
3333 {
3334 int rc = gai_port(aihead, sptr->s_port, SOCK_STREAMSOCK_STREAM);
3335 if (rc < 0)
3336 return EAI_MEMORY-10;
3337 num_found += rc;
3338 }
3339 }
3340 if (hints->ai_socktype == 0 || hints->ai_socktype == SOCK_DGRAMSOCK_DGRAM)
3341 {
3342 servent* sptr = getservbyname(serv, "udp");
3343 if (sptr != 0)
3344 {
3345 int rc = gai_port(aihead, sptr->s_port, SOCK_DGRAMSOCK_DGRAM);
3346 if (rc < 0)
3347 return EAI_MEMORY-10;
3348 num_found += rc;
3349 }
3350 }
3351 }
3352
3353 if (num_found == 0)
3354 {
3355 if (hints->ai_socktype == 0)
3356 {
3357 // All calls to getservbyname() failed.
3358 return EAI_NONAME-2;
3359 }
3360 else
3361 {
3362 // Service not supported for socket type.
3363 return EAI_SERVICE-8;
3364 }
3365 }
3366
3367 return 0;
3368}
3369
3370inline int gai_echeck(const char* host, const char* service,
3371 int flags, int family, int socktype, int protocol)
3372{
3373 (void)(flags);
3374 (void)(protocol);
3375
3376 // Host or service must be specified.
3377 if (host == 0 || host[0] == '\0')
3378 if (service == 0 || service[0] == '\0')
3379 return EAI_NONAME-2;
3380
3381 // Check combination of family and socket type.
3382 switch (family)
3383 {
3384 case BOOST_ASIO_OS_DEF(AF_UNSPEC)0:
3385 break;
3386 case BOOST_ASIO_OS_DEF(AF_INET)2:
3387 case BOOST_ASIO_OS_DEF(AF_INET6)10:
3388 if (service != 0 && service[0] != '\0')
3389 if (socktype != 0 && socktype != SOCK_STREAMSOCK_STREAM && socktype != SOCK_DGRAMSOCK_DGRAM)
3390 return EAI_SOCKTYPE-7;
3391 break;
3392 default:
3393 return EAI_FAMILY-6;
3394 }
3395
3396 return 0;
3397}
3398
3399inline void freeaddrinfo_emulation(addrinfo_type* aihead)
3400{
3401 addrinfo_type* ai = aihead;
3402 while (ai)
3403 {
3404 gai_free(ai->ai_addr);
3405 gai_free(ai->ai_canonname);
3406 addrinfo_type* ainext = ai->ai_next;
3407 gai_free(ai);
3408 ai = ainext;
3409 }
3410}
3411
3412inline int getaddrinfo_emulation(const char* host, const char* service,
3413 const addrinfo_type* hintsp, addrinfo_type** result)
3414{
3415 // Set up linked list of addrinfo structures.
3416 addrinfo_type* aihead = 0;
3417 addrinfo_type** ainext = &aihead;
3418 char* canon = 0;
3419
3420 // Supply default hints if not specified by caller.
3421 addrinfo_type hints = addrinfo_type();
3422 hints.ai_family = BOOST_ASIO_OS_DEF(AF_UNSPEC)0;
3423 if (hintsp)
3424 hints = *hintsp;
3425
3426 // If the resolution is not specifically for AF_INET6, remove the AI_V4MAPPED
3427 // and AI_ALL flags.
3428#if defined(AI_V4MAPPED0x0008)
3429 if (hints.ai_family != BOOST_ASIO_OS_DEF(AF_INET6)10)
3430 hints.ai_flags &= ~AI_V4MAPPED0x0008;
3431#endif
3432#if defined(AI_ALL0x0010)
3433 if (hints.ai_family != BOOST_ASIO_OS_DEF(AF_INET6)10)
3434 hints.ai_flags &= ~AI_ALL0x0010;
3435#endif
3436
3437 // Basic error checking.
3438 int rc = gai_echeck(host, service, hints.ai_flags, hints.ai_family,
3439 hints.ai_socktype, hints.ai_protocol);
3440 if (rc != 0)
3441 {
3442 freeaddrinfo_emulation(aihead);
3443 return rc;
3444 }
3445
3446 gai_search search[2];
3447 int search_count = gai_nsearch(host, &hints, search);
3448 for (gai_search* sptr = search; sptr < search + search_count; ++sptr)
3449 {
3450 // Check for IPv4 dotted decimal string.
3451 in4_addr_type inaddr;
3452 boost::system::error_code ec;
3453 if (socket_ops::inet_pton(BOOST_ASIO_OS_DEF(AF_INET)2,
3454 sptr->host, &inaddr, 0, ec) == 1)
3455 {
3456 if (hints.ai_family != BOOST_ASIO_OS_DEF(AF_UNSPEC)0
3457 && hints.ai_family != BOOST_ASIO_OS_DEF(AF_INET)2)
3458 {
3459 freeaddrinfo_emulation(aihead);
3460 gai_free(canon);
3461 return EAI_FAMILY-6;
3462 }
3463 if (sptr->family == BOOST_ASIO_OS_DEF(AF_INET)2)
3464 {
3465 rc = gai_aistruct(&ainext, &hints, &inaddr, BOOST_ASIO_OS_DEF(AF_INET)2);
3466 if (rc != 0)
3467 {
3468 freeaddrinfo_emulation(aihead);
3469 gai_free(canon);
3470 return rc;
3471 }
3472 }
3473 continue;
3474 }
3475
3476 // Check for IPv6 hex string.
3477 in6_addr_type in6addr;
3478 if (socket_ops::inet_pton(BOOST_ASIO_OS_DEF(AF_INET6)10,
3479 sptr->host, &in6addr, 0, ec) == 1)
3480 {
3481 if (hints.ai_family != BOOST_ASIO_OS_DEF(AF_UNSPEC)0
3482 && hints.ai_family != BOOST_ASIO_OS_DEF(AF_INET6)10)
3483 {
3484 freeaddrinfo_emulation(aihead);
3485 gai_free(canon);
3486 return EAI_FAMILY-6;
3487 }
3488 if (sptr->family == BOOST_ASIO_OS_DEF(AF_INET6)10)
3489 {
3490 rc = gai_aistruct(&ainext, &hints, &in6addr,
3491 BOOST_ASIO_OS_DEF(AF_INET6)10);
3492 if (rc != 0)
3493 {
3494 freeaddrinfo_emulation(aihead);
3495 gai_free(canon);
3496 return rc;
3497 }
3498 }
3499 continue;
3500 }
3501
3502 // Look up hostname.
3503 hostent hent;
3504 char hbuf[8192] = "";
3505 hostent* hptr = socket_ops::gethostbyname(sptr->host,
3506 sptr->family, &hent, hbuf, sizeof(hbuf), hints.ai_flags, ec);
3507 if (hptr == 0)
3508 {
3509 if (search_count == 2)
3510 {
3511 // Failure is OK if there are multiple searches.
3512 continue;
3513 }
3514 freeaddrinfo_emulation(aihead);
3515 gai_free(canon);
3516 if (ec == boost::asio::error::host_not_found)
3517 return EAI_NONAME-2;
3518 if (ec == boost::asio::error::host_not_found_try_again)
3519 return EAI_AGAIN-3;
3520 if (ec == boost::asio::error::no_recovery)
3521 return EAI_FAIL-4;
3522 if (ec == boost::asio::error::no_data)
3523 return EAI_NONAME-2;
3524 return EAI_NONAME-2;
3525 }
3526
3527 // Check for address family mismatch if one was specified.
3528 if (hints.ai_family != BOOST_ASIO_OS_DEF(AF_UNSPEC)0
3529 && hints.ai_family != hptr->h_addrtype)
3530 {
3531 freeaddrinfo_emulation(aihead);
3532 gai_free(canon);
3533 socket_ops::freehostent(hptr);
3534 return EAI_FAMILY-6;
3535 }
3536
3537 // Save canonical name first time.
3538 if (host != 0 && host[0] != '\0' && hptr->h_name && hptr->h_name[0]
3539 && (hints.ai_flags & AI_CANONNAME0x0002) && canon == 0)
3540 {
3541 std::size_t canon_len = strlen(hptr->h_name) + 1;
3542 canon = gai_alloc<char>(canon_len);
3543 if (canon == 0)
3544 {
3545 freeaddrinfo_emulation(aihead);
3546 socket_ops::freehostent(hptr);
3547 return EAI_MEMORY-10;
3548 }
3549 gai_strcpy(canon, hptr->h_name, canon_len);
3550 }
3551
3552 // Create an addrinfo structure for each returned address.
3553 for (char** ap = hptr->h_addr_list; *ap; ++ap)
3554 {
3555 rc = gai_aistruct(&ainext, &hints, *ap, hptr->h_addrtype);
3556 if (rc != 0)
3557 {
3558 freeaddrinfo_emulation(aihead);
3559 gai_free(canon);
3560 socket_ops::freehostent(hptr);
3561 return EAI_FAMILY-6;
3562 }
3563 }
3564
3565 socket_ops::freehostent(hptr);
3566 }
3567
3568 // Check if we found anything.
3569 if (aihead == 0)
3570 {
3571 gai_free(canon);
3572 return EAI_NONAME-2;
3573 }
3574
3575 // Return canonical name in first entry.
3576 if (host != 0 && host[0] != '\0' && (hints.ai_flags & AI_CANONNAME0x0002))
3577 {
3578 if (canon)
3579 {
3580 aihead->ai_canonname = canon;
3581 canon = 0;
3582 }
3583 else
3584 {
3585 std::size_t canonname_len = strlen(search[0].host) + 1;
3586 aihead->ai_canonname = gai_alloc<char>(canonname_len);
3587 if (aihead->ai_canonname == 0)
3588 {
3589 freeaddrinfo_emulation(aihead);
3590 return EAI_MEMORY-10;
3591 }
3592 gai_strcpy(aihead->ai_canonname, search[0].host, canonname_len);
3593 }
3594 }
3595 gai_free(canon);
3596
3597 // Process the service name.
3598 if (service != 0 && service[0] != '\0')
3599 {
3600 rc = gai_serv(aihead, &hints, service);
3601 if (rc != 0)
3602 {
3603 freeaddrinfo_emulation(aihead);
3604 return rc;
3605 }
3606 }
3607
3608 // Return result to caller.
3609 *result = aihead;
3610 return 0;
3611}
3612
3613inline boost::system::error_code getnameinfo_emulation(
3614 const socket_addr_type* sa, std::size_t salen, char* host,
3615 std::size_t hostlen, char* serv, std::size_t servlen, int flags,
3616 boost::system::error_code& ec)
3617{
3618 using namespace std;
3619
3620 const char* addr;
3621 size_t addr_len;
3622 unsigned short port;
3623 switch (sa->sa_family)
3624 {
3625 case BOOST_ASIO_OS_DEF(AF_INET)2:
3626 if (salen != sizeof(sockaddr_in4_type))
3627 {
3628 return ec = boost::asio::error::invalid_argument;
3629 }
3630 addr = reinterpret_cast<const char*>(
3631 &reinterpret_cast<const sockaddr_in4_type*>(sa)->sin_addr);
3632 addr_len = sizeof(in4_addr_type);
3633 port = reinterpret_cast<const sockaddr_in4_type*>(sa)->sin_port;
3634 break;
3635 case BOOST_ASIO_OS_DEF(AF_INET6)10:
3636 if (salen != sizeof(sockaddr_in6_type))
3637 {
3638 return ec = boost::asio::error::invalid_argument;
3639 }
3640 addr = reinterpret_cast<const char*>(
3641 &reinterpret_cast<const sockaddr_in6_type*>(sa)->sin6_addr);
3642 addr_len = sizeof(in6_addr_type);
3643 port = reinterpret_cast<const sockaddr_in6_type*>(sa)->sin6_port;
3644 break;
3645 default:
3646 return ec = boost::asio::error::address_family_not_supported;
3647 }
3648
3649 if (host && hostlen > 0)
3650 {
3651 if (flags & NI_NUMERICHOST1)
3652 {
3653 if (socket_ops::inet_ntop(sa->sa_family, addr, host, hostlen, 0, ec) == 0)
3654 {
3655 return ec;
3656 }
3657 }
3658 else
3659 {
3660 hostent hent;
3661 char hbuf[8192] = "";
3662 hostent* hptr = socket_ops::gethostbyaddr(addr,
3663 static_cast<int>(addr_len), sa->sa_family,
3664 &hent, hbuf, sizeof(hbuf), ec);
3665 if (hptr && hptr->h_name && hptr->h_name[0] != '\0')
3666 {
3667 if (flags & NI_NOFQDN4)
3668 {
3669 char* dot = strchr(hptr->h_name, '.');
3670 if (dot)
3671 {
3672 *dot = 0;
3673 }
3674 }
3675 gai_strcpy(host, hptr->h_name, hostlen);
3676 socket_ops::freehostent(hptr);
3677 }
3678 else
3679 {
3680 socket_ops::freehostent(hptr);
3681 if (flags & NI_NAMEREQD8)
3682 {
3683 return ec = boost::asio::error::host_not_found;
3684 }
3685 if (socket_ops::inet_ntop(sa->sa_family,
3686 addr, host, hostlen, 0, ec) == 0)
3687 {
3688 return ec;
3689 }
3690 }
3691 }
3692 }
3693
3694 if (serv && servlen > 0)
3695 {
3696 if (flags & NI_NUMERICSERV2)
3697 {
3698 if (servlen < 6)
3699 {
3700 return ec = boost::asio::error::no_buffer_space;
3701 }
3702#if defined(BOOST_ASIO_HAS_SNPRINTF)
3703 snprintf(serv, servlen, "%u", ntohs(port)__bswap_16 (port));
3704#elif defined(BOOST_ASIO_HAS_SECURE_RTL)
3705 sprintf_s(serv, servlen, "%u", ntohs(port)__bswap_16 (port));
3706#else // defined(BOOST_ASIO_HAS_SECURE_RTL)
3707 sprintf(serv, "%u", ntohs(port)__bswap_16 (port));
3708#endif // defined(BOOST_ASIO_HAS_SECURE_RTL)
3709 }
3710 else
3711 {
3712#if defined(BOOST_ASIO_HAS_PTHREADS1)
3713 static ::pthread_mutex_t mutex = PTHREAD_MUTEX_INITIALIZER{ { 0, 0, 0, 0, PTHREAD_MUTEX_TIMED_NP, 0, 0, { __null, __null
} } }
;
3714 ::pthread_mutex_lock(&mutex);
3715#endif // defined(BOOST_ASIO_HAS_PTHREADS)
3716 servent* sptr = ::getservbyport(port, (flags & NI_DGRAM16) ? "udp" : 0);
3717 if (sptr && sptr->s_name && sptr->s_name[0] != '\0')
3718 {
3719 gai_strcpy(serv, sptr->s_name, servlen);
3720 }
3721 else
3722 {
3723 if (servlen < 6)
3724 {
3725 return ec = boost::asio::error::no_buffer_space;
3726 }
3727#if defined(BOOST_ASIO_HAS_SNPRINTF)
3728 snprintf(serv, servlen, "%u", ntohs(port)__bswap_16 (port));
3729#elif defined(BOOST_ASIO_HAS_SECURE_RTL)
3730 sprintf_s(serv, servlen, "%u", ntohs(port)__bswap_16 (port));
3731#else // defined(BOOST_ASIO_HAS_SECURE_RTL)
3732 sprintf(serv, "%u", ntohs(port)__bswap_16 (port));
3733#endif // defined(BOOST_ASIO_HAS_SECURE_RTL)
3734 }
3735#if defined(BOOST_ASIO_HAS_PTHREADS1)
3736 ::pthread_mutex_unlock(&mutex);
3737#endif // defined(BOOST_ASIO_HAS_PTHREADS)
3738 }
3739 }
3740
3741 boost::asio::error::clear(ec);
3742 return ec;
3743}
3744
3745#endif // !defined(BOOST_ASIO_HAS_GETADDRINFO)
3746
3747inline boost::system::error_code translate_addrinfo_error(int error)
3748{
3749 switch (error)
3750 {
3751 case 0:
3752 return boost::system::error_code();
3753 case EAI_AGAIN-3:
3754 return boost::asio::error::host_not_found_try_again;
3755 case EAI_BADFLAGS-1:
3756 return boost::asio::error::invalid_argument;
3757 case EAI_FAIL-4:
3758 return boost::asio::error::no_recovery;
3759 case EAI_FAMILY-6:
3760 return boost::asio::error::address_family_not_supported;
3761 case EAI_MEMORY-10:
3762 return boost::asio::error::no_memory;
3763 case EAI_NONAME-2:
3764#if defined(EAI_ADDRFAMILY-9)
3765 case EAI_ADDRFAMILY-9:
3766#endif
3767#if defined(EAI_NODATA-5) && (EAI_NODATA-5 != EAI_NONAME-2)
3768 case EAI_NODATA-5:
3769#endif
3770 return boost::asio::error::host_not_found;
3771 case EAI_SERVICE-8:
3772 return boost::asio::error::service_not_found;
3773 case EAI_SOCKTYPE-7:
3774 return boost::asio::error::socket_type_not_supported;
3775 default: // Possibly the non-portable EAI_SYSTEM.
3776#if defined(BOOST_ASIO_WINDOWS) || defined(__CYGWIN__)
3777 return boost::system::error_code(
3778 WSAGetLastError(), boost::asio::error::get_system_category());
3779#else
3780 return boost::system::error_code(
3781 errno(*__errno_location ()), boost::asio::error::get_system_category());
3782#endif
3783 }
3784}
3785
3786boost::system::error_code getaddrinfo(const char* host,
3787 const char* service, const addrinfo_type& hints,
3788 addrinfo_type** result, boost::system::error_code& ec)
3789{
3790 host = (host && *host) ? host : 0;
3791 service = (service && *service) ? service : 0;
3792 clear_last_error();
3793#if defined(BOOST_ASIO_WINDOWS) || defined(__CYGWIN__)
3794# if defined(BOOST_ASIO_HAS_GETADDRINFO1)
3795 // Building for Windows XP, Windows Server 2003, or later.
3796 int error = ::getaddrinfo(host, service, &hints, result);
3797 return ec = translate_addrinfo_error(error);
3798# else
3799 // Building for Windows 2000 or earlier.
3800 typedef int (WSAAPI *gai_t)(const char*,
3801 const char*, const addrinfo_type*, addrinfo_type**);
3802 if (HMODULE winsock_module = ::GetModuleHandleA("ws2_32"))
3803 {
3804 if (gai_t gai = (gai_t)::GetProcAddress(winsock_module, "getaddrinfo"))
3805 {
3806 int error = gai(host, service, &hints, result);
3807 return ec = translate_addrinfo_error(error);
3808 }
3809 }
3810 int error = getaddrinfo_emulation(host, service, &hints, result);
3811 return ec = translate_addrinfo_error(error);
3812# endif
3813#elif !defined(BOOST_ASIO_HAS_GETADDRINFO1)
3814 int error = getaddrinfo_emulation(host, service, &hints, result);
3815 return ec = translate_addrinfo_error(error);
3816#else
3817 int error = ::getaddrinfo(host, service, &hints, result);
3818#if defined(__MACH__) && defined(__APPLE__)
3819 using namespace std; // For isdigit and atoi.
3820 if (error == 0 && service && isdigit(static_cast<unsigned char>(service[0])))
3821 {
3822 u_short_type port = host_to_network_short(atoi(service));
3823 for (addrinfo_type* ai = *result; ai; ai = ai->ai_next)
3824 {
3825 switch (ai->ai_family)
3826 {
3827 case BOOST_ASIO_OS_DEF(AF_INET)2:
3828 {
3829 sockaddr_in4_type* sinptr =
3830 reinterpret_cast<sockaddr_in4_type*>(ai->ai_addr);
3831 if (sinptr->sin_port == 0)
3832 sinptr->sin_port = port;
3833 break;
3834 }
3835 case BOOST_ASIO_OS_DEF(AF_INET6)10:
3836 {
3837 sockaddr_in6_type* sin6ptr =
3838 reinterpret_cast<sockaddr_in6_type*>(ai->ai_addr);
3839 if (sin6ptr->sin6_port == 0)
3840 sin6ptr->sin6_port = port;
3841 break;
3842 }
3843 default:
3844 break;
3845 }
3846 }
3847 }
3848#endif
3849 return ec = translate_addrinfo_error(error);
3850#endif
3851}
3852
3853boost::system::error_code background_getaddrinfo(
3854 const weak_cancel_token_type& cancel_token, const char* host,
3855 const char* service, const addrinfo_type& hints,
3856 addrinfo_type** result, boost::system::error_code& ec)
3857{
3858 if (cancel_token.expired())
3859 ec = boost::asio::error::operation_aborted;
3860 else
3861 socket_ops::getaddrinfo(host, service, hints, result, ec);
3862 return ec;
3863}
3864
3865void freeaddrinfo(addrinfo_type* ai)
3866{
3867#if defined(BOOST_ASIO_WINDOWS) || defined(__CYGWIN__)
3868# if defined(BOOST_ASIO_HAS_GETADDRINFO1)
3869 // Building for Windows XP, Windows Server 2003, or later.
3870 ::freeaddrinfo(ai);
3871# else
3872 // Building for Windows 2000 or earlier.
3873 typedef int (WSAAPI *fai_t)(addrinfo_type*);
3874 if (HMODULE winsock_module = ::GetModuleHandleA("ws2_32"))
3875 {
3876 if (fai_t fai = (fai_t)::GetProcAddress(winsock_module, "freeaddrinfo"))
3877 {
3878 fai(ai);
3879 return;
3880 }
3881 }
3882 freeaddrinfo_emulation(ai);
3883# endif
3884#elif !defined(BOOST_ASIO_HAS_GETADDRINFO1)
3885 freeaddrinfo_emulation(ai);
3886#else
3887 ::freeaddrinfo(ai);
3888#endif
3889}
3890
3891boost::system::error_code getnameinfo(const void* addr,
3892 std::size_t addrlen, char* host, std::size_t hostlen,
3893 char* serv, std::size_t servlen, int flags, boost::system::error_code& ec)
3894{
3895#if defined(BOOST_ASIO_WINDOWS) || defined(__CYGWIN__)
3896# if defined(BOOST_ASIO_HAS_GETADDRINFO1)
3897 // Building for Windows XP, Windows Server 2003, or later.
3898 clear_last_error();
3899 int error = ::getnameinfo(static_cast<const socket_addr_type*>(addr),
3900 static_cast<socklen_t>(addrlen), host, static_cast<DWORD>(hostlen),
3901 serv, static_cast<DWORD>(servlen), flags);
3902 return ec = translate_addrinfo_error(error);
3903# else
3904 // Building for Windows 2000 or earlier.
3905 typedef int (WSAAPI *gni_t)(const socket_addr_type*,
3906 int, char*, DWORD, char*, DWORD, int);
3907 if (HMODULE winsock_module = ::GetModuleHandleA("ws2_32"))
3908 {
3909 if (gni_t gni = (gni_t)::GetProcAddress(winsock_module, "getnameinfo"))
3910 {
3911 clear_last_error();
3912 int error = gni(static_cast<const socket_addr_type*>(addr),
3913 static_cast<int>(addrlen), host, static_cast<DWORD>(hostlen),
3914 serv, static_cast<DWORD>(servlen), flags);
3915 return ec = translate_addrinfo_error(error);
3916 }
3917 }
3918 clear_last_error();
3919 return getnameinfo_emulation(static_cast<const socket_addr_type*>(addr),
3920 addrlen, host, hostlen, serv, servlen, flags, ec);
3921# endif
3922#elif !defined(BOOST_ASIO_HAS_GETADDRINFO1)
3923 using namespace std; // For memcpy.
3924 sockaddr_storage_type tmp_addr;
3925 memcpy(&tmp_addr, addr, addrlen);
3926 addr = &tmp_addr;
3927 clear_last_error();
3928 return getnameinfo_emulation(static_cast<const socket_addr_type*>(addr),
3929 addrlen, host, hostlen, serv, servlen, flags, ec);
3930#else
3931 clear_last_error();
3932 int error = ::getnameinfo(static_cast<const socket_addr_type*>(addr),
3933 addrlen, host, hostlen, serv, servlen, flags);
3934 return ec = translate_addrinfo_error(error);
3935#endif
3936}
3937
3938boost::system::error_code sync_getnameinfo(const void* addr,
3939 std::size_t addrlen, char* host, std::size_t hostlen, char* serv,
3940 std::size_t servlen, int sock_type, boost::system::error_code& ec)
3941{
3942 // First try resolving with the service name. If that fails try resolving
3943 // but allow the service to be returned as a number.
3944 int flags = (sock_type == SOCK_DGRAMSOCK_DGRAM) ? NI_DGRAM16 : 0;
3945 socket_ops::getnameinfo(addr, addrlen, host,
3946 hostlen, serv, servlen, flags, ec);
3947 if (ec)
3948 {
3949 socket_ops::getnameinfo(addr, addrlen, host, hostlen,
3950 serv, servlen, flags | NI_NUMERICSERV2, ec);
3951 }
3952
3953 return ec;
3954}
3955
3956boost::system::error_code background_getnameinfo(
3957 const weak_cancel_token_type& cancel_token,
3958 const void* addr, std::size_t addrlen,
3959 char* host, std::size_t hostlen, char* serv,
3960 std::size_t servlen, int sock_type, boost::system::error_code& ec)
3961{
3962 if (cancel_token.expired())
3963 {
3964 ec = boost::asio::error::operation_aborted;
3965 }
3966 else
3967 {
3968 // First try resolving with the service name. If that fails try resolving
3969 // but allow the service to be returned as a number.
3970 int flags = (sock_type == SOCK_DGRAMSOCK_DGRAM) ? NI_DGRAM16 : 0;
3971 socket_ops::getnameinfo(addr, addrlen, host,
3972 hostlen, serv, servlen, flags, ec);
3973 if (ec)
3974 {
3975 socket_ops::getnameinfo(addr, addrlen, host, hostlen,
3976 serv, servlen, flags | NI_NUMERICSERV2, ec);
3977 }
3978 }
3979
3980 return ec;
3981}
3982
3983#endif // !defined(BOOST_ASIO_WINDOWS_RUNTIME)
3984
3985u_long_type network_to_host_long(u_long_type value)
3986{
3987#if defined(BOOST_ASIO_WINDOWS_RUNTIME)
3988 unsigned char* value_p = reinterpret_cast<unsigned char*>(&value);
3989 u_long_type result = (static_cast<u_long_type>(value_p[0]) << 24)
3990 | (static_cast<u_long_type>(value_p[1]) << 16)
3991 | (static_cast<u_long_type>(value_p[2]) << 8)
3992 | static_cast<u_long_type>(value_p[3]);
3993 return result;
3994#else // defined(BOOST_ASIO_WINDOWS_RUNTIME)
3995 return ntohl(value)__bswap_32 (value);
3996#endif // defined(BOOST_ASIO_WINDOWS_RUNTIME)
3997}
3998
3999u_long_type host_to_network_long(u_long_type value)
4000{
4001#if defined(BOOST_ASIO_WINDOWS_RUNTIME)
4002 u_long_type result;
4003 unsigned char* result_p = reinterpret_cast<unsigned char*>(&result);
4004 result_p[0] = static_cast<unsigned char>((value >> 24) & 0xFF);
4005 result_p[1] = static_cast<unsigned char>((value >> 16) & 0xFF);
4006 result_p[2] = static_cast<unsigned char>((value >> 8) & 0xFF);
4007 result_p[3] = static_cast<unsigned char>(value & 0xFF);
4008 return result;
4009#else // defined(BOOST_ASIO_WINDOWS_RUNTIME)
4010 return htonl(value)__bswap_32 (value);
4011#endif // defined(BOOST_ASIO_WINDOWS_RUNTIME)
4012}
4013
4014u_short_type network_to_host_short(u_short_type value)
4015{
4016#if defined(BOOST_ASIO_WINDOWS_RUNTIME)
4017 unsigned char* value_p = reinterpret_cast<unsigned char*>(&value);
4018 u_short_type result = (static_cast<u_short_type>(value_p[0]) << 8)
4019 | static_cast<u_short_type>(value_p[1]);
4020 return result;
4021#else // defined(BOOST_ASIO_WINDOWS_RUNTIME)
4022 return ntohs(value)__bswap_16 (value);
4023#endif // defined(BOOST_ASIO_WINDOWS_RUNTIME)
4024}
4025
4026u_short_type host_to_network_short(u_short_type value)
4027{
4028#if defined(BOOST_ASIO_WINDOWS_RUNTIME)
4029 u_short_type result;
4030 unsigned char* result_p = reinterpret_cast<unsigned char*>(&result);
4031 result_p[0] = static_cast<unsigned char>((value >> 8) & 0xFF);
4032 result_p[1] = static_cast<unsigned char>(value & 0xFF);
4033 return result;
4034#else // defined(BOOST_ASIO_WINDOWS_RUNTIME)
4035 return htons(value)__bswap_16 (value);
4036#endif // defined(BOOST_ASIO_WINDOWS_RUNTIME)
4037}
4038
4039} // namespace socket_ops
4040} // namespace detail
4041} // namespace asio
4042} // namespace boost
4043
4044#include <boost/asio/detail/pop_options.hpp>
4045
4046#endif // BOOST_ASIO_DETAIL_SOCKET_OPS_IPP