Bug Summary

File:usr/include/boost/asio/detail/impl/socket_ops.ipp
Warning:line 811, 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 -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 -fhalf-no-semantic-interposition -mframe-pointer=all -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/src/lib/tcp/tests -fcoverage-compilation-dir=/home/fedora/workspace/kea-dev/clang-static-analyzer/src/lib/tcp/tests -resource-dir /usr/bin/../lib/clang/19 -D HAVE_CONFIG_H -I . -I ../../../.. -I ../../../../src/lib -I ../../../../src/lib -D TEST_CA_DIR="/home/fedora/workspace/kea-dev/clang-static-analyzer/src/lib/tcp/tests/../../asiolink/testutils/ca" -I /usr/src/googletest/googletest -I /usr/src/googletest/googletest/include -D OS_LINUX -I ../../../.. -I ../../../.. -internal-isystem /usr/bin/../lib/gcc/x86_64-redhat-linux/14/../../../../include/c++/14 -internal-isystem /usr/bin/../lib/gcc/x86_64-redhat-linux/14/../../../../include/c++/14/x86_64-redhat-linux -internal-isystem /usr/bin/../lib/gcc/x86_64-redhat-linux/14/../../../../include/c++/14/backward -internal-isystem /usr/bin/../lib/clang/19/include -internal-isystem /usr/local/include -internal-isystem /usr/bin/../lib/gcc/x86_64-redhat-linux/14/../../../../x86_64-redhat-linux/include -internal-externc-isystem /include -internal-externc-isystem /usr/include -O0 -Wwrite-strings -Wno-sign-compare -Wno-missing-field-initializers -Wno-unused-parameter -Wno-unused-private-field -std=c++20 -fdeprecated-macro -ferror-limit 19 -stack-protector 2 -fgnuc-version=4.2.1 -fno-implicit-modules -fskip-odr-check-in-gmf -fcxx-exceptions -fexceptions -analyzer-output=html -faddrsig -D__GCC_HAVE_DWARF2_CFI_ASM=1 -o /home/fedora/workspace/kea-dev/clang-static-analyzer/report/2024-12-20-083036-19082-1 -x c++ mt_tcp_listener_mgr_unittests.cc

mt_tcp_listener_mgr_unittests.cc

1// Copyright (C) 2022-2024 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, "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
, "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, "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
, "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, "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
, "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, "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
, "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, "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
, "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, "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("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("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_,
1
Calling constructor for 'TcpTestClient'
53
Returning from constructor for 'TcpTestClient'
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);
54
Calling 'TcpTestClient::startRequest'
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_,
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, "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
, "mt_tcp_listener_mgr_unittests.cc", 200, "Failed") = ::testing
::Message() << "client->startRequest(request_body.str())"
<< " threw non-std::exception"; } }
;
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, "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_service.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, "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, "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, "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, "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, "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, "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, "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, "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
, "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, "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
, "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, "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, "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, "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
, "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, "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, "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
, "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, "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(), 0)switch (0) case 0: default: if (const ::testing::AssertionResult
gtest_ar = (::testing::internal::EqHelper::Compare("mt_listener_mgr_->getThreadCount()"
, "0", mt_listener_mgr_->getThreadCount(), 0))) ; else ::testing
::internal::AssertHelper(::testing::TestPartResult::kNonFatalFailure
, "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, "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(), 1)switch (0) case 0: default: if (const ::testing::AssertionResult
gtest_ar = (::testing::internal::EqHelper::Compare("responses.size()"
, "1", responses.size(), 1))) ; else return ::testing::internal
::AssertHelper(::testing::TestPartResult::kFatalFailure, "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, "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
, "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, "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, "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, "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, "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, "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, "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, "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, "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, "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, "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, "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
, "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, "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, num_clients / clients_per_thread.size())switch (0) case 0: default: if (const ::testing::AssertionResult
gtest_ar = (::testing::internal::EqHelper::Compare("it.second"
, "num_clients / clients_per_thread.size()", it.second, num_clients
/ clients_per_thread.size()))) ; else ::testing::internal::AssertHelper
(::testing::TestPartResult::kNonFatalFailure, "mt_tcp_listener_mgr_unittests.cc"
, 533, gtest_ar.failure_message()) = ::testing::Message()
534 << "thread-id: " << it.first
535 << ", clients: " << it.second << std::endl;
536 }
537 }
538
539 /// @brief Pauses and resumes a MtTcpListener while it processes command
540 /// requests.
541 ///
542 /// This function command will create a MtTcpListenerMgr
543 /// with the given number of threads, initiates the given
544 /// number of clients, each requesting the "thread" command,
545 /// and then iteratively runs the test's IOService until all
546 /// the clients have received their responses or an error occurs.
547 /// It will pause and resume the listener at intervals governed
548 /// by the given number of pauses.
549 ///
550 /// @param num_threads - the number of threads the MtTcpListener
551 /// should use. Must be greater than 0.
552 /// @param num_clients - the number of clients that should issue the
553 /// thread command. Each client is used to carry out a single thread
554 /// command request. Must be greater than 0.
555 /// @param num_pauses Desired number of times the listener should be
556 /// paused during the test. Must be greater than 0.
557 void workPauseAndResume(size_t num_threads, size_t num_clients,
558 size_t num_pauses) {
559 // First we makes sure the parameter rules apply.
560 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, "mt_tcp_listener_mgr_unittests.cc", 560, ::testing
::internal::GetBoolAssertionFailureMessage( gtest_ar_, "num_threads"
, "false", "true") .c_str()) = ::testing::Message()
;
561 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, "mt_tcp_listener_mgr_unittests.cc", 561, ::testing
::internal::GetBoolAssertionFailureMessage( gtest_ar_, "num_clients"
, "false", "true") .c_str()) = ::testing::Message()
;
562 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, "mt_tcp_listener_mgr_unittests.cc", 562, ::testing
::internal::GetBoolAssertionFailureMessage( gtest_ar_, "num_pauses"
, "false", "true") .c_str()) = ::testing::Message()
;
563 num_threads_ = num_threads;
564 num_clients_ = num_clients;
565
566 // Create an MtTcpListenerMgr with prescribed number of threads and the
567 // simple handler.
568 createMtTcpListenerMgr(num_threads,
569 std::bind(&MtTcpListenerMgrTest::simpleCommandHandler,
570 this, ph::_1));
571
572 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, "mt_tcp_listener_mgr_unittests.cc", 572, ::testing
::internal::GetBoolAssertionFailureMessage( gtest_ar_, "mt_listener_mgr_"
, "false", "true") .c_str()) = ::testing::Message()
;
573
574 // Start it and verify it is running.
575 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, "mt_tcp_listener_mgr_unittests.cc"
, 575, "Failed") = ::testing::Message() << "mt_listener_mgr_->start()"
<< " threw type: " << typeid(ex).name() <<
", what: " << ex.what(); } catch (...) { return ::testing
::internal::AssertHelper(::testing::TestPartResult::kFatalFailure
, "mt_tcp_listener_mgr_unittests.cc", 575, "Failed") = ::testing
::Message() << "mt_listener_mgr_->start()" << " threw non-std::exception"
; } }
;
576 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, "mt_tcp_listener_mgr_unittests.cc"
, 576, ::testing::internal::GetBoolAssertionFailureMessage( gtest_ar_
, "mt_listener_mgr_->isRunning()", "false", "true") .c_str
()) = ::testing::Message()
;
577 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, "mt_tcp_listener_mgr_unittests.cc", 577, gtest_ar
.failure_message()) = ::testing::Message()
;
578
579 // Initiate the prescribed number of command requests.
580 num_in_progress_ = 0;
581 while (clients_.size() < num_clients) {
582 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, "mt_tcp_listener_mgr_unittests.cc"
, 582, "Failed") = ::testing::Message() << "startThreadCommand(\"I am done\")"
<< " threw type: " << typeid(ex).name() <<
", what: " << ex.what(); } catch (...) { return ::testing
::internal::AssertHelper(::testing::TestPartResult::kFatalFailure
, "mt_tcp_listener_mgr_unittests.cc", 582, "Failed") = ::testing
::Message() << "startThreadCommand(\"I am done\")" <<
" threw non-std::exception"; } }
;
583 }
584
585 // Now we run the client-side IOService until all requests are done,
586 // errors occur or the test times out. We'll pause and resume the
587 // number of times given by num_pauses.
588 size_t num_done = 0;
589 size_t total_requests = clients_.size();
590 while (num_done < total_requests) {
591 // Calculate how many more requests to process before we pause again.
592 // We divide the number of outstanding requests by the number of pauses
593 // and stop after we've done at least that many more requests.
594 size_t request_limit = (pause_cnt_ < num_pauses ?
595 (num_done + ((total_requests - num_done) / num_pauses))
596 : total_requests);
597
598 // Run test IOService until we hit the limit.
599 runIOService(request_limit);
600
601 // If we've done all our pauses we should be through.
602 if (pause_cnt_ == num_pauses) {
603 break;
604 }
605
606 // Pause the client.
607 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_607
; } catch (...) { gtest_msg.value = "it throws."; goto gtest_label_testnothrow_607
; } } else gtest_label_testnothrow_607 : return ::testing::internal
::AssertHelper(::testing::TestPartResult::kFatalFailure, "mt_tcp_listener_mgr_unittests.cc"
, 607, ("Expected: " "mt_listener_mgr_->pause()" " doesn't throw an exception.\n"
" Actual: " + gtest_msg.value) .c_str()) = ::testing::Message
()
;
608 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, "mt_tcp_listener_mgr_unittests.cc"
, 608, ::testing::internal::GetBoolAssertionFailureMessage( gtest_ar_
, "mt_listener_mgr_->isPaused()", "false", "true") .c_str(
)) = ::testing::Message()
;
609 ++pause_cnt_;
610
611 // Check our progress.
612 num_done = 0;
613 for (auto const& client : clients_) {
614 if (client->receiveDone()) {
615 ++num_done;
616 }
617 }
618
619 // We should completed at least as many as our
620 // target limit.
621 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, "mt_tcp_listener_mgr_unittests.cc"
, 621, gtest_ar.failure_message()) = ::testing::Message()
;
622
623 // Resume the listener.
624 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_624
; } catch (...) { gtest_msg.value = "it throws."; goto gtest_label_testnothrow_624
; } } else gtest_label_testnothrow_624 : return ::testing::internal
::AssertHelper(::testing::TestPartResult::kFatalFailure, "mt_tcp_listener_mgr_unittests.cc"
, 624, ("Expected: " "mt_listener_mgr_->resume()" " doesn't throw an exception.\n"
" Actual: " + gtest_msg.value) .c_str()) = ::testing::Message
()
;
625 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, "mt_tcp_listener_mgr_unittests.cc"
, 625, ::testing::internal::GetBoolAssertionFailureMessage( gtest_ar_
, "mt_listener_mgr_->isRunning()", "false", "true") .c_str
()) = ::testing::Message()
;
626 }
627
628 // Stop the listener and then verify it has stopped.
629 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, "mt_tcp_listener_mgr_unittests.cc"
, 629, "Failed") = ::testing::Message() << "mt_listener_mgr_->stop()"
<< " threw type: " << typeid(ex).name() <<
", what: " << ex.what(); } catch (...) { return ::testing
::internal::AssertHelper(::testing::TestPartResult::kFatalFailure
, "mt_tcp_listener_mgr_unittests.cc", 629, "Failed") = ::testing
::Message() << "mt_listener_mgr_->stop()" << " threw non-std::exception"
; } }
;
630 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, "mt_tcp_listener_mgr_unittests.cc"
, 630, ::testing::internal::GetBoolAssertionFailureMessage( gtest_ar_
, "mt_listener_mgr_->isStopped()", "false", "true") .c_str
()) = ::testing::Message()
;
631 EXPECT_EQ(mt_listener_mgr_->getThreadCount(), 0)switch (0) case 0: default: if (const ::testing::AssertionResult
gtest_ar = (::testing::internal::EqHelper::Compare("mt_listener_mgr_->getThreadCount()"
, "0", mt_listener_mgr_->getThreadCount(), 0))) ; else ::testing
::internal::AssertHelper(::testing::TestPartResult::kNonFatalFailure
, "mt_tcp_listener_mgr_unittests.cc", 631, gtest_ar.failure_message
()) = ::testing::Message()
;
632
633 // Iterate over the clients, checking their outcomes.
634 size_t total_responses = 0;
635 for (auto const& client : clients_) {
636 // Client should have completed its receive successfully.
637 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, "mt_tcp_listener_mgr_unittests.cc"
, 637, ::testing::internal::GetBoolAssertionFailureMessage( gtest_ar_
, "client->receiveDone()", "false", "true") .c_str()) = ::
testing::Message()
;
638
639 // Now we walk the element tree to get the response data. It should look
640 // this:
641 //
642 // {
643 // "arguments": { "client-ptr": "xxxxx",
644 // "sign-off": "good bye",
645 // "thread-id": "zzzzz" },
646 // "result": 0
647 // }
648 //
649 // We expect one response.
650 auto responses = client->getResponses();
651 ASSERT_EQ(responses.size(), 1)switch (0) case 0: default: if (const ::testing::AssertionResult
gtest_ar = (::testing::internal::EqHelper::Compare("responses.size()"
, "1", responses.size(), 1))) ; else return ::testing::internal
::AssertHelper(::testing::TestPartResult::kFatalFailure, "mt_tcp_listener_mgr_unittests.cc"
, 651, gtest_ar.failure_message()) = ::testing::Message()
;
652
653 // First we turn it into an Element tree.
654 ConstElementPtr answer;
655 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, "mt_tcp_listener_mgr_unittests.cc"
, 655, "Failed") = ::testing::Message() << "answer = Element::fromJSON(responses.front())"
<< " threw type: " << typeid(ex).name() <<
", what: " << ex.what(); } catch (...) { return ::testing
::internal::AssertHelper(::testing::TestPartResult::kFatalFailure
, "mt_tcp_listener_mgr_unittests.cc", 655, "Failed") = ::testing
::Message() << "answer = Element::fromJSON(responses.front())"
<< " threw non-std::exception"; } }
;
656
657 // Answer should be a map containing "arguments" and "results".
658 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, "mt_tcp_listener_mgr_unittests.cc", 658, gtest_ar
.failure_message()) = ::testing::Message()
;
659
660 // "result" should be 0.
661 ConstElementPtr result = answer->get("result");
662 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, "mt_tcp_listener_mgr_unittests.cc", 662, ::testing
::internal::GetBoolAssertionFailureMessage( gtest_ar_, "result"
, "false", "true") .c_str()) = ::testing::Message()
;
663 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, "mt_tcp_listener_mgr_unittests.cc"
, 663, gtest_ar.failure_message()) = ::testing::Message()
;
664 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, "mt_tcp_listener_mgr_unittests.cc"
, 664, gtest_ar.failure_message()) = ::testing::Message()
;
665
666 // "arguments" is a map containing "client-ptr" and "thread-id".
667 ConstElementPtr arguments = answer->get("arguments");
668 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, "mt_tcp_listener_mgr_unittests.cc", 668, ::testing
::internal::GetBoolAssertionFailureMessage( gtest_ar_, "arguments"
, "false", "true") .c_str()) = ::testing::Message()
;
669 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, "mt_tcp_listener_mgr_unittests.cc", 669, gtest_ar
.failure_message()) = ::testing::Message()
;
670
671 // "client-ptr" is a string.
672 ConstElementPtr client_ptr = arguments->get("client-ptr");
673 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, "mt_tcp_listener_mgr_unittests.cc", 673, ::testing
::internal::GetBoolAssertionFailureMessage( gtest_ar_, "client_ptr"
, "false", "true") .c_str()) = ::testing::Message()
;
674 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, "mt_tcp_listener_mgr_unittests.cc"
, 674, gtest_ar.failure_message()) = ::testing::Message()
;
675
676 // "thread-id" is a string.
677 ConstElementPtr thread_id = arguments->get("thread-id");
678 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, "mt_tcp_listener_mgr_unittests.cc", 678, ::testing
::internal::GetBoolAssertionFailureMessage( gtest_ar_, "thread_id"
, "false", "true") .c_str()) = ::testing::Message()
;
679 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, "mt_tcp_listener_mgr_unittests.cc"
, 679, gtest_ar.failure_message()) = ::testing::Message()
;
680 std::string thread_id_str = thread_id->stringValue();
681
682 // Make sure the response received was for this client.
683 std::stringstream ss;
684 ss << client;
685 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, "mt_tcp_listener_mgr_unittests.cc", 685, gtest_ar
.failure_message()) = ::testing::Message()
;
686
687 ++total_responses;
688 }
689
690 // We should have responses for all our clients.
691 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
, "mt_tcp_listener_mgr_unittests.cc", 691, gtest_ar.failure_message
()) = ::testing::Message()
;
692
693 // We should have had the expected number of pauses.
694 if (!num_pauses) {
695 ASSERT_EQ(pause_cnt_, 0)switch (0) case 0: default: if (const ::testing::AssertionResult
gtest_ar = (::testing::internal::EqHelper::Compare("pause_cnt_"
, "0", pause_cnt_, 0))) ; else return ::testing::internal::AssertHelper
(::testing::TestPartResult::kFatalFailure, "mt_tcp_listener_mgr_unittests.cc"
, 695, gtest_ar.failure_message()) = ::testing::Message()
;
696 } else {
697 // We allow a range on pauses of +-1.
698 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, "mt_tcp_listener_mgr_unittests.cc", 699, ::testing
::internal::GetBoolAssertionFailureMessage( gtest_ar_, "(num_pauses - 1) <= pause_cnt_ && (pause_cnt_ <= (num_pauses + 1))"
, "false", "true") .c_str()) = ::testing::Message()
699 (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, "mt_tcp_listener_mgr_unittests.cc", 699, ::testing
::internal::GetBoolAssertionFailureMessage( gtest_ar_, "(num_pauses - 1) <= pause_cnt_ && (pause_cnt_ <= (num_pauses + 1))"
, "false", "true") .c_str()) = ::testing::Message()
700 << " num_pauses: " << num_pauses
701 << ", pause_cnt_" << pause_cnt_;
702 }
703 }
704
705 /// @brief MtTcpListenerMgr instance under test.
706 MtTcpListenerMgrPtr mt_listener_mgr_;
707
708 /// @brief IO service used in drive the test and test clients.
709 IOServicePtr io_service_;
710
711 /// @brief Asynchronous timer service to detect timeouts.
712 IntervalTimer test_timer_;
713
714 /// @brief Asynchronous timer for running IO service for a specified amount
715 /// of time.
716 IntervalTimer run_io_service_timer_;
717
718 /// @brief List of client connections.
719 std::list<TcpTestClientPtr> clients_;
720
721 /// @brief Number of threads the listener should use for the test.
722 size_t num_threads_;
723
724 /// @brief Number of client requests to make during the test.
725 size_t num_clients_;
726
727 /// @brief Number of requests currently in progress.
728 size_t num_in_progress_;
729
730 /// @brief Number of requests that have finished.
731 size_t num_finished_;
732
733 /// @brief Chunk size of requests that need to be processed in parallel.
734 ///
735 /// This can either be the number of threads (if the number of requests is
736 /// greater than the number of threads) or the number of requests (if the
737 /// number of threads is greater than the number of requests).
738 size_t chunk_size_;
739
740 /// @brief Mutex used to lock during thread coordination.
741 std::mutex mutex_;
742
743 /// @brief Condition variable used to coordinate threads.
744 std::condition_variable cv_;
745
746 /// @brief Number of times client has been paused during the test.
747 size_t pause_cnt_;
748
749 /// @brief Number of clients that have completed their assignment or
750 /// failed
751 size_t clients_done_;
752
753 /// @brief Response Handler passed down to each connection.
754 TcpTestConnection::ResponseHandler response_handler_;
755};
756
757/// Verifies the construction, starting, stopping, pausing, resuming,
758/// and destruction of MtTcpListener.
759TEST_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; static
::testing::TestInfo* const test_info_ __attribute__((unused)
); }; ::testing::TestInfo* const MtTcpListenerMgrTest_basics_Test
::test_info_ = ::testing::internal::MakeAndRegisterTestInfo( "MtTcpListenerMgrTest"
, "basics", nullptr, nullptr, ::testing::internal::CodeLocation
("mt_tcp_listener_mgr_unittests.cc", 759), (::testing::internal
::GetTypeId<MtTcpListenerMgrTest>()), ::testing::internal
::SuiteApiResolver< MtTcpListenerMgrTest>::GetSetUpCaseOrSuite
("mt_tcp_listener_mgr_unittests.cc", 759), ::testing::internal
::SuiteApiResolver< MtTcpListenerMgrTest>::GetTearDownCaseOrSuite
("mt_tcp_listener_mgr_unittests.cc", 759), new ::testing::internal
::TestFactoryImpl<MtTcpListenerMgrTest_basics_Test>); void
MtTcpListenerMgrTest_basics_Test::TestBody()
{
760 // Make sure multi-threading is off.
761 MultiThreadingMgr::instance().setMode(false);
762 IOAddress address(SERVER_ADDRESS);
763 uint16_t port = SERVER_PORT;
764
765 // Make sure we can create one.
766 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, "mt_tcp_listener_mgr_unittests.cc"
, 770, "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
, "mt_tcp_listener_mgr_unittests.cc", 770, "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"; } }
767 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, "mt_tcp_listener_mgr_unittests.cc"
, 770, "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
, "mt_tcp_listener_mgr_unittests.cc", 770, "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 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, "mt_tcp_listener_mgr_unittests.cc"
, 770, "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
, "mt_tcp_listener_mgr_unittests.cc", 770, "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 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, "mt_tcp_listener_mgr_unittests.cc"
, 770, "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
, "mt_tcp_listener_mgr_unittests.cc", 770, "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 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, "mt_tcp_listener_mgr_unittests.cc"
, 770, "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
, "mt_tcp_listener_mgr_unittests.cc", 770, "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
772 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, "mt_tcp_listener_mgr_unittests.cc", 772, ::testing
::internal::GetBoolAssertionFailureMessage( gtest_ar_, "mt_listener_mgr_"
, "false", "true") .c_str()) = ::testing::Message()
;
773
774 // Verify the getters do what we expect.
775 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, "mt_tcp_listener_mgr_unittests.cc", 775, gtest_ar
.failure_message()) = ::testing::Message()
;
776 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
, "mt_tcp_listener_mgr_unittests.cc", 776, gtest_ar.failure_message
()) = ::testing::Message()
;
777 EXPECT_EQ(mt_listener_mgr_->getThreadPoolSize(), 1)switch (0) case 0: default: if (const ::testing::AssertionResult
gtest_ar = (::testing::internal::EqHelper::Compare("mt_listener_mgr_->getThreadPoolSize()"
, "1", mt_listener_mgr_->getThreadPoolSize(), 1))) ; else ::
testing::internal::AssertHelper(::testing::TestPartResult::kNonFatalFailure
, "mt_tcp_listener_mgr_unittests.cc", 777, gtest_ar.failure_message
()) = ::testing::Message()
;
778 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, "mt_tcp_listener_mgr_unittests.cc"
, 778, ::testing::internal::GetBoolAssertionFailureMessage( gtest_ar_
, "mt_listener_mgr_->getTlsContext()", "true", "false") .c_str
()) = ::testing::Message()
;
779
780 // It should not have an IOService, should not be listening and
781 // should have no threads.
782 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, "mt_tcp_listener_mgr_unittests.cc"
, 782, ::testing::internal::GetBoolAssertionFailureMessage( gtest_ar_
, "mt_listener_mgr_->getThreadIOService()", "true", "false"
) .c_str()) = ::testing::Message()
;
783 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, "mt_tcp_listener_mgr_unittests.cc"
, 783, ::testing::internal::GetBoolAssertionFailureMessage( gtest_ar_
, "mt_listener_mgr_->isStopped()", "false", "true") .c_str
()) = ::testing::Message()
;
784 EXPECT_EQ(mt_listener_mgr_->getThreadCount(), 0)switch (0) case 0: default: if (const ::testing::AssertionResult
gtest_ar = (::testing::internal::EqHelper::Compare("mt_listener_mgr_->getThreadCount()"
, "0", mt_listener_mgr_->getThreadCount(), 0))) ; else ::testing
::internal::AssertHelper(::testing::TestPartResult::kNonFatalFailure
, "mt_tcp_listener_mgr_unittests.cc", 784, gtest_ar.failure_message
()) = ::testing::Message()
;
785
786 // Verify that we cannot start it when multi-threading is disabled.
787 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, "mt_tcp_listener_mgr_unittests.cc"
, 787, ::testing::internal::GetBoolAssertionFailureMessage( gtest_ar_
, "MultiThreadingMgr::instance().getMode()", "true", "false")
.c_str()) = ::testing::Message()
;
788 ASSERT_THROW_MSG(mt_listener_mgr_->start(), InvalidOperation,{ try { mt_listener_mgr_->start(); return ::testing::internal
::AssertHelper(::testing::TestPartResult::kFatalFailure, "mt_tcp_listener_mgr_unittests.cc"
, 790, "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
, "mt_tcp_listener_mgr_unittests.cc", 790, gtest_ar.failure_message
()) = ::testing::Message(); } catch (...) { return ::testing::
internal::AssertHelper(::testing::TestPartResult::kFatalFailure
, "mt_tcp_listener_mgr_unittests.cc", 790, "Failed") = ::testing
::Message() << "wrong exception type thrown, expected: "
<< "InvalidOperation"; } }
789 "MtTcpListenerMgr cannot be started"{ try { mt_listener_mgr_->start(); return ::testing::internal
::AssertHelper(::testing::TestPartResult::kFatalFailure, "mt_tcp_listener_mgr_unittests.cc"
, 790, "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
, "mt_tcp_listener_mgr_unittests.cc", 790, gtest_ar.failure_message
()) = ::testing::Message(); } catch (...) { return ::testing::
internal::AssertHelper(::testing::TestPartResult::kFatalFailure
, "mt_tcp_listener_mgr_unittests.cc", 790, "Failed") = ::testing
::Message() << "wrong exception type thrown, expected: "
<< "InvalidOperation"; } }
790 " when multi-threading is disabled"){ try { mt_listener_mgr_->start(); return ::testing::internal
::AssertHelper(::testing::TestPartResult::kFatalFailure, "mt_tcp_listener_mgr_unittests.cc"
, 790, "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
, "mt_tcp_listener_mgr_unittests.cc", 790, gtest_ar.failure_message
()) = ::testing::Message(); } catch (...) { return ::testing::
internal::AssertHelper(::testing::TestPartResult::kFatalFailure
, "mt_tcp_listener_mgr_unittests.cc", 790, "Failed") = ::testing
::Message() << "wrong exception type thrown, expected: "
<< "InvalidOperation"; } }
;
791
792 // It should still not be listening and have no threads.
793 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, "mt_tcp_listener_mgr_unittests.cc"
, 793, ::testing::internal::GetBoolAssertionFailureMessage( gtest_ar_
, "mt_listener_mgr_->isStopped()", "false", "true") .c_str
()) = ::testing::Message()
;
794 EXPECT_EQ(mt_listener_mgr_->getThreadCount(), 0)switch (0) case 0: default: if (const ::testing::AssertionResult
gtest_ar = (::testing::internal::EqHelper::Compare("mt_listener_mgr_->getThreadCount()"
, "0", mt_listener_mgr_->getThreadCount(), 0))) ; else ::testing
::internal::AssertHelper(::testing::TestPartResult::kNonFatalFailure
, "mt_tcp_listener_mgr_unittests.cc", 794, gtest_ar.failure_message
()) = ::testing::Message()
;
795
796 // Enable multi-threading.
797 MultiThreadingMgr::instance().setMode(true);
798
799 // Make sure we can start it and it's listening with 1 thread.
800 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, "mt_tcp_listener_mgr_unittests.cc"
, 800, "Failed") = ::testing::Message() << "mt_listener_mgr_->start()"
<< " threw type: " << typeid(ex).name() <<
", what: " << ex.what(); } catch (...) { return ::testing
::internal::AssertHelper(::testing::TestPartResult::kFatalFailure
, "mt_tcp_listener_mgr_unittests.cc", 800, "Failed") = ::testing
::Message() << "mt_listener_mgr_->start()" << " threw non-std::exception"
; } }
;
801 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, "mt_tcp_listener_mgr_unittests.cc"
, 801, ::testing::internal::GetBoolAssertionFailureMessage( gtest_ar_
, "mt_listener_mgr_->isRunning()", "false", "true") .c_str
()) = ::testing::Message()
;
802 EXPECT_EQ(mt_listener_mgr_->getThreadCount(), 1)switch (0) case 0: default: if (const ::testing::AssertionResult
gtest_ar = (::testing::internal::EqHelper::Compare("mt_listener_mgr_->getThreadCount()"
, "1", mt_listener_mgr_->getThreadCount(), 1))) ; else ::testing
::internal::AssertHelper(::testing::TestPartResult::kNonFatalFailure
, "mt_tcp_listener_mgr_unittests.cc", 802, gtest_ar.failure_message
()) = ::testing::Message()
;
803 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, "mt_tcp_listener_mgr_unittests.cc"
, 803, ::testing::internal::GetBoolAssertionFailureMessage( gtest_ar_
, "mt_listener_mgr_->getThreadIOService()", "false", "true"
) .c_str()) = ::testing::Message()
;
804 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, "mt_tcp_listener_mgr_unittests.cc"
, 804, ::testing::internal::GetBoolAssertionFailureMessage( gtest_ar_
, "mt_listener_mgr_->getThreadIOService()->stopped()", "true"
, "false") .c_str()) = ::testing::Message()
;
805
806 // Trying to start it again should fail.
807 ASSERT_THROW_MSG(mt_listener_mgr_->start(), InvalidOperation,{ try { mt_listener_mgr_->start(); return ::testing::internal
::AssertHelper(::testing::TestPartResult::kFatalFailure, "mt_tcp_listener_mgr_unittests.cc"
, 808, "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, "mt_tcp_listener_mgr_unittests.cc"
, 808, gtest_ar.failure_message()) = ::testing::Message(); } catch
(...) { return ::testing::internal::AssertHelper(::testing::
TestPartResult::kFatalFailure, "mt_tcp_listener_mgr_unittests.cc"
, 808, "Failed") = ::testing::Message() << "wrong exception type thrown, expected: "
<< "InvalidOperation"; } }
808 "MtTcpListenerMgr already started!"){ try { mt_listener_mgr_->start(); return ::testing::internal
::AssertHelper(::testing::TestPartResult::kFatalFailure, "mt_tcp_listener_mgr_unittests.cc"
, 808, "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, "mt_tcp_listener_mgr_unittests.cc"
, 808, gtest_ar.failure_message()) = ::testing::Message(); } catch
(...) { return ::testing::internal::AssertHelper(::testing::
TestPartResult::kFatalFailure, "mt_tcp_listener_mgr_unittests.cc"
, 808, "Failed") = ::testing::Message() << "wrong exception type thrown, expected: "
<< "InvalidOperation"; } }
;
809
810 // Stop it and verify we're no longer listening.
811 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, "mt_tcp_listener_mgr_unittests.cc"
, 811, "Failed") = ::testing::Message() << "mt_listener_mgr_->stop()"
<< " threw type: " << typeid(ex).name() <<
", what: " << ex.what(); } catch (...) { return ::testing
::internal::AssertHelper(::testing::TestPartResult::kFatalFailure
, "mt_tcp_listener_mgr_unittests.cc", 811, "Failed") = ::testing
::Message() << "mt_listener_mgr_->stop()" << " threw non-std::exception"
; } }
;
812 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, "mt_tcp_listener_mgr_unittests.cc"
, 812, ::testing::internal::GetBoolAssertionFailureMessage( gtest_ar_
, "mt_listener_mgr_->isStopped()", "false", "true") .c_str
()) = ::testing::Message()
;
813 EXPECT_EQ(mt_listener_mgr_->getThreadCount(), 0)switch (0) case 0: default: if (const ::testing::AssertionResult
gtest_ar = (::testing::internal::EqHelper::Compare("mt_listener_mgr_->getThreadCount()"
, "0", mt_listener_mgr_->getThreadCount(), 0))) ; else ::testing
::internal::AssertHelper(::testing::TestPartResult::kNonFatalFailure
, "mt_tcp_listener_mgr_unittests.cc", 813, gtest_ar.failure_message
()) = ::testing::Message()
;
814 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, "mt_tcp_listener_mgr_unittests.cc"
, 814, ::testing::internal::GetBoolAssertionFailureMessage( gtest_ar_
, "mt_listener_mgr_->getThreadIOService()", "true", "false"
) .c_str()) = ::testing::Message()
;
815
816 // Make sure we can call stop again without problems.
817 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, "mt_tcp_listener_mgr_unittests.cc"
, 817, "Failed") = ::testing::Message() << "mt_listener_mgr_->stop()"
<< " threw type: " << typeid(ex).name() <<
", what: " << ex.what(); } catch (...) { return ::testing
::internal::AssertHelper(::testing::TestPartResult::kFatalFailure
, "mt_tcp_listener_mgr_unittests.cc", 817, "Failed") = ::testing
::Message() << "mt_listener_mgr_->stop()" << " threw non-std::exception"
; } }
;
818
819 // We should be able to restart it.
820 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, "mt_tcp_listener_mgr_unittests.cc"
, 820, "Failed") = ::testing::Message() << "mt_listener_mgr_->start()"
<< " threw type: " << typeid(ex).name() <<
", what: " << ex.what(); } catch (...) { return ::testing
::internal::AssertHelper(::testing::TestPartResult::kFatalFailure
, "mt_tcp_listener_mgr_unittests.cc", 820, "Failed") = ::testing
::Message() << "mt_listener_mgr_->start()" << " threw non-std::exception"
; } }
;
821 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, "mt_tcp_listener_mgr_unittests.cc"
, 821, ::testing::internal::GetBoolAssertionFailureMessage( gtest_ar_
, "mt_listener_mgr_->isRunning()", "false", "true") .c_str
()) = ::testing::Message()
;
822 EXPECT_EQ(mt_listener_mgr_->getThreadCount(), 1)switch (0) case 0: default: if (const ::testing::AssertionResult
gtest_ar = (::testing::internal::EqHelper::Compare("mt_listener_mgr_->getThreadCount()"
, "1", mt_listener_mgr_->getThreadCount(), 1))) ; else ::testing
::internal::AssertHelper(::testing::TestPartResult::kNonFatalFailure
, "mt_tcp_listener_mgr_unittests.cc", 822, gtest_ar.failure_message
()) = ::testing::Message()
;
823 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, "mt_tcp_listener_mgr_unittests.cc"
, 823, ::testing::internal::GetBoolAssertionFailureMessage( gtest_ar_
, "mt_listener_mgr_->getThreadIOService()", "false", "true"
) .c_str()) = ::testing::Message()
;
824 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, "mt_tcp_listener_mgr_unittests.cc"
, 824, ::testing::internal::GetBoolAssertionFailureMessage( gtest_ar_
, "mt_listener_mgr_->getThreadIOService()->stopped()", "true"
, "false") .c_str()) = ::testing::Message()
;
825
826 // Destroying it should also stop it.
827 // If the test timeouts we know it didn't!
828 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, "mt_tcp_listener_mgr_unittests.cc"
, 828, "Failed") = ::testing::Message() << "mt_listener_mgr_.reset()"
<< " threw type: " << typeid(ex).name() <<
", what: " << ex.what(); } catch (...) { return ::testing
::internal::AssertHelper(::testing::TestPartResult::kFatalFailure
, "mt_tcp_listener_mgr_unittests.cc", 828, "Failed") = ::testing
::Message() << "mt_listener_mgr_.reset()" << " threw non-std::exception"
; } }
;
829
830 // Verify we can construct with more than one thread.
831 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, "mt_tcp_listener_mgr_unittests.cc"
, 835, "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
, "mt_tcp_listener_mgr_unittests.cc", 835, "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"; } }
832 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, "mt_tcp_listener_mgr_unittests.cc"
, 835, "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
, "mt_tcp_listener_mgr_unittests.cc", 835, "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 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, "mt_tcp_listener_mgr_unittests.cc"
, 835, "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
, "mt_tcp_listener_mgr_unittests.cc", 835, "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 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, "mt_tcp_listener_mgr_unittests.cc"
, 835, "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
, "mt_tcp_listener_mgr_unittests.cc", 835, "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 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, "mt_tcp_listener_mgr_unittests.cc"
, 835, "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
, "mt_tcp_listener_mgr_unittests.cc", 835, "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
837 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, "mt_tcp_listener_mgr_unittests.cc"
, 837, "Failed") = ::testing::Message() << "mt_listener_mgr_->start()"
<< " threw type: " << typeid(ex).name() <<
", what: " << ex.what(); } catch (...) { return ::testing
::internal::AssertHelper(::testing::TestPartResult::kFatalFailure
, "mt_tcp_listener_mgr_unittests.cc", 837, "Failed") = ::testing
::Message() << "mt_listener_mgr_->start()" << " threw non-std::exception"
; } }
;
838 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, "mt_tcp_listener_mgr_unittests.cc", 838, gtest_ar
.failure_message()) = ::testing::Message()
;
839 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
, "mt_tcp_listener_mgr_unittests.cc", 839, gtest_ar.failure_message
()) = ::testing::Message()
;
840 EXPECT_EQ(mt_listener_mgr_->getThreadCount(), 4)switch (0) case 0: default: if (const ::testing::AssertionResult
gtest_ar = (::testing::internal::EqHelper::Compare("mt_listener_mgr_->getThreadCount()"
, "4", mt_listener_mgr_->getThreadCount(), 4))) ; else ::testing
::internal::AssertHelper(::testing::TestPartResult::kNonFatalFailure
, "mt_tcp_listener_mgr_unittests.cc", 840, gtest_ar.failure_message
()) = ::testing::Message()
;
841 EXPECT_EQ(mt_listener_mgr_->getThreadPoolSize(), 4)switch (0) case 0: default: if (const ::testing::AssertionResult
gtest_ar = (::testing::internal::EqHelper::Compare("mt_listener_mgr_->getThreadPoolSize()"
, "4", mt_listener_mgr_->getThreadPoolSize(), 4))) ; else ::
testing::internal::AssertHelper(::testing::TestPartResult::kNonFatalFailure
, "mt_tcp_listener_mgr_unittests.cc", 841, gtest_ar.failure_message
()) = ::testing::Message()
;
842 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, "mt_tcp_listener_mgr_unittests.cc"
, 842, ::testing::internal::GetBoolAssertionFailureMessage( gtest_ar_
, "mt_listener_mgr_->isRunning()", "false", "true") .c_str
()) = ::testing::Message()
;
843 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, "mt_tcp_listener_mgr_unittests.cc"
, 843, ::testing::internal::GetBoolAssertionFailureMessage( gtest_ar_
, "mt_listener_mgr_->getThreadIOService()", "false", "true"
) .c_str()) = ::testing::Message()
;
844 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, "mt_tcp_listener_mgr_unittests.cc"
, 844, ::testing::internal::GetBoolAssertionFailureMessage( gtest_ar_
, "mt_listener_mgr_->getThreadIOService()->stopped()", "true"
, "false") .c_str()) = ::testing::Message()
;
845
846 // Verify we can pause it. We should still be listening, threads intact,
847 // IOService stopped, state set to PAUSED.
848 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, "mt_tcp_listener_mgr_unittests.cc"
, 848, "Failed") = ::testing::Message() << "mt_listener_mgr_->pause()"
<< " threw type: " << typeid(ex).name() <<
", what: " << ex.what(); } catch (...) { return ::testing
::internal::AssertHelper(::testing::TestPartResult::kFatalFailure
, "mt_tcp_listener_mgr_unittests.cc", 848, "Failed") = ::testing
::Message() << "mt_listener_mgr_->pause()" << " threw non-std::exception"
; } }
;
849 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, "mt_tcp_listener_mgr_unittests.cc"
, 849, ::testing::internal::GetBoolAssertionFailureMessage( gtest_ar_
, "mt_listener_mgr_->isPaused()", "false", "true") .c_str(
)) = ::testing::Message()
;
850 EXPECT_EQ(mt_listener_mgr_->getThreadCount(), 4)switch (0) case 0: default: if (const ::testing::AssertionResult
gtest_ar = (::testing::internal::EqHelper::Compare("mt_listener_mgr_->getThreadCount()"
, "4", mt_listener_mgr_->getThreadCount(), 4))) ; else ::testing
::internal::AssertHelper(::testing::TestPartResult::kNonFatalFailure
, "mt_tcp_listener_mgr_unittests.cc", 850, gtest_ar.failure_message
()) = ::testing::Message()
;
851 EXPECT_EQ(mt_listener_mgr_->getThreadPoolSize(), 4)switch (0) case 0: default: if (const ::testing::AssertionResult
gtest_ar = (::testing::internal::EqHelper::Compare("mt_listener_mgr_->getThreadPoolSize()"
, "4", mt_listener_mgr_->getThreadPoolSize(), 4))) ; else ::
testing::internal::AssertHelper(::testing::TestPartResult::kNonFatalFailure
, "mt_tcp_listener_mgr_unittests.cc", 851, gtest_ar.failure_message
()) = ::testing::Message()
;
852 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, "mt_tcp_listener_mgr_unittests.cc"
, 852, ::testing::internal::GetBoolAssertionFailureMessage( gtest_ar_
, "mt_listener_mgr_->getThreadIOService()", "false", "true"
) .c_str()) = ::testing::Message()
;
853 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, "mt_tcp_listener_mgr_unittests.cc"
, 853, ::testing::internal::GetBoolAssertionFailureMessage( gtest_ar_
, "mt_listener_mgr_->getThreadIOService()->stopped()", "false"
, "true") .c_str()) = ::testing::Message()
;
854
855 // Verify we can resume it.
856 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, "mt_tcp_listener_mgr_unittests.cc"
, 856, "Failed") = ::testing::Message() << "mt_listener_mgr_->resume()"
<< " threw type: " << typeid(ex).name() <<
", what: " << ex.what(); } catch (...) { return ::testing
::internal::AssertHelper(::testing::TestPartResult::kFatalFailure
, "mt_tcp_listener_mgr_unittests.cc", 856, "Failed") = ::testing
::Message() << "mt_listener_mgr_->resume()" <<
" threw non-std::exception"; } }
;
857 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, "mt_tcp_listener_mgr_unittests.cc"
, 857, ::testing::internal::GetBoolAssertionFailureMessage( gtest_ar_
, "mt_listener_mgr_->isRunning()", "false", "true") .c_str
()) = ::testing::Message()
;
858 EXPECT_EQ(mt_listener_mgr_->getThreadCount(), 4)switch (0) case 0: default: if (const ::testing::AssertionResult
gtest_ar = (::testing::internal::EqHelper::Compare("mt_listener_mgr_->getThreadCount()"
, "4", mt_listener_mgr_->getThreadCount(), 4))) ; else ::testing
::internal::AssertHelper(::testing::TestPartResult::kNonFatalFailure
, "mt_tcp_listener_mgr_unittests.cc", 858, gtest_ar.failure_message
()) = ::testing::Message()
;
859 EXPECT_EQ(mt_listener_mgr_->getThreadPoolSize(), 4)switch (0) case 0: default: if (const ::testing::AssertionResult
gtest_ar = (::testing::internal::EqHelper::Compare("mt_listener_mgr_->getThreadPoolSize()"
, "4", mt_listener_mgr_->getThreadPoolSize(), 4))) ; else ::
testing::internal::AssertHelper(::testing::TestPartResult::kNonFatalFailure
, "mt_tcp_listener_mgr_unittests.cc", 859, gtest_ar.failure_message
()) = ::testing::Message()
;
860 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, "mt_tcp_listener_mgr_unittests.cc"
, 860, ::testing::internal::GetBoolAssertionFailureMessage( gtest_ar_
, "mt_listener_mgr_->getThreadIOService()", "false", "true"
) .c_str()) = ::testing::Message()
;
861 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, "mt_tcp_listener_mgr_unittests.cc"
, 861, ::testing::internal::GetBoolAssertionFailureMessage( gtest_ar_
, "mt_listener_mgr_->getThreadIOService()->stopped()", "true"
, "false") .c_str()) = ::testing::Message()
;
862
863 // Stop it and verify we're no longer listening.
864 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, "mt_tcp_listener_mgr_unittests.cc"
, 864, "Failed") = ::testing::Message() << "mt_listener_mgr_->stop()"
<< " threw type: " << typeid(ex).name() <<
", what: " << ex.what(); } catch (...) { return ::testing
::internal::AssertHelper(::testing::TestPartResult::kFatalFailure
, "mt_tcp_listener_mgr_unittests.cc", 864, "Failed") = ::testing
::Message() << "mt_listener_mgr_->stop()" << " threw non-std::exception"
; } }
;
865 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, "mt_tcp_listener_mgr_unittests.cc"
, 865, ::testing::internal::GetBoolAssertionFailureMessage( gtest_ar_
, "mt_listener_mgr_->isStopped()", "false", "true") .c_str
()) = ::testing::Message()
;
866 EXPECT_EQ(mt_listener_mgr_->getThreadCount(), 0)switch (0) case 0: default: if (const ::testing::AssertionResult
gtest_ar = (::testing::internal::EqHelper::Compare("mt_listener_mgr_->getThreadCount()"
, "0", mt_listener_mgr_->getThreadCount(), 0))) ; else ::testing
::internal::AssertHelper(::testing::TestPartResult::kNonFatalFailure
, "mt_tcp_listener_mgr_unittests.cc", 866, gtest_ar.failure_message
()) = ::testing::Message()
;
867 EXPECT_EQ(mt_listener_mgr_->getThreadPoolSize(), 4)switch (0) case 0: default: if (const ::testing::AssertionResult
gtest_ar = (::testing::internal::EqHelper::Compare("mt_listener_mgr_->getThreadPoolSize()"
, "4", mt_listener_mgr_->getThreadPoolSize(), 4))) ; else ::
testing::internal::AssertHelper(::testing::TestPartResult::kNonFatalFailure
, "mt_tcp_listener_mgr_unittests.cc", 867, gtest_ar.failure_message
()) = ::testing::Message()
;
868 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, "mt_tcp_listener_mgr_unittests.cc"
, 868, ::testing::internal::GetBoolAssertionFailureMessage( gtest_ar_
, "mt_listener_mgr_->getThreadIOService()", "true", "false"
) .c_str()) = ::testing::Message()
;
869 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, "mt_tcp_listener_mgr_unittests.cc"
, 869, ::testing::internal::GetBoolAssertionFailureMessage( gtest_ar_
, "mt_listener_mgr_->isStopped()", "false", "true") .c_str
()) = ::testing::Message()
;
870}
871
872// Now we'll run some permutations of the number of listener threads
873// and the number of client requests.
874
875// One thread, one client.
876TEST_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; static
::testing::TestInfo* const test_info_ __attribute__((unused)
); }; ::testing::TestInfo* const MtTcpListenerMgrTest_oneByOne_Test
::test_info_ = ::testing::internal::MakeAndRegisterTestInfo( "MtTcpListenerMgrTest"
, "oneByOne", nullptr, nullptr, ::testing::internal::CodeLocation
("mt_tcp_listener_mgr_unittests.cc", 876), (::testing::internal
::GetTypeId<MtTcpListenerMgrTest>()), ::testing::internal
::SuiteApiResolver< MtTcpListenerMgrTest>::GetSetUpCaseOrSuite
("mt_tcp_listener_mgr_unittests.cc", 876), ::testing::internal
::SuiteApiResolver< MtTcpListenerMgrTest>::GetTearDownCaseOrSuite
("mt_tcp_listener_mgr_unittests.cc", 876), new ::testing::internal
::TestFactoryImpl<MtTcpListenerMgrTest_oneByOne_Test>);
void MtTcpListenerMgrTest_oneByOne_Test::TestBody()
{
877 size_t num_threads = 1;
878 size_t num_clients = 1;
879 threadListenAndRespond(num_threads, num_clients);
880}
881
882// One thread, four clients.
883TEST_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; static
::testing::TestInfo* const test_info_ __attribute__((unused)
); }; ::testing::TestInfo* const MtTcpListenerMgrTest_oneByFour_Test
::test_info_ = ::testing::internal::MakeAndRegisterTestInfo( "MtTcpListenerMgrTest"
, "oneByFour", nullptr, nullptr, ::testing::internal::CodeLocation
("mt_tcp_listener_mgr_unittests.cc", 883), (::testing::internal
::GetTypeId<MtTcpListenerMgrTest>()), ::testing::internal
::SuiteApiResolver< MtTcpListenerMgrTest>::GetSetUpCaseOrSuite
("mt_tcp_listener_mgr_unittests.cc", 883), ::testing::internal
::SuiteApiResolver< MtTcpListenerMgrTest>::GetTearDownCaseOrSuite
("mt_tcp_listener_mgr_unittests.cc", 883), new ::testing::internal
::TestFactoryImpl<MtTcpListenerMgrTest_oneByFour_Test>)
; void MtTcpListenerMgrTest_oneByFour_Test::TestBody()
{
884 size_t num_threads = 1;
885 size_t num_clients = 4;
886 threadListenAndRespond(num_threads, num_clients);
887}
888
889// Four threads, one clients.
890TEST_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; static
::testing::TestInfo* const test_info_ __attribute__((unused)
); }; ::testing::TestInfo* const MtTcpListenerMgrTest_fourByOne_Test
::test_info_ = ::testing::internal::MakeAndRegisterTestInfo( "MtTcpListenerMgrTest"
, "fourByOne", nullptr, nullptr, ::testing::internal::CodeLocation
("mt_tcp_listener_mgr_unittests.cc", 890), (::testing::internal
::GetTypeId<MtTcpListenerMgrTest>()), ::testing::internal
::SuiteApiResolver< MtTcpListenerMgrTest>::GetSetUpCaseOrSuite
("mt_tcp_listener_mgr_unittests.cc", 890), ::testing::internal
::SuiteApiResolver< MtTcpListenerMgrTest>::GetTearDownCaseOrSuite
("mt_tcp_listener_mgr_unittests.cc", 890), new ::testing::internal
::TestFactoryImpl<MtTcpListenerMgrTest_fourByOne_Test>)
; void MtTcpListenerMgrTest_fourByOne_Test::TestBody()
{
891 size_t num_threads = 4;
892 size_t num_clients = 1;
893 threadListenAndRespond(num_threads, num_clients);
894}
895
896// Four threads, four clients.
897TEST_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; static
::testing::TestInfo* const test_info_ __attribute__((unused)
); }; ::testing::TestInfo* const MtTcpListenerMgrTest_fourByFour_Test
::test_info_ = ::testing::internal::MakeAndRegisterTestInfo( "MtTcpListenerMgrTest"
, "fourByFour", nullptr, nullptr, ::testing::internal::CodeLocation
("mt_tcp_listener_mgr_unittests.cc", 897), (::testing::internal
::GetTypeId<MtTcpListenerMgrTest>()), ::testing::internal
::SuiteApiResolver< MtTcpListenerMgrTest>::GetSetUpCaseOrSuite
("mt_tcp_listener_mgr_unittests.cc", 897), ::testing::internal
::SuiteApiResolver< MtTcpListenerMgrTest>::GetTearDownCaseOrSuite
("mt_tcp_listener_mgr_unittests.cc", 897), new ::testing::internal
::TestFactoryImpl<MtTcpListenerMgrTest_fourByFour_Test>
); void MtTcpListenerMgrTest_fourByFour_Test::TestBody()
{
898 size_t num_threads = 4;
899 size_t num_clients = 4;
900 threadListenAndRespond(num_threads, num_clients);
901}
902
903// Four threads, eight clients.
904TEST_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; static
::testing::TestInfo* const test_info_ __attribute__((unused)
); }; ::testing::TestInfo* const MtTcpListenerMgrTest_fourByEight_Test
::test_info_ = ::testing::internal::MakeAndRegisterTestInfo( "MtTcpListenerMgrTest"
, "fourByEight", nullptr, nullptr, ::testing::internal::CodeLocation
("mt_tcp_listener_mgr_unittests.cc", 904), (::testing::internal
::GetTypeId<MtTcpListenerMgrTest>()), ::testing::internal
::SuiteApiResolver< MtTcpListenerMgrTest>::GetSetUpCaseOrSuite
("mt_tcp_listener_mgr_unittests.cc", 904), ::testing::internal
::SuiteApiResolver< MtTcpListenerMgrTest>::GetTearDownCaseOrSuite
("mt_tcp_listener_mgr_unittests.cc", 904), new ::testing::internal
::TestFactoryImpl<MtTcpListenerMgrTest_fourByEight_Test>
); void MtTcpListenerMgrTest_fourByEight_Test::TestBody()
{
905 size_t num_threads = 4;
906 size_t num_clients = 8;
907 threadListenAndRespond(num_threads, num_clients);
908}
909
910// Six threads, eighteen clients.
911TEST_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; static
::testing::TestInfo* const test_info_ __attribute__((unused)
); }; ::testing::TestInfo* const MtTcpListenerMgrTest_sixByEighteen_Test
::test_info_ = ::testing::internal::MakeAndRegisterTestInfo( "MtTcpListenerMgrTest"
, "sixByEighteen", nullptr, nullptr, ::testing::internal::CodeLocation
("mt_tcp_listener_mgr_unittests.cc", 911), (::testing::internal
::GetTypeId<MtTcpListenerMgrTest>()), ::testing::internal
::SuiteApiResolver< MtTcpListenerMgrTest>::GetSetUpCaseOrSuite
("mt_tcp_listener_mgr_unittests.cc", 911), ::testing::internal
::SuiteApiResolver< MtTcpListenerMgrTest>::GetTearDownCaseOrSuite
("mt_tcp_listener_mgr_unittests.cc", 911), new ::testing::internal
::TestFactoryImpl<MtTcpListenerMgrTest_sixByEighteen_Test>
); void MtTcpListenerMgrTest_sixByEighteen_Test::TestBody()
{
912 size_t num_threads = 6;
913 size_t num_clients = 18;
914 threadListenAndRespond(num_threads, num_clients);
915}
916
917// Pauses and resumes the listener while it is processing
918// requests.
919TEST_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; static
::testing::TestInfo* const test_info_ __attribute__((unused)
); }; ::testing::TestInfo* const MtTcpListenerMgrTest_pauseAndResume_Test
::test_info_ = ::testing::internal::MakeAndRegisterTestInfo( "MtTcpListenerMgrTest"
, "pauseAndResume", nullptr, nullptr, ::testing::internal::CodeLocation
("mt_tcp_listener_mgr_unittests.cc", 919), (::testing::internal
::GetTypeId<MtTcpListenerMgrTest>()), ::testing::internal
::SuiteApiResolver< MtTcpListenerMgrTest>::GetSetUpCaseOrSuite
("mt_tcp_listener_mgr_unittests.cc", 919), ::testing::internal
::SuiteApiResolver< MtTcpListenerMgrTest>::GetTearDownCaseOrSuite
("mt_tcp_listener_mgr_unittests.cc", 919), new ::testing::internal
::TestFactoryImpl<MtTcpListenerMgrTest_pauseAndResume_Test
>); void MtTcpListenerMgrTest_pauseAndResume_Test::TestBody
()
{
920 size_t num_threads = 6;
921 size_t num_clients = 18;
922 size_t num_pauses = 3;
923 workPauseAndResume(num_threads, num_clients, num_pauses);
924}
925
926// Check if a TLS listener can be created.
927TEST_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
; static ::testing::TestInfo* const test_info_ __attribute__(
(unused)); }; ::testing::TestInfo* const MtTcpListenerMgrTest_tls_Test
::test_info_ = ::testing::internal::MakeAndRegisterTestInfo( "MtTcpListenerMgrTest"
, "tls", nullptr, nullptr, ::testing::internal::CodeLocation(
"mt_tcp_listener_mgr_unittests.cc", 927), (::testing::internal
::GetTypeId<MtTcpListenerMgrTest>()), ::testing::internal
::SuiteApiResolver< MtTcpListenerMgrTest>::GetSetUpCaseOrSuite
("mt_tcp_listener_mgr_unittests.cc", 927), ::testing::internal
::SuiteApiResolver< MtTcpListenerMgrTest>::GetTearDownCaseOrSuite
("mt_tcp_listener_mgr_unittests.cc", 927), new ::testing::internal
::TestFactoryImpl<MtTcpListenerMgrTest_tls_Test>); void
MtTcpListenerMgrTest_tls_Test::TestBody()
{
928 IOAddress address(SERVER_ADDRESS);
929 uint16_t port = SERVER_PORT;
930 TlsContextPtr context;
931 configServer(context);
932
933 // Make sure we can create the listener.
934 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, "mt_tcp_listener_mgr_unittests.cc", 940, "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
, "mt_tcp_listener_mgr_unittests.cc", 940, "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"; } }
935 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, "mt_tcp_listener_mgr_unittests.cc", 940, "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
, "mt_tcp_listener_mgr_unittests.cc", 940, "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 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, "mt_tcp_listener_mgr_unittests.cc", 940, "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
, "mt_tcp_listener_mgr_unittests.cc", 940, "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 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, "mt_tcp_listener_mgr_unittests.cc", 940, "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
, "mt_tcp_listener_mgr_unittests.cc", 940, "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 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, "mt_tcp_listener_mgr_unittests.cc", 940, "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
, "mt_tcp_listener_mgr_unittests.cc", 940, "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 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, "mt_tcp_listener_mgr_unittests.cc", 940, "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
, "mt_tcp_listener_mgr_unittests.cc", 940, "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 ){ 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, "mt_tcp_listener_mgr_unittests.cc", 940, "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
, "mt_tcp_listener_mgr_unittests.cc", 940, "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
942 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, "mt_tcp_listener_mgr_unittests.cc", 942, gtest_ar
.failure_message()) = ::testing::Message()
;
943 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
, "mt_tcp_listener_mgr_unittests.cc", 943, gtest_ar.failure_message
()) = ::testing::Message()
;
944 EXPECT_EQ(mt_listener_mgr_->getThreadPoolSize(), 1)switch (0) case 0: default: if (const ::testing::AssertionResult
gtest_ar = (::testing::internal::EqHelper::Compare("mt_listener_mgr_->getThreadPoolSize()"
, "1", mt_listener_mgr_->getThreadPoolSize(), 1))) ; else ::
testing::internal::AssertHelper(::testing::TestPartResult::kNonFatalFailure
, "mt_tcp_listener_mgr_unittests.cc", 944, gtest_ar.failure_message
()) = ::testing::Message()
;
945 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, "mt_tcp_listener_mgr_unittests.cc", 945, gtest_ar
.failure_message()) = ::testing::Message()
;
946 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, "mt_tcp_listener_mgr_unittests.cc"
, 946, ::testing::internal::GetBoolAssertionFailureMessage( gtest_ar_
, "mt_listener_mgr_->isStopped()", "false", "true") .c_str
()) = ::testing::Message()
;
947 EXPECT_EQ(mt_listener_mgr_->getThreadCount(), 0)switch (0) case 0: default: if (const ::testing::AssertionResult
gtest_ar = (::testing::internal::EqHelper::Compare("mt_listener_mgr_->getThreadCount()"
, "0", mt_listener_mgr_->getThreadCount(), 0))) ; else ::testing
::internal::AssertHelper(::testing::TestPartResult::kNonFatalFailure
, "mt_tcp_listener_mgr_unittests.cc", 947, gtest_ar.failure_message
()) = ::testing::Message()
;
948
949 // Make sure we can start it and it's listening with 1 thread.
950 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, "mt_tcp_listener_mgr_unittests.cc"
, 950, "Failed") = ::testing::Message() << "mt_listener_mgr_->start()"
<< " threw type: " << typeid(ex).name() <<
", what: " << ex.what(); } catch (...) { return ::testing
::internal::AssertHelper(::testing::TestPartResult::kFatalFailure
, "mt_tcp_listener_mgr_unittests.cc", 950, "Failed") = ::testing
::Message() << "mt_listener_mgr_->start()" << " threw non-std::exception"
; } }
;
951 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, "mt_tcp_listener_mgr_unittests.cc"
, 951, ::testing::internal::GetBoolAssertionFailureMessage( gtest_ar_
, "mt_listener_mgr_->isRunning()", "false", "true") .c_str
()) = ::testing::Message()
;
952 EXPECT_EQ(mt_listener_mgr_->getThreadCount(), 1)switch (0) case 0: default: if (const ::testing::AssertionResult
gtest_ar = (::testing::internal::EqHelper::Compare("mt_listener_mgr_->getThreadCount()"
, "1", mt_listener_mgr_->getThreadCount(), 1))) ; else ::testing
::internal::AssertHelper(::testing::TestPartResult::kNonFatalFailure
, "mt_tcp_listener_mgr_unittests.cc", 952, gtest_ar.failure_message
()) = ::testing::Message()
;
953 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, "mt_tcp_listener_mgr_unittests.cc"
, 953, ::testing::internal::GetBoolAssertionFailureMessage( gtest_ar_
, "mt_listener_mgr_->getThreadIOService()", "false", "true"
) .c_str()) = ::testing::Message()
;
954 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, "mt_tcp_listener_mgr_unittests.cc"
, 954, ::testing::internal::GetBoolAssertionFailureMessage( gtest_ar_
, "mt_listener_mgr_->getThreadIOService()->stopped()", "true"
, "false") .c_str()) = ::testing::Message()
;
955
956 // Stop it.
957 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, "mt_tcp_listener_mgr_unittests.cc"
, 957, "Failed") = ::testing::Message() << "mt_listener_mgr_->stop()"
<< " threw type: " << typeid(ex).name() <<
", what: " << ex.what(); } catch (...) { return ::testing
::internal::AssertHelper(::testing::TestPartResult::kFatalFailure
, "mt_tcp_listener_mgr_unittests.cc", 957, "Failed") = ::testing
::Message() << "mt_listener_mgr_->stop()" << " threw non-std::exception"
; } }
;
958 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, "mt_tcp_listener_mgr_unittests.cc"
, 958, ::testing::internal::GetBoolAssertionFailureMessage( gtest_ar_
, "mt_listener_mgr_->isStopped()", "false", "true") .c_str
()) = ::testing::Message()
;
959 EXPECT_EQ(mt_listener_mgr_->getThreadCount(), 0)switch (0) case 0: default: if (const ::testing::AssertionResult
gtest_ar = (::testing::internal::EqHelper::Compare("mt_listener_mgr_->getThreadCount()"
, "0", mt_listener_mgr_->getThreadCount(), 0))) ; else ::testing
::internal::AssertHelper(::testing::TestPartResult::kNonFatalFailure
, "mt_tcp_listener_mgr_unittests.cc", 959, gtest_ar.failure_message
()) = ::testing::Message()
;
960 EXPECT_EQ(mt_listener_mgr_->getThreadPoolSize(), 1)switch (0) case 0: default: if (const ::testing::AssertionResult
gtest_ar = (::testing::internal::EqHelper::Compare("mt_listener_mgr_->getThreadPoolSize()"
, "1", mt_listener_mgr_->getThreadPoolSize(), 1))) ; else ::
testing::internal::AssertHelper(::testing::TestPartResult::kNonFatalFailure
, "mt_tcp_listener_mgr_unittests.cc", 960, gtest_ar.failure_message
()) = ::testing::Message()
;
961 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, "mt_tcp_listener_mgr_unittests.cc"
, 961, ::testing::internal::GetBoolAssertionFailureMessage( gtest_ar_
, "mt_listener_mgr_->getThreadIOService()", "true", "false"
) .c_str()) = ::testing::Message()
;
962 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, "mt_tcp_listener_mgr_unittests.cc"
, 962, ::testing::internal::GetBoolAssertionFailureMessage( gtest_ar_
, "mt_listener_mgr_->isStopped()", "false", "true") .c_str
()) = ::testing::Message()
;
963}
964
965/// Verifies that idle timeout can be passed down to the internal listener.
966TEST_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; static
::testing::TestInfo* const test_info_ __attribute__((unused)
); }; ::testing::TestInfo* const MtTcpListenerMgrTest_idleTimeout_Test
::test_info_ = ::testing::internal::MakeAndRegisterTestInfo( "MtTcpListenerMgrTest"
, "idleTimeout", nullptr, nullptr, ::testing::internal::CodeLocation
("mt_tcp_listener_mgr_unittests.cc", 966), (::testing::internal
::GetTypeId<MtTcpListenerMgrTest>()), ::testing::internal
::SuiteApiResolver< MtTcpListenerMgrTest>::GetSetUpCaseOrSuite
("mt_tcp_listener_mgr_unittests.cc", 966), ::testing::internal
::SuiteApiResolver< MtTcpListenerMgrTest>::GetTearDownCaseOrSuite
("mt_tcp_listener_mgr_unittests.cc", 966), new ::testing::internal
::TestFactoryImpl<MtTcpListenerMgrTest_idleTimeout_Test>
); void MtTcpListenerMgrTest_idleTimeout_Test::TestBody()
{
967 // Create an MtTcpListenerMgr.
968 createMtTcpListenerMgr(1, std::bind(&MtTcpListenerMgrTest::synchronizedCommandHandler,
969 this, ph::_1));
970 // Verify the default timeout value.
971 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
, "mt_tcp_listener_mgr_unittests.cc", 971, gtest_ar.failure_message
()) = ::testing::Message()
;
972
973 // Set a new timeout value.
974 mt_listener_mgr_->setIdleTimeout(200);
975 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
, "mt_tcp_listener_mgr_unittests.cc", 975, gtest_ar.failure_message
()) = ::testing::Message()
;
976
977 // Start the listener, which should instantiate the internal listener.
978 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, "mt_tcp_listener_mgr_unittests.cc"
, 978, "Failed") = ::testing::Message() << "mt_listener_mgr_->start()"
<< " threw type: " << typeid(ex).name() <<
", what: " << ex.what(); } catch (...) { return ::testing
::internal::AssertHelper(::testing::TestPartResult::kFatalFailure
, "mt_tcp_listener_mgr_unittests.cc", 978, "Failed") = ::testing
::Message() << "mt_listener_mgr_->start()" << " threw non-std::exception"
; } }
;
979 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, "mt_tcp_listener_mgr_unittests.cc"
, 979, ::testing::internal::GetBoolAssertionFailureMessage( gtest_ar_
, "mt_listener_mgr_->isRunning()", "false", "true") .c_str
()) = ::testing::Message()
;
980
981 // Verify the internal listener's timeout value.
982 auto tcp_listener = mt_listener_mgr_->getTcpListener();
983 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, "mt_tcp_listener_mgr_unittests.cc", 983, ::testing
::internal::GetBoolAssertionFailureMessage( gtest_ar_, "tcp_listener"
, "false", "true") .c_str()) = ::testing::Message()
;
984 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
, "mt_tcp_listener_mgr_unittests.cc", 984, gtest_ar.failure_message
()) = ::testing::Message()
;
985}
986
987} // end of anonymous namespace

./tcp_test_client.h

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

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

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

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

1//
2// io_object_impl.hpp
3// ~~~~~~~~~~~~~~~~~~
4//
5// Copyright (c) 2003-2023 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)),
7
Calling 'use_service<boost::asio::detail::reactive_socket_service<boost::asio::ip::tcp>>'
48
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#if defined(BOOST_ASIO_HAS_MOVE1)
65 // Move-construct an I/O object.
66 io_object_impl(io_object_impl&& other)
67 : service_(&other.get_service()),
68 executor_(other.get_executor())
69 {
70 service_->move_construct(implementation_, other.implementation_);
71 }
72
73 // Perform converting move-construction of an I/O object on the same service.
74 template <typename Executor1>
75 io_object_impl(io_object_impl<IoObjectService, Executor1>&& other)
76 : service_(&other.get_service()),
77 executor_(other.get_executor())
78 {
79 service_->move_construct(implementation_, other.get_implementation());
80 }
81
82 // Perform converting move-construction of an I/O object on another service.
83 template <typename IoObjectService1, typename Executor1>
84 io_object_impl(io_object_impl<IoObjectService1, Executor1>&& other)
85 : service_(&boost::asio::use_service<IoObjectService>(
86 io_object_impl::get_context(other.get_executor()))),
87 executor_(other.get_executor())
88 {
89 service_->converting_move_construct(implementation_,
90 other.get_service(), other.get_implementation());
91 }
92#endif // defined(BOOST_ASIO_HAS_MOVE)
93
94 // Destructor.
95 ~io_object_impl()
96 {
97 service_->destroy(implementation_);
98 }
99
100#if defined(BOOST_ASIO_HAS_MOVE1)
101 // Move-assign an I/O object.
102 io_object_impl& operator=(io_object_impl&& other)
103 {
104 if (this != &other)
105 {
106 service_->move_assign(implementation_,
107 *other.service_, other.implementation_);
108 executor_.~executor_type();
109 new (&executor_) executor_type(other.executor_);
110 service_ = other.service_;
111 }
112 return *this;
113 }
114#endif // defined(BOOST_ASIO_HAS_MOVE)
115
116 // Get the executor associated with the object.
117 const executor_type& get_executor() BOOST_ASIO_NOEXCEPTnoexcept
118 {
119 return executor_;
120 }
121
122 // Get the service associated with the I/O object.
123 service_type& get_service()
124 {
125 return *service_;
126 }
127
128 // Get the service associated with the I/O object.
129 const service_type& get_service() const
130 {
131 return *service_;
132 }
133
134 // Get the underlying implementation of the I/O object.
135 implementation_type& get_implementation()
136 {
137 return implementation_;
138 }
139
140 // Get the underlying implementation of the I/O object.
141 const implementation_type& get_implementation() const
142 {
143 return implementation_;
144 }
145
146private:
147 // Helper function to get an executor's context.
148 template <typename T>
149 static execution_context& get_context(const T& t,
150 typename enable_if<execution::is_executor<T>::value>::type* = 0)
151 {
152 return boost::asio::query(t, execution::context);
153 }
154
155 // Helper function to get an executor's context.
156 template <typename T>
157 static execution_context& get_context(const T& t,
158 typename enable_if<!execution::is_executor<T>::value>::type* = 0)
159 {
160 return t.context();
161 }
162
163 // Disallow copying and copy assignment.
164 io_object_impl(const io_object_impl&);
165 io_object_impl& operator=(const io_object_impl&);
166
167 // The service associated with the I/O object.
168 service_type* service_;
169
170 // The underlying implementation of the I/O object.
171 implementation_type implementation_;
172
173 // The associated executor.
174 executor_type executor_;
175};
176
177} // namespace detail
178} // namespace asio
179} // namespace boost
180
181#include <boost/asio/detail/pop_options.hpp>
182
183#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-2023 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/detail/completion_handler.hpp>
19#include <boost/asio/detail/executor_op.hpp>
20#include <boost/asio/detail/fenced_block.hpp>
21#include <boost/asio/detail/handler_type_requirements.hpp>
22#include <boost/asio/detail/non_const_lvalue.hpp>
23#include <boost/asio/detail/service_registry.hpp>
24#include <boost/asio/detail/throw_error.hpp>
25#include <boost/asio/detail/type_traits.hpp>
26
27#include <boost/asio/detail/push_options.hpp>
28
29namespace boost {
30namespace asio {
31
32#if !defined(GENERATING_DOCUMENTATION)
33
34template <typename Service>
35inline Service& use_service(io_context& ioc)
36{
37 // Check that Service meets the necessary type requirements.
38 (void)static_cast<execution_context::service*>(static_cast<Service*>(0));
39 (void)static_cast<const execution_context::id*>(&Service::id);
40
41 return ioc.service_registry_->template use_service<Service>(ioc);
8
Calling 'service_registry::use_service'
47
Returning from 'service_registry::use_service'
42}
43
44template <>
45inline detail::io_context_impl& use_service<detail::io_context_impl>(
46 io_context& ioc)
47{
48 return ioc.impl_;
49}
50
51#endif // !defined(GENERATING_DOCUMENTATION)
52
53inline io_context::executor_type
54io_context::get_executor() BOOST_ASIO_NOEXCEPTnoexcept
55{
56 return executor_type(*this);
57}
58
59#if defined(BOOST_ASIO_HAS_CHRONO1)
60
61template <typename Rep, typename Period>
62std::size_t io_context::run_for(
63 const chrono::duration<Rep, Period>& rel_time)
64{
65 return this->run_until(chrono::steady_clock::now() + rel_time);
66}
67
68template <typename Clock, typename Duration>
69std::size_t io_context::run_until(
70 const chrono::time_point<Clock, Duration>& abs_time)
71{
72 std::size_t n = 0;
73 while (this->run_one_until(abs_time))
74 if (n != (std::numeric_limits<std::size_t>::max)())
75 ++n;
76 return n;
77}
78
79template <typename Rep, typename Period>
80std::size_t io_context::run_one_for(
81 const chrono::duration<Rep, Period>& rel_time)
82{
83 return this->run_one_until(chrono::steady_clock::now() + rel_time);
84}
85
86template <typename Clock, typename Duration>
87std::size_t io_context::run_one_until(
88 const chrono::time_point<Clock, Duration>& abs_time)
89{
90 typename Clock::time_point now = Clock::now();
91 while (now < abs_time)
92 {
93 typename Clock::duration rel_time = abs_time - now;
94 if (rel_time > chrono::seconds(1))
95 rel_time = chrono::seconds(1);
96
97 boost::system::error_code ec;
98 std::size_t s = impl_.wait_one(
99 static_cast<long>(chrono::duration_cast<
100 chrono::microseconds>(rel_time).count()), ec);
101 boost::asio::detail::throw_error(ec);
102
103 if (s || impl_.stopped())
104 return s;
105
106 now = Clock::now();
107 }
108
109 return 0;
110}
111
112#endif // defined(BOOST_ASIO_HAS_CHRONO)
113
114#if !defined(BOOST_ASIO_NO_DEPRECATED)
115
116inline void io_context::reset()
117{
118 restart();
119}
120
121struct io_context::initiate_dispatch
122{
123 template <typename LegacyCompletionHandler>
124 void operator()(BOOST_ASIO_MOVE_ARG(LegacyCompletionHandler)LegacyCompletionHandler&& handler,
125 io_context* self) const
126 {
127 // If you get an error on the following line it means that your handler does
128 // not meet the documented type requirements for a LegacyCompletionHandler.
129 BOOST_ASIO_LEGACY_COMPLETION_HANDLER_CHECK(typedef typename ::boost::asio::async_result< typename ::boost
::asio::decay<LegacyCompletionHandler>::type, void()>
::completion_handler_type asio_true_handler_type; static_assert
(sizeof(boost::asio::detail::zero_arg_copyable_handler_test( boost
::asio::detail::clvref< asio_true_handler_type>(), 0)) ==
1, "CompletionHandler type requirements not met"); typedef boost
::asio::detail::handler_type_requirements< sizeof( boost::
asio::detail::argbyv( boost::asio::detail::clvref< asio_true_handler_type
>())) + sizeof( boost::asio::detail::rorlvref< asio_true_handler_type
>()(), char(0))> __attribute__((__unused__))
130 LegacyCompletionHandler, handler)typedef typename ::boost::asio::async_result< typename ::boost
::asio::decay<LegacyCompletionHandler>::type, void()>
::completion_handler_type asio_true_handler_type; static_assert
(sizeof(boost::asio::detail::zero_arg_copyable_handler_test( boost
::asio::detail::clvref< asio_true_handler_type>(), 0)) ==
1, "CompletionHandler type requirements not met"); typedef boost
::asio::detail::handler_type_requirements< sizeof( boost::
asio::detail::argbyv( boost::asio::detail::clvref< asio_true_handler_type
>())) + sizeof( boost::asio::detail::rorlvref< asio_true_handler_type
>()(), char(0))> __attribute__((__unused__))
type_check;
131
132 detail::non_const_lvalue<LegacyCompletionHandler> handler2(handler);
133 if (self->impl_.can_dispatch())
134 {
135 detail::fenced_block b(detail::fenced_block::full);
136 boost_asio_handler_invoke_helpers::invoke(
137 handler2.value, handler2.value);
138 }
139 else
140 {
141 // Allocate and construct an operation to wrap the handler.
142 typedef detail::completion_handler<
143 typename decay<LegacyCompletionHandler>::type, executor_type> op;
144 typename op::ptr p = { detail::addressof(handler2.value),
145 op::ptr::allocate(handler2.value), 0 };
146 p.p = new (p.v) op(handler2.value, self->get_executor());
147
148 BOOST_ASIO_HANDLER_CREATION((*self, *p.p,(void)0
149 "io_context", self, 0, "dispatch"))(void)0;
150
151 self->impl_.do_dispatch(p.p);
152 p.v = p.p = 0;
153 }
154 }
155};
156
157template <typename LegacyCompletionHandler>
158BOOST_ASIO_INITFN_AUTO_RESULT_TYPE_PREFIX(LegacyCompletionHandler, void ())auto
159io_context::dispatch(BOOST_ASIO_MOVE_ARG(LegacyCompletionHandler)LegacyCompletionHandler&& handler)
160 BOOST_ASIO_INITFN_AUTO_RESULT_TYPE_SUFFIX((
161 async_initiate<LegacyCompletionHandler, void ()>(
162 declval<initiate_dispatch>(), handler, this)))
163{
164 return async_initiate<LegacyCompletionHandler, void ()>(
165 initiate_dispatch(), handler, this);
166}
167
168struct io_context::initiate_post
169{
170 template <typename LegacyCompletionHandler>
171 void operator()(BOOST_ASIO_MOVE_ARG(LegacyCompletionHandler)LegacyCompletionHandler&& handler,
172 io_context* self) const
173 {
174 // If you get an error on the following line it means that your handler does
175 // not meet the documented type requirements for a LegacyCompletionHandler.
176 BOOST_ASIO_LEGACY_COMPLETION_HANDLER_CHECK(typedef typename ::boost::asio::async_result< typename ::boost
::asio::decay<LegacyCompletionHandler>::type, void()>
::completion_handler_type asio_true_handler_type; static_assert
(sizeof(boost::asio::detail::zero_arg_copyable_handler_test( boost
::asio::detail::clvref< asio_true_handler_type>(), 0)) ==
1, "CompletionHandler type requirements not met"); typedef boost
::asio::detail::handler_type_requirements< sizeof( boost::
asio::detail::argbyv( boost::asio::detail::clvref< asio_true_handler_type
>())) + sizeof( boost::asio::detail::rorlvref< asio_true_handler_type
>()(), char(0))> __attribute__((__unused__))
177 LegacyCompletionHandler, handler)typedef typename ::boost::asio::async_result< typename ::boost
::asio::decay<LegacyCompletionHandler>::type, void()>
::completion_handler_type asio_true_handler_type; static_assert
(sizeof(boost::asio::detail::zero_arg_copyable_handler_test( boost
::asio::detail::clvref< asio_true_handler_type>(), 0)) ==
1, "CompletionHandler type requirements not met"); typedef boost
::asio::detail::handler_type_requirements< sizeof( boost::
asio::detail::argbyv( boost::asio::detail::clvref< asio_true_handler_type
>())) + sizeof( boost::asio::detail::rorlvref< asio_true_handler_type
>()(), char(0))> __attribute__((__unused__))
type_check;
178
179 detail::non_const_lvalue<LegacyCompletionHandler> handler2(handler);
180
181 bool is_continuation =
182 boost_asio_handler_cont_helpers::is_continuation(handler2.value);
183
184 // Allocate and construct an operation to wrap the handler.
185 typedef detail::completion_handler<
186 typename decay<LegacyCompletionHandler>::type, executor_type> op;
187 typename op::ptr p = { detail::addressof(handler2.value),
188 op::ptr::allocate(handler2.value), 0 };
189 p.p = new (p.v) op(handler2.value, self->get_executor());
190
191 BOOST_ASIO_HANDLER_CREATION((*self, *p.p,(void)0
192 "io_context", self, 0, "post"))(void)0;
193
194 self->impl_.post_immediate_completion(p.p, is_continuation);
195 p.v = p.p = 0;
196 }
197};
198
199template <typename LegacyCompletionHandler>
200BOOST_ASIO_INITFN_AUTO_RESULT_TYPE_PREFIX(LegacyCompletionHandler, void ())auto
201io_context::post(BOOST_ASIO_MOVE_ARG(LegacyCompletionHandler)LegacyCompletionHandler&& handler)
202 BOOST_ASIO_INITFN_AUTO_RESULT_TYPE_SUFFIX((
203 async_initiate<LegacyCompletionHandler, void ()>(
204 declval<initiate_post>(), handler, this)))
205{
206 return async_initiate<LegacyCompletionHandler, void ()>(
207 initiate_post(), handler, this);
208}
209
210template <typename Handler>
211#if defined(GENERATING_DOCUMENTATION)
212unspecified
213#else
214inline detail::wrapped_handler<io_context&, Handler>
215#endif
216io_context::wrap(Handler handler)
217{
218 return detail::wrapped_handler<io_context&, Handler>(*this, handler);
219}
220
221#endif // !defined(BOOST_ASIO_NO_DEPRECATED)
222
223template <typename Allocator, uintptr_t Bits>
224io_context::basic_executor_type<Allocator, Bits>&
225io_context::basic_executor_type<Allocator, Bits>::operator=(
226 const basic_executor_type& other) BOOST_ASIO_NOEXCEPTnoexcept
227{
228 if (this != &other)
229 {
230 static_cast<Allocator&>(*this) = static_cast<const Allocator&>(other);
231 io_context* old_io_context = context_ptr();
232 target_ = other.target_;
233 if (Bits & outstanding_work_tracked)
234 {
235 if (context_ptr())
236 context_ptr()->impl_.work_started();
237 if (old_io_context)
238 old_io_context->impl_.work_finished();
239 }
240 }
241 return *this;
242}
243
244#if defined(BOOST_ASIO_HAS_MOVE1)
245template <typename Allocator, uintptr_t Bits>
246io_context::basic_executor_type<Allocator, Bits>&
247io_context::basic_executor_type<Allocator, Bits>::operator=(
248 basic_executor_type&& other) BOOST_ASIO_NOEXCEPTnoexcept
249{
250 if (this != &other)
251 {
252 static_cast<Allocator&>(*this) = static_cast<Allocator&&>(other);
253 io_context* old_io_context = context_ptr();
254 target_ = other.target_;
255 if (Bits & outstanding_work_tracked)
256 {
257 other.target_ = 0;
258 if (old_io_context)
259 old_io_context->impl_.work_finished();
260 }
261 }
262 return *this;
263}
264#endif // defined(BOOST_ASIO_HAS_MOVE)
265
266template <typename Allocator, uintptr_t Bits>
267inline bool io_context::basic_executor_type<Allocator,
268 Bits>::running_in_this_thread() const BOOST_ASIO_NOEXCEPTnoexcept
269{
270 return context_ptr()->impl_.can_dispatch();
271}
272
273template <typename Allocator, uintptr_t Bits>
274template <typename Function>
275void io_context::basic_executor_type<Allocator, Bits>::execute(
276 BOOST_ASIO_MOVE_ARG(Function)Function&& f) const
277{
278 typedef typename decay<Function>::type function_type;
279
280 // Invoke immediately if the blocking.possibly property is enabled and we are
281 // already inside the thread pool.
282 if ((bits() & blocking_never) == 0 && context_ptr()->impl_.can_dispatch())
283 {
284 // Make a local, non-const copy of the function.
285 function_type tmp(BOOST_ASIO_MOVE_CAST(Function)static_cast<Function&&>(f));
286
287#if defined(BOOST_ASIO_HAS_STD_EXCEPTION_PTR1) \
288 && !defined(BOOST_ASIO_NO_EXCEPTIONS)
289 try
290 {
291#endif // defined(BOOST_ASIO_HAS_STD_EXCEPTION_PTR)
292 // && !defined(BOOST_ASIO_NO_EXCEPTIONS)
293 detail::fenced_block b(detail::fenced_block::full);
294 boost_asio_handler_invoke_helpers::invoke(tmp, tmp);
295 return;
296#if defined(BOOST_ASIO_HAS_STD_EXCEPTION_PTR1) \
297 && !defined(BOOST_ASIO_NO_EXCEPTIONS)
298 }
299 catch (...)
300 {
301 context_ptr()->impl_.capture_current_exception();
302 return;
303 }
304#endif // defined(BOOST_ASIO_HAS_STD_EXCEPTION_PTR)
305 // && !defined(BOOST_ASIO_NO_EXCEPTIONS)
306 }
307
308 // Allocate and construct an operation to wrap the function.
309 typedef detail::executor_op<function_type, Allocator, detail::operation> op;
310 typename op::ptr p = {
311 detail::addressof(static_cast<const Allocator&>(*this)),
312 op::ptr::allocate(static_cast<const Allocator&>(*this)), 0 };
313 p.p = new (p.v) op(BOOST_ASIO_MOVE_CAST(Function)static_cast<Function&&>(f),
314 static_cast<const Allocator&>(*this));
315
316 BOOST_ASIO_HANDLER_CREATION((*context_ptr(), *p.p,(void)0
317 "io_context", context_ptr(), 0, "execute"))(void)0;
318
319 context_ptr()->impl_.post_immediate_completion(p.p,
320 (bits() & relationship_continuation) != 0);
321 p.v = p.p = 0;
322}
323
324#if !defined(BOOST_ASIO_NO_TS_EXECUTORS)
325template <typename Allocator, uintptr_t Bits>
326inline io_context& io_context::basic_executor_type<
327 Allocator, Bits>::context() const BOOST_ASIO_NOEXCEPTnoexcept
328{
329 return *context_ptr();
330}
331
332template <typename Allocator, uintptr_t Bits>
333inline void io_context::basic_executor_type<Allocator,
334 Bits>::on_work_started() const BOOST_ASIO_NOEXCEPTnoexcept
335{
336 context_ptr()->impl_.work_started();
337}
338
339template <typename Allocator, uintptr_t Bits>
340inline void io_context::basic_executor_type<Allocator,
341 Bits>::on_work_finished() const BOOST_ASIO_NOEXCEPTnoexcept
342{
343 context_ptr()->impl_.work_finished();
344}
345
346template <typename Allocator, uintptr_t Bits>
347template <typename Function, typename OtherAllocator>
348void io_context::basic_executor_type<Allocator, Bits>::dispatch(
349 BOOST_ASIO_MOVE_ARG(Function)Function&& f, const OtherAllocator& a) const
350{
351 typedef typename decay<Function>::type function_type;
352
353 // Invoke immediately if we are already inside the thread pool.
354 if (context_ptr()->impl_.can_dispatch())
355 {
356 // Make a local, non-const copy of the function.
357 function_type tmp(BOOST_ASIO_MOVE_CAST(Function)static_cast<Function&&>(f));
358
359 detail::fenced_block b(detail::fenced_block::full);
360 boost_asio_handler_invoke_helpers::invoke(tmp, tmp);
361 return;
362 }
363
364 // Allocate and construct an operation to wrap the function.
365 typedef detail::executor_op<function_type,
366 OtherAllocator, detail::operation> op;
367 typename op::ptr p = { detail::addressof(a), op::ptr::allocate(a), 0 };
368 p.p = new (p.v) op(BOOST_ASIO_MOVE_CAST(Function)static_cast<Function&&>(f), a);
369
370 BOOST_ASIO_HANDLER_CREATION((*context_ptr(), *p.p,(void)0
371 "io_context", context_ptr(), 0, "dispatch"))(void)0;
372
373 context_ptr()->impl_.post_immediate_completion(p.p, false);
374 p.v = p.p = 0;
375}
376
377template <typename Allocator, uintptr_t Bits>
378template <typename Function, typename OtherAllocator>
379void io_context::basic_executor_type<Allocator, Bits>::post(
380 BOOST_ASIO_MOVE_ARG(Function)Function&& f, const OtherAllocator& a) const
381{
382 typedef typename decay<Function>::type function_type;
383
384 // Allocate and construct an operation to wrap the function.
385 typedef detail::executor_op<function_type,
386 OtherAllocator, detail::operation> op;
387 typename op::ptr p = { detail::addressof(a), op::ptr::allocate(a), 0 };
388 p.p = new (p.v) op(BOOST_ASIO_MOVE_CAST(Function)static_cast<Function&&>(f), a);
389
390 BOOST_ASIO_HANDLER_CREATION((*context_ptr(), *p.p,(void)0
391 "io_context", context_ptr(), 0, "post"))(void)0;
392
393 context_ptr()->impl_.post_immediate_completion(p.p, false);
394 p.v = p.p = 0;
395}
396
397template <typename Allocator, uintptr_t Bits>
398template <typename Function, typename OtherAllocator>
399void io_context::basic_executor_type<Allocator, Bits>::defer(
400 BOOST_ASIO_MOVE_ARG(Function)Function&& f, const OtherAllocator& a) const
401{
402 typedef typename decay<Function>::type function_type;
403
404 // Allocate and construct an operation to wrap the function.
405 typedef detail::executor_op<function_type,
406 OtherAllocator, detail::operation> op;
407 typename op::ptr p = { detail::addressof(a), op::ptr::allocate(a), 0 };
408 p.p = new (p.v) op(BOOST_ASIO_MOVE_CAST(Function)static_cast<Function&&>(f), a);
409
410 BOOST_ASIO_HANDLER_CREATION((*context_ptr(), *p.p,(void)0
411 "io_context", context_ptr(), 0, "defer"))(void)0;
412
413 context_ptr()->impl_.post_immediate_completion(p.p, true);
414 p.v = p.p = 0;
415}
416#endif // !defined(BOOST_ASIO_NO_TS_EXECUTORS)
417
418#if !defined(BOOST_ASIO_NO_DEPRECATED)
419inline io_context::work::work(boost::asio::io_context& io_context)
420 : io_context_impl_(io_context.impl_)
421{
422 io_context_impl_.work_started();
423}
424
425inline io_context::work::work(const work& other)
426 : io_context_impl_(other.io_context_impl_)
427{
428 io_context_impl_.work_started();
429}
430
431inline io_context::work::~work()
432{
433 io_context_impl_.work_finished();
434}
435
436inline boost::asio::io_context& io_context::work::get_io_context()
437{
438 return static_cast<boost::asio::io_context&>(io_context_impl_.context());
439}
440#endif // !defined(BOOST_ASIO_NO_DEPRECATED)
441
442inline boost::asio::io_context& io_context::service::get_io_context()
443{
444 return static_cast<boost::asio::io_context&>(context());
445}
446
447} // namespace asio
448} // namespace boost
449
450#include <boost/asio/detail/pop_options.hpp>
451
452#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-2023 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_));
16
Calling 'service_registry::do_use_service'
22
Calling 'service_registry::do_use_service'
30
Returning from 'service_registry::do_use_service'
39
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));
9
Calling 'service_registry::do_use_service'
46
Returning from 'service_registry::do_use_service'
40}
41
42template <typename Service>
43void service_registry::add_service(Service* new_service)
44{
45 execution_context::service::key key;
46 init_key<Service>(key, 0);
47 return do_add_service(key, new_service);
48}
49
50template <typename Service>
51bool service_registry::has_service() const
52{
53 execution_context::service::key key;
54 init_key<Service>(key, 0);
55 return do_has_service(key);
56}
57
58template <typename Service>
59inline void service_registry::init_key(
60 execution_context::service::key& key, ...)
61{
62 init_key_from_id(key, Service::id);
63}
64
65#if !defined(BOOST_ASIO_NO_TYPEID)
66template <typename Service>
67void service_registry::init_key(execution_context::service::key& key,
68 typename enable_if<
69 is_base_of<typename Service::key_type, Service>::value>::type*)
70{
71 key.type_info_ = &typeid(typeid_wrapper<Service>);
72 key.id_ = 0;
73}
74
75template <typename Service>
76void service_registry::init_key_from_id(execution_context::service::key& key,
77 const service_id<Service>& /*id*/)
78{
79 key.type_info_ = &typeid(typeid_wrapper<Service>);
80 key.id_ = 0;
81}
82#endif // !defined(BOOST_ASIO_NO_TYPEID)
83
84template <typename Service, typename Owner>
85execution_context::service* service_registry::create(void* owner)
86{
87 return new Service(*static_cast<Owner*>(owner));
12
Calling constructor for 'reactive_socket_service<boost::asio::ip::tcp>'
19
Calling constructor for 'epoll_reactor'
36
Returning from constructor for 'epoll_reactor'
43
Returning from constructor for 'reactive_socket_service<boost::asio::ip::tcp>'
88}
89
90} // namespace detail
91} // namespace asio
92} // namespace boost
93
94#include <boost/asio/detail/pop_options.hpp>
95
96#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-2023 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 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(execution_context::service* service)
109{
110 delete service;
111}
112
113execution_context::service* service_registry::do_use_service(
114 const execution_context::service::key& key,
115 factory_type factory, void* owner)
116{
117 boost::asio::detail::mutex::scoped_lock lock(mutex_);
23
Calling constructor for 'scoped_lock<boost::asio::detail::posix_mutex>'
27
Returning from constructor for 'scoped_lock<boost::asio::detail::posix_mutex>'
118
119 // First see if there is an existing service object with the given key.
120 execution_context::service* service = first_service_;
121 while (service)
10
Loop condition is false. Execution continues on line 131
17
Loop condition is false. Execution continues on line 131
28
Loop condition is false. Execution continues on line 131
122 {
123 if (keys_match(service->key_, key))
124 return service;
125 service = service->next_;
126 }
127
128 // Create a new service object. The service registry's mutex is not locked
129 // at this time to allow for nested calls into this function from the new
130 // service's constructor.
131 lock.unlock();
132 auto_service_ptr new_service = { factory(owner) };
11
Calling 'service_registry::create'
18
Calling 'service_registry::create'
37
Returning from 'service_registry::create'
44
Returning from 'service_registry::create'
133 new_service.ptr_->key_ = key;
134 lock.lock();
135
136 // Check that nobody else created another service object of the same type
137 // while the lock was released.
138 service = first_service_;
139 while (service)
29
Loop condition is false. Execution continues on line 147
38
Loop condition is false. Execution continues on line 147
45
Loop condition is false. Execution continues on line 147
140 {
141 if (keys_match(service->key_, key))
142 return service;
143 service = service->next_;
144 }
145
146 // Service was successfully initialised, pass ownership to registry.
147 new_service.ptr_->next_ = first_service_;
148 first_service_ = new_service.ptr_;
149 new_service.ptr_ = 0;
150 return first_service_;
151}
152
153void service_registry::do_add_service(
154 const execution_context::service::key& key,
155 execution_context::service* new_service)
156{
157 if (&owner_ != &new_service->context())
158 boost::asio::detail::throw_exception(invalid_service_owner());
159
160 boost::asio::detail::mutex::scoped_lock lock(mutex_);
161
162 // Check if there is an existing service object with the given key.
163 execution_context::service* service = first_service_;
164 while (service)
165 {
166 if (keys_match(service->key_, key))
167 boost::asio::detail::throw_exception(service_already_exists());
168 service = service->next_;
169 }
170
171 // Take ownership of the service object.
172 new_service->key_ = key;
173 new_service->next_ = first_service_;
174 first_service_ = new_service;
175}
176
177bool service_registry::do_has_service(
178 const execution_context::service::key& key) const
179{
180 boost::asio::detail::mutex::scoped_lock lock(mutex_);
181
182 execution_context::service* service = first_service_;
183 while (service)
184 {
185 if (keys_match(service->key_, key))
186 return true;
187 service = service->next_;
188 }
189
190 return false;
191}
192
193} // namespace detail
194} // namespace asio
195} // namespace boost
196
197#include <boost/asio/detail/pop_options.hpp>
198
199#endif // BOOST_ASIO_DETAIL_IMPL_SERVICE_REGISTRY_IPP

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

1//
2// detail/reactive_socket_service.hpp
3// ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
4//
5// Copyright (c) 2003-2023 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)
13
Calling constructor for 'reactive_socket_service_base'
42
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) BOOST_ASIO_NOEXCEPTnoexcept
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
(::std::source_location::current()); (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
(::std::source_location::current()); (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
(::std::source_location::current()); (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
(::std::source_location::current()); (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
(::std::source_location::current()); (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
(::std::source_location::current()); (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
(::std::source_location::current()); (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
(::std::source_location::current()); (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
(::std::source_location::current()); (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
(::std::source_location::current()); (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 typename associated_cancellation_slot<Handler>::type 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, &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 typename associated_cancellation_slot<Handler>::type 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, &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
(::std::source_location::current()); (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
(::std::source_location::current()); (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 typename associated_cancellation_slot<Handler>::type 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, &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 typename associated_cancellation_slot<Handler>::type 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, &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
(::std::source_location::current()); (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
(::std::source_location::current()); (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 typename associated_cancellation_slot<Handler>::type 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#if defined(BOOST_ASIO_HAS_MOVE1)
546 // Start an asynchronous accept. The peer_endpoint object must be valid until
547 // the accept's handler is invoked.
548 template <typename PeerIoExecutor, typename Handler, typename IoExecutor>
549 void async_move_accept(implementation_type& impl,
550 const PeerIoExecutor& peer_io_ex, endpoint_type* peer_endpoint,
551 Handler& handler, const IoExecutor& io_ex)
552 {
553 bool is_continuation =
554 boost_asio_handler_cont_helpers::is_continuation(handler);
555
556 typename associated_cancellation_slot<Handler>::type slot
557 = boost::asio::get_associated_cancellation_slot(handler);
558
559 // Allocate and construct an operation to wrap the handler.
560 typedef reactive_socket_move_accept_op<Protocol,
561 PeerIoExecutor, Handler, IoExecutor> op;
562 typename op::ptr p = { boost::asio::detail::addressof(handler),
563 op::ptr::allocate(handler), 0 };
564 p.p = new (p.v) op(success_ec_, peer_io_ex, impl.socket_,
565 impl.state_, impl.protocol_, peer_endpoint, handler, io_ex);
566
567 // Optionally register for per-operation cancellation.
568 if (slot.is_connected())
569 {
570 p.p->cancellation_key_ =
571 &slot.template emplace<reactor_op_cancellation>(
572 &reactor_, &impl.reactor_data_, impl.socket_, reactor::read_op);
573 }
574
575 BOOST_ASIO_HANDLER_CREATION((reactor_.context(), *p.p, "socket",(void)0
576 &impl, impl.socket_, "async_accept"))(void)0;
577
578 start_accept_op(impl, p.p, is_continuation, false, &io_ex, 0);
579 p.v = p.p = 0;
580 }
581#endif // defined(BOOST_ASIO_HAS_MOVE)
582
583 // Connect the socket to the specified endpoint.
584 boost::system::error_code connect(implementation_type& impl,
585 const endpoint_type& peer_endpoint, boost::system::error_code& ec)
586 {
587 socket_ops::sync_connect(impl.socket_,
588 peer_endpoint.data(), peer_endpoint.size(), ec);
589 BOOST_ASIO_ERROR_LOCATION(ec)do { static constexpr boost::source_location loc = ::boost::source_location
(::std::source_location::current()); (ec).assign((ec), &loc
); } while (false)
;
590 return ec;
591 }
592
593 // Start an asynchronous connect.
594 template <typename Handler, typename IoExecutor>
595 void async_connect(implementation_type& impl,
596 const endpoint_type& peer_endpoint,
597 Handler& handler, const IoExecutor& io_ex)
598 {
599 bool is_continuation =
600 boost_asio_handler_cont_helpers::is_continuation(handler);
601
602 typename associated_cancellation_slot<Handler>::type slot
603 = boost::asio::get_associated_cancellation_slot(handler);
604
605 // Allocate and construct an operation to wrap the handler.
606 typedef reactive_socket_connect_op<Handler, IoExecutor> op;
607 typename op::ptr p = { boost::asio::detail::addressof(handler),
608 op::ptr::allocate(handler), 0 };
609 p.p = new (p.v) op(success_ec_, impl.socket_, handler, io_ex);
610
611 // Optionally register for per-operation cancellation.
612 if (slot.is_connected())
613 {
614 p.p->cancellation_key_ =
615 &slot.template emplace<reactor_op_cancellation>(
616 &reactor_, &impl.reactor_data_, impl.socket_, reactor::connect_op);
617 }
618
619 BOOST_ASIO_HANDLER_CREATION((reactor_.context(), *p.p, "socket",(void)0
620 &impl, impl.socket_, "async_connect"))(void)0;
621
622 start_connect_op(impl, p.p, is_continuation,
623 peer_endpoint.data(), peer_endpoint.size(), &io_ex, 0);
624 p.v = p.p = 0;
625 }
626};
627
628} // namespace detail
629} // namespace asio
630} // namespace boost
631
632#include <boost/asio/detail/pop_options.hpp>
633
634#endif // !defined(BOOST_ASIO_HAS_IOCP)
635 // && !defined(BOOST_ASIO_HAS_IO_URING_AS_DEFAULT)
636
637#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-2023 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/detail/reactive_socket_service_base.hpp>
25
26#include <boost/asio/detail/push_options.hpp>
27
28namespace boost {
29namespace asio {
30namespace detail {
31
32reactive_socket_service_base::reactive_socket_service_base(
33 execution_context& context)
34 : reactor_(use_service<reactor>(context))
14
Calling 'use_service<boost::asio::detail::epoll_reactor>'
41
Returning from 'use_service<boost::asio::detail::epoll_reactor>'
35{
36 reactor_.init_task();
37}
38
39void reactive_socket_service_base::base_shutdown()
40{
41}
42
43void reactive_socket_service_base::construct(
44 reactive_socket_service_base::base_implementation_type& impl)
45{
46 impl.socket_ = invalid_socket;
47 impl.state_ = 0;
48 impl.reactor_data_ = reactor::per_descriptor_data();
49}
50
51void reactive_socket_service_base::base_move_construct(
52 reactive_socket_service_base::base_implementation_type& impl,
53 reactive_socket_service_base::base_implementation_type& other_impl)
54 BOOST_ASIO_NOEXCEPTnoexcept
55{
56 impl.socket_ = other_impl.socket_;
57 other_impl.socket_ = invalid_socket;
58
59 impl.state_ = other_impl.state_;
60 other_impl.state_ = 0;
61
62 reactor_.move_descriptor(impl.socket_,
63 impl.reactor_data_, other_impl.reactor_data_);
64}
65
66void reactive_socket_service_base::base_move_assign(
67 reactive_socket_service_base::base_implementation_type& impl,
68 reactive_socket_service_base& other_service,
69 reactive_socket_service_base::base_implementation_type& other_impl)
70{
71 destroy(impl);
72
73 impl.socket_ = other_impl.socket_;
74 other_impl.socket_ = invalid_socket;
75
76 impl.state_ = other_impl.state_;
77 other_impl.state_ = 0;
78
79 other_service.reactor_.move_descriptor(impl.socket_,
80 impl.reactor_data_, other_impl.reactor_data_);
81}
82
83void reactive_socket_service_base::destroy(
84 reactive_socket_service_base::base_implementation_type& impl)
85{
86 if (impl.socket_ != invalid_socket)
87 {
88 BOOST_ASIO_HANDLER_OPERATION((reactor_.context(),(void)0
89 "socket", &impl, impl.socket_, "close"))(void)0;
90
91 reactor_.deregister_descriptor(impl.socket_, impl.reactor_data_,
92 (impl.state_ & socket_ops::possible_dup) == 0);
93
94 boost::system::error_code ignored_ec;
95 socket_ops::close(impl.socket_, impl.state_, true, ignored_ec);
96
97 reactor_.cleanup_descriptor_data(impl.reactor_data_);
98 }
99}
100
101boost::system::error_code reactive_socket_service_base::close(
102 reactive_socket_service_base::base_implementation_type& impl,
103 boost::system::error_code& ec)
104{
105 if (is_open(impl))
106 {
107 BOOST_ASIO_HANDLER_OPERATION((reactor_.context(),(void)0
108 "socket", &impl, impl.socket_, "close"))(void)0;
109
110 reactor_.deregister_descriptor(impl.socket_, impl.reactor_data_,
111 (impl.state_ & socket_ops::possible_dup) == 0);
112
113 socket_ops::close(impl.socket_, impl.state_, false, ec);
114
115 reactor_.cleanup_descriptor_data(impl.reactor_data_);
116 }
117 else
118 {
119 ec = boost::system::error_code();
120 }
121
122 // The descriptor is closed by the OS even if close() returns an error.
123 //
124 // (Actually, POSIX says the state of the descriptor is unspecified. On
125 // Linux the descriptor is apparently closed anyway; e.g. see
126 // http://lkml.org/lkml/2005/9/10/129
127 // We'll just have to assume that other OSes follow the same behaviour. The
128 // known exception is when Windows's closesocket() function fails with
129 // WSAEWOULDBLOCK, but this case is handled inside socket_ops::close().
130 construct(impl);
131
132 return ec;
133}
134
135socket_type reactive_socket_service_base::release(
136 reactive_socket_service_base::base_implementation_type& impl,
137 boost::system::error_code& ec)
138{
139 if (!is_open(impl))
140 {
141 ec = boost::asio::error::bad_descriptor;
142 return invalid_socket;
143 }
144
145 BOOST_ASIO_HANDLER_OPERATION((reactor_.context(),(void)0
146 "socket", &impl, impl.socket_, "release"))(void)0;
147
148 reactor_.deregister_descriptor(impl.socket_, impl.reactor_data_, false);
149 reactor_.cleanup_descriptor_data(impl.reactor_data_);
150 socket_type sock = impl.socket_;
151 construct(impl);
152 ec = boost::system::error_code();
153 return sock;
154}
155
156boost::system::error_code reactive_socket_service_base::cancel(
157 reactive_socket_service_base::base_implementation_type& impl,
158 boost::system::error_code& ec)
159{
160 if (!is_open(impl))
161 {
162 ec = boost::asio::error::bad_descriptor;
163 return ec;
164 }
165
166 BOOST_ASIO_HANDLER_OPERATION((reactor_.context(),(void)0
167 "socket", &impl, impl.socket_, "cancel"))(void)0;
168
169 reactor_.cancel_ops(impl.socket_, impl.reactor_data_);
170 ec = boost::system::error_code();
171 return ec;
172}
173
174boost::system::error_code reactive_socket_service_base::do_open(
175 reactive_socket_service_base::base_implementation_type& impl,
176 int af, int type, int protocol, boost::system::error_code& ec)
177{
178 if (is_open(impl))
179 {
180 ec = boost::asio::error::already_open;
181 return ec;
182 }
183
184 socket_holder sock(socket_ops::socket(af, type, protocol, ec));
185 if (sock.get() == invalid_socket)
186 return ec;
187
188 if (int err = reactor_.register_descriptor(sock.get(), impl.reactor_data_))
189 {
190 ec = boost::system::error_code(err,
191 boost::asio::error::get_system_category());
192 return ec;
193 }
194
195 impl.socket_ = sock.release();
196 switch (type)
197 {
198 case SOCK_STREAMSOCK_STREAM: impl.state_ = socket_ops::stream_oriented; break;
199 case SOCK_DGRAMSOCK_DGRAM: impl.state_ = socket_ops::datagram_oriented; break;
200 default: impl.state_ = 0; break;
201 }
202 ec = boost::system::error_code();
203 return ec;
204}
205
206boost::system::error_code reactive_socket_service_base::do_assign(
207 reactive_socket_service_base::base_implementation_type& impl, int type,
208 const reactive_socket_service_base::native_handle_type& native_socket,
209 boost::system::error_code& ec)
210{
211 if (is_open(impl))
212 {
213 ec = boost::asio::error::already_open;
214 return ec;
215 }
216
217 if (int err = reactor_.register_descriptor(
218 native_socket, impl.reactor_data_))
219 {
220 ec = boost::system::error_code(err,
221 boost::asio::error::get_system_category());
222 return ec;
223 }
224
225 impl.socket_ = native_socket;
226 switch (type)
227 {
228 case SOCK_STREAMSOCK_STREAM: impl.state_ = socket_ops::stream_oriented; break;
229 case SOCK_DGRAMSOCK_DGRAM: impl.state_ = socket_ops::datagram_oriented; break;
230 default: impl.state_ = 0; break;
231 }
232 impl.state_ |= socket_ops::possible_dup;
233 ec = boost::system::error_code();
234 return ec;
235}
236
237void reactive_socket_service_base::do_start_op(
238 reactive_socket_service_base::base_implementation_type& impl, int op_type,
239 reactor_op* op, bool is_continuation, bool is_non_blocking, bool noop,
240 void (*on_immediate)(operation* op, bool, const void*),
241 const void* immediate_arg)
242{
243 if (!noop)
244 {
245 if ((impl.state_ & socket_ops::non_blocking)
246 || socket_ops::set_internal_non_blocking(
247 impl.socket_, impl.state_, true, op->ec_))
248 {
249 reactor_.start_op(op_type, impl.socket_, impl.reactor_data_, op,
250 is_continuation, is_non_blocking, on_immediate, immediate_arg);
251 return;
252 }
253 }
254
255 on_immediate(op, is_continuation, immediate_arg);
256}
257
258void reactive_socket_service_base::do_start_accept_op(
259 reactive_socket_service_base::base_implementation_type& impl,
260 reactor_op* op, bool is_continuation, bool peer_is_open,
261 void (*on_immediate)(operation* op, bool, const void*),
262 const void* immediate_arg)
263{
264 if (!peer_is_open)
265 {
266 do_start_op(impl, reactor::read_op, op, is_continuation,
267 true, false, on_immediate, immediate_arg);
268 }
269 else
270 {
271 op->ec_ = boost::asio::error::already_open;
272 on_immediate(op, is_continuation, immediate_arg);
273 }
274}
275
276void reactive_socket_service_base::do_start_connect_op(
277 reactive_socket_service_base::base_implementation_type& impl,
278 reactor_op* op, bool is_continuation, const void* addr, size_t addrlen,
279 void (*on_immediate)(operation* op, bool, const void*),
280 const void* immediate_arg)
281{
282 if ((impl.state_ & socket_ops::non_blocking)
283 || socket_ops::set_internal_non_blocking(
284 impl.socket_, impl.state_, true, op->ec_))
285 {
286 if (socket_ops::connect(impl.socket_, addr, addrlen, op->ec_) != 0)
287 {
288 if (op->ec_ == boost::asio::error::in_progress
289 || op->ec_ == boost::asio::error::would_block)
290 {
291 op->ec_ = boost::system::error_code();
292 reactor_.start_op(reactor::connect_op, impl.socket_, impl.reactor_data_,
293 op, is_continuation, false, on_immediate, immediate_arg);
294 return;
295 }
296 }
297 }
298
299 on_immediate(op, is_continuation, immediate_arg);
300}
301
302} // namespace detail
303} // namespace asio
304} // namespace boost
305
306#include <boost/asio/detail/pop_options.hpp>
307
308#endif // !defined(BOOST_ASIO_HAS_IOCP)
309 // && !defined(BOOST_ASIO_WINDOWS_RUNTIME)
310 // && !defined(BOOST_ASIO_HAS_IO_URING_AS_DEFAULT)
311
312#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-2023 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 <boost/asio/detail/handler_type_requirements.hpp>
19#include <boost/asio/detail/scoped_ptr.hpp>
20#include <boost/asio/detail/service_registry.hpp>
21
22#include <boost/asio/detail/push_options.hpp>
23
24namespace boost {
25namespace asio {
26
27#if !defined(GENERATING_DOCUMENTATION)
28
29template <typename Service>
30inline Service& use_service(execution_context& e)
31{
32 // Check that Service meets the necessary type requirements.
33 (void)static_cast<execution_context::service*>(static_cast<Service*>(0));
34
35 return e.service_registry_->template use_service<Service>();
15
Calling 'service_registry::use_service'
21
Calling 'service_registry::use_service'
31
Returning from 'service_registry::use_service'
40
Returning from 'service_registry::use_service'
36}
37
38#if defined(BOOST_ASIO_HAS_VARIADIC_TEMPLATES1)
39
40template <typename Service, typename... Args>
41Service& make_service(execution_context& e, BOOST_ASIO_MOVE_ARG(Args)Args&&... args)
42{
43 detail::scoped_ptr<Service> svc(
44 new Service(e, BOOST_ASIO_MOVE_CAST(Args)static_cast<Args&&>(args)...));
45 e.service_registry_->template add_service<Service>(svc.get());
46 Service& result = *svc;
47 svc.release();
48 return result;
49}
50
51#else // defined(BOOST_ASIO_HAS_VARIADIC_TEMPLATES)
52
53template <typename Service>
54Service& make_service(execution_context& e)
55{
56 detail::scoped_ptr<Service> svc(new Service(e));
57 e.service_registry_->template add_service<Service>(svc.get());
58 Service& result = *svc;
59 svc.release();
60 return result;
61}
62
63#define BOOST_ASIO_PRIVATE_MAKE_SERVICE_DEF(n) \
64 template <typename Service, BOOST_ASIO_VARIADIC_TPARAMS(n)> \
65 Service& make_service(execution_context& e, \
66 BOOST_ASIO_VARIADIC_MOVE_PARAMS(n)) \
67 { \
68 detail::scoped_ptr<Service> svc( \
69 new Service(e, BOOST_ASIO_VARIADIC_MOVE_ARGS(n))); \
70 e.service_registry_->template add_service<Service>(svc.get()); \
71 Service& result = *svc; \
72 svc.release(); \
73 return result; \
74 } \
75 /**/
76 BOOST_ASIO_VARIADIC_GENERATE(BOOST_ASIO_PRIVATE_MAKE_SERVICE_DEF)
77#undef BOOST_ASIO_PRIVATE_MAKE_SERVICE_DEF
78
79#endif // defined(BOOST_ASIO_HAS_VARIADIC_TEMPLATES)
80
81template <typename Service>
82inline void add_service(execution_context& e, Service* svc)
83{
84 // Check that Service meets the necessary type requirements.
85 (void)static_cast<execution_context::service*>(static_cast<Service*>(0));
86
87 e.service_registry_->template add_service<Service>(svc);
88}
89
90template <typename Service>
91inline bool has_service(execution_context& e)
92{
93 // Check that Service meets the necessary type requirements.
94 (void)static_cast<execution_context::service*>(static_cast<Service*>(0));
95
96 return e.service_registry_->template has_service<Service>();
97}
98
99#endif // !defined(GENERATING_DOCUMENTATION)
100
101inline execution_context& execution_context::service::context()
102{
103 return owner_;
104}
105
106} // namespace asio
107} // namespace boost
108
109#include <boost/asio/detail/pop_options.hpp>
110
111#endif // BOOST_ASIO_IMPL_EXECUTION_CONTEXT_HPP

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

1//
2// detail/impl/epoll_reactor.ipp
3// ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
4//
5// Copyright (c) 2003-2023 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_EPOLL_REACTOR_IPP
12#define BOOST_ASIO_DETAIL_IMPL_EPOLL_REACTOR_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_EPOLL1)
21
22#include <cstddef>
23#include <sys/epoll.h>
24#include <boost/asio/detail/epoll_reactor.hpp>
25#include <boost/asio/detail/scheduler.hpp>
26#include <boost/asio/detail/throw_error.hpp>
27#include <boost/asio/error.hpp>
28
29#if defined(BOOST_ASIO_HAS_TIMERFD1)
30# include <sys/timerfd.h>
31#endif // defined(BOOST_ASIO_HAS_TIMERFD)
32
33#include <boost/asio/detail/push_options.hpp>
34
35namespace boost {
36namespace asio {
37namespace detail {
38
39epoll_reactor::epoll_reactor(boost::asio::execution_context& ctx)
40 : execution_context_service_base<epoll_reactor>(ctx),
41 scheduler_(use_service<scheduler>(ctx)),
20
Calling 'use_service<boost::asio::detail::scheduler>'
32
Returning from 'use_service<boost::asio::detail::scheduler>'
42 mutex_(BOOST_ASIO_CONCURRENCY_HINT_IS_LOCKING((((static_cast<unsigned>(scheduler_.concurrency_hint())
& (0xFFFF0000u | 0x2u)) ^ 0xA5100000u) != 0)
33
Assuming the condition is false
43 REACTOR_REGISTRATION, scheduler_.concurrency_hint())(((static_cast<unsigned>(scheduler_.concurrency_hint())
& (0xFFFF0000u | 0x2u)) ^ 0xA5100000u) != 0)
),
44 interrupter_(),
45 epoll_fd_(do_epoll_create()),
46 timer_fd_(do_timerfd_create()),
47 shutdown_(false),
48 registered_descriptors_mutex_(mutex_.enabled())
49{
50 // Add the interrupter's descriptor to epoll.
51 epoll_event ev = { 0, { 0 } };
52 ev.events = EPOLLINEPOLLIN | EPOLLERREPOLLERR | EPOLLETEPOLLET;
53 ev.data.ptr = &interrupter_;
54 epoll_ctl(epoll_fd_, EPOLL_CTL_ADD1, interrupter_.read_descriptor(), &ev);
55 interrupter_.interrupt();
56
57 // Add the timer descriptor to epoll.
58 if (timer_fd_ != -1)
34
Assuming the condition is false
35
Taking false branch
59 {
60 ev.events = EPOLLINEPOLLIN | EPOLLERREPOLLERR;
61 ev.data.ptr = &timer_fd_;
62 epoll_ctl(epoll_fd_, EPOLL_CTL_ADD1, timer_fd_, &ev);
63 }
64}
65
66epoll_reactor::~epoll_reactor()
67{
68 if (epoll_fd_ != -1)
69 close(epoll_fd_);
70 if (timer_fd_ != -1)
71 close(timer_fd_);
72}
73
74void epoll_reactor::shutdown()
75{
76 mutex::scoped_lock lock(mutex_);
77 shutdown_ = true;
78 lock.unlock();
79
80 op_queue<operation> ops;
81
82 while (descriptor_state* state = registered_descriptors_.first())
83 {
84 for (int i = 0; i < max_ops; ++i)
85 ops.push(state->op_queue_[i]);
86 state->shutdown_ = true;
87 registered_descriptors_.free(state);
88 }
89
90 timer_queues_.get_all_timers(ops);
91
92 scheduler_.abandon_operations(ops);
93}
94
95void epoll_reactor::notify_fork(
96 boost::asio::execution_context::fork_event fork_ev)
97{
98 if (fork_ev == boost::asio::execution_context::fork_child)
99 {
100 if (epoll_fd_ != -1)
101 ::close(epoll_fd_);
102 epoll_fd_ = -1;
103 epoll_fd_ = do_epoll_create();
104
105 if (timer_fd_ != -1)
106 ::close(timer_fd_);
107 timer_fd_ = -1;
108 timer_fd_ = do_timerfd_create();
109
110 interrupter_.recreate();
111
112 // Add the interrupter's descriptor to epoll.
113 epoll_event ev = { 0, { 0 } };
114 ev.events = EPOLLINEPOLLIN | EPOLLERREPOLLERR | EPOLLETEPOLLET;
115 ev.data.ptr = &interrupter_;
116 epoll_ctl(epoll_fd_, EPOLL_CTL_ADD1, interrupter_.read_descriptor(), &ev);
117 interrupter_.interrupt();
118
119 // Add the timer descriptor to epoll.
120 if (timer_fd_ != -1)
121 {
122 ev.events = EPOLLINEPOLLIN | EPOLLERREPOLLERR;
123 ev.data.ptr = &timer_fd_;
124 epoll_ctl(epoll_fd_, EPOLL_CTL_ADD1, timer_fd_, &ev);
125 }
126
127 update_timeout();
128
129 // Re-register all descriptors with epoll.
130 mutex::scoped_lock descriptors_lock(registered_descriptors_mutex_);
131 for (descriptor_state* state = registered_descriptors_.first();
132 state != 0; state = state->next_)
133 {
134 ev.events = state->registered_events_;
135 ev.data.ptr = state;
136 int result = epoll_ctl(epoll_fd_, EPOLL_CTL_ADD1, state->descriptor_, &ev);
137 if (result != 0)
138 {
139 boost::system::error_code ec(errno(*__errno_location ()),
140 boost::asio::error::get_system_category());
141 boost::asio::detail::throw_error(ec, "epoll re-registration");
142 }
143 }
144 }
145}
146
147void epoll_reactor::init_task()
148{
149 scheduler_.init_task();
150}
151
152int epoll_reactor::register_descriptor(socket_type descriptor,
153 epoll_reactor::per_descriptor_data& descriptor_data)
154{
155 descriptor_data = allocate_descriptor_state();
156
157 BOOST_ASIO_HANDLER_REACTOR_REGISTRATION(((void)0
158 context(), static_cast<uintmax_t>(descriptor),(void)0
159 reinterpret_cast<uintmax_t>(descriptor_data)))(void)0;
160
161 {
162 mutex::scoped_lock descriptor_lock(descriptor_data->mutex_);
163
164 descriptor_data->reactor_ = this;
165 descriptor_data->descriptor_ = descriptor;
166 descriptor_data->shutdown_ = false;
167 for (int i = 0; i < max_ops; ++i)
168 descriptor_data->try_speculative_[i] = true;
169 }
170
171 epoll_event ev = { 0, { 0 } };
172 ev.events = EPOLLINEPOLLIN | EPOLLERREPOLLERR | EPOLLHUPEPOLLHUP | EPOLLPRIEPOLLPRI | EPOLLETEPOLLET;
173 descriptor_data->registered_events_ = ev.events;
174 ev.data.ptr = descriptor_data;
175 int result = epoll_ctl(epoll_fd_, EPOLL_CTL_ADD1, descriptor, &ev);
176 if (result != 0)
177 {
178 if (errno(*__errno_location ()) == EPERM1)
179 {
180 // This file descriptor type is not supported by epoll. However, if it is
181 // a regular file then operations on it will not block. We will allow
182 // this descriptor to be used and fail later if an operation on it would
183 // otherwise require a trip through the reactor.
184 descriptor_data->registered_events_ = 0;
185 return 0;
186 }
187 return errno(*__errno_location ());
188 }
189
190 return 0;
191}
192
193int epoll_reactor::register_internal_descriptor(
194 int op_type, socket_type descriptor,
195 epoll_reactor::per_descriptor_data& descriptor_data, reactor_op* op)
196{
197 descriptor_data = allocate_descriptor_state();
198
199 BOOST_ASIO_HANDLER_REACTOR_REGISTRATION(((void)0
200 context(), static_cast<uintmax_t>(descriptor),(void)0
201 reinterpret_cast<uintmax_t>(descriptor_data)))(void)0;
202
203 {
204 mutex::scoped_lock descriptor_lock(descriptor_data->mutex_);
205
206 descriptor_data->reactor_ = this;
207 descriptor_data->descriptor_ = descriptor;
208 descriptor_data->shutdown_ = false;
209 descriptor_data->op_queue_[op_type].push(op);
210 for (int i = 0; i < max_ops; ++i)
211 descriptor_data->try_speculative_[i] = true;
212 }
213
214 epoll_event ev = { 0, { 0 } };
215 ev.events = EPOLLINEPOLLIN | EPOLLERREPOLLERR | EPOLLHUPEPOLLHUP | EPOLLPRIEPOLLPRI | EPOLLETEPOLLET;
216 descriptor_data->registered_events_ = ev.events;
217 ev.data.ptr = descriptor_data;
218 int result = epoll_ctl(epoll_fd_, EPOLL_CTL_ADD1, descriptor, &ev);
219 if (result != 0)
220 return errno(*__errno_location ());
221
222 return 0;
223}
224
225void epoll_reactor::move_descriptor(socket_type,
226 epoll_reactor::per_descriptor_data& target_descriptor_data,
227 epoll_reactor::per_descriptor_data& source_descriptor_data)
228{
229 target_descriptor_data = source_descriptor_data;
230 source_descriptor_data = 0;
231}
232
233void epoll_reactor::call_post_immediate_completion(
234 operation* op, bool is_continuation, const void* self)
235{
236 static_cast<const epoll_reactor*>(self)->post_immediate_completion(
237 op, is_continuation);
238}
239
240void epoll_reactor::start_op(int op_type, socket_type descriptor,
241 epoll_reactor::per_descriptor_data& descriptor_data, reactor_op* op,
242 bool is_continuation, bool allow_speculative,
243 void (*on_immediate)(operation*, bool, const void*),
244 const void* immediate_arg)
245{
246 if (!descriptor_data)
247 {
248 op->ec_ = boost::asio::error::bad_descriptor;
249 on_immediate(op, is_continuation, immediate_arg);
250 return;
251 }
252
253 mutex::scoped_lock descriptor_lock(descriptor_data->mutex_);
254
255 if (descriptor_data->shutdown_)
256 {
257 on_immediate(op, is_continuation, immediate_arg);
258 return;
259 }
260
261 if (descriptor_data->op_queue_[op_type].empty())
262 {
263 if (allow_speculative
264 && (op_type != read_op
265 || descriptor_data->op_queue_[except_op].empty()))
266 {
267 if (descriptor_data->try_speculative_[op_type])
268 {
269 if (reactor_op::status status = op->perform())
270 {
271 if (status == reactor_op::done_and_exhausted)
272 if (descriptor_data->registered_events_ != 0)
273 descriptor_data->try_speculative_[op_type] = false;
274 descriptor_lock.unlock();
275 on_immediate(op, is_continuation, immediate_arg);
276 return;
277 }
278 }
279
280 if (descriptor_data->registered_events_ == 0)
281 {
282 op->ec_ = boost::asio::error::operation_not_supported;
283 on_immediate(op, is_continuation, immediate_arg);
284 return;
285 }
286
287 if (op_type == write_op)
288 {
289 if ((descriptor_data->registered_events_ & EPOLLOUTEPOLLOUT) == 0)
290 {
291 epoll_event ev = { 0, { 0 } };
292 ev.events = descriptor_data->registered_events_ | EPOLLOUTEPOLLOUT;
293 ev.data.ptr = descriptor_data;
294 if (epoll_ctl(epoll_fd_, EPOLL_CTL_MOD3, descriptor, &ev) == 0)
295 {
296 descriptor_data->registered_events_ |= ev.events;
297 }
298 else
299 {
300 op->ec_ = boost::system::error_code(errno(*__errno_location ()),
301 boost::asio::error::get_system_category());
302 on_immediate(op, is_continuation, immediate_arg);
303 return;
304 }
305 }
306 }
307 }
308 else if (descriptor_data->registered_events_ == 0)
309 {
310 op->ec_ = boost::asio::error::operation_not_supported;
311 on_immediate(op, is_continuation, immediate_arg);
312 return;
313 }
314 else
315 {
316 if (op_type == write_op)
317 {
318 descriptor_data->registered_events_ |= EPOLLOUTEPOLLOUT;
319 }
320
321 epoll_event ev = { 0, { 0 } };
322 ev.events = descriptor_data->registered_events_;
323 ev.data.ptr = descriptor_data;
324 epoll_ctl(epoll_fd_, EPOLL_CTL_MOD3, descriptor, &ev);
325 }
326 }
327
328 descriptor_data->op_queue_[op_type].push(op);
329 scheduler_.work_started();
330}
331
332void epoll_reactor::cancel_ops(socket_type,
333 epoll_reactor::per_descriptor_data& descriptor_data)
334{
335 if (!descriptor_data)
336 return;
337
338 mutex::scoped_lock descriptor_lock(descriptor_data->mutex_);
339
340 op_queue<operation> ops;
341 for (int i = 0; i < max_ops; ++i)
342 {
343 while (reactor_op* op = descriptor_data->op_queue_[i].front())
344 {
345 op->ec_ = boost::asio::error::operation_aborted;
346 descriptor_data->op_queue_[i].pop();
347 ops.push(op);
348 }
349 }
350
351 descriptor_lock.unlock();
352
353 scheduler_.post_deferred_completions(ops);
354}
355
356void epoll_reactor::cancel_ops_by_key(socket_type,
357 epoll_reactor::per_descriptor_data& descriptor_data,
358 int op_type, void* cancellation_key)
359{
360 if (!descriptor_data)
361 return;
362
363 mutex::scoped_lock descriptor_lock(descriptor_data->mutex_);
364
365 op_queue<operation> ops;
366 op_queue<reactor_op> other_ops;
367 while (reactor_op* op = descriptor_data->op_queue_[op_type].front())
368 {
369 descriptor_data->op_queue_[op_type].pop();
370 if (op->cancellation_key_ == cancellation_key)
371 {
372 op->ec_ = boost::asio::error::operation_aborted;
373 ops.push(op);
374 }
375 else
376 other_ops.push(op);
377 }
378 descriptor_data->op_queue_[op_type].push(other_ops);
379
380 descriptor_lock.unlock();
381
382 scheduler_.post_deferred_completions(ops);
383}
384
385void epoll_reactor::deregister_descriptor(socket_type descriptor,
386 epoll_reactor::per_descriptor_data& descriptor_data, bool closing)
387{
388 if (!descriptor_data)
389 return;
390
391 mutex::scoped_lock descriptor_lock(descriptor_data->mutex_);
392
393 if (!descriptor_data->shutdown_)
394 {
395 if (closing)
396 {
397 // The descriptor will be automatically removed from the epoll set when
398 // it is closed.
399 }
400 else if (descriptor_data->registered_events_ != 0)
401 {
402 epoll_event ev = { 0, { 0 } };
403 epoll_ctl(epoll_fd_, EPOLL_CTL_DEL2, descriptor, &ev);
404 }
405
406 op_queue<operation> ops;
407 for (int i = 0; i < max_ops; ++i)
408 {
409 while (reactor_op* op = descriptor_data->op_queue_[i].front())
410 {
411 op->ec_ = boost::asio::error::operation_aborted;
412 descriptor_data->op_queue_[i].pop();
413 ops.push(op);
414 }
415 }
416
417 descriptor_data->descriptor_ = -1;
418 descriptor_data->shutdown_ = true;
419
420 descriptor_lock.unlock();
421
422 BOOST_ASIO_HANDLER_REACTOR_DEREGISTRATION(((void)0
423 context(), static_cast<uintmax_t>(descriptor),(void)0
424 reinterpret_cast<uintmax_t>(descriptor_data)))(void)0;
425
426 scheduler_.post_deferred_completions(ops);
427
428 // Leave descriptor_data set so that it will be freed by the subsequent
429 // call to cleanup_descriptor_data.
430 }
431 else
432 {
433 // We are shutting down, so prevent cleanup_descriptor_data from freeing
434 // the descriptor_data object and let the destructor free it instead.
435 descriptor_data = 0;
436 }
437}
438
439void epoll_reactor::deregister_internal_descriptor(socket_type descriptor,
440 epoll_reactor::per_descriptor_data& descriptor_data)
441{
442 if (!descriptor_data)
443 return;
444
445 mutex::scoped_lock descriptor_lock(descriptor_data->mutex_);
446
447 if (!descriptor_data->shutdown_)
448 {
449 epoll_event ev = { 0, { 0 } };
450 epoll_ctl(epoll_fd_, EPOLL_CTL_DEL2, descriptor, &ev);
451
452 op_queue<operation> ops;
453 for (int i = 0; i < max_ops; ++i)
454 ops.push(descriptor_data->op_queue_[i]);
455
456 descriptor_data->descriptor_ = -1;
457 descriptor_data->shutdown_ = true;
458
459 descriptor_lock.unlock();
460
461 BOOST_ASIO_HANDLER_REACTOR_DEREGISTRATION(((void)0
462 context(), static_cast<uintmax_t>(descriptor),(void)0
463 reinterpret_cast<uintmax_t>(descriptor_data)))(void)0;
464
465 // Leave descriptor_data set so that it will be freed by the subsequent
466 // call to cleanup_descriptor_data.
467 }
468 else
469 {
470 // We are shutting down, so prevent cleanup_descriptor_data from freeing
471 // the descriptor_data object and let the destructor free it instead.
472 descriptor_data = 0;
473 }
474}
475
476void epoll_reactor::cleanup_descriptor_data(
477 per_descriptor_data& descriptor_data)
478{
479 if (descriptor_data)
480 {
481 free_descriptor_state(descriptor_data);
482 descriptor_data = 0;
483 }
484}
485
486void epoll_reactor::run(long usec, op_queue<operation>& ops)
487{
488 // This code relies on the fact that the scheduler queues the reactor task
489 // behind all descriptor operations generated by this function. This means,
490 // that by the time we reach this point, any previously returned descriptor
491 // operations have already been dequeued. Therefore it is now safe for us to
492 // reuse and return them for the scheduler to queue again.
493
494 // Calculate timeout. Check the timer queues only if timerfd is not in use.
495 int timeout;
496 if (usec == 0)
497 timeout = 0;
498 else
499 {
500 timeout = (usec < 0) ? -1 : ((usec - 1) / 1000 + 1);
501 if (timer_fd_ == -1)
502 {
503 mutex::scoped_lock lock(mutex_);
504 timeout = get_timeout(timeout);
505 }
506 }
507
508 // Block on the epoll descriptor.
509 epoll_event events[128];
510 int num_events = epoll_wait(epoll_fd_, events, 128, timeout);
511
512#if defined(BOOST_ASIO_ENABLE_HANDLER_TRACKING)
513 // Trace the waiting events.
514 for (int i = 0; i < num_events; ++i)
515 {
516 void* ptr = events[i].data.ptr;
517 if (ptr == &interrupter_)
518 {
519 // Ignore.
520 }
521# if defined(BOOST_ASIO_HAS_TIMERFD1)
522 else if (ptr == &timer_fd_)
523 {
524 // Ignore.
525 }
526# endif // defined(BOOST_ASIO_HAS_TIMERFD)
527 else
528 {
529 unsigned event_mask = 0;
530 if ((events[i].events & EPOLLINEPOLLIN) != 0)
531 event_mask |= BOOST_ASIO_HANDLER_REACTOR_READ_EVENT0;
532 if ((events[i].events & EPOLLOUTEPOLLOUT))
533 event_mask |= BOOST_ASIO_HANDLER_REACTOR_WRITE_EVENT0;
534 if ((events[i].events & (EPOLLERREPOLLERR | EPOLLHUPEPOLLHUP)) != 0)
535 event_mask |= BOOST_ASIO_HANDLER_REACTOR_ERROR_EVENT0;
536 BOOST_ASIO_HANDLER_REACTOR_EVENTS((context(),(void)0
537 reinterpret_cast<uintmax_t>(ptr), event_mask))(void)0;
538 }
539 }
540#endif // defined(BOOST_ASIO_ENABLE_HANDLER_TRACKING)
541
542#if defined(BOOST_ASIO_HAS_TIMERFD1)
543 bool check_timers = (timer_fd_ == -1);
544#else // defined(BOOST_ASIO_HAS_TIMERFD)
545 bool check_timers = true;
546#endif // defined(BOOST_ASIO_HAS_TIMERFD)
547
548 // Dispatch the waiting events.
549 for (int i = 0; i < num_events; ++i)
550 {
551 void* ptr = events[i].data.ptr;
552 if (ptr == &interrupter_)
553 {
554 // No need to reset the interrupter since we're leaving the descriptor
555 // in a ready-to-read state and relying on edge-triggered notifications
556 // to make it so that we only get woken up when the descriptor's epoll
557 // registration is updated.
558
559#if defined(BOOST_ASIO_HAS_TIMERFD1)
560 if (timer_fd_ == -1)
561 check_timers = true;
562#else // defined(BOOST_ASIO_HAS_TIMERFD)
563 check_timers = true;
564#endif // defined(BOOST_ASIO_HAS_TIMERFD)
565 }
566#if defined(BOOST_ASIO_HAS_TIMERFD1)
567 else if (ptr == &timer_fd_)
568 {
569 check_timers = true;
570 }
571#endif // defined(BOOST_ASIO_HAS_TIMERFD)
572 else
573 {
574 // The descriptor operation doesn't count as work in and of itself, so we
575 // don't call work_started() here. This still allows the scheduler to
576 // stop if the only remaining operations are descriptor operations.
577 descriptor_state* descriptor_data = static_cast<descriptor_state*>(ptr);
578 if (!ops.is_enqueued(descriptor_data))
579 {
580 descriptor_data->set_ready_events(events[i].events);
581 ops.push(descriptor_data);
582 }
583 else
584 {
585 descriptor_data->add_ready_events(events[i].events);
586 }
587 }
588 }
589
590 if (check_timers)
591 {
592 mutex::scoped_lock common_lock(mutex_);
593 timer_queues_.get_ready_timers(ops);
594
595#if defined(BOOST_ASIO_HAS_TIMERFD1)
596 if (timer_fd_ != -1)
597 {
598 itimerspec new_timeout;
599 itimerspec old_timeout;
600 int flags = get_timeout(new_timeout);
601 timerfd_settime(timer_fd_, flags, &new_timeout, &old_timeout);
602 }
603#endif // defined(BOOST_ASIO_HAS_TIMERFD)
604 }
605}
606
607void epoll_reactor::interrupt()
608{
609 epoll_event ev = { 0, { 0 } };
610 ev.events = EPOLLINEPOLLIN | EPOLLERREPOLLERR | EPOLLETEPOLLET;
611 ev.data.ptr = &interrupter_;
612 epoll_ctl(epoll_fd_, EPOLL_CTL_MOD3, interrupter_.read_descriptor(), &ev);
613}
614
615int epoll_reactor::do_epoll_create()
616{
617#if defined(EPOLL_CLOEXECEPOLL_CLOEXEC)
618 int fd = epoll_create1(EPOLL_CLOEXECEPOLL_CLOEXEC);
619#else // defined(EPOLL_CLOEXEC)
620 int fd = -1;
621 errno(*__errno_location ()) = EINVAL22;
622#endif // defined(EPOLL_CLOEXEC)
623
624 if (fd == -1 && (errno(*__errno_location ()) == EINVAL22 || errno(*__errno_location ()) == ENOSYS38))
625 {
626 fd = epoll_create(epoll_size);
627 if (fd != -1)
628 ::fcntl(fd, F_SETFD2, FD_CLOEXEC1);
629 }
630
631 if (fd == -1)
632 {
633 boost::system::error_code ec(errno(*__errno_location ()),
634 boost::asio::error::get_system_category());
635 boost::asio::detail::throw_error(ec, "epoll");
636 }
637
638 return fd;
639}
640
641int epoll_reactor::do_timerfd_create()
642{
643#if defined(BOOST_ASIO_HAS_TIMERFD1)
644# if defined(TFD_CLOEXECTFD_CLOEXEC)
645 int fd = timerfd_create(CLOCK_MONOTONIC1, TFD_CLOEXECTFD_CLOEXEC);
646# else // defined(TFD_CLOEXEC)
647 int fd = -1;
648 errno(*__errno_location ()) = EINVAL22;
649# endif // defined(TFD_CLOEXEC)
650
651 if (fd == -1 && errno(*__errno_location ()) == EINVAL22)
652 {
653 fd = timerfd_create(CLOCK_MONOTONIC1, 0);
654 if (fd != -1)
655 ::fcntl(fd, F_SETFD2, FD_CLOEXEC1);
656 }
657
658 return fd;
659#else // defined(BOOST_ASIO_HAS_TIMERFD)
660 return -1;
661#endif // defined(BOOST_ASIO_HAS_TIMERFD)
662}
663
664epoll_reactor::descriptor_state* epoll_reactor::allocate_descriptor_state()
665{
666 mutex::scoped_lock descriptors_lock(registered_descriptors_mutex_);
667 return registered_descriptors_.alloc(BOOST_ASIO_CONCURRENCY_HINT_IS_LOCKING((((static_cast<unsigned>(scheduler_.concurrency_hint())
& (0xFFFF0000u | 0x4u)) ^ 0xA5100000u) != 0)
668 REACTOR_IO, scheduler_.concurrency_hint())(((static_cast<unsigned>(scheduler_.concurrency_hint())
& (0xFFFF0000u | 0x4u)) ^ 0xA5100000u) != 0)
);
669}
670
671void epoll_reactor::free_descriptor_state(epoll_reactor::descriptor_state* s)
672{
673 mutex::scoped_lock descriptors_lock(registered_descriptors_mutex_);
674 registered_descriptors_.free(s);
675}
676
677void epoll_reactor::do_add_timer_queue(timer_queue_base& queue)
678{
679 mutex::scoped_lock lock(mutex_);
680 timer_queues_.insert(&queue);
681}
682
683void epoll_reactor::do_remove_timer_queue(timer_queue_base& queue)
684{
685 mutex::scoped_lock lock(mutex_);
686 timer_queues_.erase(&queue);
687}
688
689void epoll_reactor::update_timeout()
690{
691#if defined(BOOST_ASIO_HAS_TIMERFD1)
692 if (timer_fd_ != -1)
693 {
694 itimerspec new_timeout;
695 itimerspec old_timeout;
696 int flags = get_timeout(new_timeout);
697 timerfd_settime(timer_fd_, flags, &new_timeout, &old_timeout);
698 return;
699 }
700#endif // defined(BOOST_ASIO_HAS_TIMERFD)
701 interrupt();
702}
703
704int epoll_reactor::get_timeout(int msec)
705{
706 // By default we will wait no longer than 5 minutes. This will ensure that
707 // any changes to the system clock are detected after no longer than this.
708 const int max_msec = 5 * 60 * 1000;
709 return timer_queues_.wait_duration_msec(
710 (msec < 0 || max_msec < msec) ? max_msec : msec);
711}
712
713#if defined(BOOST_ASIO_HAS_TIMERFD1)
714int epoll_reactor::get_timeout(itimerspec& ts)
715{
716 ts.it_interval.tv_sec = 0;
717 ts.it_interval.tv_nsec = 0;
718
719 long usec = timer_queues_.wait_duration_usec(5 * 60 * 1000 * 1000);
720 ts.it_value.tv_sec = usec / 1000000;
721 ts.it_value.tv_nsec = usec ? (usec % 1000000) * 1000 : 1;
722
723 return usec ? 0 : TFD_TIMER_ABSTIMETFD_TIMER_ABSTIME;
724}
725#endif // defined(BOOST_ASIO_HAS_TIMERFD)
726
727struct epoll_reactor::perform_io_cleanup_on_block_exit
728{
729 explicit perform_io_cleanup_on_block_exit(epoll_reactor* r)
730 : reactor_(r), first_op_(0)
731 {
732 }
733
734 ~perform_io_cleanup_on_block_exit()
735 {
736 if (first_op_)
737 {
738 // Post the remaining completed operations for invocation.
739 if (!ops_.empty())
740 reactor_->scheduler_.post_deferred_completions(ops_);
741
742 // A user-initiated operation has completed, but there's no need to
743 // explicitly call work_finished() here. Instead, we'll take advantage of
744 // the fact that the scheduler will call work_finished() once we return.
745 }
746 else
747 {
748 // No user-initiated operations have completed, so we need to compensate
749 // for the work_finished() call that the scheduler will make once this
750 // operation returns.
751 reactor_->scheduler_.compensating_work_started();
752 }
753 }
754
755 epoll_reactor* reactor_;
756 op_queue<operation> ops_;
757 operation* first_op_;
758};
759
760epoll_reactor::descriptor_state::descriptor_state(bool locking)
761 : operation(&epoll_reactor::descriptor_state::do_complete),
762 mutex_(locking)
763{
764}
765
766operation* epoll_reactor::descriptor_state::perform_io(uint32_t events)
767{
768 mutex_.lock();
769 perform_io_cleanup_on_block_exit io_cleanup(reactor_);
770 mutex::scoped_lock descriptor_lock(mutex_, mutex::scoped_lock::adopt_lock);
771
772 // Exception operations must be processed first to ensure that any
773 // out-of-band data is read before normal data.
774 static const int flag[max_ops] = { EPOLLINEPOLLIN, EPOLLOUTEPOLLOUT, EPOLLPRIEPOLLPRI };
775 for (int j = max_ops - 1; j >= 0; --j)
776 {
777 if (events & (flag[j] | EPOLLERREPOLLERR | EPOLLHUPEPOLLHUP))
778 {
779 try_speculative_[j] = true;
780 while (reactor_op* op = op_queue_[j].front())
781 {
782 if (reactor_op::status status = op->perform())
783 {
784 op_queue_[j].pop();
785 io_cleanup.ops_.push(op);
786 if (status == reactor_op::done_and_exhausted)
787 {
788 try_speculative_[j] = false;
789 break;
790 }
791 }
792 else
793 break;
794 }
795 }
796 }
797
798 // The first operation will be returned for completion now. The others will
799 // be posted for later by the io_cleanup object's destructor.
800 io_cleanup.first_op_ = io_cleanup.ops_.front();
801 io_cleanup.ops_.pop();
802 return io_cleanup.first_op_;
803}
804
805void epoll_reactor::descriptor_state::do_complete(
806 void* owner, operation* base,
807 const boost::system::error_code& ec, std::size_t bytes_transferred)
808{
809 if (owner)
810 {
811 descriptor_state* descriptor_data = static_cast<descriptor_state*>(base);
812 uint32_t events = static_cast<uint32_t>(bytes_transferred);
813 if (operation* op = descriptor_data->perform_io(events))
814 {
815 op->complete(owner, ec, 0);
816 }
817 }
818}
819
820} // namespace detail
821} // namespace asio
822} // namespace boost
823
824#include <boost/asio/detail/pop_options.hpp>
825
826#endif // defined(BOOST_ASIO_HAS_EPOLL)
827
828#endif // BOOST_ASIO_DETAIL_IMPL_EPOLL_REACTOR_IPP

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

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