summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorLutz Bichler <Lutz.Bichler@bmw.de>2020-11-30 09:44:44 +0100
committerLutz Bichler <Lutz.Bichler@bmw.de>2020-11-30 09:44:44 +0100
commit710a8613ee5bd9eb490addecd7f2ee8049c4fd0c (patch)
tree49215269c551ac7eba482b3d9f6f084f56bf2fd3
parent46e6856a1a61f4b24e29c1f2d3ed0b4ee7da0ede (diff)
downloadvSomeIP-710a8613ee5bd9eb490addecd7f2ee8049c4fd0c.tar.gz
vsomeip 3.1.20.13.1.20.1
-rw-r--r--CHANGES46
-rw-r--r--CMakeLists.txt43
-rw-r--r--implementation/configuration/include/configuration.hpp8
-rw-r--r--implementation/configuration/include/configuration_impl.hpp29
-rw-r--r--implementation/configuration/include/e2e.hpp5
-rw-r--r--implementation/configuration/include/internal.hpp.in4
-rw-r--r--implementation/configuration/include/internal_android.hpp4
-rw-r--r--implementation/configuration/src/configuration_impl.cpp86
-rw-r--r--implementation/e2e_protection/include/crc/crc.hpp4
-rw-r--r--implementation/e2e_protection/include/e2e/profile/e2e_provider.hpp10
-rw-r--r--implementation/e2e_protection/include/e2e/profile/e2e_provider_impl.hpp21
-rw-r--r--implementation/e2e_protection/include/e2e/profile/profile01/checker.hpp6
-rw-r--r--implementation/e2e_protection/include/e2e/profile/profile01/profile_01.hpp25
-rw-r--r--implementation/e2e_protection/include/e2e/profile/profile01/protector.hpp12
-rw-r--r--implementation/e2e_protection/include/e2e/profile/profile04/checker.hpp45
-rw-r--r--implementation/e2e_protection/include/e2e/profile/profile04/profile_04.hpp63
-rw-r--r--implementation/e2e_protection/include/e2e/profile/profile04/protector.hpp43
-rw-r--r--implementation/e2e_protection/include/e2e/profile/profile_custom/checker.hpp6
-rw-r--r--implementation/e2e_protection/include/e2e/profile/profile_custom/profile_custom.hpp11
-rw-r--r--implementation/e2e_protection/include/e2e/profile/profile_custom/protector.hpp8
-rw-r--r--implementation/e2e_protection/include/e2e/profile/profile_interface/checker.hpp11
-rw-r--r--implementation/e2e_protection/include/e2e/profile/profile_interface/profile_interface.hpp3
-rw-r--r--implementation/e2e_protection/include/e2e/profile/profile_interface/protector.hpp7
-rw-r--r--implementation/e2e_protection/src/crc/crc.cpp72
-rw-r--r--implementation/e2e_protection/src/e2e/profile/e2e_provider_impl.cpp120
-rw-r--r--implementation/e2e_protection/src/e2e/profile/profile01/checker.cpp8
-rw-r--r--implementation/e2e_protection/src/e2e/profile/profile01/protector.cpp5
-rw-r--r--implementation/e2e_protection/src/e2e/profile/profile04/checker.cpp114
-rw-r--r--implementation/e2e_protection/src/e2e/profile/profile04/profile_04.cpp33
-rw-r--r--implementation/e2e_protection/src/e2e/profile/profile04/protector.cpp81
-rw-r--r--implementation/e2e_protection/src/e2e/profile/profile_custom/checker.cpp9
-rw-r--r--implementation/e2e_protection/src/e2e/profile/profile_custom/protector.cpp5
-rw-r--r--implementation/endpoints/include/endpoint_manager_impl.hpp10
-rw-r--r--implementation/endpoints/include/server_endpoint_impl.hpp4
-rw-r--r--implementation/endpoints/include/tcp_server_endpoint_impl.hpp1
-rw-r--r--implementation/endpoints/include/udp_server_endpoint_impl.hpp1
-rw-r--r--implementation/endpoints/src/endpoint_manager_impl.cpp125
-rw-r--r--implementation/endpoints/src/server_endpoint_impl.cpp12
-rw-r--r--implementation/endpoints/src/tcp_client_endpoint_impl.cpp2
-rw-r--r--implementation/endpoints/src/tcp_server_endpoint_impl.cpp69
-rw-r--r--implementation/endpoints/src/tp_message.cpp13
-rw-r--r--implementation/endpoints/src/udp_client_endpoint_impl.cpp6
-rw-r--r--implementation/endpoints/src/udp_server_endpoint_impl.cpp28
-rw-r--r--implementation/helper/1.74/boost/asio/basic_datagram_socket_ext.hpp1118
-rw-r--r--implementation/helper/1.74/boost/asio/basic_socket_acceptor_ext.hpp2381
-rw-r--r--implementation/helper/1.74/boost/asio/basic_socket_ext.hpp1859
-rw-r--r--implementation/helper/1.74/boost/asio/basic_socket_ext_local.hpp1859
-rw-r--r--implementation/helper/1.74/boost/asio/basic_stream_socket_ext.hpp996
-rw-r--r--implementation/helper/1.74/boost/asio/detail/handler_type_requirements_ext.hpp586
-rw-r--r--implementation/helper/1.74/boost/asio/detail/handler_type_requirements_ext_local.hpp588
-rw-r--r--implementation/helper/1.74/boost/asio/detail/impl/reactive_socket_service_base_ext.ipp302
-rw-r--r--implementation/helper/1.74/boost/asio/detail/impl/reactive_socket_service_base_ext_local.ipp302
-rw-r--r--implementation/helper/1.74/boost/asio/detail/impl/socket_ops_ext.ipp214
-rw-r--r--implementation/helper/1.74/boost/asio/detail/impl/socket_ops_ext_local.ipp307
-rw-r--r--implementation/helper/1.74/boost/asio/detail/reactive_socket_recv_op_ext.hpp162
-rw-r--r--implementation/helper/1.74/boost/asio/detail/reactive_socket_recv_op_ext_local.hpp162
-rw-r--r--implementation/helper/1.74/boost/asio/detail/reactive_socket_recvfrom_op_ext.hpp153
-rw-r--r--implementation/helper/1.74/boost/asio/detail/reactive_socket_recvfrom_op_ext_local.hpp148
-rw-r--r--implementation/helper/1.74/boost/asio/detail/reactive_socket_recvmsg_op_ext.hpp144
-rw-r--r--implementation/helper/1.74/boost/asio/detail/reactive_socket_recvmsg_op_ext_local.hpp145
-rw-r--r--implementation/helper/1.74/boost/asio/detail/reactive_socket_service_base_ext.hpp524
-rw-r--r--implementation/helper/1.74/boost/asio/detail/reactive_socket_service_base_ext_local.hpp524
-rw-r--r--implementation/helper/1.74/boost/asio/detail/reactive_socket_service_ext.hpp508
-rw-r--r--implementation/helper/1.74/boost/asio/detail/reactive_socket_service_ext_local.hpp508
-rw-r--r--implementation/helper/1.74/boost/asio/detail/reactor_op_ext.hpp43
-rw-r--r--implementation/helper/1.74/boost/asio/detail/reactor_op_ext_local.hpp44
-rw-r--r--implementation/helper/1.74/boost/asio/detail/socket_ops_ext.hpp62
-rw-r--r--implementation/helper/1.74/boost/asio/detail/socket_ops_ext_local.hpp95
-rw-r--r--implementation/helper/1.74/boost/asio/ip/udp_ext.hpp115
-rw-r--r--implementation/helper/1.74/boost/asio/local/stream_protocol_ext.hpp93
-rw-r--r--implementation/routing/include/routing_manager_impl.hpp52
-rw-r--r--implementation/routing/include/routing_manager_proxy.hpp2
-rw-r--r--implementation/routing/include/routing_manager_stub.hpp70
-rw-r--r--implementation/routing/include/routing_manager_stub_host.hpp4
-rw-r--r--implementation/routing/include/types.hpp5
-rw-r--r--implementation/routing/src/routing_manager_base.cpp9
-rw-r--r--implementation/routing/src/routing_manager_impl.cpp560
-rw-r--r--implementation/routing/src/routing_manager_proxy.cpp92
-rw-r--r--implementation/routing/src/routing_manager_stub.cpp428
-rw-r--r--implementation/runtime/include/application_impl.hpp6
-rw-r--r--implementation/runtime/src/application_impl.cpp45
-rw-r--r--implementation/security/include/policy.hpp87
-rw-r--r--implementation/security/include/security.hpp9
-rw-r--r--implementation/security/include/security_impl.hpp34
-rw-r--r--implementation/security/src/policy.cpp499
-rw-r--r--implementation/security/src/policy_manager_impl.cpp64
-rw-r--r--implementation/security/src/security_impl.cpp1432
-rw-r--r--implementation/service_discovery/include/service_discovery_host.hpp1
-rw-r--r--implementation/service_discovery/include/service_discovery_impl.hpp3
-rw-r--r--implementation/service_discovery/src/service_discovery_impl.cpp36
-rw-r--r--implementation/utility/include/utility.hpp4
-rw-r--r--implementation/utility/src/utility.cpp20
-rw-r--r--test/CMakeLists.txt84
-rw-r--r--test/configuration_tests/configuration-test-deprecated.json4
-rw-r--r--test/configuration_tests/configuration-test.cpp55
-rw-r--r--test/configuration_tests/configuration-test.json4
-rw-r--r--test/e2e_tests/conf/e2e_profile_04_test_client_external.json.in56
-rw-r--r--test/e2e_tests/conf/e2e_profile_04_test_service_external.json.in57
-rw-r--r--test/e2e_tests/e2e_profile_04_test_client.cpp313
-rw-r--r--test/e2e_tests/e2e_profile_04_test_client.hpp48
-rw-r--r--test/e2e_tests/e2e_profile_04_test_common.hpp24
-rwxr-xr-xtest/e2e_tests/e2e_profile_04_test_external_master_start.sh76
-rwxr-xr-xtest/e2e_tests/e2e_profile_04_test_external_slave_start.sh50
-rw-r--r--test/e2e_tests/e2e_profile_04_test_service.cpp324
-rw-r--r--test/e2e_tests/e2e_profile_04_test_service.hpp48
105 files changed, 18035 insertions, 1730 deletions
diff --git a/CHANGES b/CHANGES
index 39e715a..269e0a9 100644
--- a/CHANGES
+++ b/CHANGES
@@ -1,6 +1,35 @@
Changes
=======
+v3.1.20.1
+- CMakeLists.txt fixes
+ (by Martin Haase)
+- Mark all services unavailable when the routing manager goes down
+ (by Philip Werner & dannyrhubarb)
+
+v3.1.20
+- SomeIP/TP optimization
+- Fix for expired subscriptions
+
+v3.1.19
+- Log statistics for high frequent received remote events
+- Avoid unintended deletion of all service instances in release_service()
+- Prevent deletion of server endpoint on SubscribeEventGroupACK with multicast endpoint
+- Do not lock the multicast mutex twice
+
+v3.1.18
+- Support boost 1.74
+- Ignore remote offers without referenced endpoint options
+- Fixed race condition when removing security policies
+- Ensure composite send operations have finished before resetting TCP server endpoint
+
+v3.1.17
+- Support AutoSAR E2E Profile 4
+- Support dynamic policies for offered services
+- Fixed race condition between service shutdown and subscription
+- Fixed race condition between service instances offered on the
+ same endpoint(s).
+
v3.1.16.1
- Restore IPv6 within UDP server endpoint
- AOSP build adaptation to vsomeip3 libraries
@@ -15,6 +44,23 @@ v3.1.15
- Speedup security policy handling
- Enable building with boost v1.73.0
+v3.1.14.1
+- Merged extended support for static routing (versioning)
+ (by Jean-Patrice Laude jean-patrice.laude@renault.com)
+- Merged simplification of build process for hello_world example
+ (by Nikolay Khilyuk nkh@ua.fm)
+- Updated Android.bp to use boost 1.70 or higher
+- Merged Android support for hello_world example
+ (by Nikolay Khilyuk nkh@ua.fm)
+- Align response sample to documentation (do not specify application name)
+ (by JayHou houjie@lixiang.com)
+- Call dlerror before calling dlsym to clear previous error
+ (by Oleg Kharitonov Oleg.Kharitonov@elektrobit.com)
+- Get base path from environment variable for Android NDK
+ (by Nikolay Khilyuk nkh@ua.fm)
+- Fixed wrong library naming
+ (by Nikolay Khilyuk nkh@ua.fm)
+
v3.1.14
- Fixed race conditions (application registration, subscription)
diff --git a/CMakeLists.txt b/CMakeLists.txt
index e2ccc46..9fca08f 100644
--- a/CMakeLists.txt
+++ b/CMakeLists.txt
@@ -11,7 +11,7 @@ set (VSOMEIP_COMPAT_NAME vsomeip)
set (VSOMEIP_MAJOR_VERSION 3)
set (VSOMEIP_MINOR_VERSION 1)
-set (VSOMEIP_PATCH_VERSION 16)
+set (VSOMEIP_PATCH_VERSION 20)
set (VSOMEIP_HOTFIX_VERSION 1)
set (VSOMEIP_VERSION ${VSOMEIP_MAJOR_VERSION}.${VSOMEIP_MINOR_VERSION}.${VSOMEIP_PATCH_VERSION})
@@ -31,9 +31,9 @@ endif()
###################################################################################################
# Offer the user the choice of overriding the installation directories
-set (INSTALL_LIB_DIR lib CACHE PATH "Installation directory for libraries")
-set (INSTALL_BIN_DIR bin CACHE PATH "Installation directory for executables")
-set (INSTALL_INCLUDE_DIR include CACHE PATH "Installation directory for header files")
+set (INSTALL_LIB_DIR lib CACHE STRING "Installation directory for libraries")
+set (INSTALL_BIN_DIR bin CACHE STRING "Installation directory for executables")
+set (INSTALL_INCLUDE_DIR include CACHE STRING "Installation directory for header files")
if (WIN32 AND NOT CYGWIN)
set (DEF_INSTALL_CMAKE_DIR CMake)
@@ -41,15 +41,7 @@ else ()
set (DEF_INSTALL_CMAKE_DIR lib/cmake/${VSOMEIP_NAME})
endif ()
-set (INSTALL_CMAKE_DIR ${DEF_INSTALL_CMAKE_DIR} CACHE PATH "Installation directory for CMake files")
-
-# Make relative paths absolute (needed later on)
-foreach (p LIB BIN INCLUDE CMAKE)
- set (var INSTALL_${p}_DIR)
- if (NOT IS_ABSOLUTE "${${var}}")
- set (ABSOLUTE_${var} "${CMAKE_INSTALL_PREFIX}/${${var}}") # Add all targets to the build-tree export set
- endif ()
-endforeach ()
+set (INSTALL_CMAKE_DIR ${DEF_INSTALL_CMAKE_DIR} CACHE STRING "Installation directory for CMake files")
###################################################################################################
# Set a default build type if none was specified
@@ -135,6 +127,11 @@ else ()
set (VSOMEIP_ENABLE_MULTIPLE_ROUTING_MANAGERS 0)
endif ()
+# Session handling configuration
+if (ENABLE_SESSION_HANDLING_CONFIG)
+set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -DVSOMEIP_HAS_SESSION_HANDLING_CONFIG")
+endif ()
+
################################################################################
# Dependencies
################################################################################
@@ -173,8 +170,10 @@ else()
endif()
message( STATUS "Using boost version: ${VSOMEIP_BOOST_VERSION}" )
-if (${VSOMEIP_BOOST_VERSION} GREATER 107300)
-message( ERROR "boost version ${VSOMEIP_BOOST_VERSION} is not (yet) supported. Latest supported version is 1.72.0" )
+if (${VSOMEIP_BOOST_VERSION} GREATER 107400)
+message( ERROR "boost version ${VSOMEIP_BOOST_VERSION} is not (yet) supported. Latest supported version is 1.74.0" )
+elseif(${VSOMEIP_BOOST_VERSION} GREATER 107300)
+set(VSOMEIP_BOOST_HELPER implementation/helper/1.74)
elseif(${VSOMEIP_BOOST_VERSION} GREATER 106999)
set(VSOMEIP_BOOST_HELPER implementation/helper/1.70)
elseif(${VSOMEIP_BOOST_VERSION} GREATER 106599)
@@ -214,6 +213,9 @@ endif ()
include_directories(
interface
+)
+
+include_directories(SYSTEM
${VSOMEIP_BOOST_HELPER}
${DLT_INCLUDE_DIRS}
)
@@ -235,7 +237,6 @@ if (MSVC)
set(CMAKE_C_FLAGS "${CMAKE_C_FLAGS} -D_WINSOCK_DEPRECATED_NO_WARNINGS -D_WIN32_WINNT=${BOOST_WINDOWS_VERSION} -DWIN32 -DBOOST_ASIO_DISABLE_IOCP /EHsc")
set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -D_CRT_SECURE_NO_WARNINGS -D_SCL_SECURE_NO_WARNINGS -D_WINSOCK_DEPRECATED_NO_WARNINGS -D_WIN32_WINNT=${BOOST_WINDOWS_VERSION} -DWIN32 -DBOOST_ASIO_DISABLE_IOCP /EHsc")
set(USE_RT "")
- set(Boost_LIBRARIES "")
link_directories(${Boost_LIBRARY_DIR_DEBUG})
ADD_DEFINITIONS( -DBOOST_ALL_DYN_LINK )
else()
@@ -676,6 +677,16 @@ else()
set(TEST_SECOND_ADDRESS "ON")
endif()
+set(TEST_E2E_PROFILE_04 "OFF" CACHE BOOL
+ "Controls whether E2E Profile 04 tests should run or not")
+if (ENABLE_SESSION_HANDLING_CONFIG)
+ set(TEST_E2E_PROFILE_04 "ON")
+else ()
+ message(WARNING "ENABLE_SESSION_HANDLING_CONFIG isn't set. "
+ "Test of E2E Profile 04 is not enabled.")
+endif ()
+
+
SET(TEST_UID_DEFAULT_VALUE "123456789")
SET(TEST_UID "${TEST_UID_DEFAULT_VALUE}" CACHE STRING
"The User ID of the user running the test: Needed for security")
diff --git a/implementation/configuration/include/configuration.hpp b/implementation/configuration/include/configuration.hpp
index f20d040..a962298 100644
--- a/implementation/configuration/include/configuration.hpp
+++ b/implementation/configuration/include/configuration.hpp
@@ -130,6 +130,9 @@ public:
virtual std::size_t get_io_thread_count(const std::string &_name) const = 0;
virtual int get_io_thread_nice_level(const std::string &_name) const = 0;
virtual std::size_t get_request_debouncing(const std::string &_name) const = 0;
+#ifdef VSOMEIP_HAS_SESSION_HANDLING_CONFIG
+ virtual bool has_session_handling(const std::string &_name) const = 0;
+#endif // VSOMEIP_HAS_SESSION_HANDLING_CONFIG
virtual std::uint32_t get_max_message_size_local() const = 0;
virtual std::uint32_t get_max_message_size_reliable(const std::string& _address,
@@ -265,6 +268,11 @@ public:
// routing shutdown timeout
virtual std::uint32_t get_shutdown_timeout() const = 0;
+
+ virtual bool log_statistics() const = 0;
+ virtual uint32_t get_statistics_interval() const = 0;
+ virtual uint32_t get_statistics_min_freq() const = 0;
+ virtual uint32_t get_statistics_max_messages() const = 0;
};
} // namespace vsomeip_v3
diff --git a/implementation/configuration/include/configuration_impl.hpp b/implementation/configuration/include/configuration_impl.hpp
index 5b77c18..66cfc84 100644
--- a/implementation/configuration/include/configuration_impl.hpp
+++ b/implementation/configuration/include/configuration_impl.hpp
@@ -115,6 +115,7 @@ public:
VSOMEIP_EXPORT std::size_t get_io_thread_count(const std::string &_name) const;
VSOMEIP_EXPORT int get_io_thread_nice_level(const std::string &_name) const;
VSOMEIP_EXPORT std::size_t get_request_debouncing(const std::string &_name) const;
+ VSOMEIP_EXPORT bool has_session_handling(const std::string &_name) const;
VSOMEIP_EXPORT std::set<std::pair<service_t, instance_t> > get_remote_services() const;
@@ -232,6 +233,12 @@ public:
std::uint16_t _port_service, method_t _method) const;
VSOMEIP_EXPORT std::uint32_t get_shutdown_timeout() const;
+
+ VSOMEIP_EXPORT bool log_statistics() const;
+ VSOMEIP_EXPORT uint32_t get_statistics_interval() const;
+ VSOMEIP_EXPORT uint32_t get_statistics_min_freq() const;
+ VSOMEIP_EXPORT uint32_t get_statistics_max_messages() const;
+
private:
void read_data(const std::set<std::string> &_input,
std::vector<configuration_element> &_elements,
@@ -399,16 +406,19 @@ protected:
std::map<std::string,
std::tuple<
client_t,
- std::size_t,
- std::size_t,
- std::size_t,
- std::size_t,
+ std::size_t, // max dispatchers
+ std::size_t, // max dispatch time
+ std::size_t, // thread count
+ std::size_t, // request debouncing
std::map<
plugin_type_e,
std::set<std::string>
- >,
- int,
- std::string
+ >, // plugins
+ int, // nice level
+ std::string // overlay
+#ifdef VSOMEIP_HAS_SESSION_HANDLING_CONFIG
+ , bool // has session handling?
+#endif // VSOMEIP_HAS_SESSION_HANDLING_CONFIG
>
> applications_;
std::set<client_t> client_identifiers_;
@@ -553,6 +563,11 @@ protected:
mutable std::mutex secure_services_mutex_;
std::map<service_t, std::set<instance_t> > secure_services_;
+
+ bool log_statistics_;
+ uint32_t statistics_interval_;
+ uint32_t statistics_min_freq_;
+ uint32_t statistics_max_messages_;
};
} // namespace cfg
diff --git a/implementation/configuration/include/e2e.hpp b/implementation/configuration/include/e2e.hpp
index 8c873c2..705c92d 100644
--- a/implementation/configuration/include/e2e.hpp
+++ b/implementation/configuration/include/e2e.hpp
@@ -19,16 +19,14 @@ struct e2e {
typedef std::map<std::string, std::string> custom_parameters_t;
e2e() :
- data_id(0),
variant(""),
profile(""),
service_id(0),
event_id(0) {
}
- e2e(uint16_t _data_id, std::string _variant, std::string _profile, service_t _service_id,
+ e2e(std::string _variant, std::string _profile, service_t _service_id,
event_t _event_id, custom_parameters_t&& _custom_parameters) :
- data_id(_data_id),
variant(_variant),
profile(_profile),
service_id(_service_id),
@@ -37,7 +35,6 @@ struct e2e {
}
// common config
- uint16_t data_id;
std::string variant;
std::string profile;
service_t service_id;
diff --git a/implementation/configuration/include/internal.hpp.in b/implementation/configuration/include/internal.hpp.in
index 94a6e66..cc21616 100644
--- a/implementation/configuration/include/internal.hpp.in
+++ b/implementation/configuration/include/internal.hpp.in
@@ -84,6 +84,9 @@
#define VSOMEIP_MAX_DISPATCH_TIME 100
#define VSOMEIP_REQUEST_DEBOUNCE_TIME 10
+#define VSOMEIP_DEFAULT_STATISTICS_MAX_MSG 50
+#define VSOMEIP_DEFAULT_STATISTICS_MIN_FREQ 50
+#define VSOMEIP_DEFAULT_STATISTICS_INTERVAL 10000
#define VSOMEIP_MAX_WAIT_SENT 5
@@ -134,6 +137,7 @@
#define VSOMEIP_REMOVE_SECURITY_POLICY_RESPONSE 0x26
#define VSOMEIP_UPDATE_SECURITY_CREDENTIALS 0x27
#define VSOMEIP_DISTRIBUTE_SECURITY_POLICIES 0x28
+#define VSOMEIP_UPDATE_SECURITY_POLICY_INT 0x29
#define VSOMEIP_SEND_COMMAND_SIZE 13
#define VSOMEIP_SEND_COMMAND_INSTANCE_POS_MIN 7
diff --git a/implementation/configuration/include/internal_android.hpp b/implementation/configuration/include/internal_android.hpp
index 8043676..28cbb5c 100644
--- a/implementation/configuration/include/internal_android.hpp
+++ b/implementation/configuration/include/internal_android.hpp
@@ -68,6 +68,9 @@
#define VSOMEIP_MAX_DISPATCH_TIME 100
#define VSOMEIP_REQUEST_DEBOUNCE_TIME 10
+#define VSOMEIP_DEFAULT_STATISTICS_MAX_MSG 50
+#define VSOMEIP_DEFAULT_STATISTICS_MIN_FREQ 50
+#define VSOMEIP_DEFAULT_STATISTICS_INTERVAL 10000
#define VSOMEIP_MAX_WAIT_SENT 5
@@ -118,6 +121,7 @@
#define VSOMEIP_REMOVE_SECURITY_POLICY_RESPONSE 0x26
#define VSOMEIP_UPDATE_SECURITY_CREDENTIALS 0x27
#define VSOMEIP_DISTRIBUTE_SECURITY_POLICIES 0x28
+#define VSOMEIP_UPDATE_SECURITY_POLICY_INT 0x29
#define VSOMEIP_SEND_COMMAND_SIZE 13
#define VSOMEIP_SEND_COMMAND_INSTANCE_POS_MIN 7
diff --git a/implementation/configuration/src/configuration_impl.cpp b/implementation/configuration/src/configuration_impl.cpp
index 9f7aeab..475d265 100644
--- a/implementation/configuration/src/configuration_impl.cpp
+++ b/implementation/configuration/src/configuration_impl.cpp
@@ -90,7 +90,11 @@ configuration_impl::configuration_impl()
npdu_default_debounce_resp_(VSOMEIP_DEFAULT_NPDU_DEBOUNCING_NANO),
npdu_default_max_retention_requ_(VSOMEIP_DEFAULT_NPDU_MAXIMUM_RETENTION_NANO),
npdu_default_max_retention_resp_(VSOMEIP_DEFAULT_NPDU_MAXIMUM_RETENTION_NANO),
- shutdown_timeout_(VSOMEIP_DEFAULT_SHUTDOWN_TIMEOUT) {
+ shutdown_timeout_(VSOMEIP_DEFAULT_SHUTDOWN_TIMEOUT),
+ log_statistics_(true),
+ statistics_interval_(VSOMEIP_DEFAULT_STATISTICS_INTERVAL),
+ statistics_min_freq_(VSOMEIP_DEFAULT_STATISTICS_MIN_FREQ),
+ statistics_max_messages_(VSOMEIP_DEFAULT_STATISTICS_MAX_MSG) {
unicast_ = unicast_.from_string(VSOMEIP_UNICAST_ADDRESS);
netmask_ = netmask_.from_string(VSOMEIP_NETMASK);
for (auto i = 0; i < ET_MAX; i++)
@@ -190,6 +194,11 @@ configuration_impl::configuration_impl(const configuration_impl &_other)
has_issued_methods_warning_ = _other.has_issued_methods_warning_;
has_issued_clients_warning_ = _other.has_issued_clients_warning_;
+
+ log_statistics_ = _other.log_statistics_;
+ statistics_interval_ = _other.statistics_interval_;
+ statistics_min_freq_ = _other.statistics_min_freq_;
+ statistics_max_messages_ = _other.statistics_max_messages_;
}
configuration_impl::~configuration_impl() {
@@ -595,6 +604,25 @@ bool configuration_impl::load_logging(
if (log_status_interval_ > 0) {
log_status_ = true;
}
+ } else if (its_key == "statistics") {
+ for (auto j : i->second) {
+ std::stringstream its_converter;
+ std::string its_sub_key(j.first);
+ std::string its_sub_value(j.second.data());
+ if (its_sub_key == "interval") {
+ its_converter << std::dec << its_sub_value;
+ its_converter >> statistics_interval_;
+ if (statistics_interval_ > 0) {
+ log_statistics_ = true;
+ }
+ } else if (its_sub_key == "min-frequency") {
+ its_converter << std::dec << its_sub_value;
+ its_converter >> statistics_min_freq_;
+ } else if (its_sub_key == "max-messages") {
+ its_converter << std::dec << its_sub_value;
+ its_converter >> statistics_max_messages_;
+ }
+ }
}
}
} catch (...) {
@@ -646,6 +674,9 @@ void configuration_impl::load_application_data(
std::map<plugin_type_e, std::set<std::string>> plugins;
int its_io_thread_nice_level(VSOMEIP_IO_THREAD_NICE_LEVEL);
std::string its_overlay;
+#ifdef VSOMEIP_HAS_SESSION_HANDLING_CONFIG
+ bool has_session_handling(true);
+#endif // VSOMEIP_HAS_SESSION_HANDLING_CONFIG
for (auto i = _tree.begin(); i != _tree.end(); ++i) {
std::string its_key(i->first);
std::string its_value(i->second.data());
@@ -690,6 +721,11 @@ void configuration_impl::load_application_data(
} else if (its_key == "overlay") {
its_overlay = its_value;
}
+#ifdef VSOMEIP_HAS_SESSION_HANDLING_CONFIG
+ else if (its_key == "has_session_handling") {
+ has_session_handling = (its_value != "false");
+ }
+#endif // VSOMEIP_HAS_SESSION_HANDLING_CONFIG
}
if (its_name != "") {
if (applications_.find(its_name) == applications_.end()) {
@@ -708,7 +744,11 @@ void configuration_impl::load_application_data(
= std::make_tuple(its_id, its_max_dispatchers,
its_max_dispatch_time, its_io_thread_count,
its_request_debounce_time, plugins, its_io_thread_nice_level,
- its_overlay);
+ its_overlay
+#ifdef VSOMEIP_HAS_SESSION_HANDLING_CONFIG
+ , has_session_handling
+#endif // VSOMEIP_HAS_SESSION_HANDLING_CONFIG
+ );
} else {
VSOMEIP_WARNING << "Multiple configurations for application "
<< its_name << ". Ignoring a configuration from "
@@ -2431,6 +2471,18 @@ std::size_t configuration_impl::get_max_dispatch_time(
return its_max_dispatch_time;
}
+#ifdef VSOMEIP_HAS_SESSION_HANDLING_CONFIG
+bool configuration_impl::has_session_handling(const std::string &_name) const {
+
+ bool its_value(true);
+
+ auto found_application = applications_.find(_name);
+ if (found_application != applications_.end())
+ its_value = std::get<8>(found_application->second);
+
+ return (its_value);
+}
+#endif // VSOMEIP_HAS_SESSION_HANDLING_CONFIG
std::set<std::pair<service_t, instance_t> >
configuration_impl::get_remote_services() const {
@@ -2854,7 +2906,6 @@ void configuration_impl::load_e2e(const configuration_element &_element) {
void configuration_impl::load_e2e_protected(const boost::property_tree::ptree &_tree) {
- uint16_t data_id(0);
std::string variant("");
std::string profile("");
service_t service_id(0);
@@ -2864,15 +2915,7 @@ void configuration_impl::load_e2e_protected(const boost::property_tree::ptree &_
for (auto l = _tree.begin(); l != _tree.end(); ++l) {
std::stringstream its_converter;
- if (l->first == "data_id" && data_id == 0) {
- std::string value = l->second.data();
- if (value.size() > 1 && value[0] == '0' && value[1] == 'x') {
- its_converter << std::hex << value;
- } else {
- its_converter << std::dec << value;
- }
- its_converter >> data_id;
- } else if (l->first == "service_id") {
+ if (l->first == "service_id") {
std::string value = l->second.data();
if (value.size() > 1 && value[0] == '0' && value[1] == 'x') {
its_converter << std::hex << value;
@@ -2901,7 +2944,6 @@ void configuration_impl::load_e2e_protected(const boost::property_tree::ptree &_
}
}
e2e_configuration_[std::make_pair(service_id, event_id)] = std::make_shared<cfg::e2e>(
- data_id,
variant,
profile,
service_id,
@@ -3910,7 +3952,7 @@ configuration_impl::has_overlay(const std::string &_name) const {
void
configuration_impl::load_overlay(const std::string &_name) {
std::set<std::string> its_input;
- std::vector<element> its_elements;
+ std::vector<configuration_element> its_elements;
std::set<std::string> its_failed;
auto its_application = applications_.find(_name);
@@ -3933,5 +3975,21 @@ std::uint32_t configuration_impl::get_shutdown_timeout() const {
return shutdown_timeout_;
}
+bool configuration_impl::log_statistics() const {
+ return log_statistics_;
+}
+
+uint32_t configuration_impl::get_statistics_interval() const {
+ return statistics_interval_;
+}
+
+uint32_t configuration_impl::get_statistics_min_freq() const {
+ return statistics_min_freq_;
+}
+
+uint32_t configuration_impl::get_statistics_max_messages() const {
+ return statistics_max_messages_;
+}
+
} // namespace config
} // namespace vsomeip_v3
diff --git a/implementation/e2e_protection/include/crc/crc.hpp b/implementation/e2e_protection/include/crc/crc.hpp
index 6120d86..b8d5688 100644
--- a/implementation/e2e_protection/include/crc/crc.hpp
+++ b/implementation/e2e_protection/include/crc/crc.hpp
@@ -14,9 +14,9 @@ namespace vsomeip_v3 {
class e2e_crc {
public:
static uint8_t calculate_profile_01(buffer_view _buffer_view,
- const uint8_t _start_value = 0x00U);
+ const uint8_t _start_value = 0x00U);
static uint32_t calculate_profile_04(buffer_view _buffer_view,
- const uint32_t _start_value = 0x00000000U);
+ const uint32_t _start_value = 0x00000000U);
static uint32_t calculate_profile_custom(buffer_view _buffer_view);
diff --git a/implementation/e2e_protection/include/e2e/profile/e2e_provider.hpp b/implementation/e2e_protection/include/e2e/profile/e2e_provider.hpp
index aa45829..41d7487 100644
--- a/implementation/e2e_protection/include/e2e/profile/e2e_provider.hpp
+++ b/implementation/e2e_protection/include/e2e/profile/e2e_provider.hpp
@@ -24,9 +24,13 @@ public:
virtual bool is_protected(e2exf::data_identifier_t id) const = 0;
virtual bool is_checked(e2exf::data_identifier_t id) const = 0;
- virtual void protect(e2exf::data_identifier_t id, e2e_buffer &_buffer) = 0;
- virtual void check(e2exf::data_identifier_t id, const e2e_buffer &_buffer,
- e2e::profile_interface::check_status_t &_generic_check_status) = 0;
+ virtual std::size_t get_protection_base(e2exf::data_identifier_t _id) const = 0;
+
+ virtual void protect(e2exf::data_identifier_t id,
+ e2e_buffer &_buffer, instance_t _instance) = 0;
+ virtual void check(e2exf::data_identifier_t id,
+ const e2e_buffer &_buffer, instance_t _instance,
+ e2e::profile_interface::check_status_t &_generic_check_status) = 0;
};
} // namespace e2e
diff --git a/implementation/e2e_protection/include/e2e/profile/e2e_provider_impl.hpp b/implementation/e2e_protection/include/e2e/profile/e2e_provider_impl.hpp
index b7d41a6..62db2e2 100644
--- a/implementation/e2e_protection/include/e2e/profile/e2e_provider_impl.hpp
+++ b/implementation/e2e_protection/include/e2e/profile/e2e_provider_impl.hpp
@@ -32,13 +32,18 @@ public:
VSOMEIP_EXPORT bool is_protected(e2exf::data_identifier_t id) const override;
VSOMEIP_EXPORT bool is_checked(e2exf::data_identifier_t id) const override;
- VSOMEIP_EXPORT void protect(e2exf::data_identifier_t id, e2e_buffer &_buffer) override;
- VSOMEIP_EXPORT void check(e2exf::data_identifier_t id, const e2e_buffer &_buffer,
- profile_interface::check_status_t &_generic_check_status) override;
+ VSOMEIP_EXPORT std::size_t get_protection_base(e2exf::data_identifier_t _id) const override;
+
+ VSOMEIP_EXPORT void protect(e2exf::data_identifier_t id,
+ e2e_buffer &_buffer, instance_t _instance) override;
+ VSOMEIP_EXPORT void check(e2exf::data_identifier_t id,
+ const e2e_buffer &_buffer, instance_t _instance,
+ profile_interface::check_status_t &_generic_check_status) override;
private:
- std::map<e2exf::data_identifier_t, std::shared_ptr<profile_interface::protector>> custom_protectors;
- std::map<e2exf::data_identifier_t, std::shared_ptr<profile_interface::checker>> custom_checkers;
+ std::map<e2exf::data_identifier_t, std::shared_ptr<profile_interface::protector>> custom_protectors_;
+ std::map<e2exf::data_identifier_t, std::shared_ptr<profile_interface::checker>> custom_checkers_;
+ std::map<e2exf::data_identifier_t, std::size_t> custom_bases_;
template<typename config_t>
config_t make_e2e_profile_config(const std::shared_ptr<cfg::e2e>& config);
@@ -50,13 +55,15 @@ private:
std::shared_ptr<e2e::profile_interface::checker> checker;
if ((config->variant == "checker") || (config->variant == "both")) {
- custom_checkers[data_identifier] = std::make_shared<checker_t>(profile_config);
+ custom_checkers_[data_identifier] = std::make_shared<checker_t>(profile_config);
}
std::shared_ptr<e2e::profile_interface::protector> protector;
if ((config->variant == "protector") || (config->variant == "both")) {
- custom_protectors[data_identifier] = std::make_shared<protector_t>(profile_config);
+ custom_protectors_[data_identifier] = std::make_shared<protector_t>(profile_config);
}
+
+ custom_bases_[data_identifier] = profile_config.base_;
}
};
diff --git a/implementation/e2e_protection/include/e2e/profile/profile01/checker.hpp b/implementation/e2e_protection/include/e2e/profile/profile01/checker.hpp
index 3010949..4184996 100644
--- a/implementation/e2e_protection/include/e2e/profile/profile01/checker.hpp
+++ b/implementation/e2e_protection/include/e2e/profile/profile01/checker.hpp
@@ -15,15 +15,15 @@ namespace profile01 {
class profile_01_checker final : public e2e::profile_interface::checker {
- public:
+public:
profile_01_checker(void) = delete;
// [SWS_E2E_00389] initialize state
explicit profile_01_checker(const profile_config &_config) :
config_(_config) {}
- virtual void check(const e2e_buffer &_buffer,
- e2e::profile_interface::check_status_t &_generic_check_status) override final;
+ void check(const e2e_buffer &_buffer, instance_t _instance,
+ e2e::profile_interface::check_status_t &_generic_check_status) override final;
private:
profile_config config_;
diff --git a/implementation/e2e_protection/include/e2e/profile/profile01/profile_01.hpp b/implementation/e2e_protection/include/e2e/profile/profile01/profile_01.hpp
index c6cd5cf..54b2d5c 100644
--- a/implementation/e2e_protection/include/e2e/profile/profile01/profile_01.hpp
+++ b/implementation/e2e_protection/include/e2e/profile/profile01/profile_01.hpp
@@ -7,6 +7,9 @@
#define VSOMEIP_V3_E2E_PROFILE01_PROFILE01_HPP
#include <cstdint>
+
+#include <vsomeip/defines.hpp>
+
#include "../../../buffer/buffer.hpp"
namespace vsomeip_v3 {
@@ -26,14 +29,6 @@ class profile_01 {
enum class p01_data_id_mode : uint8_t {E2E_P01_DATAID_BOTH, E2E_P01_DATAID_ALT, E2E_P01_DATAID_LOW, E2E_P01_DATAID_NIBBLE};
struct profile_config {
- // [SWS_E2E_00018]
- uint16_t crc_offset_;
- uint16_t data_id_;
- p01_data_id_mode data_id_mode_;
- uint16_t data_length_;
- uint16_t counter_offset_;
- uint16_t data_id_nibble_offset_;
-
profile_config() = delete;
profile_config(uint16_t _crc_offset, uint16_t _data_id,
@@ -43,10 +38,22 @@ struct profile_config {
: crc_offset_(_crc_offset), data_id_(_data_id),
data_id_mode_(_data_id_mode), data_length_(_data_length),
counter_offset_(_counter_offset),
- data_id_nibble_offset_(_data_id_nibble_offset) {
+ data_id_nibble_offset_(_data_id_nibble_offset),
+ base_(VSOMEIP_FULL_HEADER_SIZE) {
}
profile_config(const profile_config &_config) = default;
profile_config &operator=(const profile_config &_config) = default;
+
+ // [SWS_E2E_00018]
+ uint16_t crc_offset_;
+ uint16_t data_id_;
+ p01_data_id_mode data_id_mode_;
+ uint16_t data_length_;
+ uint16_t counter_offset_;
+ uint16_t data_id_nibble_offset_;
+
+ // SOME/IP base
+ size_t base_;
};
} // namespace profile01
diff --git a/implementation/e2e_protection/include/e2e/profile/profile01/protector.hpp b/implementation/e2e_protection/include/e2e/profile/profile01/protector.hpp
index fe8b603..13bd524 100644
--- a/implementation/e2e_protection/include/e2e/profile/profile01/protector.hpp
+++ b/implementation/e2e_protection/include/e2e/profile/profile01/protector.hpp
@@ -7,6 +7,7 @@
#define VSOMEIP_V3_E2E_PROFILE01_PROTECTOR_HPP
#include <mutex>
+
#include "../profile01/profile_01.hpp"
#include "../profile_interface/protector.hpp"
@@ -15,14 +16,14 @@ namespace e2e {
namespace profile01 {
class protector final : public e2e::profile_interface::protector {
- public:
+public:
protector(void) = delete;
- explicit protector(const profile_config &_config) : config_(_config), counter_(0){};
+ explicit protector(const profile_config &_config) : config_(_config), counter_(0) {};
- void protect(e2e_buffer &_buffer) override final;
+ void protect(e2e_buffer &_buffer, instance_t _instance) override final;
- private:
+private:
void write_counter(e2e_buffer &_buffer);
@@ -32,8 +33,7 @@ class protector final : public e2e::profile_interface::protector {
void increment_counter(void);
-
- private:
+private:
profile_config config_;
uint8_t counter_;
std::mutex protect_mutex_;
diff --git a/implementation/e2e_protection/include/e2e/profile/profile04/checker.hpp b/implementation/e2e_protection/include/e2e/profile/profile04/checker.hpp
new file mode 100644
index 0000000..c16eb10
--- /dev/null
+++ b/implementation/e2e_protection/include/e2e/profile/profile04/checker.hpp
@@ -0,0 +1,45 @@
+// Copyright (C) 2020 Bayerische Motoren Werke Aktiengesellschaft (BMW AG)
+// This Source Code Form is subject to the terms of the Mozilla Public
+// License, v. 2.0. If a copy of the MPL was not distributed with this
+// file, You can obtain one at http://mozilla.org/MPL/2.0/.
+
+#ifndef VSOMEIP_V3_E2E_PROFILE04_CHECKER_HPP
+#define VSOMEIP_V3_E2E_PROFILE04_CHECKER_HPP
+
+#include "../profile04/profile_04.hpp"
+#include "../profile_interface/checker.hpp"
+
+namespace vsomeip_v3 {
+namespace e2e {
+namespace profile04 {
+
+class profile_04_checker final : public e2e::profile_interface::checker {
+
+public:
+ profile_04_checker(void) = delete;
+
+ // [SWS_E2E_00389] initialize state
+ explicit profile_04_checker(const profile_config &_config) :
+ config_(_config), counter_(0xffff) {}
+
+ void check(const e2e_buffer &_buffer, instance_t _instance,
+ e2e::profile_interface::check_status_t &_generic_check_status) override final;
+
+private:
+ bool verify_input(const e2e_buffer &_buffer) const;
+ bool verify_counter(uint16_t _received_counter) const;
+
+ bool read_16(const e2e_buffer &_buffer, uint16_t &_data, size_t _index) const;
+ bool read_32(const e2e_buffer &_buffer, uint32_t &_data, size_t _index) const;
+
+ std::mutex check_mutex_;
+
+ profile_config config_;
+ uint16_t counter_;
+};
+
+} // namespace profile_04
+} // namespace e2e
+} // namespace vsomeip_v3
+
+#endif // VSOMEIP_V3_E2E_PROFILE04_CHECKER_HPP
diff --git a/implementation/e2e_protection/include/e2e/profile/profile04/profile_04.hpp b/implementation/e2e_protection/include/e2e/profile/profile04/profile_04.hpp
new file mode 100644
index 0000000..88be05c
--- /dev/null
+++ b/implementation/e2e_protection/include/e2e/profile/profile04/profile_04.hpp
@@ -0,0 +1,63 @@
+// Copyright (C) 2020 Bayerische Motoren Werke Aktiengesellschaft (BMW AG)
+// This Source Code Form is subject to the terms of the Mozilla Public
+// License, v. 2.0. If a copy of the MPL was not distributed with this
+// file, You can obtain one at http://mozilla.org/MPL/2.0/.
+
+#ifndef VSOMEIP_V3_E2E_PROFILE04_PROFILE04_HPP
+#define VSOMEIP_V3_E2E_PROFILE04_PROFILE04_HPP
+
+#include <cstdint>
+
+#include <vsomeip/defines.hpp>
+
+#include "../../../buffer/buffer.hpp"
+
+// The MSB of the dataID is the instance identifier.
+// Therefore, the instance identifier must fit into a single byte.
+#define VSOMEIP_E2E_PROFILE04_MAX_INSTANCE 0x00ff
+
+namespace vsomeip_v3 {
+namespace e2e {
+namespace profile04 {
+
+struct profile_config;
+
+class profile_04 {
+public:
+ static uint32_t compute_crc(const profile_config &_config, const e2e_buffer &_buffer);
+};
+
+// [SWS_E2E_00200]
+struct profile_config {
+ profile_config() = delete;
+
+ profile_config(uint32_t _data_id, size_t _offset,
+ size_t _min_data_length, size_t _max_data_length,
+ uint16_t _max_delta_counter)
+ : data_id_(_data_id), offset_(_offset),
+ min_data_length_(_min_data_length), max_data_length_(_max_data_length),
+ max_delta_counter_(_max_delta_counter),
+ base_(VSOMEIP_SOMEIP_HEADER_SIZE) {
+ }
+ profile_config(const profile_config &_config) = default;
+ profile_config &operator=(const profile_config &_config) = default;
+
+ // [SWS_E2E_00334]
+ uint32_t data_id_;
+ size_t offset_; // This must be configured in bit but as a multiple of 8.
+ // As we must use it as an index, we do the math once at
+ // configuration time and use the correct data type here.
+ // Thus, this value is always the byte where the CRC starts.
+ size_t min_data_length_;
+ size_t max_data_length_;
+ uint16_t max_delta_counter_;
+
+ // SOME/IP base
+ size_t base_;
+};
+
+} // namespace profile_04
+} // namespace e2e
+} // namespace vsomeip_v3
+
+#endif // VSOMEIP_V3_E2E_PROFILE04_PROFILE04_HPP
diff --git a/implementation/e2e_protection/include/e2e/profile/profile04/protector.hpp b/implementation/e2e_protection/include/e2e/profile/profile04/protector.hpp
new file mode 100644
index 0000000..fd4a6e7
--- /dev/null
+++ b/implementation/e2e_protection/include/e2e/profile/profile04/protector.hpp
@@ -0,0 +1,43 @@
+// Copyright (C) 2020 Bayerische Motoren Werke Aktiengesellschaft (BMW AG)
+// This Source Code Form is subject to the terms of the Mozilla Public
+// License, v. 2.0. If a copy of the MPL was not distributed with this
+// file, You can obtain one at http://mozilla.org/MPL/2.0/.
+
+#ifndef VSOMEIP_V3_E2E_PROFILE04_PROTECTOR_HPP
+#define VSOMEIP_V3_E2E_PROFILE04_PROTECTOR_HPP
+
+#include <mutex>
+#include "../profile04/profile_04.hpp"
+#include "../profile_interface/protector.hpp"
+
+namespace vsomeip_v3 {
+namespace e2e {
+namespace profile04 {
+
+class protector final : public e2e::profile_interface::protector {
+public:
+ protector(void) = delete;
+
+ explicit protector(const profile_config &_config)
+ : config_(_config), counter_(0) {};
+
+ void protect(e2e_buffer &_buffer, instance_t _instance) override final;
+
+private:
+ bool verify_inputs(e2e_buffer &_buffer);
+ void increment_counter();
+
+ void write_16(e2e_buffer &_buffer, uint16_t _data, size_t _index);
+ void write_32(e2e_buffer &_buffer, uint32_t _data, size_t _index);
+
+private:
+ profile_config config_;
+ uint16_t counter_;
+ std::mutex protect_mutex_;
+};
+
+} // namespace profile_04
+} // namespace e2e
+} // namespace vsomeip_v3
+
+#endif // VSOMEIP_V3_E2E_PROFILE04_PROTECTOR_HPP
diff --git a/implementation/e2e_protection/include/e2e/profile/profile_custom/checker.hpp b/implementation/e2e_protection/include/e2e/profile/profile_custom/checker.hpp
index 73f1bbb..e233205 100644
--- a/implementation/e2e_protection/include/e2e/profile/profile_custom/checker.hpp
+++ b/implementation/e2e_protection/include/e2e/profile/profile_custom/checker.hpp
@@ -23,10 +23,10 @@ public:
explicit profile_custom_checker(const e2e::profile_custom::profile_config &_config) :
config_(_config) {}
- virtual void check(const e2e_buffer &_buffer,
- e2e::profile_interface::check_status_t &_generic_check_status);
+ void check(const e2e_buffer &_buffer, instance_t _instance,
+ e2e::profile_interface::check_status_t &_generic_check_status) override final;
- private:
+private:
uint32_t read_crc(const e2e_buffer &_buffer) const;
private:
diff --git a/implementation/e2e_protection/include/e2e/profile/profile_custom/profile_custom.hpp b/implementation/e2e_protection/include/e2e/profile/profile_custom/profile_custom.hpp
index 1cabefa..244989d 100644
--- a/implementation/e2e_protection/include/e2e/profile/profile_custom/profile_custom.hpp
+++ b/implementation/e2e_protection/include/e2e/profile/profile_custom/profile_custom.hpp
@@ -7,6 +7,9 @@
#define VSOMEIP_V3_E2E_PROFILE_CUSTOM_PROFILE_CUSTOM_HPP
#include <cstdint>
+
+#include <vsomeip/defines.hpp>
+
#include "../../../buffer/buffer.hpp"
namespace vsomeip_v3 {
@@ -23,15 +26,17 @@ class profile_custom {
};
struct profile_config {
- uint16_t crc_offset_;
-
profile_config() = delete;
profile_config(uint16_t _crc_offset)
- : crc_offset_(_crc_offset) {
+ : crc_offset_(_crc_offset),
+ base_(VSOMEIP_FULL_HEADER_SIZE) {
}
profile_config(const profile_config &_config) = default;
profile_config &operator=(const profile_config &_config) = default;
+
+ uint16_t crc_offset_;
+ size_t base_;
};
} // namespace profile_custom
diff --git a/implementation/e2e_protection/include/e2e/profile/profile_custom/protector.hpp b/implementation/e2e_protection/include/e2e/profile/profile_custom/protector.hpp
index 31b976b..a2ec5d1 100644
--- a/implementation/e2e_protection/include/e2e/profile/profile_custom/protector.hpp
+++ b/implementation/e2e_protection/include/e2e/profile/profile_custom/protector.hpp
@@ -15,18 +15,18 @@ namespace e2e {
namespace profile_custom {
class protector final : public e2e::profile_interface::protector {
- public:
+public:
protector(void) = delete;
explicit protector(const profile_config &_config) : config_(_config){};
- void protect(e2e_buffer &_buffer) override final;
+ void protect(e2e_buffer &_buffer, instance_t _instance) override final;
- private:
+private:
void write_crc(e2e_buffer &_buffer, uint32_t _computed_crc);
- private:
+private:
profile_config config_;
std::mutex protect_mutex_;
};
diff --git a/implementation/e2e_protection/include/e2e/profile/profile_interface/checker.hpp b/implementation/e2e_protection/include/e2e/profile/profile_interface/checker.hpp
index f160ea1..12cb6b7 100644
--- a/implementation/e2e_protection/include/e2e/profile/profile_interface/checker.hpp
+++ b/implementation/e2e_protection/include/e2e/profile/profile_interface/checker.hpp
@@ -6,18 +6,21 @@
#ifndef VSOMEIP_V3_E2E_PROFILE_INTERFACE_CHECKER_HPP
#define VSOMEIP_V3_E2E_PROFILE_INTERFACE_CHECKER_HPP
+#include <mutex>
+
+#include <vsomeip/primitive_types.hpp>
+
#include "../profile_interface/profile_interface.hpp"
#include "../../../buffer/buffer.hpp"
-#include <mutex>
namespace vsomeip_v3 {
namespace e2e {
namespace profile_interface {
class checker : public profile_interface {
- public:
- virtual void check(const e2e_buffer &_buffer,
- check_status_t &_generic_check_status) = 0;
+public:
+ virtual void check(const e2e_buffer &_buffer, instance_t _instance,
+ check_status_t &_generic_check_status) = 0;
};
} // namespace profile_interface
diff --git a/implementation/e2e_protection/include/e2e/profile/profile_interface/profile_interface.hpp b/implementation/e2e_protection/include/e2e/profile/profile_interface/profile_interface.hpp
index dc72aac..5fa018c 100644
--- a/implementation/e2e_protection/include/e2e/profile/profile_interface/profile_interface.hpp
+++ b/implementation/e2e_protection/include/e2e/profile/profile_interface/profile_interface.hpp
@@ -18,8 +18,7 @@ enum generic_check_status : check_status_t { E2E_OK, E2E_WRONG_CRC, E2E_ERROR};
class profile_interface {
public:
- virtual ~profile_interface() {
- }
+ virtual ~profile_interface() {}
};
} // namespace profile_interface
diff --git a/implementation/e2e_protection/include/e2e/profile/profile_interface/protector.hpp b/implementation/e2e_protection/include/e2e/profile/profile_interface/protector.hpp
index 5bae188..4b02971 100644
--- a/implementation/e2e_protection/include/e2e/profile/profile_interface/protector.hpp
+++ b/implementation/e2e_protection/include/e2e/profile/profile_interface/protector.hpp
@@ -6,6 +6,8 @@
#ifndef VSOMEIP_V3_E2E_PROFILE_INTERFACE_PROTECTOR_HPP
#define VSOMEIP_V3_E2E_PROFILE_INTERFACE_PROTECTOR_HPP
+#include <vsomeip/primitive_types.hpp>
+
#include "../../../buffer/buffer.hpp"
#include "../profile_interface/profile_interface.hpp"
@@ -14,8 +16,9 @@ namespace e2e {
namespace profile_interface {
class protector : public profile_interface {
- public:
- virtual void protect(e2e_buffer &_buffer) = 0;
+public:
+ virtual void protect(e2e_buffer &_buffer,
+ instance_t _instance) = 0;
};
} // namespace profile_interface
diff --git a/implementation/e2e_protection/src/crc/crc.cpp b/implementation/e2e_protection/src/crc/crc.cpp
index 335b48d..60ddb6c 100644
--- a/implementation/e2e_protection/src/crc/crc.cpp
+++ b/implementation/e2e_protection/src/crc/crc.cpp
@@ -72,46 +72,48 @@ const uint8_t e2e_crc::lookup_table_profile_01_[256] = {
* - ReflectOut = true
*/
uint32_t e2e_crc::calculate_profile_04(buffer_view _buffer_view, const uint32_t _start_value) {
- uint32_t crc = _start_value ^ 0xFFFFFFFFU;
- for (uint8_t byte : _buffer_view) {
- crc = lookup_table_profile_04_[static_cast<uint8_t>(byte ^ crc)] ^ (crc >> 8U);
- }
- crc = crc ^ 0xFFFFFFFFU;
+ uint32_t crc = (_start_value ^ 0xFFFFFFFFU);
- return crc;
+ for (uint8_t byte : _buffer_view)
+ crc = lookup_table_profile_04_[static_cast<uint8_t>(byte ^ crc)] ^ (crc >> 8U);
+
+ return (crc ^ 0xFFFFFFFFU);
}
const uint32_t e2e_crc::lookup_table_profile_04_[256] = {
- 0x00000000U, 0x30850FF5U, 0x610A1FEAU, 0x518F101FU, 0xC2143FD4U, 0xF2913021U, 0xA31E203EU, 0x939B2FCBU, 0x159615F7U,
- 0x25131A02U, 0x749C0A1DU, 0x441905E8U, 0xD7822A23U, 0xE70725D6U, 0xB68835C9U, 0x860D3A3CU, 0x2B2C2BEEU, 0x1BA9241BU,
- 0x4A263404U, 0x7AA33BF1U, 0xE938143AU, 0xD9BD1BCFU, 0x88320BD0U, 0xB8B70425U, 0x3EBA3E19U, 0x0E3F31ECU, 0x5FB021F3U,
- 0x6F352E06U, 0xFCAE01CDU, 0xCC2B0E38U, 0x9DA41E27U, 0xAD2111D2U, 0x565857DCU, 0x66DD5829U, 0x37524836U, 0x07D747C3U,
- 0x944C6808U, 0xA4C967FDU, 0xF54677E2U, 0xC5C37817U, 0x43CE422BU, 0x734B4DDEU, 0x22C45DC1U, 0x12415234U, 0x81DA7DFFU,
- 0xB15F720AU, 0xE0D06215U, 0xD0556DE0U, 0x7D747C32U, 0x4DF173C7U, 0x1C7E63D8U, 0x2CFB6C2DU, 0xBF6043E6U, 0x8FE54C13U,
- 0xDE6A5C0CU, 0xEEEF53F9U, 0x68E269C5U, 0x58676630U, 0x09E8762FU, 0x396D79DAU, 0xAAF65611U, 0x9A7359E4U, 0xCBFC49FBU,
- 0xFB79460EU, 0xACB0AFB8U, 0x9C35A04DU, 0xCDBAB052U, 0xFD3FBFA7U, 0x6EA4906CU, 0x5E219F99U, 0x0FAE8F86U, 0x3F2B8073U,
- 0xB926BA4FU, 0x89A3B5BAU, 0xD82CA5A5U, 0xE8A9AA50U, 0x7B32859BU, 0x4BB78A6EU, 0x1A389A71U, 0x2ABD9584U, 0x879C8456U,
- 0xB7198BA3U, 0xE6969BBCU, 0xD6139449U, 0x4588BB82U, 0x750DB477U, 0x2482A468U, 0x1407AB9DU, 0x920A91A1U, 0xA28F9E54U,
- 0xF3008E4BU, 0xC38581BEU, 0x501EAE75U, 0x609BA180U, 0x3114B19FU, 0x0191BE6AU, 0xFAE8F864U, 0xCA6DF791U, 0x9BE2E78EU,
- 0xAB67E87BU, 0x38FCC7B0U, 0x0879C845U, 0x59F6D85AU, 0x6973D7AFU, 0xEF7EED93U, 0xDFFBE266U, 0x8E74F279U, 0xBEF1FD8CU,
- 0x2D6AD247U, 0x1DEFDDB2U, 0x4C60CDADU, 0x7CE5C258U, 0xD1C4D38AU, 0xE141DC7FU, 0xB0CECC60U, 0x804BC395U, 0x13D0EC5EU,
- 0x2355E3ABU, 0x72DAF3B4U, 0x425FFC41U, 0xC452C67DU, 0xF4D7C988U, 0xA558D997U, 0x95DDD662U, 0x0646F9A9U, 0x36C3F65CU,
- 0x674CE643U, 0x57C9E9B6U, 0xC8DF352FU, 0xF85A3ADAU, 0xA9D52AC5U, 0x99502530U, 0x0ACB0AFBU, 0x3A4E050EU, 0x6BC11511U,
- 0x5B441AE4U, 0xDD4920D8U, 0xEDCC2F2DU, 0xBC433F32U, 0x8CC630C7U, 0x1F5D1F0CU, 0x2FD810F9U, 0x7E5700E6U, 0x4ED20F13U,
- 0xE3F31EC1U, 0xD3761134U, 0x82F9012BU, 0xB27C0EDEU, 0x21E72115U, 0x11622EE0U, 0x40ED3EFFU, 0x7068310AU, 0xF6650B36U,
- 0xC6E004C3U, 0x976F14DCU, 0xA7EA1B29U, 0x347134E2U, 0x04F43B17U, 0x557B2B08U, 0x65FE24FDU, 0x9E8762F3U, 0xAE026D06U,
- 0xFF8D7D19U, 0xCF0872ECU, 0x5C935D27U, 0x6C1652D2U, 0x3D9942CDU, 0x0D1C4D38U, 0x8B117704U, 0xBB9478F1U, 0xEA1B68EEU,
- 0xDA9E671BU, 0x490548D0U, 0x79804725U, 0x280F573AU, 0x188A58CFU, 0xB5AB491DU, 0x852E46E8U, 0xD4A156F7U, 0xE4245902U,
- 0x77BF76C9U, 0x473A793CU, 0x16B56923U, 0x263066D6U, 0xA03D5CEAU, 0x90B8531FU, 0xC1374300U, 0xF1B24CF5U, 0x6229633EU,
- 0x52AC6CCBU, 0x03237CD4U, 0x33A67321U, 0x646F9A97U, 0x54EA9562U, 0x0565857DU, 0x35E08A88U, 0xA67BA543U, 0x96FEAAB6U,
- 0xC771BAA9U, 0xF7F4B55CU, 0x71F98F60U, 0x417C8095U, 0x10F3908AU, 0x20769F7FU, 0xB3EDB0B4U, 0x8368BF41U, 0xD2E7AF5EU,
- 0xE262A0ABU, 0x4F43B179U, 0x7FC6BE8CU, 0x2E49AE93U, 0x1ECCA166U, 0x8D578EADU, 0xBDD28158U, 0xEC5D9147U, 0xDCD89EB2U,
- 0x5AD5A48EU, 0x6A50AB7BU, 0x3BDFBB64U, 0x0B5AB491U, 0x98C19B5AU, 0xA84494AFU, 0xF9CB84B0U, 0xC94E8B45U, 0x3237CD4BU,
- 0x02B2C2BEU, 0x533DD2A1U, 0x63B8DD54U, 0xF023F29FU, 0xC0A6FD6AU, 0x9129ED75U, 0xA1ACE280U, 0x27A1D8BCU, 0x1724D749U,
- 0x46ABC756U, 0x762EC8A3U, 0xE5B5E768U, 0xD530E89DU, 0x84BFF882U, 0xB43AF777U, 0x191BE6A5U, 0x299EE950U, 0x7811F94FU,
- 0x4894F6BAU, 0xDB0FD971U, 0xEB8AD684U, 0xBA05C69BU, 0x8A80C96EU, 0x0C8DF352U, 0x3C08FCA7U, 0x6D87ECB8U, 0x5D02E34DU,
- 0xCE99CC86U, 0xFE1CC373U, 0xAF93D36CU, 0x9F16DC99U
+ 0x00000000U, 0x30850FF5U, 0x610A1FEAU, 0x518F101FU, 0xC2143FD4U, 0xF2913021U, 0xA31E203EU, 0x939B2FCBU,
+ 0x159615F7U, 0x25131A02U, 0x749C0A1DU, 0x441905E8U, 0xD7822A23U, 0xE70725D6U, 0xB68835C9U, 0x860D3A3CU,
+ 0x2B2C2BEEU, 0x1BA9241BU, 0x4A263404U, 0x7AA33BF1U, 0xE938143AU, 0xD9BD1BCFU, 0x88320BD0U, 0xB8B70425U,
+ 0x3EBA3E19U, 0x0E3F31ECU, 0x5FB021F3U, 0x6F352E06U, 0xFCAE01CDU, 0xCC2B0E38U, 0x9DA41E27U, 0xAD2111D2U,
+ 0x565857DCU, 0x66DD5829U, 0x37524836U, 0x07D747C3U, 0x944C6808U, 0xA4C967FDU, 0xF54677E2U, 0xC5C37817U,
+ 0x43CE422BU, 0x734B4DDEU, 0x22C45DC1U, 0x12415234U, 0x81DA7DFFU, 0xB15F720AU, 0xE0D06215U, 0xD0556DE0U,
+ 0x7D747C32U, 0x4DF173C7U, 0x1C7E63D8U, 0x2CFB6C2DU, 0xBF6043E6U, 0x8FE54C13U, 0xDE6A5C0CU, 0xEEEF53F9U,
+ 0x68E269C5U, 0x58676630U, 0x09E8762FU, 0x396D79DAU, 0xAAF65611U, 0x9A7359E4U, 0xCBFC49FBU, 0xFB79460EU,
+ 0xACB0AFB8U, 0x9C35A04DU, 0xCDBAB052U, 0xFD3FBFA7U, 0x6EA4906CU, 0x5E219F99U, 0x0FAE8F86U, 0x3F2B8073U,
+ 0xB926BA4FU, 0x89A3B5BAU, 0xD82CA5A5U, 0xE8A9AA50U, 0x7B32859BU, 0x4BB78A6EU, 0x1A389A71U, 0x2ABD9584U,
+ 0x879C8456U, 0xB7198BA3U, 0xE6969BBCU, 0xD6139449U, 0x4588BB82U, 0x750DB477U, 0x2482A468U, 0x1407AB9DU,
+ 0x920A91A1U, 0xA28F9E54U, 0xF3008E4BU, 0xC38581BEU, 0x501EAE75U, 0x609BA180U, 0x3114B19FU, 0x0191BE6AU,
+ 0xFAE8F864U, 0xCA6DF791U, 0x9BE2E78EU, 0xAB67E87BU, 0x38FCC7B0U, 0x0879C845U, 0x59F6D85AU, 0x6973D7AFU,
+ 0xEF7EED93U, 0xDFFBE266U, 0x8E74F279U, 0xBEF1FD8CU, 0x2D6AD247U, 0x1DEFDDB2U, 0x4C60CDADU, 0x7CE5C258U,
+ 0xD1C4D38AU, 0xE141DC7FU, 0xB0CECC60U, 0x804BC395U, 0x13D0EC5EU, 0x2355E3ABU, 0x72DAF3B4U, 0x425FFC41U,
+ 0xC452C67DU, 0xF4D7C988U, 0xA558D997U, 0x95DDD662U, 0x0646F9A9U, 0x36C3F65CU, 0x674CE643U, 0x57C9E9B6U,
+ 0xC8DF352FU, 0xF85A3ADAU, 0xA9D52AC5U, 0x99502530U, 0x0ACB0AFBU, 0x3A4E050EU, 0x6BC11511U, 0x5B441AE4U,
+ 0xDD4920D8U, 0xEDCC2F2DU, 0xBC433F32U, 0x8CC630C7U, 0x1F5D1F0CU, 0x2FD810F9U, 0x7E5700E6U, 0x4ED20F13U,
+ 0xE3F31EC1U, 0xD3761134U, 0x82F9012BU, 0xB27C0EDEU, 0x21E72115U, 0x11622EE0U, 0x40ED3EFFU, 0x7068310AU,
+ 0xF6650B36U, 0xC6E004C3U, 0x976F14DCU, 0xA7EA1B29U, 0x347134E2U, 0x04F43B17U, 0x557B2B08U, 0x65FE24FDU,
+ 0x9E8762F3U, 0xAE026D06U, 0xFF8D7D19U, 0xCF0872ECU, 0x5C935D27U, 0x6C1652D2U, 0x3D9942CDU, 0x0D1C4D38U,
+ 0x8B117704U, 0xBB9478F1U, 0xEA1B68EEU, 0xDA9E671BU, 0x490548D0U, 0x79804725U, 0x280F573AU, 0x188A58CFU,
+ 0xB5AB491DU, 0x852E46E8U, 0xD4A156F7U, 0xE4245902U, 0x77BF76C9U, 0x473A793CU, 0x16B56923U, 0x263066D6U,
+ 0xA03D5CEAU, 0x90B8531FU, 0xC1374300U, 0xF1B24CF5U, 0x6229633EU, 0x52AC6CCBU, 0x03237CD4U, 0x33A67321U,
+ 0x646F9A97U, 0x54EA9562U, 0x0565857DU, 0x35E08A88U, 0xA67BA543U, 0x96FEAAB6U, 0xC771BAA9U, 0xF7F4B55CU,
+ 0x71F98F60U, 0x417C8095U, 0x10F3908AU, 0x20769F7FU, 0xB3EDB0B4U, 0x8368BF41U, 0xD2E7AF5EU, 0xE262A0ABU,
+ 0x4F43B179U, 0x7FC6BE8CU, 0x2E49AE93U, 0x1ECCA166U, 0x8D578EADU, 0xBDD28158U, 0xEC5D9147U, 0xDCD89EB2U,
+ 0x5AD5A48EU, 0x6A50AB7BU, 0x3BDFBB64U, 0x0B5AB491U, 0x98C19B5AU, 0xA84494AFU, 0xF9CB84B0U, 0xC94E8B45U,
+ 0x3237CD4BU, 0x02B2C2BEU, 0x533DD2A1U, 0x63B8DD54U, 0xF023F29FU, 0xC0A6FD6AU, 0x9129ED75U, 0xA1ACE280U,
+ 0x27A1D8BCU, 0x1724D749U, 0x46ABC756U, 0x762EC8A3U, 0xE5B5E768U, 0xD530E89DU, 0x84BFF882U, 0xB43AF777U,
+ 0x191BE6A5U, 0x299EE950U, 0x7811F94FU, 0x4894F6BAU, 0xDB0FD971U, 0xEB8AD684U, 0xBA05C69BU, 0x8A80C96EU,
+ 0x0C8DF352U, 0x3C08FCA7U, 0x6D87ECB8U, 0x5D02E34DU, 0xCE99CC86U, 0xFE1CC373U, 0xAF93D36CU, 0x9F16DC99U
};
/**
diff --git a/implementation/e2e_protection/src/e2e/profile/e2e_provider_impl.cpp b/implementation/e2e_protection/src/e2e/profile/e2e_provider_impl.cpp
index 7a82446..111e126 100644
--- a/implementation/e2e_protection/src/e2e/profile/e2e_provider_impl.cpp
+++ b/implementation/e2e_protection/src/e2e/profile/e2e_provider_impl.cpp
@@ -3,33 +3,49 @@
// License, v. 2.0. If a copy of the MPL was not distributed with this
// file, You can obtain one at http://mozilla.org/MPL/2.0/.
+#include <iomanip>
+#include <sstream>
+
+#include <vsomeip/internal/logger.hpp>
+
#include "../../../../e2e_protection/include/e2e/profile/e2e_provider_impl.hpp"
#include "../../../../e2e_protection/include/e2e/profile/profile01/checker.hpp"
#include "../../../../e2e_protection/include/e2e/profile/profile01/profile_01.hpp"
#include "../../../../e2e_protection/include/e2e/profile/profile01/protector.hpp"
+#include "../../../../e2e_protection/include/e2e/profile/profile04/checker.hpp"
+#include "../../../../e2e_protection/include/e2e/profile/profile04/profile_04.hpp"
+#include "../../../../e2e_protection/include/e2e/profile/profile04/protector.hpp"
+
#include "../../../../e2e_protection/include/e2e/profile/profile_custom/checker.hpp"
#include "../../../../e2e_protection/include/e2e/profile/profile_custom/profile_custom.hpp"
#include "../../../../e2e_protection/include/e2e/profile/profile_custom/protector.hpp"
-#include <sstream>
-
namespace {
template<typename value_t>
-value_t read_value_from_config(const std::shared_ptr<vsomeip_v3::cfg::e2e>& config,
- const std::string& name,
- value_t default_value = value_t()) {
- if(config && config->custom_parameters.count(name)) {
- value_t value;
+value_t read_value_from_config(const std::shared_ptr<vsomeip_v3::cfg::e2e> &_config,
+ const std::string &_name,
+ value_t _default_value = value_t()) {
+
+ if (_config && _config->custom_parameters.count(_name)) {
+
std::stringstream its_converter;
- its_converter << config->custom_parameters[name];
- its_converter >> value;
- return value;
+ std::string its_value(_config->custom_parameters[_name]);
+
+ if (its_value.size() > 1 && its_value[0] == '0' && its_value[1] == 'x') {
+ its_converter << std::hex << its_value;
+ } else {
+ its_converter << std::dec << its_value;
+ }
+
+ value_t its_converted_value;
+ its_converter >> its_converted_value;
+ return its_converted_value;
}
- return default_value;
+ return _default_value;
}
} // namespace
@@ -51,67 +67,109 @@ e2e_provider_impl::~e2e_provider_impl()
bool e2e_provider_impl::add_configuration(std::shared_ptr<cfg::e2e> config)
{
- if(config->profile == "CRC8") {
+ if (config->profile == "CRC8" || config->profile == "P01") {
process_e2e_profile<profile01::profile_config, profile01::profile_01_checker, profile01::protector>(config);
return true;
}
- if(config->profile == "CRC32") {
+ if (config->profile == "CRC32" || config->profile == "CSTM") {
process_e2e_profile<profile_custom::profile_config, profile_custom::profile_custom_checker, profile_custom::protector>(config);
return true;
}
+ if (config->profile == "P04") {
+ process_e2e_profile<profile04::profile_config, profile04::profile_04_checker, profile04::protector>(config);
+ return true;
+ }
+
return false;
}
bool e2e_provider_impl::is_protected(e2exf::data_identifier_t id) const
{
- return custom_protectors.count(id) > 0;
+ return custom_protectors_.count(id) > 0;
}
bool e2e_provider_impl::is_checked(e2exf::data_identifier_t id) const
{
- return custom_checkers.count(id) > 0;
+ return custom_checkers_.count(id) > 0;
+}
+
+std::size_t e2e_provider_impl::get_protection_base(e2exf::data_identifier_t id) const
+{
+ const auto found_base = custom_bases_.find(id);
+ if (found_base != custom_bases_.end())
+ return (found_base->second);
+
+ return (0);
}
-void e2e_provider_impl::protect(e2exf::data_identifier_t id, e2e_buffer &_buffer)
+void e2e_provider_impl::protect(e2exf::data_identifier_t id, e2e_buffer &_buffer,
+ instance_t _instance)
{
- auto protector = custom_protectors.find(id);
- if(protector != custom_protectors.end()) {
- protector->second->protect(_buffer);
+ auto protector = custom_protectors_.find(id);
+ if(protector != custom_protectors_.end()) {
+ protector->second->protect(_buffer, _instance);
}
}
-void e2e_provider_impl::check(e2exf::data_identifier_t id, const e2e_buffer &_buffer,
- profile_interface::check_status_t &_generic_check_status)
+void e2e_provider_impl::check(e2exf::data_identifier_t id,
+ const e2e_buffer &_buffer, instance_t _instance,
+ profile_interface::check_status_t &_generic_check_status)
{
- auto checker = custom_checkers.find(id);
- if(checker != custom_checkers.end()) {
- checker->second->check(_buffer, _generic_check_status);
+ auto checker = custom_checkers_.find(id);
+ if(checker != custom_checkers_.end()) {
+ checker->second->check(_buffer, _instance, _generic_check_status);
}
}
template<>
vsomeip_v3::e2e::profile01::profile_config
-e2e_provider_impl::make_e2e_profile_config(const std::shared_ptr<cfg::e2e>& config) {
- uint16_t crc_offset = read_value_from_config<uint16_t>(config, "crc_offset");
- uint16_t data_length = read_value_from_config<uint16_t>(config, "data_length");
+e2e_provider_impl::make_e2e_profile_config(const std::shared_ptr<cfg::e2e> &_config) {
+ uint16_t data_id = read_value_from_config<uint16_t>(_config, "data_id");
+ uint16_t crc_offset = read_value_from_config<uint16_t>(_config, "crc_offset");
+ uint16_t data_length = read_value_from_config<uint16_t>(_config, "data_length");
// counter field behind CRC8
- uint16_t counter_offset = read_value_from_config<uint16_t>(config, "counter_offset", 8);
+ uint16_t counter_offset = read_value_from_config<uint16_t>(_config, "counter_offset", 8);
// data id nibble behind 4 bit counter value
- uint16_t data_id_nibble_offset = read_value_from_config<uint16_t>(config, "data_id_nibble_offset", 12);
+ uint16_t data_id_nibble_offset = read_value_from_config<uint16_t>(_config, "data_id_nibble_offset", 12);
e2e::profile01::p01_data_id_mode data_id_mode =
static_cast<e2e::profile01::p01_data_id_mode>(
- read_value_from_config<uint16_t>(config, "data_id_mode"));
+ read_value_from_config<uint16_t>(_config, "data_id_mode"));
- return e2e::profile01::profile_config(crc_offset, config->data_id, data_id_mode,
+ return e2e::profile01::profile_config(crc_offset, data_id, data_id_mode,
data_length, counter_offset, data_id_nibble_offset);
}
template<>
+vsomeip_v3::e2e::profile04::profile_config
+e2e_provider_impl::make_e2e_profile_config(const std::shared_ptr<cfg::e2e> &_config) {
+
+ uint32_t data_id = read_value_from_config<uint32_t>(_config, "data_id");
+
+ size_t offset = read_value_from_config<size_t>(_config, "crc_offset");
+ if (offset % 8)
+ VSOMEIP_ERROR << "Offset in E2E P04 configuration must be multiple of 8"
+ " (" << offset << ")";
+ offset /= 8;
+
+ size_t min_data_length = read_value_from_config<size_t>(_config,
+ "min_data_length", 0);
+
+ size_t max_data_length = read_value_from_config<size_t>(_config,
+ "max_data_length", size_t(0xffff));
+
+ uint16_t max_delta_counter = read_value_from_config<uint16_t>(_config,
+ "max_delta_counter", uint16_t(0xffff));
+
+ return e2e::profile04::profile_config(data_id, offset,
+ min_data_length, max_data_length, max_delta_counter);
+}
+
+template<>
e2e::profile_custom::profile_config
e2e_provider_impl::make_e2e_profile_config(const std::shared_ptr<cfg::e2e>& config) {
uint16_t crc_offset = read_value_from_config<uint16_t>(config, "crc_offset");
diff --git a/implementation/e2e_protection/src/e2e/profile/profile01/checker.cpp b/implementation/e2e_protection/src/e2e/profile/profile01/checker.cpp
index bea8dc1..a5d75d8 100644
--- a/implementation/e2e_protection/src/e2e/profile/profile01/checker.cpp
+++ b/implementation/e2e_protection/src/e2e/profile/profile01/checker.cpp
@@ -16,8 +16,11 @@ namespace e2e {
namespace profile01 {
// [SWS_E2E_00196]
-void profile_01_checker::check(const e2e_buffer &_buffer,
- e2e::profile_interface::check_status_t &_generic_check_status) {
+void profile_01_checker::check(const e2e_buffer &_buffer, instance_t _instance,
+ e2e::profile_interface::check_status_t &_generic_check_status) {
+
+ (void)_instance;
+
std::lock_guard<std::mutex> lock(check_mutex_);
_generic_check_status = e2e::profile_interface::generic_check_status::E2E_ERROR;
@@ -34,7 +37,6 @@ void profile_01_checker::check(const e2e_buffer &_buffer,
<< (uint32_t) calculated_crc << " received CRC: " << (uint32_t) received_crc;
}
}
- return;
}
} // namespace profile01
diff --git a/implementation/e2e_protection/src/e2e/profile/profile01/protector.cpp b/implementation/e2e_protection/src/e2e/profile/profile01/protector.cpp
index 551a801..e5cb4ba 100644
--- a/implementation/e2e_protection/src/e2e/profile/profile01/protector.cpp
+++ b/implementation/e2e_protection/src/e2e/profile/profile01/protector.cpp
@@ -16,7 +16,10 @@ namespace e2e {
namespace profile01 {
/** @req [SWS_E2E_00195] */
-void protector::protect(e2e_buffer &_buffer) {
+void protector::protect(e2e_buffer &_buffer, instance_t _instance) {
+
+ (void)_instance;
+
std::lock_guard<std::mutex> lock(protect_mutex_);
if (profile_01::is_buffer_length_valid(config_, _buffer)) {
diff --git a/implementation/e2e_protection/src/e2e/profile/profile04/checker.cpp b/implementation/e2e_protection/src/e2e/profile/profile04/checker.cpp
new file mode 100644
index 0000000..c9761ca
--- /dev/null
+++ b/implementation/e2e_protection/src/e2e/profile/profile04/checker.cpp
@@ -0,0 +1,114 @@
+// Copyright (C) 2020 Bayerische Motoren Werke Aktiengesellschaft (BMW AG)
+// This Source Code Form is subject to the terms of the Mozilla Public
+// License, v. 2.0. If a copy of the MPL was not distributed with this
+// file, You can obtain one at http://mozilla.org/MPL/2.0/.
+
+#include <iomanip>
+
+#include <vsomeip/internal/logger.hpp>
+#include "../../utility/include/byteorder.hpp"
+
+#include "../../../../../e2e_protection/include/e2e/profile/profile04/checker.hpp"
+
+
+namespace vsomeip_v3 {
+namespace e2e {
+namespace profile04 {
+
+// [SWS_E2E_00355]
+void profile_04_checker::check(const e2e_buffer &_buffer, instance_t _instance,
+ e2e::profile_interface::check_status_t &_generic_check_status) {
+
+ std::lock_guard<std::mutex> lock(check_mutex_);
+ _generic_check_status = e2e::profile_interface::generic_check_status::E2E_ERROR;
+
+ if (_instance > VSOMEIP_E2E_PROFILE04_MAX_INSTANCE) {
+ VSOMEIP_ERROR << "E2E Profile 4 can only be used for instances [1-255]";
+ return;
+ }
+
+ /** @req [SWS_E2E_356] */
+ if (verify_input(_buffer)) {
+ /** @req [SWS_E2E_357] */
+ uint16_t its_received_length;
+ if (read_16(_buffer, its_received_length, 0)) {
+ /** @req [SWS_E2E_358] */
+ uint16_t its_received_counter;
+ if (read_16(_buffer, its_received_counter, 2)) {
+ /** @req [SWS_E2E_359] */
+ uint32_t its_received_data_id;
+ if (read_32(_buffer, its_received_data_id, 4)) {
+ /** @req [SWS_E2E_360] */
+ uint32_t its_received_crc;
+ if (read_32(_buffer, its_received_crc, 8)) {
+ uint32_t its_crc = profile_04::compute_crc(config_, _buffer);
+ /** @req [SWS_E2E_361] */
+ if (its_received_crc != its_crc) {
+ _generic_check_status = e2e::profile_interface::generic_check_status::E2E_WRONG_CRC;
+ VSOMEIP_ERROR << std::hex << "E2E P04 protection: CRC32 does not match: calculated CRC: "
+ << its_crc << " received CRC: " << its_received_crc;
+ } else {
+ uint32_t its_data_id(uint32_t(_instance) << 24 | config_.data_id_);
+ if (its_received_data_id == its_data_id
+ && static_cast<size_t>(its_received_length) == _buffer.size()
+ && verify_counter(its_received_counter)) {
+ _generic_check_status = e2e::profile_interface::generic_check_status::E2E_OK;
+ }
+ counter_ = its_received_counter;
+ }
+ }
+ }
+ }
+ }
+ }
+}
+
+bool
+profile_04_checker::verify_input(const e2e_buffer &_buffer) const {
+
+ auto its_length = _buffer.size();
+ return (its_length >= config_.min_data_length_
+ && its_length <= config_.max_data_length_);
+}
+
+bool
+profile_04_checker::verify_counter(uint16_t _received_counter) const {
+
+ static bool has_counter(false);
+ uint16_t its_delta(0);
+
+ if (has_counter) {
+ if (counter_ < _received_counter)
+ its_delta = uint16_t(_received_counter - counter_);
+ else
+ its_delta = uint16_t(uint16_t(0xffff) - counter_ + _received_counter);
+ } else {
+ has_counter = true;
+ }
+
+ return (its_delta <= config_.max_delta_counter_);
+}
+
+bool
+profile_04_checker::read_16(const e2e_buffer &_buffer,
+ uint16_t &_data, size_t _index) const {
+
+ _data = VSOMEIP_BYTES_TO_WORD(_buffer[config_.offset_ + _index],
+ _buffer[config_.offset_ + _index + 1]);
+ return (true);
+}
+
+bool
+profile_04_checker::read_32(const e2e_buffer &_buffer,
+ uint32_t &_data, size_t _index) const {
+
+ _data = VSOMEIP_BYTES_TO_LONG(_buffer[config_.offset_ + _index],
+ _buffer[config_.offset_ + _index + 1],
+ _buffer[config_.offset_ + _index + 2],
+ _buffer[config_.offset_ + _index + 3]);
+ return (true);
+}
+
+} // namespace profile01
+} // namespace e2e
+} // namespace vsomeip_v3
diff --git a/implementation/e2e_protection/src/e2e/profile/profile04/profile_04.cpp b/implementation/e2e_protection/src/e2e/profile/profile04/profile_04.cpp
new file mode 100644
index 0000000..05ab5e9
--- /dev/null
+++ b/implementation/e2e_protection/src/e2e/profile/profile04/profile_04.cpp
@@ -0,0 +1,33 @@
+// Copyright (C) 2014-2017 Bayerische Motoren Werke Aktiengesellschaft (BMW AG)
+// This Source Code Form is subject to the terms of the Mozilla Public
+// License, v. 2.0. If a copy of the MPL was not distributed with this
+// file, You can obtain one at http://mozilla.org/MPL/2.0/.
+
+#include <iomanip>
+#include <iostream>
+#include <sstream>
+#include <string>
+
+#include "../../../../../e2e_protection/include/e2e/profile/profile04/profile_04.hpp"
+#include "../../../../../e2e_protection/include/crc/crc.hpp"
+
+namespace vsomeip_v3 {
+namespace e2e {
+namespace profile04 {
+
+uint32_t profile_04::compute_crc(const profile_config &_config, const e2e_buffer &_buffer) {
+
+ buffer_view its_before(_buffer, _config.offset_ + 8);
+ uint32_t computed_crc = e2e_crc::calculate_profile_04(its_before);
+
+ if (_config.offset_ + 12 < _buffer.size()) {
+ buffer_view its_after(_buffer, _config.offset_ + 12, _buffer.size());
+ computed_crc = e2e_crc::calculate_profile_04(its_after, computed_crc);
+ }
+
+ return (computed_crc);
+}
+
+} // namespace profile04
+} // namespace e2e
+} // namespace vsomeip_v3
diff --git a/implementation/e2e_protection/src/e2e/profile/profile04/protector.cpp b/implementation/e2e_protection/src/e2e/profile/profile04/protector.cpp
new file mode 100644
index 0000000..a9287f2
--- /dev/null
+++ b/implementation/e2e_protection/src/e2e/profile/profile04/protector.cpp
@@ -0,0 +1,81 @@
+// Copyright (C) 2020 Bayerische Motoren Werke Aktiengesellschaft (BMW AG)
+// This Source Code Form is subject to the terms of the Mozilla Public
+// License, v. 2.0. If a copy of the MPL was not distributed with this
+// file, You can obtain one at http://mozilla.org/MPL/2.0/.
+
+#include <iomanip>
+
+#include "../../../../../e2e_protection/include/e2e/profile/profile04/protector.hpp"
+
+#include <vsomeip/internal/logger.hpp>
+#include "../../utility/include/byteorder.hpp"
+
+namespace vsomeip_v3 {
+namespace e2e {
+namespace profile04 {
+
+/** @req [SWS_E2E_00195] */
+void
+protector::protect(e2e_buffer &_buffer, instance_t _instance) {
+ std::lock_guard<std::mutex> lock(protect_mutex_);
+
+ if (_instance > VSOMEIP_E2E_PROFILE04_MAX_INSTANCE) {
+ VSOMEIP_ERROR << "E2E Profile 4 can only be used for instances [1-255]";
+ return;
+ }
+
+ /** @req: [SWS_E2E_00363] */
+ if (verify_inputs(_buffer)) {
+
+ /** @req [SWS_E2E_00364] */
+ write_16(_buffer, static_cast<uint16_t>(_buffer.size()), 0);
+
+ /** @req [SWS_E2E_00365] */
+ write_16(_buffer, counter_, 2);
+
+ /** @req [SWS_E2E_00366] */
+ uint32_t its_data_id(uint32_t(_instance) << 24 | config_.data_id_);
+ write_32(_buffer, its_data_id, 4);
+
+ /** @req [SWS_E2E_00367] */
+ uint32_t its_crc = profile_04::compute_crc(config_, _buffer);
+
+ /** @req [SWS_E2E_0368] */
+ write_32(_buffer, its_crc, 8);
+
+ /** @req [SWS_E2E_00369] */
+ increment_counter();
+ }
+}
+
+bool
+protector::verify_inputs(e2e_buffer &_buffer) {
+
+ return (_buffer.size() >= config_.min_data_length_
+ && _buffer.size() <= config_.max_data_length_);
+}
+
+void
+protector::write_16(e2e_buffer &_buffer, uint16_t _data, size_t _index) {
+
+ _buffer[config_.offset_ + _index] = VSOMEIP_WORD_BYTE1(_data);
+ _buffer[config_.offset_ + _index + 1] = VSOMEIP_WORD_BYTE0(_data);
+}
+
+void
+protector::write_32(e2e_buffer &_buffer, uint32_t _data, size_t _index) {
+
+ _buffer[config_.offset_ + _index] = VSOMEIP_LONG_BYTE3(_data);
+ _buffer[config_.offset_ + _index + 1] = VSOMEIP_LONG_BYTE2(_data);
+ _buffer[config_.offset_ + _index + 2] = VSOMEIP_LONG_BYTE1(_data);
+ _buffer[config_.offset_ + _index + 3] = VSOMEIP_LONG_BYTE0(_data);
+}
+
+void
+protector::increment_counter() {
+ counter_++;
+}
+
+} // namespace profile04
+} // namespace e2e
+} // namespace vsomeip_v3
diff --git a/implementation/e2e_protection/src/e2e/profile/profile_custom/checker.cpp b/implementation/e2e_protection/src/e2e/profile/profile_custom/checker.cpp
index 42e1ca8..9916a2f 100644
--- a/implementation/e2e_protection/src/e2e/profile/profile_custom/checker.cpp
+++ b/implementation/e2e_protection/src/e2e/profile/profile_custom/checker.cpp
@@ -16,11 +16,15 @@ namespace e2e {
namespace profile_custom {
void profile_custom_checker::check(const e2e_buffer &_buffer,
- e2e::profile_interface::check_status_t &_generic_check_status) {
+ instance_t _instance,
+ e2e::profile_interface::check_status_t &_generic_check_status) {
+
+ (void)_instance;
+
std::lock_guard<std::mutex> lock(check_mutex_);
_generic_check_status = e2e::profile_interface::generic_check_status::E2E_ERROR;
- if (profile_custom::is_buffer_length_valid(config_, _buffer)) {
+ if (profile_custom::is_buffer_length_valid(config_, _buffer)) {
uint32_t received_crc(0);
uint32_t calculated_crc(0);
@@ -34,7 +38,6 @@ void profile_custom_checker::check(const e2e_buffer &_buffer,
<< (uint32_t) calculated_crc << " received CRC: " << (uint32_t) received_crc;
}
}
- return;
}
uint32_t profile_custom_checker::read_crc(const e2e_buffer &_buffer) const {
diff --git a/implementation/e2e_protection/src/e2e/profile/profile_custom/protector.cpp b/implementation/e2e_protection/src/e2e/profile/profile_custom/protector.cpp
index 276c02b..c71f91f 100644
--- a/implementation/e2e_protection/src/e2e/profile/profile_custom/protector.cpp
+++ b/implementation/e2e_protection/src/e2e/profile/profile_custom/protector.cpp
@@ -16,7 +16,10 @@ namespace vsomeip_v3 {
namespace e2e {
namespace profile_custom {
-void protector::protect(e2e_buffer &_buffer) {
+void protector::protect(e2e_buffer &_buffer, instance_t _instance) {
+
+ (void)_instance;
+
std::lock_guard<std::mutex> lock(protect_mutex_);
if (profile_custom::is_buffer_length_valid(config_, _buffer)) {
diff --git a/implementation/endpoints/include/endpoint_manager_impl.hpp b/implementation/endpoints/include/endpoint_manager_impl.hpp
index cdf41b8..a7d28c6 100644
--- a/implementation/endpoints/include/endpoint_manager_impl.hpp
+++ b/implementation/endpoints/include/endpoint_manager_impl.hpp
@@ -44,12 +44,13 @@ public:
std::shared_ptr<endpoint> create_server_endpoint(uint16_t _port,
bool _reliable,
bool _start);
+
std::shared_ptr<endpoint> find_server_endpoint(uint16_t _port,
bool _reliable) const;
std::shared_ptr<endpoint> find_or_create_server_endpoint(
uint16_t _port, bool _reliable, bool _start, service_t _service,
- instance_t _instance);
+ instance_t _instance, bool &_is_found, bool _is_multicast = false);
bool remove_server_endpoint(uint16_t _port, bool _reliable);
@@ -57,6 +58,7 @@ public:
bool _reliable);
void find_or_create_multicast_endpoint(
service_t _service, instance_t _instance,
+ const boost::asio::ip::address &_sender,
const boost::asio::ip::address &_address, uint16_t _port);
void clear_multicast_endpoints(service_t _service, instance_t _instance);
@@ -70,7 +72,12 @@ public:
instance_t find_instance(service_t _service,
endpoint* const _endpoint) const;
+ instance_t find_instance_multicast(service_t _service,
+ const boost::asio::ip::address &_sender) const;
+
bool remove_instance(service_t _service, endpoint* const _endpoint);
+ bool remove_instance_multicast(service_t _service, instance_t _instance);
+
// endpoint_host interface
void on_connect(std::shared_ptr<endpoint> _endpoint);
@@ -111,6 +118,7 @@ private:
client_endpoints_by_ip_t client_endpoints_by_ip_;
std::map<service_t, std::map<endpoint *, instance_t> > service_instances_;
+ std::map<service_t, std::map<boost::asio::ip::address, instance_t> > service_instances_multicast_;
std::map<bool, std::set<uint16_t>> used_client_ports_;
std::mutex used_client_ports_mutex_;
diff --git a/implementation/endpoints/include/server_endpoint_impl.hpp b/implementation/endpoints/include/server_endpoint_impl.hpp
index 4e03115..193043c 100644
--- a/implementation/endpoints/include/server_endpoint_impl.hpp
+++ b/implementation/endpoints/include/server_endpoint_impl.hpp
@@ -107,6 +107,10 @@ protected:
mutable std::mutex mutex_;
+ std::mutex sent_mutex_;
+ bool is_sending_;
+ boost::asio::steady_timer sent_timer_;
+
private:
virtual std::string get_remote_information(
const queue_iterator_type _queue_iterator) const = 0;
diff --git a/implementation/endpoints/include/tcp_server_endpoint_impl.hpp b/implementation/endpoints/include/tcp_server_endpoint_impl.hpp
index c6481b8..af9a724 100644
--- a/implementation/endpoints/include/tcp_server_endpoint_impl.hpp
+++ b/implementation/endpoints/include/tcp_server_endpoint_impl.hpp
@@ -106,6 +106,7 @@ private:
service_t _service, method_t _method, client_t _client, session_t _session,
const std::chrono::steady_clock::time_point _start);
void stop_and_remove_connection();
+ void wait_until_sent(const boost::system::error_code &_error);
std::mutex socket_mutex_;
tcp_server_endpoint_impl::socket_type socket_;
diff --git a/implementation/endpoints/include/udp_server_endpoint_impl.hpp b/implementation/endpoints/include/udp_server_endpoint_impl.hpp
index db936f3..4ceefb6 100644
--- a/implementation/endpoints/include/udp_server_endpoint_impl.hpp
+++ b/implementation/endpoints/include/udp_server_endpoint_impl.hpp
@@ -48,6 +48,7 @@ public:
std::chrono::nanoseconds *_maximum_retention) const;
VSOMEIP_EXPORT void join(const std::string &_address);
+ VSOMEIP_EXPORT void join_unlocked(const std::string &_address);
void leave(const std::string &_address);
void add_default_target(service_t _service,
diff --git a/implementation/endpoints/src/endpoint_manager_impl.cpp b/implementation/endpoints/src/endpoint_manager_impl.cpp
index dc02aa5..32ba31d 100644
--- a/implementation/endpoints/src/endpoint_manager_impl.cpp
+++ b/implementation/endpoints/src/endpoint_manager_impl.cpp
@@ -146,18 +146,60 @@ void endpoint_manager_impl::is_remote_service_known(
void endpoint_manager_impl::add_remote_service_info(
service_t _service, instance_t _instance,
const std::shared_ptr<endpoint_definition>& _ep_definition) {
- std::lock_guard<std::recursive_mutex> its_lock(endpoint_mutex_);
- remote_service_info_[_service][_instance][_ep_definition->is_reliable()] =
+
+ std::shared_ptr<serviceinfo> its_info;
+ std::shared_ptr<endpoint> its_endpoint;
+ bool must_report(false);
+ {
+ std::lock_guard<std::recursive_mutex> its_lock(endpoint_mutex_);
+ remote_service_info_[_service][_instance][_ep_definition->is_reliable()] =
_ep_definition;
+
+ if (_ep_definition->is_reliable()) {
+ its_endpoint = find_remote_client(_service, _instance, true);
+ must_report = (its_endpoint && its_endpoint->is_established_or_connected());
+ if (must_report)
+ its_info = rm_->find_service(_service, _instance);
+ }
+ }
+
+ if (must_report)
+ static_cast<routing_manager_impl*>(rm_)->service_endpoint_connected(
+ _service, _instance, its_info->get_major(), its_info->get_minor(),
+ its_endpoint, false);
}
void endpoint_manager_impl::add_remote_service_info(
service_t _service, instance_t _instance,
const std::shared_ptr<endpoint_definition>& _ep_definition_reliable,
const std::shared_ptr<endpoint_definition>& _ep_definition_unreliable) {
- std::lock_guard<std::recursive_mutex> its_lock(endpoint_mutex_);
- remote_service_info_[_service][_instance][true] = _ep_definition_reliable;
- remote_service_info_[_service][_instance][false] = _ep_definition_unreliable;
+
+ std::shared_ptr<serviceinfo> its_info;
+ std::shared_ptr<endpoint> its_reliable, its_unreliable;
+ bool must_report(false);
+ {
+ std::lock_guard<std::recursive_mutex> its_lock(endpoint_mutex_);
+ remote_service_info_[_service][_instance][false] = _ep_definition_unreliable;
+ remote_service_info_[_service][_instance][true] = _ep_definition_reliable;
+
+ its_unreliable = find_remote_client(_service, _instance, false);
+ its_reliable = find_remote_client(_service, _instance, true);
+
+ must_report = (its_unreliable && its_unreliable->is_established_or_connected()
+ && its_reliable && its_reliable->is_established_or_connected());
+
+ if (must_report)
+ its_info = rm_->find_service(_service, _instance);
+ }
+
+ if (must_report) {
+ static_cast<routing_manager_impl*>(rm_)->service_endpoint_connected(
+ _service, _instance, its_info->get_major(), its_info->get_minor(),
+ its_unreliable, false);
+ static_cast<routing_manager_impl*>(rm_)->service_endpoint_connected(
+ _service, _instance, its_info->get_major(), its_info->get_minor(),
+ its_reliable, false);
+ }
}
void endpoint_manager_impl::clear_remote_service_info(service_t _service,
@@ -230,7 +272,6 @@ std::shared_ptr<endpoint> endpoint_manager_impl::create_server_endpoint(
return (its_endpoint);
}
-
std::shared_ptr<endpoint> endpoint_manager_impl::find_server_endpoint(
uint16_t _port, bool _reliable) const {
std::shared_ptr<endpoint> its_endpoint;
@@ -247,15 +288,20 @@ std::shared_ptr<endpoint> endpoint_manager_impl::find_server_endpoint(
std::shared_ptr<endpoint> endpoint_manager_impl::find_or_create_server_endpoint(
uint16_t _port, bool _reliable, bool _start, service_t _service,
- instance_t _instance) {
+ instance_t _instance, bool &_is_found, bool _is_multicast) {
std::shared_ptr<endpoint> its_endpoint = find_server_endpoint(_port,
_reliable);
+ _is_found = false;
if (!its_endpoint) {
its_endpoint = create_server_endpoint(_port, _reliable, _start);
+ } else {
+ _is_found = true;
}
if (its_endpoint) {
std::lock_guard<std::recursive_mutex> its_lock(endpoint_mutex_);
- service_instances_[_service][its_endpoint.get()] = _instance;
+ if (!_is_multicast) {
+ service_instances_[_service][its_endpoint.get()] = _instance;
+ }
its_endpoint->increment_use_count();
}
return (its_endpoint);
@@ -369,6 +415,7 @@ void endpoint_manager_impl::clear_client_endpoints(service_t _service, instance_
void endpoint_manager_impl::find_or_create_multicast_endpoint(
service_t _service, instance_t _instance,
+ const boost::asio::ip::address &_sender,
const boost::asio::ip::address &_address, uint16_t _port) {
bool multicast_known(false);
{
@@ -386,25 +433,27 @@ void endpoint_manager_impl::find_or_create_multicast_endpoint(
}
}
}
- if (!multicast_known) {
- // Save multicast info to be able to delete the endpoint
- // as soon as the instance stops offering its service
- std::shared_ptr<endpoint_definition> endpoint_def =
- endpoint_definition::get(_address, _port, false, _service, _instance);
- multicast_info[_service][_instance] = endpoint_def;
- }
}
const bool is_someip = configuration_->is_someip(_service, _instance);
-
+ bool _is_found(false);
// Create multicast endpoint & join multicase group
std::shared_ptr<endpoint> its_endpoint = find_or_create_server_endpoint(
- _port, false, is_someip, _service, _instance);
+ _port, false, is_someip, _service, _instance, _is_found, true);
+ if (!_is_found) {
+ // Only save multicast info if we created a new endpoint
+ // to be able to delete the new endpoint
+ // as soon as the instance stops offering its service
+ std::shared_ptr<endpoint_definition> endpoint_def =
+ endpoint_definition::get(_address, _port, false, _service, _instance);
+ multicast_info[_service][_instance] = endpoint_def;
+ }
+
if (its_endpoint) {
if (!multicast_known) {
std::lock_guard<std::recursive_mutex> its_lock(endpoint_mutex_);
- service_instances_[_service][its_endpoint.get()] = _instance;
+ service_instances_multicast_[_service][_sender] = _instance;
}
- dynamic_cast<udp_server_endpoint_impl*>(its_endpoint.get())->join(
+ dynamic_cast<udp_server_endpoint_impl*>(its_endpoint.get())->join_unlocked(
_address.to_string());
} else {
VSOMEIP_ERROR <<"Could not find/create multicast endpoint!";
@@ -412,7 +461,6 @@ void endpoint_manager_impl::find_or_create_multicast_endpoint(
}
void endpoint_manager_impl::clear_multicast_endpoints(service_t _service, instance_t _instance) {
-
std::shared_ptr<endpoint> multicast_endpoint;
std::string address;
@@ -438,14 +486,14 @@ void endpoint_manager_impl::clear_multicast_endpoints(service_t _service, instan
if (0 >= multicast_info[_service].size()) {
multicast_info.erase(_service);
}
- // Clear service_instances_ for multicast endpoint
- (void)remove_instance(_service, multicast_endpoint.get());
+ (void)remove_instance_multicast(_service, _instance);
}
}
}
if (multicast_endpoint) {
dynamic_cast<udp_server_endpoint_impl*>(
multicast_endpoint.get())->leave(address);
+
multicast_endpoint->stop();
}
}
@@ -607,6 +655,20 @@ instance_t endpoint_manager_impl::find_instance(
return its_instance;
}
+instance_t endpoint_manager_impl::find_instance_multicast(
+ service_t _service, const boost::asio::ip::address &_sender) const {
+ instance_t its_instance(0xFFFF);
+ std::lock_guard<std::recursive_mutex> its_lock(endpoint_mutex_);
+ auto found_service = service_instances_multicast_.find(_service);
+ if (found_service != service_instances_multicast_.end()) {
+ auto found_sender = found_service->second.find(_sender);
+ if (found_sender != found_service->second.end()) {
+ its_instance = found_sender->second;
+ }
+ }
+ return its_instance;
+}
+
bool endpoint_manager_impl::remove_instance(service_t _service,
endpoint* const _endpoint) {
std::lock_guard<std::recursive_mutex> its_lock(endpoint_mutex_);
@@ -622,6 +684,25 @@ bool endpoint_manager_impl::remove_instance(service_t _service,
return (_endpoint->get_use_count() == 0);
}
+bool endpoint_manager_impl::remove_instance_multicast(service_t _service,
+ instance_t _instance) {
+ std::lock_guard<std::recursive_mutex> its_lock(endpoint_mutex_);
+ auto found_service = service_instances_multicast_.find(_service);
+ if (found_service != service_instances_multicast_.end()) {
+ for (auto &its_sender : found_service->second) {
+ if (its_sender.second == _instance) {
+ if (found_service->second.erase(its_sender.first)) {
+ if (!found_service->second.size()) {
+ service_instances_multicast_.erase(_service);
+ }
+ }
+ return (true);
+ }
+ }
+ }
+ return (false);
+}
+
void endpoint_manager_impl::on_connect(std::shared_ptr<endpoint> _endpoint) {
// Is called when endpoint->connect succeeded!
struct service_info {
diff --git a/implementation/endpoints/src/server_endpoint_impl.cpp b/implementation/endpoints/src/server_endpoint_impl.cpp
index 06b61f4..90aea96 100644
--- a/implementation/endpoints/src/server_endpoint_impl.cpp
+++ b/implementation/endpoints/src/server_endpoint_impl.cpp
@@ -34,7 +34,9 @@ server_endpoint_impl<Protocol>::server_endpoint_impl(
configuration::endpoint_queue_limit_t _queue_limit,
const std::shared_ptr<configuration>& _configuration)
: endpoint_impl<Protocol>(_endpoint_host, _routing_host, _local, _io, _max_message_size,
- _queue_limit, _configuration) {
+ _queue_limit, _configuration),
+ sent_timer_(_io) {
+ is_sending_ = false;
}
template<typename Protocol>
@@ -594,6 +596,14 @@ void server_endpoint_impl<Protocol>::send_cbk(
boost::system::error_code const &_error, std::size_t _bytes) {
(void)_bytes;
+ {
+ std::lock_guard<std::mutex> its_sent_lock(sent_mutex_);
+ is_sending_ = false;
+
+ boost::system::error_code ec;
+ sent_timer_.cancel(ec);
+ }
+
std::lock_guard<std::mutex> its_lock(mutex_);
auto check_if_all_msgs_for_stopped_service_are_sent = [&]() {
diff --git a/implementation/endpoints/src/tcp_client_endpoint_impl.cpp b/implementation/endpoints/src/tcp_client_endpoint_impl.cpp
index 2a86244..c490f53 100644
--- a/implementation/endpoints/src/tcp_client_endpoint_impl.cpp
+++ b/implementation/endpoints/src/tcp_client_endpoint_impl.cpp
@@ -915,7 +915,7 @@ void tcp_client_endpoint_impl::wait_until_sent(const boost::system::error_code &
its_sent_lock.unlock();
if (!_error)
VSOMEIP_WARNING << __func__
- << ": Maximum wait time for send operation exceeded.";
+ << ": Maximum wait time for send operation exceeded for tce.";
std::shared_ptr<endpoint_host> its_ep_host = endpoint_host_.lock();
its_ep_host->on_disconnect(shared_from_this());
diff --git a/implementation/endpoints/src/tcp_server_endpoint_impl.cpp b/implementation/endpoints/src/tcp_server_endpoint_impl.cpp
index b7b1d0a..1cd2b5b 100644
--- a/implementation/endpoints/src/tcp_server_endpoint_impl.cpp
+++ b/implementation/endpoints/src/tcp_server_endpoint_impl.cpp
@@ -408,6 +408,11 @@ void tcp_server_endpoint_impl::connection::send_queued(
{
std::lock_guard<std::mutex> its_lock(socket_mutex_);
+ {
+ std::lock_guard<std::mutex> its_sent_lock(its_server->sent_mutex_);
+ its_server->is_sending_ = true;
+ }
+
boost::asio::async_write(socket_, boost::asio::buffer(*its_buffer),
std::bind(&tcp_server_endpoint_impl::connection::write_completion_condition,
shared_from_this(),
@@ -652,19 +657,15 @@ void tcp_server_endpoint_impl::connection::receive_cbk(
<< " remote: " << get_address_port_remote()
<< ". Closing connection due to missing/broken data TCP stream.";
}
- {
- std::lock_guard<std::mutex> its_lock(its_server->connections_mutex_);
- stop();
- }
- its_server->remove_connection(this);
+ wait_until_sent(boost::asio::error::operation_aborted);
return;
} else if (max_message_size_ != MESSAGE_SIZE_UNLIMITED
&& current_message_size > max_message_size_) {
- std::lock_guard<std::mutex> its_lock(socket_mutex_);
recv_buffer_size_ = 0;
recv_buffer_.resize(recv_buffer_size_initial_, 0x0);
recv_buffer_.shrink_to_fit();
if (magic_cookies_enabled_) {
+ std::lock_guard<std::mutex> its_lock(socket_mutex_);
VSOMEIP_ERROR << "Received a TCP message which exceeds "
<< "maximum message size ("
<< std::dec << current_message_size
@@ -674,19 +675,18 @@ void tcp_server_endpoint_impl::connection::receive_cbk(
<< get_address_port_local() << " remote: "
<< get_address_port_remote();
} else {
- VSOMEIP_ERROR << "Received a TCP message which exceeds "
- << "maximum message size ("
- << std::dec << current_message_size
- << " > " << std::dec << max_message_size_
- << ") Magic cookies are disabled: "
- << "Connection will be closed! local: "
- << get_address_port_local() << " remote: "
- << get_address_port_remote();
{
- std::lock_guard<std::mutex> its_lock(its_server->connections_mutex_);
- stop();
+ std::lock_guard<std::mutex> its_lock(socket_mutex_);
+ VSOMEIP_ERROR << "Received a TCP message which exceeds "
+ << "maximum message size ("
+ << std::dec << current_message_size
+ << " > " << std::dec << max_message_size_
+ << ") Magic cookies are disabled: "
+ << "Connection will be closed! local: "
+ << get_address_port_local() << " remote: "
+ << get_address_port_remote();
}
- its_server->remove_connection(this);
+ wait_until_sent(boost::asio::error::operation_aborted);
return;
}
} else if (current_message_size > recv_buffer_size_) {
@@ -720,11 +720,7 @@ void tcp_server_endpoint_impl::connection::receive_cbk(
<< " remote: " << get_address_port_remote()
<< ". Closing connection due to missing/broken data TCP stream.";
}
- {
- std::lock_guard<std::mutex> its_lock(its_server->connections_mutex_);
- stop();
- }
- its_server->remove_connection(this);
+ wait_until_sent(boost::asio::error::operation_aborted);
return;
}
}
@@ -752,11 +748,7 @@ void tcp_server_endpoint_impl::connection::receive_cbk(
<< " local: " << get_address_port_local()
<< " remote: " << get_address_port_remote();
}
- {
- std::lock_guard<std::mutex> its_lock(its_server->connections_mutex_);
- stop();
- }
- its_server->remove_connection(this);
+ wait_until_sent(boost::asio::error::operation_aborted);
}
}
@@ -962,4 +954,27 @@ bool tcp_server_endpoint_impl::tp_segmentation_enabled(service_t _service,
return false;
}
+void tcp_server_endpoint_impl::connection::wait_until_sent(const boost::system::error_code &_error) {
+ std::shared_ptr<tcp_server_endpoint_impl> its_server(server_.lock());
+ std::unique_lock<std::mutex> its_sent_lock(its_server->sent_mutex_);
+ if (!its_server->is_sending_ || !_error) {
+ its_sent_lock.unlock();
+ if (!_error)
+ VSOMEIP_WARNING << __func__
+ << ": Maximum wait time for send operation exceeded for tse.";
+ {
+ std::lock_guard<std::mutex> its_lock(its_server->connections_mutex_);
+ stop();
+ }
+ its_server->remove_connection(this);
+ } else {
+ std::chrono::milliseconds its_timeout(VSOMEIP_MAX_TCP_SENT_WAIT_TIME);
+ boost::system::error_code ec;
+ its_server->sent_timer_.expires_from_now(its_timeout, ec);
+ its_server->sent_timer_.async_wait(std::bind(&tcp_server_endpoint_impl::connection::wait_until_sent,
+ std::dynamic_pointer_cast<tcp_server_endpoint_impl::connection>(shared_from_this()),
+ std::placeholders::_1));
+ }
+}
+
} // namespace vsomeip_v3
diff --git a/implementation/endpoints/src/tp_message.cpp b/implementation/endpoints/src/tp_message.cpp
index f786a4f..57696ca 100644
--- a/implementation/endpoints/src/tp_message.cpp
+++ b/implementation/endpoints/src/tp_message.cpp
@@ -301,6 +301,11 @@ bool tp_message::check_lengths(const byte_t* const _data,
_data[VSOMEIP_LENGTH_POS_MIN + 1],
_data[VSOMEIP_LENGTH_POS_MIN + 2],
_data[VSOMEIP_LENGTH_POS_MAX]);
+ const tp_header_t its_tp_header = VSOMEIP_BYTES_TO_LONG(
+ _data[VSOMEIP_TP_HEADER_POS_MIN],
+ _data[VSOMEIP_TP_HEADER_POS_MIN + 1],
+ _data[VSOMEIP_TP_HEADER_POS_MIN + 2],
+ _data[VSOMEIP_TP_HEADER_POS_MAX]);
bool ret(true);
if (!tp::tp_flag_is_set(_data[VSOMEIP_MESSAGE_TYPE_POS])) {
VSOMEIP_ERROR << __func__ << ": TP flag not set "
@@ -344,6 +349,14 @@ bool tp_message::check_lengths(const byte_t* const _data,
<< " current message size: " << std::dec << current_message_size_
<< " maximum message size: " << std::dec << max_message_size_;
ret = false;
+ } else if (tp::get_offset(its_tp_header) + _segment_size > max_message_size_ ) {
+ VSOMEIP_ERROR << __func__ << ": SomeIP/TP offset field exceeds maximum configured message size: "
+ << get_message_id(_data, _data_length)
+ << " TP offset [bytes]: " << std::dec << tp::get_offset(its_tp_header)
+ << " segment size: " << std::dec << _segment_size
+ << " current message size: " << std::dec << current_message_size_
+ << " maximum message size: " << std::dec << max_message_size_;
+ ret = false;
}
return ret;
}
diff --git a/implementation/endpoints/src/udp_client_endpoint_impl.cpp b/implementation/endpoints/src/udp_client_endpoint_impl.cpp
index 6bbd337..ff24173 100644
--- a/implementation/endpoints/src/udp_client_endpoint_impl.cpp
+++ b/implementation/endpoints/src/udp_client_endpoint_impl.cpp
@@ -93,8 +93,8 @@ void udp_client_endpoint_impl::connect() {
// If specified, bind to device
std::string its_device(configuration_->get_device());
if (its_device != "") {
- if (!setsockopt(socket_->native_handle(),
- SOL_SOCKET, SO_BINDTODEVICE, its_device.c_str(), (int)its_device.size())) {
+ if (setsockopt(socket_->native_handle(),
+ SOL_SOCKET, SO_BINDTODEVICE, its_device.c_str(), (int)its_device.size()) == -1) {
VSOMEIP_WARNING << "UDP Client: Could not bind to device \"" << its_device << "\"";
}
}
@@ -268,7 +268,7 @@ void udp_client_endpoint_impl::receive_cbk(
#if 0
std::stringstream msg;
msg << "ucei::rcb(" << _error.message() << "): ";
- for (std::size_t i = 0; i < _bytes + recv_buffer_size_; ++i)
+ for (std::size_t i = 0; i < _bytes; ++i)
msg << std::hex << std::setw(2) << std::setfill('0')
<< (int) (*_recv_buffer)[i] << " ";
VSOMEIP_INFO << msg.str();
diff --git a/implementation/endpoints/src/udp_server_endpoint_impl.cpp b/implementation/endpoints/src/udp_server_endpoint_impl.cpp
index ce1bb2d..add828c 100644
--- a/implementation/endpoints/src/udp_server_endpoint_impl.cpp
+++ b/implementation/endpoints/src/udp_server_endpoint_impl.cpp
@@ -291,6 +291,12 @@ bool udp_server_endpoint_impl::is_joined(
void udp_server_endpoint_impl::join(const std::string &_address) {
+ std::lock_guard<std::mutex> its_lock(multicast_mutex_);
+ join_unlocked(_address);
+}
+
+void udp_server_endpoint_impl::join_unlocked(const std::string &_address) {
+
bool has_received(false);
//
@@ -317,11 +323,11 @@ void udp_server_endpoint_impl::join(const std::string &_address) {
if (!multicast_local_) {
if (is_v4) {
multicast_local_ = std::unique_ptr<endpoint_type>(
- new endpoint_type(boost::asio::ip::address_v4::any(), local_port_));
+ new endpoint_type(boost::asio::ip::address_v4::any(), local_port_));
}
if (is_v6) {
multicast_local_ = std::unique_ptr<endpoint_type>(
- new endpoint_type(boost::asio::ip::address_v6::any(), local_port_));
+ new endpoint_type(boost::asio::ip::address_v6::any(), local_port_));
}
}
@@ -398,7 +404,6 @@ void udp_server_endpoint_impl::join(const std::string &_address) {
}
};
- std::lock_guard<std::mutex> its_lock(multicast_mutex_);
if (!is_joined(_address, &has_received)) {
join_func(_address);
} else if (!has_received) {
@@ -556,7 +561,8 @@ void udp_server_endpoint_impl::on_message_received(
} else if (current_message_size > VSOMEIP_RETURN_CODE_POS &&
(_buffer[i + VSOMEIP_PROTOCOL_VERSION_POS] != VSOMEIP_PROTOCOL_VERSION ||
!utility::is_valid_message_type(tp::tp::tp_flag_unset(_buffer[i + VSOMEIP_MESSAGE_TYPE_POS])) ||
- !utility::is_valid_return_code(static_cast<return_code_e>(_buffer[i + VSOMEIP_RETURN_CODE_POS]))
+ !utility::is_valid_return_code(static_cast<return_code_e>(_buffer[i + VSOMEIP_RETURN_CODE_POS])) ||
+ (tp::tp::tp_flag_is_set(_buffer[i + VSOMEIP_MESSAGE_TYPE_POS]) && get_local_port() == configuration_->get_sd_port())
)) {
if (_buffer[i + VSOMEIP_PROTOCOL_VERSION_POS] != VSOMEIP_PROTOCOL_VERSION) {
VSOMEIP_ERROR << "use: Wrong protocol version: 0x"
@@ -585,6 +591,11 @@ void udp_server_endpoint_impl::on_message_received(
<< std::uint32_t(_buffer[i + VSOMEIP_RETURN_CODE_POS])
<< " local: " << get_address_port_local()
<< " remote: " << its_remote_address << ":" << std::dec << its_remote_port;
+ } else if (tp::tp::tp_flag_is_set(_buffer[i + VSOMEIP_MESSAGE_TYPE_POS])
+ && get_local_port() == configuration_->get_sd_port()) {
+ VSOMEIP_WARNING << "use: Received a SomeIP/TP message on SD port:"
+ << " local: " << get_address_port_local()
+ << " remote: " << its_remote_address << ":" << std::dec << its_remote_port;
}
return;
}
@@ -614,6 +625,15 @@ void udp_server_endpoint_impl::on_message_received(
}
}
if (tp::tp::tp_flag_is_set(_buffer[i + VSOMEIP_MESSAGE_TYPE_POS])) {
+ const method_t its_method = VSOMEIP_BYTES_TO_WORD(_buffer[i + VSOMEIP_METHOD_POS_MIN],
+ _buffer[i + VSOMEIP_METHOD_POS_MAX]);
+ if (!tp_segmentation_enabled(its_service, its_method)) {
+ VSOMEIP_WARNING << "use: Received a SomeIP/TP message for service: 0x" << std::hex << its_service
+ << " method: 0x" << its_method << " which is not configured for TP:"
+ << " local: " << get_address_port_local()
+ << " remote: " << its_remote_address << ":" << std::dec << its_remote_port;
+ return;
+ }
const auto res = tp_reassembler_->process_tp_message(
&_buffer[i], current_message_size,
its_remote_address, its_remote_port);
diff --git a/implementation/helper/1.74/boost/asio/basic_datagram_socket_ext.hpp b/implementation/helper/1.74/boost/asio/basic_datagram_socket_ext.hpp
new file mode 100644
index 0000000..49a4950
--- /dev/null
+++ b/implementation/helper/1.74/boost/asio/basic_datagram_socket_ext.hpp
@@ -0,0 +1,1118 @@
+//
+// basic_datagram_socket_ext.hpp
+// ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+//
+// Copyright (c) 2003-2019 Christopher M. Kohlhoff (chris at kohlhoff dot com)
+// Copyright (C) 2016-2019 Bayerische Motoren Werke Aktiengesellschaft (BMW AG)
+//
+// Distributed under the Boost Software License, Version 1.0. (See accompanying
+// file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt)
+//
+
+#ifndef BOOST_ASIO_BASIC_DATAGRAM_SOCKET_EXT_HPP
+#define BOOST_ASIO_BASIC_DATAGRAM_SOCKET_EXT_HPP
+
+#if defined(_MSC_VER) && (_MSC_VER >= 1200)
+# pragma once
+#endif // defined(_MSC_VER) && (_MSC_VER >= 1200)
+
+#include <boost/asio/detail/config.hpp>
+#include <cstddef>
+#include <boost/asio/basic_socket_ext.hpp>
+#include <boost/asio/detail/handler_type_requirements_ext.hpp>
+#include <boost/asio/detail/non_const_lvalue.hpp>
+#include <boost/asio/detail/throw_error.hpp>
+#include <boost/asio/detail/type_traits.hpp>
+#include <boost/asio/error.hpp>
+
+#include <boost/asio/detail/push_options.hpp>
+
+namespace boost {
+namespace asio {
+
+#if !defined(BOOST_ASIO_BASIC_DATAGRAM_SOCKET_EXT_FWD_DECL)
+#define BOOST_ASIO_BASIC_DATAGRAM_SOCKET_EXT_FWD_DECL
+
+// Forward declaration with defaulted arguments.
+template <typename Protocol, typename Executor = executor>
+class basic_datagram_socket_ext;
+
+#endif // !defined(BOOST_ASIO_BASIC_DATAGRAM_SOCKET_EXT_FWD_DECL)
+
+/// Provides datagram-oriented socket functionality.
+/**
+ * The basic_datagram_socket class template provides asynchronous and blocking
+ * datagram-oriented socket functionality.
+ *
+ * @par Thread Safety
+ * @e Distinct @e objects: Safe.@n
+ * @e Shared @e objects: Unsafe.
+ */
+template <typename Protocol, typename Executor>
+class basic_datagram_socket_ext
+ : public basic_socket_ext<Protocol, Executor>
+{
+public:
+ /// The type of the executor associated with the object.
+ typedef Executor executor_type;
+
+ /// Rebinds the socket type to another executor.
+ template <typename Executor1>
+ struct rebind_executor
+ {
+ /// The socket type when rebound to the specified executor.
+ typedef basic_datagram_socket_ext<Protocol, Executor1> other;
+ };
+
+ /// The native representation of a socket.
+#if defined(GENERATING_DOCUMENTATION)
+ typedef implementation_defined native_handle_type;
+#else
+ typedef typename basic_socket_ext<Protocol,
+ Executor>::native_handle_type native_handle_type;
+#endif
+
+ /// The protocol type.
+ typedef Protocol protocol_type;
+
+ /// The endpoint type.
+ typedef typename Protocol::endpoint endpoint_type;
+
+ /// Construct a basic_datagram_socket without opening it.
+ /**
+ * This constructor creates a datagram socket without opening it. The open()
+ * function must be called before data can be sent or received on the socket.
+ *
+ * @param ex The I/O executor that the socket will use, by default, to
+ * dispatch handlers for any asynchronous operations performed on the socket.
+ */
+ explicit basic_datagram_socket_ext(const executor_type& ex)
+ : basic_socket_ext<Protocol, Executor>(ex)
+ {
+ }
+
+ /// Construct a basic_datagram_socket without opening it.
+ /**
+ * This constructor creates a datagram socket without opening it. The open()
+ * function must be called before data can be sent or received on the socket.
+ *
+ * @param context An execution context which provides the I/O executor that
+ * the socket will use, by default, to dispatch handlers for any asynchronous
+ * operations performed on the socket.
+ */
+ template <typename ExecutionContext>
+ explicit basic_datagram_socket_ext(ExecutionContext& context,
+ typename enable_if<
+ is_convertible<ExecutionContext&, execution_context&>::value
+ >::type* = 0)
+ : basic_socket_ext<Protocol, Executor>(context)
+ {
+ }
+
+ /// Construct and open a basic_datagram_socket.
+ /**
+ * This constructor creates and opens a datagram socket.
+ *
+ * @param ex The I/O executor that the socket will use, by default, to
+ * dispatch handlers for any asynchronous operations performed on the socket.
+ *
+ * @param protocol An object specifying protocol parameters to be used.
+ *
+ * @throws boost::system::system_error Thrown on failure.
+ */
+ basic_datagram_socket_ext(const executor_type& ex, const protocol_type& protocol)
+ : basic_socket_ext<Protocol, Executor>(ex, protocol)
+ {
+ }
+
+ /// Construct and open a basic_datagram_socket.
+ /**
+ * This constructor creates and opens a datagram socket.
+ *
+ * @param context An execution context which provides the I/O executor that
+ * the socket will use, by default, to dispatch handlers for any asynchronous
+ * operations performed on the socket.
+ *
+ * @param protocol An object specifying protocol parameters to be used.
+ *
+ * @throws boost::system::system_error Thrown on failure.
+ */
+ template <typename ExecutionContext>
+ basic_datagram_socket_ext(ExecutionContext& context,
+ const protocol_type& protocol,
+ typename enable_if<
+ is_convertible<ExecutionContext&, execution_context&>::value
+ >::type* = 0)
+ : basic_socket_ext<Protocol, Executor>(context, protocol)
+ {
+ }
+
+ /// Construct a basic_datagram_socket, opening it and binding it to the given
+ /// local endpoint.
+ /**
+ * This constructor creates a datagram socket and automatically opens it bound
+ * to the specified endpoint on the local machine. The protocol used is the
+ * protocol associated with the given endpoint.
+ *
+ * @param ex The I/O executor that the socket will use, by default, to
+ * dispatch handlers for any asynchronous operations performed on the socket.
+ *
+ * @param endpoint An endpoint on the local machine to which the datagram
+ * socket will be bound.
+ *
+ * @throws boost::system::system_error Thrown on failure.
+ */
+ basic_datagram_socket_ext(const executor_type& ex, const endpoint_type& endpoint)
+ : basic_socket_ext<Protocol, Executor>(ex, endpoint)
+ {
+ }
+
+ /// Construct a basic_datagram_socket, opening it and binding it to the given
+ /// local endpoint.
+ /**
+ * This constructor creates a datagram socket and automatically opens it bound
+ * to the specified endpoint on the local machine. The protocol used is the
+ * protocol associated with the given endpoint.
+ *
+ * @param context An execution context which provides the I/O executor that
+ * the socket will use, by default, to dispatch handlers for any asynchronous
+ * operations performed on the socket.
+ *
+ * @param endpoint An endpoint on the local machine to which the datagram
+ * socket will be bound.
+ *
+ * @throws boost::system::system_error Thrown on failure.
+ */
+ template <typename ExecutionContext>
+ basic_datagram_socket_ext(ExecutionContext& context,
+ const endpoint_type& endpoint,
+ typename enable_if<
+ is_convertible<ExecutionContext&, execution_context&>::value
+ >::type* = 0)
+ : basic_socket_ext<Protocol, Executor>(context, endpoint)
+ {
+ }
+
+ /// Construct a basic_datagram_socket on an existing native socket.
+ /**
+ * This constructor creates a datagram socket object to hold an existing
+ * native socket.
+ *
+ * @param ex The I/O executor that the socket will use, by default, to
+ * dispatch handlers for any asynchronous operations performed on the socket.
+ *
+ * @param protocol An object specifying protocol parameters to be used.
+ *
+ * @param native_socket The new underlying socket implementation.
+ *
+ * @throws boost::system::system_error Thrown on failure.
+ */
+ basic_datagram_socket_ext(const executor_type& ex,
+ const protocol_type& protocol, const native_handle_type& native_socket)
+ : basic_socket_ext<Protocol, Executor>(ex, protocol, native_socket)
+ {
+ }
+
+ /// Construct a basic_datagram_socket on an existing native socket.
+ /**
+ * This constructor creates a datagram socket object to hold an existing
+ * native socket.
+ *
+ * @param context An execution context which provides the I/O executor that
+ * the socket will use, by default, to dispatch handlers for any asynchronous
+ * operations performed on the socket.
+ *
+ * @param protocol An object specifying protocol parameters to be used.
+ *
+ * @param native_socket The new underlying socket implementation.
+ *
+ * @throws boost::system::system_error Thrown on failure.
+ */
+ template <typename ExecutionContext>
+ basic_datagram_socket_ext(ExecutionContext& context,
+ const protocol_type& protocol, const native_handle_type& native_socket,
+ typename enable_if<
+ is_convertible<ExecutionContext&, execution_context&>::value
+ >::type* = 0)
+ : basic_socket_ext<Protocol, Executor>(context, protocol, native_socket)
+ {
+ }
+
+#if defined(BOOST_ASIO_HAS_MOVE) || defined(GENERATING_DOCUMENTATION)
+ /// Move-construct a basic_datagram_socket from another.
+ /**
+ * This constructor moves a datagram socket from one object to another.
+ *
+ * @param other The other basic_datagram_socket object from which the move
+ * will occur.
+ *
+ * @note Following the move, the moved-from object is in the same state as if
+ * constructed using the @c basic_datagram_socket(const executor_type&)
+ * constructor.
+ */
+ basic_datagram_socket_ext(basic_datagram_socket_ext&& other)
+ : basic_socket_ext<Protocol, Executor>(std::move(other))
+ {
+ }
+
+ /// Move-assign a basic_datagram_socket from another.
+ /**
+ * This assignment operator moves a datagram socket from one object to
+ * another.
+ *
+ * @param other The other basic_datagram_socket object from which the move
+ * will occur.
+ *
+ * @note Following the move, the moved-from object is in the same state as if
+ * constructed using the @c basic_datagram_socket(const executor_type&)
+ * constructor.
+ */
+ basic_datagram_socket_ext& operator=(basic_datagram_socket_ext&& other)
+ {
+ basic_socket_ext<Protocol, Executor>::operator=(std::move(other));
+ return *this;
+ }
+
+ /// Move-construct a basic_datagram_socket from a socket of another protocol
+ /// type.
+ /**
+ * This constructor moves a datagram socket from one object to another.
+ *
+ * @param other The other basic_datagram_socket object from which the move
+ * will occur.
+ *
+ * @note Following the move, the moved-from object is in the same state as if
+ * constructed using the @c basic_datagram_socket(const executor_type&)
+ * constructor.
+ */
+ template <typename Protocol1, typename Executor1>
+ basic_datagram_socket_ext(basic_datagram_socket_ext<Protocol1, Executor1>&& other,
+ typename enable_if<
+ is_convertible<Protocol1, Protocol>::value
+ && is_convertible<Executor1, Executor>::value
+ >::type* = 0)
+ : basic_socket_ext<Protocol, Executor>(std::move(other))
+ {
+ }
+
+ /// Move-assign a basic_datagram_socket from a socket of another protocol
+ /// type.
+ /**
+ * This assignment operator moves a datagram socket from one object to
+ * another.
+ *
+ * @param other The other basic_datagram_socket object from which the move
+ * will occur.
+ *
+ * @note Following the move, the moved-from object is in the same state as if
+ * constructed using the @c basic_datagram_socket(const executor_type&)
+ * constructor.
+ */
+ template <typename Protocol1, typename Executor1>
+ typename enable_if<
+ is_convertible<Protocol1, Protocol>::value
+ && is_convertible<Executor1, Executor>::value,
+ basic_datagram_socket_ext&
+ >::type operator=(basic_datagram_socket_ext<Protocol1, Executor1>&& other)
+ {
+ basic_socket_ext<Protocol, Executor>::operator=(std::move(other));
+ return *this;
+ }
+#endif // defined(BOOST_ASIO_HAS_MOVE) || defined(GENERATING_DOCUMENTATION)
+
+ /// Destroys the socket.
+ /**
+ * This function destroys the socket, cancelling any outstanding asynchronous
+ * operations associated with the socket as if by calling @c cancel.
+ */
+ ~basic_datagram_socket_ext()
+ {
+ }
+
+ /// Send some data on a connected socket.
+ /**
+ * This function is used to send data on the datagram socket. The function
+ * call will block until the data has been sent successfully or an error
+ * occurs.
+ *
+ * @param buffers One ore more data buffers to be sent on the socket.
+ *
+ * @returns The number of bytes sent.
+ *
+ * @throws boost::system::system_error Thrown on failure.
+ *
+ * @note The send operation can only be used with a connected socket. Use
+ * the send_to function to send data on an unconnected datagram socket.
+ *
+ * @par Example
+ * To send a single data buffer use the @ref buffer function as follows:
+ * @code socket.send(boost::asio::buffer(data, size)); @endcode
+ * See the @ref buffer documentation for information on sending multiple
+ * buffers in one go, and how to use it with arrays, boost::array or
+ * std::vector.
+ */
+ template <typename ConstBufferSequence>
+ std::size_t send(const ConstBufferSequence& buffers)
+ {
+ boost::system::error_code ec;
+ std::size_t s = this->impl_.get_service().send(
+ this->impl_.get_implementation(), buffers, 0, ec);
+ boost::asio::detail::throw_error(ec, "send");
+ return s;
+ }
+
+ /// Send some data on a connected socket.
+ /**
+ * This function is used to send data on the datagram socket. The function
+ * call will block until the data has been sent successfully or an error
+ * occurs.
+ *
+ * @param buffers One ore more data buffers to be sent on the socket.
+ *
+ * @param flags Flags specifying how the send call is to be made.
+ *
+ * @returns The number of bytes sent.
+ *
+ * @throws boost::system::system_error Thrown on failure.
+ *
+ * @note The send operation can only be used with a connected socket. Use
+ * the send_to function to send data on an unconnected datagram socket.
+ */
+ template <typename ConstBufferSequence>
+ std::size_t send(const ConstBufferSequence& buffers,
+ socket_base::message_flags flags)
+ {
+ boost::system::error_code ec;
+ std::size_t s = this->impl_.get_service().send(
+ this->impl_.get_implementation(), buffers, flags, ec);
+ boost::asio::detail::throw_error(ec, "send");
+ return s;
+ }
+
+ /// Send some data on a connected socket.
+ /**
+ * This function is used to send data on the datagram socket. The function
+ * call will block until the data has been sent successfully or an error
+ * occurs.
+ *
+ * @param buffers One or more data buffers to be sent on the socket.
+ *
+ * @param flags Flags specifying how the send call is to be made.
+ *
+ * @param ec Set to indicate what error occurred, if any.
+ *
+ * @returns The number of bytes sent.
+ *
+ * @note The send operation can only be used with a connected socket. Use
+ * the send_to function to send data on an unconnected datagram socket.
+ */
+ template <typename ConstBufferSequence>
+ std::size_t send(const ConstBufferSequence& buffers,
+ socket_base::message_flags flags, boost::system::error_code& ec)
+ {
+ return this->impl_.get_service().send(
+ this->impl_.get_implementation(), buffers, flags, ec);
+ }
+
+ /// Start an asynchronous send on a connected socket.
+ /**
+ * This function is used to asynchronously send data on the datagram socket.
+ * The function call always returns immediately.
+ *
+ * @param buffers One or more data buffers to be sent on the socket. Although
+ * the buffers object may be copied as necessary, ownership of the underlying
+ * memory blocks is retained by the caller, which must guarantee that they
+ * remain valid until the handler is called.
+ *
+ * @param handler The handler to be called when the send operation completes.
+ * Copies will be made of the handler as required. The function signature of
+ * the handler must be:
+ * @code void handler(
+ * const boost::system::error_code& error, // Result of operation.
+ * std::size_t bytes_transferred // Number of bytes sent.
+ * ); @endcode
+ * Regardless of whether the asynchronous operation completes immediately or
+ * not, the handler will not be invoked from within this function. On
+ * immediate completion, invocation of the handler will be performed in a
+ * manner equivalent to using boost::asio::post().
+ *
+ * @note The async_send operation can only be used with a connected socket.
+ * Use the async_send_to function to send data on an unconnected datagram
+ * socket.
+ *
+ * @par Example
+ * To send a single data buffer use the @ref buffer function as follows:
+ * @code
+ * socket.async_send(boost::asio::buffer(data, size), handler);
+ * @endcode
+ * See the @ref buffer documentation for information on sending multiple
+ * buffers in one go, and how to use it with arrays, boost::array or
+ * std::vector.
+ */
+ template <typename ConstBufferSequence, typename WriteHandler>
+ BOOST_ASIO_INITFN_RESULT_TYPE(WriteHandler,
+ void (boost::system::error_code, std::size_t))
+ async_send(const ConstBufferSequence& buffers,
+ BOOST_ASIO_MOVE_ARG(WriteHandler) handler)
+ {
+ return async_initiate<WriteHandler,
+ void (boost::system::error_code, std::size_t)>(
+ initiate_async_send(), handler, this,
+ buffers, socket_base::message_flags(0));
+ }
+
+ /// Start an asynchronous send on a connected socket.
+ /**
+ * This function is used to asynchronously send data on the datagram socket.
+ * The function call always returns immediately.
+ *
+ * @param buffers One or more data buffers to be sent on the socket. Although
+ * the buffers object may be copied as necessary, ownership of the underlying
+ * memory blocks is retained by the caller, which must guarantee that they
+ * remain valid until the handler is called.
+ *
+ * @param flags Flags specifying how the send call is to be made.
+ *
+ * @param handler The handler to be called when the send operation completes.
+ * Copies will be made of the handler as required. The function signature of
+ * the handler must be:
+ * @code void handler(
+ * const boost::system::error_code& error, // Result of operation.
+ * std::size_t bytes_transferred // Number of bytes sent.
+ * ); @endcode
+ * Regardless of whether the asynchronous operation completes immediately or
+ * not, the handler will not be invoked from within this function. On
+ * immediate completion, invocation of the handler will be performed in a
+ * manner equivalent to using boost::asio::post().
+ *
+ * @note The async_send operation can only be used with a connected socket.
+ * Use the async_send_to function to send data on an unconnected datagram
+ * socket.
+ */
+ template <typename ConstBufferSequence, typename WriteHandler>
+ BOOST_ASIO_INITFN_RESULT_TYPE(WriteHandler,
+ void (boost::system::error_code, std::size_t))
+ async_send(const ConstBufferSequence& buffers,
+ socket_base::message_flags flags,
+ BOOST_ASIO_MOVE_ARG(WriteHandler) handler)
+ {
+ return async_initiate<WriteHandler,
+ void (boost::system::error_code, std::size_t)>(
+ initiate_async_send(), handler, this, buffers, flags);
+ }
+
+ /// Send a datagram to the specified endpoint.
+ /**
+ * This function is used to send a datagram to the specified remote endpoint.
+ * The function call will block until the data has been sent successfully or
+ * an error occurs.
+ *
+ * @param buffers One or more data buffers to be sent to the remote endpoint.
+ *
+ * @param destination The remote endpoint to which the data will be sent.
+ *
+ * @returns The number of bytes sent.
+ *
+ * @throws boost::system::system_error Thrown on failure.
+ *
+ * @par Example
+ * To send a single data buffer use the @ref buffer function as follows:
+ * @code
+ * boost::asio::ip::udp::endpoint destination(
+ * boost::asio::ip::address::from_string("1.2.3.4"), 12345);
+ * socket.send_to(boost::asio::buffer(data, size), destination);
+ * @endcode
+ * See the @ref buffer documentation for information on sending multiple
+ * buffers in one go, and how to use it with arrays, boost::array or
+ * std::vector.
+ */
+ template <typename ConstBufferSequence>
+ std::size_t send_to(const ConstBufferSequence& buffers,
+ const endpoint_type& destination)
+ {
+ boost::system::error_code ec;
+ std::size_t s = this->impl_.get_service().send_to(
+ this->impl_.get_implementation(), buffers, destination, 0, ec);
+ boost::asio::detail::throw_error(ec, "send_to");
+ return s;
+ }
+
+ /// Send a datagram to the specified endpoint.
+ /**
+ * This function is used to send a datagram to the specified remote endpoint.
+ * The function call will block until the data has been sent successfully or
+ * an error occurs.
+ *
+ * @param buffers One or more data buffers to be sent to the remote endpoint.
+ *
+ * @param destination The remote endpoint to which the data will be sent.
+ *
+ * @param flags Flags specifying how the send call is to be made.
+ *
+ * @returns The number of bytes sent.
+ *
+ * @throws boost::system::system_error Thrown on failure.
+ */
+ template <typename ConstBufferSequence>
+ std::size_t send_to(const ConstBufferSequence& buffers,
+ const endpoint_type& destination, socket_base::message_flags flags)
+ {
+ boost::system::error_code ec;
+ std::size_t s = this->impl_.get_service().send_to(
+ this->impl_.get_implementation(), buffers, destination, flags, ec);
+ boost::asio::detail::throw_error(ec, "send_to");
+ return s;
+ }
+
+ /// Send a datagram to the specified endpoint.
+ /**
+ * This function is used to send a datagram to the specified remote endpoint.
+ * The function call will block until the data has been sent successfully or
+ * an error occurs.
+ *
+ * @param buffers One or more data buffers to be sent to the remote endpoint.
+ *
+ * @param destination The remote endpoint to which the data will be sent.
+ *
+ * @param flags Flags specifying how the send call is to be made.
+ *
+ * @param ec Set to indicate what error occurred, if any.
+ *
+ * @returns The number of bytes sent.
+ */
+ template <typename ConstBufferSequence>
+ std::size_t send_to(const ConstBufferSequence& buffers,
+ const endpoint_type& destination, socket_base::message_flags flags,
+ boost::system::error_code& ec)
+ {
+ return this->impl_.get_service().send_to(this->impl_.get_implementation(),
+ buffers, destination, flags, ec);
+ }
+
+ /// Start an asynchronous send.
+ /**
+ * This function is used to asynchronously send a datagram to the specified
+ * remote endpoint. The function call always returns immediately.
+ *
+ * @param buffers One or more data buffers to be sent to the remote endpoint.
+ * Although the buffers object may be copied as necessary, ownership of the
+ * underlying memory blocks is retained by the caller, which must guarantee
+ * that they remain valid until the handler is called.
+ *
+ * @param destination The remote endpoint to which the data will be sent.
+ * Copies will be made of the endpoint as required.
+ *
+ * @param handler The handler to be called when the send operation completes.
+ * Copies will be made of the handler as required. The function signature of
+ * the handler must be:
+ * @code void handler(
+ * const boost::system::error_code& error, // Result of operation.
+ * std::size_t bytes_transferred // Number of bytes sent.
+ * ); @endcode
+ * Regardless of whether the asynchronous operation completes immediately or
+ * not, the handler will not be invoked from within this function. On
+ * immediate completion, invocation of the handler will be performed in a
+ * manner equivalent to using boost::asio::post().
+ *
+ * @par Example
+ * To send a single data buffer use the @ref buffer function as follows:
+ * @code
+ * boost::asio::ip::udp::endpoint destination(
+ * boost::asio::ip::address::from_string("1.2.3.4"), 12345);
+ * socket.async_send_to(
+ * boost::asio::buffer(data, size), destination, handler);
+ * @endcode
+ * See the @ref buffer documentation for information on sending multiple
+ * buffers in one go, and how to use it with arrays, boost::array or
+ * std::vector.
+ */
+ template <typename ConstBufferSequence, typename WriteHandler>
+ BOOST_ASIO_INITFN_RESULT_TYPE(WriteHandler,
+ void (boost::system::error_code, std::size_t))
+ async_send_to(const ConstBufferSequence& buffers,
+ const endpoint_type& destination,
+ BOOST_ASIO_MOVE_ARG(WriteHandler) handler)
+ {
+ return async_initiate<WriteHandler,
+ void (boost::system::error_code, std::size_t)>(
+ initiate_async_send_to(), handler, this, buffers,
+ destination, socket_base::message_flags(0));
+ }
+
+ /// Start an asynchronous send.
+ /**
+ * This function is used to asynchronously send a datagram to the specified
+ * remote endpoint. The function call always returns immediately.
+ *
+ * @param buffers One or more data buffers to be sent to the remote endpoint.
+ * Although the buffers object may be copied as necessary, ownership of the
+ * underlying memory blocks is retained by the caller, which must guarantee
+ * that they remain valid until the handler is called.
+ *
+ * @param flags Flags specifying how the send call is to be made.
+ *
+ * @param destination The remote endpoint to which the data will be sent.
+ * Copies will be made of the endpoint as required.
+ *
+ * @param handler The handler to be called when the send operation completes.
+ * Copies will be made of the handler as required. The function signature of
+ * the handler must be:
+ * @code void handler(
+ * const boost::system::error_code& error, // Result of operation.
+ * std::size_t bytes_transferred // Number of bytes sent.
+ * ); @endcode
+ * Regardless of whether the asynchronous operation completes immediately or
+ * not, the handler will not be invoked from within this function. On
+ * immediate completion, invocation of the handler will be performed in a
+ * manner equivalent to using boost::asio::post().
+ */
+ template <typename ConstBufferSequence, typename WriteHandler>
+ BOOST_ASIO_INITFN_RESULT_TYPE(WriteHandler,
+ void (boost::system::error_code, std::size_t))
+ async_send_to(const ConstBufferSequence& buffers,
+ const endpoint_type& destination, socket_base::message_flags flags,
+ BOOST_ASIO_MOVE_ARG(WriteHandler) handler)
+ {
+ return async_initiate<WriteHandler,
+ void (boost::system::error_code, std::size_t)>(
+ initiate_async_send_to(), handler, this, buffers, destination, flags);
+ }
+
+ /// Receive some data on a connected socket.
+ /**
+ * This function is used to receive data on the datagram socket. The function
+ * call will block until data has been received successfully or an error
+ * occurs.
+ *
+ * @param buffers One or more buffers into which the data will be received.
+ *
+ * @returns The number of bytes received.
+ *
+ * @throws boost::system::system_error Thrown on failure.
+ *
+ * @note The receive operation can only be used with a connected socket. Use
+ * the receive_from function to receive data on an unconnected datagram
+ * socket.
+ *
+ * @par Example
+ * To receive into a single data buffer use the @ref buffer function as
+ * follows:
+ * @code socket.receive(boost::asio::buffer(data, size)); @endcode
+ * See the @ref buffer documentation for information on receiving into
+ * multiple buffers in one go, and how to use it with arrays, boost::array or
+ * std::vector.
+ */
+ template <typename MutableBufferSequence>
+ std::size_t receive(const MutableBufferSequence& buffers)
+ {
+ boost::system::error_code ec;
+ std::size_t s = this->impl_.get_service().receive(
+ this->impl_.get_implementation(), buffers, 0, ec);
+ boost::asio::detail::throw_error(ec, "receive");
+ return s;
+ }
+
+ /// Receive some data on a connected socket.
+ /**
+ * This function is used to receive data on the datagram socket. The function
+ * call will block until data has been received successfully or an error
+ * occurs.
+ *
+ * @param buffers One or more buffers into which the data will be received.
+ *
+ * @param flags Flags specifying how the receive call is to be made.
+ *
+ * @returns The number of bytes received.
+ *
+ * @throws boost::system::system_error Thrown on failure.
+ *
+ * @note The receive operation can only be used with a connected socket. Use
+ * the receive_from function to receive data on an unconnected datagram
+ * socket.
+ */
+ template <typename MutableBufferSequence>
+ std::size_t receive(const MutableBufferSequence& buffers,
+ socket_base::message_flags flags)
+ {
+ boost::system::error_code ec;
+ std::size_t s = this->impl_.get_service().receive(
+ this->impl_.get_implementation(), buffers, flags, ec);
+ boost::asio::detail::throw_error(ec, "receive");
+ return s;
+ }
+
+ /// Receive some data on a connected socket.
+ /**
+ * This function is used to receive data on the datagram socket. The function
+ * call will block until data has been received successfully or an error
+ * occurs.
+ *
+ * @param buffers One or more buffers into which the data will be received.
+ *
+ * @param flags Flags specifying how the receive call is to be made.
+ *
+ * @param ec Set to indicate what error occurred, if any.
+ *
+ * @returns The number of bytes received.
+ *
+ * @note The receive operation can only be used with a connected socket. Use
+ * the receive_from function to receive data on an unconnected datagram
+ * socket.
+ */
+ template <typename MutableBufferSequence>
+ std::size_t receive(const MutableBufferSequence& buffers,
+ socket_base::message_flags flags, boost::system::error_code& ec)
+ {
+ return this->impl_.get_service().receive(
+ this->impl_.get_implementation(), buffers, flags, ec);
+ }
+
+ /// Start an asynchronous receive on a connected socket.
+ /**
+ * This function is used to asynchronously receive data from the datagram
+ * socket. The function call always returns immediately.
+ *
+ * @param buffers One or more buffers into which the data will be received.
+ * Although the buffers object may be copied as necessary, ownership of the
+ * underlying memory blocks is retained by the caller, which must guarantee
+ * that they remain valid until the handler is called.
+ *
+ * @param handler The handler to be called when the receive operation
+ * completes. Copies will be made of the handler as required. The function
+ * signature of the handler must be:
+ * @code void handler(
+ * const boost::system::error_code& error, // Result of operation.
+ * std::size_t bytes_transferred // Number of bytes received.
+ * ); @endcode
+ * Regardless of whether the asynchronous operation completes immediately or
+ * not, the handler will not be invoked from within this function. On
+ * immediate completion, invocation of the handler will be performed in a
+ * manner equivalent to using boost::asio::post().
+ *
+ * @note The async_receive operation can only be used with a connected socket.
+ * Use the async_receive_from function to receive data on an unconnected
+ * datagram socket.
+ *
+ * @par Example
+ * To receive into a single data buffer use the @ref buffer function as
+ * follows:
+ * @code
+ * socket.async_receive(boost::asio::buffer(data, size), handler);
+ * @endcode
+ * See the @ref buffer documentation for information on receiving into
+ * multiple buffers in one go, and how to use it with arrays, boost::array or
+ * std::vector.
+ */
+ template <typename MutableBufferSequence, typename ReadHandler>
+ BOOST_ASIO_INITFN_RESULT_TYPE(ReadHandler,
+ void (boost::system::error_code, std::size_t, boost::asio::ip::address))
+ async_receive(const MutableBufferSequence& buffers,
+ BOOST_ASIO_MOVE_ARG(ReadHandler) handler)
+ {
+ return async_initiate<ReadHandler,
+ void (boost::system::error_code, std::size_t, boost::asio::ip::address)>(
+ initiate_async_receive(), handler, this,
+ buffers, socket_base::message_flags(0));
+ }
+
+ /// Start an asynchronous receive on a connected socket.
+ /**
+ * This function is used to asynchronously receive data from the datagram
+ * socket. The function call always returns immediately.
+ *
+ * @param buffers One or more buffers into which the data will be received.
+ * Although the buffers object may be copied as necessary, ownership of the
+ * underlying memory blocks is retained by the caller, which must guarantee
+ * that they remain valid until the handler is called.
+ *
+ * @param flags Flags specifying how the receive call is to be made.
+ *
+ * @param handler The handler to be called when the receive operation
+ * completes. Copies will be made of the handler as required. The function
+ * signature of the handler must be:
+ * @code void handler(
+ * const boost::system::error_code& error, // Result of operation.
+ * std::size_t bytes_transferred // Number of bytes received.
+ * ); @endcode
+ * Regardless of whether the asynchronous operation completes immediately or
+ * not, the handler will not be invoked from within this function. On
+ * immediate completion, invocation of the handler will be performed in a
+ * manner equivalent to using boost::asio::post().
+ *
+ * @note The async_receive operation can only be used with a connected socket.
+ * Use the async_receive_from function to receive data on an unconnected
+ * datagram socket.
+ */
+ template <typename MutableBufferSequence, typename ReadHandler>
+ BOOST_ASIO_INITFN_RESULT_TYPE(ReadHandler,
+ void (boost::system::error_code, std::size_t, boost::asio::ip::address))
+ async_receive(const MutableBufferSequence& buffers,
+ socket_base::message_flags flags,
+ BOOST_ASIO_MOVE_ARG(ReadHandler) handler)
+ {
+ return async_initiate<ReadHandler,
+ void (boost::system::error_code, std::size_t, boost::asio::ip::address)>(
+ initiate_async_receive(), handler, this, buffers, flags);
+ }
+
+ /// Receive a datagram with the endpoint of the sender.
+ /**
+ * This function is used to receive a datagram. The function call will block
+ * until data has been received successfully or an error occurs.
+ *
+ * @param buffers One or more buffers into which the data will be received.
+ *
+ * @param sender_endpoint An endpoint object that receives the endpoint of
+ * the remote sender of the datagram.
+ *
+ * @returns The number of bytes received.
+ *
+ * @throws boost::system::system_error Thrown on failure.
+ *
+ * @par Example
+ * To receive into a single data buffer use the @ref buffer function as
+ * follows:
+ * @code
+ * boost::asio::ip::udp::endpoint sender_endpoint;
+ * socket.receive_from(
+ * boost::asio::buffer(data, size), sender_endpoint);
+ * @endcode
+ * See the @ref buffer documentation for information on receiving into
+ * multiple buffers in one go, and how to use it with arrays, boost::array or
+ * std::vector.
+ */
+ template <typename MutableBufferSequence>
+ std::size_t receive_from(const MutableBufferSequence& buffers,
+ endpoint_type& sender_endpoint)
+ {
+ boost::system::error_code ec;
+ std::size_t s = this->impl_.get_service().receive_from(
+ this->impl_.get_implementation(), buffers, sender_endpoint, 0, ec);
+ boost::asio::detail::throw_error(ec, "receive_from");
+ return s;
+ }
+
+ /// Receive a datagram with the endpoint of the sender.
+ /**
+ * This function is used to receive a datagram. The function call will block
+ * until data has been received successfully or an error occurs.
+ *
+ * @param buffers One or more buffers into which the data will be received.
+ *
+ * @param sender_endpoint An endpoint object that receives the endpoint of
+ * the remote sender of the datagram.
+ *
+ * @param flags Flags specifying how the receive call is to be made.
+ *
+ * @returns The number of bytes received.
+ *
+ * @throws boost::system::system_error Thrown on failure.
+ */
+ template <typename MutableBufferSequence>
+ std::size_t receive_from(const MutableBufferSequence& buffers,
+ endpoint_type& sender_endpoint, socket_base::message_flags flags)
+ {
+ boost::system::error_code ec;
+ std::size_t s = this->impl_.get_service().receive_from(
+ this->impl_.get_implementation(), buffers, sender_endpoint, flags, ec);
+ boost::asio::detail::throw_error(ec, "receive_from");
+ return s;
+ }
+
+ /// Receive a datagram with the endpoint of the sender.
+ /**
+ * This function is used to receive a datagram. The function call will block
+ * until data has been received successfully or an error occurs.
+ *
+ * @param buffers One or more buffers into which the data will be received.
+ *
+ * @param sender_endpoint An endpoint object that receives the endpoint of
+ * the remote sender of the datagram.
+ *
+ * @param flags Flags specifying how the receive call is to be made.
+ *
+ * @param ec Set to indicate what error occurred, if any.
+ *
+ * @returns The number of bytes received.
+ */
+ template <typename MutableBufferSequence>
+ std::size_t receive_from(const MutableBufferSequence& buffers,
+ endpoint_type& sender_endpoint, socket_base::message_flags flags,
+ boost::system::error_code& ec)
+ {
+ return this->impl_.get_service().receive_from(
+ this->impl_.get_implementation(), buffers, sender_endpoint, flags, ec);
+ }
+
+ /// Start an asynchronous receive.
+ /**
+ * This function is used to asynchronously receive a datagram. The function
+ * call always returns immediately.
+ *
+ * @param buffers One or more buffers into which the data will be received.
+ * Although the buffers object may be copied as necessary, ownership of the
+ * underlying memory blocks is retained by the caller, which must guarantee
+ * that they remain valid until the handler is called.
+ *
+ * @param sender_endpoint An endpoint object that receives the endpoint of
+ * the remote sender of the datagram. Ownership of the sender_endpoint object
+ * is retained by the caller, which must guarantee that it is valid until the
+ * handler is called.
+ *
+ * @param handler The handler to be called when the receive operation
+ * completes. Copies will be made of the handler as required. The function
+ * signature of the handler must be:
+ * @code void handler(
+ * const boost::system::error_code& error, // Result of operation.
+ * std::size_t bytes_transferred // Number of bytes received.
+ * ); @endcode
+ * Regardless of whether the asynchronous operation completes immediately or
+ * not, the handler will not be invoked from within this function. On
+ * immediate completion, invocation of the handler will be performed in a
+ * manner equivalent to using boost::asio::post().
+ *
+ * @par Example
+ * To receive into a single data buffer use the @ref buffer function as
+ * follows:
+ * @code socket.async_receive_from(
+ * boost::asio::buffer(data, size), sender_endpoint, handler); @endcode
+ * See the @ref buffer documentation for information on receiving into
+ * multiple buffers in one go, and how to use it with arrays, boost::array or
+ * std::vector.
+ */
+ template <typename MutableBufferSequence, typename ReadHandler>
+ BOOST_ASIO_INITFN_RESULT_TYPE(ReadHandler,
+ void (boost::system::error_code, std::size_t, boost::asio::ip::address))
+ async_receive_from(const MutableBufferSequence& buffers,
+ endpoint_type& sender_endpoint,
+ BOOST_ASIO_MOVE_ARG(ReadHandler) handler)
+ {
+ return async_initiate<ReadHandler,
+ void (boost::system::error_code, std::size_t, boost::asio::ip::address)>(
+ initiate_async_receive_from(), handler, this, buffers,
+ &sender_endpoint, socket_base::message_flags(0));
+ }
+
+ /// Start an asynchronous receive.
+ /**
+ * This function is used to asynchronously receive a datagram. The function
+ * call always returns immediately.
+ *
+ * @param buffers One or more buffers into which the data will be received.
+ * Although the buffers object may be copied as necessary, ownership of the
+ * underlying memory blocks is retained by the caller, which must guarantee
+ * that they remain valid until the handler is called.
+ *
+ * @param sender_endpoint An endpoint object that receives the endpoint of
+ * the remote sender of the datagram. Ownership of the sender_endpoint object
+ * is retained by the caller, which must guarantee that it is valid until the
+ * handler is called.
+ *
+ * @param flags Flags specifying how the receive call is to be made.
+ *
+ * @param handler The handler to be called when the receive operation
+ * completes. Copies will be made of the handler as required. The function
+ * signature of the handler must be:
+ * @code void handler(
+ * const boost::system::error_code& error, // Result of operation.
+ * std::size_t bytes_transferred // Number of bytes received.
+ * ); @endcode
+ * Regardless of whether the asynchronous operation completes immediately or
+ * not, the handler will not be invoked from within this function. On
+ * immediate completion, invocation of the handler will be performed in a
+ * manner equivalent to using boost::asio::post().
+ */
+ template <typename MutableBufferSequence, typename ReadHandler>
+ BOOST_ASIO_INITFN_RESULT_TYPE(ReadHandler,
+ void (boost::system::error_code, std::size_t, boost::asio::ip::address))
+ async_receive_from(const MutableBufferSequence& buffers,
+ endpoint_type& sender_endpoint, socket_base::message_flags flags,
+ BOOST_ASIO_MOVE_ARG(ReadHandler) handler)
+ {
+ return async_initiate<ReadHandler,
+ void (boost::system::error_code, std::size_t, boost::asio::ip::address)>(
+ initiate_async_receive_from(), handler,
+ this, buffers, &sender_endpoint, flags);
+ }
+
+private:
+ struct initiate_async_send
+ {
+ template <typename WriteHandler, typename ConstBufferSequence>
+ void operator()(BOOST_ASIO_MOVE_ARG(WriteHandler) handler,
+ basic_datagram_socket_ext* self, const ConstBufferSequence& buffers,
+ socket_base::message_flags flags) const
+ {
+ // If you get an error on the following line it means that your handler
+ // does not meet the documented type requirements for a WriteHandler.
+ BOOST_ASIO_WRITE_HANDLER_CHECK(WriteHandler, handler) type_check;
+
+ detail::non_const_lvalue<WriteHandler> handler2(handler);
+ self->impl_.get_service().async_send(
+ self->impl_.get_implementation(), buffers, flags,
+ handler2.value, self->impl_.get_executor());
+ }
+ };
+
+ struct initiate_async_send_to
+ {
+ template <typename WriteHandler, typename ConstBufferSequence>
+ void operator()(BOOST_ASIO_MOVE_ARG(WriteHandler) handler,
+ basic_datagram_socket_ext* self, const ConstBufferSequence& buffers,
+ const endpoint_type& destination,
+ socket_base::message_flags flags) const
+ {
+ // If you get an error on the following line it means that your handler
+ // does not meet the documented type requirements for a WriteHandler.
+ BOOST_ASIO_WRITE_HANDLER_CHECK(WriteHandler, handler) type_check;
+
+ detail::non_const_lvalue<WriteHandler> handler2(handler);
+ self->impl_.get_service().async_send_to(
+ self->impl_.get_implementation(), buffers, destination, flags,
+ handler2.value, self->impl_.get_executor());
+ }
+ };
+
+ struct initiate_async_receive
+ {
+ template <typename ReadHandler, typename MutableBufferSequence>
+ void operator()(BOOST_ASIO_MOVE_ARG(ReadHandler) handler,
+ basic_datagram_socket_ext* self, const MutableBufferSequence& buffers,
+ socket_base::message_flags flags) const
+ {
+ // If you get an error on the following line it means that your handler
+ // does not meet the documented type requirements for a ReadHandler.
+ BOOST_ASIO_READ_HANDLER_CHECK_EXT(ReadHandler, handler) type_check;
+
+ detail::non_const_lvalue<ReadHandler> handler2(handler);
+ self->impl_.get_service().async_receive(
+ self->impl_.get_implementation(), buffers, flags,
+ handler2.value, self->impl_.get_executor());
+ }
+ };
+
+ struct initiate_async_receive_from
+ {
+ template <typename ReadHandler, typename MutableBufferSequence>
+ void operator()(BOOST_ASIO_MOVE_ARG(ReadHandler) handler,
+ basic_datagram_socket_ext* self, const MutableBufferSequence& buffers,
+ endpoint_type* sender_endpoint, socket_base::message_flags flags) const
+ {
+ // If you get an error on the following line it means that your handler
+ // does not meet the documented type requirements for a ReadHandler.
+ BOOST_ASIO_READ_HANDLER_CHECK_EXT(ReadHandler, handler) type_check;
+
+ detail::non_const_lvalue<ReadHandler> handler2(handler);
+ self->impl_.get_service().async_receive_from(
+ self->impl_.get_implementation(), buffers, *sender_endpoint, flags,
+ handler2.value, self->impl_.get_executor());
+ }
+ };
+};
+
+} // namespace asio
+} // namespace boost
+
+#include <boost/asio/detail/pop_options.hpp>
+
+#endif // BOOST_ASIO_BASIC_DATAGRAM_SOCKET_EXT_HPP
diff --git a/implementation/helper/1.74/boost/asio/basic_socket_acceptor_ext.hpp b/implementation/helper/1.74/boost/asio/basic_socket_acceptor_ext.hpp
new file mode 100644
index 0000000..998b86d
--- /dev/null
+++ b/implementation/helper/1.74/boost/asio/basic_socket_acceptor_ext.hpp
@@ -0,0 +1,2381 @@
+//
+// basic_socket_acceptor_ext.hpp
+// ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+//
+// Copyright (c) 2003-2019 Christopher M. Kohlhoff (chris at kohlhoff dot com)
+// Copyright (c) 2019 Bayerische Motoren Werke Aktiengesellschaft (BMW AG)
+//
+// Distributed under the Boost Software License, Version 1.0. (See accompanying
+// file LICENSE_boost or copy at http://www.boost.org/LICENSE_1_0.txt)
+//
+
+#ifndef BOOST_ASIO_BASIC_SOCKET_ACCEPTOR_EXT_HPP
+#define BOOST_ASIO_BASIC_SOCKET_ACCEPTOR_EXT_HPP
+
+#if defined(_MSC_VER) && (_MSC_VER >= 1200)
+# pragma once
+#endif // defined(_MSC_VER) && (_MSC_VER >= 1200)
+
+#include <boost/asio/detail/config.hpp>
+#include <boost/asio/basic_socket_ext_local.hpp>
+#include <boost/asio/detail/handler_type_requirements_ext.hpp>
+#include <boost/asio/detail/io_object_impl.hpp>
+#include <boost/asio/detail/non_const_lvalue.hpp>
+#include <boost/asio/detail/throw_error.hpp>
+#include <boost/asio/detail/type_traits.hpp>
+#include <boost/asio/error.hpp>
+#include <boost/asio/execution_context.hpp>
+#include <boost/asio/executor.hpp>
+#include <boost/asio/socket_base.hpp>
+
+#if defined(BOOST_ASIO_WINDOWS_RUNTIME)
+# include <boost/asio/detail/null_socket_service.hpp>
+#elif defined(BOOST_ASIO_HAS_IOCP)
+# include <boost/asio/detail/win_iocp_socket_service.hpp>
+#else
+# include <boost/asio/detail/reactive_socket_service_ext_local.hpp>
+#endif
+
+#if defined(BOOST_ASIO_HAS_MOVE)
+# include <utility>
+#endif // defined(BOOST_ASIO_HAS_MOVE)
+
+#include <boost/asio/detail/push_options.hpp>
+
+namespace boost {
+namespace asio {
+
+#if !defined(BOOST_ASIO_BASIC_SOCKET_ACCEPTOR_EXT_FWD_DECL)
+#define BOOST_ASIO_BASIC_SOCKET_ACCEPTOR_EXT_FWD_DECL
+
+// Forward declaration with defaulted arguments.
+template <typename Protocol, typename Executor = executor>
+class basic_socket_acceptor_ext;
+
+#endif // !defined(BOOST_ASIO_BASIC_SOCKET_ACCEPTOR_EXT_FWD_DECL)
+
+/// Provides the ability to accept new connections.
+/**
+ * The basic_socket_acceptor_ext class template is used for accepting new socket
+ * connections.
+ *
+ * @par Thread Safety
+ * @e Distinct @e objects: Safe.@n
+ * @e Shared @e objects: Unsafe.
+ *
+ * @par Example
+ * Opening a socket acceptor with the SO_REUSEADDR option enabled:
+ * @code
+ * boost::asio::ip::tcp::acceptor acceptor(my_context);
+ * boost::asio::ip::tcp::endpoint endpoint(boost::asio::ip::tcp::v4(), port);
+ * acceptor.open(endpoint.protocol());
+ * acceptor.set_option(boost::asio::ip::tcp::acceptor::reuse_address(true));
+ * acceptor.bind(endpoint);
+ * acceptor.listen();
+ * @endcode
+ */
+template <typename Protocol, typename Executor>
+class basic_socket_acceptor_ext
+ : public socket_base
+{
+public:
+ /// The type of the executor associated with the object.
+ typedef Executor executor_type;
+
+ /// The native representation of an acceptor.
+#if defined(GENERATING_DOCUMENTATION)
+ typedef implementation_defined native_handle_type;
+#elif defined(BOOST_ASIO_WINDOWS_RUNTIME)
+ typedef typename detail::null_socket_service<
+ Protocol>::native_handle_type native_handle_type;
+#elif defined(BOOST_ASIO_HAS_IOCP)
+ typedef typename detail::win_iocp_socket_service<
+ Protocol>::native_handle_type native_handle_type;
+#else
+ typedef typename detail::reactive_socket_service_ext_local<
+ Protocol>::native_handle_type native_handle_type;
+#endif
+
+ /// The protocol type.
+ typedef Protocol protocol_type;
+
+ /// The endpoint type.
+ typedef typename Protocol::endpoint endpoint_type;
+
+ /// Construct an acceptor without opening it.
+ /**
+ * This constructor creates an acceptor without opening it to listen for new
+ * connections. The open() function must be called before the acceptor can
+ * accept new socket connections.
+ *
+ * @param ex The I/O executor that the acceptor will use, by default, to
+ * dispatch handlers for any asynchronous operations performed on the
+ * acceptor.
+ */
+ explicit basic_socket_acceptor_ext(const executor_type& ex)
+ : impl_(ex)
+ {
+ }
+
+ /// Construct an acceptor without opening it.
+ /**
+ * This constructor creates an acceptor without opening it to listen for new
+ * connections. The open() function must be called before the acceptor can
+ * accept new socket connections.
+ *
+ * @param context An execution context which provides the I/O executor that
+ * the acceptor will use, by default, to dispatch handlers for any
+ * asynchronous operations performed on the acceptor.
+ */
+ template <typename ExecutionContext>
+ explicit basic_socket_acceptor_ext(ExecutionContext& context,
+ typename enable_if<
+ is_convertible<ExecutionContext&, execution_context&>::value
+ >::type* = 0)
+ : impl_(context)
+ {
+ }
+
+ /// Construct an open acceptor.
+ /**
+ * This constructor creates an acceptor and automatically opens it.
+ *
+ * @param ex The I/O executor that the acceptor will use, by default, to
+ * dispatch handlers for any asynchronous operations performed on the
+ * acceptor.
+ *
+ * @param protocol An object specifying protocol parameters to be used.
+ *
+ * @throws boost::system::system_error Thrown on failure.
+ */
+ basic_socket_acceptor_ext(const executor_type& ex, const protocol_type& protocol)
+ : impl_(ex)
+ {
+ boost::system::error_code ec;
+ impl_.get_service().open(impl_.get_implementation(), protocol, ec);
+ boost::asio::detail::throw_error(ec, "open");
+ }
+
+ /// Construct an open acceptor.
+ /**
+ * This constructor creates an acceptor and automatically opens it.
+ *
+ * @param context An execution context which provides the I/O executor that
+ * the acceptor will use, by default, to dispatch handlers for any
+ * asynchronous operations performed on the acceptor.
+ *
+ * @param protocol An object specifying protocol parameters to be used.
+ *
+ * @throws boost::system::system_error Thrown on failure.
+ */
+ template <typename ExecutionContext>
+ basic_socket_acceptor_ext(ExecutionContext& context,
+ const protocol_type& protocol,
+ typename enable_if<
+ is_convertible<ExecutionContext&, execution_context&>::value
+ >::type* = 0)
+ : impl_(context)
+ {
+ boost::system::error_code ec;
+ impl_.get_service().open(impl_.get_implementation(), protocol, ec);
+ boost::asio::detail::throw_error(ec, "open");
+ }
+
+ /// Construct an acceptor opened on the given endpoint.
+ /**
+ * This constructor creates an acceptor and automatically opens it to listen
+ * for new connections on the specified endpoint.
+ *
+ * @param ex The I/O executor that the acceptor will use, by default, to
+ * dispatch handlers for any asynchronous operations performed on the
+ * acceptor.
+ *
+ * @param endpoint An endpoint on the local machine on which the acceptor
+ * will listen for new connections.
+ *
+ * @param reuse_addr Whether the constructor should set the socket option
+ * socket_base::reuse_address.
+ *
+ * @throws boost::system::system_error Thrown on failure.
+ *
+ * @note This constructor is equivalent to the following code:
+ * @code
+ * basic_socket_acceptor<Protocol> acceptor(my_context);
+ * acceptor.open(endpoint.protocol());
+ * if (reuse_addr)
+ * acceptor.set_option(socket_base::reuse_address(true));
+ * acceptor.bind(endpoint);
+ * acceptor.listen();
+ * @endcode
+ */
+ basic_socket_acceptor_ext(const executor_type& ex,
+ const endpoint_type& endpoint, bool reuse_addr = true)
+ : impl_(ex)
+ {
+ boost::system::error_code ec;
+ const protocol_type protocol = endpoint.protocol();
+ impl_.get_service().open(impl_.get_implementation(), protocol, ec);
+ boost::asio::detail::throw_error(ec, "open");
+ if (reuse_addr)
+ {
+ impl_.get_service().set_option(impl_.get_implementation(),
+ socket_base::reuse_address(true), ec);
+ boost::asio::detail::throw_error(ec, "set_option");
+ }
+ impl_.get_service().bind(impl_.get_implementation(), endpoint, ec);
+ boost::asio::detail::throw_error(ec, "bind");
+ impl_.get_service().listen(impl_.get_implementation(),
+ socket_base::max_listen_connections, ec);
+ boost::asio::detail::throw_error(ec, "listen");
+ }
+
+ /// Construct an acceptor opened on the given endpoint.
+ /**
+ * This constructor creates an acceptor and automatically opens it to listen
+ * for new connections on the specified endpoint.
+ *
+ * @param context An execution context which provides the I/O executor that
+ * the acceptor will use, by default, to dispatch handlers for any
+ * asynchronous operations performed on the acceptor.
+ *
+ * @param endpoint An endpoint on the local machine on which the acceptor
+ * will listen for new connections.
+ *
+ * @param reuse_addr Whether the constructor should set the socket option
+ * socket_base::reuse_address.
+ *
+ * @throws boost::system::system_error Thrown on failure.
+ *
+ * @note This constructor is equivalent to the following code:
+ * @code
+ * basic_socket_acceptor<Protocol> acceptor(my_context);
+ * acceptor.open(endpoint.protocol());
+ * if (reuse_addr)
+ * acceptor.set_option(socket_base::reuse_address(true));
+ * acceptor.bind(endpoint);
+ * acceptor.listen();
+ * @endcode
+ */
+ template <typename ExecutionContext>
+ basic_socket_acceptor_ext(ExecutionContext& context,
+ const endpoint_type& endpoint, bool reuse_addr = true,
+ typename enable_if<
+ is_convertible<ExecutionContext&, execution_context&>::value
+ >::type* = 0)
+ : impl_(context)
+ {
+ boost::system::error_code ec;
+ const protocol_type protocol = endpoint.protocol();
+ impl_.get_service().open(impl_.get_implementation(), protocol, ec);
+ boost::asio::detail::throw_error(ec, "open");
+ if (reuse_addr)
+ {
+ impl_.get_service().set_option(impl_.get_implementation(),
+ socket_base::reuse_address(true), ec);
+ boost::asio::detail::throw_error(ec, "set_option");
+ }
+ impl_.get_service().bind(impl_.get_implementation(), endpoint, ec);
+ boost::asio::detail::throw_error(ec, "bind");
+ impl_.get_service().listen(impl_.get_implementation(),
+ socket_base::max_listen_connections, ec);
+ boost::asio::detail::throw_error(ec, "listen");
+ }
+
+ /// Construct a basic_socket_acceptor on an existing native acceptor.
+ /**
+ * This constructor creates an acceptor object to hold an existing native
+ * acceptor.
+ *
+ * @param ex The I/O executor that the acceptor will use, by default, to
+ * dispatch handlers for any asynchronous operations performed on the
+ * acceptor.
+ *
+ * @param protocol An object specifying protocol parameters to be used.
+ *
+ * @param native_acceptor A native acceptor.
+ *
+ * @throws boost::system::system_error Thrown on failure.
+ */
+ basic_socket_acceptor_ext(const executor_type& ex,
+ const protocol_type& protocol, const native_handle_type& native_acceptor)
+ : impl_(ex)
+ {
+ boost::system::error_code ec;
+ impl_.get_service().assign(impl_.get_implementation(),
+ protocol, native_acceptor, ec);
+ boost::asio::detail::throw_error(ec, "assign");
+ }
+
+ /// Construct a basic_socket_acceptor on an existing native acceptor.
+ /**
+ * This constructor creates an acceptor object to hold an existing native
+ * acceptor.
+ *
+ * @param context An execution context which provides the I/O executor that
+ * the acceptor will use, by default, to dispatch handlers for any
+ * asynchronous operations performed on the acceptor.
+ *
+ * @param protocol An object specifying protocol parameters to be used.
+ *
+ * @param native_acceptor A native acceptor.
+ *
+ * @throws boost::system::system_error Thrown on failure.
+ */
+ template <typename ExecutionContext>
+ basic_socket_acceptor_ext(ExecutionContext& context,
+ const protocol_type& protocol, const native_handle_type& native_acceptor,
+ typename enable_if<
+ is_convertible<ExecutionContext&, execution_context&>::value
+ >::type* = 0)
+ : impl_(context)
+ {
+ boost::system::error_code ec;
+ impl_.get_service().assign(impl_.get_implementation(),
+ protocol, native_acceptor, ec);
+ boost::asio::detail::throw_error(ec, "assign");
+ }
+
+#if defined(BOOST_ASIO_HAS_MOVE) || defined(GENERATING_DOCUMENTATION)
+ /// Move-construct a basic_socket_acceptor from another.
+ /**
+ * This constructor moves an acceptor from one object to another.
+ *
+ * @param other The other basic_socket_acceptor object from which the move
+ * will occur.
+ *
+ * @note Following the move, the moved-from object is in the same state as if
+ * constructed using the @c basic_socket_acceptor(const executor_type&)
+ * constructor.
+ */
+ basic_socket_acceptor_ext(basic_socket_acceptor_ext&& other)
+ : impl_(std::move(other.impl_))
+ {
+ }
+
+ /// Move-assign a basic_socket_acceptor from another.
+ /**
+ * This assignment operator moves an acceptor from one object to another.
+ *
+ * @param other The other basic_socket_acceptor object from which the move
+ * will occur.
+ *
+ * @note Following the move, the moved-from object is in the same state as if
+ * constructed using the @c basic_socket_acceptor(const executor_type&)
+ * constructor.
+ */
+ basic_socket_acceptor_ext& operator=(basic_socket_acceptor_ext&& other)
+ {
+ impl_ = std::move(other.impl_);
+ return *this;
+ }
+
+ // All socket acceptors have access to each other's implementations.
+ template <typename Protocol1, typename Executor1>
+ friend class basic_socket_acceptor_ext;
+
+ /// Move-construct a basic_socket_acceptor from an acceptor of another
+ /// protocol type.
+ /**
+ * This constructor moves an acceptor from one object to another.
+ *
+ * @param other The other basic_socket_acceptor object from which the move
+ * will occur.
+ *
+ * @note Following the move, the moved-from object is in the same state as if
+ * constructed using the @c basic_socket_acceptor(const executor_type&)
+ * constructor.
+ */
+ template <typename Protocol1, typename Executor1>
+ basic_socket_acceptor_ext(basic_socket_acceptor_ext<Protocol1, Executor1>&& other,
+ typename enable_if<
+ is_convertible<Protocol1, Protocol>::value
+ && is_convertible<Executor1, Executor>::value
+ >::type* = 0)
+ : impl_(std::move(other.impl_))
+ {
+ }
+
+ /// Move-assign a basic_socket_acceptor from an acceptor of another protocol
+ /// type.
+ /**
+ * This assignment operator moves an acceptor from one object to another.
+ *
+ * @param other The other basic_socket_acceptor object from which the move
+ * will occur.
+ *
+ * @note Following the move, the moved-from object is in the same state as if
+ * constructed using the @c basic_socket_acceptor(const executor_type&)
+ * constructor.
+ */
+ template <typename Protocol1, typename Executor1>
+ typename enable_if<
+ is_convertible<Protocol1, Protocol>::value
+ && is_convertible<Executor1, Executor>::value,
+ basic_socket_acceptor_ext&
+ >::type operator=(basic_socket_acceptor_ext<Protocol1, Executor1>&& other)
+ {
+ basic_socket_acceptor_ext tmp(std::move(other));
+ impl_ = std::move(tmp.impl_);
+ return *this;
+ }
+#endif // defined(BOOST_ASIO_HAS_MOVE) || defined(GENERATING_DOCUMENTATION)
+
+ /// Destroys the acceptor.
+ /**
+ * This function destroys the acceptor, cancelling any outstanding
+ * asynchronous operations associated with the acceptor as if by calling
+ * @c cancel.
+ */
+ ~basic_socket_acceptor_ext()
+ {
+ }
+
+ /// Get the executor associated with the object.
+ executor_type get_executor() BOOST_ASIO_NOEXCEPT
+ {
+ return impl_.get_executor();
+ }
+
+ /// Open the acceptor using the specified protocol.
+ /**
+ * This function opens the socket acceptor so that it will use the specified
+ * protocol.
+ *
+ * @param protocol An object specifying which protocol is to be used.
+ *
+ * @throws boost::system::system_error Thrown on failure.
+ *
+ * @par Example
+ * @code
+ * boost::asio::ip::tcp::acceptor acceptor(my_context);
+ * acceptor.open(boost::asio::ip::tcp::v4());
+ * @endcode
+ */
+ void open(const protocol_type& protocol = protocol_type())
+ {
+ boost::system::error_code ec;
+ impl_.get_service().open(impl_.get_implementation(), protocol, ec);
+ boost::asio::detail::throw_error(ec, "open");
+ }
+
+ /// Open the acceptor using the specified protocol.
+ /**
+ * This function opens the socket acceptor so that it will use the specified
+ * protocol.
+ *
+ * @param protocol An object specifying which protocol is to be used.
+ *
+ * @param ec Set to indicate what error occurred, if any.
+ *
+ * @par Example
+ * @code
+ * boost::asio::ip::tcp::acceptor acceptor(my_context);
+ * boost::system::error_code ec;
+ * acceptor.open(boost::asio::ip::tcp::v4(), ec);
+ * if (ec)
+ * {
+ * // An error occurred.
+ * }
+ * @endcode
+ */
+ BOOST_ASIO_SYNC_OP_VOID open(const protocol_type& protocol,
+ boost::system::error_code& ec)
+ {
+ impl_.get_service().open(impl_.get_implementation(), protocol, ec);
+ BOOST_ASIO_SYNC_OP_VOID_RETURN(ec);
+ }
+
+ /// Assigns an existing native acceptor to the acceptor.
+ /*
+ * This function opens the acceptor to hold an existing native acceptor.
+ *
+ * @param protocol An object specifying which protocol is to be used.
+ *
+ * @param native_acceptor A native acceptor.
+ *
+ * @throws boost::system::system_error Thrown on failure.
+ */
+ void assign(const protocol_type& protocol,
+ const native_handle_type& native_acceptor)
+ {
+ boost::system::error_code ec;
+ impl_.get_service().assign(impl_.get_implementation(),
+ protocol, native_acceptor, ec);
+ boost::asio::detail::throw_error(ec, "assign");
+ }
+
+ /// Assigns an existing native acceptor to the acceptor.
+ /*
+ * This function opens the acceptor to hold an existing native acceptor.
+ *
+ * @param protocol An object specifying which protocol is to be used.
+ *
+ * @param native_acceptor A native acceptor.
+ *
+ * @param ec Set to indicate what error occurred, if any.
+ */
+ BOOST_ASIO_SYNC_OP_VOID assign(const protocol_type& protocol,
+ const native_handle_type& native_acceptor, boost::system::error_code& ec)
+ {
+ impl_.get_service().assign(impl_.get_implementation(),
+ protocol, native_acceptor, ec);
+ BOOST_ASIO_SYNC_OP_VOID_RETURN(ec);
+ }
+
+ /// Determine whether the acceptor is open.
+ bool is_open() const
+ {
+ return impl_.get_service().is_open(impl_.get_implementation());
+ }
+
+ /// Bind the acceptor to the given local endpoint.
+ /**
+ * This function binds the socket acceptor to the specified endpoint on the
+ * local machine.
+ *
+ * @param endpoint An endpoint on the local machine to which the socket
+ * acceptor will be bound.
+ *
+ * @throws boost::system::system_error Thrown on failure.
+ *
+ * @par Example
+ * @code
+ * boost::asio::ip::tcp::acceptor acceptor(my_context);
+ * boost::asio::ip::tcp::endpoint endpoint(boost::asio::ip::tcp::v4(), 12345);
+ * acceptor.open(endpoint.protocol());
+ * acceptor.bind(endpoint);
+ * @endcode
+ */
+ void bind(const endpoint_type& endpoint)
+ {
+ boost::system::error_code ec;
+ impl_.get_service().bind(impl_.get_implementation(), endpoint, ec);
+ boost::asio::detail::throw_error(ec, "bind");
+ }
+
+ /// Bind the acceptor to the given local endpoint.
+ /**
+ * This function binds the socket acceptor to the specified endpoint on the
+ * local machine.
+ *
+ * @param endpoint An endpoint on the local machine to which the socket
+ * acceptor will be bound.
+ *
+ * @param ec Set to indicate what error occurred, if any.
+ *
+ * @par Example
+ * @code
+ * boost::asio::ip::tcp::acceptor acceptor(my_context);
+ * boost::asio::ip::tcp::endpoint endpoint(boost::asio::ip::tcp::v4(), 12345);
+ * acceptor.open(endpoint.protocol());
+ * boost::system::error_code ec;
+ * acceptor.bind(endpoint, ec);
+ * if (ec)
+ * {
+ * // An error occurred.
+ * }
+ * @endcode
+ */
+ BOOST_ASIO_SYNC_OP_VOID bind(const endpoint_type& endpoint,
+ boost::system::error_code& ec)
+ {
+ impl_.get_service().bind(impl_.get_implementation(), endpoint, ec);
+ BOOST_ASIO_SYNC_OP_VOID_RETURN(ec);
+ }
+
+ /// Place the acceptor into the state where it will listen for new
+ /// connections.
+ /**
+ * This function puts the socket acceptor into the state where it may accept
+ * new connections.
+ *
+ * @param backlog The maximum length of the queue of pending connections.
+ *
+ * @throws boost::system::system_error Thrown on failure.
+ */
+ void listen(int backlog = socket_base::max_listen_connections)
+ {
+ boost::system::error_code ec;
+ impl_.get_service().listen(impl_.get_implementation(), backlog, ec);
+ boost::asio::detail::throw_error(ec, "listen");
+ }
+
+ /// Place the acceptor into the state where it will listen for new
+ /// connections.
+ /**
+ * This function puts the socket acceptor into the state where it may accept
+ * new connections.
+ *
+ * @param backlog The maximum length of the queue of pending connections.
+ *
+ * @param ec Set to indicate what error occurred, if any.
+ *
+ * @par Example
+ * @code
+ * boost::asio::ip::tcp::acceptor acceptor(my_context);
+ * ...
+ * boost::system::error_code ec;
+ * acceptor.listen(boost::asio::socket_base::max_listen_connections, ec);
+ * if (ec)
+ * {
+ * // An error occurred.
+ * }
+ * @endcode
+ */
+ BOOST_ASIO_SYNC_OP_VOID listen(int backlog, boost::system::error_code& ec)
+ {
+ impl_.get_service().listen(impl_.get_implementation(), backlog, ec);
+ BOOST_ASIO_SYNC_OP_VOID_RETURN(ec);
+ }
+
+ /// Close the acceptor.
+ /**
+ * This function is used to close the acceptor. Any asynchronous accept
+ * operations will be cancelled immediately.
+ *
+ * A subsequent call to open() is required before the acceptor can again be
+ * used to again perform socket accept operations.
+ *
+ * @throws boost::system::system_error Thrown on failure.
+ */
+ void close()
+ {
+ boost::system::error_code ec;
+ impl_.get_service().close(impl_.get_implementation(), ec);
+ boost::asio::detail::throw_error(ec, "close");
+ }
+
+ /// Close the acceptor.
+ /**
+ * This function is used to close the acceptor. Any asynchronous accept
+ * operations will be cancelled immediately.
+ *
+ * A subsequent call to open() is required before the acceptor can again be
+ * used to again perform socket accept operations.
+ *
+ * @param ec Set to indicate what error occurred, if any.
+ *
+ * @par Example
+ * @code
+ * boost::asio::ip::tcp::acceptor acceptor(my_context);
+ * ...
+ * boost::system::error_code ec;
+ * acceptor.close(ec);
+ * if (ec)
+ * {
+ * // An error occurred.
+ * }
+ * @endcode
+ */
+ BOOST_ASIO_SYNC_OP_VOID close(boost::system::error_code& ec)
+ {
+ impl_.get_service().close(impl_.get_implementation(), ec);
+ BOOST_ASIO_SYNC_OP_VOID_RETURN(ec);
+ }
+
+ /// Release ownership of the underlying native acceptor.
+ /**
+ * This function causes all outstanding asynchronous accept operations to
+ * finish immediately, and the handlers for cancelled operations will be
+ * passed the boost::asio::error::operation_aborted error. Ownership of the
+ * native acceptor is then transferred to the caller.
+ *
+ * @throws boost::system::system_error Thrown on failure.
+ *
+ * @note This function is unsupported on Windows versions prior to Windows
+ * 8.1, and will fail with boost::asio::error::operation_not_supported on
+ * these platforms.
+ */
+#if defined(BOOST_ASIO_MSVC) && (BOOST_ASIO_MSVC >= 1400) \
+ && (!defined(_WIN32_WINNT) || _WIN32_WINNT < 0x0603)
+ __declspec(deprecated("This function always fails with "
+ "operation_not_supported when used on Windows versions "
+ "prior to Windows 8.1."))
+#endif
+ native_handle_type release()
+ {
+ boost::system::error_code ec;
+ native_handle_type s = impl_.get_service().release(
+ impl_.get_implementation(), ec);
+ boost::asio::detail::throw_error(ec, "release");
+ return s;
+ }
+
+ /// Release ownership of the underlying native acceptor.
+ /**
+ * This function causes all outstanding asynchronous accept operations to
+ * finish immediately, and the handlers for cancelled operations will be
+ * passed the boost::asio::error::operation_aborted error. Ownership of the
+ * native acceptor is then transferred to the caller.
+ *
+ * @param ec Set to indicate what error occurred, if any.
+ *
+ * @note This function is unsupported on Windows versions prior to Windows
+ * 8.1, and will fail with boost::asio::error::operation_not_supported on
+ * these platforms.
+ */
+#if defined(BOOST_ASIO_MSVC) && (BOOST_ASIO_MSVC >= 1400) \
+ && (!defined(_WIN32_WINNT) || _WIN32_WINNT < 0x0603)
+ __declspec(deprecated("This function always fails with "
+ "operation_not_supported when used on Windows versions "
+ "prior to Windows 8.1."))
+#endif
+ native_handle_type release(boost::system::error_code& ec)
+ {
+ return impl_.get_service().release(impl_.get_implementation(), ec);
+ }
+
+ /// Get the native acceptor representation.
+ /**
+ * This function may be used to obtain the underlying representation of the
+ * acceptor. This is intended to allow access to native acceptor functionality
+ * that is not otherwise provided.
+ */
+ native_handle_type native_handle()
+ {
+ return impl_.get_service().native_handle(impl_.get_implementation());
+ }
+
+ /// Cancel all asynchronous operations associated with the acceptor.
+ /**
+ * This function causes all outstanding asynchronous connect, send and receive
+ * operations to finish immediately, and the handlers for cancelled operations
+ * will be passed the boost::asio::error::operation_aborted error.
+ *
+ * @throws boost::system::system_error Thrown on failure.
+ */
+ void cancel()
+ {
+ boost::system::error_code ec;
+ impl_.get_service().cancel(impl_.get_implementation(), ec);
+ boost::asio::detail::throw_error(ec, "cancel");
+ }
+
+ /// Cancel all asynchronous operations associated with the acceptor.
+ /**
+ * This function causes all outstanding asynchronous connect, send and receive
+ * operations to finish immediately, and the handlers for cancelled operations
+ * will be passed the boost::asio::error::operation_aborted error.
+ *
+ * @param ec Set to indicate what error occurred, if any.
+ */
+ BOOST_ASIO_SYNC_OP_VOID cancel(boost::system::error_code& ec)
+ {
+ impl_.get_service().cancel(impl_.get_implementation(), ec);
+ BOOST_ASIO_SYNC_OP_VOID_RETURN(ec);
+ }
+
+ /// Set an option on the acceptor.
+ /**
+ * This function is used to set an option on the acceptor.
+ *
+ * @param option The new option value to be set on the acceptor.
+ *
+ * @throws boost::system::system_error Thrown on failure.
+ *
+ * @sa SettableSocketOption @n
+ * boost::asio::socket_base::reuse_address
+ * boost::asio::socket_base::enable_connection_aborted
+ *
+ * @par Example
+ * Setting the SOL_SOCKET/SO_REUSEADDR option:
+ * @code
+ * boost::asio::ip::tcp::acceptor acceptor(my_context);
+ * ...
+ * boost::asio::ip::tcp::acceptor::reuse_address option(true);
+ * acceptor.set_option(option);
+ * @endcode
+ */
+ template <typename SettableSocketOption>
+ void set_option(const SettableSocketOption& option)
+ {
+ boost::system::error_code ec;
+ impl_.get_service().set_option(impl_.get_implementation(), option, ec);
+ boost::asio::detail::throw_error(ec, "set_option");
+ }
+
+ /// Set an option on the acceptor.
+ /**
+ * This function is used to set an option on the acceptor.
+ *
+ * @param option The new option value to be set on the acceptor.
+ *
+ * @param ec Set to indicate what error occurred, if any.
+ *
+ * @sa SettableSocketOption @n
+ * boost::asio::socket_base::reuse_address
+ * boost::asio::socket_base::enable_connection_aborted
+ *
+ * @par Example
+ * Setting the SOL_SOCKET/SO_REUSEADDR option:
+ * @code
+ * boost::asio::ip::tcp::acceptor acceptor(my_context);
+ * ...
+ * boost::asio::ip::tcp::acceptor::reuse_address option(true);
+ * boost::system::error_code ec;
+ * acceptor.set_option(option, ec);
+ * if (ec)
+ * {
+ * // An error occurred.
+ * }
+ * @endcode
+ */
+ template <typename SettableSocketOption>
+ BOOST_ASIO_SYNC_OP_VOID set_option(const SettableSocketOption& option,
+ boost::system::error_code& ec)
+ {
+ impl_.get_service().set_option(impl_.get_implementation(), option, ec);
+ BOOST_ASIO_SYNC_OP_VOID_RETURN(ec);
+ }
+
+ /// Get an option from the acceptor.
+ /**
+ * This function is used to get the current value of an option on the
+ * acceptor.
+ *
+ * @param option The option value to be obtained from the acceptor.
+ *
+ * @throws boost::system::system_error Thrown on failure.
+ *
+ * @sa GettableSocketOption @n
+ * boost::asio::socket_base::reuse_address
+ *
+ * @par Example
+ * Getting the value of the SOL_SOCKET/SO_REUSEADDR option:
+ * @code
+ * boost::asio::ip::tcp::acceptor acceptor(my_context);
+ * ...
+ * boost::asio::ip::tcp::acceptor::reuse_address option;
+ * acceptor.get_option(option);
+ * bool is_set = option.get();
+ * @endcode
+ */
+ template <typename GettableSocketOption>
+ void get_option(GettableSocketOption& option) const
+ {
+ boost::system::error_code ec;
+ impl_.get_service().get_option(impl_.get_implementation(), option, ec);
+ boost::asio::detail::throw_error(ec, "get_option");
+ }
+
+ /// Get an option from the acceptor.
+ /**
+ * This function is used to get the current value of an option on the
+ * acceptor.
+ *
+ * @param option The option value to be obtained from the acceptor.
+ *
+ * @param ec Set to indicate what error occurred, if any.
+ *
+ * @sa GettableSocketOption @n
+ * boost::asio::socket_base::reuse_address
+ *
+ * @par Example
+ * Getting the value of the SOL_SOCKET/SO_REUSEADDR option:
+ * @code
+ * boost::asio::ip::tcp::acceptor acceptor(my_context);
+ * ...
+ * boost::asio::ip::tcp::acceptor::reuse_address option;
+ * boost::system::error_code ec;
+ * acceptor.get_option(option, ec);
+ * if (ec)
+ * {
+ * // An error occurred.
+ * }
+ * bool is_set = option.get();
+ * @endcode
+ */
+ template <typename GettableSocketOption>
+ BOOST_ASIO_SYNC_OP_VOID get_option(GettableSocketOption& option,
+ boost::system::error_code& ec) const
+ {
+ impl_.get_service().get_option(impl_.get_implementation(), option, ec);
+ BOOST_ASIO_SYNC_OP_VOID_RETURN(ec);
+ }
+
+ /// Perform an IO control command on the acceptor.
+ /**
+ * This function is used to execute an IO control command on the acceptor.
+ *
+ * @param command The IO control command to be performed on the acceptor.
+ *
+ * @throws boost::system::system_error Thrown on failure.
+ *
+ * @sa IoControlCommand @n
+ * boost::asio::socket_base::non_blocking_io
+ *
+ * @par Example
+ * Getting the number of bytes ready to read:
+ * @code
+ * boost::asio::ip::tcp::acceptor acceptor(my_context);
+ * ...
+ * boost::asio::ip::tcp::acceptor::non_blocking_io command(true);
+ * socket.io_control(command);
+ * @endcode
+ */
+ template <typename IoControlCommand>
+ void io_control(IoControlCommand& command)
+ {
+ boost::system::error_code ec;
+ impl_.get_service().io_control(impl_.get_implementation(), command, ec);
+ boost::asio::detail::throw_error(ec, "io_control");
+ }
+
+ /// Perform an IO control command on the acceptor.
+ /**
+ * This function is used to execute an IO control command on the acceptor.
+ *
+ * @param command The IO control command to be performed on the acceptor.
+ *
+ * @param ec Set to indicate what error occurred, if any.
+ *
+ * @sa IoControlCommand @n
+ * boost::asio::socket_base::non_blocking_io
+ *
+ * @par Example
+ * Getting the number of bytes ready to read:
+ * @code
+ * boost::asio::ip::tcp::acceptor acceptor(my_context);
+ * ...
+ * boost::asio::ip::tcp::acceptor::non_blocking_io command(true);
+ * boost::system::error_code ec;
+ * socket.io_control(command, ec);
+ * if (ec)
+ * {
+ * // An error occurred.
+ * }
+ * @endcode
+ */
+ template <typename IoControlCommand>
+ BOOST_ASIO_SYNC_OP_VOID io_control(IoControlCommand& command,
+ boost::system::error_code& ec)
+ {
+ impl_.get_service().io_control(impl_.get_implementation(), command, ec);
+ BOOST_ASIO_SYNC_OP_VOID_RETURN(ec);
+ }
+
+ /// Gets the non-blocking mode of the acceptor.
+ /**
+ * @returns @c true if the acceptor's synchronous operations will fail with
+ * boost::asio::error::would_block if they are unable to perform the requested
+ * operation immediately. If @c false, synchronous operations will block
+ * until complete.
+ *
+ * @note The non-blocking mode has no effect on the behaviour of asynchronous
+ * operations. Asynchronous operations will never fail with the error
+ * boost::asio::error::would_block.
+ */
+ bool non_blocking() const
+ {
+ return impl_.get_service().non_blocking(impl_.get_implementation());
+ }
+
+ /// Sets the non-blocking mode of the acceptor.
+ /**
+ * @param mode If @c true, the acceptor's synchronous operations will fail
+ * with boost::asio::error::would_block if they are unable to perform the
+ * requested operation immediately. If @c false, synchronous operations will
+ * block until complete.
+ *
+ * @throws boost::system::system_error Thrown on failure.
+ *
+ * @note The non-blocking mode has no effect on the behaviour of asynchronous
+ * operations. Asynchronous operations will never fail with the error
+ * boost::asio::error::would_block.
+ */
+ void non_blocking(bool mode)
+ {
+ boost::system::error_code ec;
+ impl_.get_service().non_blocking(impl_.get_implementation(), mode, ec);
+ boost::asio::detail::throw_error(ec, "non_blocking");
+ }
+
+ /// Sets the non-blocking mode of the acceptor.
+ /**
+ * @param mode If @c true, the acceptor's synchronous operations will fail
+ * with boost::asio::error::would_block if they are unable to perform the
+ * requested operation immediately. If @c false, synchronous operations will
+ * block until complete.
+ *
+ * @param ec Set to indicate what error occurred, if any.
+ *
+ * @note The non-blocking mode has no effect on the behaviour of asynchronous
+ * operations. Asynchronous operations will never fail with the error
+ * boost::asio::error::would_block.
+ */
+ BOOST_ASIO_SYNC_OP_VOID non_blocking(
+ bool mode, boost::system::error_code& ec)
+ {
+ impl_.get_service().non_blocking(impl_.get_implementation(), mode, ec);
+ BOOST_ASIO_SYNC_OP_VOID_RETURN(ec);
+ }
+
+ /// Gets the non-blocking mode of the native acceptor implementation.
+ /**
+ * This function is used to retrieve the non-blocking mode of the underlying
+ * native acceptor. This mode has no effect on the behaviour of the acceptor
+ * object's synchronous operations.
+ *
+ * @returns @c true if the underlying acceptor is in non-blocking mode and
+ * direct system calls may fail with boost::asio::error::would_block (or the
+ * equivalent system error).
+ *
+ * @note The current non-blocking mode is cached by the acceptor object.
+ * Consequently, the return value may be incorrect if the non-blocking mode
+ * was set directly on the native acceptor.
+ */
+ bool native_non_blocking() const
+ {
+ return impl_.get_service().native_non_blocking(impl_.get_implementation());
+ }
+
+ /// Sets the non-blocking mode of the native acceptor implementation.
+ /**
+ * This function is used to modify the non-blocking mode of the underlying
+ * native acceptor. It has no effect on the behaviour of the acceptor object's
+ * synchronous operations.
+ *
+ * @param mode If @c true, the underlying acceptor is put into non-blocking
+ * mode and direct system calls may fail with boost::asio::error::would_block
+ * (or the equivalent system error).
+ *
+ * @throws boost::system::system_error Thrown on failure. If the @c mode is
+ * @c false, but the current value of @c non_blocking() is @c true, this
+ * function fails with boost::asio::error::invalid_argument, as the
+ * combination does not make sense.
+ */
+ void native_non_blocking(bool mode)
+ {
+ boost::system::error_code ec;
+ impl_.get_service().native_non_blocking(
+ impl_.get_implementation(), mode, ec);
+ boost::asio::detail::throw_error(ec, "native_non_blocking");
+ }
+
+ /// Sets the non-blocking mode of the native acceptor implementation.
+ /**
+ * This function is used to modify the non-blocking mode of the underlying
+ * native acceptor. It has no effect on the behaviour of the acceptor object's
+ * synchronous operations.
+ *
+ * @param mode If @c true, the underlying acceptor is put into non-blocking
+ * mode and direct system calls may fail with boost::asio::error::would_block
+ * (or the equivalent system error).
+ *
+ * @param ec Set to indicate what error occurred, if any. If the @c mode is
+ * @c false, but the current value of @c non_blocking() is @c true, this
+ * function fails with boost::asio::error::invalid_argument, as the
+ * combination does not make sense.
+ */
+ BOOST_ASIO_SYNC_OP_VOID native_non_blocking(
+ bool mode, boost::system::error_code& ec)
+ {
+ impl_.get_service().native_non_blocking(
+ impl_.get_implementation(), mode, ec);
+ BOOST_ASIO_SYNC_OP_VOID_RETURN(ec);
+ }
+
+ /// Get the local endpoint of the acceptor.
+ /**
+ * This function is used to obtain the locally bound endpoint of the acceptor.
+ *
+ * @returns An object that represents the local endpoint of the acceptor.
+ *
+ * @throws boost::system::system_error Thrown on failure.
+ *
+ * @par Example
+ * @code
+ * boost::asio::ip::tcp::acceptor acceptor(my_context);
+ * ...
+ * boost::asio::ip::tcp::endpoint endpoint = acceptor.local_endpoint();
+ * @endcode
+ */
+ endpoint_type local_endpoint() const
+ {
+ boost::system::error_code ec;
+ endpoint_type ep = impl_.get_service().local_endpoint(
+ impl_.get_implementation(), ec);
+ boost::asio::detail::throw_error(ec, "local_endpoint");
+ return ep;
+ }
+
+ /// Get the local endpoint of the acceptor.
+ /**
+ * This function is used to obtain the locally bound endpoint of the acceptor.
+ *
+ * @param ec Set to indicate what error occurred, if any.
+ *
+ * @returns An object that represents the local endpoint of the acceptor.
+ * Returns a default-constructed endpoint object if an error occurred and the
+ * error handler did not throw an exception.
+ *
+ * @par Example
+ * @code
+ * boost::asio::ip::tcp::acceptor acceptor(my_context);
+ * ...
+ * boost::system::error_code ec;
+ * boost::asio::ip::tcp::endpoint endpoint = acceptor.local_endpoint(ec);
+ * if (ec)
+ * {
+ * // An error occurred.
+ * }
+ * @endcode
+ */
+ endpoint_type local_endpoint(boost::system::error_code& ec) const
+ {
+ return impl_.get_service().local_endpoint(impl_.get_implementation(), ec);
+ }
+
+ /// Wait for the acceptor to become ready to read, ready to write, or to have
+ /// pending error conditions.
+ /**
+ * This function is used to perform a blocking wait for an acceptor to enter
+ * a ready to read, write or error condition state.
+ *
+ * @param w Specifies the desired acceptor state.
+ *
+ * @par Example
+ * Waiting for an acceptor to become readable.
+ * @code
+ * boost::asio::ip::tcp::acceptor acceptor(my_context);
+ * ...
+ * acceptor.wait(boost::asio::ip::tcp::acceptor::wait_read);
+ * @endcode
+ */
+ void wait(wait_type w)
+ {
+ boost::system::error_code ec;
+ impl_.get_service().wait(impl_.get_implementation(), w, ec);
+ boost::asio::detail::throw_error(ec, "wait");
+ }
+
+ /// Wait for the acceptor to become ready to read, ready to write, or to have
+ /// pending error conditions.
+ /**
+ * This function is used to perform a blocking wait for an acceptor to enter
+ * a ready to read, write or error condition state.
+ *
+ * @param w Specifies the desired acceptor state.
+ *
+ * @param ec Set to indicate what error occurred, if any.
+ *
+ * @par Example
+ * Waiting for an acceptor to become readable.
+ * @code
+ * boost::asio::ip::tcp::acceptor acceptor(my_context);
+ * ...
+ * boost::system::error_code ec;
+ * acceptor.wait(boost::asio::ip::tcp::acceptor::wait_read, ec);
+ * @endcode
+ */
+ BOOST_ASIO_SYNC_OP_VOID wait(wait_type w, boost::system::error_code& ec)
+ {
+ impl_.get_service().wait(impl_.get_implementation(), w, ec);
+ BOOST_ASIO_SYNC_OP_VOID_RETURN(ec);
+ }
+
+ /// Asynchronously wait for the acceptor to become ready to read, ready to
+ /// write, or to have pending error conditions.
+ /**
+ * This function is used to perform an asynchronous wait for an acceptor to
+ * enter a ready to read, write or error condition state.
+ *
+ * @param w Specifies the desired acceptor state.
+ *
+ * @param handler The handler to be called when the wait operation completes.
+ * Copies will be made of the handler as required. The function signature of
+ * the handler must be:
+ * @code void handler(
+ * const boost::system::error_code& error // Result of operation
+ * ); @endcode
+ * Regardless of whether the asynchronous operation completes immediately or
+ * not, the handler will not be invoked from within this function. On
+ * immediate completion, invocation of the handler will be performed in a
+ * manner equivalent to using boost::asio::post().
+ *
+ * @par Example
+ * @code
+ * void wait_handler(const boost::system::error_code& error)
+ * {
+ * if (!error)
+ * {
+ * // Wait succeeded.
+ * }
+ * }
+ *
+ * ...
+ *
+ * boost::asio::ip::tcp::acceptor acceptor(my_context);
+ * ...
+ * acceptor.async_wait(
+ * boost::asio::ip::tcp::acceptor::wait_read,
+ * wait_handler);
+ * @endcode
+ */
+ template <typename WaitHandler>
+ BOOST_ASIO_INITFN_RESULT_TYPE(WaitHandler,
+ void (boost::system::error_code))
+ async_wait(wait_type w, BOOST_ASIO_MOVE_ARG(WaitHandler) handler)
+ {
+ return async_initiate<WaitHandler, void (boost::system::error_code)>(
+ initiate_async_wait(), handler, this, w);
+ }
+
+#if !defined(BOOST_ASIO_NO_EXTENSIONS)
+ /// Accept a new connection.
+ /**
+ * This function is used to accept a new connection from a peer into the
+ * given socket. The function call will block until a new connection has been
+ * accepted successfully or an error occurs.
+ *
+ * @param peer The socket into which the new connection will be accepted.
+ *
+ * @throws boost::system::system_error Thrown on failure.
+ *
+ * @par Example
+ * @code
+ * boost::asio::ip::tcp::acceptor acceptor(my_context);
+ * ...
+ * boost::asio::ip::tcp::socket socket(my_context);
+ * acceptor.accept(socket);
+ * @endcode
+ */
+ template <typename Protocol1, typename Executor1>
+ void accept(basic_socket_ext_local<Protocol1, Executor1>& peer,
+ typename enable_if<
+ is_convertible<Protocol, Protocol1>::value
+ >::type* = 0)
+ {
+ boost::system::error_code ec;
+ impl_.get_service().accept(impl_.get_implementation(),
+ peer, static_cast<endpoint_type*>(0), ec);
+ boost::asio::detail::throw_error(ec, "accept");
+ }
+
+ /// Accept a new connection.
+ /**
+ * This function is used to accept a new connection from a peer into the
+ * given socket. The function call will block until a new connection has been
+ * accepted successfully or an error occurs.
+ *
+ * @param peer The socket into which the new connection will be accepted.
+ *
+ * @param ec Set to indicate what error occurred, if any.
+ *
+ * @par Example
+ * @code
+ * boost::asio::ip::tcp::acceptor acceptor(my_context);
+ * ...
+ * boost::asio::ip::tcp::socket socket(my_context);
+ * boost::system::error_code ec;
+ * acceptor.accept(socket, ec);
+ * if (ec)
+ * {
+ * // An error occurred.
+ * }
+ * @endcode
+ */
+ template <typename Protocol1, typename Executor1>
+ BOOST_ASIO_SYNC_OP_VOID accept(
+ basic_socket_ext_local<Protocol1, Executor1>& peer, boost::system::error_code& ec,
+ typename enable_if<
+ is_convertible<Protocol, Protocol1>::value
+ >::type* = 0)
+ {
+ impl_.get_service().accept(impl_.get_implementation(),
+ peer, static_cast<endpoint_type*>(0), ec);
+ BOOST_ASIO_SYNC_OP_VOID_RETURN(ec);
+ }
+
+ /// Start an asynchronous accept.
+ /**
+ * This function is used to asynchronously accept a new connection into a
+ * socket. The function call always returns immediately.
+ *
+ * @param peer The socket into which the new connection will be accepted.
+ * Ownership of the peer object is retained by the caller, which must
+ * guarantee that it is valid until the handler is called.
+ *
+ * @param handler The handler to be called when the accept operation
+ * completes. Copies will be made of the handler as required. The function
+ * signature of the handler must be:
+ * @code void handler(
+ * const boost::system::error_code& error // Result of operation.
+ * ); @endcode
+ * Regardless of whether the asynchronous operation completes immediately or
+ * not, the handler will not be invoked from within this function. On
+ * immediate completion, invocation of the handler will be performed in a
+ * manner equivalent to using boost::asio::post().
+ *
+ * @par Example
+ * @code
+ * void accept_handler(const boost::system::error_code& error)
+ * {
+ * if (!error)
+ * {
+ * // Accept succeeded.
+ * }
+ * }
+ *
+ * ...
+ *
+ * boost::asio::ip::tcp::acceptor acceptor(my_context);
+ * ...
+ * boost::asio::ip::tcp::socket socket(my_context);
+ * acceptor.async_accept(socket, accept_handler);
+ * @endcode
+ */
+ template <typename Protocol1, typename Executor1, typename AcceptHandler>
+ BOOST_ASIO_INITFN_RESULT_TYPE(AcceptHandler,
+ void (boost::system::error_code))
+ async_accept(basic_socket_ext_local<Protocol1, Executor1>& peer,
+ BOOST_ASIO_MOVE_ARG(AcceptHandler) handler,
+ typename enable_if<
+ is_convertible<Protocol, Protocol1>::value
+ >::type* = 0)
+ {
+ return async_initiate<AcceptHandler, void (boost::system::error_code)>(
+ initiate_async_accept(), handler, this,
+ &peer, static_cast<endpoint_type*>(0));
+ }
+
+ /// Accept a new connection and obtain the endpoint of the peer
+ /**
+ * This function is used to accept a new connection from a peer into the
+ * given socket, and additionally provide the endpoint of the remote peer.
+ * The function call will block until a new connection has been accepted
+ * successfully or an error occurs.
+ *
+ * @param peer The socket into which the new connection will be accepted.
+ *
+ * @param peer_endpoint An endpoint object which will receive the endpoint of
+ * the remote peer.
+ *
+ * @throws boost::system::system_error Thrown on failure.
+ *
+ * @par Example
+ * @code
+ * boost::asio::ip::tcp::acceptor acceptor(my_context);
+ * ...
+ * boost::asio::ip::tcp::socket socket(my_context);
+ * boost::asio::ip::tcp::endpoint endpoint;
+ * acceptor.accept(socket, endpoint);
+ * @endcode
+ */
+ template <typename Executor1>
+ void accept(basic_socket_ext_local<protocol_type, Executor1>& peer,
+ endpoint_type& peer_endpoint)
+ {
+ boost::system::error_code ec;
+ impl_.get_service().accept(impl_.get_implementation(),
+ peer, &peer_endpoint, ec);
+ boost::asio::detail::throw_error(ec, "accept");
+ }
+
+ /// Accept a new connection and obtain the endpoint of the peer
+ /**
+ * This function is used to accept a new connection from a peer into the
+ * given socket, and additionally provide the endpoint of the remote peer.
+ * The function call will block until a new connection has been accepted
+ * successfully or an error occurs.
+ *
+ * @param peer The socket into which the new connection will be accepted.
+ *
+ * @param peer_endpoint An endpoint object which will receive the endpoint of
+ * the remote peer.
+ *
+ * @param ec Set to indicate what error occurred, if any.
+ *
+ * @par Example
+ * @code
+ * boost::asio::ip::tcp::acceptor acceptor(my_context);
+ * ...
+ * boost::asio::ip::tcp::socket socket(my_context);
+ * boost::asio::ip::tcp::endpoint endpoint;
+ * boost::system::error_code ec;
+ * acceptor.accept(socket, endpoint, ec);
+ * if (ec)
+ * {
+ * // An error occurred.
+ * }
+ * @endcode
+ */
+ template <typename Executor1>
+ BOOST_ASIO_SYNC_OP_VOID accept(basic_socket_ext_local<protocol_type, Executor1>& peer,
+ endpoint_type& peer_endpoint, boost::system::error_code& ec)
+ {
+ impl_.get_service().accept(
+ impl_.get_implementation(), peer, &peer_endpoint, ec);
+ BOOST_ASIO_SYNC_OP_VOID_RETURN(ec);
+ }
+
+ /// Start an asynchronous accept.
+ /**
+ * This function is used to asynchronously accept a new connection into a
+ * socket, and additionally obtain the endpoint of the remote peer. The
+ * function call always returns immediately.
+ *
+ * @param peer The socket into which the new connection will be accepted.
+ * Ownership of the peer object is retained by the caller, which must
+ * guarantee that it is valid until the handler is called.
+ *
+ * @param peer_endpoint An endpoint object into which the endpoint of the
+ * remote peer will be written. Ownership of the peer_endpoint object is
+ * retained by the caller, which must guarantee that it is valid until the
+ * handler is called.
+ *
+ * @param handler The handler to be called when the accept operation
+ * completes. Copies will be made of the handler as required. The function
+ * signature of the handler must be:
+ * @code void handler(
+ * const boost::system::error_code& error // Result of operation.
+ * ); @endcode
+ * Regardless of whether the asynchronous operation completes immediately or
+ * not, the handler will not be invoked from within this function. On
+ * immediate completion, invocation of the handler will be performed in a
+ * manner equivalent to using boost::asio::post().
+ */
+ template <typename Executor1, typename AcceptHandler>
+ BOOST_ASIO_INITFN_RESULT_TYPE(AcceptHandler,
+ void (boost::system::error_code))
+ async_accept(basic_socket_ext_local<protocol_type, Executor1>& peer,
+ endpoint_type& peer_endpoint, BOOST_ASIO_MOVE_ARG(AcceptHandler) handler)
+ {
+ return async_initiate<AcceptHandler, void (boost::system::error_code)>(
+ initiate_async_accept(), handler, this, &peer, &peer_endpoint);
+ }
+#endif // !defined(BOOST_ASIO_NO_EXTENSIONS)
+
+#if defined(BOOST_ASIO_HAS_MOVE) || defined(GENERATING_DOCUMENTATION)
+ /// Accept a new connection.
+ /**
+ * This function is used to accept a new connection from a peer. The function
+ * call will block until a new connection has been accepted successfully or
+ * an error occurs.
+ *
+ * This overload requires that the Protocol template parameter satisfy the
+ * AcceptableProtocol type requirements.
+ *
+ * @returns A socket object representing the newly accepted connection.
+ *
+ * @throws boost::system::system_error Thrown on failure.
+ *
+ * @par Example
+ * @code
+ * boost::asio::ip::tcp::acceptor acceptor(my_context);
+ * ...
+ * boost::asio::ip::tcp::socket socket(acceptor.accept());
+ * @endcode
+ */
+ typename Protocol::socket accept()
+ {
+ boost::system::error_code ec;
+ typename Protocol::socket peer(impl_.get_executor());
+ impl_.get_service().accept(impl_.get_implementation(), peer, 0, ec);
+ boost::asio::detail::throw_error(ec, "accept");
+ return peer;
+ }
+
+ /// Accept a new connection.
+ /**
+ * This function is used to accept a new connection from a peer. The function
+ * call will block until a new connection has been accepted successfully or
+ * an error occurs.
+ *
+ * This overload requires that the Protocol template parameter satisfy the
+ * AcceptableProtocol type requirements.
+ *
+ * @param ec Set to indicate what error occurred, if any.
+ *
+ * @returns On success, a socket object representing the newly accepted
+ * connection. On error, a socket object where is_open() is false.
+ *
+ * @par Example
+ * @code
+ * boost::asio::ip::tcp::acceptor acceptor(my_context);
+ * ...
+ * boost::asio::ip::tcp::socket socket(acceptor.accept(ec));
+ * if (ec)
+ * {
+ * // An error occurred.
+ * }
+ * @endcode
+ */
+ typename Protocol::socket accept(boost::system::error_code& ec)
+ {
+ typename Protocol::socket peer(impl_.get_executor());
+ impl_.get_service().accept(impl_.get_implementation(), peer, 0, ec);
+ return peer;
+ }
+
+ /// Start an asynchronous accept.
+ /**
+ * This function is used to asynchronously accept a new connection. The
+ * function call always returns immediately.
+ *
+ * This overload requires that the Protocol template parameter satisfy the
+ * AcceptableProtocol type requirements.
+ *
+ * @param handler The handler to be called when the accept operation
+ * completes. Copies will be made of the handler as required. The function
+ * signature of the handler must be:
+ * @code void handler(
+ * const boost::system::error_code& error, // Result of operation.
+ * typename Protocol::socket peer // On success, the newly accepted socket.
+ * ); @endcode
+ * Regardless of whether the asynchronous operation completes immediately or
+ * not, the handler will not be invoked from within this function. On
+ * immediate completion, invocation of the handler will be performed in a
+ * manner equivalent to using boost::asio::post().
+ *
+ * @par Example
+ * @code
+ * void accept_handler(const boost::system::error_code& error,
+ * boost::asio::ip::tcp::socket peer)
+ * {
+ * if (!error)
+ * {
+ * // Accept succeeded.
+ * }
+ * }
+ *
+ * ...
+ *
+ * boost::asio::ip::tcp::acceptor acceptor(my_context);
+ * ...
+ * acceptor.async_accept(accept_handler);
+ * @endcode
+ */
+ template <typename MoveAcceptHandler>
+ BOOST_ASIO_INITFN_RESULT_TYPE(MoveAcceptHandler,
+ void (boost::system::error_code, typename Protocol::socket))
+ async_accept(BOOST_ASIO_MOVE_ARG(MoveAcceptHandler) handler)
+ {
+ return async_initiate<MoveAcceptHandler,
+ void (boost::system::error_code, typename Protocol::socket)>(
+ initiate_async_move_accept(), handler, this,
+ impl_.get_executor(), static_cast<endpoint_type*>(0),
+ static_cast<typename Protocol::socket*>(0));
+ }
+
+ /// Accept a new connection.
+ /**
+ * This function is used to accept a new connection from a peer. The function
+ * call will block until a new connection has been accepted successfully or
+ * an error occurs.
+ *
+ * This overload requires that the Protocol template parameter satisfy the
+ * AcceptableProtocol type requirements.
+ *
+ * @param ex The I/O executor object to be used for the newly
+ * accepted socket.
+ *
+ * @returns A socket object representing the newly accepted connection.
+ *
+ * @throws boost::system::system_error Thrown on failure.
+ *
+ * @par Example
+ * @code
+ * boost::asio::ip::tcp::acceptor acceptor(my_context);
+ * ...
+ * boost::asio::ip::tcp::socket socket(acceptor.accept());
+ * @endcode
+ */
+ template <typename Executor1>
+ typename Protocol::socket::template rebind_executor<Executor1>::other
+ accept(const Executor1& ex,
+ typename enable_if<
+ is_executor<Executor1>::value
+ >::type* = 0)
+ {
+ boost::system::error_code ec;
+ typename Protocol::socket::template
+ rebind_executor<Executor1>::other peer(ex);
+ impl_.get_service().accept(impl_.get_implementation(), peer, 0, ec);
+ boost::asio::detail::throw_error(ec, "accept");
+ return peer;
+ }
+
+ /// Accept a new connection.
+ /**
+ * This function is used to accept a new connection from a peer. The function
+ * call will block until a new connection has been accepted successfully or
+ * an error occurs.
+ *
+ * This overload requires that the Protocol template parameter satisfy the
+ * AcceptableProtocol type requirements.
+ *
+ * @param context The I/O execution context object to be used for the newly
+ * accepted socket.
+ *
+ * @returns A socket object representing the newly accepted connection.
+ *
+ * @throws boost::system::system_error Thrown on failure.
+ *
+ * @par Example
+ * @code
+ * boost::asio::ip::tcp::acceptor acceptor(my_context);
+ * ...
+ * boost::asio::ip::tcp::socket socket(acceptor.accept());
+ * @endcode
+ */
+ template <typename ExecutionContext>
+ typename Protocol::socket::template rebind_executor<
+ typename ExecutionContext::executor_type>::other
+ accept(ExecutionContext& context,
+ typename enable_if<
+ is_convertible<ExecutionContext&, execution_context&>::value
+ >::type* = 0)
+ {
+ boost::system::error_code ec;
+ typename Protocol::socket::template rebind_executor<
+ typename ExecutionContext::executor_type>::other peer(context);
+ impl_.get_service().accept(impl_.get_implementation(), peer, 0, ec);
+ boost::asio::detail::throw_error(ec, "accept");
+ return peer;
+ }
+
+ /// Accept a new connection.
+ /**
+ * This function is used to accept a new connection from a peer. The function
+ * call will block until a new connection has been accepted successfully or
+ * an error occurs.
+ *
+ * This overload requires that the Protocol template parameter satisfy the
+ * AcceptableProtocol type requirements.
+ *
+ * @param ex The I/O executor object to be used for the newly accepted
+ * socket.
+ *
+ * @param ec Set to indicate what error occurred, if any.
+ *
+ * @returns On success, a socket object representing the newly accepted
+ * connection. On error, a socket object where is_open() is false.
+ *
+ * @par Example
+ * @code
+ * boost::asio::ip::tcp::acceptor acceptor(my_context);
+ * ...
+ * boost::asio::ip::tcp::socket socket(acceptor.accept(my_context2, ec));
+ * if (ec)
+ * {
+ * // An error occurred.
+ * }
+ * @endcode
+ */
+ template <typename Executor1>
+ typename Protocol::socket::template rebind_executor<Executor1>::other
+ accept(const Executor1& ex, boost::system::error_code& ec,
+ typename enable_if<
+ is_executor<Executor1>::value
+ >::type* = 0)
+ {
+ typename Protocol::socket::template
+ rebind_executor<Executor1>::other peer(ex);
+ impl_.get_service().accept(impl_.get_implementation(), peer, 0, ec);
+ return peer;
+ }
+
+ /// Accept a new connection.
+ /**
+ * This function is used to accept a new connection from a peer. The function
+ * call will block until a new connection has been accepted successfully or
+ * an error occurs.
+ *
+ * This overload requires that the Protocol template parameter satisfy the
+ * AcceptableProtocol type requirements.
+ *
+ * @param context The I/O execution context object to be used for the newly
+ * accepted socket.
+ *
+ * @param ec Set to indicate what error occurred, if any.
+ *
+ * @returns On success, a socket object representing the newly accepted
+ * connection. On error, a socket object where is_open() is false.
+ *
+ * @par Example
+ * @code
+ * boost::asio::ip::tcp::acceptor acceptor(my_context);
+ * ...
+ * boost::asio::ip::tcp::socket socket(acceptor.accept(my_context2, ec));
+ * if (ec)
+ * {
+ * // An error occurred.
+ * }
+ * @endcode
+ */
+ template <typename ExecutionContext>
+ typename Protocol::socket::template rebind_executor<
+ typename ExecutionContext::executor_type>::other
+ accept(ExecutionContext& context, boost::system::error_code& ec,
+ typename enable_if<
+ is_convertible<ExecutionContext&, execution_context&>::value
+ >::type* = 0)
+ {
+ typename Protocol::socket::template rebind_executor<
+ typename ExecutionContext::executor_type>::other peer(context);
+ impl_.get_service().accept(impl_.get_implementation(), peer, 0, ec);
+ return peer;
+ }
+
+ /// Start an asynchronous accept.
+ /**
+ * This function is used to asynchronously accept a new connection. The
+ * function call always returns immediately.
+ *
+ * This overload requires that the Protocol template parameter satisfy the
+ * AcceptableProtocol type requirements.
+ *
+ * @param ex The I/O executor object to be used for the newly accepted
+ * socket.
+ *
+ * @param handler The handler to be called when the accept operation
+ * completes. Copies will be made of the handler as required. The function
+ * signature of the handler must be:
+ * @code void handler(
+ * const boost::system::error_code& error, // Result of operation.
+ * typename Protocol::socket::template rebind_executor<
+ * Executor1>::other peer // On success, the newly accepted socket.
+ * ); @endcode
+ * Regardless of whether the asynchronous operation completes immediately or
+ * not, the handler will not be invoked from within this function. On
+ * immediate completion, invocation of the handler will be performed in a
+ * manner equivalent to using boost::asio::post().
+ *
+ * @par Example
+ * @code
+ * void accept_handler(const boost::system::error_code& error,
+ * boost::asio::ip::tcp::socket peer)
+ * {
+ * if (!error)
+ * {
+ * // Accept succeeded.
+ * }
+ * }
+ *
+ * ...
+ *
+ * boost::asio::ip::tcp::acceptor acceptor(my_context);
+ * ...
+ * acceptor.async_accept(my_context2, accept_handler);
+ * @endcode
+ */
+ template <typename Executor1, typename MoveAcceptHandler>
+ BOOST_ASIO_INITFN_RESULT_TYPE(MoveAcceptHandler,
+ void (boost::system::error_code,
+ typename Protocol::socket::template rebind_executor<
+ Executor1>::other))
+ async_accept(const Executor1& ex,
+ BOOST_ASIO_MOVE_ARG(MoveAcceptHandler) handler,
+ typename enable_if<
+ is_executor<Executor1>::value
+ >::type* = 0)
+ {
+ typedef typename Protocol::socket::template rebind_executor<
+ Executor1>::other other_socket_type;
+
+ return async_initiate<MoveAcceptHandler,
+ void (boost::system::error_code, other_socket_type)>(
+ initiate_async_move_accept(), handler, this,
+ ex, static_cast<endpoint_type*>(0),
+ static_cast<other_socket_type*>(0));
+ }
+
+ /// Start an asynchronous accept.
+ /**
+ * This function is used to asynchronously accept a new connection. The
+ * function call always returns immediately.
+ *
+ * This overload requires that the Protocol template parameter satisfy the
+ * AcceptableProtocol type requirements.
+ *
+ * @param context The I/O execution context object to be used for the newly
+ * accepted socket.
+ *
+ * @param handler The handler to be called when the accept operation
+ * completes. Copies will be made of the handler as required. The function
+ * signature of the handler must be:
+ * @code void handler(
+ * const boost::system::error_code& error, // Result of operation.
+ * typename Protocol::socket::template rebind_executor<
+ * typename ExecutionContext::executor_type>::other peer
+ * // On success, the newly accepted socket.
+ * ); @endcode
+ * Regardless of whether the asynchronous operation completes immediately or
+ * not, the handler will not be invoked from within this function. On
+ * immediate completion, invocation of the handler will be performed in a
+ * manner equivalent to using boost::asio::post().
+ *
+ * @par Example
+ * @code
+ * void accept_handler(const boost::system::error_code& error,
+ * boost::asio::ip::tcp::socket peer)
+ * {
+ * if (!error)
+ * {
+ * // Accept succeeded.
+ * }
+ * }
+ *
+ * ...
+ *
+ * boost::asio::ip::tcp::acceptor acceptor(my_context);
+ * ...
+ * acceptor.async_accept(my_context2, accept_handler);
+ * @endcode
+ */
+ template <typename ExecutionContext, typename MoveAcceptHandler>
+ BOOST_ASIO_INITFN_RESULT_TYPE(MoveAcceptHandler,
+ void (boost::system::error_code,
+ typename Protocol::socket::template rebind_executor<
+ typename ExecutionContext::executor_type>::other))
+ async_accept(ExecutionContext& context,
+ BOOST_ASIO_MOVE_ARG(MoveAcceptHandler) handler,
+ typename enable_if<
+ is_convertible<ExecutionContext&, execution_context&>::value
+ >::type* = 0)
+ {
+ typedef typename Protocol::socket::template rebind_executor<
+ typename ExecutionContext::executor_type>::other other_socket_type;
+
+ return async_initiate<MoveAcceptHandler,
+ void (boost::system::error_code, other_socket_type)>(
+ initiate_async_move_accept(), handler, this,
+ context.get_executor(), static_cast<endpoint_type*>(0),
+ static_cast<other_socket_type*>(0));
+ }
+
+ /// Accept a new connection.
+ /**
+ * This function is used to accept a new connection from a peer. The function
+ * call will block until a new connection has been accepted successfully or
+ * an error occurs.
+ *
+ * This overload requires that the Protocol template parameter satisfy the
+ * AcceptableProtocol type requirements.
+ *
+ * @param peer_endpoint An endpoint object into which the endpoint of the
+ * remote peer will be written.
+ *
+ * @returns A socket object representing the newly accepted connection.
+ *
+ * @throws boost::system::system_error Thrown on failure.
+ *
+ * @par Example
+ * @code
+ * boost::asio::ip::tcp::acceptor acceptor(my_context);
+ * ...
+ * boost::asio::ip::tcp::endpoint endpoint;
+ * boost::asio::ip::tcp::socket socket(acceptor.accept(endpoint));
+ * @endcode
+ */
+ typename Protocol::socket accept(endpoint_type& peer_endpoint)
+ {
+ boost::system::error_code ec;
+ typename Protocol::socket peer(impl_.get_executor());
+ impl_.get_service().accept(impl_.get_implementation(),
+ peer, &peer_endpoint, ec);
+ boost::asio::detail::throw_error(ec, "accept");
+ return peer;
+ }
+
+ /// Accept a new connection.
+ /**
+ * This function is used to accept a new connection from a peer. The function
+ * call will block until a new connection has been accepted successfully or
+ * an error occurs.
+ *
+ * This overload requires that the Protocol template parameter satisfy the
+ * AcceptableProtocol type requirements.
+ *
+ * @param peer_endpoint An endpoint object into which the endpoint of the
+ * remote peer will be written.
+ *
+ * @param ec Set to indicate what error occurred, if any.
+ *
+ * @returns On success, a socket object representing the newly accepted
+ * connection. On error, a socket object where is_open() is false.
+ *
+ * @par Example
+ * @code
+ * boost::asio::ip::tcp::acceptor acceptor(my_context);
+ * ...
+ * boost::asio::ip::tcp::endpoint endpoint;
+ * boost::asio::ip::tcp::socket socket(acceptor.accept(endpoint, ec));
+ * if (ec)
+ * {
+ * // An error occurred.
+ * }
+ * @endcode
+ */
+ typename Protocol::socket accept(
+ endpoint_type& peer_endpoint, boost::system::error_code& ec)
+ {
+ typename Protocol::socket peer(impl_.get_executor());
+ impl_.get_service().accept(impl_.get_implementation(),
+ peer, &peer_endpoint, ec);
+ return peer;
+ }
+
+ /// Start an asynchronous accept.
+ /**
+ * This function is used to asynchronously accept a new connection. The
+ * function call always returns immediately.
+ *
+ * This overload requires that the Protocol template parameter satisfy the
+ * AcceptableProtocol type requirements.
+ *
+ * @param peer_endpoint An endpoint object into which the endpoint of the
+ * remote peer will be written. Ownership of the peer_endpoint object is
+ * retained by the caller, which must guarantee that it is valid until the
+ * handler is called.
+ *
+ * @param handler The handler to be called when the accept operation
+ * completes. Copies will be made of the handler as required. The function
+ * signature of the handler must be:
+ * @code void handler(
+ * const boost::system::error_code& error, // Result of operation.
+ * typename Protocol::socket peer // On success, the newly accepted socket.
+ * ); @endcode
+ * Regardless of whether the asynchronous operation completes immediately or
+ * not, the handler will not be invoked from within this function. On
+ * immediate completion, invocation of the handler will be performed in a
+ * manner equivalent to using boost::asio::post().
+ *
+ * @par Example
+ * @code
+ * void accept_handler(const boost::system::error_code& error,
+ * boost::asio::ip::tcp::socket peer)
+ * {
+ * if (!error)
+ * {
+ * // Accept succeeded.
+ * }
+ * }
+ *
+ * ...
+ *
+ * boost::asio::ip::tcp::acceptor acceptor(my_context);
+ * ...
+ * boost::asio::ip::tcp::endpoint endpoint;
+ * acceptor.async_accept(endpoint, accept_handler);
+ * @endcode
+ */
+ template <typename MoveAcceptHandler>
+ BOOST_ASIO_INITFN_RESULT_TYPE(MoveAcceptHandler,
+ void (boost::system::error_code, typename Protocol::socket))
+ async_accept(endpoint_type& peer_endpoint,
+ BOOST_ASIO_MOVE_ARG(MoveAcceptHandler) handler)
+ {
+ return async_initiate<MoveAcceptHandler,
+ void (boost::system::error_code, typename Protocol::socket)>(
+ initiate_async_move_accept(), handler, this,
+ impl_.get_executor(), &peer_endpoint,
+ static_cast<typename Protocol::socket*>(0));
+ }
+
+ /// Accept a new connection.
+ /**
+ * This function is used to accept a new connection from a peer. The function
+ * call will block until a new connection has been accepted successfully or
+ * an error occurs.
+ *
+ * This overload requires that the Protocol template parameter satisfy the
+ * AcceptableProtocol type requirements.
+ *
+ * @param ex The I/O executor object to be used for the newly accepted
+ * socket.
+ *
+ * @param peer_endpoint An endpoint object into which the endpoint of the
+ * remote peer will be written.
+ *
+ * @returns A socket object representing the newly accepted connection.
+ *
+ * @throws boost::system::system_error Thrown on failure.
+ *
+ * @par Example
+ * @code
+ * boost::asio::ip::tcp::acceptor acceptor(my_context);
+ * ...
+ * boost::asio::ip::tcp::endpoint endpoint;
+ * boost::asio::ip::tcp::socket socket(
+ * acceptor.accept(my_context2, endpoint));
+ * @endcode
+ */
+ template <typename Executor1>
+ typename Protocol::socket::template rebind_executor<Executor1>::other
+ accept(const Executor1& ex, endpoint_type& peer_endpoint,
+ typename enable_if<
+ is_executor<Executor1>::value
+ >::type* = 0)
+ {
+ boost::system::error_code ec;
+ typename Protocol::socket::template
+ rebind_executor<Executor1>::other peer(ex);
+ impl_.get_service().accept(impl_.get_implementation(),
+ peer, &peer_endpoint, ec);
+ boost::asio::detail::throw_error(ec, "accept");
+ return peer;
+ }
+
+ /// Accept a new connection.
+ /**
+ * This function is used to accept a new connection from a peer. The function
+ * call will block until a new connection has been accepted successfully or
+ * an error occurs.
+ *
+ * This overload requires that the Protocol template parameter satisfy the
+ * AcceptableProtocol type requirements.
+ *
+ * @param context The I/O execution context object to be used for the newly
+ * accepted socket.
+ *
+ * @param peer_endpoint An endpoint object into which the endpoint of the
+ * remote peer will be written.
+ *
+ * @returns A socket object representing the newly accepted connection.
+ *
+ * @throws boost::system::system_error Thrown on failure.
+ *
+ * @par Example
+ * @code
+ * boost::asio::ip::tcp::acceptor acceptor(my_context);
+ * ...
+ * boost::asio::ip::tcp::endpoint endpoint;
+ * boost::asio::ip::tcp::socket socket(
+ * acceptor.accept(my_context2, endpoint));
+ * @endcode
+ */
+ template <typename ExecutionContext>
+ typename Protocol::socket::template rebind_executor<
+ typename ExecutionContext::executor_type>::other
+ accept(ExecutionContext& context, endpoint_type& peer_endpoint,
+ typename enable_if<
+ is_convertible<ExecutionContext&, execution_context&>::value
+ >::type* = 0)
+ {
+ boost::system::error_code ec;
+ typename Protocol::socket::template rebind_executor<
+ typename ExecutionContext::executor_type>::other peer(context);
+ impl_.get_service().accept(impl_.get_implementation(),
+ peer, &peer_endpoint, ec);
+ boost::asio::detail::throw_error(ec, "accept");
+ return peer;
+ }
+
+ /// Accept a new connection.
+ /**
+ * This function is used to accept a new connection from a peer. The function
+ * call will block until a new connection has been accepted successfully or
+ * an error occurs.
+ *
+ * This overload requires that the Protocol template parameter satisfy the
+ * AcceptableProtocol type requirements.
+ *
+ * @param ex The I/O executor object to be used for the newly accepted
+ * socket.
+ *
+ * @param peer_endpoint An endpoint object into which the endpoint of the
+ * remote peer will be written.
+ *
+ * @param ec Set to indicate what error occurred, if any.
+ *
+ * @returns On success, a socket object representing the newly accepted
+ * connection. On error, a socket object where is_open() is false.
+ *
+ * @par Example
+ * @code
+ * boost::asio::ip::tcp::acceptor acceptor(my_context);
+ * ...
+ * boost::asio::ip::tcp::endpoint endpoint;
+ * boost::asio::ip::tcp::socket socket(
+ * acceptor.accept(my_context2, endpoint, ec));
+ * if (ec)
+ * {
+ * // An error occurred.
+ * }
+ * @endcode
+ */
+ template <typename Executor1>
+ typename Protocol::socket::template rebind_executor<Executor1>::other
+ accept(const executor_type& ex,
+ endpoint_type& peer_endpoint, boost::system::error_code& ec,
+ typename enable_if<
+ is_executor<Executor1>::value
+ >::type* = 0)
+ {
+ typename Protocol::socket::template
+ rebind_executor<Executor1>::other peer(ex);
+ impl_.get_service().accept(impl_.get_implementation(),
+ peer, &peer_endpoint, ec);
+ return peer;
+ }
+
+ /// Accept a new connection.
+ /**
+ * This function is used to accept a new connection from a peer. The function
+ * call will block until a new connection has been accepted successfully or
+ * an error occurs.
+ *
+ * This overload requires that the Protocol template parameter satisfy the
+ * AcceptableProtocol type requirements.
+ *
+ * @param context The I/O execution context object to be used for the newly
+ * accepted socket.
+ *
+ * @param peer_endpoint An endpoint object into which the endpoint of the
+ * remote peer will be written.
+ *
+ * @param ec Set to indicate what error occurred, if any.
+ *
+ * @returns On success, a socket object representing the newly accepted
+ * connection. On error, a socket object where is_open() is false.
+ *
+ * @par Example
+ * @code
+ * boost::asio::ip::tcp::acceptor acceptor(my_context);
+ * ...
+ * boost::asio::ip::tcp::endpoint endpoint;
+ * boost::asio::ip::tcp::socket socket(
+ * acceptor.accept(my_context2, endpoint, ec));
+ * if (ec)
+ * {
+ * // An error occurred.
+ * }
+ * @endcode
+ */
+ template <typename ExecutionContext>
+ typename Protocol::socket::template rebind_executor<
+ typename ExecutionContext::executor_type>::other
+ accept(ExecutionContext& context,
+ endpoint_type& peer_endpoint, boost::system::error_code& ec,
+ typename enable_if<
+ is_convertible<ExecutionContext&, execution_context&>::value
+ >::type* = 0)
+ {
+ typename Protocol::socket::template rebind_executor<
+ typename ExecutionContext::executor_type>::other peer(context);
+ impl_.get_service().accept(impl_.get_implementation(),
+ peer, &peer_endpoint, ec);
+ return peer;
+ }
+
+ /// Start an asynchronous accept.
+ /**
+ * This function is used to asynchronously accept a new connection. The
+ * function call always returns immediately.
+ *
+ * This overload requires that the Protocol template parameter satisfy the
+ * AcceptableProtocol type requirements.
+ *
+ * @param ex The I/O executor object to be used for the newly accepted
+ * socket.
+ *
+ * @param peer_endpoint An endpoint object into which the endpoint of the
+ * remote peer will be written. Ownership of the peer_endpoint object is
+ * retained by the caller, which must guarantee that it is valid until the
+ * handler is called.
+ *
+ * @param handler The handler to be called when the accept operation
+ * completes. Copies will be made of the handler as required. The function
+ * signature of the handler must be:
+ * @code void handler(
+ * const boost::system::error_code& error, // Result of operation.
+ * typename Protocol::socket::template rebind_executor<
+ * Executor1>::other peer // On success, the newly accepted socket.
+ * ); @endcode
+ * Regardless of whether the asynchronous operation completes immediately or
+ * not, the handler will not be invoked from within this function. On
+ * immediate completion, invocation of the handler will be performed in a
+ * manner equivalent to using boost::asio::post().
+ *
+ * @par Example
+ * @code
+ * void accept_handler(const boost::system::error_code& error,
+ * boost::asio::ip::tcp::socket peer)
+ * {
+ * if (!error)
+ * {
+ * // Accept succeeded.
+ * }
+ * }
+ *
+ * ...
+ *
+ * boost::asio::ip::tcp::acceptor acceptor(my_context);
+ * ...
+ * boost::asio::ip::tcp::endpoint endpoint;
+ * acceptor.async_accept(my_context2, endpoint, accept_handler);
+ * @endcode
+ */
+ template <typename Executor1, typename MoveAcceptHandler>
+ BOOST_ASIO_INITFN_RESULT_TYPE(MoveAcceptHandler,
+ void (boost::system::error_code,
+ typename Protocol::socket::template rebind_executor<
+ Executor1>::other))
+ async_accept(const Executor1& ex, endpoint_type& peer_endpoint,
+ BOOST_ASIO_MOVE_ARG(MoveAcceptHandler) handler,
+ typename enable_if<
+ is_executor<Executor1>::value
+ >::type* = 0)
+ {
+ typedef typename Protocol::socket::template rebind_executor<
+ Executor1>::other other_socket_type;
+
+ return async_initiate<MoveAcceptHandler,
+ void (boost::system::error_code, other_socket_type)>(
+ initiate_async_move_accept(), handler, this,
+ ex, &peer_endpoint,
+ static_cast<other_socket_type*>(0));
+ }
+
+ /// Start an asynchronous accept.
+ /**
+ * This function is used to asynchronously accept a new connection. The
+ * function call always returns immediately.
+ *
+ * This overload requires that the Protocol template parameter satisfy the
+ * AcceptableProtocol type requirements.
+ *
+ * @param context The I/O execution context object to be used for the newly
+ * accepted socket.
+ *
+ * @param peer_endpoint An endpoint object into which the endpoint of the
+ * remote peer will be written. Ownership of the peer_endpoint object is
+ * retained by the caller, which must guarantee that it is valid until the
+ * handler is called.
+ *
+ * @param handler The handler to be called when the accept operation
+ * completes. Copies will be made of the handler as required. The function
+ * signature of the handler must be:
+ * @code void handler(
+ * const boost::system::error_code& error, // Result of operation.
+ * typename Protocol::socket::template rebind_executor<
+ * typename ExecutionContext::executor_type>::other peer
+ * // On success, the newly accepted socket.
+ * ); @endcode
+ * Regardless of whether the asynchronous operation completes immediately or
+ * not, the handler will not be invoked from within this function. On
+ * immediate completion, invocation of the handler will be performed in a
+ * manner equivalent to using boost::asio::post().
+ *
+ * @par Example
+ * @code
+ * void accept_handler(const boost::system::error_code& error,
+ * boost::asio::ip::tcp::socket peer)
+ * {
+ * if (!error)
+ * {
+ * // Accept succeeded.
+ * }
+ * }
+ *
+ * ...
+ *
+ * boost::asio::ip::tcp::acceptor acceptor(my_context);
+ * ...
+ * boost::asio::ip::tcp::endpoint endpoint;
+ * acceptor.async_accept(my_context2, endpoint, accept_handler);
+ * @endcode
+ */
+ template <typename ExecutionContext, typename MoveAcceptHandler>
+ BOOST_ASIO_INITFN_RESULT_TYPE(MoveAcceptHandler,
+ void (boost::system::error_code,
+ typename Protocol::socket::template rebind_executor<
+ typename ExecutionContext::executor_type>::other))
+ async_accept(ExecutionContext& context,
+ endpoint_type& peer_endpoint,
+ BOOST_ASIO_MOVE_ARG(MoveAcceptHandler) handler,
+ typename enable_if<
+ is_convertible<ExecutionContext&, execution_context&>::value
+ >::type* = 0)
+ {
+ typedef typename Protocol::socket::template rebind_executor<
+ typename ExecutionContext::executor_type>::other other_socket_type;
+
+ return async_initiate<MoveAcceptHandler,
+ void (boost::system::error_code, other_socket_type)>(
+ initiate_async_move_accept(), handler, this,
+ context.get_executor(), &peer_endpoint,
+ static_cast<other_socket_type*>(0));
+ }
+#endif // defined(BOOST_ASIO_HAS_MOVE) || defined(GENERATING_DOCUMENTATION)
+
+private:
+ // Disallow copying and assignment.
+ basic_socket_acceptor_ext(const basic_socket_acceptor_ext&) BOOST_ASIO_DELETED;
+ basic_socket_acceptor_ext& operator=(
+ const basic_socket_acceptor_ext&) BOOST_ASIO_DELETED;
+
+ struct initiate_async_wait
+ {
+ template <typename WaitHandler>
+ void operator()(BOOST_ASIO_MOVE_ARG(WaitHandler) handler,
+ basic_socket_acceptor_ext* self, wait_type w) const
+ {
+ // If you get an error on the following line it means that your handler
+ // does not meet the documented type requirements for a WaitHandler.
+ BOOST_ASIO_WAIT_HANDLER_CHECK(WaitHandler, handler) type_check;
+
+ detail::non_const_lvalue<WaitHandler> handler2(handler);
+ self->impl_.get_service().async_wait(
+ self->impl_.get_implementation(), w, handler2.value,
+ self->impl_.get_implementation_executor());
+ }
+ };
+
+ struct initiate_async_accept
+ {
+ template <typename AcceptHandler, typename Protocol1, typename Executor1>
+ void operator()(BOOST_ASIO_MOVE_ARG(AcceptHandler) handler,
+ basic_socket_acceptor_ext* self, basic_socket_ext_local<Protocol1, Executor1>* peer,
+ endpoint_type* peer_endpoint) const
+ {
+ // If you get an error on the following line it means that your handler
+ // does not meet the documented type requirements for a AcceptHandler.
+ BOOST_ASIO_ACCEPT_HANDLER_CHECK(AcceptHandler, handler) type_check;
+
+ detail::non_const_lvalue<AcceptHandler> handler2(handler);
+ self->impl_.get_service().async_accept(
+ self->impl_.get_implementation(), *peer, peer_endpoint,
+ handler2.value, self->impl_.get_executor());
+ }
+ };
+
+ struct initiate_async_move_accept
+ {
+ template <typename MoveAcceptHandler, typename Executor1, typename Socket>
+ void operator()(BOOST_ASIO_MOVE_ARG(MoveAcceptHandler) handler,
+ basic_socket_acceptor_ext* self, const Executor1& peer_ex,
+ endpoint_type* peer_endpoint, Socket*) const
+ {
+ // If you get an error on the following line it means that your handler
+ // does not meet the documented type requirements for a MoveAcceptHandler.
+ BOOST_ASIO_MOVE_ACCEPT_HANDLER_CHECK(
+ MoveAcceptHandler, handler, Socket) type_check;
+
+ detail::non_const_lvalue<MoveAcceptHandler> handler2(handler);
+ self->impl_.get_service().async_move_accept(
+ self->impl_.get_implementation(), peer_ex, peer_endpoint,
+ handler2.value, self->impl_.get_implementation_executor());
+ }
+ };
+
+#if defined(BOOST_ASIO_WINDOWS_RUNTIME)
+ detail::io_object_impl<
+ detail::null_socket_service<Protocol>, Executor> impl_;
+#elif defined(BOOST_ASIO_HAS_IOCP)
+ detail::io_object_impl<
+ detail::win_iocp_socket_service<Protocol>, Executor> impl_;
+#else
+ detail::io_object_impl<
+ detail::reactive_socket_service_ext_local<Protocol>, Executor> impl_;
+#endif
+};
+
+} // namespace asio
+} // namespace boost
+
+#include <boost/asio/detail/pop_options.hpp>
+
+#endif // BOOST_ASIO_BASIC_SOCKET_ACCEPTOR_EXT_HPP
diff --git a/implementation/helper/1.74/boost/asio/basic_socket_ext.hpp b/implementation/helper/1.74/boost/asio/basic_socket_ext.hpp
new file mode 100644
index 0000000..523f97a
--- /dev/null
+++ b/implementation/helper/1.74/boost/asio/basic_socket_ext.hpp
@@ -0,0 +1,1859 @@
+//
+// basic_socket_ext.hpp
+// ~~~~~~~~~~~~~~~~~~~~
+//
+// Copyright (c) 2003-2019 Christopher M. Kohlhoff (chris at kohlhoff dot com)
+// Copyright (c) 2018,2019 Bayerische Motoren Werke Aktiengesellschaft (BMW AG)
+//
+// Distributed under the Boost Software License, Version 1.0. (See accompanying
+// file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt)
+//
+
+#ifndef BOOST_ASIO_BASIC_SOCKET_EXT_HPP
+#define BOOST_ASIO_BASIC_SOCKET_EXT_HPP
+
+#if defined(_MSC_VER) && (_MSC_VER >= 1200)
+# pragma once
+#endif // defined(_MSC_VER) && (_MSC_VER >= 1200)
+
+#include <boost/asio/detail/config.hpp>
+#include <boost/asio/async_result.hpp>
+#include <boost/asio/detail/handler_type_requirements.hpp>
+#include <boost/asio/detail/io_object_impl.hpp>
+#include <boost/asio/detail/non_const_lvalue.hpp>
+#include <boost/asio/detail/throw_error.hpp>
+#include <boost/asio/detail/type_traits.hpp>
+#include <boost/asio/error.hpp>
+#include <boost/asio/execution_context.hpp>
+#include <boost/asio/executor.hpp>
+#include <boost/asio/post.hpp>
+#include <boost/asio/socket_base.hpp>
+
+#if defined(BOOST_ASIO_WINDOWS_RUNTIME)
+# include <boost/asio/detail/null_socket_service.hpp>
+#elif defined(BOOST_ASIO_HAS_IOCP)
+# include <boost/asio/detail/win_iocp_socket_service.hpp>
+#else
+# include <boost/asio/detail/reactive_socket_service_ext.hpp>
+#endif
+
+#if defined(BOOST_ASIO_HAS_MOVE)
+# include <utility>
+#endif // defined(BOOST_ASIO_HAS_MOVE)
+
+#include <boost/asio/detail/push_options.hpp>
+
+namespace boost {
+namespace asio {
+
+#if !defined(BOOST_ASIO_BASIC_SOCKET_EXT_FWD_DECL)
+#define BOOST_ASIO_BASIC_SOCKET_EXT_FWD_DECL
+
+// Forward declaration with defaulted arguments.
+template <typename Protocol, typename Executor = executor>
+class basic_socket_ext;
+
+#endif // !defined(BOOST_ASIO_BASIC_SOCKET_EXT_FWD_DECL)
+
+/// Provides socket functionality.
+/**
+ * The basic_socket class template provides functionality that is common to both
+ * stream-oriented and datagram-oriented sockets.
+ *
+ * @par Thread Safety
+ * @e Distinct @e objects: Safe.@n
+ * @e Shared @e objects: Unsafe.
+ */
+template <typename Protocol, typename Executor>
+class basic_socket_ext
+ : public socket_base
+{
+public:
+ /// The type of the executor associated with the object.
+ typedef Executor executor_type;
+
+ /// Rebinds the socket type to another executor.
+ template <typename Executor1>
+ struct rebind_executor
+ {
+ /// The socket type when rebound to the specified executor.
+ typedef basic_socket_ext<Protocol, Executor1> other;
+ };
+
+ /// The native representation of a socket.
+#if defined(GENERATING_DOCUMENTATION)
+ typedef implementation_defined native_handle_type;
+#elif defined(BOOST_ASIO_WINDOWS_RUNTIME)
+ typedef typename detail::null_socket_service<
+ Protocol>::native_handle_type native_handle_type;
+#elif defined(BOOST_ASIO_HAS_IOCP)
+ typedef typename detail::win_iocp_socket_service<
+ Protocol>::native_handle_type native_handle_type;
+#else
+ typedef typename detail::reactive_socket_service_ext<
+ Protocol>::native_handle_type native_handle_type;
+#endif
+
+ /// The protocol type.
+ typedef Protocol protocol_type;
+
+ /// The endpoint type.
+ typedef typename Protocol::endpoint endpoint_type;
+
+#if !defined(BOOST_ASIO_NO_EXTENSIONS)
+ /// A basic_socket is always the lowest layer.
+ typedef basic_socket_ext<Protocol, Executor> lowest_layer_type;
+#endif // !defined(BOOST_ASIO_NO_EXTENSIONS)
+
+ /// Construct a basic_socket without opening it.
+ /**
+ * This constructor creates a socket without opening it.
+ *
+ * @param ex The I/O executor that the socket will use, by default, to
+ * dispatch handlers for any asynchronous operations performed on the socket.
+ */
+ explicit basic_socket_ext(const executor_type& ex)
+ : impl_(ex)
+ {
+ }
+
+ /// Construct a basic_socket without opening it.
+ /**
+ * This constructor creates a socket without opening it.
+ *
+ * @param context An execution context which provides the I/O executor that
+ * the socket will use, by default, to dispatch handlers for any asynchronous
+ * operations performed on the socket.
+ */
+ template <typename ExecutionContext>
+ explicit basic_socket_ext(ExecutionContext& context,
+ typename enable_if<
+ is_convertible<ExecutionContext&, execution_context&>::value
+ >::type* = 0)
+ : impl_(context)
+ {
+ }
+
+ /// Construct and open a basic_socket.
+ /**
+ * This constructor creates and opens a socket.
+ *
+ * @param ex The I/O executor that the socket will use, by default, to
+ * dispatch handlers for any asynchronous operations performed on the socket.
+ *
+ * @param protocol An object specifying protocol parameters to be used.
+ *
+ * @throws boost::system::system_error Thrown on failure.
+ */
+ basic_socket_ext(const executor_type& ex, const protocol_type& protocol)
+ : impl_(ex)
+ {
+ boost::system::error_code ec;
+ impl_.get_service().open(impl_.get_implementation(), protocol, ec);
+ boost::asio::detail::throw_error(ec, "open");
+ }
+
+ /// Construct and open a basic_socket.
+ /**
+ * This constructor creates and opens a socket.
+ *
+ * @param context An execution context which provides the I/O executor that
+ * the socket will use, by default, to dispatch handlers for any asynchronous
+ * operations performed on the socket.
+ *
+ * @param protocol An object specifying protocol parameters to be used.
+ *
+ * @throws boost::system::system_error Thrown on failure.
+ */
+ template <typename ExecutionContext>
+ basic_socket_ext(ExecutionContext& context, const protocol_type& protocol,
+ typename enable_if<
+ is_convertible<ExecutionContext&, execution_context&>::value
+ >::type* = 0)
+ : impl_(context)
+ {
+ boost::system::error_code ec;
+ impl_.get_service().open(impl_.get_implementation(), protocol, ec);
+ boost::asio::detail::throw_error(ec, "open");
+ }
+
+ /// Construct a basic_socket, opening it and binding it to the given local
+ /// endpoint.
+ /**
+ * This constructor creates a socket and automatically opens it bound to the
+ * specified endpoint on the local machine. The protocol used is the protocol
+ * associated with the given endpoint.
+ *
+ * @param ex The I/O executor that the socket will use, by default, to
+ * dispatch handlers for any asynchronous operations performed on the socket.
+ *
+ * @param endpoint An endpoint on the local machine to which the socket will
+ * be bound.
+ *
+ * @throws boost::system::system_error Thrown on failure.
+ */
+ basic_socket_ext(const executor_type& ex, const endpoint_type& endpoint)
+ : impl_(ex)
+ {
+ boost::system::error_code ec;
+ const protocol_type protocol = endpoint.protocol();
+ impl_.get_service().open(impl_.get_implementation(), protocol, ec);
+ boost::asio::detail::throw_error(ec, "open");
+ impl_.get_service().bind(impl_.get_implementation(), endpoint, ec);
+ boost::asio::detail::throw_error(ec, "bind");
+ }
+
+ /// Construct a basic_socket, opening it and binding it to the given local
+ /// endpoint.
+ /**
+ * This constructor creates a socket and automatically opens it bound to the
+ * specified endpoint on the local machine. The protocol used is the protocol
+ * associated with the given endpoint.
+ *
+ * @param context An execution context which provides the I/O executor that
+ * the socket will use, by default, to dispatch handlers for any asynchronous
+ * operations performed on the socket.
+ *
+ * @param endpoint An endpoint on the local machine to which the socket will
+ * be bound.
+ *
+ * @throws boost::system::system_error Thrown on failure.
+ */
+ template <typename ExecutionContext>
+ basic_socket_ext(ExecutionContext& context, const endpoint_type& endpoint,
+ typename enable_if<
+ is_convertible<ExecutionContext&, execution_context&>::value
+ >::type* = 0)
+ : impl_(context)
+ {
+ boost::system::error_code ec;
+ const protocol_type protocol = endpoint.protocol();
+ impl_.get_service().open(impl_.get_implementation(), protocol, ec);
+ boost::asio::detail::throw_error(ec, "open");
+ impl_.get_service().bind(impl_.get_implementation(), endpoint, ec);
+ boost::asio::detail::throw_error(ec, "bind");
+ }
+
+ /// Construct a basic_socket on an existing native socket.
+ /**
+ * This constructor creates a socket object to hold an existing native socket.
+ *
+ * @param ex The I/O executor that the socket will use, by default, to
+ * dispatch handlers for any asynchronous operations performed on the socket.
+ *
+ * @param protocol An object specifying protocol parameters to be used.
+ *
+ * @param native_socket A native socket.
+ *
+ * @throws boost::system::system_error Thrown on failure.
+ */
+ basic_socket_ext(const executor_type& ex, const protocol_type& protocol,
+ const native_handle_type& native_socket)
+ : impl_(ex)
+ {
+ boost::system::error_code ec;
+ impl_.get_service().assign(impl_.get_implementation(),
+ protocol, native_socket, ec);
+ boost::asio::detail::throw_error(ec, "assign");
+ }
+
+ /// Construct a basic_socket on an existing native socket.
+ /**
+ * This constructor creates a socket object to hold an existing native socket.
+ *
+ * @param context An execution context which provides the I/O executor that
+ * the socket will use, by default, to dispatch handlers for any asynchronous
+ * operations performed on the socket.
+ *
+ * @param protocol An object specifying protocol parameters to be used.
+ *
+ * @param native_socket A native socket.
+ *
+ * @throws boost::system::system_error Thrown on failure.
+ */
+ template <typename ExecutionContext>
+ basic_socket_ext(ExecutionContext& context, const protocol_type& protocol,
+ const native_handle_type& native_socket,
+ typename enable_if<
+ is_convertible<ExecutionContext&, execution_context&>::value
+ >::type* = 0)
+ : impl_(context)
+ {
+ boost::system::error_code ec;
+ impl_.get_service().assign(impl_.get_implementation(),
+ protocol, native_socket, ec);
+ boost::asio::detail::throw_error(ec, "assign");
+ }
+
+#if defined(BOOST_ASIO_HAS_MOVE) || defined(GENERATING_DOCUMENTATION)
+ /// Move-construct a basic_socket from another.
+ /**
+ * This constructor moves a socket from one object to another.
+ *
+ * @param other The other basic_socket object from which the move will
+ * occur.
+ *
+ * @note Following the move, the moved-from object is in the same state as if
+ * constructed using the @c basic_socket(const executor_type&) constructor.
+ */
+ basic_socket_ext(basic_socket_ext&& other)
+ : impl_(std::move(other.impl_))
+ {
+ }
+
+ /// Move-assign a basic_socket from another.
+ /**
+ * This assignment operator moves a socket from one object to another.
+ *
+ * @param other The other basic_socket object from which the move will
+ * occur.
+ *
+ * @note Following the move, the moved-from object is in the same state as if
+ * constructed using the @c basic_socket(const executor_type&) constructor.
+ */
+ basic_socket_ext& operator=(basic_socket_ext&& other)
+ {
+ impl_ = std::move(other.impl_);
+ return *this;
+ }
+
+ // All sockets have access to each other's implementations.
+ template <typename Protocol1, typename Executor1>
+ friend class basic_socket_ext;
+
+ /// Move-construct a basic_socket from a socket of another protocol type.
+ /**
+ * This constructor moves a socket from one object to another.
+ *
+ * @param other The other basic_socket object from which the move will
+ * occur.
+ *
+ * @note Following the move, the moved-from object is in the same state as if
+ * constructed using the @c basic_socket(const executor_type&) constructor.
+ */
+ template <typename Protocol1, typename Executor1>
+ basic_socket_ext(basic_socket_ext<Protocol1, Executor1>&& other,
+ typename enable_if<
+ is_convertible<Protocol1, Protocol>::value
+ && is_convertible<Executor1, Executor>::value
+ >::type* = 0)
+ : impl_(std::move(other.impl_))
+ {
+ }
+
+ /// Move-assign a basic_socket from a socket of another protocol type.
+ /**
+ * This assignment operator moves a socket from one object to another.
+ *
+ * @param other The other basic_socket object from which the move will
+ * occur.
+ *
+ * @note Following the move, the moved-from object is in the same state as if
+ * constructed using the @c basic_socket(const executor_type&) constructor.
+ */
+ template <typename Protocol1, typename Executor1>
+ typename enable_if<
+ is_convertible<Protocol1, Protocol>::value
+ && is_convertible<Executor1, Executor>::value,
+ basic_socket_ext&
+ >::type operator=(basic_socket_ext<Protocol1, Executor1> && other)
+ {
+ basic_socket_ext tmp(std::move(other));
+ impl_ = std::move(tmp.impl_);
+ return *this;
+ }
+#endif // defined(BOOST_ASIO_HAS_MOVE) || defined(GENERATING_DOCUMENTATION)
+
+ /// Get the executor associated with the object.
+ executor_type get_executor() BOOST_ASIO_NOEXCEPT
+ {
+ return impl_.get_executor();
+ }
+
+#if !defined(BOOST_ASIO_NO_EXTENSIONS)
+ /// Get a reference to the lowest layer.
+ /**
+ * This function returns a reference to the lowest layer in a stack of
+ * layers. Since a basic_socket cannot contain any further layers, it simply
+ * returns a reference to itself.
+ *
+ * @return A reference to the lowest layer in the stack of layers. Ownership
+ * is not transferred to the caller.
+ */
+ lowest_layer_type& lowest_layer()
+ {
+ return *this;
+ }
+
+ /// Get a const reference to the lowest layer.
+ /**
+ * This function returns a const reference to the lowest layer in a stack of
+ * layers. Since a basic_socket cannot contain any further layers, it simply
+ * returns a reference to itself.
+ *
+ * @return A const reference to the lowest layer in the stack of layers.
+ * Ownership is not transferred to the caller.
+ */
+ const lowest_layer_type& lowest_layer() const
+ {
+ return *this;
+ }
+#endif // !defined(BOOST_ASIO_NO_EXTENSIONS)
+
+ /// Open the socket using the specified protocol.
+ /**
+ * This function opens the socket so that it will use the specified protocol.
+ *
+ * @param protocol An object specifying protocol parameters to be used.
+ *
+ * @throws boost::system::system_error Thrown on failure.
+ *
+ * @par Example
+ * @code
+ * boost::asio::ip::tcp::socket socket(my_context);
+ * socket.open(boost::asio::ip::tcp::v4());
+ * @endcode
+ */
+ void open(const protocol_type& protocol = protocol_type())
+ {
+ boost::system::error_code ec;
+ impl_.get_service().open(impl_.get_implementation(), protocol, ec);
+ boost::asio::detail::throw_error(ec, "open");
+ }
+
+ /// Open the socket using the specified protocol.
+ /**
+ * This function opens the socket so that it will use the specified protocol.
+ *
+ * @param protocol An object specifying which protocol is to be used.
+ *
+ * @param ec Set to indicate what error occurred, if any.
+ *
+ * @par Example
+ * @code
+ * boost::asio::ip::tcp::socket socket(my_context);
+ * boost::system::error_code ec;
+ * socket.open(boost::asio::ip::tcp::v4(), ec);
+ * if (ec)
+ * {
+ * // An error occurred.
+ * }
+ * @endcode
+ */
+ BOOST_ASIO_SYNC_OP_VOID open(const protocol_type& protocol,
+ boost::system::error_code& ec)
+ {
+ impl_.get_service().open(impl_.get_implementation(), protocol, ec);
+ BOOST_ASIO_SYNC_OP_VOID_RETURN(ec);
+ }
+
+ /// Assign an existing native socket to the socket.
+ /*
+ * This function opens the socket to hold an existing native socket.
+ *
+ * @param protocol An object specifying which protocol is to be used.
+ *
+ * @param native_socket A native socket.
+ *
+ * @throws boost::system::system_error Thrown on failure.
+ */
+ void assign(const protocol_type& protocol,
+ const native_handle_type& native_socket)
+ {
+ boost::system::error_code ec;
+ impl_.get_service().assign(impl_.get_implementation(),
+ protocol, native_socket, ec);
+ boost::asio::detail::throw_error(ec, "assign");
+ }
+
+ /// Assign an existing native socket to the socket.
+ /*
+ * This function opens the socket to hold an existing native socket.
+ *
+ * @param protocol An object specifying which protocol is to be used.
+ *
+ * @param native_socket A native socket.
+ *
+ * @param ec Set to indicate what error occurred, if any.
+ */
+ BOOST_ASIO_SYNC_OP_VOID assign(const protocol_type& protocol,
+ const native_handle_type& native_socket, boost::system::error_code& ec)
+ {
+ impl_.get_service().assign(impl_.get_implementation(),
+ protocol, native_socket, ec);
+ BOOST_ASIO_SYNC_OP_VOID_RETURN(ec);
+ }
+
+ /// Determine whether the socket is open.
+ bool is_open() const
+ {
+ return impl_.get_service().is_open(impl_.get_implementation());
+ }
+
+ /// Close the socket.
+ /**
+ * This function is used to close the socket. Any asynchronous send, receive
+ * or connect operations will be cancelled immediately, and will complete
+ * with the boost::asio::error::operation_aborted error.
+ *
+ * @throws boost::system::system_error Thrown on failure. Note that, even if
+ * the function indicates an error, the underlying descriptor is closed.
+ *
+ * @note For portable behaviour with respect to graceful closure of a
+ * connected socket, call shutdown() before closing the socket.
+ */
+ void close()
+ {
+ boost::system::error_code ec;
+ impl_.get_service().close(impl_.get_implementation(), ec);
+ boost::asio::detail::throw_error(ec, "close");
+ }
+
+ /// Close the socket.
+ /**
+ * This function is used to close the socket. Any asynchronous send, receive
+ * or connect operations will be cancelled immediately, and will complete
+ * with the boost::asio::error::operation_aborted error.
+ *
+ * @param ec Set to indicate what error occurred, if any. Note that, even if
+ * the function indicates an error, the underlying descriptor is closed.
+ *
+ * @par Example
+ * @code
+ * boost::asio::ip::tcp::socket socket(my_context);
+ * ...
+ * boost::system::error_code ec;
+ * socket.close(ec);
+ * if (ec)
+ * {
+ * // An error occurred.
+ * }
+ * @endcode
+ *
+ * @note For portable behaviour with respect to graceful closure of a
+ * connected socket, call shutdown() before closing the socket.
+ */
+ BOOST_ASIO_SYNC_OP_VOID close(boost::system::error_code& ec)
+ {
+ impl_.get_service().close(impl_.get_implementation(), ec);
+ BOOST_ASIO_SYNC_OP_VOID_RETURN(ec);
+ }
+
+ /// Release ownership of the underlying native socket.
+ /**
+ * This function causes all outstanding asynchronous connect, send and receive
+ * operations to finish immediately, and the handlers for cancelled operations
+ * will be passed the boost::asio::error::operation_aborted error. Ownership
+ * of the native socket is then transferred to the caller.
+ *
+ * @throws boost::system::system_error Thrown on failure.
+ *
+ * @note This function is unsupported on Windows versions prior to Windows
+ * 8.1, and will fail with boost::asio::error::operation_not_supported on
+ * these platforms.
+ */
+#if defined(BOOST_ASIO_MSVC) && (BOOST_ASIO_MSVC >= 1400) \
+ && (!defined(_WIN32_WINNT) || _WIN32_WINNT < 0x0603)
+ __declspec(deprecated("This function always fails with "
+ "operation_not_supported when used on Windows versions "
+ "prior to Windows 8.1."))
+#endif
+ native_handle_type release()
+ {
+ boost::system::error_code ec;
+ native_handle_type s = impl_.get_service().release(
+ impl_.get_implementation(), ec);
+ boost::asio::detail::throw_error(ec, "release");
+ return s;
+ }
+
+ /// Release ownership of the underlying native socket.
+ /**
+ * This function causes all outstanding asynchronous connect, send and receive
+ * operations to finish immediately, and the handlers for cancelled operations
+ * will be passed the boost::asio::error::operation_aborted error. Ownership
+ * of the native socket is then transferred to the caller.
+ *
+ * @param ec Set to indicate what error occurred, if any.
+ *
+ * @note This function is unsupported on Windows versions prior to Windows
+ * 8.1, and will fail with boost::asio::error::operation_not_supported on
+ * these platforms.
+ */
+#if defined(BOOST_ASIO_MSVC) && (BOOST_ASIO_MSVC >= 1400) \
+ && (!defined(_WIN32_WINNT) || _WIN32_WINNT < 0x0603)
+ __declspec(deprecated("This function always fails with "
+ "operation_not_supported when used on Windows versions "
+ "prior to Windows 8.1."))
+#endif
+ native_handle_type release(boost::system::error_code& ec)
+ {
+ return impl_.get_service().release(impl_.get_implementation(), ec);
+ }
+
+ /// Get the native socket representation.
+ /**
+ * This function may be used to obtain the underlying representation of the
+ * socket. This is intended to allow access to native socket functionality
+ * that is not otherwise provided.
+ */
+ native_handle_type native_handle()
+ {
+ return impl_.get_service().native_handle(impl_.get_implementation());
+ }
+
+ /// Cancel all asynchronous operations associated with the socket.
+ /**
+ * This function causes all outstanding asynchronous connect, send and receive
+ * operations to finish immediately, and the handlers for cancelled operations
+ * will be passed the boost::asio::error::operation_aborted error.
+ *
+ * @throws boost::system::system_error Thrown on failure.
+ *
+ * @note Calls to cancel() will always fail with
+ * boost::asio::error::operation_not_supported when run on Windows XP, Windows
+ * Server 2003, and earlier versions of Windows, unless
+ * BOOST_ASIO_ENABLE_CANCELIO is defined. However, the CancelIo function has
+ * two issues that should be considered before enabling its use:
+ *
+ * @li It will only cancel asynchronous operations that were initiated in the
+ * current thread.
+ *
+ * @li It can appear to complete without error, but the request to cancel the
+ * unfinished operations may be silently ignored by the operating system.
+ * Whether it works or not seems to depend on the drivers that are installed.
+ *
+ * For portable cancellation, consider using one of the following
+ * alternatives:
+ *
+ * @li Disable asio's I/O completion port backend by defining
+ * BOOST_ASIO_DISABLE_IOCP.
+ *
+ * @li Use the close() function to simultaneously cancel the outstanding
+ * operations and close the socket.
+ *
+ * When running on Windows Vista, Windows Server 2008, and later, the
+ * CancelIoEx function is always used. This function does not have the
+ * problems described above.
+ */
+#if defined(BOOST_ASIO_MSVC) && (BOOST_ASIO_MSVC >= 1400) \
+ && (!defined(_WIN32_WINNT) || _WIN32_WINNT < 0x0600) \
+ && !defined(BOOST_ASIO_ENABLE_CANCELIO)
+ __declspec(deprecated("By default, this function always fails with "
+ "operation_not_supported when used on Windows XP, Windows Server 2003, "
+ "or earlier. Consult documentation for details."))
+#endif
+ void cancel()
+ {
+ boost::system::error_code ec;
+ impl_.get_service().cancel(impl_.get_implementation(), ec);
+ boost::asio::detail::throw_error(ec, "cancel");
+ }
+
+ /// Cancel all asynchronous operations associated with the socket.
+ /**
+ * This function causes all outstanding asynchronous connect, send and receive
+ * operations to finish immediately, and the handlers for cancelled operations
+ * will be passed the boost::asio::error::operation_aborted error.
+ *
+ * @param ec Set to indicate what error occurred, if any.
+ *
+ * @note Calls to cancel() will always fail with
+ * boost::asio::error::operation_not_supported when run on Windows XP, Windows
+ * Server 2003, and earlier versions of Windows, unless
+ * BOOST_ASIO_ENABLE_CANCELIO is defined. However, the CancelIo function has
+ * two issues that should be considered before enabling its use:
+ *
+ * @li It will only cancel asynchronous operations that were initiated in the
+ * current thread.
+ *
+ * @li It can appear to complete without error, but the request to cancel the
+ * unfinished operations may be silently ignored by the operating system.
+ * Whether it works or not seems to depend on the drivers that are installed.
+ *
+ * For portable cancellation, consider using one of the following
+ * alternatives:
+ *
+ * @li Disable asio's I/O completion port backend by defining
+ * BOOST_ASIO_DISABLE_IOCP.
+ *
+ * @li Use the close() function to simultaneously cancel the outstanding
+ * operations and close the socket.
+ *
+ * When running on Windows Vista, Windows Server 2008, and later, the
+ * CancelIoEx function is always used. This function does not have the
+ * problems described above.
+ */
+#if defined(BOOST_ASIO_MSVC) && (BOOST_ASIO_MSVC >= 1400) \
+ && (!defined(_WIN32_WINNT) || _WIN32_WINNT < 0x0600) \
+ && !defined(BOOST_ASIO_ENABLE_CANCELIO)
+ __declspec(deprecated("By default, this function always fails with "
+ "operation_not_supported when used on Windows XP, Windows Server 2003, "
+ "or earlier. Consult documentation for details."))
+#endif
+ BOOST_ASIO_SYNC_OP_VOID cancel(boost::system::error_code& ec)
+ {
+ impl_.get_service().cancel(impl_.get_implementation(), ec);
+ BOOST_ASIO_SYNC_OP_VOID_RETURN(ec);
+ }
+
+ /// Determine whether the socket is at the out-of-band data mark.
+ /**
+ * This function is used to check whether the socket input is currently
+ * positioned at the out-of-band data mark.
+ *
+ * @return A bool indicating whether the socket is at the out-of-band data
+ * mark.
+ *
+ * @throws boost::system::system_error Thrown on failure.
+ */
+ bool at_mark() const
+ {
+ boost::system::error_code ec;
+ bool b = impl_.get_service().at_mark(impl_.get_implementation(), ec);
+ boost::asio::detail::throw_error(ec, "at_mark");
+ return b;
+ }
+
+ /// Determine whether the socket is at the out-of-band data mark.
+ /**
+ * This function is used to check whether the socket input is currently
+ * positioned at the out-of-band data mark.
+ *
+ * @param ec Set to indicate what error occurred, if any.
+ *
+ * @return A bool indicating whether the socket is at the out-of-band data
+ * mark.
+ */
+ bool at_mark(boost::system::error_code& ec) const
+ {
+ return impl_.get_service().at_mark(impl_.get_implementation(), ec);
+ }
+
+ /// Determine the number of bytes available for reading.
+ /**
+ * This function is used to determine the number of bytes that may be read
+ * without blocking.
+ *
+ * @return The number of bytes that may be read without blocking, or 0 if an
+ * error occurs.
+ *
+ * @throws boost::system::system_error Thrown on failure.
+ */
+ std::size_t available() const
+ {
+ boost::system::error_code ec;
+ std::size_t s = impl_.get_service().available(
+ impl_.get_implementation(), ec);
+ boost::asio::detail::throw_error(ec, "available");
+ return s;
+ }
+
+ /// Determine the number of bytes available for reading.
+ /**
+ * This function is used to determine the number of bytes that may be read
+ * without blocking.
+ *
+ * @param ec Set to indicate what error occurred, if any.
+ *
+ * @return The number of bytes that may be read without blocking, or 0 if an
+ * error occurs.
+ */
+ std::size_t available(boost::system::error_code& ec) const
+ {
+ return impl_.get_service().available(impl_.get_implementation(), ec);
+ }
+
+ /// Bind the socket to the given local endpoint.
+ /**
+ * This function binds the socket to the specified endpoint on the local
+ * machine.
+ *
+ * @param endpoint An endpoint on the local machine to which the socket will
+ * be bound.
+ *
+ * @throws boost::system::system_error Thrown on failure.
+ *
+ * @par Example
+ * @code
+ * boost::asio::ip::tcp::socket socket(my_context);
+ * socket.open(boost::asio::ip::tcp::v4());
+ * socket.bind(boost::asio::ip::tcp::endpoint(
+ * boost::asio::ip::tcp::v4(), 12345));
+ * @endcode
+ */
+ void bind(const endpoint_type& endpoint)
+ {
+ boost::system::error_code ec;
+ impl_.get_service().bind(impl_.get_implementation(), endpoint, ec);
+ boost::asio::detail::throw_error(ec, "bind");
+ }
+
+ /// Bind the socket to the given local endpoint.
+ /**
+ * This function binds the socket to the specified endpoint on the local
+ * machine.
+ *
+ * @param endpoint An endpoint on the local machine to which the socket will
+ * be bound.
+ *
+ * @param ec Set to indicate what error occurred, if any.
+ *
+ * @par Example
+ * @code
+ * boost::asio::ip::tcp::socket socket(my_context);
+ * socket.open(boost::asio::ip::tcp::v4());
+ * boost::system::error_code ec;
+ * socket.bind(boost::asio::ip::tcp::endpoint(
+ * boost::asio::ip::tcp::v4(), 12345), ec);
+ * if (ec)
+ * {
+ * // An error occurred.
+ * }
+ * @endcode
+ */
+ BOOST_ASIO_SYNC_OP_VOID bind(const endpoint_type& endpoint,
+ boost::system::error_code& ec)
+ {
+ impl_.get_service().bind(impl_.get_implementation(), endpoint, ec);
+ BOOST_ASIO_SYNC_OP_VOID_RETURN(ec);
+ }
+
+ /// Connect the socket to the specified endpoint.
+ /**
+ * This function is used to connect a socket to the specified remote endpoint.
+ * The function call will block until the connection is successfully made or
+ * an error occurs.
+ *
+ * The socket is automatically opened if it is not already open. If the
+ * connect fails, and the socket was automatically opened, the socket is
+ * not returned to the closed state.
+ *
+ * @param peer_endpoint The remote endpoint to which the socket will be
+ * connected.
+ *
+ * @throws boost::system::system_error Thrown on failure.
+ *
+ * @par Example
+ * @code
+ * boost::asio::ip::tcp::socket socket(my_context);
+ * boost::asio::ip::tcp::endpoint endpoint(
+ * boost::asio::ip::address::from_string("1.2.3.4"), 12345);
+ * socket.connect(endpoint);
+ * @endcode
+ */
+ void connect(const endpoint_type& peer_endpoint)
+ {
+ boost::system::error_code ec;
+ if (!is_open())
+ {
+ impl_.get_service().open(impl_.get_implementation(),
+ peer_endpoint.protocol(), ec);
+ boost::asio::detail::throw_error(ec, "connect");
+ }
+ impl_.get_service().connect(impl_.get_implementation(), peer_endpoint, ec);
+ boost::asio::detail::throw_error(ec, "connect");
+ }
+
+ /// Connect the socket to the specified endpoint.
+ /**
+ * This function is used to connect a socket to the specified remote endpoint.
+ * The function call will block until the connection is successfully made or
+ * an error occurs.
+ *
+ * The socket is automatically opened if it is not already open. If the
+ * connect fails, and the socket was automatically opened, the socket is
+ * not returned to the closed state.
+ *
+ * @param peer_endpoint The remote endpoint to which the socket will be
+ * connected.
+ *
+ * @param ec Set to indicate what error occurred, if any.
+ *
+ * @par Example
+ * @code
+ * boost::asio::ip::tcp::socket socket(my_context);
+ * boost::asio::ip::tcp::endpoint endpoint(
+ * boost::asio::ip::address::from_string("1.2.3.4"), 12345);
+ * boost::system::error_code ec;
+ * socket.connect(endpoint, ec);
+ * if (ec)
+ * {
+ * // An error occurred.
+ * }
+ * @endcode
+ */
+ BOOST_ASIO_SYNC_OP_VOID connect(const endpoint_type& peer_endpoint,
+ boost::system::error_code& ec)
+ {
+ if (!is_open())
+ {
+ impl_.get_service().open(impl_.get_implementation(),
+ peer_endpoint.protocol(), ec);
+ if (ec)
+ {
+ BOOST_ASIO_SYNC_OP_VOID_RETURN(ec);
+ }
+ }
+
+ impl_.get_service().connect(impl_.get_implementation(), peer_endpoint, ec);
+ BOOST_ASIO_SYNC_OP_VOID_RETURN(ec);
+ }
+
+ /// Start an asynchronous connect.
+ /**
+ * This function is used to asynchronously connect a socket to the specified
+ * remote endpoint. The function call always returns immediately.
+ *
+ * The socket is automatically opened if it is not already open. If the
+ * connect fails, and the socket was automatically opened, the socket is
+ * not returned to the closed state.
+ *
+ * @param peer_endpoint The remote endpoint to which the socket will be
+ * connected. Copies will be made of the endpoint object as required.
+ *
+ * @param handler The handler to be called when the connection operation
+ * completes. Copies will be made of the handler as required. The function
+ * signature of the handler must be:
+ * @code void handler(
+ * const boost::system::error_code& error // Result of operation
+ * ); @endcode
+ * Regardless of whether the asynchronous operation completes immediately or
+ * not, the handler will not be invoked from within this function. On
+ * immediate completion, invocation of the handler will be performed in a
+ * manner equivalent to using boost::asio::post().
+ *
+ * @par Example
+ * @code
+ * void connect_handler(const boost::system::error_code& error)
+ * {
+ * if (!error)
+ * {
+ * // Connect succeeded.
+ * }
+ * }
+ *
+ * ...
+ *
+ * boost::asio::ip::tcp::socket socket(my_context);
+ * boost::asio::ip::tcp::endpoint endpoint(
+ * boost::asio::ip::address::from_string("1.2.3.4"), 12345);
+ * socket.async_connect(endpoint, connect_handler);
+ * @endcode
+ */
+ template <typename ConnectHandler>
+ BOOST_ASIO_INITFN_RESULT_TYPE(ConnectHandler,
+ void (boost::system::error_code))
+ async_connect(const endpoint_type& peer_endpoint,
+ BOOST_ASIO_MOVE_ARG(ConnectHandler) handler)
+ {
+ boost::system::error_code open_ec;
+ if (!is_open())
+ {
+ const protocol_type protocol = peer_endpoint.protocol();
+ impl_.get_service().open(impl_.get_implementation(), protocol, open_ec);
+ }
+
+ return async_initiate<ConnectHandler, void (boost::system::error_code)>(
+ initiate_async_connect(), handler, this, peer_endpoint, open_ec);
+ }
+
+ /// Set an option on the socket.
+ /**
+ * This function is used to set an option on the socket.
+ *
+ * @param option The new option value to be set on the socket.
+ *
+ * @throws boost::system::system_error Thrown on failure.
+ *
+ * @sa SettableSocketOption @n
+ * boost::asio::socket_base::broadcast @n
+ * boost::asio::socket_base::do_not_route @n
+ * boost::asio::socket_base::keep_alive @n
+ * boost::asio::socket_base::linger @n
+ * boost::asio::socket_base::receive_buffer_size @n
+ * boost::asio::socket_base::receive_low_watermark @n
+ * boost::asio::socket_base::reuse_address @n
+ * boost::asio::socket_base::send_buffer_size @n
+ * boost::asio::socket_base::send_low_watermark @n
+ * boost::asio::ip::multicast::join_group @n
+ * boost::asio::ip::multicast::leave_group @n
+ * boost::asio::ip::multicast::enable_loopback @n
+ * boost::asio::ip::multicast::outbound_interface @n
+ * boost::asio::ip::multicast::hops @n
+ * boost::asio::ip::tcp::no_delay
+ *
+ * @par Example
+ * Setting the IPPROTO_TCP/TCP_NODELAY option:
+ * @code
+ * boost::asio::ip::tcp::socket socket(my_context);
+ * ...
+ * boost::asio::ip::tcp::no_delay option(true);
+ * socket.set_option(option);
+ * @endcode
+ */
+ template <typename SettableSocketOption>
+ void set_option(const SettableSocketOption& option)
+ {
+ boost::system::error_code ec;
+ impl_.get_service().set_option(impl_.get_implementation(), option, ec);
+ boost::asio::detail::throw_error(ec, "set_option");
+ }
+
+ /// Set an option on the socket.
+ /**
+ * This function is used to set an option on the socket.
+ *
+ * @param option The new option value to be set on the socket.
+ *
+ * @param ec Set to indicate what error occurred, if any.
+ *
+ * @sa SettableSocketOption @n
+ * boost::asio::socket_base::broadcast @n
+ * boost::asio::socket_base::do_not_route @n
+ * boost::asio::socket_base::keep_alive @n
+ * boost::asio::socket_base::linger @n
+ * boost::asio::socket_base::receive_buffer_size @n
+ * boost::asio::socket_base::receive_low_watermark @n
+ * boost::asio::socket_base::reuse_address @n
+ * boost::asio::socket_base::send_buffer_size @n
+ * boost::asio::socket_base::send_low_watermark @n
+ * boost::asio::ip::multicast::join_group @n
+ * boost::asio::ip::multicast::leave_group @n
+ * boost::asio::ip::multicast::enable_loopback @n
+ * boost::asio::ip::multicast::outbound_interface @n
+ * boost::asio::ip::multicast::hops @n
+ * boost::asio::ip::tcp::no_delay
+ *
+ * @par Example
+ * Setting the IPPROTO_TCP/TCP_NODELAY option:
+ * @code
+ * boost::asio::ip::tcp::socket socket(my_context);
+ * ...
+ * boost::asio::ip::tcp::no_delay option(true);
+ * boost::system::error_code ec;
+ * socket.set_option(option, ec);
+ * if (ec)
+ * {
+ * // An error occurred.
+ * }
+ * @endcode
+ */
+ template <typename SettableSocketOption>
+ BOOST_ASIO_SYNC_OP_VOID set_option(const SettableSocketOption& option,
+ boost::system::error_code& ec)
+ {
+ impl_.get_service().set_option(impl_.get_implementation(), option, ec);
+ BOOST_ASIO_SYNC_OP_VOID_RETURN(ec);
+ }
+
+ /// Get an option from the socket.
+ /**
+ * This function is used to get the current value of an option on the socket.
+ *
+ * @param option The option value to be obtained from the socket.
+ *
+ * @throws boost::system::system_error Thrown on failure.
+ *
+ * @sa GettableSocketOption @n
+ * boost::asio::socket_base::broadcast @n
+ * boost::asio::socket_base::do_not_route @n
+ * boost::asio::socket_base::keep_alive @n
+ * boost::asio::socket_base::linger @n
+ * boost::asio::socket_base::receive_buffer_size @n
+ * boost::asio::socket_base::receive_low_watermark @n
+ * boost::asio::socket_base::reuse_address @n
+ * boost::asio::socket_base::send_buffer_size @n
+ * boost::asio::socket_base::send_low_watermark @n
+ * boost::asio::ip::multicast::join_group @n
+ * boost::asio::ip::multicast::leave_group @n
+ * boost::asio::ip::multicast::enable_loopback @n
+ * boost::asio::ip::multicast::outbound_interface @n
+ * boost::asio::ip::multicast::hops @n
+ * boost::asio::ip::tcp::no_delay
+ *
+ * @par Example
+ * Getting the value of the SOL_SOCKET/SO_KEEPALIVE option:
+ * @code
+ * boost::asio::ip::tcp::socket socket(my_context);
+ * ...
+ * boost::asio::ip::tcp::socket::keep_alive option;
+ * socket.get_option(option);
+ * bool is_set = option.value();
+ * @endcode
+ */
+ template <typename GettableSocketOption>
+ void get_option(GettableSocketOption& option) const
+ {
+ boost::system::error_code ec;
+ impl_.get_service().get_option(impl_.get_implementation(), option, ec);
+ boost::asio::detail::throw_error(ec, "get_option");
+ }
+
+ /// Get an option from the socket.
+ /**
+ * This function is used to get the current value of an option on the socket.
+ *
+ * @param option The option value to be obtained from the socket.
+ *
+ * @param ec Set to indicate what error occurred, if any.
+ *
+ * @sa GettableSocketOption @n
+ * boost::asio::socket_base::broadcast @n
+ * boost::asio::socket_base::do_not_route @n
+ * boost::asio::socket_base::keep_alive @n
+ * boost::asio::socket_base::linger @n
+ * boost::asio::socket_base::receive_buffer_size @n
+ * boost::asio::socket_base::receive_low_watermark @n
+ * boost::asio::socket_base::reuse_address @n
+ * boost::asio::socket_base::send_buffer_size @n
+ * boost::asio::socket_base::send_low_watermark @n
+ * boost::asio::ip::multicast::join_group @n
+ * boost::asio::ip::multicast::leave_group @n
+ * boost::asio::ip::multicast::enable_loopback @n
+ * boost::asio::ip::multicast::outbound_interface @n
+ * boost::asio::ip::multicast::hops @n
+ * boost::asio::ip::tcp::no_delay
+ *
+ * @par Example
+ * Getting the value of the SOL_SOCKET/SO_KEEPALIVE option:
+ * @code
+ * boost::asio::ip::tcp::socket socket(my_context);
+ * ...
+ * boost::asio::ip::tcp::socket::keep_alive option;
+ * boost::system::error_code ec;
+ * socket.get_option(option, ec);
+ * if (ec)
+ * {
+ * // An error occurred.
+ * }
+ * bool is_set = option.value();
+ * @endcode
+ */
+ template <typename GettableSocketOption>
+ BOOST_ASIO_SYNC_OP_VOID get_option(GettableSocketOption& option,
+ boost::system::error_code& ec) const
+ {
+ impl_.get_service().get_option(impl_.get_implementation(), option, ec);
+ BOOST_ASIO_SYNC_OP_VOID_RETURN(ec);
+ }
+
+ /// Perform an IO control command on the socket.
+ /**
+ * This function is used to execute an IO control command on the socket.
+ *
+ * @param command The IO control command to be performed on the socket.
+ *
+ * @throws boost::system::system_error Thrown on failure.
+ *
+ * @sa IoControlCommand @n
+ * boost::asio::socket_base::bytes_readable @n
+ * boost::asio::socket_base::non_blocking_io
+ *
+ * @par Example
+ * Getting the number of bytes ready to read:
+ * @code
+ * boost::asio::ip::tcp::socket socket(my_context);
+ * ...
+ * boost::asio::ip::tcp::socket::bytes_readable command;
+ * socket.io_control(command);
+ * std::size_t bytes_readable = command.get();
+ * @endcode
+ */
+ template <typename IoControlCommand>
+ void io_control(IoControlCommand& command)
+ {
+ boost::system::error_code ec;
+ impl_.get_service().io_control(impl_.get_implementation(), command, ec);
+ boost::asio::detail::throw_error(ec, "io_control");
+ }
+
+ /// Perform an IO control command on the socket.
+ /**
+ * This function is used to execute an IO control command on the socket.
+ *
+ * @param command The IO control command to be performed on the socket.
+ *
+ * @param ec Set to indicate what error occurred, if any.
+ *
+ * @sa IoControlCommand @n
+ * boost::asio::socket_base::bytes_readable @n
+ * boost::asio::socket_base::non_blocking_io
+ *
+ * @par Example
+ * Getting the number of bytes ready to read:
+ * @code
+ * boost::asio::ip::tcp::socket socket(my_context);
+ * ...
+ * boost::asio::ip::tcp::socket::bytes_readable command;
+ * boost::system::error_code ec;
+ * socket.io_control(command, ec);
+ * if (ec)
+ * {
+ * // An error occurred.
+ * }
+ * std::size_t bytes_readable = command.get();
+ * @endcode
+ */
+ template <typename IoControlCommand>
+ BOOST_ASIO_SYNC_OP_VOID io_control(IoControlCommand& command,
+ boost::system::error_code& ec)
+ {
+ impl_.get_service().io_control(impl_.get_implementation(), command, ec);
+ BOOST_ASIO_SYNC_OP_VOID_RETURN(ec);
+ }
+
+ /// Gets the non-blocking mode of the socket.
+ /**
+ * @returns @c true if the socket's synchronous operations will fail with
+ * boost::asio::error::would_block if they are unable to perform the requested
+ * operation immediately. If @c false, synchronous operations will block
+ * until complete.
+ *
+ * @note The non-blocking mode has no effect on the behaviour of asynchronous
+ * operations. Asynchronous operations will never fail with the error
+ * boost::asio::error::would_block.
+ */
+ bool non_blocking() const
+ {
+ return impl_.get_service().non_blocking(impl_.get_implementation());
+ }
+
+ /// Sets the non-blocking mode of the socket.
+ /**
+ * @param mode If @c true, the socket's synchronous operations will fail with
+ * boost::asio::error::would_block if they are unable to perform the requested
+ * operation immediately. If @c false, synchronous operations will block
+ * until complete.
+ *
+ * @throws boost::system::system_error Thrown on failure.
+ *
+ * @note The non-blocking mode has no effect on the behaviour of asynchronous
+ * operations. Asynchronous operations will never fail with the error
+ * boost::asio::error::would_block.
+ */
+ void non_blocking(bool mode)
+ {
+ boost::system::error_code ec;
+ impl_.get_service().non_blocking(impl_.get_implementation(), mode, ec);
+ boost::asio::detail::throw_error(ec, "non_blocking");
+ }
+
+ /// Sets the non-blocking mode of the socket.
+ /**
+ * @param mode If @c true, the socket's synchronous operations will fail with
+ * boost::asio::error::would_block if they are unable to perform the requested
+ * operation immediately. If @c false, synchronous operations will block
+ * until complete.
+ *
+ * @param ec Set to indicate what error occurred, if any.
+ *
+ * @note The non-blocking mode has no effect on the behaviour of asynchronous
+ * operations. Asynchronous operations will never fail with the error
+ * boost::asio::error::would_block.
+ */
+ BOOST_ASIO_SYNC_OP_VOID non_blocking(
+ bool mode, boost::system::error_code& ec)
+ {
+ impl_.get_service().non_blocking(impl_.get_implementation(), mode, ec);
+ BOOST_ASIO_SYNC_OP_VOID_RETURN(ec);
+ }
+
+ /// Gets the non-blocking mode of the native socket implementation.
+ /**
+ * This function is used to retrieve the non-blocking mode of the underlying
+ * native socket. This mode has no effect on the behaviour of the socket
+ * object's synchronous operations.
+ *
+ * @returns @c true if the underlying socket is in non-blocking mode and
+ * direct system calls may fail with boost::asio::error::would_block (or the
+ * equivalent system error).
+ *
+ * @note The current non-blocking mode is cached by the socket object.
+ * Consequently, the return value may be incorrect if the non-blocking mode
+ * was set directly on the native socket.
+ *
+ * @par Example
+ * This function is intended to allow the encapsulation of arbitrary
+ * non-blocking system calls as asynchronous operations, in a way that is
+ * transparent to the user of the socket object. The following example
+ * illustrates how Linux's @c sendfile system call might be encapsulated:
+ * @code template <typename Handler>
+ * struct sendfile_op
+ * {
+ * tcp::socket& sock_;
+ * int fd_;
+ * Handler handler_;
+ * off_t offset_;
+ * std::size_t total_bytes_transferred_;
+ *
+ * // Function call operator meeting WriteHandler requirements.
+ * // Used as the handler for the async_write_some operation.
+ * void operator()(boost::system::error_code ec, std::size_t)
+ * {
+ * // Put the underlying socket into non-blocking mode.
+ * if (!ec)
+ * if (!sock_.native_non_blocking())
+ * sock_.native_non_blocking(true, ec);
+ *
+ * if (!ec)
+ * {
+ * for (;;)
+ * {
+ * // Try the system call.
+ * errno = 0;
+ * int n = ::sendfile(sock_.native_handle(), fd_, &offset_, 65536);
+ * ec = boost::system::error_code(n < 0 ? errno : 0,
+ * boost::asio::error::get_system_category());
+ * total_bytes_transferred_ += ec ? 0 : n;
+ *
+ * // Retry operation immediately if interrupted by signal.
+ * if (ec == boost::asio::error::interrupted)
+ * continue;
+ *
+ * // Check if we need to run the operation again.
+ * if (ec == boost::asio::error::would_block
+ * || ec == boost::asio::error::try_again)
+ * {
+ * // We have to wait for the socket to become ready again.
+ * sock_.async_wait(tcp::socket::wait_write, *this);
+ * return;
+ * }
+ *
+ * if (ec || n == 0)
+ * {
+ * // An error occurred, or we have reached the end of the file.
+ * // Either way we must exit the loop so we can call the handler.
+ * break;
+ * }
+ *
+ * // Loop around to try calling sendfile again.
+ * }
+ * }
+ *
+ * // Pass result back to user's handler.
+ * handler_(ec, total_bytes_transferred_);
+ * }
+ * };
+ *
+ * template <typename Handler>
+ * void async_sendfile(tcp::socket& sock, int fd, Handler h)
+ * {
+ * sendfile_op<Handler> op = { sock, fd, h, 0, 0 };
+ * sock.async_wait(tcp::socket::wait_write, op);
+ * } @endcode
+ */
+ bool native_non_blocking() const
+ {
+ return impl_.get_service().native_non_blocking(impl_.get_implementation());
+ }
+
+ /// Sets the non-blocking mode of the native socket implementation.
+ /**
+ * This function is used to modify the non-blocking mode of the underlying
+ * native socket. It has no effect on the behaviour of the socket object's
+ * synchronous operations.
+ *
+ * @param mode If @c true, the underlying socket is put into non-blocking
+ * mode and direct system calls may fail with boost::asio::error::would_block
+ * (or the equivalent system error).
+ *
+ * @throws boost::system::system_error Thrown on failure. If the @c mode is
+ * @c false, but the current value of @c non_blocking() is @c true, this
+ * function fails with boost::asio::error::invalid_argument, as the
+ * combination does not make sense.
+ *
+ * @par Example
+ * This function is intended to allow the encapsulation of arbitrary
+ * non-blocking system calls as asynchronous operations, in a way that is
+ * transparent to the user of the socket object. The following example
+ * illustrates how Linux's @c sendfile system call might be encapsulated:
+ * @code template <typename Handler>
+ * struct sendfile_op
+ * {
+ * tcp::socket& sock_;
+ * int fd_;
+ * Handler handler_;
+ * off_t offset_;
+ * std::size_t total_bytes_transferred_;
+ *
+ * // Function call operator meeting WriteHandler requirements.
+ * // Used as the handler for the async_write_some operation.
+ * void operator()(boost::system::error_code ec, std::size_t)
+ * {
+ * // Put the underlying socket into non-blocking mode.
+ * if (!ec)
+ * if (!sock_.native_non_blocking())
+ * sock_.native_non_blocking(true, ec);
+ *
+ * if (!ec)
+ * {
+ * for (;;)
+ * {
+ * // Try the system call.
+ * errno = 0;
+ * int n = ::sendfile(sock_.native_handle(), fd_, &offset_, 65536);
+ * ec = boost::system::error_code(n < 0 ? errno : 0,
+ * boost::asio::error::get_system_category());
+ * total_bytes_transferred_ += ec ? 0 : n;
+ *
+ * // Retry operation immediately if interrupted by signal.
+ * if (ec == boost::asio::error::interrupted)
+ * continue;
+ *
+ * // Check if we need to run the operation again.
+ * if (ec == boost::asio::error::would_block
+ * || ec == boost::asio::error::try_again)
+ * {
+ * // We have to wait for the socket to become ready again.
+ * sock_.async_wait(tcp::socket::wait_write, *this);
+ * return;
+ * }
+ *
+ * if (ec || n == 0)
+ * {
+ * // An error occurred, or we have reached the end of the file.
+ * // Either way we must exit the loop so we can call the handler.
+ * break;
+ * }
+ *
+ * // Loop around to try calling sendfile again.
+ * }
+ * }
+ *
+ * // Pass result back to user's handler.
+ * handler_(ec, total_bytes_transferred_);
+ * }
+ * };
+ *
+ * template <typename Handler>
+ * void async_sendfile(tcp::socket& sock, int fd, Handler h)
+ * {
+ * sendfile_op<Handler> op = { sock, fd, h, 0, 0 };
+ * sock.async_wait(tcp::socket::wait_write, op);
+ * } @endcode
+ */
+ void native_non_blocking(bool mode)
+ {
+ boost::system::error_code ec;
+ impl_.get_service().native_non_blocking(
+ impl_.get_implementation(), mode, ec);
+ boost::asio::detail::throw_error(ec, "native_non_blocking");
+ }
+
+ /// Sets the non-blocking mode of the native socket implementation.
+ /**
+ * This function is used to modify the non-blocking mode of the underlying
+ * native socket. It has no effect on the behaviour of the socket object's
+ * synchronous operations.
+ *
+ * @param mode If @c true, the underlying socket is put into non-blocking
+ * mode and direct system calls may fail with boost::asio::error::would_block
+ * (or the equivalent system error).
+ *
+ * @param ec Set to indicate what error occurred, if any. If the @c mode is
+ * @c false, but the current value of @c non_blocking() is @c true, this
+ * function fails with boost::asio::error::invalid_argument, as the
+ * combination does not make sense.
+ *
+ * @par Example
+ * This function is intended to allow the encapsulation of arbitrary
+ * non-blocking system calls as asynchronous operations, in a way that is
+ * transparent to the user of the socket object. The following example
+ * illustrates how Linux's @c sendfile system call might be encapsulated:
+ * @code template <typename Handler>
+ * struct sendfile_op
+ * {
+ * tcp::socket& sock_;
+ * int fd_;
+ * Handler handler_;
+ * off_t offset_;
+ * std::size_t total_bytes_transferred_;
+ *
+ * // Function call operator meeting WriteHandler requirements.
+ * // Used as the handler for the async_write_some operation.
+ * void operator()(boost::system::error_code ec, std::size_t)
+ * {
+ * // Put the underlying socket into non-blocking mode.
+ * if (!ec)
+ * if (!sock_.native_non_blocking())
+ * sock_.native_non_blocking(true, ec);
+ *
+ * if (!ec)
+ * {
+ * for (;;)
+ * {
+ * // Try the system call.
+ * errno = 0;
+ * int n = ::sendfile(sock_.native_handle(), fd_, &offset_, 65536);
+ * ec = boost::system::error_code(n < 0 ? errno : 0,
+ * boost::asio::error::get_system_category());
+ * total_bytes_transferred_ += ec ? 0 : n;
+ *
+ * // Retry operation immediately if interrupted by signal.
+ * if (ec == boost::asio::error::interrupted)
+ * continue;
+ *
+ * // Check if we need to run the operation again.
+ * if (ec == boost::asio::error::would_block
+ * || ec == boost::asio::error::try_again)
+ * {
+ * // We have to wait for the socket to become ready again.
+ * sock_.async_wait(tcp::socket::wait_write, *this);
+ * return;
+ * }
+ *
+ * if (ec || n == 0)
+ * {
+ * // An error occurred, or we have reached the end of the file.
+ * // Either way we must exit the loop so we can call the handler.
+ * break;
+ * }
+ *
+ * // Loop around to try calling sendfile again.
+ * }
+ * }
+ *
+ * // Pass result back to user's handler.
+ * handler_(ec, total_bytes_transferred_);
+ * }
+ * };
+ *
+ * template <typename Handler>
+ * void async_sendfile(tcp::socket& sock, int fd, Handler h)
+ * {
+ * sendfile_op<Handler> op = { sock, fd, h, 0, 0 };
+ * sock.async_wait(tcp::socket::wait_write, op);
+ * } @endcode
+ */
+ BOOST_ASIO_SYNC_OP_VOID native_non_blocking(
+ bool mode, boost::system::error_code& ec)
+ {
+ impl_.get_service().native_non_blocking(
+ impl_.get_implementation(), mode, ec);
+ BOOST_ASIO_SYNC_OP_VOID_RETURN(ec);
+ }
+
+ /// Get the local endpoint of the socket.
+ /**
+ * This function is used to obtain the locally bound endpoint of the socket.
+ *
+ * @returns An object that represents the local endpoint of the socket.
+ *
+ * @throws boost::system::system_error Thrown on failure.
+ *
+ * @par Example
+ * @code
+ * boost::asio::ip::tcp::socket socket(my_context);
+ * ...
+ * boost::asio::ip::tcp::endpoint endpoint = socket.local_endpoint();
+ * @endcode
+ */
+ endpoint_type local_endpoint() const
+ {
+ boost::system::error_code ec;
+ endpoint_type ep = impl_.get_service().local_endpoint(
+ impl_.get_implementation(), ec);
+ boost::asio::detail::throw_error(ec, "local_endpoint");
+ return ep;
+ }
+
+ /// Get the local endpoint of the socket.
+ /**
+ * This function is used to obtain the locally bound endpoint of the socket.
+ *
+ * @param ec Set to indicate what error occurred, if any.
+ *
+ * @returns An object that represents the local endpoint of the socket.
+ * Returns a default-constructed endpoint object if an error occurred.
+ *
+ * @par Example
+ * @code
+ * boost::asio::ip::tcp::socket socket(my_context);
+ * ...
+ * boost::system::error_code ec;
+ * boost::asio::ip::tcp::endpoint endpoint = socket.local_endpoint(ec);
+ * if (ec)
+ * {
+ * // An error occurred.
+ * }
+ * @endcode
+ */
+ endpoint_type local_endpoint(boost::system::error_code& ec) const
+ {
+ return impl_.get_service().local_endpoint(impl_.get_implementation(), ec);
+ }
+
+ /// Get the remote endpoint of the socket.
+ /**
+ * This function is used to obtain the remote endpoint of the socket.
+ *
+ * @returns An object that represents the remote endpoint of the socket.
+ *
+ * @throws boost::system::system_error Thrown on failure.
+ *
+ * @par Example
+ * @code
+ * boost::asio::ip::tcp::socket socket(my_context);
+ * ...
+ * boost::asio::ip::tcp::endpoint endpoint = socket.remote_endpoint();
+ * @endcode
+ */
+ endpoint_type remote_endpoint() const
+ {
+ boost::system::error_code ec;
+ endpoint_type ep = impl_.get_service().remote_endpoint(
+ impl_.get_implementation(), ec);
+ boost::asio::detail::throw_error(ec, "remote_endpoint");
+ return ep;
+ }
+
+ /// Get the remote endpoint of the socket.
+ /**
+ * This function is used to obtain the remote endpoint of the socket.
+ *
+ * @param ec Set to indicate what error occurred, if any.
+ *
+ * @returns An object that represents the remote endpoint of the socket.
+ * Returns a default-constructed endpoint object if an error occurred.
+ *
+ * @par Example
+ * @code
+ * boost::asio::ip::tcp::socket socket(my_context);
+ * ...
+ * boost::system::error_code ec;
+ * boost::asio::ip::tcp::endpoint endpoint = socket.remote_endpoint(ec);
+ * if (ec)
+ * {
+ * // An error occurred.
+ * }
+ * @endcode
+ */
+ endpoint_type remote_endpoint(boost::system::error_code& ec) const
+ {
+ return impl_.get_service().remote_endpoint(impl_.get_implementation(), ec);
+ }
+
+ /// Disable sends or receives on the socket.
+ /**
+ * This function is used to disable send operations, receive operations, or
+ * both.
+ *
+ * @param what Determines what types of operation will no longer be allowed.
+ *
+ * @throws boost::system::system_error Thrown on failure.
+ *
+ * @par Example
+ * Shutting down the send side of the socket:
+ * @code
+ * boost::asio::ip::tcp::socket socket(my_context);
+ * ...
+ * socket.shutdown(boost::asio::ip::tcp::socket::shutdown_send);
+ * @endcode
+ */
+ void shutdown(shutdown_type what)
+ {
+ boost::system::error_code ec;
+ impl_.get_service().shutdown(impl_.get_implementation(), what, ec);
+ boost::asio::detail::throw_error(ec, "shutdown");
+ }
+
+ /// Disable sends or receives on the socket.
+ /**
+ * This function is used to disable send operations, receive operations, or
+ * both.
+ *
+ * @param what Determines what types of operation will no longer be allowed.
+ *
+ * @param ec Set to indicate what error occurred, if any.
+ *
+ * @par Example
+ * Shutting down the send side of the socket:
+ * @code
+ * boost::asio::ip::tcp::socket socket(my_context);
+ * ...
+ * boost::system::error_code ec;
+ * socket.shutdown(boost::asio::ip::tcp::socket::shutdown_send, ec);
+ * if (ec)
+ * {
+ * // An error occurred.
+ * }
+ * @endcode
+ */
+ BOOST_ASIO_SYNC_OP_VOID shutdown(shutdown_type what,
+ boost::system::error_code& ec)
+ {
+ impl_.get_service().shutdown(impl_.get_implementation(), what, ec);
+ BOOST_ASIO_SYNC_OP_VOID_RETURN(ec);
+ }
+
+ /// Wait for the socket to become ready to read, ready to write, or to have
+ /// pending error conditions.
+ /**
+ * This function is used to perform a blocking wait for a socket to enter
+ * a ready to read, write or error condition state.
+ *
+ * @param w Specifies the desired socket state.
+ *
+ * @par Example
+ * Waiting for a socket to become readable.
+ * @code
+ * boost::asio::ip::tcp::socket socket(my_context);
+ * ...
+ * socket.wait(boost::asio::ip::tcp::socket::wait_read);
+ * @endcode
+ */
+ void wait(wait_type w)
+ {
+ boost::system::error_code ec;
+ impl_.get_service().wait(impl_.get_implementation(), w, ec);
+ boost::asio::detail::throw_error(ec, "wait");
+ }
+
+ /// Wait for the socket to become ready to read, ready to write, or to have
+ /// pending error conditions.
+ /**
+ * This function is used to perform a blocking wait for a socket to enter
+ * a ready to read, write or error condition state.
+ *
+ * @param w Specifies the desired socket state.
+ *
+ * @param ec Set to indicate what error occurred, if any.
+ *
+ * @par Example
+ * Waiting for a socket to become readable.
+ * @code
+ * boost::asio::ip::tcp::socket socket(my_context);
+ * ...
+ * boost::system::error_code ec;
+ * socket.wait(boost::asio::ip::tcp::socket::wait_read, ec);
+ * @endcode
+ */
+ BOOST_ASIO_SYNC_OP_VOID wait(wait_type w, boost::system::error_code& ec)
+ {
+ impl_.get_service().wait(impl_.get_implementation(), w, ec);
+ BOOST_ASIO_SYNC_OP_VOID_RETURN(ec);
+ }
+
+ /// Asynchronously wait for the socket to become ready to read, ready to
+ /// write, or to have pending error conditions.
+ /**
+ * This function is used to perform an asynchronous wait for a socket to enter
+ * a ready to read, write or error condition state.
+ *
+ * @param w Specifies the desired socket state.
+ *
+ * @param handler The handler to be called when the wait operation completes.
+ * Copies will be made of the handler as required. The function signature of
+ * the handler must be:
+ * @code void handler(
+ * const boost::system::error_code& error // Result of operation
+ * ); @endcode
+ * Regardless of whether the asynchronous operation completes immediately or
+ * not, the handler will not be invoked from within this function. On
+ * immediate completion, invocation of the handler will be performed in a
+ * manner equivalent to using boost::asio::post().
+ *
+ * @par Example
+ * @code
+ * void wait_handler(const boost::system::error_code& error)
+ * {
+ * if (!error)
+ * {
+ * // Wait succeeded.
+ * }
+ * }
+ *
+ * ...
+ *
+ * boost::asio::ip::tcp::socket socket(my_context);
+ * ...
+ * socket.async_wait(boost::asio::ip::tcp::socket::wait_read, wait_handler);
+ * @endcode
+ */
+ template <typename WaitHandler>
+ BOOST_ASIO_INITFN_RESULT_TYPE(WaitHandler,
+ void (boost::system::error_code))
+ async_wait(wait_type w, BOOST_ASIO_MOVE_ARG(WaitHandler) handler)
+ {
+ return async_initiate<WaitHandler, void (boost::system::error_code)>(
+ initiate_async_wait(), handler, this, w);
+ }
+
+protected:
+ /// Protected destructor to prevent deletion through this type.
+ /**
+ * This function destroys the socket, cancelling any outstanding asynchronous
+ * operations associated with the socket as if by calling @c cancel.
+ */
+ ~basic_socket_ext()
+ {
+ }
+
+#if defined(BOOST_ASIO_WINDOWS_RUNTIME)
+ detail::io_object_impl<
+ detail::null_socket_service<Protocol>, Executor> impl_;
+#elif defined(BOOST_ASIO_HAS_IOCP)
+ detail::io_object_impl<
+ detail::win_iocp_socket_service<Protocol>, Executor> impl_;
+#else
+ detail::io_object_impl<
+ detail::reactive_socket_service_ext<Protocol>, Executor> impl_;
+#endif
+
+private:
+ // Disallow copying and assignment.
+ basic_socket_ext(const basic_socket_ext&) BOOST_ASIO_DELETED;
+ basic_socket_ext& operator=(const basic_socket_ext&) BOOST_ASIO_DELETED;
+
+ struct initiate_async_connect
+ {
+ template <typename ConnectHandler>
+ void operator()(BOOST_ASIO_MOVE_ARG(ConnectHandler) handler,
+ basic_socket_ext* self, const endpoint_type& peer_endpoint,
+ const boost::system::error_code& open_ec) const
+ {
+ // If you get an error on the following line it means that your handler
+ // does not meet the documented type requirements for a ConnectHandler.
+ BOOST_ASIO_CONNECT_HANDLER_CHECK(ConnectHandler, handler) type_check;
+
+ if (open_ec)
+ {
+ boost::asio::post(self->impl_.get_executor(),
+ boost::asio::detail::bind_handler(
+ BOOST_ASIO_MOVE_CAST(ConnectHandler)(handler), open_ec));
+ }
+ else
+ {
+ detail::non_const_lvalue<ConnectHandler> handler2(handler);
+ self->impl_.get_service().async_connect(
+ self->impl_.get_implementation(), peer_endpoint,
+ handler2.value, self->impl_.get_implementation_executor());
+ }
+ }
+ };
+
+ struct initiate_async_wait
+ {
+ template <typename WaitHandler>
+ void operator()(BOOST_ASIO_MOVE_ARG(WaitHandler) handler,
+ basic_socket_ext* self, wait_type w) const
+ {
+ // If you get an error on the following line it means that your handler
+ // does not meet the documented type requirements for a WaitHandler.
+ BOOST_ASIO_WAIT_HANDLER_CHECK(WaitHandler, handler) type_check;
+
+ detail::non_const_lvalue<WaitHandler> handler2(handler);
+ self->impl_.get_service().async_wait(
+ self->impl_.get_implementation(), w, handler2.value,
+ self->impl_.get_implementation_executor());
+ }
+ };
+};
+
+} // namespace asio
+} // namespace boost
+
+#include <boost/asio/detail/pop_options.hpp>
+
+#endif // BOOST_ASIO_BASIC_SOCKET_EXT_HPP
diff --git a/implementation/helper/1.74/boost/asio/basic_socket_ext_local.hpp b/implementation/helper/1.74/boost/asio/basic_socket_ext_local.hpp
new file mode 100644
index 0000000..855d01c
--- /dev/null
+++ b/implementation/helper/1.74/boost/asio/basic_socket_ext_local.hpp
@@ -0,0 +1,1859 @@
+//
+// basic_socket_ext_local.hpp
+// ~~~~~~~~~~~~~~~~~~~~~~~~~~
+//
+// Copyright (c) 2003-2019 Christopher M. Kohlhoff (chris at kohlhoff dot com)
+// Copyright (c) 2018,2019 Bayerische Motoren Werke Aktiengesellschaft (BMW AG)
+//
+// Distributed under the Boost Software License, Version 1.0. (See accompanying
+// file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt)
+//
+
+#ifndef BOOST_ASIO_BASIC_SOCKET_EXT_LOCAL_HPP
+#define BOOST_ASIO_BASIC_SOCKET_EXT_LOCAL_HPP
+
+#if defined(_MSC_VER) && (_MSC_VER >= 1200)
+# pragma once
+#endif // defined(_MSC_VER) && (_MSC_VER >= 1200)
+
+#include <boost/asio/detail/config.hpp>
+#include <boost/asio/async_result.hpp>
+#include <boost/asio/detail/handler_type_requirements_ext.hpp>
+#include <boost/asio/detail/io_object_impl.hpp>
+#include <boost/asio/detail/non_const_lvalue.hpp>
+#include <boost/asio/detail/throw_error.hpp>
+#include <boost/asio/detail/type_traits.hpp>
+#include <boost/asio/error.hpp>
+#include <boost/asio/execution_context.hpp>
+#include <boost/asio/executor.hpp>
+#include <boost/asio/post.hpp>
+#include <boost/asio/socket_base.hpp>
+
+#if defined(BOOST_ASIO_WINDOWS_RUNTIME)
+# include <boost/asio/detail/null_socket_service.hpp>
+#elif defined(BOOST_ASIO_HAS_IOCP)
+# include <boost/asio/detail/win_iocp_socket_service.hpp>
+#else
+# include <boost/asio/detail/reactive_socket_service_ext_local.hpp>
+#endif
+
+#if defined(BOOST_ASIO_HAS_MOVE)
+# include <utility>
+#endif // defined(BOOST_ASIO_HAS_MOVE)
+
+#include <boost/asio/detail/push_options.hpp>
+
+namespace boost {
+namespace asio {
+
+#if !defined(BOOST_ASIO_BASIC_SOCKET_EXT_LOCAL_FWD_DECL)
+#define BOOST_ASIO_BASIC_SOCKET_EXT_LOCAL_FWD_DECL
+
+// Forward declaration with defaulted arguments.
+template <typename Protocol, typename Executor = executor>
+class basic_socket_ext_local;
+
+#endif // !defined(BOOST_ASIO_BASIC_SOCKET_EXT_LOCAL_FWD_DECL)
+
+/// Provides socket functionality.
+/**
+ * The basic_socket class template provides functionality that is common to both
+ * stream-oriented and datagram-oriented sockets.
+ *
+ * @par Thread Safety
+ * @e Distinct @e objects: Safe.@n
+ * @e Shared @e objects: Unsafe.
+ */
+template <typename Protocol, typename Executor>
+class basic_socket_ext_local
+ : public socket_base
+{
+public:
+ /// The type of the executor associated with the object.
+ typedef Executor executor_type;
+
+ /// Rebinds the socket type to another executor.
+ template <typename Executor1>
+ struct rebind_executor
+ {
+ /// The socket type when rebound to the specified executor.
+ typedef basic_socket_ext_local<Protocol, Executor1> other;
+ };
+
+ /// The native representation of a socket.
+#if defined(GENERATING_DOCUMENTATION)
+ typedef implementation_defined native_handle_type;
+#elif defined(BOOST_ASIO_WINDOWS_RUNTIME)
+ typedef typename detail::null_socket_service<
+ Protocol>::native_handle_type native_handle_type;
+#elif defined(BOOST_ASIO_HAS_IOCP)
+ typedef typename detail::win_iocp_socket_service<
+ Protocol>::native_handle_type native_handle_type;
+#else
+ typedef typename detail::reactive_socket_service_ext_local<
+ Protocol>::native_handle_type native_handle_type;
+#endif
+
+ /// The protocol type.
+ typedef Protocol protocol_type;
+
+ /// The endpoint type.
+ typedef typename Protocol::endpoint endpoint_type;
+
+#if !defined(BOOST_ASIO_NO_EXTENSIONS)
+ /// A basic_socket is always the lowest layer.
+ typedef basic_socket_ext_local<Protocol, Executor> lowest_layer_type;
+#endif // !defined(BOOST_ASIO_NO_EXTENSIONS)
+
+ /// Construct a basic_socket without opening it.
+ /**
+ * This constructor creates a socket without opening it.
+ *
+ * @param ex The I/O executor that the socket will use, by default, to
+ * dispatch handlers for any asynchronous operations performed on the socket.
+ */
+ explicit basic_socket_ext_local(const executor_type& ex)
+ : impl_(ex)
+ {
+ }
+
+ /// Construct a basic_socket without opening it.
+ /**
+ * This constructor creates a socket without opening it.
+ *
+ * @param context An execution context which provides the I/O executor that
+ * the socket will use, by default, to dispatch handlers for any asynchronous
+ * operations performed on the socket.
+ */
+ template <typename ExecutionContext>
+ explicit basic_socket_ext_local(ExecutionContext& context,
+ typename enable_if<
+ is_convertible<ExecutionContext&, execution_context&>::value
+ >::type* = 0)
+ : impl_(context)
+ {
+ }
+
+ /// Construct and open a basic_socket.
+ /**
+ * This constructor creates and opens a socket.
+ *
+ * @param ex The I/O executor that the socket will use, by default, to
+ * dispatch handlers for any asynchronous operations performed on the socket.
+ *
+ * @param protocol An object specifying protocol parameters to be used.
+ *
+ * @throws boost::system::system_error Thrown on failure.
+ */
+ basic_socket_ext_local(const executor_type& ex, const protocol_type& protocol)
+ : impl_(ex)
+ {
+ boost::system::error_code ec;
+ impl_.get_service().open(impl_.get_implementation(), protocol, ec);
+ boost::asio::detail::throw_error(ec, "open");
+ }
+
+ /// Construct and open a basic_socket.
+ /**
+ * This constructor creates and opens a socket.
+ *
+ * @param context An execution context which provides the I/O executor that
+ * the socket will use, by default, to dispatch handlers for any asynchronous
+ * operations performed on the socket.
+ *
+ * @param protocol An object specifying protocol parameters to be used.
+ *
+ * @throws boost::system::system_error Thrown on failure.
+ */
+ template <typename ExecutionContext>
+ basic_socket_ext_local(ExecutionContext& context, const protocol_type& protocol,
+ typename enable_if<
+ is_convertible<ExecutionContext&, execution_context&>::value
+ >::type* = 0)
+ : impl_(context)
+ {
+ boost::system::error_code ec;
+ impl_.get_service().open(impl_.get_implementation(), protocol, ec);
+ boost::asio::detail::throw_error(ec, "open");
+ }
+
+ /// Construct a basic_socket, opening it and binding it to the given local
+ /// endpoint.
+ /**
+ * This constructor creates a socket and automatically opens it bound to the
+ * specified endpoint on the local machine. The protocol used is the protocol
+ * associated with the given endpoint.
+ *
+ * @param ex The I/O executor that the socket will use, by default, to
+ * dispatch handlers for any asynchronous operations performed on the socket.
+ *
+ * @param endpoint An endpoint on the local machine to which the socket will
+ * be bound.
+ *
+ * @throws boost::system::system_error Thrown on failure.
+ */
+ basic_socket_ext_local(const executor_type& ex, const endpoint_type& endpoint)
+ : impl_(ex)
+ {
+ boost::system::error_code ec;
+ const protocol_type protocol = endpoint.protocol();
+ impl_.get_service().open(impl_.get_implementation(), protocol, ec);
+ boost::asio::detail::throw_error(ec, "open");
+ impl_.get_service().bind(impl_.get_implementation(), endpoint, ec);
+ boost::asio::detail::throw_error(ec, "bind");
+ }
+
+ /// Construct a basic_socket, opening it and binding it to the given local
+ /// endpoint.
+ /**
+ * This constructor creates a socket and automatically opens it bound to the
+ * specified endpoint on the local machine. The protocol used is the protocol
+ * associated with the given endpoint.
+ *
+ * @param context An execution context which provides the I/O executor that
+ * the socket will use, by default, to dispatch handlers for any asynchronous
+ * operations performed on the socket.
+ *
+ * @param endpoint An endpoint on the local machine to which the socket will
+ * be bound.
+ *
+ * @throws boost::system::system_error Thrown on failure.
+ */
+ template <typename ExecutionContext>
+ basic_socket_ext_local(ExecutionContext& context, const endpoint_type& endpoint,
+ typename enable_if<
+ is_convertible<ExecutionContext&, execution_context&>::value
+ >::type* = 0)
+ : impl_(context)
+ {
+ boost::system::error_code ec;
+ const protocol_type protocol = endpoint.protocol();
+ impl_.get_service().open(impl_.get_implementation(), protocol, ec);
+ boost::asio::detail::throw_error(ec, "open");
+ impl_.get_service().bind(impl_.get_implementation(), endpoint, ec);
+ boost::asio::detail::throw_error(ec, "bind");
+ }
+
+ /// Construct a basic_socket on an existing native socket.
+ /**
+ * This constructor creates a socket object to hold an existing native socket.
+ *
+ * @param ex The I/O executor that the socket will use, by default, to
+ * dispatch handlers for any asynchronous operations performed on the socket.
+ *
+ * @param protocol An object specifying protocol parameters to be used.
+ *
+ * @param native_socket A native socket.
+ *
+ * @throws boost::system::system_error Thrown on failure.
+ */
+ basic_socket_ext_local(const executor_type& ex, const protocol_type& protocol,
+ const native_handle_type& native_socket)
+ : impl_(ex)
+ {
+ boost::system::error_code ec;
+ impl_.get_service().assign(impl_.get_implementation(),
+ protocol, native_socket, ec);
+ boost::asio::detail::throw_error(ec, "assign");
+ }
+
+ /// Construct a basic_socket on an existing native socket.
+ /**
+ * This constructor creates a socket object to hold an existing native socket.
+ *
+ * @param context An execution context which provides the I/O executor that
+ * the socket will use, by default, to dispatch handlers for any asynchronous
+ * operations performed on the socket.
+ *
+ * @param protocol An object specifying protocol parameters to be used.
+ *
+ * @param native_socket A native socket.
+ *
+ * @throws boost::system::system_error Thrown on failure.
+ */
+ template <typename ExecutionContext>
+ basic_socket_ext_local(ExecutionContext& context, const protocol_type& protocol,
+ const native_handle_type& native_socket,
+ typename enable_if<
+ is_convertible<ExecutionContext&, execution_context&>::value
+ >::type* = 0)
+ : impl_(context)
+ {
+ boost::system::error_code ec;
+ impl_.get_service().assign(impl_.get_implementation(),
+ protocol, native_socket, ec);
+ boost::asio::detail::throw_error(ec, "assign");
+ }
+
+#if defined(BOOST_ASIO_HAS_MOVE) || defined(GENERATING_DOCUMENTATION)
+ /// Move-construct a basic_socket from another.
+ /**
+ * This constructor moves a socket from one object to another.
+ *
+ * @param other The other basic_socket object from which the move will
+ * occur.
+ *
+ * @note Following the move, the moved-from object is in the same state as if
+ * constructed using the @c basic_socket(const executor_type&) constructor.
+ */
+ basic_socket_ext_local(basic_socket_ext_local&& other)
+ : impl_(std::move(other.impl_))
+ {
+ }
+
+ /// Move-assign a basic_socket from another.
+ /**
+ * This assignment operator moves a socket from one object to another.
+ *
+ * @param other The other basic_socket object from which the move will
+ * occur.
+ *
+ * @note Following the move, the moved-from object is in the same state as if
+ * constructed using the @c basic_socket(const executor_type&) constructor.
+ */
+ basic_socket_ext_local& operator=(basic_socket_ext_local&& other)
+ {
+ impl_ = std::move(other.impl_);
+ return *this;
+ }
+
+ // All sockets have access to each other's implementations.
+ template <typename Protocol1, typename Executor1>
+ friend class basic_socket_ext_local;
+
+ /// Move-construct a basic_socket from a socket of another protocol type.
+ /**
+ * This constructor moves a socket from one object to another.
+ *
+ * @param other The other basic_socket object from which the move will
+ * occur.
+ *
+ * @note Following the move, the moved-from object is in the same state as if
+ * constructed using the @c basic_socket(const executor_type&) constructor.
+ */
+ template <typename Protocol1, typename Executor1>
+ basic_socket_ext_local(basic_socket_ext_local<Protocol1, Executor1>&& other,
+ typename enable_if<
+ is_convertible<Protocol1, Protocol>::value
+ && is_convertible<Executor1, Executor>::value
+ >::type* = 0)
+ : impl_(std::move(other.impl_))
+ {
+ }
+
+ /// Move-assign a basic_socket from a socket of another protocol type.
+ /**
+ * This assignment operator moves a socket from one object to another.
+ *
+ * @param other The other basic_socket object from which the move will
+ * occur.
+ *
+ * @note Following the move, the moved-from object is in the same state as if
+ * constructed using the @c basic_socket(const executor_type&) constructor.
+ */
+ template <typename Protocol1, typename Executor1>
+ typename enable_if<
+ is_convertible<Protocol1, Protocol>::value
+ && is_convertible<Executor1, Executor>::value,
+ basic_socket_ext_local&
+ >::type operator=(basic_socket_ext_local<Protocol1, Executor1> && other)
+ {
+ basic_socket_ext_local tmp(std::move(other));
+ impl_ = std::move(tmp.impl_);
+ return *this;
+ }
+#endif // defined(BOOST_ASIO_HAS_MOVE) || defined(GENERATING_DOCUMENTATION)
+
+ /// Get the executor associated with the object.
+ executor_type get_executor() BOOST_ASIO_NOEXCEPT
+ {
+ return impl_.get_executor();
+ }
+
+#if !defined(BOOST_ASIO_NO_EXTENSIONS)
+ /// Get a reference to the lowest layer.
+ /**
+ * This function returns a reference to the lowest layer in a stack of
+ * layers. Since a basic_socket cannot contain any further layers, it simply
+ * returns a reference to itself.
+ *
+ * @return A reference to the lowest layer in the stack of layers. Ownership
+ * is not transferred to the caller.
+ */
+ lowest_layer_type& lowest_layer()
+ {
+ return *this;
+ }
+
+ /// Get a const reference to the lowest layer.
+ /**
+ * This function returns a const reference to the lowest layer in a stack of
+ * layers. Since a basic_socket cannot contain any further layers, it simply
+ * returns a reference to itself.
+ *
+ * @return A const reference to the lowest layer in the stack of layers.
+ * Ownership is not transferred to the caller.
+ */
+ const lowest_layer_type& lowest_layer() const
+ {
+ return *this;
+ }
+#endif // !defined(BOOST_ASIO_NO_EXTENSIONS)
+
+ /// Open the socket using the specified protocol.
+ /**
+ * This function opens the socket so that it will use the specified protocol.
+ *
+ * @param protocol An object specifying protocol parameters to be used.
+ *
+ * @throws boost::system::system_error Thrown on failure.
+ *
+ * @par Example
+ * @code
+ * boost::asio::ip::tcp::socket socket(my_context);
+ * socket.open(boost::asio::ip::tcp::v4());
+ * @endcode
+ */
+ void open(const protocol_type& protocol = protocol_type())
+ {
+ boost::system::error_code ec;
+ impl_.get_service().open(impl_.get_implementation(), protocol, ec);
+ boost::asio::detail::throw_error(ec, "open");
+ }
+
+ /// Open the socket using the specified protocol.
+ /**
+ * This function opens the socket so that it will use the specified protocol.
+ *
+ * @param protocol An object specifying which protocol is to be used.
+ *
+ * @param ec Set to indicate what error occurred, if any.
+ *
+ * @par Example
+ * @code
+ * boost::asio::ip::tcp::socket socket(my_context);
+ * boost::system::error_code ec;
+ * socket.open(boost::asio::ip::tcp::v4(), ec);
+ * if (ec)
+ * {
+ * // An error occurred.
+ * }
+ * @endcode
+ */
+ BOOST_ASIO_SYNC_OP_VOID open(const protocol_type& protocol,
+ boost::system::error_code& ec)
+ {
+ impl_.get_service().open(impl_.get_implementation(), protocol, ec);
+ BOOST_ASIO_SYNC_OP_VOID_RETURN(ec);
+ }
+
+ /// Assign an existing native socket to the socket.
+ /*
+ * This function opens the socket to hold an existing native socket.
+ *
+ * @param protocol An object specifying which protocol is to be used.
+ *
+ * @param native_socket A native socket.
+ *
+ * @throws boost::system::system_error Thrown on failure.
+ */
+ void assign(const protocol_type& protocol,
+ const native_handle_type& native_socket)
+ {
+ boost::system::error_code ec;
+ impl_.get_service().assign(impl_.get_implementation(),
+ protocol, native_socket, ec);
+ boost::asio::detail::throw_error(ec, "assign");
+ }
+
+ /// Assign an existing native socket to the socket.
+ /*
+ * This function opens the socket to hold an existing native socket.
+ *
+ * @param protocol An object specifying which protocol is to be used.
+ *
+ * @param native_socket A native socket.
+ *
+ * @param ec Set to indicate what error occurred, if any.
+ */
+ BOOST_ASIO_SYNC_OP_VOID assign(const protocol_type& protocol,
+ const native_handle_type& native_socket, boost::system::error_code& ec)
+ {
+ impl_.get_service().assign(impl_.get_implementation(),
+ protocol, native_socket, ec);
+ BOOST_ASIO_SYNC_OP_VOID_RETURN(ec);
+ }
+
+ /// Determine whether the socket is open.
+ bool is_open() const
+ {
+ return impl_.get_service().is_open(impl_.get_implementation());
+ }
+
+ /// Close the socket.
+ /**
+ * This function is used to close the socket. Any asynchronous send, receive
+ * or connect operations will be cancelled immediately, and will complete
+ * with the boost::asio::error::operation_aborted error.
+ *
+ * @throws boost::system::system_error Thrown on failure. Note that, even if
+ * the function indicates an error, the underlying descriptor is closed.
+ *
+ * @note For portable behaviour with respect to graceful closure of a
+ * connected socket, call shutdown() before closing the socket.
+ */
+ void close()
+ {
+ boost::system::error_code ec;
+ impl_.get_service().close(impl_.get_implementation(), ec);
+ boost::asio::detail::throw_error(ec, "close");
+ }
+
+ /// Close the socket.
+ /**
+ * This function is used to close the socket. Any asynchronous send, receive
+ * or connect operations will be cancelled immediately, and will complete
+ * with the boost::asio::error::operation_aborted error.
+ *
+ * @param ec Set to indicate what error occurred, if any. Note that, even if
+ * the function indicates an error, the underlying descriptor is closed.
+ *
+ * @par Example
+ * @code
+ * boost::asio::ip::tcp::socket socket(my_context);
+ * ...
+ * boost::system::error_code ec;
+ * socket.close(ec);
+ * if (ec)
+ * {
+ * // An error occurred.
+ * }
+ * @endcode
+ *
+ * @note For portable behaviour with respect to graceful closure of a
+ * connected socket, call shutdown() before closing the socket.
+ */
+ BOOST_ASIO_SYNC_OP_VOID close(boost::system::error_code& ec)
+ {
+ impl_.get_service().close(impl_.get_implementation(), ec);
+ BOOST_ASIO_SYNC_OP_VOID_RETURN(ec);
+ }
+
+ /// Release ownership of the underlying native socket.
+ /**
+ * This function causes all outstanding asynchronous connect, send and receive
+ * operations to finish immediately, and the handlers for cancelled operations
+ * will be passed the boost::asio::error::operation_aborted error. Ownership
+ * of the native socket is then transferred to the caller.
+ *
+ * @throws boost::system::system_error Thrown on failure.
+ *
+ * @note This function is unsupported on Windows versions prior to Windows
+ * 8.1, and will fail with boost::asio::error::operation_not_supported on
+ * these platforms.
+ */
+#if defined(BOOST_ASIO_MSVC) && (BOOST_ASIO_MSVC >= 1400) \
+ && (!defined(_WIN32_WINNT) || _WIN32_WINNT < 0x0603)
+ __declspec(deprecated("This function always fails with "
+ "operation_not_supported when used on Windows versions "
+ "prior to Windows 8.1."))
+#endif
+ native_handle_type release()
+ {
+ boost::system::error_code ec;
+ native_handle_type s = impl_.get_service().release(
+ impl_.get_implementation(), ec);
+ boost::asio::detail::throw_error(ec, "release");
+ return s;
+ }
+
+ /// Release ownership of the underlying native socket.
+ /**
+ * This function causes all outstanding asynchronous connect, send and receive
+ * operations to finish immediately, and the handlers for cancelled operations
+ * will be passed the boost::asio::error::operation_aborted error. Ownership
+ * of the native socket is then transferred to the caller.
+ *
+ * @param ec Set to indicate what error occurred, if any.
+ *
+ * @note This function is unsupported on Windows versions prior to Windows
+ * 8.1, and will fail with boost::asio::error::operation_not_supported on
+ * these platforms.
+ */
+#if defined(BOOST_ASIO_MSVC) && (BOOST_ASIO_MSVC >= 1400) \
+ && (!defined(_WIN32_WINNT) || _WIN32_WINNT < 0x0603)
+ __declspec(deprecated("This function always fails with "
+ "operation_not_supported when used on Windows versions "
+ "prior to Windows 8.1."))
+#endif
+ native_handle_type release(boost::system::error_code& ec)
+ {
+ return impl_.get_service().release(impl_.get_implementation(), ec);
+ }
+
+ /// Get the native socket representation.
+ /**
+ * This function may be used to obtain the underlying representation of the
+ * socket. This is intended to allow access to native socket functionality
+ * that is not otherwise provided.
+ */
+ native_handle_type native_handle()
+ {
+ return impl_.get_service().native_handle(impl_.get_implementation());
+ }
+
+ /// Cancel all asynchronous operations associated with the socket.
+ /**
+ * This function causes all outstanding asynchronous connect, send and receive
+ * operations to finish immediately, and the handlers for cancelled operations
+ * will be passed the boost::asio::error::operation_aborted error.
+ *
+ * @throws boost::system::system_error Thrown on failure.
+ *
+ * @note Calls to cancel() will always fail with
+ * boost::asio::error::operation_not_supported when run on Windows XP, Windows
+ * Server 2003, and earlier versions of Windows, unless
+ * BOOST_ASIO_ENABLE_CANCELIO is defined. However, the CancelIo function has
+ * two issues that should be considered before enabling its use:
+ *
+ * @li It will only cancel asynchronous operations that were initiated in the
+ * current thread.
+ *
+ * @li It can appear to complete without error, but the request to cancel the
+ * unfinished operations may be silently ignored by the operating system.
+ * Whether it works or not seems to depend on the drivers that are installed.
+ *
+ * For portable cancellation, consider using one of the following
+ * alternatives:
+ *
+ * @li Disable asio's I/O completion port backend by defining
+ * BOOST_ASIO_DISABLE_IOCP.
+ *
+ * @li Use the close() function to simultaneously cancel the outstanding
+ * operations and close the socket.
+ *
+ * When running on Windows Vista, Windows Server 2008, and later, the
+ * CancelIoEx function is always used. This function does not have the
+ * problems described above.
+ */
+#if defined(BOOST_ASIO_MSVC) && (BOOST_ASIO_MSVC >= 1400) \
+ && (!defined(_WIN32_WINNT) || _WIN32_WINNT < 0x0600) \
+ && !defined(BOOST_ASIO_ENABLE_CANCELIO)
+ __declspec(deprecated("By default, this function always fails with "
+ "operation_not_supported when used on Windows XP, Windows Server 2003, "
+ "or earlier. Consult documentation for details."))
+#endif
+ void cancel()
+ {
+ boost::system::error_code ec;
+ impl_.get_service().cancel(impl_.get_implementation(), ec);
+ boost::asio::detail::throw_error(ec, "cancel");
+ }
+
+ /// Cancel all asynchronous operations associated with the socket.
+ /**
+ * This function causes all outstanding asynchronous connect, send and receive
+ * operations to finish immediately, and the handlers for cancelled operations
+ * will be passed the boost::asio::error::operation_aborted error.
+ *
+ * @param ec Set to indicate what error occurred, if any.
+ *
+ * @note Calls to cancel() will always fail with
+ * boost::asio::error::operation_not_supported when run on Windows XP, Windows
+ * Server 2003, and earlier versions of Windows, unless
+ * BOOST_ASIO_ENABLE_CANCELIO is defined. However, the CancelIo function has
+ * two issues that should be considered before enabling its use:
+ *
+ * @li It will only cancel asynchronous operations that were initiated in the
+ * current thread.
+ *
+ * @li It can appear to complete without error, but the request to cancel the
+ * unfinished operations may be silently ignored by the operating system.
+ * Whether it works or not seems to depend on the drivers that are installed.
+ *
+ * For portable cancellation, consider using one of the following
+ * alternatives:
+ *
+ * @li Disable asio's I/O completion port backend by defining
+ * BOOST_ASIO_DISABLE_IOCP.
+ *
+ * @li Use the close() function to simultaneously cancel the outstanding
+ * operations and close the socket.
+ *
+ * When running on Windows Vista, Windows Server 2008, and later, the
+ * CancelIoEx function is always used. This function does not have the
+ * problems described above.
+ */
+#if defined(BOOST_ASIO_MSVC) && (BOOST_ASIO_MSVC >= 1400) \
+ && (!defined(_WIN32_WINNT) || _WIN32_WINNT < 0x0600) \
+ && !defined(BOOST_ASIO_ENABLE_CANCELIO)
+ __declspec(deprecated("By default, this function always fails with "
+ "operation_not_supported when used on Windows XP, Windows Server 2003, "
+ "or earlier. Consult documentation for details."))
+#endif
+ BOOST_ASIO_SYNC_OP_VOID cancel(boost::system::error_code& ec)
+ {
+ impl_.get_service().cancel(impl_.get_implementation(), ec);
+ BOOST_ASIO_SYNC_OP_VOID_RETURN(ec);
+ }
+
+ /// Determine whether the socket is at the out-of-band data mark.
+ /**
+ * This function is used to check whether the socket input is currently
+ * positioned at the out-of-band data mark.
+ *
+ * @return A bool indicating whether the socket is at the out-of-band data
+ * mark.
+ *
+ * @throws boost::system::system_error Thrown on failure.
+ */
+ bool at_mark() const
+ {
+ boost::system::error_code ec;
+ bool b = impl_.get_service().at_mark(impl_.get_implementation(), ec);
+ boost::asio::detail::throw_error(ec, "at_mark");
+ return b;
+ }
+
+ /// Determine whether the socket is at the out-of-band data mark.
+ /**
+ * This function is used to check whether the socket input is currently
+ * positioned at the out-of-band data mark.
+ *
+ * @param ec Set to indicate what error occurred, if any.
+ *
+ * @return A bool indicating whether the socket is at the out-of-band data
+ * mark.
+ */
+ bool at_mark(boost::system::error_code& ec) const
+ {
+ return impl_.get_service().at_mark(impl_.get_implementation(), ec);
+ }
+
+ /// Determine the number of bytes available for reading.
+ /**
+ * This function is used to determine the number of bytes that may be read
+ * without blocking.
+ *
+ * @return The number of bytes that may be read without blocking, or 0 if an
+ * error occurs.
+ *
+ * @throws boost::system::system_error Thrown on failure.
+ */
+ std::size_t available() const
+ {
+ boost::system::error_code ec;
+ std::size_t s = impl_.get_service().available(
+ impl_.get_implementation(), ec);
+ boost::asio::detail::throw_error(ec, "available");
+ return s;
+ }
+
+ /// Determine the number of bytes available for reading.
+ /**
+ * This function is used to determine the number of bytes that may be read
+ * without blocking.
+ *
+ * @param ec Set to indicate what error occurred, if any.
+ *
+ * @return The number of bytes that may be read without blocking, or 0 if an
+ * error occurs.
+ */
+ std::size_t available(boost::system::error_code& ec) const
+ {
+ return impl_.get_service().available(impl_.get_implementation(), ec);
+ }
+
+ /// Bind the socket to the given local endpoint.
+ /**
+ * This function binds the socket to the specified endpoint on the local
+ * machine.
+ *
+ * @param endpoint An endpoint on the local machine to which the socket will
+ * be bound.
+ *
+ * @throws boost::system::system_error Thrown on failure.
+ *
+ * @par Example
+ * @code
+ * boost::asio::ip::tcp::socket socket(my_context);
+ * socket.open(boost::asio::ip::tcp::v4());
+ * socket.bind(boost::asio::ip::tcp::endpoint(
+ * boost::asio::ip::tcp::v4(), 12345));
+ * @endcode
+ */
+ void bind(const endpoint_type& endpoint)
+ {
+ boost::system::error_code ec;
+ impl_.get_service().bind(impl_.get_implementation(), endpoint, ec);
+ boost::asio::detail::throw_error(ec, "bind");
+ }
+
+ /// Bind the socket to the given local endpoint.
+ /**
+ * This function binds the socket to the specified endpoint on the local
+ * machine.
+ *
+ * @param endpoint An endpoint on the local machine to which the socket will
+ * be bound.
+ *
+ * @param ec Set to indicate what error occurred, if any.
+ *
+ * @par Example
+ * @code
+ * boost::asio::ip::tcp::socket socket(my_context);
+ * socket.open(boost::asio::ip::tcp::v4());
+ * boost::system::error_code ec;
+ * socket.bind(boost::asio::ip::tcp::endpoint(
+ * boost::asio::ip::tcp::v4(), 12345), ec);
+ * if (ec)
+ * {
+ * // An error occurred.
+ * }
+ * @endcode
+ */
+ BOOST_ASIO_SYNC_OP_VOID bind(const endpoint_type& endpoint,
+ boost::system::error_code& ec)
+ {
+ impl_.get_service().bind(impl_.get_implementation(), endpoint, ec);
+ BOOST_ASIO_SYNC_OP_VOID_RETURN(ec);
+ }
+
+ /// Connect the socket to the specified endpoint.
+ /**
+ * This function is used to connect a socket to the specified remote endpoint.
+ * The function call will block until the connection is successfully made or
+ * an error occurs.
+ *
+ * The socket is automatically opened if it is not already open. If the
+ * connect fails, and the socket was automatically opened, the socket is
+ * not returned to the closed state.
+ *
+ * @param peer_endpoint The remote endpoint to which the socket will be
+ * connected.
+ *
+ * @throws boost::system::system_error Thrown on failure.
+ *
+ * @par Example
+ * @code
+ * boost::asio::ip::tcp::socket socket(my_context);
+ * boost::asio::ip::tcp::endpoint endpoint(
+ * boost::asio::ip::address::from_string("1.2.3.4"), 12345);
+ * socket.connect(endpoint);
+ * @endcode
+ */
+ void connect(const endpoint_type& peer_endpoint)
+ {
+ boost::system::error_code ec;
+ if (!is_open())
+ {
+ impl_.get_service().open(impl_.get_implementation(),
+ peer_endpoint.protocol(), ec);
+ boost::asio::detail::throw_error(ec, "connect");
+ }
+ impl_.get_service().connect(impl_.get_implementation(), peer_endpoint, ec);
+ boost::asio::detail::throw_error(ec, "connect");
+ }
+
+ /// Connect the socket to the specified endpoint.
+ /**
+ * This function is used to connect a socket to the specified remote endpoint.
+ * The function call will block until the connection is successfully made or
+ * an error occurs.
+ *
+ * The socket is automatically opened if it is not already open. If the
+ * connect fails, and the socket was automatically opened, the socket is
+ * not returned to the closed state.
+ *
+ * @param peer_endpoint The remote endpoint to which the socket will be
+ * connected.
+ *
+ * @param ec Set to indicate what error occurred, if any.
+ *
+ * @par Example
+ * @code
+ * boost::asio::ip::tcp::socket socket(my_context);
+ * boost::asio::ip::tcp::endpoint endpoint(
+ * boost::asio::ip::address::from_string("1.2.3.4"), 12345);
+ * boost::system::error_code ec;
+ * socket.connect(endpoint, ec);
+ * if (ec)
+ * {
+ * // An error occurred.
+ * }
+ * @endcode
+ */
+ BOOST_ASIO_SYNC_OP_VOID connect(const endpoint_type& peer_endpoint,
+ boost::system::error_code& ec)
+ {
+ if (!is_open())
+ {
+ impl_.get_service().open(impl_.get_implementation(),
+ peer_endpoint.protocol(), ec);
+ if (ec)
+ {
+ BOOST_ASIO_SYNC_OP_VOID_RETURN(ec);
+ }
+ }
+
+ impl_.get_service().connect(impl_.get_implementation(), peer_endpoint, ec);
+ BOOST_ASIO_SYNC_OP_VOID_RETURN(ec);
+ }
+
+ /// Start an asynchronous connect.
+ /**
+ * This function is used to asynchronously connect a socket to the specified
+ * remote endpoint. The function call always returns immediately.
+ *
+ * The socket is automatically opened if it is not already open. If the
+ * connect fails, and the socket was automatically opened, the socket is
+ * not returned to the closed state.
+ *
+ * @param peer_endpoint The remote endpoint to which the socket will be
+ * connected. Copies will be made of the endpoint object as required.
+ *
+ * @param handler The handler to be called when the connection operation
+ * completes. Copies will be made of the handler as required. The function
+ * signature of the handler must be:
+ * @code void handler(
+ * const boost::system::error_code& error // Result of operation
+ * ); @endcode
+ * Regardless of whether the asynchronous operation completes immediately or
+ * not, the handler will not be invoked from within this function. On
+ * immediate completion, invocation of the handler will be performed in a
+ * manner equivalent to using boost::asio::post().
+ *
+ * @par Example
+ * @code
+ * void connect_handler(const boost::system::error_code& error)
+ * {
+ * if (!error)
+ * {
+ * // Connect succeeded.
+ * }
+ * }
+ *
+ * ...
+ *
+ * boost::asio::ip::tcp::socket socket(my_context);
+ * boost::asio::ip::tcp::endpoint endpoint(
+ * boost::asio::ip::address::from_string("1.2.3.4"), 12345);
+ * socket.async_connect(endpoint, connect_handler);
+ * @endcode
+ */
+ template <typename ConnectHandler>
+ BOOST_ASIO_INITFN_RESULT_TYPE(ConnectHandler,
+ void (boost::system::error_code))
+ async_connect(const endpoint_type& peer_endpoint,
+ BOOST_ASIO_MOVE_ARG(ConnectHandler) handler)
+ {
+ boost::system::error_code open_ec;
+ if (!is_open())
+ {
+ const protocol_type protocol = peer_endpoint.protocol();
+ impl_.get_service().open(impl_.get_implementation(), protocol, open_ec);
+ }
+
+ return async_initiate<ConnectHandler, void (boost::system::error_code)>(
+ initiate_async_connect(), handler, this, peer_endpoint, open_ec);
+ }
+
+ /// Set an option on the socket.
+ /**
+ * This function is used to set an option on the socket.
+ *
+ * @param option The new option value to be set on the socket.
+ *
+ * @throws boost::system::system_error Thrown on failure.
+ *
+ * @sa SettableSocketOption @n
+ * boost::asio::socket_base::broadcast @n
+ * boost::asio::socket_base::do_not_route @n
+ * boost::asio::socket_base::keep_alive @n
+ * boost::asio::socket_base::linger @n
+ * boost::asio::socket_base::receive_buffer_size @n
+ * boost::asio::socket_base::receive_low_watermark @n
+ * boost::asio::socket_base::reuse_address @n
+ * boost::asio::socket_base::send_buffer_size @n
+ * boost::asio::socket_base::send_low_watermark @n
+ * boost::asio::ip::multicast::join_group @n
+ * boost::asio::ip::multicast::leave_group @n
+ * boost::asio::ip::multicast::enable_loopback @n
+ * boost::asio::ip::multicast::outbound_interface @n
+ * boost::asio::ip::multicast::hops @n
+ * boost::asio::ip::tcp::no_delay
+ *
+ * @par Example
+ * Setting the IPPROTO_TCP/TCP_NODELAY option:
+ * @code
+ * boost::asio::ip::tcp::socket socket(my_context);
+ * ...
+ * boost::asio::ip::tcp::no_delay option(true);
+ * socket.set_option(option);
+ * @endcode
+ */
+ template <typename SettableSocketOption>
+ void set_option(const SettableSocketOption& option)
+ {
+ boost::system::error_code ec;
+ impl_.get_service().set_option(impl_.get_implementation(), option, ec);
+ boost::asio::detail::throw_error(ec, "set_option");
+ }
+
+ /// Set an option on the socket.
+ /**
+ * This function is used to set an option on the socket.
+ *
+ * @param option The new option value to be set on the socket.
+ *
+ * @param ec Set to indicate what error occurred, if any.
+ *
+ * @sa SettableSocketOption @n
+ * boost::asio::socket_base::broadcast @n
+ * boost::asio::socket_base::do_not_route @n
+ * boost::asio::socket_base::keep_alive @n
+ * boost::asio::socket_base::linger @n
+ * boost::asio::socket_base::receive_buffer_size @n
+ * boost::asio::socket_base::receive_low_watermark @n
+ * boost::asio::socket_base::reuse_address @n
+ * boost::asio::socket_base::send_buffer_size @n
+ * boost::asio::socket_base::send_low_watermark @n
+ * boost::asio::ip::multicast::join_group @n
+ * boost::asio::ip::multicast::leave_group @n
+ * boost::asio::ip::multicast::enable_loopback @n
+ * boost::asio::ip::multicast::outbound_interface @n
+ * boost::asio::ip::multicast::hops @n
+ * boost::asio::ip::tcp::no_delay
+ *
+ * @par Example
+ * Setting the IPPROTO_TCP/TCP_NODELAY option:
+ * @code
+ * boost::asio::ip::tcp::socket socket(my_context);
+ * ...
+ * boost::asio::ip::tcp::no_delay option(true);
+ * boost::system::error_code ec;
+ * socket.set_option(option, ec);
+ * if (ec)
+ * {
+ * // An error occurred.
+ * }
+ * @endcode
+ */
+ template <typename SettableSocketOption>
+ BOOST_ASIO_SYNC_OP_VOID set_option(const SettableSocketOption& option,
+ boost::system::error_code& ec)
+ {
+ impl_.get_service().set_option(impl_.get_implementation(), option, ec);
+ BOOST_ASIO_SYNC_OP_VOID_RETURN(ec);
+ }
+
+ /// Get an option from the socket.
+ /**
+ * This function is used to get the current value of an option on the socket.
+ *
+ * @param option The option value to be obtained from the socket.
+ *
+ * @throws boost::system::system_error Thrown on failure.
+ *
+ * @sa GettableSocketOption @n
+ * boost::asio::socket_base::broadcast @n
+ * boost::asio::socket_base::do_not_route @n
+ * boost::asio::socket_base::keep_alive @n
+ * boost::asio::socket_base::linger @n
+ * boost::asio::socket_base::receive_buffer_size @n
+ * boost::asio::socket_base::receive_low_watermark @n
+ * boost::asio::socket_base::reuse_address @n
+ * boost::asio::socket_base::send_buffer_size @n
+ * boost::asio::socket_base::send_low_watermark @n
+ * boost::asio::ip::multicast::join_group @n
+ * boost::asio::ip::multicast::leave_group @n
+ * boost::asio::ip::multicast::enable_loopback @n
+ * boost::asio::ip::multicast::outbound_interface @n
+ * boost::asio::ip::multicast::hops @n
+ * boost::asio::ip::tcp::no_delay
+ *
+ * @par Example
+ * Getting the value of the SOL_SOCKET/SO_KEEPALIVE option:
+ * @code
+ * boost::asio::ip::tcp::socket socket(my_context);
+ * ...
+ * boost::asio::ip::tcp::socket::keep_alive option;
+ * socket.get_option(option);
+ * bool is_set = option.value();
+ * @endcode
+ */
+ template <typename GettableSocketOption>
+ void get_option(GettableSocketOption& option) const
+ {
+ boost::system::error_code ec;
+ impl_.get_service().get_option(impl_.get_implementation(), option, ec);
+ boost::asio::detail::throw_error(ec, "get_option");
+ }
+
+ /// Get an option from the socket.
+ /**
+ * This function is used to get the current value of an option on the socket.
+ *
+ * @param option The option value to be obtained from the socket.
+ *
+ * @param ec Set to indicate what error occurred, if any.
+ *
+ * @sa GettableSocketOption @n
+ * boost::asio::socket_base::broadcast @n
+ * boost::asio::socket_base::do_not_route @n
+ * boost::asio::socket_base::keep_alive @n
+ * boost::asio::socket_base::linger @n
+ * boost::asio::socket_base::receive_buffer_size @n
+ * boost::asio::socket_base::receive_low_watermark @n
+ * boost::asio::socket_base::reuse_address @n
+ * boost::asio::socket_base::send_buffer_size @n
+ * boost::asio::socket_base::send_low_watermark @n
+ * boost::asio::ip::multicast::join_group @n
+ * boost::asio::ip::multicast::leave_group @n
+ * boost::asio::ip::multicast::enable_loopback @n
+ * boost::asio::ip::multicast::outbound_interface @n
+ * boost::asio::ip::multicast::hops @n
+ * boost::asio::ip::tcp::no_delay
+ *
+ * @par Example
+ * Getting the value of the SOL_SOCKET/SO_KEEPALIVE option:
+ * @code
+ * boost::asio::ip::tcp::socket socket(my_context);
+ * ...
+ * boost::asio::ip::tcp::socket::keep_alive option;
+ * boost::system::error_code ec;
+ * socket.get_option(option, ec);
+ * if (ec)
+ * {
+ * // An error occurred.
+ * }
+ * bool is_set = option.value();
+ * @endcode
+ */
+ template <typename GettableSocketOption>
+ BOOST_ASIO_SYNC_OP_VOID get_option(GettableSocketOption& option,
+ boost::system::error_code& ec) const
+ {
+ impl_.get_service().get_option(impl_.get_implementation(), option, ec);
+ BOOST_ASIO_SYNC_OP_VOID_RETURN(ec);
+ }
+
+ /// Perform an IO control command on the socket.
+ /**
+ * This function is used to execute an IO control command on the socket.
+ *
+ * @param command The IO control command to be performed on the socket.
+ *
+ * @throws boost::system::system_error Thrown on failure.
+ *
+ * @sa IoControlCommand @n
+ * boost::asio::socket_base::bytes_readable @n
+ * boost::asio::socket_base::non_blocking_io
+ *
+ * @par Example
+ * Getting the number of bytes ready to read:
+ * @code
+ * boost::asio::ip::tcp::socket socket(my_context);
+ * ...
+ * boost::asio::ip::tcp::socket::bytes_readable command;
+ * socket.io_control(command);
+ * std::size_t bytes_readable = command.get();
+ * @endcode
+ */
+ template <typename IoControlCommand>
+ void io_control(IoControlCommand& command)
+ {
+ boost::system::error_code ec;
+ impl_.get_service().io_control(impl_.get_implementation(), command, ec);
+ boost::asio::detail::throw_error(ec, "io_control");
+ }
+
+ /// Perform an IO control command on the socket.
+ /**
+ * This function is used to execute an IO control command on the socket.
+ *
+ * @param command The IO control command to be performed on the socket.
+ *
+ * @param ec Set to indicate what error occurred, if any.
+ *
+ * @sa IoControlCommand @n
+ * boost::asio::socket_base::bytes_readable @n
+ * boost::asio::socket_base::non_blocking_io
+ *
+ * @par Example
+ * Getting the number of bytes ready to read:
+ * @code
+ * boost::asio::ip::tcp::socket socket(my_context);
+ * ...
+ * boost::asio::ip::tcp::socket::bytes_readable command;
+ * boost::system::error_code ec;
+ * socket.io_control(command, ec);
+ * if (ec)
+ * {
+ * // An error occurred.
+ * }
+ * std::size_t bytes_readable = command.get();
+ * @endcode
+ */
+ template <typename IoControlCommand>
+ BOOST_ASIO_SYNC_OP_VOID io_control(IoControlCommand& command,
+ boost::system::error_code& ec)
+ {
+ impl_.get_service().io_control(impl_.get_implementation(), command, ec);
+ BOOST_ASIO_SYNC_OP_VOID_RETURN(ec);
+ }
+
+ /// Gets the non-blocking mode of the socket.
+ /**
+ * @returns @c true if the socket's synchronous operations will fail with
+ * boost::asio::error::would_block if they are unable to perform the requested
+ * operation immediately. If @c false, synchronous operations will block
+ * until complete.
+ *
+ * @note The non-blocking mode has no effect on the behaviour of asynchronous
+ * operations. Asynchronous operations will never fail with the error
+ * boost::asio::error::would_block.
+ */
+ bool non_blocking() const
+ {
+ return impl_.get_service().non_blocking(impl_.get_implementation());
+ }
+
+ /// Sets the non-blocking mode of the socket.
+ /**
+ * @param mode If @c true, the socket's synchronous operations will fail with
+ * boost::asio::error::would_block if they are unable to perform the requested
+ * operation immediately. If @c false, synchronous operations will block
+ * until complete.
+ *
+ * @throws boost::system::system_error Thrown on failure.
+ *
+ * @note The non-blocking mode has no effect on the behaviour of asynchronous
+ * operations. Asynchronous operations will never fail with the error
+ * boost::asio::error::would_block.
+ */
+ void non_blocking(bool mode)
+ {
+ boost::system::error_code ec;
+ impl_.get_service().non_blocking(impl_.get_implementation(), mode, ec);
+ boost::asio::detail::throw_error(ec, "non_blocking");
+ }
+
+ /// Sets the non-blocking mode of the socket.
+ /**
+ * @param mode If @c true, the socket's synchronous operations will fail with
+ * boost::asio::error::would_block if they are unable to perform the requested
+ * operation immediately. If @c false, synchronous operations will block
+ * until complete.
+ *
+ * @param ec Set to indicate what error occurred, if any.
+ *
+ * @note The non-blocking mode has no effect on the behaviour of asynchronous
+ * operations. Asynchronous operations will never fail with the error
+ * boost::asio::error::would_block.
+ */
+ BOOST_ASIO_SYNC_OP_VOID non_blocking(
+ bool mode, boost::system::error_code& ec)
+ {
+ impl_.get_service().non_blocking(impl_.get_implementation(), mode, ec);
+ BOOST_ASIO_SYNC_OP_VOID_RETURN(ec);
+ }
+
+ /// Gets the non-blocking mode of the native socket implementation.
+ /**
+ * This function is used to retrieve the non-blocking mode of the underlying
+ * native socket. This mode has no effect on the behaviour of the socket
+ * object's synchronous operations.
+ *
+ * @returns @c true if the underlying socket is in non-blocking mode and
+ * direct system calls may fail with boost::asio::error::would_block (or the
+ * equivalent system error).
+ *
+ * @note The current non-blocking mode is cached by the socket object.
+ * Consequently, the return value may be incorrect if the non-blocking mode
+ * was set directly on the native socket.
+ *
+ * @par Example
+ * This function is intended to allow the encapsulation of arbitrary
+ * non-blocking system calls as asynchronous operations, in a way that is
+ * transparent to the user of the socket object. The following example
+ * illustrates how Linux's @c sendfile system call might be encapsulated:
+ * @code template <typename Handler>
+ * struct sendfile_op
+ * {
+ * tcp::socket& sock_;
+ * int fd_;
+ * Handler handler_;
+ * off_t offset_;
+ * std::size_t total_bytes_transferred_;
+ *
+ * // Function call operator meeting WriteHandler requirements.
+ * // Used as the handler for the async_write_some operation.
+ * void operator()(boost::system::error_code ec, std::size_t)
+ * {
+ * // Put the underlying socket into non-blocking mode.
+ * if (!ec)
+ * if (!sock_.native_non_blocking())
+ * sock_.native_non_blocking(true, ec);
+ *
+ * if (!ec)
+ * {
+ * for (;;)
+ * {
+ * // Try the system call.
+ * errno = 0;
+ * int n = ::sendfile(sock_.native_handle(), fd_, &offset_, 65536);
+ * ec = boost::system::error_code(n < 0 ? errno : 0,
+ * boost::asio::error::get_system_category());
+ * total_bytes_transferred_ += ec ? 0 : n;
+ *
+ * // Retry operation immediately if interrupted by signal.
+ * if (ec == boost::asio::error::interrupted)
+ * continue;
+ *
+ * // Check if we need to run the operation again.
+ * if (ec == boost::asio::error::would_block
+ * || ec == boost::asio::error::try_again)
+ * {
+ * // We have to wait for the socket to become ready again.
+ * sock_.async_wait(tcp::socket::wait_write, *this);
+ * return;
+ * }
+ *
+ * if (ec || n == 0)
+ * {
+ * // An error occurred, or we have reached the end of the file.
+ * // Either way we must exit the loop so we can call the handler.
+ * break;
+ * }
+ *
+ * // Loop around to try calling sendfile again.
+ * }
+ * }
+ *
+ * // Pass result back to user's handler.
+ * handler_(ec, total_bytes_transferred_);
+ * }
+ * };
+ *
+ * template <typename Handler>
+ * void async_sendfile(tcp::socket& sock, int fd, Handler h)
+ * {
+ * sendfile_op<Handler> op = { sock, fd, h, 0, 0 };
+ * sock.async_wait(tcp::socket::wait_write, op);
+ * } @endcode
+ */
+ bool native_non_blocking() const
+ {
+ return impl_.get_service().native_non_blocking(impl_.get_implementation());
+ }
+
+ /// Sets the non-blocking mode of the native socket implementation.
+ /**
+ * This function is used to modify the non-blocking mode of the underlying
+ * native socket. It has no effect on the behaviour of the socket object's
+ * synchronous operations.
+ *
+ * @param mode If @c true, the underlying socket is put into non-blocking
+ * mode and direct system calls may fail with boost::asio::error::would_block
+ * (or the equivalent system error).
+ *
+ * @throws boost::system::system_error Thrown on failure. If the @c mode is
+ * @c false, but the current value of @c non_blocking() is @c true, this
+ * function fails with boost::asio::error::invalid_argument, as the
+ * combination does not make sense.
+ *
+ * @par Example
+ * This function is intended to allow the encapsulation of arbitrary
+ * non-blocking system calls as asynchronous operations, in a way that is
+ * transparent to the user of the socket object. The following example
+ * illustrates how Linux's @c sendfile system call might be encapsulated:
+ * @code template <typename Handler>
+ * struct sendfile_op
+ * {
+ * tcp::socket& sock_;
+ * int fd_;
+ * Handler handler_;
+ * off_t offset_;
+ * std::size_t total_bytes_transferred_;
+ *
+ * // Function call operator meeting WriteHandler requirements.
+ * // Used as the handler for the async_write_some operation.
+ * void operator()(boost::system::error_code ec, std::size_t)
+ * {
+ * // Put the underlying socket into non-blocking mode.
+ * if (!ec)
+ * if (!sock_.native_non_blocking())
+ * sock_.native_non_blocking(true, ec);
+ *
+ * if (!ec)
+ * {
+ * for (;;)
+ * {
+ * // Try the system call.
+ * errno = 0;
+ * int n = ::sendfile(sock_.native_handle(), fd_, &offset_, 65536);
+ * ec = boost::system::error_code(n < 0 ? errno : 0,
+ * boost::asio::error::get_system_category());
+ * total_bytes_transferred_ += ec ? 0 : n;
+ *
+ * // Retry operation immediately if interrupted by signal.
+ * if (ec == boost::asio::error::interrupted)
+ * continue;
+ *
+ * // Check if we need to run the operation again.
+ * if (ec == boost::asio::error::would_block
+ * || ec == boost::asio::error::try_again)
+ * {
+ * // We have to wait for the socket to become ready again.
+ * sock_.async_wait(tcp::socket::wait_write, *this);
+ * return;
+ * }
+ *
+ * if (ec || n == 0)
+ * {
+ * // An error occurred, or we have reached the end of the file.
+ * // Either way we must exit the loop so we can call the handler.
+ * break;
+ * }
+ *
+ * // Loop around to try calling sendfile again.
+ * }
+ * }
+ *
+ * // Pass result back to user's handler.
+ * handler_(ec, total_bytes_transferred_);
+ * }
+ * };
+ *
+ * template <typename Handler>
+ * void async_sendfile(tcp::socket& sock, int fd, Handler h)
+ * {
+ * sendfile_op<Handler> op = { sock, fd, h, 0, 0 };
+ * sock.async_wait(tcp::socket::wait_write, op);
+ * } @endcode
+ */
+ void native_non_blocking(bool mode)
+ {
+ boost::system::error_code ec;
+ impl_.get_service().native_non_blocking(
+ impl_.get_implementation(), mode, ec);
+ boost::asio::detail::throw_error(ec, "native_non_blocking");
+ }
+
+ /// Sets the non-blocking mode of the native socket implementation.
+ /**
+ * This function is used to modify the non-blocking mode of the underlying
+ * native socket. It has no effect on the behaviour of the socket object's
+ * synchronous operations.
+ *
+ * @param mode If @c true, the underlying socket is put into non-blocking
+ * mode and direct system calls may fail with boost::asio::error::would_block
+ * (or the equivalent system error).
+ *
+ * @param ec Set to indicate what error occurred, if any. If the @c mode is
+ * @c false, but the current value of @c non_blocking() is @c true, this
+ * function fails with boost::asio::error::invalid_argument, as the
+ * combination does not make sense.
+ *
+ * @par Example
+ * This function is intended to allow the encapsulation of arbitrary
+ * non-blocking system calls as asynchronous operations, in a way that is
+ * transparent to the user of the socket object. The following example
+ * illustrates how Linux's @c sendfile system call might be encapsulated:
+ * @code template <typename Handler>
+ * struct sendfile_op
+ * {
+ * tcp::socket& sock_;
+ * int fd_;
+ * Handler handler_;
+ * off_t offset_;
+ * std::size_t total_bytes_transferred_;
+ *
+ * // Function call operator meeting WriteHandler requirements.
+ * // Used as the handler for the async_write_some operation.
+ * void operator()(boost::system::error_code ec, std::size_t)
+ * {
+ * // Put the underlying socket into non-blocking mode.
+ * if (!ec)
+ * if (!sock_.native_non_blocking())
+ * sock_.native_non_blocking(true, ec);
+ *
+ * if (!ec)
+ * {
+ * for (;;)
+ * {
+ * // Try the system call.
+ * errno = 0;
+ * int n = ::sendfile(sock_.native_handle(), fd_, &offset_, 65536);
+ * ec = boost::system::error_code(n < 0 ? errno : 0,
+ * boost::asio::error::get_system_category());
+ * total_bytes_transferred_ += ec ? 0 : n;
+ *
+ * // Retry operation immediately if interrupted by signal.
+ * if (ec == boost::asio::error::interrupted)
+ * continue;
+ *
+ * // Check if we need to run the operation again.
+ * if (ec == boost::asio::error::would_block
+ * || ec == boost::asio::error::try_again)
+ * {
+ * // We have to wait for the socket to become ready again.
+ * sock_.async_wait(tcp::socket::wait_write, *this);
+ * return;
+ * }
+ *
+ * if (ec || n == 0)
+ * {
+ * // An error occurred, or we have reached the end of the file.
+ * // Either way we must exit the loop so we can call the handler.
+ * break;
+ * }
+ *
+ * // Loop around to try calling sendfile again.
+ * }
+ * }
+ *
+ * // Pass result back to user's handler.
+ * handler_(ec, total_bytes_transferred_);
+ * }
+ * };
+ *
+ * template <typename Handler>
+ * void async_sendfile(tcp::socket& sock, int fd, Handler h)
+ * {
+ * sendfile_op<Handler> op = { sock, fd, h, 0, 0 };
+ * sock.async_wait(tcp::socket::wait_write, op);
+ * } @endcode
+ */
+ BOOST_ASIO_SYNC_OP_VOID native_non_blocking(
+ bool mode, boost::system::error_code& ec)
+ {
+ impl_.get_service().native_non_blocking(
+ impl_.get_implementation(), mode, ec);
+ BOOST_ASIO_SYNC_OP_VOID_RETURN(ec);
+ }
+
+ /// Get the local endpoint of the socket.
+ /**
+ * This function is used to obtain the locally bound endpoint of the socket.
+ *
+ * @returns An object that represents the local endpoint of the socket.
+ *
+ * @throws boost::system::system_error Thrown on failure.
+ *
+ * @par Example
+ * @code
+ * boost::asio::ip::tcp::socket socket(my_context);
+ * ...
+ * boost::asio::ip::tcp::endpoint endpoint = socket.local_endpoint();
+ * @endcode
+ */
+ endpoint_type local_endpoint() const
+ {
+ boost::system::error_code ec;
+ endpoint_type ep = impl_.get_service().local_endpoint(
+ impl_.get_implementation(), ec);
+ boost::asio::detail::throw_error(ec, "local_endpoint");
+ return ep;
+ }
+
+ /// Get the local endpoint of the socket.
+ /**
+ * This function is used to obtain the locally bound endpoint of the socket.
+ *
+ * @param ec Set to indicate what error occurred, if any.
+ *
+ * @returns An object that represents the local endpoint of the socket.
+ * Returns a default-constructed endpoint object if an error occurred.
+ *
+ * @par Example
+ * @code
+ * boost::asio::ip::tcp::socket socket(my_context);
+ * ...
+ * boost::system::error_code ec;
+ * boost::asio::ip::tcp::endpoint endpoint = socket.local_endpoint(ec);
+ * if (ec)
+ * {
+ * // An error occurred.
+ * }
+ * @endcode
+ */
+ endpoint_type local_endpoint(boost::system::error_code& ec) const
+ {
+ return impl_.get_service().local_endpoint(impl_.get_implementation(), ec);
+ }
+
+ /// Get the remote endpoint of the socket.
+ /**
+ * This function is used to obtain the remote endpoint of the socket.
+ *
+ * @returns An object that represents the remote endpoint of the socket.
+ *
+ * @throws boost::system::system_error Thrown on failure.
+ *
+ * @par Example
+ * @code
+ * boost::asio::ip::tcp::socket socket(my_context);
+ * ...
+ * boost::asio::ip::tcp::endpoint endpoint = socket.remote_endpoint();
+ * @endcode
+ */
+ endpoint_type remote_endpoint() const
+ {
+ boost::system::error_code ec;
+ endpoint_type ep = impl_.get_service().remote_endpoint(
+ impl_.get_implementation(), ec);
+ boost::asio::detail::throw_error(ec, "remote_endpoint");
+ return ep;
+ }
+
+ /// Get the remote endpoint of the socket.
+ /**
+ * This function is used to obtain the remote endpoint of the socket.
+ *
+ * @param ec Set to indicate what error occurred, if any.
+ *
+ * @returns An object that represents the remote endpoint of the socket.
+ * Returns a default-constructed endpoint object if an error occurred.
+ *
+ * @par Example
+ * @code
+ * boost::asio::ip::tcp::socket socket(my_context);
+ * ...
+ * boost::system::error_code ec;
+ * boost::asio::ip::tcp::endpoint endpoint = socket.remote_endpoint(ec);
+ * if (ec)
+ * {
+ * // An error occurred.
+ * }
+ * @endcode
+ */
+ endpoint_type remote_endpoint(boost::system::error_code& ec) const
+ {
+ return impl_.get_service().remote_endpoint(impl_.get_implementation(), ec);
+ }
+
+ /// Disable sends or receives on the socket.
+ /**
+ * This function is used to disable send operations, receive operations, or
+ * both.
+ *
+ * @param what Determines what types of operation will no longer be allowed.
+ *
+ * @throws boost::system::system_error Thrown on failure.
+ *
+ * @par Example
+ * Shutting down the send side of the socket:
+ * @code
+ * boost::asio::ip::tcp::socket socket(my_context);
+ * ...
+ * socket.shutdown(boost::asio::ip::tcp::socket::shutdown_send);
+ * @endcode
+ */
+ void shutdown(shutdown_type what)
+ {
+ boost::system::error_code ec;
+ impl_.get_service().shutdown(impl_.get_implementation(), what, ec);
+ boost::asio::detail::throw_error(ec, "shutdown");
+ }
+
+ /// Disable sends or receives on the socket.
+ /**
+ * This function is used to disable send operations, receive operations, or
+ * both.
+ *
+ * @param what Determines what types of operation will no longer be allowed.
+ *
+ * @param ec Set to indicate what error occurred, if any.
+ *
+ * @par Example
+ * Shutting down the send side of the socket:
+ * @code
+ * boost::asio::ip::tcp::socket socket(my_context);
+ * ...
+ * boost::system::error_code ec;
+ * socket.shutdown(boost::asio::ip::tcp::socket::shutdown_send, ec);
+ * if (ec)
+ * {
+ * // An error occurred.
+ * }
+ * @endcode
+ */
+ BOOST_ASIO_SYNC_OP_VOID shutdown(shutdown_type what,
+ boost::system::error_code& ec)
+ {
+ impl_.get_service().shutdown(impl_.get_implementation(), what, ec);
+ BOOST_ASIO_SYNC_OP_VOID_RETURN(ec);
+ }
+
+ /// Wait for the socket to become ready to read, ready to write, or to have
+ /// pending error conditions.
+ /**
+ * This function is used to perform a blocking wait for a socket to enter
+ * a ready to read, write or error condition state.
+ *
+ * @param w Specifies the desired socket state.
+ *
+ * @par Example
+ * Waiting for a socket to become readable.
+ * @code
+ * boost::asio::ip::tcp::socket socket(my_context);
+ * ...
+ * socket.wait(boost::asio::ip::tcp::socket::wait_read);
+ * @endcode
+ */
+ void wait(wait_type w)
+ {
+ boost::system::error_code ec;
+ impl_.get_service().wait(impl_.get_implementation(), w, ec);
+ boost::asio::detail::throw_error(ec, "wait");
+ }
+
+ /// Wait for the socket to become ready to read, ready to write, or to have
+ /// pending error conditions.
+ /**
+ * This function is used to perform a blocking wait for a socket to enter
+ * a ready to read, write or error condition state.
+ *
+ * @param w Specifies the desired socket state.
+ *
+ * @param ec Set to indicate what error occurred, if any.
+ *
+ * @par Example
+ * Waiting for a socket to become readable.
+ * @code
+ * boost::asio::ip::tcp::socket socket(my_context);
+ * ...
+ * boost::system::error_code ec;
+ * socket.wait(boost::asio::ip::tcp::socket::wait_read, ec);
+ * @endcode
+ */
+ BOOST_ASIO_SYNC_OP_VOID wait(wait_type w, boost::system::error_code& ec)
+ {
+ impl_.get_service().wait(impl_.get_implementation(), w, ec);
+ BOOST_ASIO_SYNC_OP_VOID_RETURN(ec);
+ }
+
+ /// Asynchronously wait for the socket to become ready to read, ready to
+ /// write, or to have pending error conditions.
+ /**
+ * This function is used to perform an asynchronous wait for a socket to enter
+ * a ready to read, write or error condition state.
+ *
+ * @param w Specifies the desired socket state.
+ *
+ * @param handler The handler to be called when the wait operation completes.
+ * Copies will be made of the handler as required. The function signature of
+ * the handler must be:
+ * @code void handler(
+ * const boost::system::error_code& error // Result of operation
+ * ); @endcode
+ * Regardless of whether the asynchronous operation completes immediately or
+ * not, the handler will not be invoked from within this function. On
+ * immediate completion, invocation of the handler will be performed in a
+ * manner equivalent to using boost::asio::post().
+ *
+ * @par Example
+ * @code
+ * void wait_handler(const boost::system::error_code& error)
+ * {
+ * if (!error)
+ * {
+ * // Wait succeeded.
+ * }
+ * }
+ *
+ * ...
+ *
+ * boost::asio::ip::tcp::socket socket(my_context);
+ * ...
+ * socket.async_wait(boost::asio::ip::tcp::socket::wait_read, wait_handler);
+ * @endcode
+ */
+ template <typename WaitHandler>
+ BOOST_ASIO_INITFN_RESULT_TYPE(WaitHandler,
+ void (boost::system::error_code))
+ async_wait(wait_type w, BOOST_ASIO_MOVE_ARG(WaitHandler) handler)
+ {
+ return async_initiate<WaitHandler, void (boost::system::error_code)>(
+ initiate_async_wait(), handler, this, w);
+ }
+
+protected:
+ /// Protected destructor to prevent deletion through this type.
+ /**
+ * This function destroys the socket, cancelling any outstanding asynchronous
+ * operations associated with the socket as if by calling @c cancel.
+ */
+ ~basic_socket_ext_local()
+ {
+ }
+
+#if defined(BOOST_ASIO_WINDOWS_RUNTIME)
+ detail::io_object_impl<
+ detail::null_socket_service<Protocol>, Executor> impl_;
+#elif defined(BOOST_ASIO_HAS_IOCP)
+ detail::io_object_impl<
+ detail::win_iocp_socket_service<Protocol>, Executor> impl_;
+#else
+ detail::io_object_impl<
+ detail::reactive_socket_service_ext_local<Protocol>, Executor> impl_;
+#endif
+
+private:
+ // Disallow copying and assignment.
+ basic_socket_ext_local(const basic_socket_ext_local&) BOOST_ASIO_DELETED;
+ basic_socket_ext_local& operator=(const basic_socket_ext_local&) BOOST_ASIO_DELETED;
+
+ struct initiate_async_connect
+ {
+ template <typename ConnectHandler>
+ void operator()(BOOST_ASIO_MOVE_ARG(ConnectHandler) handler,
+ basic_socket_ext_local* self, const endpoint_type& peer_endpoint,
+ const boost::system::error_code& open_ec) const
+ {
+ // If you get an error on the following line it means that your handler
+ // does not meet the documented type requirements for a ConnectHandler.
+ BOOST_ASIO_CONNECT_HANDLER_CHECK(ConnectHandler, handler) type_check;
+
+ if (open_ec)
+ {
+ boost::asio::post(self->impl_.get_executor(),
+ boost::asio::detail::bind_handler(
+ BOOST_ASIO_MOVE_CAST(ConnectHandler)(handler), open_ec));
+ }
+ else
+ {
+ detail::non_const_lvalue<ConnectHandler> handler2(handler);
+ self->impl_.get_service().async_connect(
+ self->impl_.get_implementation(), peer_endpoint,
+ handler2.value, self->impl_.get_implementation_executor());
+ }
+ }
+ };
+
+ struct initiate_async_wait
+ {
+ template <typename WaitHandler>
+ void operator()(BOOST_ASIO_MOVE_ARG(WaitHandler) handler,
+ basic_socket_ext_local* self, wait_type w) const
+ {
+ // If you get an error on the following line it means that your handler
+ // does not meet the documented type requirements for a WaitHandler.
+ BOOST_ASIO_WAIT_HANDLER_CHECK(WaitHandler, handler) type_check;
+
+ detail::non_const_lvalue<WaitHandler> handler2(handler);
+ self->impl_.get_service().async_wait(
+ self->impl_.get_implementation(), w, handler2.value,
+ self->impl_.get_implementation_executor());
+ }
+ };
+};
+
+} // namespace asio
+} // namespace boost
+
+#include <boost/asio/detail/pop_options.hpp>
+
+#endif // BOOST_ASIO_BASIC_SOCKET_EXT_LOCAL_HPP
diff --git a/implementation/helper/1.74/boost/asio/basic_stream_socket_ext.hpp b/implementation/helper/1.74/boost/asio/basic_stream_socket_ext.hpp
new file mode 100644
index 0000000..e77f5eb
--- /dev/null
+++ b/implementation/helper/1.74/boost/asio/basic_stream_socket_ext.hpp
@@ -0,0 +1,996 @@
+//
+// basic_stream_socket_ext.hpp
+// ~~~~~~~~~~~~~~~~~~~~~~~~~~~
+//
+// Copyright (c) 2003-2019 Christopher M. Kohlhoff (chris at kohlhoff dot com)
+// Copyright (c) 2016-2019 Bayerische Motoren Werke Aktiengesellschaft (BMW AG)
+//
+// Distributed under the Boost Software License, Version 1.0. (See accompanying
+// file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt)
+//
+
+#ifndef BOOST_ASIO_BASIC_STREAM_SOCKET_EXT_HPP
+#define BOOST_ASIO_BASIC_STREAM_SOCKET_EXT_HPP
+
+#if defined(_MSC_VER) && (_MSC_VER >= 1200)
+# pragma once
+#endif // defined(_MSC_VER) && (_MSC_VER >= 1200)
+
+#include <boost/asio/detail/config.hpp>
+#include <cstddef>
+#include <boost/asio/async_result.hpp>
+#include <boost/asio/basic_socket_ext_local.hpp>
+#include <boost/asio/detail/handler_type_requirements_ext_local.hpp>
+#include <boost/asio/detail/non_const_lvalue.hpp>
+#include <boost/asio/detail/throw_error.hpp>
+#include <boost/asio/error.hpp>
+
+#include <boost/asio/detail/push_options.hpp>
+
+namespace boost {
+namespace asio {
+
+#if !defined(BOOST_ASIO_BASIC_STREAM_SOCKET_EXT_FWD_DECL)
+#define BOOST_ASIO_BASIC_STREAM_SOCKET_EXT_FWD_DECL
+
+// Forward declaration with defaulted arguments.
+template <typename Protocol, typename Executor = executor>
+class basic_stream_socket_ext;
+
+#endif // !defined(BOOST_ASIO_BASIC_STREAM_SOCKET_EXT_FWD_DECL)
+
+/// Provides stream-oriented socket functionality.
+/**
+ * The basic_stream_socket_ext class template provides asynchronous and blocking
+ * stream-oriented socket functionality.
+ *
+ * @par Thread Safety
+ * @e Distinct @e objects: Safe.@n
+ * @e Shared @e objects: Unsafe.
+ *
+ * @par Concepts:
+ * AsyncReadStream, AsyncWriteStream, Stream, SyncReadStream, SyncWriteStream.
+ */
+template <typename Protocol, typename Executor>
+class basic_stream_socket_ext
+ : public basic_socket_ext_local<Protocol, Executor>
+{
+public:
+ /// The type of the executor associated with the object.
+ typedef Executor executor_type;
+
+ /// Rebinds the socket type to another executor.
+ template <typename Executor1>
+ struct rebind_executor
+ {
+ /// The socket type when rebound to the specified executor.
+ typedef basic_stream_socket_ext<Protocol, Executor1> other;
+ };
+
+ /// The native representation of a socket.
+#if defined(GENERATING_DOCUMENTATION)
+ typedef implementation_defined native_handle_type;
+#else
+ typedef typename basic_socket<Protocol,
+ Executor>::native_handle_type native_handle_type;
+#endif
+
+ /// The protocol type.
+ typedef Protocol protocol_type;
+
+ /// The endpoint type.
+ typedef typename Protocol::endpoint endpoint_type;
+
+ /// Construct a basic_stream_socket without opening it.
+ /**
+ * This constructor creates a stream socket without opening it. The socket
+ * needs to be opened and then connected or accepted before data can be sent
+ * or received on it.
+ *
+ * @param ex The I/O executor that the socket will use, by default, to
+ * dispatch handlers for any asynchronous operations performed on the socket.
+ */
+ explicit basic_stream_socket_ext(const executor_type& ex)
+ : basic_socket_ext_local<Protocol, Executor>(ex)
+ {
+ }
+
+ /// Construct a basic_stream_socket without opening it.
+ /**
+ * This constructor creates a stream socket without opening it. The socket
+ * needs to be opened and then connected or accepted before data can be sent
+ * or received on it.
+ *
+ * @param context An execution context which provides the I/O executor that
+ * the socket will use, by default, to dispatch handlers for any asynchronous
+ * operations performed on the socket.
+ */
+ template <typename ExecutionContext>
+ explicit basic_stream_socket_ext(ExecutionContext& context,
+ typename enable_if<
+ is_convertible<ExecutionContext&, execution_context&>::value
+ >::type* = 0)
+ : basic_socket_ext_local<Protocol, Executor>(context)
+ {
+ }
+
+ /// Construct and open a basic_stream_socket.
+ /**
+ * This constructor creates and opens a stream socket. The socket needs to be
+ * connected or accepted before data can be sent or received on it.
+ *
+ * @param ex The I/O executor that the socket will use, by default, to
+ * dispatch handlers for any asynchronous operations performed on the socket.
+ *
+ * @param protocol An object specifying protocol parameters to be used.
+ *
+ * @throws boost::system::system_error Thrown on failure.
+ */
+ basic_stream_socket_ext(const executor_type& ex, const protocol_type& protocol)
+ : basic_socket_ext_local<Protocol, Executor>(ex, protocol)
+ {
+ }
+
+ /// Construct and open a basic_stream_socket.
+ /**
+ * This constructor creates and opens a stream socket. The socket needs to be
+ * connected or accepted before data can be sent or received on it.
+ *
+ * @param context An execution context which provides the I/O executor that
+ * the socket will use, by default, to dispatch handlers for any asynchronous
+ * operations performed on the socket.
+ *
+ * @param protocol An object specifying protocol parameters to be used.
+ *
+ * @throws boost::system::system_error Thrown on failure.
+ */
+ template <typename ExecutionContext>
+ basic_stream_socket_ext(ExecutionContext& context, const protocol_type& protocol,
+ typename enable_if<
+ is_convertible<ExecutionContext&, execution_context&>::value
+ >::type* = 0)
+ : basic_socket_ext_local<Protocol, Executor>(context, protocol)
+ {
+ }
+
+ /// Construct a basic_stream_socket, opening it and binding it to the given
+ /// local endpoint.
+ /**
+ * This constructor creates a stream socket and automatically opens it bound
+ * to the specified endpoint on the local machine. The protocol used is the
+ * protocol associated with the given endpoint.
+ *
+ * @param ex The I/O executor that the socket will use, by default, to
+ * dispatch handlers for any asynchronous operations performed on the socket.
+ *
+ * @param endpoint An endpoint on the local machine to which the stream
+ * socket will be bound.
+ *
+ * @throws boost::system::system_error Thrown on failure.
+ */
+ basic_stream_socket_ext(const executor_type& ex, const endpoint_type& endpoint)
+ : basic_socket_ext_local<Protocol, Executor>(ex, endpoint)
+ {
+ }
+
+ /// Construct a basic_stream_socket, opening it and binding it to the given
+ /// local endpoint.
+ /**
+ * This constructor creates a stream socket and automatically opens it bound
+ * to the specified endpoint on the local machine. The protocol used is the
+ * protocol associated with the given endpoint.
+ *
+ * @param context An execution context which provides the I/O executor that
+ * the socket will use, by default, to dispatch handlers for any asynchronous
+ * operations performed on the socket.
+ *
+ * @param endpoint An endpoint on the local machine to which the stream
+ * socket will be bound.
+ *
+ * @throws boost::system::system_error Thrown on failure.
+ */
+ template <typename ExecutionContext>
+ basic_stream_socket_ext(ExecutionContext& context, const endpoint_type& endpoint,
+ typename enable_if<
+ is_convertible<ExecutionContext&, execution_context&>::value
+ >::type* = 0)
+ : basic_socket_ext_local<Protocol, Executor>(context, endpoint)
+ {
+ }
+
+ /// Construct a basic_stream_socket on an existing native socket.
+ /**
+ * This constructor creates a stream socket object to hold an existing native
+ * socket.
+ *
+ * @param ex The I/O executor that the socket will use, by default, to
+ * dispatch handlers for any asynchronous operations performed on the socket.
+ *
+ * @param protocol An object specifying protocol parameters to be used.
+ *
+ * @param native_socket The new underlying socket implementation.
+ *
+ * @throws boost::system::system_error Thrown on failure.
+ */
+ basic_stream_socket_ext(const executor_type& ex,
+ const protocol_type& protocol, const native_handle_type& native_socket)
+ : basic_socket_ext_local<Protocol, Executor>(ex, protocol, native_socket)
+ {
+ }
+
+ /// Construct a basic_stream_socket on an existing native socket.
+ /**
+ * This constructor creates a stream socket object to hold an existing native
+ * socket.
+ *
+ * @param context An execution context which provides the I/O executor that
+ * the socket will use, by default, to dispatch handlers for any asynchronous
+ * operations performed on the socket.
+ *
+ * @param protocol An object specifying protocol parameters to be used.
+ *
+ * @param native_socket The new underlying socket implementation.
+ *
+ * @throws boost::system::system_error Thrown on failure.
+ */
+ template <typename ExecutionContext>
+ basic_stream_socket_ext(ExecutionContext& context,
+ const protocol_type& protocol, const native_handle_type& native_socket,
+ typename enable_if<
+ is_convertible<ExecutionContext&, execution_context&>::value
+ >::type* = 0)
+ : basic_socket_ext_local<Protocol, Executor>(context, protocol, native_socket)
+ {
+ }
+
+#if defined(BOOST_ASIO_HAS_MOVE) || defined(GENERATING_DOCUMENTATION)
+ /// Move-construct a basic_stream_socket from another.
+ /**
+ * This constructor moves a stream socket from one object to another.
+ *
+ * @param other The other basic_stream_socket object from which the move
+ * will occur.
+ *
+ * @note Following the move, the moved-from object is in the same state as if
+ * constructed using the @c basic_stream_socket(const executor_type&)
+ * constructor.
+ */
+ basic_stream_socket_ext(basic_stream_socket_ext&& other)
+ : basic_socket_ext_local<Protocol, Executor>(std::move(other))
+ {
+ }
+
+ /// Move-assign a basic_stream_socket from another.
+ /**
+ * This assignment operator moves a stream socket from one object to another.
+ *
+ * @param other The other basic_stream_socket object from which the move
+ * will occur.
+ *
+ * @note Following the move, the moved-from object is in the same state as if
+ * constructed using the @c basic_stream_socket(const executor_type&)
+ * constructor.
+ */
+ basic_stream_socket_ext& operator=(basic_stream_socket_ext&& other)
+ {
+ basic_socket_ext_local<Protocol, Executor>::operator=(std::move(other));
+ return *this;
+ }
+
+ /// Move-construct a basic_stream_socket from a socket of another protocol
+ /// type.
+ /**
+ * This constructor moves a stream socket from one object to another.
+ *
+ * @param other The other basic_stream_socket object from which the move
+ * will occur.
+ *
+ * @note Following the move, the moved-from object is in the same state as if
+ * constructed using the @c basic_stream_socket(const executor_type&)
+ * constructor.
+ */
+ template <typename Protocol1, typename Executor1>
+ basic_stream_socket_ext(basic_stream_socket_ext<Protocol1, Executor1>&& other,
+ typename enable_if<
+ is_convertible<Protocol1, Protocol>::value
+ && is_convertible<Executor1, Executor>::value
+ >::type* = 0)
+ : basic_socket_ext_local<Protocol, Executor>(std::move(other))
+ {
+ }
+
+ /// Move-assign a basic_stream_socket from a socket of another protocol type.
+ /**
+ * This assignment operator moves a stream socket from one object to another.
+ *
+ * @param other The other basic_stream_socket object from which the move
+ * will occur.
+ *
+ * @note Following the move, the moved-from object is in the same state as if
+ * constructed using the @c basic_stream_socket(const executor_type&)
+ * constructor.
+ */
+ template <typename Protocol1, typename Executor1>
+ typename enable_if<
+ is_convertible<Protocol1, Protocol>::value
+ && is_convertible<Executor1, Executor>::value,
+ basic_stream_socket_ext&
+ >::type operator=(basic_stream_socket_ext<Protocol1, Executor1>&& other)
+ {
+ basic_socket_ext_local<Protocol, Executor>::operator=(std::move(other));
+ return *this;
+ }
+#endif // defined(BOOST_ASIO_HAS_MOVE) || defined(GENERATING_DOCUMENTATION)
+
+ /// Destroys the socket.
+ /**
+ * This function destroys the socket, cancelling any outstanding asynchronous
+ * operations associated with the socket as if by calling @c cancel.
+ */
+ ~basic_stream_socket_ext()
+ {
+ }
+
+ /// Send some data on the socket.
+ /**
+ * This function is used to send data on the stream socket. The function
+ * call will block until one or more bytes of the data has been sent
+ * successfully, or an until error occurs.
+ *
+ * @param buffers One or more data buffers to be sent on the socket.
+ *
+ * @returns The number of bytes sent.
+ *
+ * @throws boost::system::system_error Thrown on failure.
+ *
+ * @note The send operation may not transmit all of the data to the peer.
+ * Consider using the @ref write function if you need to ensure that all data
+ * is written before the blocking operation completes.
+ *
+ * @par Example
+ * To send a single data buffer use the @ref buffer function as follows:
+ * @code
+ * socket.send(boost::asio::buffer(data, size));
+ * @endcode
+ * See the @ref buffer documentation for information on sending multiple
+ * buffers in one go, and how to use it with arrays, boost::array or
+ * std::vector.
+ */
+ template <typename ConstBufferSequence>
+ std::size_t send(const ConstBufferSequence& buffers)
+ {
+ boost::system::error_code ec;
+ std::size_t s = this->impl_.get_service().send(
+ this->impl_.get_implementation(), buffers, 0, ec);
+ boost::asio::detail::throw_error(ec, "send");
+ return s;
+ }
+
+ /// Send some data on the socket.
+ /**
+ * This function is used to send data on the stream socket. The function
+ * call will block until one or more bytes of the data has been sent
+ * successfully, or an until error occurs.
+ *
+ * @param buffers One or more data buffers to be sent on the socket.
+ *
+ * @param flags Flags specifying how the send call is to be made.
+ *
+ * @returns The number of bytes sent.
+ *
+ * @throws boost::system::system_error Thrown on failure.
+ *
+ * @note The send operation may not transmit all of the data to the peer.
+ * Consider using the @ref write function if you need to ensure that all data
+ * is written before the blocking operation completes.
+ *
+ * @par Example
+ * To send a single data buffer use the @ref buffer function as follows:
+ * @code
+ * socket.send(boost::asio::buffer(data, size), 0);
+ * @endcode
+ * See the @ref buffer documentation for information on sending multiple
+ * buffers in one go, and how to use it with arrays, boost::array or
+ * std::vector.
+ */
+ template <typename ConstBufferSequence>
+ std::size_t send(const ConstBufferSequence& buffers,
+ socket_base::message_flags flags)
+ {
+ boost::system::error_code ec;
+ std::size_t s = this->impl_.get_service().send(
+ this->impl_.get_implementation(), buffers, flags, ec);
+ boost::asio::detail::throw_error(ec, "send");
+ return s;
+ }
+
+ /// Send some data on the socket.
+ /**
+ * This function is used to send data on the stream socket. The function
+ * call will block until one or more bytes of the data has been sent
+ * successfully, or an until error occurs.
+ *
+ * @param buffers One or more data buffers to be sent on the socket.
+ *
+ * @param flags Flags specifying how the send call is to be made.
+ *
+ * @param ec Set to indicate what error occurred, if any.
+ *
+ * @returns The number of bytes sent. Returns 0 if an error occurred.
+ *
+ * @note The send operation may not transmit all of the data to the peer.
+ * Consider using the @ref write function if you need to ensure that all data
+ * is written before the blocking operation completes.
+ */
+ template <typename ConstBufferSequence>
+ std::size_t send(const ConstBufferSequence& buffers,
+ socket_base::message_flags flags, boost::system::error_code& ec)
+ {
+ return this->impl_.get_service().send(
+ this->impl_.get_implementation(), buffers, flags, ec);
+ }
+
+ /// Start an asynchronous send.
+ /**
+ * This function is used to asynchronously send data on the stream socket.
+ * The function call always returns immediately.
+ *
+ * @param buffers One or more data buffers to be sent on the socket. Although
+ * the buffers object may be copied as necessary, ownership of the underlying
+ * memory blocks is retained by the caller, which must guarantee that they
+ * remain valid until the handler is called.
+ *
+ * @param handler The handler to be called when the send operation completes.
+ * Copies will be made of the handler as required. The function signature of
+ * the handler must be:
+ * @code void handler(
+ * const boost::system::error_code& error, // Result of operation.
+ * std::size_t bytes_transferred // Number of bytes sent.
+ * ); @endcode
+ * Regardless of whether the asynchronous operation completes immediately or
+ * not, the handler will not be invoked from within this function. On
+ * immediate completion, invocation of the handler will be performed in a
+ * manner equivalent to using boost::asio::post().
+ *
+ * @note The send operation may not transmit all of the data to the peer.
+ * Consider using the @ref async_write function if you need to ensure that all
+ * data is written before the asynchronous operation completes.
+ *
+ * @par Example
+ * To send a single data buffer use the @ref buffer function as follows:
+ * @code
+ * socket.async_send(boost::asio::buffer(data, size), handler);
+ * @endcode
+ * See the @ref buffer documentation for information on sending multiple
+ * buffers in one go, and how to use it with arrays, boost::array or
+ * std::vector.
+ */
+ template <typename ConstBufferSequence, typename WriteHandler>
+ BOOST_ASIO_INITFN_RESULT_TYPE(WriteHandler,
+ void (boost::system::error_code, std::size_t))
+ async_send(const ConstBufferSequence& buffers,
+ BOOST_ASIO_MOVE_ARG(WriteHandler) handler)
+ {
+ return async_initiate<WriteHandler,
+ void (boost::system::error_code, std::size_t)>(
+ initiate_async_send(), handler, this,
+ buffers, socket_base::message_flags(0));
+ }
+
+ /// Start an asynchronous send.
+ /**
+ * This function is used to asynchronously send data on the stream socket.
+ * The function call always returns immediately.
+ *
+ * @param buffers One or more data buffers to be sent on the socket. Although
+ * the buffers object may be copied as necessary, ownership of the underlying
+ * memory blocks is retained by the caller, which must guarantee that they
+ * remain valid until the handler is called.
+ *
+ * @param flags Flags specifying how the send call is to be made.
+ *
+ * @param handler The handler to be called when the send operation completes.
+ * Copies will be made of the handler as required. The function signature of
+ * the handler must be:
+ * @code void handler(
+ * const boost::system::error_code& error, // Result of operation.
+ * std::size_t bytes_transferred // Number of bytes sent.
+ * ); @endcode
+ * Regardless of whether the asynchronous operation completes immediately or
+ * not, the handler will not be invoked from within this function. On
+ * immediate completion, invocation of the handler will be performed in a
+ * manner equivalent to using boost::asio::post().
+ *
+ * @note The send operation may not transmit all of the data to the peer.
+ * Consider using the @ref async_write function if you need to ensure that all
+ * data is written before the asynchronous operation completes.
+ *
+ * @par Example
+ * To send a single data buffer use the @ref buffer function as follows:
+ * @code
+ * socket.async_send(boost::asio::buffer(data, size), 0, handler);
+ * @endcode
+ * See the @ref buffer documentation for information on sending multiple
+ * buffers in one go, and how to use it with arrays, boost::array or
+ * std::vector.
+ */
+ template <typename ConstBufferSequence, typename WriteHandler>
+ BOOST_ASIO_INITFN_RESULT_TYPE(WriteHandler,
+ void (boost::system::error_code, std::size_t))
+ async_send(const ConstBufferSequence& buffers,
+ socket_base::message_flags flags,
+ BOOST_ASIO_MOVE_ARG(WriteHandler) handler)
+ {
+ return async_initiate<WriteHandler,
+ void (boost::system::error_code, std::size_t)>(
+ initiate_async_send(), handler, this, buffers, flags);
+ }
+
+ /// Receive some data on the socket.
+ /**
+ * This function is used to receive data on the stream socket. The function
+ * call will block until one or more bytes of data has been received
+ * successfully, or until an error occurs.
+ *
+ * @param buffers One or more buffers into which the data will be received.
+ *
+ * @returns The number of bytes received.
+ *
+ * @throws boost::system::system_error Thrown on failure. An error code of
+ * boost::asio::error::eof indicates that the connection was closed by the
+ * peer.
+ *
+ * @note The receive operation may not receive all of the requested number of
+ * bytes. Consider using the @ref read function if you need to ensure that the
+ * requested amount of data is read before the blocking operation completes.
+ *
+ * @par Example
+ * To receive into a single data buffer use the @ref buffer function as
+ * follows:
+ * @code
+ * socket.receive(boost::asio::buffer(data, size));
+ * @endcode
+ * See the @ref buffer documentation for information on receiving into
+ * multiple buffers in one go, and how to use it with arrays, boost::array or
+ * std::vector.
+ */
+ template <typename MutableBufferSequence>
+ std::size_t receive(const MutableBufferSequence& buffers)
+ {
+ boost::system::error_code ec;
+ std::size_t s = this->impl_.get_service().receive(
+ this->impl_.get_implementation(), buffers, 0, ec);
+ boost::asio::detail::throw_error(ec, "receive");
+ return s;
+ }
+
+ /// Receive some data on the socket.
+ /**
+ * This function is used to receive data on the stream socket. The function
+ * call will block until one or more bytes of data has been received
+ * successfully, or until an error occurs.
+ *
+ * @param buffers One or more buffers into which the data will be received.
+ *
+ * @param flags Flags specifying how the receive call is to be made.
+ *
+ * @returns The number of bytes received.
+ *
+ * @throws boost::system::system_error Thrown on failure. An error code of
+ * boost::asio::error::eof indicates that the connection was closed by the
+ * peer.
+ *
+ * @note The receive operation may not receive all of the requested number of
+ * bytes. Consider using the @ref read function if you need to ensure that the
+ * requested amount of data is read before the blocking operation completes.
+ *
+ * @par Example
+ * To receive into a single data buffer use the @ref buffer function as
+ * follows:
+ * @code
+ * socket.receive(boost::asio::buffer(data, size), 0);
+ * @endcode
+ * See the @ref buffer documentation for information on receiving into
+ * multiple buffers in one go, and how to use it with arrays, boost::array or
+ * std::vector.
+ */
+ template <typename MutableBufferSequence>
+ std::size_t receive(const MutableBufferSequence& buffers,
+ socket_base::message_flags flags)
+ {
+ boost::system::error_code ec;
+ std::size_t s = this->impl_.get_service().receive(
+ this->impl_.get_implementation(), buffers, flags, ec);
+ boost::asio::detail::throw_error(ec, "receive");
+ return s;
+ }
+
+ /// Receive some data on a connected socket.
+ /**
+ * This function is used to receive data on the stream socket. The function
+ * call will block until one or more bytes of data has been received
+ * successfully, or until an error occurs.
+ *
+ * @param buffers One or more buffers into which the data will be received.
+ *
+ * @param flags Flags specifying how the receive call is to be made.
+ *
+ * @param ec Set to indicate what error occurred, if any.
+ *
+ * @returns The number of bytes received. Returns 0 if an error occurred.
+ *
+ * @note The receive operation may not receive all of the requested number of
+ * bytes. Consider using the @ref read function if you need to ensure that the
+ * requested amount of data is read before the blocking operation completes.
+ */
+ template <typename MutableBufferSequence>
+ std::size_t receive(const MutableBufferSequence& buffers,
+ socket_base::message_flags flags, boost::system::error_code& ec)
+ {
+ return this->impl_.get_service().receive(
+ this->impl_.get_implementation(), buffers, flags, ec);
+ }
+
+ /// Start an asynchronous receive.
+ /**
+ * This function is used to asynchronously receive data from the stream
+ * socket. The function call always returns immediately.
+ *
+ * @param buffers One or more buffers into which the data will be received.
+ * Although the buffers object may be copied as necessary, ownership of the
+ * underlying memory blocks is retained by the caller, which must guarantee
+ * that they remain valid until the handler is called.
+ *
+ * @param handler The handler to be called when the receive operation
+ * completes. Copies will be made of the handler as required. The function
+ * signature of the handler must be:
+ * @code void handler(
+ * const boost::system::error_code& error, // Result of operation.
+ * std::size_t bytes_transferred // Number of bytes received.
+ * ); @endcode
+ * Regardless of whether the asynchronous operation completes immediately or
+ * not, the handler will not be invoked from within this function. On
+ * immediate completion, invocation of the handler will be performed in a
+ * manner equivalent to using boost::asio::post().
+ *
+ * @note The receive operation may not receive all of the requested number of
+ * bytes. Consider using the @ref async_read function if you need to ensure
+ * that the requested amount of data is received before the asynchronous
+ * operation completes.
+ *
+ * @par Example
+ * To receive into a single data buffer use the @ref buffer function as
+ * follows:
+ * @code
+ * socket.async_receive(boost::asio::buffer(data, size), handler);
+ * @endcode
+ * See the @ref buffer documentation for information on receiving into
+ * multiple buffers in one go, and how to use it with arrays, boost::array or
+ * std::vector.
+ */
+ template <typename MutableBufferSequence, typename ReadHandler>
+ BOOST_ASIO_INITFN_RESULT_TYPE(ReadHandler,
+ void (boost::system::error_code, std::size_t, std::uint32_t, std::uint32_t))
+ async_receive(const MutableBufferSequence& buffers,
+ BOOST_ASIO_MOVE_ARG(ReadHandler) handler)
+ {
+ return async_initiate<ReadHandler,
+ void (boost::system::error_code, std::size_t, std::uint32_t, std::uint32_t)>(
+ initiate_async_receive(), handler, this,
+ buffers, socket_base::message_flags(0));
+ }
+
+ /// Start an asynchronous receive.
+ /**
+ * This function is used to asynchronously receive data from the stream
+ * socket. The function call always returns immediately.
+ *
+ * @param buffers One or more buffers into which the data will be received.
+ * Although the buffers object may be copied as necessary, ownership of the
+ * underlying memory blocks is retained by the caller, which must guarantee
+ * that they remain valid until the handler is called.
+ *
+ * @param flags Flags specifying how the receive call is to be made.
+ *
+ * @param handler The handler to be called when the receive operation
+ * completes. Copies will be made of the handler as required. The function
+ * signature of the handler must be:
+ * @code void handler(
+ * const boost::system::error_code& error, // Result of operation.
+ * std::size_t bytes_transferred // Number of bytes received.
+ * ); @endcode
+ * Regardless of whether the asynchronous operation completes immediately or
+ * not, the handler will not be invoked from within this function. On
+ * immediate completion, invocation of the handler will be performed in a
+ * manner equivalent to using boost::asio::post().
+ *
+ * @note The receive operation may not receive all of the requested number of
+ * bytes. Consider using the @ref async_read function if you need to ensure
+ * that the requested amount of data is received before the asynchronous
+ * operation completes.
+ *
+ * @par Example
+ * To receive into a single data buffer use the @ref buffer function as
+ * follows:
+ * @code
+ * socket.async_receive(boost::asio::buffer(data, size), 0, handler);
+ * @endcode
+ * See the @ref buffer documentation for information on receiving into
+ * multiple buffers in one go, and how to use it with arrays, boost::array or
+ * std::vector.
+ */
+ template <typename MutableBufferSequence, typename ReadHandler>
+ BOOST_ASIO_INITFN_RESULT_TYPE(ReadHandler,
+ void (boost::system::error_code, std::size_t, std::uint32_t, std::uint32_t))
+ async_receive(const MutableBufferSequence& buffers,
+ socket_base::message_flags flags,
+ BOOST_ASIO_MOVE_ARG(ReadHandler) handler)
+ {
+ return async_initiate<ReadHandler,
+ void (boost::system::error_code, std::size_t, std::uint32_t, std::uint32_t)>(
+ initiate_async_receive(), handler, this, buffers, flags);
+ }
+
+ /// Write some data to the socket.
+ /**
+ * This function is used to write data to the stream socket. The function call
+ * will block until one or more bytes of the data has been written
+ * successfully, or until an error occurs.
+ *
+ * @param buffers One or more data buffers to be written to the socket.
+ *
+ * @returns The number of bytes written.
+ *
+ * @throws boost::system::system_error Thrown on failure. An error code of
+ * boost::asio::error::eof indicates that the connection was closed by the
+ * peer.
+ *
+ * @note The write_some operation may not transmit all of the data to the
+ * peer. Consider using the @ref write function if you need to ensure that
+ * all data is written before the blocking operation completes.
+ *
+ * @par Example
+ * To write a single data buffer use the @ref buffer function as follows:
+ * @code
+ * socket.write_some(boost::asio::buffer(data, size));
+ * @endcode
+ * See the @ref buffer documentation for information on writing multiple
+ * buffers in one go, and how to use it with arrays, boost::array or
+ * std::vector.
+ */
+ template <typename ConstBufferSequence>
+ std::size_t write_some(const ConstBufferSequence& buffers)
+ {
+ boost::system::error_code ec;
+ std::size_t s = this->impl_.get_service().send(
+ this->impl_.get_implementation(), buffers, 0, ec);
+ boost::asio::detail::throw_error(ec, "write_some");
+ return s;
+ }
+
+ /// Write some data to the socket.
+ /**
+ * This function is used to write data to the stream socket. The function call
+ * will block until one or more bytes of the data has been written
+ * successfully, or until an error occurs.
+ *
+ * @param buffers One or more data buffers to be written to the socket.
+ *
+ * @param ec Set to indicate what error occurred, if any.
+ *
+ * @returns The number of bytes written. Returns 0 if an error occurred.
+ *
+ * @note The write_some operation may not transmit all of the data to the
+ * peer. Consider using the @ref write function if you need to ensure that
+ * all data is written before the blocking operation completes.
+ */
+ template <typename ConstBufferSequence>
+ std::size_t write_some(const ConstBufferSequence& buffers,
+ boost::system::error_code& ec)
+ {
+ return this->impl_.get_service().send(
+ this->impl_.get_implementation(), buffers, 0, ec);
+ }
+
+ /// Start an asynchronous write.
+ /**
+ * This function is used to asynchronously write data to the stream socket.
+ * The function call always returns immediately.
+ *
+ * @param buffers One or more data buffers to be written to the socket.
+ * Although the buffers object may be copied as necessary, ownership of the
+ * underlying memory blocks is retained by the caller, which must guarantee
+ * that they remain valid until the handler is called.
+ *
+ * @param handler The handler to be called when the write operation completes.
+ * Copies will be made of the handler as required. The function signature of
+ * the handler must be:
+ * @code void handler(
+ * const boost::system::error_code& error, // Result of operation.
+ * std::size_t bytes_transferred // Number of bytes written.
+ * ); @endcode
+ * Regardless of whether the asynchronous operation completes immediately or
+ * not, the handler will not be invoked from within this function. On
+ * immediate completion, invocation of the handler will be performed in a
+ * manner equivalent to using boost::asio::post().
+ *
+ * @note The write operation may not transmit all of the data to the peer.
+ * Consider using the @ref async_write function if you need to ensure that all
+ * data is written before the asynchronous operation completes.
+ *
+ * @par Example
+ * To write a single data buffer use the @ref buffer function as follows:
+ * @code
+ * socket.async_write_some(boost::asio::buffer(data, size), handler);
+ * @endcode
+ * See the @ref buffer documentation for information on writing multiple
+ * buffers in one go, and how to use it with arrays, boost::array or
+ * std::vector.
+ */
+ template <typename ConstBufferSequence, typename WriteHandler>
+ BOOST_ASIO_INITFN_RESULT_TYPE(WriteHandler,
+ void (boost::system::error_code, std::size_t, std::uint32_t, std::uint32_t))
+ async_write_some(const ConstBufferSequence& buffers,
+ BOOST_ASIO_MOVE_ARG(WriteHandler) handler)
+ {
+ return async_initiate<WriteHandler,
+ void (boost::system::error_code, std::size_t, std::uint32_t, std::uint32_t)>(
+ initiate_async_send(), handler, this,
+ buffers, socket_base::message_flags(0));
+ }
+
+ /// Read some data from the socket.
+ /**
+ * This function is used to read data from the stream socket. The function
+ * call will block until one or more bytes of data has been read successfully,
+ * or until an error occurs.
+ *
+ * @param buffers One or more buffers into which the data will be read.
+ *
+ * @returns The number of bytes read.
+ *
+ * @throws boost::system::system_error Thrown on failure. An error code of
+ * boost::asio::error::eof indicates that the connection was closed by the
+ * peer.
+ *
+ * @note The read_some operation may not read all of the requested number of
+ * bytes. Consider using the @ref read function if you need to ensure that
+ * the requested amount of data is read before the blocking operation
+ * completes.
+ *
+ * @par Example
+ * To read into a single data buffer use the @ref buffer function as follows:
+ * @code
+ * socket.read_some(boost::asio::buffer(data, size));
+ * @endcode
+ * See the @ref buffer documentation for information on reading into multiple
+ * buffers in one go, and how to use it with arrays, boost::array or
+ * std::vector.
+ */
+ template <typename MutableBufferSequence>
+ std::size_t read_some(const MutableBufferSequence& buffers)
+ {
+ boost::system::error_code ec;
+ std::size_t s = this->impl_.get_service().receive(
+ this->impl_.get_implementation(), buffers, 0, ec);
+ boost::asio::detail::throw_error(ec, "read_some");
+ return s;
+ }
+
+ /// Read some data from the socket.
+ /**
+ * This function is used to read data from the stream socket. The function
+ * call will block until one or more bytes of data has been read successfully,
+ * or until an error occurs.
+ *
+ * @param buffers One or more buffers into which the data will be read.
+ *
+ * @param ec Set to indicate what error occurred, if any.
+ *
+ * @returns The number of bytes read. Returns 0 if an error occurred.
+ *
+ * @note The read_some operation may not read all of the requested number of
+ * bytes. Consider using the @ref read function if you need to ensure that
+ * the requested amount of data is read before the blocking operation
+ * completes.
+ */
+ template <typename MutableBufferSequence>
+ std::size_t read_some(const MutableBufferSequence& buffers,
+ boost::system::error_code& ec)
+ {
+ return this->impl_.get_service().receive(
+ this->impl_.get_implementation(), buffers, 0, ec);
+ }
+
+ /// Start an asynchronous read.
+ /**
+ * This function is used to asynchronously read data from the stream socket.
+ * The function call always returns immediately.
+ *
+ * @param buffers One or more buffers into which the data will be read.
+ * Although the buffers object may be copied as necessary, ownership of the
+ * underlying memory blocks is retained by the caller, which must guarantee
+ * that they remain valid until the handler is called.
+ *
+ * @param handler The handler to be called when the read operation completes.
+ * Copies will be made of the handler as required. The function signature of
+ * the handler must be:
+ * @code void handler(
+ * const boost::system::error_code& error, // Result of operation.
+ * std::size_t bytes_transferred // Number of bytes read.
+ * ); @endcode
+ * Regardless of whether the asynchronous operation completes immediately or
+ * not, the handler will not be invoked from within this function. On
+ * immediate completion, invocation of the handler will be performed in a
+ * manner equivalent to using boost::asio::post().
+ *
+ * @note The read operation may not read all of the requested number of bytes.
+ * Consider using the @ref async_read function if you need to ensure that the
+ * requested amount of data is read before the asynchronous operation
+ * completes.
+ *
+ * @par Example
+ * To read into a single data buffer use the @ref buffer function as follows:
+ * @code
+ * socket.async_read_some(boost::asio::buffer(data, size), handler);
+ * @endcode
+ * See the @ref buffer documentation for information on reading into multiple
+ * buffers in one go, and how to use it with arrays, boost::array or
+ * std::vector.
+ */
+ template <typename MutableBufferSequence, typename ReadHandler>
+ BOOST_ASIO_INITFN_RESULT_TYPE(ReadHandler,
+ void (boost::system::error_code, std::size_t, std::uint32_t, std::uint32_t))
+ async_read_some(const MutableBufferSequence& buffers,
+ BOOST_ASIO_MOVE_ARG(ReadHandler) handler)
+ {
+ return async_initiate<ReadHandler,
+ void (boost::system::error_code, std::size_t, std::uint32_t, std::uint32_t)>(
+ initiate_async_receive(), handler, this,
+ buffers, socket_base::message_flags(0));
+ }
+
+private:
+ struct initiate_async_send
+ {
+ template <typename WriteHandler, typename ConstBufferSequence>
+ void operator()(BOOST_ASIO_MOVE_ARG(WriteHandler) handler,
+ basic_stream_socket_ext* self, const ConstBufferSequence& buffers,
+ socket_base::message_flags flags) const
+ {
+ // If you get an error on the following line it means that your handler
+ // does not meet the documented type requirements for a WriteHandler.
+ BOOST_ASIO_WRITE_HANDLER_CHECK(WriteHandler, handler) type_check;
+
+ detail::non_const_lvalue<WriteHandler> handler2(handler);
+ self->impl_.get_service().async_send(
+ self->impl_.get_implementation(), buffers, flags,
+ handler2.value, self->impl_.get_executor());
+ }
+ };
+
+ struct initiate_async_receive
+ {
+ template <typename ReadHandler, typename MutableBufferSequence>
+ void operator()(BOOST_ASIO_MOVE_ARG(ReadHandler) handler,
+ basic_stream_socket_ext* self, const MutableBufferSequence& buffers,
+ socket_base::message_flags flags) const
+ {
+ // If you get an error on the following line it means that your handler
+ // does not meet the documented type requirements for a ReadHandler.
+ BOOST_ASIO_READ_HANDLER_CHECK_EXT_LOCAL(ReadHandler, handler) type_check;
+
+ detail::non_const_lvalue<ReadHandler> handler2(handler);
+ self->impl_.get_service().async_receive(
+ self->impl_.get_implementation(), buffers, flags,
+ handler2.value, self->impl_.get_executor());
+ }
+ };
+};
+
+} // namespace asio
+} // namespace boost
+
+#include <boost/asio/detail/pop_options.hpp>
+
+#endif // BOOST_ASIO_BASIC_STREAM_SOCKET_EXT_HPP
diff --git a/implementation/helper/1.74/boost/asio/detail/handler_type_requirements_ext.hpp b/implementation/helper/1.74/boost/asio/detail/handler_type_requirements_ext.hpp
new file mode 100644
index 0000000..67fe6bd
--- /dev/null
+++ b/implementation/helper/1.74/boost/asio/detail/handler_type_requirements_ext.hpp
@@ -0,0 +1,586 @@
+//
+// detail/handler_type_requirements_ext.hpp
+// ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+//
+// Copyright (c) 2003-2019 Christopher M. Kohlhoff (chris at kohlhoff dot com)
+// Copyright (c) 2016-2019 Bayerische Motoren Werke Aktiengesellschaft (BMW AG)
+//
+// Distributed under the Boost Software License, Version 1.0. (See accompanying
+// file LICENSE_boost or copy at http://www.boost.org/LICENSE_1_0.txt)
+//
+
+#ifndef BOOST_ASIO_DETAIL_HANDLER_TYPE_REQUIREMENTS_EXT_HPP
+#define BOOST_ASIO_DETAIL_HANDLER_TYPE_REQUIREMENTS_EXT_HPP
+
+#if defined(_MSC_VER) && (_MSC_VER >= 1200)
+# pragma once
+#endif // defined(_MSC_VER) && (_MSC_VER >= 1200)
+
+#include <boost/asio/detail/config.hpp>
+
+// Older versions of gcc have difficulty compiling the sizeof expressions where
+// we test the handler type requirements. We'll disable checking of handler type
+// requirements for those compilers, but otherwise enable it by default.
+#if !defined(BOOST_ASIO_DISABLE_HANDLER_TYPE_REQUIREMENTS)
+# if !defined(__GNUC__) || (__GNUC__ >= 4)
+# define BOOST_ASIO_ENABLE_HANDLER_TYPE_REQUIREMENTS 1
+# endif // !defined(__GNUC__) || (__GNUC__ >= 4)
+#endif // !defined(BOOST_ASIO_DISABLE_HANDLER_TYPE_REQUIREMENTS)
+
+// With C++0x we can use a combination of enhanced SFINAE and static_assert to
+// generate better template error messages. As this technique is not yet widely
+// portable, we'll only enable it for tested compilers.
+#if !defined(BOOST_ASIO_DISABLE_HANDLER_TYPE_REQUIREMENTS_ASSERT)
+# if defined(__GNUC__)
+# if ((__GNUC__ == 4) && (__GNUC_MINOR__ >= 5)) || (__GNUC__ > 4)
+# if defined(__GXX_EXPERIMENTAL_CXX0X__)
+# define BOOST_ASIO_ENABLE_HANDLER_TYPE_REQUIREMENTS_ASSERT 1
+# endif // defined(__GXX_EXPERIMENTAL_CXX0X__)
+# endif // ((__GNUC__ == 4) && (__GNUC_MINOR__ >= 5)) || (__GNUC__ > 4)
+# endif // defined(__GNUC__)
+# if defined(BOOST_ASIO_MSVC)
+# if (_MSC_VER >= 1600)
+# define BOOST_ASIO_ENABLE_HANDLER_TYPE_REQUIREMENTS_ASSERT 1
+# endif // (_MSC_VER >= 1600)
+# endif // defined(BOOST_ASIO_MSVC)
+# if defined(__clang__)
+# if __has_feature(__cxx_static_assert__)
+# define BOOST_ASIO_ENABLE_HANDLER_TYPE_REQUIREMENTS_ASSERT 1
+# endif // __has_feature(cxx_static_assert)
+# endif // defined(__clang__)
+#endif // !defined(BOOST_ASIO_DISABLE_HANDLER_TYPE_REQUIREMENTS)
+
+#if defined(BOOST_ASIO_ENABLE_HANDLER_TYPE_REQUIREMENTS)
+# include <boost/asio/async_result.hpp>
+#endif // defined(BOOST_ASIO_ENABLE_HANDLER_TYPE_REQUIREMENTS)
+
+namespace boost {
+namespace asio {
+namespace detail {
+
+#if defined(BOOST_ASIO_ENABLE_HANDLER_TYPE_REQUIREMENTS)
+
+# if defined(BOOST_ASIO_ENABLE_HANDLER_TYPE_REQUIREMENTS_ASSERT)
+
+template <typename Handler>
+auto zero_arg_copyable_handler_test(Handler h, void*)
+ -> decltype(
+ sizeof(Handler(static_cast<const Handler&>(h))),
+ ((h)()),
+ char(0));
+
+template <typename Handler>
+char (&zero_arg_copyable_handler_test(Handler, ...))[2];
+
+template <typename Handler, typename Arg1>
+auto one_arg_handler_test(Handler h, Arg1* a1)
+ -> decltype(
+ sizeof(Handler(BOOST_ASIO_MOVE_CAST(Handler)(h))),
+ ((h)(*a1)),
+ char(0));
+
+template <typename Handler>
+char (&one_arg_handler_test(Handler h, ...))[2];
+
+template <typename Handler, typename Arg1, typename Arg2>
+auto two_arg_handler_test(Handler h, Arg1* a1, Arg2* a2)
+ -> decltype(
+ sizeof(Handler(BOOST_ASIO_MOVE_CAST(Handler)(h))),
+ ((h)(*a1, *a2)),
+ char(0));
+
+template <typename Handler>
+char (&two_arg_handler_test(Handler, ...))[2];
+
+template <typename Handler, typename Arg1, typename Arg2>
+auto two_arg_move_handler_test(Handler h, Arg1* a1, Arg2* a2)
+ -> decltype(
+ sizeof(Handler(BOOST_ASIO_MOVE_CAST(Handler)(h))),
+ ((h)(*a1, BOOST_ASIO_MOVE_CAST(Arg2)(*a2))),
+ char(0));
+
+template <typename Handler>
+char (&two_arg_move_handler_test(Handler, ...))[2];
+
+template <typename Handler, typename Arg1, typename Arg2, typename Arg3>
+auto three_arg_handler_test(Handler h, Arg1* a1, Arg2* a2, Arg3* a3)
+ -> decltype(
+ sizeof(Handler(BOOST_ASIO_MOVE_CAST(Handler)(h))),
+ ((h)(*a1, *a2, *a3)),
+ char(0));
+
+template <typename Handler>
+char (&three_arg_handler_test(Handler, ...))[2];
+
+template <typename Handler, typename Arg1, typename Arg2, typename Arg3>
+auto three_arg_move_handler_test(Handler h, Arg1* a1, Arg2* a2, Arg3 *a3)
+ -> decltype(
+ sizeof(Handler(BOOST_ASIO_MOVE_CAST(Handler)(h))),
+ ((h)(*a1, BOOST_ASIO_MOVE_CAST(Arg2)(*a2), BOOST_ASIO_MOVE_CAST(Arg3)(*a3))),
+ char(0));
+
+template <typename Handler>
+char (&three_arg_move_handler_test(Handler, ...))[2];
+
+# define BOOST_ASIO_HANDLER_TYPE_REQUIREMENTS_ASSERT(expr, msg) \
+ static_assert(expr, msg);
+
+# else // defined(BOOST_ASIO_ENABLE_HANDLER_TYPE_REQUIREMENTS_ASSERT)
+
+# define BOOST_ASIO_HANDLER_TYPE_REQUIREMENTS_ASSERT(expr, msg)
+
+# endif // defined(BOOST_ASIO_ENABLE_HANDLER_TYPE_REQUIREMENTS_ASSERT)
+
+template <typename T> T& lvref();
+template <typename T> T& lvref(T);
+template <typename T> const T& clvref();
+template <typename T> const T& clvref(T);
+#if defined(BOOST_ASIO_HAS_MOVE)
+template <typename T> T rvref();
+template <typename T> T rvref(T);
+#else // defined(BOOST_ASIO_HAS_MOVE)
+template <typename T> const T& rvref();
+template <typename T> const T& rvref(T);
+#endif // defined(BOOST_ASIO_HAS_MOVE)
+template <typename T> char argbyv(T);
+
+#if 0
+template <int>
+struct handler_type_requirements
+{
+};
+#endif
+
+#define BOOST_ASIO_LEGACY_COMPLETION_HANDLER_CHECK( \
+ handler_type, handler) \
+ \
+ typedef BOOST_ASIO_HANDLER_TYPE(handler_type, \
+ void()) asio_true_handler_type; \
+ \
+ BOOST_ASIO_HANDLER_TYPE_REQUIREMENTS_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::lvref< \
+ asio_true_handler_type>()(), \
+ char(0))> BOOST_ASIO_UNUSED_TYPEDEF
+
+#define BOOST_ASIO_READ_HANDLER_CHECK_EXT( \
+ handler_type, handler) \
+ \
+ typedef BOOST_ASIO_HANDLER_TYPE(handler_type, \
+ void(boost::system::error_code, std::size_t, \
+ boost::asio::ip::address)) \
+ asio_true_handler_type; \
+ \
+ BOOST_ASIO_HANDLER_TYPE_REQUIREMENTS_ASSERT( \
+ sizeof(boost::asio::detail::three_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), \
+ static_cast<const boost::asio::ip::address*>(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::lvref< \
+ asio_true_handler_type>()( \
+ boost::asio::detail::lvref<const boost::system::error_code>(), \
+ boost::asio::detail::lvref<const std::size_t>(), \
+ boost::asio::detail::lvref<const boost::asio::ip::address>()), \
+ char(0))> BOOST_ASIO_UNUSED_TYPEDEF
+
+#define BOOST_ASIO_WRITE_HANDLER_CHECK( \
+ handler_type, handler) \
+ \
+ typedef BOOST_ASIO_HANDLER_TYPE(handler_type, \
+ void(boost::system::error_code, std::size_t)) \
+ asio_true_handler_type; \
+ \
+ BOOST_ASIO_HANDLER_TYPE_REQUIREMENTS_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::lvref< \
+ asio_true_handler_type>()( \
+ boost::asio::detail::lvref<const boost::system::error_code>(), \
+ boost::asio::detail::lvref<const std::size_t>()), \
+ char(0))> BOOST_ASIO_UNUSED_TYPEDEF
+
+#if 0
+#define BOOST_ASIO_ACCEPT_HANDLER_CHECK( \
+ handler_type, handler) \
+ \
+ typedef BOOST_ASIO_HANDLER_TYPE(handler_type, \
+ void(boost::system::error_code)) \
+ asio_true_handler_type; \
+ \
+ BOOST_ASIO_HANDLER_TYPE_REQUIREMENTS_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, \
+ "AcceptHandler 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::lvref< \
+ asio_true_handler_type>()( \
+ boost::asio::detail::lvref<const boost::system::error_code>()), \
+ char(0))> BOOST_ASIO_UNUSED_TYPEDEF
+
+#define BOOST_ASIO_MOVE_ACCEPT_HANDLER_CHECK( \
+ handler_type, handler, socket_type) \
+ \
+ typedef BOOST_ASIO_HANDLER_TYPE(handler_type, \
+ void(boost::system::error_code, socket_type)) \
+ asio_true_handler_type; \
+ \
+ BOOST_ASIO_HANDLER_TYPE_REQUIREMENTS_ASSERT( \
+ sizeof(boost::asio::detail::two_arg_move_handler_test( \
+ boost::asio::detail::rvref< \
+ asio_true_handler_type>(), \
+ static_cast<const boost::system::error_code*>(0), \
+ static_cast<socket_type*>(0))) == 1, \
+ "MoveAcceptHandler 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::lvref< \
+ asio_true_handler_type>()( \
+ boost::asio::detail::lvref<const boost::system::error_code>(), \
+ boost::asio::detail::rvref<socket_type>()), \
+ char(0))> BOOST_ASIO_UNUSED_TYPEDEF
+#endif
+
+#define BOOST_ASIO_CONNECT_HANDLER_CHECK( \
+ handler_type, handler) \
+ \
+ typedef BOOST_ASIO_HANDLER_TYPE(handler_type, \
+ void(boost::system::error_code)) \
+ asio_true_handler_type; \
+ \
+ BOOST_ASIO_HANDLER_TYPE_REQUIREMENTS_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::lvref< \
+ asio_true_handler_type>()( \
+ boost::asio::detail::lvref<const boost::system::error_code>()), \
+ char(0))> BOOST_ASIO_UNUSED_TYPEDEF
+
+#define BOOST_ASIO_RANGE_CONNECT_HANDLER_CHECK( \
+ handler_type, handler, endpoint_type) \
+ \
+ typedef BOOST_ASIO_HANDLER_TYPE(handler_type, \
+ void(boost::system::error_code, endpoint_type)) \
+ asio_true_handler_type; \
+ \
+ BOOST_ASIO_HANDLER_TYPE_REQUIREMENTS_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 endpoint_type*>(0))) == 1, \
+ "RangeConnectHandler 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::lvref< \
+ asio_true_handler_type>()( \
+ boost::asio::detail::lvref<const boost::system::error_code>(), \
+ boost::asio::detail::lvref<const endpoint_type>()), \
+ char(0))> BOOST_ASIO_UNUSED_TYPEDEF
+
+#define BOOST_ASIO_ITERATOR_CONNECT_HANDLER_CHECK( \
+ handler_type, handler, iter_type) \
+ \
+ typedef BOOST_ASIO_HANDLER_TYPE(handler_type, \
+ void(boost::system::error_code, iter_type)) \
+ asio_true_handler_type; \
+ \
+ BOOST_ASIO_HANDLER_TYPE_REQUIREMENTS_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 iter_type*>(0))) == 1, \
+ "IteratorConnectHandler 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::lvref< \
+ asio_true_handler_type>()( \
+ boost::asio::detail::lvref<const boost::system::error_code>(), \
+ boost::asio::detail::lvref<const iter_type>()), \
+ char(0))> BOOST_ASIO_UNUSED_TYPEDEF
+
+#define BOOST_ASIO_RESOLVE_HANDLER_CHECK( \
+ handler_type, handler, range_type) \
+ \
+ typedef BOOST_ASIO_HANDLER_TYPE(handler_type, \
+ void(boost::system::error_code, range_type)) \
+ asio_true_handler_type; \
+ \
+ BOOST_ASIO_HANDLER_TYPE_REQUIREMENTS_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 range_type*>(0))) == 1, \
+ "ResolveHandler 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::lvref< \
+ asio_true_handler_type>()( \
+ boost::asio::detail::lvref<const boost::system::error_code>(), \
+ boost::asio::detail::lvref<const range_type>()), \
+ char(0))> BOOST_ASIO_UNUSED_TYPEDEF
+
+#define BOOST_ASIO_WAIT_HANDLER_CHECK( \
+ handler_type, handler) \
+ \
+ typedef BOOST_ASIO_HANDLER_TYPE(handler_type, \
+ void(boost::system::error_code)) \
+ asio_true_handler_type; \
+ \
+ BOOST_ASIO_HANDLER_TYPE_REQUIREMENTS_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::lvref< \
+ asio_true_handler_type>()( \
+ boost::asio::detail::lvref<const boost::system::error_code>()), \
+ char(0))> BOOST_ASIO_UNUSED_TYPEDEF
+
+#define BOOST_ASIO_SIGNAL_HANDLER_CHECK( \
+ handler_type, handler) \
+ \
+ typedef BOOST_ASIO_HANDLER_TYPE(handler_type, \
+ void(boost::system::error_code, int)) \
+ asio_true_handler_type; \
+ \
+ BOOST_ASIO_HANDLER_TYPE_REQUIREMENTS_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 int*>(0))) == 1, \
+ "SignalHandler 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::lvref< \
+ asio_true_handler_type>()( \
+ boost::asio::detail::lvref<const boost::system::error_code>(), \
+ boost::asio::detail::lvref<const int>()), \
+ char(0))> BOOST_ASIO_UNUSED_TYPEDEF
+
+#define BOOST_ASIO_HANDSHAKE_HANDLER_CHECK( \
+ handler_type, handler) \
+ \
+ typedef BOOST_ASIO_HANDLER_TYPE(handler_type, \
+ void(boost::system::error_code)) \
+ asio_true_handler_type; \
+ \
+ BOOST_ASIO_HANDLER_TYPE_REQUIREMENTS_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, \
+ "HandshakeHandler 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::lvref< \
+ asio_true_handler_type>()( \
+ boost::asio::detail::lvref<const boost::system::error_code>()), \
+ char(0))> BOOST_ASIO_UNUSED_TYPEDEF
+
+#define BOOST_ASIO_BUFFERED_HANDSHAKE_HANDLER_CHECK( \
+ handler_type, handler) \
+ \
+ typedef BOOST_ASIO_HANDLER_TYPE(handler_type, \
+ void(boost::system::error_code, std::size_t)) \
+ asio_true_handler_type; \
+ \
+ BOOST_ASIO_HANDLER_TYPE_REQUIREMENTS_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, \
+ "BufferedHandshakeHandler 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::lvref< \
+ asio_true_handler_type>()( \
+ boost::asio::detail::lvref<const boost::system::error_code>(), \
+ boost::asio::detail::lvref<const std::size_t>()), \
+ char(0))> BOOST_ASIO_UNUSED_TYPEDEF
+
+#define BOOST_ASIO_SHUTDOWN_HANDLER_CHECK( \
+ handler_type, handler) \
+ \
+ typedef BOOST_ASIO_HANDLER_TYPE(handler_type, \
+ void(boost::system::error_code)) \
+ asio_true_handler_type; \
+ \
+ BOOST_ASIO_HANDLER_TYPE_REQUIREMENTS_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, \
+ "ShutdownHandler 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::lvref< \
+ asio_true_handler_type>()( \
+ boost::asio::detail::lvref<const boost::system::error_code>()), \
+ char(0))> BOOST_ASIO_UNUSED_TYPEDEF
+
+#else // !defined(BOOST_ASIO_ENABLE_HANDLER_TYPE_REQUIREMENTS)
+
+#define BOOST_ASIO_LEGACY_COMPLETION_HANDLER_CHECK( \
+ handler_type, handler) \
+ typedef int BOOST_ASIO_UNUSED_TYPEDEF
+
+#define BOOST_ASIO_READ_HANDLER_CHECK( \
+ handler_type, handler) \
+ typedef int BOOST_ASIO_UNUSED_TYPEDEF
+
+#define BOOST_ASIO_WRITE_HANDLER_CHECK( \
+ handler_type, handler) \
+ typedef int BOOST_ASIO_UNUSED_TYPEDEF
+
+#define BOOST_ASIO_ACCEPT_HANDLER_CHECK( \
+ handler_type, handler) \
+ typedef int BOOST_ASIO_UNUSED_TYPEDEF
+
+#define BOOST_ASIO_MOVE_ACCEPT_HANDLER_CHECK( \
+ handler_type, handler, socket_type) \
+ typedef int BOOST_ASIO_UNUSED_TYPEDEF
+
+#define BOOST_ASIO_CONNECT_HANDLER_CHECK( \
+ handler_type, handler) \
+ typedef int BOOST_ASIO_UNUSED_TYPEDEF
+
+#define BOOST_ASIO_RANGE_CONNECT_HANDLER_CHECK( \
+ handler_type, handler, iter_type) \
+ typedef int BOOST_ASIO_UNUSED_TYPEDEF
+
+#define BOOST_ASIO_ITERATOR_CONNECT_HANDLER_CHECK( \
+ handler_type, handler, iter_type) \
+ typedef int BOOST_ASIO_UNUSED_TYPEDEF
+
+#define BOOST_ASIO_RESOLVE_HANDLER_CHECK( \
+ handler_type, handler, iter_type) \
+ typedef int BOOST_ASIO_UNUSED_TYPEDEF
+
+#define BOOST_ASIO_WAIT_HANDLER_CHECK( \
+ handler_type, handler) \
+ typedef int BOOST_ASIO_UNUSED_TYPEDEF
+
+#define BOOST_ASIO_SIGNAL_HANDLER_CHECK( \
+ handler_type, handler) \
+ typedef int BOOST_ASIO_UNUSED_TYPEDEF
+
+#define BOOST_ASIO_HANDSHAKE_HANDLER_CHECK( \
+ handler_type, handler) \
+ typedef int BOOST_ASIO_UNUSED_TYPEDEF
+
+#define BOOST_ASIO_BUFFERED_HANDSHAKE_HANDLER_CHECK( \
+ handler_type, handler) \
+ typedef int BOOST_ASIO_UNUSED_TYPEDEF
+
+#define BOOST_ASIO_SHUTDOWN_HANDLER_CHECK( \
+ handler_type, handler) \
+ typedef int BOOST_ASIO_UNUSED_TYPEDEF
+
+#endif // !defined(BOOST_ASIO_ENABLE_HANDLER_TYPE_REQUIREMENTS)
+
+} // namespace detail
+} // namespace asio
+} // namespace boost
+
+#endif // BOOST_ASIO_DETAIL_HANDLER_TYPE_REQUIREMENTS_EXT_HPP
diff --git a/implementation/helper/1.74/boost/asio/detail/handler_type_requirements_ext_local.hpp b/implementation/helper/1.74/boost/asio/detail/handler_type_requirements_ext_local.hpp
new file mode 100644
index 0000000..65640ad
--- /dev/null
+++ b/implementation/helper/1.74/boost/asio/detail/handler_type_requirements_ext_local.hpp
@@ -0,0 +1,588 @@
+//
+// detail/handler_type_requirements_ext_local.hpp
+// ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+//
+// Copyright (c) 2003-2019 Christopher M. Kohlhoff (chris at kohlhoff dot com)
+// Copyright (c) 2016-2019 Bayerische Motoren Werke Aktiengesellschaft (BMW AG)
+//
+// Distributed under the Boost Software License, Version 1.0. (See accompanying
+// file LICENSE_boost or copy at http://www.boost.org/LICENSE_1_0.txt)
+//
+
+#ifndef BOOST_ASIO_DETAIL_HANDLER_TYPE_REQUIREMENTS_EXT_LOCAL_HPP
+#define BOOST_ASIO_DETAIL_HANDLER_TYPE_REQUIREMENTS_EXT_LOCAL_HPP
+
+#if defined(_MSC_VER) && (_MSC_VER >= 1200)
+# pragma once
+#endif // defined(_MSC_VER) && (_MSC_VER >= 1200)
+
+#include <boost/asio/detail/config.hpp>
+
+// Older versions of gcc have difficulty compiling the sizeof expressions where
+// we test the handler type requirements. We'll disable checking of handler type
+// requirements for those compilers, but otherwise enable it by default.
+#if !defined(BOOST_ASIO_DISABLE_HANDLER_TYPE_REQUIREMENTS)
+# if !defined(__GNUC__) || (__GNUC__ >= 4)
+# define BOOST_ASIO_ENABLE_HANDLER_TYPE_REQUIREMENTS 1
+# endif // !defined(__GNUC__) || (__GNUC__ >= 4)
+#endif // !defined(BOOST_ASIO_DISABLE_HANDLER_TYPE_REQUIREMENTS)
+
+// With C++0x we can use a combination of enhanced SFINAE and static_assert to
+// generate better template error messages. As this technique is not yet widely
+// portable, we'll only enable it for tested compilers.
+#if !defined(BOOST_ASIO_DISABLE_HANDLER_TYPE_REQUIREMENTS_ASSERT)
+# if defined(__GNUC__)
+# if ((__GNUC__ == 4) && (__GNUC_MINOR__ >= 5)) || (__GNUC__ > 4)
+# if defined(__GXX_EXPERIMENTAL_CXX0X__)
+# define BOOST_ASIO_ENABLE_HANDLER_TYPE_REQUIREMENTS_ASSERT 1
+# endif // defined(__GXX_EXPERIMENTAL_CXX0X__)
+# endif // ((__GNUC__ == 4) && (__GNUC_MINOR__ >= 5)) || (__GNUC__ > 4)
+# endif // defined(__GNUC__)
+# if defined(BOOST_ASIO_MSVC)
+# if (_MSC_VER >= 1600)
+# define BOOST_ASIO_ENABLE_HANDLER_TYPE_REQUIREMENTS_ASSERT 1
+# endif // (_MSC_VER >= 1600)
+# endif // defined(BOOST_ASIO_MSVC)
+# if defined(__clang__)
+# if __has_feature(__cxx_static_assert__)
+# define BOOST_ASIO_ENABLE_HANDLER_TYPE_REQUIREMENTS_ASSERT 1
+# endif // __has_feature(cxx_static_assert)
+# endif // defined(__clang__)
+#endif // !defined(BOOST_ASIO_DISABLE_HANDLER_TYPE_REQUIREMENTS)
+
+#if defined(BOOST_ASIO_ENABLE_HANDLER_TYPE_REQUIREMENTS)
+# include <boost/asio/async_result.hpp>
+#endif // defined(BOOST_ASIO_ENABLE_HANDLER_TYPE_REQUIREMENTS)
+
+namespace boost {
+namespace asio {
+namespace detail {
+
+#if defined(BOOST_ASIO_ENABLE_HANDLER_TYPE_REQUIREMENTS)
+
+# if defined(BOOST_ASIO_ENABLE_HANDLER_TYPE_REQUIREMENTS_ASSERT)
+
+template <typename Handler>
+auto zero_arg_copyable_handler_test(Handler h, void*)
+ -> decltype(
+ sizeof(Handler(static_cast<const Handler&>(h))),
+ ((h)()),
+ char(0));
+
+template <typename Handler>
+char (&zero_arg_copyable_handler_test(Handler, ...))[2];
+
+template <typename Handler, typename Arg1>
+auto one_arg_handler_test(Handler h, Arg1* a1)
+ -> decltype(
+ sizeof(Handler(BOOST_ASIO_MOVE_CAST(Handler)(h))),
+ ((h)(*a1)),
+ char(0));
+
+template <typename Handler>
+char (&one_arg_handler_test(Handler h, ...))[2];
+
+template <typename Handler, typename Arg1, typename Arg2>
+auto two_arg_handler_test(Handler h, Arg1* a1, Arg2* a2)
+ -> decltype(
+ sizeof(Handler(BOOST_ASIO_MOVE_CAST(Handler)(h))),
+ ((h)(*a1, *a2)),
+ char(0));
+
+template <typename Handler>
+char (&two_arg_handler_test(Handler, ...))[2];
+
+template <typename Handler, typename Arg1, typename Arg2>
+auto two_arg_move_handler_test(Handler h, Arg1* a1, Arg2* a2)
+ -> decltype(
+ sizeof(Handler(BOOST_ASIO_MOVE_CAST(Handler)(h))),
+ ((h)(*a1, BOOST_ASIO_MOVE_CAST(Arg2)(*a2))),
+ char(0));
+
+template <typename Handler>
+char (&two_arg_move_handler_test(Handler, ...))[2];
+
+template <typename Handler, typename Arg1, typename Arg2, typename Arg3, typename Arg4>
+auto four_arg_handler_test(Handler h, Arg1* a1, Arg2* a2, Arg3* a3, Arg4* a4)
+ -> decltype(
+ sizeof(Handler(BOOST_ASIO_MOVE_CAST(Handler)(h))),
+ ((h)(*a1, *a2, *a3, *a4)),
+ char(0));
+
+template <typename Handler>
+char (&four_arg_handler_test(Handler, ...))[2];
+
+template <typename Handler, typename Arg1, typename Arg2, typename Arg3, typename Arg4>
+auto four_arg_move_handler_test(Handler h, Arg1* a1, Arg2* a2, Arg3* a3, Arg4* a4)
+ -> decltype(
+ sizeof(Handler(BOOST_ASIO_MOVE_CAST(Handler)(h))),
+ ((h)(*a1, BOOST_ASIO_MOVE_CAST(Arg2)(*a2), BOOST_ASIO_MOVE_CAST(Arg3)(*a3), BOOST_ASIO_MOVE_CAST(Arg4)(*a4))),
+ char(0));
+
+template <typename Handler>
+char (&four_arg_move_handler_test(Handler, ...))[2];
+
+# define BOOST_ASIO_HANDLER_TYPE_REQUIREMENTS_ASSERT(expr, msg) \
+ static_assert(expr, msg);
+
+# else // defined(BOOST_ASIO_ENABLE_HANDLER_TYPE_REQUIREMENTS_ASSERT)
+
+# define BOOST_ASIO_HANDLER_TYPE_REQUIREMENTS_ASSERT(expr, msg)
+
+# endif // defined(BOOST_ASIO_ENABLE_HANDLER_TYPE_REQUIREMENTS_ASSERT)
+
+template <typename T> T& lvref();
+template <typename T> T& lvref(T);
+template <typename T> const T& clvref();
+template <typename T> const T& clvref(T);
+#if defined(BOOST_ASIO_HAS_MOVE)
+template <typename T> T rvref();
+template <typename T> T rvref(T);
+#else // defined(BOOST_ASIO_HAS_MOVE)
+template <typename T> const T& rvref();
+template <typename T> const T& rvref(T);
+#endif // defined(BOOST_ASIO_HAS_MOVE)
+template <typename T> char argbyv(T);
+
+#if 0
+template <int>
+struct handler_type_requirements
+{
+};
+#endif
+
+#define BOOST_ASIO_LEGACY_COMPLETION_HANDLER_CHECK( \
+ handler_type, handler) \
+ \
+ typedef BOOST_ASIO_HANDLER_TYPE(handler_type, \
+ void()) asio_true_handler_type; \
+ \
+ BOOST_ASIO_HANDLER_TYPE_REQUIREMENTS_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::lvref< \
+ asio_true_handler_type>()(), \
+ char(0))> BOOST_ASIO_UNUSED_TYPEDEF
+
+#define BOOST_ASIO_READ_HANDLER_CHECK_EXT_LOCAL( \
+ handler_type, handler) \
+ \
+ typedef BOOST_ASIO_HANDLER_TYPE(handler_type, \
+ void(boost::system::error_code, std::size_t, \
+ std::uint32_t, std::uint32_t)) \
+ asio_true_handler_type; \
+ \
+ BOOST_ASIO_HANDLER_TYPE_REQUIREMENTS_ASSERT( \
+ sizeof(boost::asio::detail::four_arg_handler_test( \
+ boost::asio::detail::clvref< \
+ asio_true_handler_type>(), \
+ static_cast<const boost::system::error_code*>(0), \
+ static_cast<const std::size_t*>(0), \
+ static_cast<const std::uint32_t*>(0), \
+ static_cast<const std::uint32_t*>(0))) == 1, \
+ "ReadHandler 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::lvref< \
+ asio_true_handler_type>()( \
+ boost::asio::detail::lvref<const boost::system::error_code>(), \
+ boost::asio::detail::lvref<const std::size_t>(), \
+ boost::asio::detail::lvref<const std::uint32_t>(), \
+ boost::asio::detail::lvref<const std::uint32_t>()), \
+ char(0))> BOOST_ASIO_UNUSED_TYPEDEF
+
+#define BOOST_ASIO_WRITE_HANDLER_CHECK( \
+ handler_type, handler) \
+ \
+ typedef BOOST_ASIO_HANDLER_TYPE(handler_type, \
+ void(boost::system::error_code, std::size_t)) \
+ asio_true_handler_type; \
+ \
+ BOOST_ASIO_HANDLER_TYPE_REQUIREMENTS_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::lvref< \
+ asio_true_handler_type>()( \
+ boost::asio::detail::lvref<const boost::system::error_code>(), \
+ boost::asio::detail::lvref<const std::size_t>()), \
+ char(0))> BOOST_ASIO_UNUSED_TYPEDEF
+
+#if 0
+#define BOOST_ASIO_ACCEPT_HANDLER_CHECK( \
+ handler_type, handler) \
+ \
+ typedef BOOST_ASIO_HANDLER_TYPE(handler_type, \
+ void(boost::system::error_code)) \
+ asio_true_handler_type; \
+ \
+ BOOST_ASIO_HANDLER_TYPE_REQUIREMENTS_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, \
+ "AcceptHandler 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::lvref< \
+ asio_true_handler_type>()( \
+ boost::asio::detail::lvref<const boost::system::error_code>()), \
+ char(0))> BOOST_ASIO_UNUSED_TYPEDEF
+
+#define BOOST_ASIO_MOVE_ACCEPT_HANDLER_CHECK( \
+ handler_type, handler, socket_type) \
+ \
+ typedef BOOST_ASIO_HANDLER_TYPE(handler_type, \
+ void(boost::system::error_code, socket_type)) \
+ asio_true_handler_type; \
+ \
+ BOOST_ASIO_HANDLER_TYPE_REQUIREMENTS_ASSERT( \
+ sizeof(boost::asio::detail::two_arg_move_handler_test( \
+ boost::asio::detail::rvref< \
+ asio_true_handler_type>(), \
+ static_cast<const boost::system::error_code*>(0), \
+ static_cast<socket_type*>(0))) == 1, \
+ "MoveAcceptHandler 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::lvref< \
+ asio_true_handler_type>()( \
+ boost::asio::detail::lvref<const boost::system::error_code>(), \
+ boost::asio::detail::rvref<socket_type>()), \
+ char(0))> BOOST_ASIO_UNUSED_TYPEDEF
+#endif
+
+#define BOOST_ASIO_CONNECT_HANDLER_CHECK( \
+ handler_type, handler) \
+ \
+ typedef BOOST_ASIO_HANDLER_TYPE(handler_type, \
+ void(boost::system::error_code)) \
+ asio_true_handler_type; \
+ \
+ BOOST_ASIO_HANDLER_TYPE_REQUIREMENTS_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::lvref< \
+ asio_true_handler_type>()( \
+ boost::asio::detail::lvref<const boost::system::error_code>()), \
+ char(0))> BOOST_ASIO_UNUSED_TYPEDEF
+
+#define BOOST_ASIO_RANGE_CONNECT_HANDLER_CHECK( \
+ handler_type, handler, endpoint_type) \
+ \
+ typedef BOOST_ASIO_HANDLER_TYPE(handler_type, \
+ void(boost::system::error_code, endpoint_type)) \
+ asio_true_handler_type; \
+ \
+ BOOST_ASIO_HANDLER_TYPE_REQUIREMENTS_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 endpoint_type*>(0))) == 1, \
+ "RangeConnectHandler 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::lvref< \
+ asio_true_handler_type>()( \
+ boost::asio::detail::lvref<const boost::system::error_code>(), \
+ boost::asio::detail::lvref<const endpoint_type>()), \
+ char(0))> BOOST_ASIO_UNUSED_TYPEDEF
+
+#define BOOST_ASIO_ITERATOR_CONNECT_HANDLER_CHECK( \
+ handler_type, handler, iter_type) \
+ \
+ typedef BOOST_ASIO_HANDLER_TYPE(handler_type, \
+ void(boost::system::error_code, iter_type)) \
+ asio_true_handler_type; \
+ \
+ BOOST_ASIO_HANDLER_TYPE_REQUIREMENTS_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 iter_type*>(0))) == 1, \
+ "IteratorConnectHandler 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::lvref< \
+ asio_true_handler_type>()( \
+ boost::asio::detail::lvref<const boost::system::error_code>(), \
+ boost::asio::detail::lvref<const iter_type>()), \
+ char(0))> BOOST_ASIO_UNUSED_TYPEDEF
+
+#define BOOST_ASIO_RESOLVE_HANDLER_CHECK( \
+ handler_type, handler, range_type) \
+ \
+ typedef BOOST_ASIO_HANDLER_TYPE(handler_type, \
+ void(boost::system::error_code, range_type)) \
+ asio_true_handler_type; \
+ \
+ BOOST_ASIO_HANDLER_TYPE_REQUIREMENTS_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 range_type*>(0))) == 1, \
+ "ResolveHandler 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::lvref< \
+ asio_true_handler_type>()( \
+ boost::asio::detail::lvref<const boost::system::error_code>(), \
+ boost::asio::detail::lvref<const range_type>()), \
+ char(0))> BOOST_ASIO_UNUSED_TYPEDEF
+
+#define BOOST_ASIO_WAIT_HANDLER_CHECK( \
+ handler_type, handler) \
+ \
+ typedef BOOST_ASIO_HANDLER_TYPE(handler_type, \
+ void(boost::system::error_code)) \
+ asio_true_handler_type; \
+ \
+ BOOST_ASIO_HANDLER_TYPE_REQUIREMENTS_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::lvref< \
+ asio_true_handler_type>()( \
+ boost::asio::detail::lvref<const boost::system::error_code>()), \
+ char(0))> BOOST_ASIO_UNUSED_TYPEDEF
+
+#define BOOST_ASIO_SIGNAL_HANDLER_CHECK( \
+ handler_type, handler) \
+ \
+ typedef BOOST_ASIO_HANDLER_TYPE(handler_type, \
+ void(boost::system::error_code, int)) \
+ asio_true_handler_type; \
+ \
+ BOOST_ASIO_HANDLER_TYPE_REQUIREMENTS_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 int*>(0))) == 1, \
+ "SignalHandler 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::lvref< \
+ asio_true_handler_type>()( \
+ boost::asio::detail::lvref<const boost::system::error_code>(), \
+ boost::asio::detail::lvref<const int>()), \
+ char(0))> BOOST_ASIO_UNUSED_TYPEDEF
+
+#define BOOST_ASIO_HANDSHAKE_HANDLER_CHECK( \
+ handler_type, handler) \
+ \
+ typedef BOOST_ASIO_HANDLER_TYPE(handler_type, \
+ void(boost::system::error_code)) \
+ asio_true_handler_type; \
+ \
+ BOOST_ASIO_HANDLER_TYPE_REQUIREMENTS_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, \
+ "HandshakeHandler 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::lvref< \
+ asio_true_handler_type>()( \
+ boost::asio::detail::lvref<const boost::system::error_code>()), \
+ char(0))> BOOST_ASIO_UNUSED_TYPEDEF
+
+#define BOOST_ASIO_BUFFERED_HANDSHAKE_HANDLER_CHECK( \
+ handler_type, handler) \
+ \
+ typedef BOOST_ASIO_HANDLER_TYPE(handler_type, \
+ void(boost::system::error_code, std::size_t)) \
+ asio_true_handler_type; \
+ \
+ BOOST_ASIO_HANDLER_TYPE_REQUIREMENTS_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, \
+ "BufferedHandshakeHandler 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::lvref< \
+ asio_true_handler_type>()( \
+ boost::asio::detail::lvref<const boost::system::error_code>(), \
+ boost::asio::detail::lvref<const std::size_t>()), \
+ char(0))> BOOST_ASIO_UNUSED_TYPEDEF
+
+#define BOOST_ASIO_SHUTDOWN_HANDLER_CHECK( \
+ handler_type, handler) \
+ \
+ typedef BOOST_ASIO_HANDLER_TYPE(handler_type, \
+ void(boost::system::error_code)) \
+ asio_true_handler_type; \
+ \
+ BOOST_ASIO_HANDLER_TYPE_REQUIREMENTS_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, \
+ "ShutdownHandler 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::lvref< \
+ asio_true_handler_type>()( \
+ boost::asio::detail::lvref<const boost::system::error_code>()), \
+ char(0))> BOOST_ASIO_UNUSED_TYPEDEF
+
+#else // !defined(BOOST_ASIO_ENABLE_HANDLER_TYPE_REQUIREMENTS)
+
+#define BOOST_ASIO_LEGACY_COMPLETION_HANDLER_CHECK( \
+ handler_type, handler) \
+ typedef int BOOST_ASIO_UNUSED_TYPEDEF
+
+#define BOOST_ASIO_READ_HANDLER_CHECK( \
+ handler_type, handler) \
+ typedef int BOOST_ASIO_UNUSED_TYPEDEF
+
+#define BOOST_ASIO_WRITE_HANDLER_CHECK( \
+ handler_type, handler) \
+ typedef int BOOST_ASIO_UNUSED_TYPEDEF
+
+#define BOOST_ASIO_ACCEPT_HANDLER_CHECK( \
+ handler_type, handler) \
+ typedef int BOOST_ASIO_UNUSED_TYPEDEF
+
+#define BOOST_ASIO_MOVE_ACCEPT_HANDLER_CHECK( \
+ handler_type, handler, socket_type) \
+ typedef int BOOST_ASIO_UNUSED_TYPEDEF
+
+#define BOOST_ASIO_CONNECT_HANDLER_CHECK( \
+ handler_type, handler) \
+ typedef int BOOST_ASIO_UNUSED_TYPEDEF
+
+#define BOOST_ASIO_RANGE_CONNECT_HANDLER_CHECK( \
+ handler_type, handler, iter_type) \
+ typedef int BOOST_ASIO_UNUSED_TYPEDEF
+
+#define BOOST_ASIO_ITERATOR_CONNECT_HANDLER_CHECK( \
+ handler_type, handler, iter_type) \
+ typedef int BOOST_ASIO_UNUSED_TYPEDEF
+
+#define BOOST_ASIO_RESOLVE_HANDLER_CHECK( \
+ handler_type, handler, iter_type) \
+ typedef int BOOST_ASIO_UNUSED_TYPEDEF
+
+#define BOOST_ASIO_WAIT_HANDLER_CHECK( \
+ handler_type, handler) \
+ typedef int BOOST_ASIO_UNUSED_TYPEDEF
+
+#define BOOST_ASIO_SIGNAL_HANDLER_CHECK( \
+ handler_type, handler) \
+ typedef int BOOST_ASIO_UNUSED_TYPEDEF
+
+#define BOOST_ASIO_HANDSHAKE_HANDLER_CHECK( \
+ handler_type, handler) \
+ typedef int BOOST_ASIO_UNUSED_TYPEDEF
+
+#define BOOST_ASIO_BUFFERED_HANDSHAKE_HANDLER_CHECK( \
+ handler_type, handler) \
+ typedef int BOOST_ASIO_UNUSED_TYPEDEF
+
+#define BOOST_ASIO_SHUTDOWN_HANDLER_CHECK( \
+ handler_type, handler) \
+ typedef int BOOST_ASIO_UNUSED_TYPEDEF
+
+#endif // !defined(BOOST_ASIO_ENABLE_HANDLER_TYPE_REQUIREMENTS)
+
+} // namespace detail
+} // namespace asio
+} // namespace boost
+
+#endif // BOOST_ASIO_DETAIL_HANDLER_TYPE_REQUIREMENTS_EXT_LOCAL_HPP
diff --git a/implementation/helper/1.74/boost/asio/detail/impl/reactive_socket_service_base_ext.ipp b/implementation/helper/1.74/boost/asio/detail/impl/reactive_socket_service_base_ext.ipp
new file mode 100644
index 0000000..04036ad
--- /dev/null
+++ b/implementation/helper/1.74/boost/asio/detail/impl/reactive_socket_service_base_ext.ipp
@@ -0,0 +1,302 @@
+//
+// detail/reactive_socket_service_base_ext.ipp
+// ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+//
+// Copyright (c) 2003-2019 Christopher M. Kohlhoff (chris at kohlhoff dot com)
+// Copyright (C) 2016-2019 Bayerische Motoren Werke Aktiengesellschaft (BMW AG)
+//
+// Distributed under the Boost Software License, Version 1.0. (See accompanying
+// file LICENSE_boost or copy at http://www.boost.org/LICENSE_1_0.txt)
+//
+
+#ifndef BOOST_ASIO_DETAIL_IMPL_REACTIVE_SOCKET_SERVICE_BASE_EXT_IPP
+#define BOOST_ASIO_DETAIL_IMPL_REACTIVE_SOCKET_SERVICE_BASE_EXT_IPP
+
+#if defined(_MSC_VER) && (_MSC_VER >= 1200)
+# pragma once
+#endif // defined(_MSC_VER) && (_MSC_VER >= 1200)
+
+#include <boost/asio/detail/config.hpp>
+
+#if !defined(BOOST_ASIO_HAS_IOCP) \
+ && !defined(BOOST_ASIO_WINDOWS_RUNTIME)
+
+#include <boost/asio/detail/reactive_socket_service_base_ext.hpp>
+
+#include <boost/asio/detail/push_options.hpp>
+
+namespace boost {
+namespace asio {
+namespace detail {
+
+reactive_socket_service_base_ext::reactive_socket_service_base_ext(
+ execution_context& context)
+ : reactor_(use_service<reactor>(context))
+{
+ reactor_.init_task();
+}
+
+void reactive_socket_service_base_ext::base_shutdown()
+{
+}
+
+void reactive_socket_service_base_ext::construct(
+ reactive_socket_service_base_ext::base_implementation_type& impl)
+{
+ impl.socket_ = invalid_socket;
+ impl.state_ = 0;
+}
+
+void reactive_socket_service_base_ext::base_move_construct(
+ reactive_socket_service_base_ext::base_implementation_type& impl,
+ reactive_socket_service_base_ext::base_implementation_type& other_impl)
+{
+ impl.socket_ = other_impl.socket_;
+ other_impl.socket_ = invalid_socket;
+
+ impl.state_ = other_impl.state_;
+ other_impl.state_ = 0;
+
+ reactor_.move_descriptor(impl.socket_,
+ impl.reactor_data_, other_impl.reactor_data_);
+}
+
+void reactive_socket_service_base_ext::base_move_assign(
+ reactive_socket_service_base_ext::base_implementation_type& impl,
+ reactive_socket_service_base_ext& other_service,
+ reactive_socket_service_base_ext::base_implementation_type& other_impl)
+{
+ destroy(impl);
+
+ impl.socket_ = other_impl.socket_;
+ other_impl.socket_ = invalid_socket;
+
+ impl.state_ = other_impl.state_;
+ other_impl.state_ = 0;
+
+ other_service.reactor_.move_descriptor(impl.socket_,
+ impl.reactor_data_, other_impl.reactor_data_);
+}
+
+void reactive_socket_service_base_ext::destroy(
+ reactive_socket_service_base_ext::base_implementation_type& impl)
+{
+ if (impl.socket_ != invalid_socket)
+ {
+ BOOST_ASIO_HANDLER_OPERATION((reactor_.context(),
+ "socket", &impl, impl.socket_, "close"));
+
+ reactor_.deregister_descriptor(impl.socket_, impl.reactor_data_,
+ (impl.state_ & socket_ops::possible_dup) == 0);
+
+ boost::system::error_code ignored_ec;
+ socket_ops::close(impl.socket_, impl.state_, true, ignored_ec);
+
+ reactor_.cleanup_descriptor_data(impl.reactor_data_);
+ }
+}
+
+boost::system::error_code reactive_socket_service_base_ext::close(
+ reactive_socket_service_base_ext::base_implementation_type& impl,
+ boost::system::error_code& ec)
+{
+ if (is_open(impl))
+ {
+ BOOST_ASIO_HANDLER_OPERATION((reactor_.context(),
+ "socket", &impl, impl.socket_, "close"));
+
+ reactor_.deregister_descriptor(impl.socket_, impl.reactor_data_,
+ (impl.state_ & socket_ops::possible_dup) == 0);
+
+ socket_ops::close(impl.socket_, impl.state_, false, ec);
+
+ reactor_.cleanup_descriptor_data(impl.reactor_data_);
+ }
+ else
+ {
+ ec = boost::system::error_code();
+ }
+
+ // The descriptor is closed by the OS even if close() returns an error.
+ //
+ // (Actually, POSIX says the state of the descriptor is unspecified. On
+ // Linux the descriptor is apparently closed anyway; e.g. see
+ // http://lkml.org/lkml/2005/9/10/129
+ // We'll just have to assume that other OSes follow the same behaviour. The
+ // known exception is when Windows's closesocket() function fails with
+ // WSAEWOULDBLOCK, but this case is handled inside socket_ops::close().
+ construct(impl);
+
+ return ec;
+}
+/*
+socket_type reactive_socket_service_base::release(
+ reactive_socket_service_base::base_implementation_type& impl,
+ boost::system::error_code& ec)
+{
+ if (!is_open(impl))
+ {
+ ec = boost::asio::error::bad_descriptor;
+ return invalid_socket;
+ }
+
+ BOOST_ASIO_HANDLER_OPERATION((reactor_.context(),
+ "socket", &impl, impl.socket_, "release"));
+
+ reactor_.deregister_descriptor(impl.socket_, impl.reactor_data_, false);
+ reactor_.cleanup_descriptor_data(impl.reactor_data_);
+ socket_type sock = impl.socket_;
+ construct(impl);
+ ec = boost::system::error_code();
+ return sock;
+}
+*/
+boost::system::error_code reactive_socket_service_base_ext::cancel(
+ reactive_socket_service_base_ext::base_implementation_type& impl,
+ boost::system::error_code& ec)
+{
+ if (!is_open(impl))
+ {
+ ec = boost::asio::error::bad_descriptor;
+ return ec;
+ }
+
+ BOOST_ASIO_HANDLER_OPERATION((reactor_.context(),
+ "socket", &impl, impl.socket_, "cancel"));
+
+ reactor_.cancel_ops(impl.socket_, impl.reactor_data_);
+ ec = boost::system::error_code();
+ return ec;
+}
+
+boost::system::error_code reactive_socket_service_base_ext::do_open(
+ reactive_socket_service_base_ext::base_implementation_type& impl,
+ int af, int type, int protocol, boost::system::error_code& ec)
+{
+ if (is_open(impl))
+ {
+ ec = boost::asio::error::already_open;
+ return ec;
+ }
+
+ socket_holder sock(socket_ops::socket(af, type, protocol, ec));
+ if (sock.get() == invalid_socket)
+ return ec;
+
+ if (int err = reactor_.register_descriptor(sock.get(), impl.reactor_data_))
+ {
+ ec = boost::system::error_code(err,
+ boost::asio::error::get_system_category());
+ return ec;
+ }
+
+ impl.socket_ = sock.release();
+ switch (type)
+ {
+ case SOCK_STREAM: impl.state_ = socket_ops::stream_oriented; break;
+ case SOCK_DGRAM: impl.state_ = socket_ops::datagram_oriented; break;
+ default: impl.state_ = 0; break;
+ }
+ ec = boost::system::error_code();
+ return ec;
+}
+
+boost::system::error_code reactive_socket_service_base_ext::do_assign(
+ reactive_socket_service_base_ext::base_implementation_type& impl, int type,
+ const reactive_socket_service_base_ext::native_handle_type& native_socket,
+ boost::system::error_code& ec)
+{
+ if (is_open(impl))
+ {
+ ec = boost::asio::error::already_open;
+ return ec;
+ }
+
+ if (int err = reactor_.register_descriptor(
+ native_socket, impl.reactor_data_))
+ {
+ ec = boost::system::error_code(err,
+ boost::asio::error::get_system_category());
+ return ec;
+ }
+
+ impl.socket_ = native_socket;
+ switch (type)
+ {
+ case SOCK_STREAM: impl.state_ = socket_ops::stream_oriented; break;
+ case SOCK_DGRAM: impl.state_ = socket_ops::datagram_oriented; break;
+ default: impl.state_ = 0; break;
+ }
+ impl.state_ |= socket_ops::possible_dup;
+ ec = boost::system::error_code();
+ return ec;
+}
+
+void reactive_socket_service_base_ext::start_op(
+ reactive_socket_service_base_ext::base_implementation_type& impl,
+ int op_type, reactor_op* op, bool is_continuation,
+ bool is_non_blocking, bool noop)
+{
+ if (!noop)
+ {
+ if ((impl.state_ & socket_ops::non_blocking)
+ || socket_ops::set_internal_non_blocking(
+ impl.socket_, impl.state_, true, op->ec_))
+ {
+ reactor_.start_op(op_type, impl.socket_,
+ impl.reactor_data_, op, is_continuation, is_non_blocking);
+ return;
+ }
+ }
+
+ reactor_.post_immediate_completion(op, is_continuation);
+}
+
+void reactive_socket_service_base_ext::start_accept_op(
+ reactive_socket_service_base_ext::base_implementation_type& impl,
+ reactor_op* op, bool is_continuation, bool peer_is_open)
+{
+ if (!peer_is_open)
+ start_op(impl, reactor::read_op, op, is_continuation, true, false);
+ else
+ {
+ op->ec_ = boost::asio::error::already_open;
+ reactor_.post_immediate_completion(op, is_continuation);
+ }
+}
+
+void reactive_socket_service_base_ext::start_connect_op(
+ reactive_socket_service_base_ext::base_implementation_type& impl,
+ reactor_op* op, bool is_continuation,
+ const socket_addr_type* addr, size_t addrlen)
+{
+ if ((impl.state_ & socket_ops::non_blocking)
+ || socket_ops::set_internal_non_blocking(
+ impl.socket_, impl.state_, true, op->ec_))
+ {
+ if (socket_ops::connect(impl.socket_, addr, addrlen, op->ec_) != 0)
+ {
+ if (op->ec_ == boost::asio::error::in_progress
+ || op->ec_ == boost::asio::error::would_block)
+ {
+ op->ec_ = boost::system::error_code();
+ reactor_.start_op(reactor::connect_op, impl.socket_,
+ impl.reactor_data_, op, is_continuation, false);
+ return;
+ }
+ }
+ }
+
+ reactor_.post_immediate_completion(op, is_continuation);
+}
+
+} // namespace detail
+} // namespace asio
+} // namespace boost
+
+#include <boost/asio/detail/pop_options.hpp>
+
+#endif // !defined(BOOST_ASIO_HAS_IOCP)
+ // && !defined(BOOST_ASIO_WINDOWS_RUNTIME)
+
+#endif // BOOST_ASIO_DETAIL_IMPL_REACTIVE_SOCKET_SERVICE_BASE_EXT_IPP
diff --git a/implementation/helper/1.74/boost/asio/detail/impl/reactive_socket_service_base_ext_local.ipp b/implementation/helper/1.74/boost/asio/detail/impl/reactive_socket_service_base_ext_local.ipp
new file mode 100644
index 0000000..288cf19
--- /dev/null
+++ b/implementation/helper/1.74/boost/asio/detail/impl/reactive_socket_service_base_ext_local.ipp
@@ -0,0 +1,302 @@
+//
+// detail/reactive_socket_service_base_ext_local.ipp
+// ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+//
+// Copyright (c) 2003-2019 Christopher M. Kohlhoff (chris at kohlhoff dot com)
+// Copyright (C) 2016-2019 Bayerische Motoren Werke Aktiengesellschaft (BMW AG)
+//
+// Distributed under the Boost Software License, Version 1.0. (See accompanying
+// file LICENSE_boost or copy at http://www.boost.org/LICENSE_1_0.txt)
+//
+
+#ifndef BOOST_ASIO_DETAIL_IMPL_REACTIVE_SOCKET_SERVICE_BASE_EXT_LOCAL_IPP
+#define BOOST_ASIO_DETAIL_IMPL_REACTIVE_SOCKET_SERVICE_BASE_EXT_LOCAL_IPP
+
+#if defined(_MSC_VER) && (_MSC_VER >= 1200)
+# pragma once
+#endif // defined(_MSC_VER) && (_MSC_VER >= 1200)
+
+#include <boost/asio/detail/config.hpp>
+
+#if !defined(BOOST_ASIO_HAS_IOCP) \
+ && !defined(BOOST_ASIO_WINDOWS_RUNTIME)
+
+#include <boost/asio/detail/reactive_socket_service_base_ext_local.hpp>
+
+#include <boost/asio/detail/push_options.hpp>
+
+namespace boost {
+namespace asio {
+namespace detail {
+
+reactive_socket_service_base_ext_local::reactive_socket_service_base_ext_local(
+ execution_context& context)
+ : reactor_(use_service<reactor>(context))
+{
+ reactor_.init_task();
+}
+
+void reactive_socket_service_base_ext_local::base_shutdown()
+{
+}
+
+void reactive_socket_service_base_ext_local::construct(
+ reactive_socket_service_base_ext_local::base_implementation_type& impl)
+{
+ impl.socket_ = invalid_socket;
+ impl.state_ = 0;
+}
+
+void reactive_socket_service_base_ext_local::base_move_construct(
+ reactive_socket_service_base_ext_local::base_implementation_type& impl,
+ reactive_socket_service_base_ext_local::base_implementation_type& other_impl)
+{
+ impl.socket_ = other_impl.socket_;
+ other_impl.socket_ = invalid_socket;
+
+ impl.state_ = other_impl.state_;
+ other_impl.state_ = 0;
+
+ reactor_.move_descriptor(impl.socket_,
+ impl.reactor_data_, other_impl.reactor_data_);
+}
+
+void reactive_socket_service_base_ext_local::base_move_assign(
+ reactive_socket_service_base_ext_local::base_implementation_type& impl,
+ reactive_socket_service_base_ext_local& other_service,
+ reactive_socket_service_base_ext_local::base_implementation_type& other_impl)
+{
+ destroy(impl);
+
+ impl.socket_ = other_impl.socket_;
+ other_impl.socket_ = invalid_socket;
+
+ impl.state_ = other_impl.state_;
+ other_impl.state_ = 0;
+
+ other_service.reactor_.move_descriptor(impl.socket_,
+ impl.reactor_data_, other_impl.reactor_data_);
+}
+
+void reactive_socket_service_base_ext_local::destroy(
+ reactive_socket_service_base_ext_local::base_implementation_type& impl)
+{
+ if (impl.socket_ != invalid_socket)
+ {
+ BOOST_ASIO_HANDLER_OPERATION((reactor_.context(),
+ "socket", &impl, impl.socket_, "close"));
+
+ reactor_.deregister_descriptor(impl.socket_, impl.reactor_data_,
+ (impl.state_ & socket_ops::possible_dup) == 0);
+
+ boost::system::error_code ignored_ec;
+ socket_ops::close(impl.socket_, impl.state_, true, ignored_ec);
+
+ reactor_.cleanup_descriptor_data(impl.reactor_data_);
+ }
+}
+
+boost::system::error_code reactive_socket_service_base_ext_local::close(
+ reactive_socket_service_base_ext_local::base_implementation_type& impl,
+ boost::system::error_code& ec)
+{
+ if (is_open(impl))
+ {
+ BOOST_ASIO_HANDLER_OPERATION((reactor_.context(),
+ "socket", &impl, impl.socket_, "close"));
+
+ reactor_.deregister_descriptor(impl.socket_, impl.reactor_data_,
+ (impl.state_ & socket_ops::possible_dup) == 0);
+
+ socket_ops::close(impl.socket_, impl.state_, false, ec);
+
+ reactor_.cleanup_descriptor_data(impl.reactor_data_);
+ }
+ else
+ {
+ ec = boost::system::error_code();
+ }
+
+ // The descriptor is closed by the OS even if close() returns an error.
+ //
+ // (Actually, POSIX says the state of the descriptor is unspecified. On
+ // Linux the descriptor is apparently closed anyway; e.g. see
+ // http://lkml.org/lkml/2005/9/10/129
+ // We'll just have to assume that other OSes follow the same behaviour. The
+ // known exception is when Windows's closesocket() function fails with
+ // WSAEWOULDBLOCK, but this case is handled inside socket_ops::close().
+ construct(impl);
+
+ return ec;
+}
+/*
+socket_type reactive_socket_service_base::release(
+ reactive_socket_service_base::base_implementation_type& impl,
+ boost::system::error_code& ec)
+{
+ if (!is_open(impl))
+ {
+ ec = boost::asio::error::bad_descriptor;
+ return invalid_socket;
+ }
+
+ BOOST_ASIO_HANDLER_OPERATION((reactor_.context(),
+ "socket", &impl, impl.socket_, "release"));
+
+ reactor_.deregister_descriptor(impl.socket_, impl.reactor_data_, false);
+ reactor_.cleanup_descriptor_data(impl.reactor_data_);
+ socket_type sock = impl.socket_;
+ construct(impl);
+ ec = boost::system::error_code();
+ return sock;
+}
+*/
+boost::system::error_code reactive_socket_service_base_ext_local::cancel(
+ reactive_socket_service_base_ext_local::base_implementation_type& impl,
+ boost::system::error_code& ec)
+{
+ if (!is_open(impl))
+ {
+ ec = boost::asio::error::bad_descriptor;
+ return ec;
+ }
+
+ BOOST_ASIO_HANDLER_OPERATION((reactor_.context(),
+ "socket", &impl, impl.socket_, "cancel"));
+
+ reactor_.cancel_ops(impl.socket_, impl.reactor_data_);
+ ec = boost::system::error_code();
+ return ec;
+}
+
+boost::system::error_code reactive_socket_service_base_ext_local::do_open(
+ reactive_socket_service_base_ext_local::base_implementation_type& impl,
+ int af, int type, int protocol, boost::system::error_code& ec)
+{
+ if (is_open(impl))
+ {
+ ec = boost::asio::error::already_open;
+ return ec;
+ }
+
+ socket_holder sock(socket_ops::socket(af, type, protocol, ec));
+ if (sock.get() == invalid_socket)
+ return ec;
+
+ if (int err = reactor_.register_descriptor(sock.get(), impl.reactor_data_))
+ {
+ ec = boost::system::error_code(err,
+ boost::asio::error::get_system_category());
+ return ec;
+ }
+
+ impl.socket_ = sock.release();
+ switch (type)
+ {
+ case SOCK_STREAM: impl.state_ = socket_ops::stream_oriented; break;
+ case SOCK_DGRAM: impl.state_ = socket_ops::datagram_oriented; break;
+ default: impl.state_ = 0; break;
+ }
+ ec = boost::system::error_code();
+ return ec;
+}
+
+boost::system::error_code reactive_socket_service_base_ext_local::do_assign(
+ reactive_socket_service_base_ext_local::base_implementation_type& impl, int type,
+ const reactive_socket_service_base_ext_local::native_handle_type& native_socket,
+ boost::system::error_code& ec)
+{
+ if (is_open(impl))
+ {
+ ec = boost::asio::error::already_open;
+ return ec;
+ }
+
+ if (int err = reactor_.register_descriptor(
+ native_socket, impl.reactor_data_))
+ {
+ ec = boost::system::error_code(err,
+ boost::asio::error::get_system_category());
+ return ec;
+ }
+
+ impl.socket_ = native_socket;
+ switch (type)
+ {
+ case SOCK_STREAM: impl.state_ = socket_ops::stream_oriented; break;
+ case SOCK_DGRAM: impl.state_ = socket_ops::datagram_oriented; break;
+ default: impl.state_ = 0; break;
+ }
+ impl.state_ |= socket_ops::possible_dup;
+ ec = boost::system::error_code();
+ return ec;
+}
+
+void reactive_socket_service_base_ext_local::start_op(
+ reactive_socket_service_base_ext_local::base_implementation_type& impl,
+ int op_type, reactor_op* op, bool is_continuation,
+ bool is_non_blocking, bool noop)
+{
+ if (!noop)
+ {
+ if ((impl.state_ & socket_ops::non_blocking)
+ || socket_ops::set_internal_non_blocking(
+ impl.socket_, impl.state_, true, op->ec_))
+ {
+ reactor_.start_op(op_type, impl.socket_,
+ impl.reactor_data_, op, is_continuation, is_non_blocking);
+ return;
+ }
+ }
+
+ reactor_.post_immediate_completion(op, is_continuation);
+}
+
+void reactive_socket_service_base_ext_local::start_accept_op(
+ reactive_socket_service_base_ext_local::base_implementation_type& impl,
+ reactor_op* op, bool is_continuation, bool peer_is_open)
+{
+ if (!peer_is_open)
+ start_op(impl, reactor::read_op, op, is_continuation, true, false);
+ else
+ {
+ op->ec_ = boost::asio::error::already_open;
+ reactor_.post_immediate_completion(op, is_continuation);
+ }
+}
+
+void reactive_socket_service_base_ext_local::start_connect_op(
+ reactive_socket_service_base_ext_local::base_implementation_type& impl,
+ reactor_op* op, bool is_continuation,
+ const socket_addr_type* addr, size_t addrlen)
+{
+ if ((impl.state_ & socket_ops::non_blocking)
+ || socket_ops::set_internal_non_blocking(
+ impl.socket_, impl.state_, true, op->ec_))
+ {
+ if (socket_ops::connect(impl.socket_, addr, addrlen, op->ec_) != 0)
+ {
+ if (op->ec_ == boost::asio::error::in_progress
+ || op->ec_ == boost::asio::error::would_block)
+ {
+ op->ec_ = boost::system::error_code();
+ reactor_.start_op(reactor::connect_op, impl.socket_,
+ impl.reactor_data_, op, is_continuation, false);
+ return;
+ }
+ }
+ }
+
+ reactor_.post_immediate_completion(op, is_continuation);
+}
+
+} // namespace detail
+} // namespace asio
+} // namespace boost
+
+#include <boost/asio/detail/pop_options.hpp>
+
+#endif // !defined(BOOST_ASIO_HAS_IOCP)
+ // && !defined(BOOST_ASIO_WINDOWS_RUNTIME)
+
+#endif // BOOST_ASIO_DETAIL_IMPL_REACTIVE_SOCKET_SERVICE_BASE_EXT_LOCAL_IPP
diff --git a/implementation/helper/1.74/boost/asio/detail/impl/socket_ops_ext.ipp b/implementation/helper/1.74/boost/asio/detail/impl/socket_ops_ext.ipp
new file mode 100644
index 0000000..d9585f6
--- /dev/null
+++ b/implementation/helper/1.74/boost/asio/detail/impl/socket_ops_ext.ipp
@@ -0,0 +1,214 @@
+//
+// detail/impl/socket_ops_ext.ipp
+// ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+//
+// Copyright (c) 2003-2018 Christopher M. Kohlhoff (chris at kohlhoff dot com)
+// Copyright (C) 2016-2019 Bayerische Motoren Werke Aktiengesellschaft (BMW AG)
+//
+// Distributed under the Boost Software License, Version 1.0. (See accompanying
+// file LICENSE_boost or copy at http://www.boost.org/LICENSE_1_0.txt)
+//
+
+#ifndef BOOST_ASIO_DETAIL_SOCKET_OPS_EXT_IPP
+#define BOOST_ASIO_DETAIL_SOCKET_OPS_EXT_IPP
+
+#include <boost/asio/detail/impl/socket_ops.ipp>
+
+#include <boost/asio/detail/push_options.hpp>
+
+namespace boost {
+namespace asio {
+namespace detail {
+namespace socket_ops {
+
+signed_size_type recvfrom(socket_type s, buf* bufs, size_t count,
+ int flags, socket_addr_type* addr, std::size_t* addrlen,
+ boost::system::error_code& ec, boost::asio::ip::address& da)
+{
+
+#if defined(BOOST_ASIO_WINDOWS) || defined(__CYGWIN__)
+ GUID WSARecvMsg_GUID = WSAID_WSARECVMSG;
+ LPFN_WSARECVMSG WSARecvMsg;
+ DWORD NumberOfBytes;
+ signed_size_type result;
+
+ result = WSAIoctl(s, SIO_GET_EXTENSION_FUNCTION_POINTER,
+ &WSARecvMsg_GUID, sizeof WSARecvMsg_GUID,
+ &WSARecvMsg, sizeof WSARecvMsg,
+ &NumberOfBytes, NULL, NULL);
+ get_last_error(ec, true);
+ if (ec.value() == SOCKET_ERROR) {
+ WSARecvMsg = NULL;
+ return 0;
+ }
+
+ WSABUF wsaBuf;
+ WSAMSG msg;
+ char controlBuffer[1024];
+ msg.name = addr;
+ msg.namelen = *addrlen;
+ wsaBuf.buf = bufs->buf;
+ wsaBuf.len = bufs->len;
+ msg.lpBuffers = &wsaBuf;
+ msg.dwBufferCount = count;
+ msg.Control.len = sizeof controlBuffer;
+ msg.Control.buf = controlBuffer;
+ msg.dwFlags = flags;
+
+ DWORD dwNumberOfBytesRecvd;
+ result = WSARecvMsg(s, &msg, &dwNumberOfBytesRecvd, NULL, NULL);
+ get_last_error(ec, true);
+
+ if (result >= 0) {
+ ec = boost::system::error_code();
+
+ // Find destination address
+ for (LPWSACMSGHDR cmsg = WSA_CMSG_FIRSTHDR(&msg);
+ cmsg != NULL;
+ cmsg = WSA_CMSG_NXTHDR(&msg, cmsg))
+ {
+ if (cmsg->cmsg_level != IPPROTO_IP || cmsg->cmsg_type != IP_PKTINFO)
+ continue;
+
+ struct in_pktinfo *pi = (struct in_pktinfo *) WSA_CMSG_DATA(cmsg);
+ if (pi)
+ {
+ da = boost::asio::ip::address_v4(ntohl(pi->ipi_addr.s_addr));
+ }
+ }
+ } else {
+ dwNumberOfBytesRecvd = -1;
+ }
+ return dwNumberOfBytesRecvd;
+#else // defined(BOOST_ASIO_WINDOWS) || defined(__CYGWIN__)
+ char cmbuf[0x100];
+ msghdr msg = msghdr();
+ init_msghdr_msg_name(msg.msg_name, addr);
+ msg.msg_namelen = static_cast<int>(*addrlen);
+ msg.msg_iov = bufs;
+ msg.msg_iovlen = static_cast<int>(count);
+ msg.msg_control = cmbuf;
+ msg.msg_controllen = sizeof(cmbuf);
+ signed_size_type result = ::recvmsg(s, &msg, flags);
+ get_last_error(ec, true);
+ *addrlen = msg.msg_namelen;
+ if (result >= 0) {
+ ec.assign(0, ec.category());
+
+ // Find destination address
+ for (struct cmsghdr *cmsg = CMSG_FIRSTHDR(&msg);
+ cmsg != NULL;
+ cmsg = CMSG_NXTHDR(&msg, cmsg))
+ {
+ if (cmsg->cmsg_level != IPPROTO_IP || cmsg->cmsg_type != IP_PKTINFO)
+ continue;
+
+ struct in_pktinfo *pi = (struct in_pktinfo *) CMSG_DATA(cmsg);
+ if (pi)
+ {
+ da = boost::asio::ip::address_v4(ntohl(pi->ipi_addr.s_addr));
+ }
+ }
+ }
+ return result;
+#endif // defined(BOOST_ASIO_WINDOWS) || defined(__CYGWIN__)
+}
+
+size_t sync_recvfrom(socket_type s, state_type state, buf* bufs,
+ size_t count, int flags, socket_addr_type* addr,
+ std::size_t* addrlen, boost::system::error_code& ec, boost::asio::ip::address& da)
+{
+ if (s == invalid_socket)
+ {
+ ec = boost::asio::error::bad_descriptor;
+ return 0;
+ }
+
+ // Read some data.
+ for (;;)
+ {
+ // Try to complete the operation without blocking.
+ signed_size_type bytes = socket_ops::recvfrom(
+ s, bufs, count, flags, addr, addrlen, ec, da);
+
+ // Check if operation succeeded.
+ if (bytes >= 0)
+ return bytes;
+
+ // Operation failed.
+ if ((state & user_set_non_blocking)
+ || (ec != boost::asio::error::would_block
+ && ec != boost::asio::error::try_again))
+ return 0;
+
+ // Wait for socket to become ready.
+ if (socket_ops::poll_read(s, 0, -1, ec) < 0)
+ return 0;
+ }
+}
+
+#if defined(BOOST_ASIO_HAS_IOCP)
+
+void complete_iocp_recvfrom(
+ const weak_cancel_token_type& cancel_token,
+ boost::system::error_code& ec, boost::asio::ip::address& da)
+{
+ // Map non-portable errors to their portable counterparts.
+ if (ec.value() == ERROR_NETNAME_DELETED)
+ {
+ if (cancel_token.expired())
+ ec = boost::asio::error::operation_aborted;
+ else
+ ec = boost::asio::error::connection_reset;
+ }
+ else if (ec.value() == ERROR_PORT_UNREACHABLE)
+ {
+ ec = boost::asio::error::connection_refused;
+ }
+}
+
+#else // defined(BOOST_ASIO_HAS_IOCP)
+
+bool non_blocking_recvfrom(socket_type s,
+ buf* bufs, size_t count, int flags,
+ socket_addr_type* addr, std::size_t* addrlen,
+ boost::system::error_code& ec, size_t& bytes_transferred, boost::asio::ip::address& da)
+{
+ for (;;)
+ {
+ // Read some data.
+ signed_size_type bytes = socket_ops::recvfrom(
+ s, bufs, count, flags, addr, addrlen, ec, da);
+
+ // Retry operation if interrupted by signal.
+ if (ec == boost::asio::error::interrupted)
+ continue;
+
+ // Check if we need to run the operation again.
+ if (ec == boost::asio::error::would_block
+ || ec == boost::asio::error::try_again)
+ return false;
+
+ // Operation is complete.
+ if (bytes >= 0)
+ {
+ ec = boost::system::error_code();
+ bytes_transferred = bytes;
+ }
+ else
+ bytes_transferred = 0;
+
+ return true;
+ }
+}
+
+#endif // defined(BOOST_ASIO_HAS_IOCP)
+
+} // namespace socket_ops
+} // namespace detail
+} // namespace asio
+} // namespace boost
+
+#include <boost/asio/detail/pop_options.hpp>
+
+#endif // BOOST_ASIO_DETAIL_SOCKET_OPS_EXT_IPP
diff --git a/implementation/helper/1.74/boost/asio/detail/impl/socket_ops_ext_local.ipp b/implementation/helper/1.74/boost/asio/detail/impl/socket_ops_ext_local.ipp
new file mode 100644
index 0000000..83a673b
--- /dev/null
+++ b/implementation/helper/1.74/boost/asio/detail/impl/socket_ops_ext_local.ipp
@@ -0,0 +1,307 @@
+//
+// detail/impl/socket_ops_ext_local.ipp
+// ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+//
+// Copyright (c) 2003-2018 Christopher M. Kohlhoff (chris at kohlhoff dot com)
+// Copyright (C) 2016-2019 Bayerische Motoren Werke Aktiengesellschaft (BMW AG)
+//
+// Distributed under the Boost Software License, Version 1.0. (See accompanying
+// file LICENSE_boost or copy at http://www.boost.org/LICENSE_1_0.txt)
+//
+
+#ifndef BOOST_ASIO_DETAIL_SOCKET_OPS_EXT_LOCAL_IPP
+#define BOOST_ASIO_DETAIL_SOCKET_OPS_EXT_LOCAL_IPP
+
+#include <boost/asio/detail/impl/socket_ops.ipp>
+
+#include <boost/asio/detail/push_options.hpp>
+
+namespace boost {
+namespace asio {
+namespace detail {
+namespace socket_ops {
+
+signed_size_type recv(socket_type s, buf* bufs, size_t count,
+ int flags, boost::system::error_code& ec,
+ std::uint32_t& uid, std::uint32_t& gid)
+{
+ uid = 0xFFFFFFFF;
+ gid = 0xFFFFFFFF;
+ struct ucred *ucredp;
+
+#if defined(BOOST_ASIO_WINDOWS) || defined(__CYGWIN__)
+ // Receive some data.
+ DWORD recv_buf_count = static_cast<DWORD>(count);
+ DWORD bytes_transferred = 0;
+ DWORD recv_flags = flags;
+ int result = ::WSARecv(s, bufs,
+ recv_buf_count, &bytes_transferred, &recv_flags, 0, 0);
+ get_last_error(ec, true);
+ if (ec.value() == ERROR_NETNAME_DELETED)
+ ec = boost::asio::error::connection_reset;
+ else if (ec.value() == ERROR_PORT_UNREACHABLE)
+ ec = boost::asio::error::connection_refused;
+ if (result != 0)
+ return socket_error_retval;
+ ec.assign(0, ec.category());
+ return bytes_transferred;
+#else // defined(BOOST_ASIO_WINDOWS) || defined(__CYGWIN__)
+ msghdr msg = msghdr();
+ msg.msg_iov = bufs;
+ msg.msg_iovlen = static_cast<int>(count);
+
+ union {
+ struct cmsghdr cmh;
+ char control[CMSG_SPACE(sizeof(struct ucred))];
+ } control_un;
+
+ // Set 'control_un' to describe ancillary data that we want to receive
+ control_un.cmh.cmsg_len = CMSG_LEN(sizeof(struct ucred));
+ control_un.cmh.cmsg_level = SOL_SOCKET;
+ control_un.cmh.cmsg_type = SCM_CREDENTIALS;
+
+ // Set 'msg' fields to describe 'control_un'
+ msg.msg_control = control_un.control;
+ msg.msg_controllen = sizeof(control_un.control);
+
+ signed_size_type result = ::recvmsg(s, &msg, flags);
+ get_last_error(ec, true);
+ if (result >= 0) {
+ ec.assign(0, ec.category());
+
+ // Find UID / GID
+ for (struct cmsghdr *cmsg = CMSG_FIRSTHDR(&msg);
+ cmsg != NULL;
+ cmsg = CMSG_NXTHDR(&msg, cmsg))
+ {
+ if (cmsg->cmsg_level != SOL_SOCKET || cmsg->cmsg_type != SCM_CREDENTIALS
+ || cmsg->cmsg_len != CMSG_LEN(sizeof(struct ucred)))
+ continue;
+
+ ucredp = (struct ucred *) CMSG_DATA(cmsg);
+ if (ucredp) {
+ uid = ucredp->uid;
+ gid = ucredp->gid;
+ }
+ }
+ }
+ return result;
+#endif // defined(BOOST_ASIO_WINDOWS) || defined(__CYGWIN__)
+}
+
+signed_size_type recvfrom(socket_type s, buf* bufs, size_t count,
+ int flags, socket_addr_type* addr, std::size_t* addrlen,
+ boost::system::error_code& ec,
+ std::uint32_t& uid, std::uint32_t& gid)
+{
+ uid = 0xFFFFFFFF;
+ gid = 0xFFFFFFFF;
+ struct ucred *ucredp;
+ clear_last_error();
+#if defined(BOOST_ASIO_WINDOWS) || defined(__CYGWIN__)
+ // Receive some data.
+ DWORD recv_buf_count = static_cast<DWORD>(count);
+ DWORD bytes_transferred = 0;
+ DWORD recv_flags = flags;
+ int tmp_addrlen = (int)*addrlen;
+ int result = ::WSARecvFrom(s, bufs, recv_buf_count,
+ &bytes_transferred, &recv_flags, addr, &tmp_addrlen, 0, 0);
+ get_last_error(ec, true);
+ *addrlen = (std::size_t)tmp_addrlen;
+ if (ec.value() == ERROR_NETNAME_DELETED)
+ ec = boost::asio::error::connection_reset;
+ else if (ec.value() == ERROR_PORT_UNREACHABLE)
+ ec = boost::asio::error::connection_refused;
+ if (result != 0)
+ return socket_error_retval;
+ ec.assign(0, ec.category());
+ return bytes_transferred;
+#else // defined(BOOST_ASIO_WINDOWS) || defined(__CYGWIN__)
+ msghdr msg = msghdr();
+ init_msghdr_msg_name(msg.msg_name, addr);
+ msg.msg_namelen = static_cast<int>(*addrlen);
+ msg.msg_iov = bufs;
+ msg.msg_iovlen = static_cast<int>(count);
+
+ union {
+ struct cmsghdr cmh;
+ char control[CMSG_SPACE(sizeof(struct ucred))];
+ } control_un;
+
+ // Set 'control_un' to describe ancillary data that we want to receive
+ control_un.cmh.cmsg_len = CMSG_LEN(sizeof(struct ucred));
+ control_un.cmh.cmsg_level = SOL_SOCKET;
+ control_un.cmh.cmsg_type = SCM_CREDENTIALS;
+
+ // Set 'msg' fields to describe 'control_un'
+ msg.msg_control = control_un.control;
+ msg.msg_controllen = sizeof(control_un.control);
+
+ signed_size_type result = ::recvmsg(s, &msg, flags);
+ get_last_error(ec, true);
+ *addrlen = msg.msg_namelen;
+ if (result >= 0) {
+ ec.assign(0, ec.category());
+
+ // Find UID / GID
+ for (struct cmsghdr *cmsg = CMSG_FIRSTHDR(&msg);
+ cmsg != NULL;
+ cmsg = CMSG_NXTHDR(&msg, cmsg))
+ {
+ if (cmsg->cmsg_level != SOL_SOCKET || cmsg->cmsg_type != SCM_CREDENTIALS
+ || cmsg->cmsg_len != CMSG_LEN(sizeof(struct ucred)))
+ continue;
+
+ ucredp = (struct ucred *) CMSG_DATA(cmsg);
+ if (ucredp) {
+ uid = ucredp->uid;
+ gid = ucredp->gid;
+ }
+ }
+ }
+ return result;
+#endif // defined(BOOST_ASIO_WINDOWS) || defined(__CYGWIN__)
+}
+
+size_t sync_recvfrom(socket_type s, state_type state, buf* bufs,
+ size_t count, int flags, socket_addr_type* addr,
+ std::size_t* addrlen, boost::system::error_code& ec,
+ std::uint32_t& uid, std::uint32_t& gid)
+{
+ if (s == invalid_socket)
+ {
+ ec = boost::asio::error::bad_descriptor;
+ return 0;
+ }
+
+ // Read some data.
+ for (;;)
+ {
+ // Try to complete the operation without blocking.
+ signed_size_type bytes = socket_ops::recvfrom(
+ s, bufs, count, flags, addr, addrlen, ec, uid, gid);
+
+ // Check if operation succeeded.
+ if (bytes >= 0)
+ return bytes;
+
+ // Operation failed.
+ if ((state & user_set_non_blocking)
+ || (ec != boost::asio::error::would_block
+ && ec != boost::asio::error::try_again))
+ return 0;
+
+ // Wait for socket to become ready.
+ if (socket_ops::poll_read(s, 0, -1, ec) < 0)
+ return 0;
+ }
+}
+
+#if defined(BOOST_ASIO_HAS_IOCP)
+
+void complete_iocp_recvfrom(
+ const weak_cancel_token_type& cancel_token,
+ boost::system::error_code& ec,
+ std::uint32_t& uid, std::uint32_t& gid)
+{
+ uid = 0xFFFFFFFF;
+ gid = 0xFFFFFFFF;
+ // Map non-portable errors to their portable counterparts.
+ if (ec.value() == ERROR_NETNAME_DELETED)
+ {
+ if (cancel_token.expired())
+ ec = boost::asio::error::operation_aborted;
+ else
+ ec = boost::asio::error::connection_reset;
+ }
+ else if (ec.value() == ERROR_PORT_UNREACHABLE)
+ {
+ ec = boost::asio::error::connection_refused;
+ }
+}
+
+#else // defined(BOOST_ASIO_HAS_IOCP)
+
+bool non_blocking_recv(socket_type s,
+ buf* bufs, size_t count, int flags, bool is_stream,
+ boost::system::error_code& ec, size_t& bytes_transferred,
+ std::uint32_t& uid, std::uint32_t& gid)
+{
+ for (;;)
+ {
+ // Read some data.
+ signed_size_type bytes = socket_ops::recv(s, bufs, count, flags, ec, uid, gid);
+
+ // Check for end of stream.
+ if (is_stream && bytes == 0)
+ {
+ ec = boost::asio::error::eof;
+ return true;
+ }
+
+ // Retry operation if interrupted by signal.
+ if (ec == boost::asio::error::interrupted)
+ continue;
+
+ // Check if we need to run the operation again.
+ if (ec == boost::asio::error::would_block
+ || ec == boost::asio::error::try_again)
+ return false;
+
+ // Operation is complete.
+ if (bytes >= 0)
+ {
+ ec = boost::system::error_code();
+ bytes_transferred = bytes;
+ }
+ else
+ bytes_transferred = 0;
+
+ return true;
+ }
+}
+
+bool non_blocking_recvfrom(socket_type s,
+ buf* bufs, size_t count, int flags,
+ socket_addr_type* addr, std::size_t* addrlen,
+ boost::system::error_code& ec, size_t& bytes_transferred,
+ std::uint32_t& uid, std::uint32_t& gid)
+{
+ for (;;)
+ {
+ // Read some data.
+ signed_size_type bytes = socket_ops::recvfrom(
+ s, bufs, count, flags, addr, addrlen, ec, uid, gid);
+
+ // Retry operation if interrupted by signal.
+ if (ec == boost::asio::error::interrupted)
+ continue;
+
+ // Check if we need to run the operation again.
+ if (ec == boost::asio::error::would_block
+ || ec == boost::asio::error::try_again)
+ return false;
+
+ // Operation is complete.
+ if (bytes >= 0)
+ {
+ ec = boost::system::error_code();
+ bytes_transferred = bytes;
+ }
+ else
+ bytes_transferred = 0;
+
+ return true;
+ }
+}
+
+#endif // defined(BOOST_ASIO_HAS_IOCP)
+
+} // namespace socket_ops
+} // namespace detail
+} // namespace asio
+} // namespace boost
+
+#include <boost/asio/detail/pop_options.hpp>
+
+#endif // BOOST_ASIO_DETAIL_SOCKET_OPS_EXT_LOCAL_IPP
diff --git a/implementation/helper/1.74/boost/asio/detail/reactive_socket_recv_op_ext.hpp b/implementation/helper/1.74/boost/asio/detail/reactive_socket_recv_op_ext.hpp
new file mode 100644
index 0000000..1167d57
--- /dev/null
+++ b/implementation/helper/1.74/boost/asio/detail/reactive_socket_recv_op_ext.hpp
@@ -0,0 +1,162 @@
+//
+// detail/reactive_socket_recv_op_ext.hpp
+// ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+//
+// Copyright (c) 2003-2019 Christopher M. Kohlhoff (chris at kohlhoff dot com)
+// Copyright (c) 2016-2019 Bayerische Motoren Werke Aktiengesellschaft (BMW AG)
+//
+// Distributed under the Boost Software License, Version 1.0. (See accompanying
+// file LICENSE_boost or copy at http://www.boost.org/LICENSE_1_0.txt)
+//
+
+#ifndef BOOST_ASIO_DETAIL_REACTIVE_SOCKET_RECV_OP_EXT_HPP
+#define BOOST_ASIO_DETAIL_REACTIVE_SOCKET_RECV_OP_EXT_HPP
+
+#if defined(_MSC_VER) && (_MSC_VER >= 1200)
+# pragma once
+#endif // defined(_MSC_VER) && (_MSC_VER >= 1200)
+
+#include <boost/asio/detail/config.hpp>
+#include <boost/asio/detail/bind_handler.hpp>
+#include <boost/asio/detail/buffer_sequence_adapter.hpp>
+#include <boost/asio/detail/fenced_block.hpp>
+#include <boost/asio/detail/handler_alloc_helpers.hpp>
+#include <boost/asio/detail/handler_invoke_helpers.hpp>
+#include <boost/asio/detail/handler_work.hpp>
+#include <boost/asio/detail/memory.hpp>
+#include <boost/asio/detail/reactor_op_ext.hpp>
+#include <boost/asio/detail/socket_ops_ext.hpp>
+
+#include <boost/asio/detail/push_options.hpp>
+
+namespace boost {
+namespace asio {
+namespace detail {
+
+template <typename MutableBufferSequence>
+class reactive_socket_recv_op_base_ext : public reactor_op_ext
+{
+public:
+ reactive_socket_recv_op_base_ext(const boost::system::error_code& success_ec,
+ socket_type socket, socket_ops::state_type state,
+ const MutableBufferSequence& buffers,
+ socket_base::message_flags flags, func_type complete_func)
+ : reactor_op_ext(success_ec, &reactive_socket_recv_op_base_ext::do_perform, complete_func),
+ socket_(socket),
+ state_(state),
+ buffers_(buffers),
+ flags_(flags)
+ {
+ }
+
+ static status do_perform(reactor_op* base)
+ {
+ reactive_socket_recv_op_base_ext* o(
+ static_cast<reactive_socket_recv_op_base_ext*>(base));
+
+ typedef buffer_sequence_adapter<boost::asio::mutable_buffer,
+ MutableBufferSequence> bufs_type;
+
+ status result;
+ if (bufs_type::is_single_buffer)
+ {
+ result = socket_ops::non_blocking_recv1(o->socket_,
+ bufs_type::first(o->buffers_).data(),
+ bufs_type::first(o->buffers_).size(), o->flags_,
+ (o->state_ & socket_ops::stream_oriented) != 0,
+ o->ec_, o->bytes_transferred_) ? done : not_done;
+ }
+ else
+ {
+ bufs_type bufs(o->buffers_);
+ result = socket_ops::non_blocking_recv(o->socket_,
+ bufs.buffers(), bufs.count(), o->flags_,
+ (o->state_ & socket_ops::stream_oriented) != 0,
+ o->ec_, o->bytes_transferred_) ? done : not_done;
+ }
+
+ if (result == done)
+ if ((o->state_ & socket_ops::stream_oriented) != 0)
+ if (o->bytes_transferred_ == 0)
+ result = done_and_exhausted;
+
+ BOOST_ASIO_HANDLER_REACTOR_OPERATION((*o, "non_blocking_recv",
+ o->ec_, o->bytes_transferred_));
+
+ return result;
+ }
+
+private:
+ socket_type socket_;
+ socket_ops::state_type state_;
+ MutableBufferSequence buffers_;
+ socket_base::message_flags flags_;
+};
+
+template <typename MutableBufferSequence, typename Handler, typename IoExecutor>
+class reactive_socket_recv_op_ext :
+ public reactive_socket_recv_op_base_ext<MutableBufferSequence>
+{
+public:
+ BOOST_ASIO_DEFINE_HANDLER_PTR(reactive_socket_recv_op_ext);
+
+ reactive_socket_recv_op_ext(const boost::system::error_code& success_ec,
+ socket_type socket, socket_ops::state_type state,
+ const MutableBufferSequence& buffers, socket_base::message_flags flags,
+ Handler& handler, const IoExecutor& io_ex)
+ : reactive_socket_recv_op_base_ext<MutableBufferSequence>(success_ec,
+ socket, state, buffers, flags,
+ &reactive_socket_recv_op_ext::do_complete),
+ handler_(BOOST_ASIO_MOVE_CAST(Handler)(handler)),
+ work_(handler_, io_ex)
+ {
+ }
+
+ static void do_complete(void* owner, operation* base,
+ const boost::system::error_code& /*ec*/,
+ std::size_t /*bytes_transferred*/)
+ {
+ // Take ownership of the handler object.
+ reactive_socket_recv_op_ext* o(static_cast<reactive_socket_recv_op_ext*>(base));
+ ptr p = { boost::asio::detail::addressof(o->handler_), o, o };
+
+ BOOST_ASIO_HANDLER_COMPLETION((*o));
+
+ // Take ownership of the operation's outstanding work.
+ handler_work<Handler, IoExecutor> w(
+ BOOST_ASIO_MOVE_CAST2(handler_work<Handler, IoExecutor>)(
+ o->work_));
+
+ // Make a copy of the handler so that the memory can be deallocated before
+ // the upcall is made. Even if we're not about to make an upcall, a
+ // sub-object of the handler may be the true owner of the memory associated
+ // with the handler. Consequently, a local copy of the handler is required
+ // to ensure that any owning sub-object remains valid until after we have
+ // deallocated the memory here.
+ detail::binder3<Handler, boost::system::error_code, std::size_t, boost::asio::ip::address>
+ handler(o->handler_, o->ec_, o->bytes_transferred_, o->da_);
+ p.h = boost::asio::detail::addressof(handler.handler_);
+ p.reset();
+
+ // Make the upcall if required.
+ if (owner)
+ {
+ fenced_block b(fenced_block::half);
+ BOOST_ASIO_HANDLER_INVOCATION_BEGIN((handler.arg1_, handler.arg2_, handler.arg3_));
+ w.complete(handler, handler.handler_);
+ BOOST_ASIO_HANDLER_INVOCATION_END;
+ }
+ }
+
+private:
+ Handler handler_;
+ handler_work<Handler, IoExecutor> work_;
+};
+
+} // namespace detail
+} // namespace asio
+} // namespace boost
+
+#include <boost/asio/detail/pop_options.hpp>
+
+#endif // BOOST_ASIO_DETAIL_REACTIVE_SOCKET_RECV_OP_EXT_HPP
diff --git a/implementation/helper/1.74/boost/asio/detail/reactive_socket_recv_op_ext_local.hpp b/implementation/helper/1.74/boost/asio/detail/reactive_socket_recv_op_ext_local.hpp
new file mode 100644
index 0000000..bedbd29
--- /dev/null
+++ b/implementation/helper/1.74/boost/asio/detail/reactive_socket_recv_op_ext_local.hpp
@@ -0,0 +1,162 @@
+//
+// detail/reactive_socket_recv_op_ext_local.hpp
+// ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+//
+// Copyright (c) 2003-2019 Christopher M. Kohlhoff (chris at kohlhoff dot com)
+// Copyright (c) 2019 Bayerische Motoren Werke Aktiengesellschaft (BMW AG)
+//
+// Distributed under the Boost Software License, Version 1.0. (See accompanying
+// file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt)
+//
+
+#ifndef BOOST_ASIO_DETAIL_REACTIVE_SOCKET_RECV_OP_EXT_LOCAL_HPP
+#define BOOST_ASIO_DETAIL_REACTIVE_SOCKET_RECV_OP_EXT_LOCAL_HPP
+
+#if defined(_MSC_VER) && (_MSC_VER >= 1200)
+# pragma once
+#endif // defined(_MSC_VER) && (_MSC_VER >= 1200)
+
+#include <boost/asio/detail/config.hpp>
+#include <boost/asio/detail/bind_handler.hpp>
+#include <boost/asio/detail/buffer_sequence_adapter.hpp>
+#include <boost/asio/detail/fenced_block.hpp>
+#include <boost/asio/detail/handler_alloc_helpers.hpp>
+#include <boost/asio/detail/handler_invoke_helpers.hpp>
+#include <boost/asio/detail/handler_work.hpp>
+#include <boost/asio/detail/memory.hpp>
+#include <boost/asio/detail/reactor_op_ext_local.hpp>
+#include <boost/asio/detail/socket_ops_ext_local.hpp>
+
+#include <boost/asio/detail/push_options.hpp>
+
+namespace boost {
+namespace asio {
+namespace detail {
+
+template <typename MutableBufferSequence>
+class reactive_socket_recv_op_base_ext_local : public reactor_op_ext_local
+{
+public:
+ reactive_socket_recv_op_base_ext_local(const boost::system::error_code& success_ec,
+ socket_type socket, socket_ops::state_type state,
+ const MutableBufferSequence& buffers,
+ socket_base::message_flags flags, func_type complete_func)
+ : reactor_op_ext_local(success_ec, &reactive_socket_recv_op_base_ext_local::do_perform, complete_func),
+ socket_(socket),
+ state_(state),
+ buffers_(buffers),
+ flags_(flags)
+ {
+ }
+
+ static status do_perform(reactor_op* base)
+ {
+ reactive_socket_recv_op_base_ext_local* o(
+ static_cast<reactive_socket_recv_op_base_ext_local*>(base));
+
+ typedef buffer_sequence_adapter<boost::asio::mutable_buffer,
+ MutableBufferSequence> bufs_type;
+
+ status result;
+ if (bufs_type::is_single_buffer)
+ {
+ result = socket_ops::non_blocking_recv1(o->socket_,
+ bufs_type::first(o->buffers_).data(),
+ bufs_type::first(o->buffers_).size(), o->flags_,
+ (o->state_ & socket_ops::stream_oriented) != 0,
+ o->ec_, o->bytes_transferred_) ? done : not_done;
+ }
+ else
+ {
+ bufs_type bufs(o->buffers_);
+ result = socket_ops::non_blocking_recv(o->socket_,
+ bufs.buffers(), bufs.count(), o->flags_,
+ (o->state_ & socket_ops::stream_oriented) != 0,
+ o->ec_, o->bytes_transferred_) ? done : not_done;
+ }
+
+ if (result == done)
+ if ((o->state_ & socket_ops::stream_oriented) != 0)
+ if (o->bytes_transferred_ == 0)
+ result = done_and_exhausted;
+
+ BOOST_ASIO_HANDLER_REACTOR_OPERATION((*o, "non_blocking_recv",
+ o->ec_, o->bytes_transferred_));
+
+ return result;
+ }
+
+private:
+ socket_type socket_;
+ socket_ops::state_type state_;
+ MutableBufferSequence buffers_;
+ socket_base::message_flags flags_;
+};
+
+template <typename MutableBufferSequence, typename Handler, typename IoExecutor>
+class reactive_socket_recv_op_ext_local :
+ public reactive_socket_recv_op_base_ext_local<MutableBufferSequence>
+{
+public:
+ BOOST_ASIO_DEFINE_HANDLER_PTR(reactive_socket_recv_op_ext_local);
+
+ reactive_socket_recv_op_ext_local(const boost::system::error_code& success_ec,
+ socket_type socket, socket_ops::state_type state,
+ const MutableBufferSequence& buffers, socket_base::message_flags flags,
+ Handler& handler, const IoExecutor& io_ex)
+ : reactive_socket_recv_op_base_ext_local<MutableBufferSequence>(success_ec,
+ socket, state, buffers, flags,
+ &reactive_socket_recv_op_ext_local::do_complete),
+ handler_(BOOST_ASIO_MOVE_CAST(Handler)(handler)),
+ work_(handler_, io_ex)
+ {
+ }
+
+ static void do_complete(void* owner, operation* base,
+ const boost::system::error_code& /*ec*/,
+ std::size_t /*bytes_transferred*/)
+ {
+ // Take ownership of the handler object.
+ reactive_socket_recv_op_ext_local* o(static_cast<reactive_socket_recv_op_ext_local*>(base));
+ ptr p = { boost::asio::detail::addressof(o->handler_), o, o };
+
+ BOOST_ASIO_HANDLER_COMPLETION((*o));
+
+ // Take ownership of the operation's outstanding work.
+ handler_work<Handler, IoExecutor> w(
+ BOOST_ASIO_MOVE_CAST2(handler_work<Handler, IoExecutor>)(
+ o->work_));
+
+ // Make a copy of the handler so that the memory can be deallocated before
+ // the upcall is made. Even if we're not about to make an upcall, a
+ // sub-object of the handler may be the true owner of the memory associated
+ // with the handler. Consequently, a local copy of the handler is required
+ // to ensure that any owning sub-object remains valid until after we have
+ // deallocated the memory here.
+ detail::binder4<Handler, boost::system::error_code, std::size_t, std::uint32_t, std::uint32_t>
+ handler(o->handler_, o->ec_, o->bytes_transferred_, o->uid_, o->gid_);
+ p.h = boost::asio::detail::addressof(handler.handler_);
+ p.reset();
+
+ // Make the upcall if required.
+ if (owner)
+ {
+ fenced_block b(fenced_block::half);
+ BOOST_ASIO_HANDLER_INVOCATION_BEGIN((handler.arg1_, handler.arg2_, handler.arg3, handler.arg4));
+ w.complete(handler, handler.handler_);
+ BOOST_ASIO_HANDLER_INVOCATION_END;
+ }
+ }
+
+private:
+ Handler handler_;
+ handler_work<Handler, IoExecutor> work_;
+};
+
+} // namespace detail
+} // namespace asio
+} // namespace boost
+
+#include <boost/asio/detail/pop_options.hpp>
+
+#endif // BOOST_ASIO_DETAIL_REACTIVE_SOCKET_RECV_OP_EXT_LOCAL_HPP
diff --git a/implementation/helper/1.74/boost/asio/detail/reactive_socket_recvfrom_op_ext.hpp b/implementation/helper/1.74/boost/asio/detail/reactive_socket_recvfrom_op_ext.hpp
new file mode 100644
index 0000000..875fe14
--- /dev/null
+++ b/implementation/helper/1.74/boost/asio/detail/reactive_socket_recvfrom_op_ext.hpp
@@ -0,0 +1,153 @@
+//
+// detail/reactive_socket_recvfrom_op_ext.hpp
+// ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+//
+// Copyright (c) 2003-2019 Christopher M. Kohlhoff (chris at kohlhoff dot com)
+// Copyright (c) 2016-2019 Bayerische Motoren Werke Aktiengesellschaft (BMW AG)
+//
+// Distributed under the Boost Software License, Version 1.0. (See accompanying
+// file LICENSE_boost or copy at http://www.boost.org/LICENSE_1_0.txt)
+//
+
+#ifndef BOOST_ASIO_DETAIL_REACTIVE_SOCKET_RECVFROM_OP_EXT_HPP
+#define BOOST_ASIO_DETAIL_REACTIVE_SOCKET_RECVFROM_OP_EXT_HPP
+
+#if defined(_MSC_VER) && (_MSC_VER >= 1200)
+# pragma once
+#endif // defined(_MSC_VER) && (_MSC_VER >= 1200)
+
+#include <boost/asio/detail/config.hpp>
+#include <boost/asio/detail/bind_handler.hpp>
+#include <boost/asio/detail/buffer_sequence_adapter.hpp>
+#include <boost/asio/detail/fenced_block.hpp>
+#include <boost/asio/detail/handler_alloc_helpers.hpp>
+#include <boost/asio/detail/handler_invoke_helpers.hpp>
+#include <boost/asio/detail/handler_work.hpp>
+#include <boost/asio/detail/memory.hpp>
+#include <boost/asio/detail/reactor_op_ext.hpp>
+#include <boost/asio/detail/socket_ops_ext.hpp>
+
+#include <boost/asio/detail/push_options.hpp>
+
+namespace boost {
+namespace asio {
+namespace detail {
+
+template <typename MutableBufferSequence, typename Endpoint>
+class reactive_socket_recvfrom_op_base_ext : public reactor_op_ext
+{
+public:
+ reactive_socket_recvfrom_op_base_ext(const boost::system::error_code& success_ec,
+ socket_type socket, int protocol_type,
+ const MutableBufferSequence& buffers, Endpoint& endpoint,
+ socket_base::message_flags flags, func_type complete_func)
+ : reactor_op_ext(success_ec, &reactive_socket_recvfrom_op_base_ext::do_perform, complete_func),
+ socket_(socket),
+ protocol_type_(protocol_type),
+ buffers_(buffers),
+ sender_endpoint_(endpoint),
+ flags_(flags)
+ {
+ }
+
+ static status do_perform(reactor_op* base)
+ {
+ reactive_socket_recvfrom_op_base_ext* o(
+ static_cast<reactive_socket_recvfrom_op_base_ext*>(base));
+
+ buffer_sequence_adapter<boost::asio::mutable_buffer,
+ MutableBufferSequence> bufs(o->buffers_);
+
+ std::size_t addr_len = o->sender_endpoint_.capacity();
+ status result = socket_ops::non_blocking_recvfrom(o->socket_,
+ bufs.buffers(), bufs.count(), o->flags_,
+ o->sender_endpoint_.data(), &addr_len,
+ o->ec_, o->bytes_transferred_, o->da_) ? done : not_done;
+
+ if (result && !o->ec_)
+ o->sender_endpoint_.resize(addr_len);
+
+ BOOST_ASIO_HANDLER_REACTOR_OPERATION((*o, "non_blocking_recvfrom",
+ o->ec_, o->bytes_transferred_));
+
+ return result;
+ }
+
+private:
+ socket_type socket_;
+ int protocol_type_;
+ MutableBufferSequence buffers_;
+ Endpoint& sender_endpoint_;
+ socket_base::message_flags flags_;
+};
+
+template <typename MutableBufferSequence, typename Endpoint,
+ typename Handler, typename IoExecutor>
+class reactive_socket_recvfrom_op_ext :
+ public reactive_socket_recvfrom_op_base_ext<MutableBufferSequence, Endpoint>
+{
+public:
+ BOOST_ASIO_DEFINE_HANDLER_PTR(reactive_socket_recvfrom_op_ext);
+
+ reactive_socket_recvfrom_op_ext(const boost::system::error_code& success_ec,
+ socket_type socket, int protocol_type,
+ const MutableBufferSequence& buffers, Endpoint& endpoint,
+ socket_base::message_flags flags, Handler& handler,
+ const IoExecutor& io_ex)
+ : reactive_socket_recvfrom_op_base_ext<MutableBufferSequence, Endpoint>(
+ success_ec, socket, protocol_type, buffers, endpoint, flags,
+ &reactive_socket_recvfrom_op_ext::do_complete),
+ handler_(BOOST_ASIO_MOVE_CAST(Handler)(handler)),
+ work_(handler_, io_ex)
+ {
+ }
+
+ static void do_complete(void* owner, operation* base,
+ const boost::system::error_code& /*ec*/,
+ std::size_t /*bytes_transferred*/)
+ {
+ // Take ownership of the handler object.
+ reactive_socket_recvfrom_op_ext* o(
+ static_cast<reactive_socket_recvfrom_op_ext*>(base));
+ ptr p = { boost::asio::detail::addressof(o->handler_), o, o };
+
+ BOOST_ASIO_HANDLER_COMPLETION((*o));
+
+ // Take ownership of the operation's outstanding work.
+ handler_work<Handler, IoExecutor> w(
+ BOOST_ASIO_MOVE_CAST2(handler_work<Handler, IoExecutor>)(
+ o->work_));
+
+ // Make a copy of the handler so that the memory can be deallocated before
+ // the upcall is made. Even if we're not about to make an upcall, a
+ // sub-object of the handler may be the true owner of the memory associated
+ // with the handler. Consequently, a local copy of the handler is required
+ // to ensure that any owning sub-object remains valid until after we have
+ // deallocated the memory here.
+ detail::binder3<Handler, boost::system::error_code, std::size_t, boost::asio::ip::address>
+ handler(o->handler_, o->ec_, o->bytes_transferred_, o->da_);
+ p.h = boost::asio::detail::addressof(handler.handler_);
+ p.reset();
+
+ // Make the upcall if required.
+ if (owner)
+ {
+ fenced_block b(fenced_block::half);
+ BOOST_ASIO_HANDLER_INVOCATION_BEGIN((handler.arg1_, handler.arg2_, handler.arg3_));
+ w.complete(handler, handler.handler_);
+ BOOST_ASIO_HANDLER_INVOCATION_END;
+ }
+ }
+
+private:
+ Handler handler_;
+ handler_work<Handler, IoExecutor> work_;
+};
+
+} // namespace detail
+} // namespace asio
+} // namespace boost
+
+#include <boost/asio/detail/pop_options.hpp>
+
+#endif // BOOST_ASIO_DETAIL_REACTIVE_SOCKET_RECVFROM_OP_EXT_HPP
diff --git a/implementation/helper/1.74/boost/asio/detail/reactive_socket_recvfrom_op_ext_local.hpp b/implementation/helper/1.74/boost/asio/detail/reactive_socket_recvfrom_op_ext_local.hpp
new file mode 100644
index 0000000..f9fef2b
--- /dev/null
+++ b/implementation/helper/1.74/boost/asio/detail/reactive_socket_recvfrom_op_ext_local.hpp
@@ -0,0 +1,148 @@
+//
+// detail/reactive_socket_recvfrom_op_ext_local.hpp
+// ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+//
+// Copyright (c) 2003-2019 Christopher M. Kohlhoff (chris at kohlhoff dot com)
+// Copyright (c) 2019 Bayerische Motoren Werke Aktiengesellschaft (BMW AG)
+//
+// Distributed under the Boost Software License, Version 1.0. (See accompanying
+// file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt)
+//
+
+#ifndef BOOST_ASIO_DETAIL_REACTIVE_SOCKET_RECVFROM_OP_EXT_LOCAL_HPP
+#define BOOST_ASIO_DETAIL_REACTIVE_SOCKET_RECVFROM_OP_EXT_LOCAL_HPP
+
+#if defined(_MSC_VER) && (_MSC_VER >= 1200)
+# pragma once
+#endif // defined(_MSC_VER) && (_MSC_VER >= 1200)
+
+#include <boost/asio/detail/config.hpp>
+#include <boost/asio/detail/bind_handler.hpp>
+#include <boost/asio/detail/buffer_sequence_adapter.hpp>
+#include <boost/asio/detail/fenced_block.hpp>
+#include <boost/asio/detail/memory.hpp>
+#include <boost/asio/detail/reactor_op_ext_local.hpp>
+#include <boost/asio/detail/socket_ops_ext_local.hpp>
+
+#include <boost/asio/detail/push_options.hpp>
+
+namespace boost {
+namespace asio {
+namespace detail {
+
+template <typename MutableBufferSequence, typename Endpoint>
+class reactive_socket_recvfrom_op_base_ext_local : public reactor_op_ext_local
+{
+public:
+ reactive_socket_recvfrom_op_base_ext_local(socket_type socket, int protocol_type,
+ const MutableBufferSequence& buffers, Endpoint& endpoint,
+ socket_base::message_flags flags, func_type complete_func)
+ : reactor_op_ext_local(&reactive_socket_recvfrom_op_base_ext_local::do_perform, complete_func),
+ socket_(socket),
+ protocol_type_(protocol_type),
+ buffers_(buffers),
+ sender_endpoint_(endpoint),
+ flags_(flags)
+ {
+ }
+
+ static status do_perform(reactor_op* base)
+ {
+ reactive_socket_recvfrom_op_base_ext_local* o(
+ static_cast<reactive_socket_recvfrom_op_base_ext_local*>(base));
+
+ buffer_sequence_adapter<boost::asio::mutable_buffer,
+ MutableBufferSequence> bufs(o->buffers_);
+
+ std::size_t addr_len = o->sender_endpoint_.capacity();
+ status result = socket_ops::non_blocking_recvfrom(o->socket_,
+ bufs.buffers(), bufs.count(), o->flags_,
+ o->sender_endpoint_.data(), &addr_len,
+ o->ec_, o->bytes_transferred_, o->uid_, o->gid_) ? done : not_done;
+
+ if (result && !o->ec_)
+ o->sender_endpoint_.resize(addr_len);
+
+ BOOST_ASIO_HANDLER_REACTOR_OPERATION((*o, "non_blocking_recvfrom",
+ o->ec_, o->bytes_transferred_));
+
+ return result;
+ }
+
+private:
+ socket_type socket_;
+ int protocol_type_;
+ MutableBufferSequence buffers_;
+ Endpoint& sender_endpoint_;
+ socket_base::message_flags flags_;
+};
+
+template <typename MutableBufferSequence, typename Endpoint,
+ typename Handler, typename IoExecutor>
+class reactive_socket_recvfrom_op_ext_local :
+ public reactive_socket_recvfrom_op_base_ext_local<MutableBufferSequence, Endpoint>
+{
+public:
+ BOOST_ASIO_DEFINE_HANDLER_PTR(reactive_socket_recvfrom_op_ext_local);
+
+ reactive_socket_recvfrom_op_ext_local(socket_type socket, int protocol_type,
+ const MutableBufferSequence& buffers, Endpoint& endpoint,
+ socket_base::message_flags flags, Handler& handler,
+ const IoExecutor& io_ex)
+ : reactive_socket_recvfrom_op_base_ext_local<MutableBufferSequence, Endpoint>(
+ socket, protocol_type, buffers, endpoint, flags,
+ &reactive_socket_recvfrom_op_ext_local::do_complete),
+ handler_(BOOST_ASIO_MOVE_CAST(Handler)(handler)),
+ work_(handler_, io_ex)
+ {
+ }
+
+ static void do_complete(void* owner, operation* base,
+ const boost::system::error_code& /*ec*/,
+ std::size_t /*bytes_transferred*/)
+ {
+ // Take ownership of the handler object.
+ reactive_socket_recvfrom_op_ext_local* o(
+ static_cast<reactive_socket_recvfrom_op_ext_local*>(base));
+ ptr p = { boost::asio::detail::addressof(o->handler_), o, o };
+
+ BOOST_ASIO_HANDLER_COMPLETION((*o));
+
+ // Take ownership of the operation's outstanding work.
+ handler_work<Handler, IoExecutor> w(
+ BOOST_ASIO_MOVE_CAST2(handler_work<Handler, IoExecutor>)(
+ o->work_));
+
+ // Make a copy of the handler so that the memory can be deallocated before
+ // the upcall is made. Even if we're not about to make an upcall, a
+ // sub-object of the handler may be the true owner of the memory associated
+ // with the handler. Consequently, a local copy of the handler is required
+ // to ensure that any owning sub-object remains valid until after we have
+ // deallocated the memory here.
+ detail::binder4<Handler, boost::system::error_code, std::size_t, std::uint32_t, std::uint32_t>
+ handler(o->handler_, o->ec_, o->bytes_transferred_, o->uid_, o->gid_);
+ p.h = boost::asio::detail::addressof(handler.handler_);
+ p.reset();
+
+ // Make the upcall if required.
+ if (owner)
+ {
+ fenced_block b(fenced_block::half);
+ BOOST_ASIO_HANDLER_INVOCATION_BEGIN((handler.arg1_, handler.arg2_, handler.arg3_, handler.arg4_));
+ w.complete(handler, handler.handler_);
+ BOOST_ASIO_HANDLER_INVOCATION_END;
+ }
+ }
+
+private:
+ Handler handler_;
+ handler_work<Handler, IoExecutor> work_;
+};
+
+} // namespace detail
+} // namespace asio
+} // namespace boost
+
+#include <boost/asio/detail/pop_options.hpp>
+
+#endif // BOOST_ASIO_DETAIL_REACTIVE_SOCKET_RECVFROM_OP_EXT_LOCAL_HPP
diff --git a/implementation/helper/1.74/boost/asio/detail/reactive_socket_recvmsg_op_ext.hpp b/implementation/helper/1.74/boost/asio/detail/reactive_socket_recvmsg_op_ext.hpp
new file mode 100644
index 0000000..bd315dc
--- /dev/null
+++ b/implementation/helper/1.74/boost/asio/detail/reactive_socket_recvmsg_op_ext.hpp
@@ -0,0 +1,144 @@
+//
+// detail/reactive_socket_recvmsg_op_ext.hpp
+// ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+//
+// Copyright (c) 2003-2019 Christopher M. Kohlhoff (chris at kohlhoff dot com)
+// Copyright (c) 2016-2019 Bayerische Motoren Werke Aktiengesellschaft (BMW AG)
+//
+// Distributed under the Boost Software License, Version 1.0. (See accompanying
+// file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt)
+//
+
+#ifndef BOOST_ASIO_DETAIL_REACTIVE_SOCKET_RECVMSG_OP_EXT_HPP
+#define BOOST_ASIO_DETAIL_REACTIVE_SOCKET_RECVMSG_OP_EXT_HPP
+
+#if defined(_MSC_VER) && (_MSC_VER >= 1200)
+# pragma once
+#endif // defined(_MSC_VER) && (_MSC_VER >= 1200)
+
+#include <boost/asio/detail/config.hpp>
+#include <boost/asio/detail/bind_handler.hpp>
+#include <boost/asio/detail/buffer_sequence_adapter.hpp>
+#include <boost/asio/detail/fenced_block.hpp>
+#include <boost/asio/detail/handler_alloc_helpers.hpp>
+#include <boost/asio/detail/handler_invoke_helpers.hpp>
+#include <boost/asio/detail/handler_work.hpp>
+#include <boost/asio/detail/memory.hpp>
+#include <boost/asio/detail/reactor_op_ext.hpp>
+#include <boost/asio/detail/socket_ops_ext.hpp>
+#include <boost/asio/socket_base.hpp>
+
+#include <boost/asio/detail/push_options.hpp>
+
+namespace boost {
+namespace asio {
+namespace detail {
+
+template <typename MutableBufferSequence>
+class reactive_socket_recvmsg_op_base_ext : public reactor_op_ext
+{
+public:
+ reactive_socket_recvmsg_op_base_ext(const boost::system::error_code& success_ec,
+ socket_type socket, const MutableBufferSequence& buffers, socket_base::message_flags in_flags,
+ socket_base::message_flags& out_flags, func_type complete_func)
+ : reactor_op_ext(&reactive_socket_recvmsg_op_base_ext::do_perform, complete_func),
+ socket_(socket),
+ buffers_(buffers),
+ in_flags_(in_flags),
+ out_flags_(out_flags)
+ {
+ }
+
+ static status do_perform(reactor_op* base)
+ {
+ reactive_socket_recvmsg_op_base_ext* o(
+ static_cast<reactive_socket_recvmsg_op_base_ext*>(base));
+
+ buffer_sequence_adapter<boost::asio::mutable_buffer,
+ MutableBufferSequence> bufs(o->buffers_);
+
+ status result = socket_ops::non_blocking_recvmsg(o->socket_,
+ bufs.buffers(), bufs.count(),
+ o->in_flags_, o->out_flags_,
+ o->ec_, o->bytes_transferred_) ? done : not_done;
+
+ BOOST_ASIO_HANDLER_REACTOR_OPERATION((*o, "non_blocking_recvmsg",
+ o->ec_, o->bytes_transferred_));
+
+ return result;
+ }
+
+private:
+ socket_type socket_;
+ MutableBufferSequence buffers_;
+ socket_base::message_flags in_flags_;
+ socket_base::message_flags& out_flags_;
+};
+
+template <typename MutableBufferSequence, typename Handler, typename IoExecutor>
+class reactive_socket_recvmsg_op_ext :
+ public reactive_socket_recvmsg_op_base_ext<MutableBufferSequence>
+{
+public:
+ BOOST_ASIO_DEFINE_HANDLER_PTR(reactive_socket_recvmsg_op_ext);
+
+ reactive_socket_recvmsg_op_ext(const boost::system::error_code& success_ec,
+ socket_type socket, const MutableBufferSequence& buffers, socket_base::message_flags in_flags,
+ socket_base::message_flags& out_flags, Handler& handler,
+ const IoExecutor& io_ex)
+ : reactive_socket_recvmsg_op_base_ext<MutableBufferSequence>(socket, buffers,
+ in_flags, out_flags, &reactive_socket_recvmsg_op_ext::do_complete),
+ handler_(BOOST_ASIO_MOVE_CAST(Handler)(handler)),
+ work_(handler_, io_ex)
+ {
+ }
+
+ static void do_complete(void* owner, operation* base,
+ const boost::system::error_code& /*ec*/,
+ std::size_t /*bytes_transferred*/)
+ {
+ // Take ownership of the handler object.
+ reactive_socket_recvmsg_op_ext* o(
+ static_cast<reactive_socket_recvmsg_op_ext*>(base));
+ ptr p = { boost::asio::detail::addressof(o->handler_), o, o };
+
+ BOOST_ASIO_HANDLER_COMPLETION((*o));
+
+ // Take ownership of the operation's outstanding work.
+ handler_work<Handler, IoExecutor> w(
+ BOOST_ASIO_MOVE_CAST2(handler_work<Handler, IoExecutor>)(
+ o->work_));
+
+ // Make a copy of the handler so that the memory can be deallocated before
+ // the upcall is made. Even if we're not about to make an upcall, a
+ // sub-object of the handler may be the true owner of the memory associated
+ // with the handler. Consequently, a local copy of the handler is required
+ // to ensure that any owning sub-object remains valid until after we have
+ // deallocated the memory here.
+ detail::binder3<Handler, boost::system::error_code, std::size_t, boost::asio::ip::address>
+ handler(o->handler_, o->ec_, o->bytes_transferred_, o->da_);
+ p.h = boost::asio::detail::addressof(handler.handler_);
+ p.reset();
+
+ // Make the upcall if required.
+ if (owner)
+ {
+ fenced_block b(fenced_block::half);
+ BOOST_ASIO_HANDLER_INVOCATION_BEGIN((handler.arg1_, handler.arg2_, handler.arg3_));
+ w.complete(handler, handler.handler_);
+ BOOST_ASIO_HANDLER_INVOCATION_END;
+ }
+ }
+
+private:
+ Handler handler_;
+ handler_work<Handler, IoExecutor> work_;
+};
+
+} // namespace detail
+} // namespace asio
+} // namespace boost
+
+#include <boost/asio/detail/pop_options.hpp>
+
+#endif // BOOST_ASIO_DETAIL_REACTIVE_SOCKET_RECVMSG_OP_EXT_HPP
diff --git a/implementation/helper/1.74/boost/asio/detail/reactive_socket_recvmsg_op_ext_local.hpp b/implementation/helper/1.74/boost/asio/detail/reactive_socket_recvmsg_op_ext_local.hpp
new file mode 100644
index 0000000..8148690
--- /dev/null
+++ b/implementation/helper/1.74/boost/asio/detail/reactive_socket_recvmsg_op_ext_local.hpp
@@ -0,0 +1,145 @@
+//
+// detail/reactive_socket_recvmsg_op_ext_local.hpp
+// ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+//
+// Copyright (c) 2003-2019 Christopher M. Kohlhoff (chris at kohlhoff dot com)
+// Copyright (c) 2019 Bayerische Motoren Werke Aktiengesellschaft (BMW AG)
+//
+// Distributed under the Boost Software License, Version 1.0. (See accompanying
+// file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt)
+//
+
+#ifndef BOOST_ASIO_DETAIL_REACTIVE_SOCKET_RECVMSG_OP_EXT_LOCAL_HPP
+#define BOOST_ASIO_DETAIL_REACTIVE_SOCKET_RECVMSG_OP_EXT_LOCAL_HPP
+
+#if defined(_MSC_VER) && (_MSC_VER >= 1200)
+# pragma once
+#endif // defined(_MSC_VER) && (_MSC_VER >= 1200)
+
+#include <boost/asio/detail/config.hpp>
+#include <boost/asio/detail/bind_handler.hpp>
+#include <boost/asio/detail/buffer_sequence_adapter.hpp>
+#include <boost/asio/detail/fenced_block.hpp>
+#include <boost/asio/detail/handler_alloc_helpers.hpp>
+#include <boost/asio/detail/handler_invoke_helpers.hpp>
+#include <boost/asio/detail/handler_work.hpp>
+#include <boost/asio/detail/memory.hpp>
+#include <boost/asio/detail/reactor_op_ext_local.hpp>
+#include <boost/asio/detail/socket_ops_ext_local.hpp>
+#include <boost/asio/socket_base.hpp>
+
+#include <boost/asio/detail/push_options.hpp>
+
+namespace boost {
+namespace asio {
+namespace detail {
+
+template <typename MutableBufferSequence>
+class reactive_socket_recvmsg_op_base_ext_local : public reactor_op_ext_local
+{
+public:
+ reactive_socket_recvmsg_op_base_ext_local(const boost::system::error_code& success_ec,
+ socket_type socket, const MutableBufferSequence& buffers, socket_base::message_flags in_flags,
+ socket_base::message_flags& out_flags, func_type complete_func)
+ : reactor_op_ext_local(success_ec, &reactive_socket_recvmsg_op_base_ext_local::do_perform, complete_func),
+ socket_(socket),
+ buffers_(buffers),
+ in_flags_(in_flags),
+ out_flags_(out_flags)
+ {
+ }
+
+ static status do_perform(reactor_op* base)
+ {
+ reactive_socket_recvmsg_op_base_ext_local* o(
+ static_cast<reactive_socket_recvmsg_op_base_ext_local*>(base));
+
+ buffer_sequence_adapter<boost::asio::mutable_buffer,
+ MutableBufferSequence> bufs(o->buffers_);
+
+ status result = socket_ops::non_blocking_recvmsg(o->socket_,
+ bufs.buffers(), bufs.count(),
+ o->in_flags_, o->out_flags_,
+ o->ec_, o->bytes_transferred_) ? done : not_done;
+
+ BOOST_ASIO_HANDLER_REACTOR_OPERATION((*o, "non_blocking_recvmsg",
+ o->ec_, o->bytes_transferred_));
+
+ return result;
+ }
+
+private:
+ socket_type socket_;
+ MutableBufferSequence buffers_;
+ socket_base::message_flags in_flags_;
+ socket_base::message_flags& out_flags_;
+};
+
+template <typename MutableBufferSequence, typename Handler, typename IoExecutor>
+class reactive_socket_recvmsg_op_ext_local :
+ public reactive_socket_recvmsg_op_base_ext_local<MutableBufferSequence>
+{
+public:
+ BOOST_ASIO_DEFINE_HANDLER_PTR(reactive_socket_recvmsg_op_ext_local);
+
+ reactive_socket_recvmsg_op_ext_local(const boost::system::error_code& success_ec,
+ socket_type socket, const MutableBufferSequence& buffers, socket_base::message_flags in_flags,
+ socket_base::message_flags& out_flags, Handler& handler,
+ const IoExecutor& io_ex)
+ : reactive_socket_recvmsg_op_base_ext_local<MutableBufferSequence>(success_ec,
+ socket, buffers, in_flags, out_flags,
+ &reactive_socket_recvmsg_op_ext_local::do_complete),
+ handler_(BOOST_ASIO_MOVE_CAST(Handler)(handler)),
+ work_(handler_, io_ex)
+ {
+ }
+
+ static void do_complete(void* owner, operation* base,
+ const boost::system::error_code& /*ec*/,
+ std::size_t /*bytes_transferred*/)
+ {
+ // Take ownership of the handler object.
+ reactive_socket_recvmsg_op_ext_local* o(
+ static_cast<reactive_socket_recvmsg_op_ext_local*>(base));
+ ptr p = { boost::asio::detail::addressof(o->handler_), o, o };
+
+ BOOST_ASIO_HANDLER_COMPLETION((*o));
+
+ // Take ownership of the operation's outstanding work.
+ handler_work<Handler, IoExecutor> w(
+ BOOST_ASIO_MOVE_CAST2(handler_work<Handler, IoExecutor>)(
+ o->work_));
+
+ // Make a copy of the handler so that the memory can be deallocated before
+ // the upcall is made. Even if we're not about to make an upcall, a
+ // sub-object of the handler may be the true owner of the memory associated
+ // with the handler. Consequently, a local copy of the handler is required
+ // to ensure that any owning sub-object remains valid until after we have
+ // deallocated the memory here.
+ detail::binder4<Handler, boost::system::error_code, std::size_t, std::uint32_t, std::uint32_t>
+ handler(o->handler_, o->ec_, o->bytes_transferred_, o->uid_, o->gid_);
+ p.h = boost::asio::detail::addressof(handler.handler_);
+ p.reset();
+
+ // Make the upcall if required.
+ if (owner)
+ {
+ fenced_block b(fenced_block::half);
+ BOOST_ASIO_HANDLER_INVOCATION_BEGIN((handler.arg1_, handler.arg2_, handler.arg3_, handler.arg4_));
+ w.complete(handler, handler.handler_);
+ BOOST_ASIO_HANDLER_INVOCATION_END;
+ }
+ }
+
+private:
+ Handler handler_;
+ handler_work<Handler, IoExecutor> work_;
+};
+
+} // namespace detail
+} // namespace asio
+} // namespace boost
+
+#include <boost/asio/detail/pop_options.hpp>
+
+#endif // BOOST_ASIO_DETAIL_REACTIVE_SOCKET_RECVMSG_OP_EXT_LOCAL_HPP
diff --git a/implementation/helper/1.74/boost/asio/detail/reactive_socket_service_base_ext.hpp b/implementation/helper/1.74/boost/asio/detail/reactive_socket_service_base_ext.hpp
new file mode 100644
index 0000000..2e68a87
--- /dev/null
+++ b/implementation/helper/1.74/boost/asio/detail/reactive_socket_service_base_ext.hpp
@@ -0,0 +1,524 @@
+//
+// detail/reactive_socket_service_base.hpp
+// ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+//
+// Copyright (c) 2003-2019 Christopher M. Kohlhoff (chris at kohlhoff dot com)
+// Copyright (c) 2016-2019 Bayerische Motoren Werke Aktiengesellschaft (BMW AG)
+//
+// Distributed under the Boost Software License, Version 1.0. (See accompanying
+// file LICENSE_boost or copy at http://www.boost.org/LICENSE_1_0.txt)
+//
+
+#ifndef BOOST_ASIO_DETAIL_REACTIVE_SOCKET_SERVICE_BASE_EXT_HPP
+#define BOOST_ASIO_DETAIL_REACTIVE_SOCKET_SERVICE_BASE_EXT_HPP
+
+#if defined(_MSC_VER) && (_MSC_VER >= 1200)
+# pragma once
+#endif // defined(_MSC_VER) && (_MSC_VER >= 1200)
+
+#include <boost/asio/detail/config.hpp>
+
+#if !defined(BOOST_ASIO_HAS_IOCP) \
+ && !defined(BOOST_ASIO_WINDOWS_RUNTIME)
+
+#include <boost/asio/buffer.hpp>
+#include <boost/asio/error.hpp>
+#include <boost/asio/execution_context.hpp>
+#include <boost/asio/socket_base.hpp>
+#include <boost/asio/detail/buffer_sequence_adapter.hpp>
+#include <boost/asio/detail/memory.hpp>
+#include <boost/asio/detail/reactive_null_buffers_op.hpp>
+#include <boost/asio/detail/reactive_socket_recv_op_ext.hpp>
+#include <boost/asio/detail/reactive_socket_recvmsg_op_ext.hpp>
+#include <boost/asio/detail/reactive_socket_send_op.hpp>
+#include <boost/asio/detail/reactive_wait_op.hpp>
+#include <boost/asio/detail/reactor.hpp>
+#include <boost/asio/detail/reactor_op.hpp>
+#include <boost/asio/detail/socket_holder.hpp>
+#include <boost/asio/detail/socket_ops_ext.hpp>
+#include <boost/asio/detail/socket_types.hpp>
+
+#include <boost/asio/detail/push_options.hpp>
+
+namespace boost {
+namespace asio {
+namespace detail {
+
+class reactive_socket_service_base_ext
+{
+public:
+ // The native type of a socket.
+ typedef socket_type native_handle_type;
+
+ // The implementation type of the socket.
+ struct base_implementation_type
+ {
+ // The native socket representation.
+ socket_type socket_;
+
+ // The current state of the socket.
+ socket_ops::state_type state_;
+
+ // Per-descriptor data used by the reactor.
+ reactor::per_descriptor_data reactor_data_;
+ };
+
+ // Constructor.
+ BOOST_ASIO_DECL reactive_socket_service_base_ext(execution_context& context);
+
+ // Destroy all user-defined handler objects owned by the service.
+ BOOST_ASIO_DECL void base_shutdown();
+
+ // Construct a new socket implementation.
+ BOOST_ASIO_DECL void construct(base_implementation_type& impl);
+
+ // Move-construct a new socket implementation.
+ BOOST_ASIO_DECL void base_move_construct(base_implementation_type& impl,
+ base_implementation_type& other_impl);
+
+ // Move-assign from another socket implementation.
+ BOOST_ASIO_DECL void base_move_assign(base_implementation_type& impl,
+ reactive_socket_service_base_ext& other_service,
+ base_implementation_type& other_impl);
+
+ // Destroy a socket implementation.
+ BOOST_ASIO_DECL void destroy(base_implementation_type& impl);
+
+ // Determine whether the socket is open.
+ bool is_open(const base_implementation_type& impl) const
+ {
+ return impl.socket_ != invalid_socket;
+ }
+
+ // Destroy a socket implementation.
+ BOOST_ASIO_DECL boost::system::error_code close(
+ base_implementation_type& impl, boost::system::error_code& ec);
+
+ // Release ownership of the socket.
+ BOOST_ASIO_DECL socket_type release(
+ base_implementation_type& impl, boost::system::error_code& ec);
+
+ // Get the native socket representation.
+ native_handle_type native_handle(base_implementation_type& impl)
+ {
+ return impl.socket_;
+ }
+
+ // Cancel all operations associated with the socket.
+ BOOST_ASIO_DECL boost::system::error_code cancel(
+ base_implementation_type& impl, boost::system::error_code& ec);
+
+ // Determine whether the socket is at the out-of-band data mark.
+ bool at_mark(const base_implementation_type& impl,
+ boost::system::error_code& ec) const
+ {
+ return socket_ops::sockatmark(impl.socket_, ec);
+ }
+
+ // Determine the number of bytes available for reading.
+ std::size_t available(const base_implementation_type& impl,
+ boost::system::error_code& ec) const
+ {
+ return socket_ops::available(impl.socket_, ec);
+ }
+
+ // Place the socket into the state where it will listen for new connections.
+ boost::system::error_code listen(base_implementation_type& impl,
+ int backlog, boost::system::error_code& ec)
+ {
+ socket_ops::listen(impl.socket_, backlog, ec);
+ return ec;
+ }
+
+ // Perform an IO control command on the socket.
+ template <typename IO_Control_Command>
+ boost::system::error_code io_control(base_implementation_type& impl,
+ IO_Control_Command& command, boost::system::error_code& ec)
+ {
+ socket_ops::ioctl(impl.socket_, impl.state_, command.name(),
+ static_cast<ioctl_arg_type*>(command.data()), ec);
+ return ec;
+ }
+
+ // Gets the non-blocking mode of the socket.
+ bool non_blocking(const base_implementation_type& impl) const
+ {
+ return (impl.state_ & socket_ops::user_set_non_blocking) != 0;
+ }
+
+ // Sets the non-blocking mode of the socket.
+ boost::system::error_code non_blocking(base_implementation_type& impl,
+ bool mode, boost::system::error_code& ec)
+ {
+ socket_ops::set_user_non_blocking(impl.socket_, impl.state_, mode, ec);
+ return ec;
+ }
+
+ // Gets the non-blocking mode of the native socket implementation.
+ bool native_non_blocking(const base_implementation_type& impl) const
+ {
+ return (impl.state_ & socket_ops::internal_non_blocking) != 0;
+ }
+
+ // Sets the non-blocking mode of the native socket implementation.
+ boost::system::error_code native_non_blocking(base_implementation_type& impl,
+ bool mode, boost::system::error_code& ec)
+ {
+ socket_ops::set_internal_non_blocking(impl.socket_, impl.state_, mode, ec);
+ return ec;
+ }
+
+ // Wait for the socket to become ready to read, ready to write, or to have
+ // pending error conditions.
+ boost::system::error_code wait(base_implementation_type& impl,
+ socket_base::wait_type w, boost::system::error_code& ec)
+ {
+ switch (w)
+ {
+ case socket_base::wait_read:
+ socket_ops::poll_read(impl.socket_, impl.state_, -1, ec);
+ break;
+ case socket_base::wait_write:
+ socket_ops::poll_write(impl.socket_, impl.state_, -1, ec);
+ break;
+ case socket_base::wait_error:
+ socket_ops::poll_error(impl.socket_, impl.state_, -1, ec);
+ break;
+ default:
+ ec = boost::asio::error::invalid_argument;
+ break;
+ }
+
+ return ec;
+ }
+
+ // Asynchronously wait for the socket to become ready to read, ready to
+ // write, or to have pending error conditions.
+ template <typename Handler, typename IoExecutor>
+ void async_wait(base_implementation_type& impl,
+ socket_base::wait_type w, Handler& handler, const IoExecutor& io_ex)
+ {
+ bool is_continuation =
+ boost_asio_handler_cont_helpers::is_continuation(handler);
+
+ // Allocate and construct an operation to wrap the handler.
+ typedef reactive_wait_op<Handler, IoExecutor> op;
+ typename op::ptr p = { boost::asio::detail::addressof(handler),
+ op::ptr::allocate(handler), 0 };
+ p.p = new (p.v) op(success_ec_, handler, io_ex);
+
+ BOOST_ASIO_HANDLER_CREATION((reactor_.context(), *p.p, "socket",
+ &impl, impl.socket_, "async_wait"));
+
+ int op_type;
+ switch (w)
+ {
+ case socket_base::wait_read:
+ op_type = reactor::read_op;
+ break;
+ case socket_base::wait_write:
+ op_type = reactor::write_op;
+ break;
+ case socket_base::wait_error:
+ op_type = reactor::except_op;
+ break;
+ default:
+ p.p->ec_ = boost::asio::error::invalid_argument;
+ reactor_.post_immediate_completion(p.p, is_continuation);
+ p.v = p.p = 0;
+ return;
+ }
+
+ start_op(impl, op_type, p.p, is_continuation, false, false);
+ p.v = p.p = 0;
+ }
+
+ // Send the given data to the peer.
+ template <typename ConstBufferSequence>
+ size_t send(base_implementation_type& impl,
+ const ConstBufferSequence& buffers,
+ socket_base::message_flags flags, boost::system::error_code& ec)
+ {
+ buffer_sequence_adapter<boost::asio::const_buffer,
+ ConstBufferSequence> bufs(buffers);
+
+ return socket_ops::sync_send(impl.socket_, impl.state_,
+ bufs.buffers(), bufs.count(), flags, bufs.all_empty(), ec);
+ }
+
+ // Wait until data can be sent without blocking.
+ size_t send(base_implementation_type& impl, const null_buffers&,
+ socket_base::message_flags, boost::system::error_code& ec)
+ {
+ // Wait for socket to become ready.
+ socket_ops::poll_write(impl.socket_, impl.state_, -1, ec);
+
+ return 0;
+ }
+
+ // Start an asynchronous send. The data being sent must be valid for the
+ // lifetime of the asynchronous operation.
+ template <typename ConstBufferSequence, typename Handler, typename IoExecutor>
+ void async_send(base_implementation_type& impl,
+ const ConstBufferSequence& buffers, socket_base::message_flags flags,
+ Handler& handler, const IoExecutor& io_ex)
+ {
+ bool is_continuation =
+ boost_asio_handler_cont_helpers::is_continuation(handler);
+
+ // Allocate and construct an operation to wrap the handler.
+ typedef reactive_socket_send_op<
+ ConstBufferSequence, Handler, IoExecutor> op;
+ typename op::ptr p = { boost::asio::detail::addressof(handler),
+ op::ptr::allocate(handler), 0 };
+ p.p = new (p.v) op(success_ec_, impl.socket_, impl.state_,
+ buffers, flags, handler, io_ex);
+
+ BOOST_ASIO_HANDLER_CREATION((reactor_.context(), *p.p, "socket",
+ &impl, impl.socket_, "async_send"));
+
+ start_op(impl, reactor::write_op, p.p, is_continuation, true,
+ ((impl.state_ & socket_ops::stream_oriented)
+ && buffer_sequence_adapter<boost::asio::const_buffer,
+ ConstBufferSequence>::all_empty(buffers)));
+ p.v = p.p = 0;
+ }
+
+ // Start an asynchronous wait until data can be sent without blocking.
+ template <typename Handler, typename IoExecutor>
+ void async_send(base_implementation_type& impl, const null_buffers&,
+ socket_base::message_flags, Handler& handler, const IoExecutor& io_ex)
+ {
+ bool is_continuation =
+ boost_asio_handler_cont_helpers::is_continuation(handler);
+
+ // Allocate and construct an operation to wrap the handler.
+ typedef reactive_null_buffers_op<Handler, IoExecutor> op;
+ typename op::ptr p = { boost::asio::detail::addressof(handler),
+ op::ptr::allocate(handler), 0 };
+ p.p = new (p.v) op(success_ec_, handler, io_ex);
+
+ BOOST_ASIO_HANDLER_CREATION((reactor_.context(), *p.p, "socket",
+ &impl, impl.socket_, "async_send(null_buffers)"));
+
+ start_op(impl, reactor::write_op, p.p, is_continuation, false, false);
+ p.v = p.p = 0;
+ }
+
+ // Receive some data from the peer. Returns the number of bytes received.
+ template <typename MutableBufferSequence>
+ size_t receive(base_implementation_type& impl,
+ const MutableBufferSequence& buffers,
+ socket_base::message_flags flags, boost::system::error_code& ec)
+ {
+ buffer_sequence_adapter<boost::asio::mutable_buffer,
+ MutableBufferSequence> bufs(buffers);
+
+ return socket_ops::sync_recv(impl.socket_, impl.state_,
+ bufs.buffers(), bufs.count(), flags, bufs.all_empty(), ec);
+ }
+
+ // Wait until data can be received without blocking.
+ size_t receive(base_implementation_type& impl, const null_buffers&,
+ socket_base::message_flags, boost::system::error_code& ec)
+ {
+ // Wait for socket to become ready.
+ socket_ops::poll_read(impl.socket_, impl.state_, -1, ec);
+
+ return 0;
+ }
+
+ // Start an asynchronous receive. The buffer for the data being received
+ // must be valid for the lifetime of the asynchronous operation.
+ template <typename MutableBufferSequence,
+ typename Handler, typename IoExecutor>
+ void async_receive(base_implementation_type& impl,
+ const MutableBufferSequence& buffers, socket_base::message_flags flags,
+ Handler& handler, const IoExecutor& io_ex)
+ {
+ bool is_continuation =
+ boost_asio_handler_cont_helpers::is_continuation(handler);
+
+ // Allocate and construct an operation to wrap the handler.
+ typedef reactive_socket_recv_op_ext<
+ MutableBufferSequence, Handler, IoExecutor> op;
+ typename op::ptr p = { boost::asio::detail::addressof(handler),
+ op::ptr::allocate(handler), 0 };
+ p.p = new (p.v) op(success_ec_, impl.socket_, impl.state_,
+ buffers, flags, handler, io_ex);
+
+ BOOST_ASIO_HANDLER_CREATION((reactor_.context(), *p.p, "socket",
+ &impl, impl.socket_, "async_receive"));
+
+ start_op(impl,
+ (flags & socket_base::message_out_of_band)
+ ? reactor::except_op : reactor::read_op,
+ p.p, is_continuation,
+ (flags & socket_base::message_out_of_band) == 0,
+ ((impl.state_ & socket_ops::stream_oriented)
+ && buffer_sequence_adapter<boost::asio::mutable_buffer,
+ MutableBufferSequence>::all_empty(buffers)));
+ p.v = p.p = 0;
+ }
+
+ // Wait until data can be received without blocking.
+ template <typename Handler, typename IoExecutor>
+ void async_receive(base_implementation_type& impl,
+ const null_buffers&, socket_base::message_flags flags,
+ Handler& handler, const IoExecutor& io_ex)
+ {
+ bool is_continuation =
+ boost_asio_handler_cont_helpers::is_continuation(handler);
+
+ // Allocate and construct an operation to wrap the handler.
+ typedef reactive_null_buffers_op<Handler, IoExecutor> op;
+ typename op::ptr p = { boost::asio::detail::addressof(handler),
+ op::ptr::allocate(handler), 0 };
+ p.p = new (p.v) op(success_ec_, handler, io_ex);
+
+ BOOST_ASIO_HANDLER_CREATION((reactor_.context(), *p.p, "socket",
+ &impl, impl.socket_, "async_receive(null_buffers)"));
+
+ start_op(impl,
+ (flags & socket_base::message_out_of_band)
+ ? reactor::except_op : reactor::read_op,
+ p.p, is_continuation, false, false);
+ p.v = p.p = 0;
+ }
+
+ // Receive some data with associated flags. Returns the number of bytes
+ // received.
+ template <typename MutableBufferSequence>
+ size_t receive_with_flags(base_implementation_type& impl,
+ const MutableBufferSequence& buffers,
+ socket_base::message_flags in_flags,
+ socket_base::message_flags& out_flags, boost::system::error_code& ec)
+ {
+ buffer_sequence_adapter<boost::asio::mutable_buffer,
+ MutableBufferSequence> bufs(buffers);
+
+ return socket_ops::sync_recvmsg(impl.socket_, impl.state_,
+ bufs.buffers(), bufs.count(), in_flags, out_flags, ec);
+ }
+
+ // Wait until data can be received without blocking.
+ size_t receive_with_flags(base_implementation_type& impl,
+ const null_buffers&, socket_base::message_flags,
+ socket_base::message_flags& out_flags, boost::system::error_code& ec)
+ {
+ // Wait for socket to become ready.
+ socket_ops::poll_read(impl.socket_, impl.state_, -1, ec);
+
+ // Clear out_flags, since we cannot give it any other sensible value when
+ // performing a null_buffers operation.
+ out_flags = 0;
+
+ return 0;
+ }
+
+ // Start an asynchronous receive. The buffer for the data being received
+ // must be valid for the lifetime of the asynchronous operation.
+ template <typename MutableBufferSequence,
+ typename Handler, typename IoExecutor>
+ void async_receive_with_flags(base_implementation_type& impl,
+ const MutableBufferSequence& buffers, socket_base::message_flags in_flags,
+ socket_base::message_flags& out_flags, Handler& handler,
+ const IoExecutor& io_ex)
+ {
+ bool is_continuation =
+ boost_asio_handler_cont_helpers::is_continuation(handler);
+
+ // Allocate and construct an operation to wrap the handler.
+ typedef reactive_socket_recvmsg_op_ext<
+ MutableBufferSequence, Handler, IoExecutor> op;
+ typename op::ptr p = { boost::asio::detail::addressof(handler),
+ op::ptr::allocate(handler), 0 };
+ p.p = new (p.v) op(success_ec_, impl.socket_, buffers,
+ in_flags, out_flags, handler, io_ex);
+
+ BOOST_ASIO_HANDLER_CREATION((reactor_.context(), *p.p, "socket",
+ &impl, impl.socket_, "async_receive_with_flags"));
+
+ start_op(impl,
+ (in_flags & socket_base::message_out_of_band)
+ ? reactor::except_op : reactor::read_op,
+ p.p, is_continuation,
+ (in_flags & socket_base::message_out_of_band) == 0, false);
+ p.v = p.p = 0;
+ }
+
+ // Wait until data can be received without blocking.
+ template <typename Handler, typename IoExecutor>
+ void async_receive_with_flags(base_implementation_type& impl,
+ const null_buffers&, socket_base::message_flags in_flags,
+ socket_base::message_flags& out_flags, Handler& handler,
+ const IoExecutor& io_ex)
+ {
+ bool is_continuation =
+ boost_asio_handler_cont_helpers::is_continuation(handler);
+
+ // Allocate and construct an operation to wrap the handler.
+ typedef reactive_null_buffers_op<Handler, IoExecutor> op;
+ typename op::ptr p = { boost::asio::detail::addressof(handler),
+ op::ptr::allocate(handler), 0 };
+ p.p = new (p.v) op(success_ec_, handler, io_ex);
+
+ BOOST_ASIO_HANDLER_CREATION((reactor_.context(), *p.p, "socket",
+ &impl, impl.socket_, "async_receive_with_flags(null_buffers)"));
+
+ // Clear out_flags, since we cannot give it any other sensible value when
+ // performing a null_buffers operation.
+ out_flags = 0;
+
+ start_op(impl,
+ (in_flags & socket_base::message_out_of_band)
+ ? reactor::except_op : reactor::read_op,
+ p.p, is_continuation, false, false);
+ p.v = p.p = 0;
+ }
+
+protected:
+ // Open a new socket implementation.
+ BOOST_ASIO_DECL boost::system::error_code do_open(
+ base_implementation_type& impl, int af,
+ int type, int protocol, boost::system::error_code& ec);
+
+ // Assign a native socket to a socket implementation.
+ BOOST_ASIO_DECL boost::system::error_code do_assign(
+ base_implementation_type& impl, int type,
+ const native_handle_type& native_socket, boost::system::error_code& ec);
+
+ // Start the asynchronous read or write operation.
+ BOOST_ASIO_DECL void start_op(base_implementation_type& impl, int op_type,
+ reactor_op* op, bool is_continuation, bool is_non_blocking, bool noop);
+
+ // Start the asynchronous accept operation.
+ BOOST_ASIO_DECL void start_accept_op(base_implementation_type& impl,
+ reactor_op* op, bool is_continuation, bool peer_is_open);
+
+ // Start the asynchronous connect operation.
+ BOOST_ASIO_DECL void start_connect_op(base_implementation_type& impl,
+ reactor_op* op, bool is_continuation,
+ const socket_addr_type* addr, size_t addrlen);
+
+ // The selector that performs event demultiplexing for the service.
+ reactor& reactor_;
+
+ // Cached success value to avoid accessing category singleton.
+ const boost::system::error_code success_ec_;
+};
+
+} // namespace detail
+} // namespace asio
+} // namespace boost
+
+#include <boost/asio/detail/pop_options.hpp>
+
+#if defined(BOOST_ASIO_HEADER_ONLY)
+# include <boost/asio/detail/impl/reactive_socket_service_base_ext.ipp>
+#endif // defined(BOOST_ASIO_HEADER_ONLY)
+
+#endif // !defined(BOOST_ASIO_HAS_IOCP)
+ // && !defined(BOOST_ASIO_WINDOWS_RUNTIME)
+
+#endif // BOOST_ASIO_DETAIL_REACTIVE_SOCKET_SERVICE_BASE_EXT_HPP
diff --git a/implementation/helper/1.74/boost/asio/detail/reactive_socket_service_base_ext_local.hpp b/implementation/helper/1.74/boost/asio/detail/reactive_socket_service_base_ext_local.hpp
new file mode 100644
index 0000000..a71fce5
--- /dev/null
+++ b/implementation/helper/1.74/boost/asio/detail/reactive_socket_service_base_ext_local.hpp
@@ -0,0 +1,524 @@
+//
+// detail/reactive_socket_service_base_ext_local.hpp
+// ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+//
+// Copyright (c) 2003-2019 Christopher M. Kohlhoff (chris at kohlhoff dot com)
+// Copyright (c) 2016-2019 Bayerische Motoren Werke Aktiengesellschaft (BMW AG)
+//
+// Distributed under the Boost Software License, Version 1.0. (See accompanying
+// file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt)
+//
+
+#ifndef BOOST_ASIO_DETAIL_REACTIVE_SOCKET_SERVICE_BASE_EXT_LOCAL_HPP
+#define BOOST_ASIO_DETAIL_REACTIVE_SOCKET_SERVICE_BASE_EXT_LOCAL_HPP
+
+#if defined(_MSC_VER) && (_MSC_VER >= 1200)
+# pragma once
+#endif // defined(_MSC_VER) && (_MSC_VER >= 1200)
+
+#include <boost/asio/detail/config.hpp>
+
+#if !defined(BOOST_ASIO_HAS_IOCP) \
+ && !defined(BOOST_ASIO_WINDOWS_RUNTIME)
+
+#include <boost/asio/buffer.hpp>
+#include <boost/asio/error.hpp>
+#include <boost/asio/execution_context.hpp>
+#include <boost/asio/socket_base.hpp>
+#include <boost/asio/detail/buffer_sequence_adapter.hpp>
+#include <boost/asio/detail/memory.hpp>
+#include <boost/asio/detail/reactive_null_buffers_op.hpp>
+#include <boost/asio/detail/reactive_socket_recv_op_ext_local.hpp>
+#include <boost/asio/detail/reactive_socket_recvmsg_op_ext_local.hpp>
+#include <boost/asio/detail/reactive_socket_send_op.hpp>
+#include <boost/asio/detail/reactive_wait_op.hpp>
+#include <boost/asio/detail/reactor.hpp>
+#include <boost/asio/detail/reactor_op.hpp>
+#include <boost/asio/detail/socket_holder.hpp>
+#include <boost/asio/detail/socket_ops_ext_local.hpp>
+#include <boost/asio/detail/socket_types.hpp>
+
+#include <boost/asio/detail/push_options.hpp>
+
+namespace boost {
+namespace asio {
+namespace detail {
+
+class reactive_socket_service_base_ext_local
+{
+public:
+ // The native type of a socket.
+ typedef socket_type native_handle_type;
+
+ // The implementation type of the socket.
+ struct base_implementation_type
+ {
+ // The native socket representation.
+ socket_type socket_;
+
+ // The current state of the socket.
+ socket_ops::state_type state_;
+
+ // Per-descriptor data used by the reactor.
+ reactor::per_descriptor_data reactor_data_;
+ };
+
+ // Constructor.
+ BOOST_ASIO_DECL reactive_socket_service_base_ext_local(execution_context& context);
+
+ // Destroy all user-defined handler objects owned by the service.
+ BOOST_ASIO_DECL void base_shutdown();
+
+ // Construct a new socket implementation.
+ BOOST_ASIO_DECL void construct(base_implementation_type& impl);
+
+ // Move-construct a new socket implementation.
+ BOOST_ASIO_DECL void base_move_construct(base_implementation_type& impl,
+ base_implementation_type& other_impl);
+
+ // Move-assign from another socket implementation.
+ BOOST_ASIO_DECL void base_move_assign(base_implementation_type& impl,
+ reactive_socket_service_base_ext_local& other_service,
+ base_implementation_type& other_impl);
+
+ // Destroy a socket implementation.
+ BOOST_ASIO_DECL void destroy(base_implementation_type& impl);
+
+ // Determine whether the socket is open.
+ bool is_open(const base_implementation_type& impl) const
+ {
+ return impl.socket_ != invalid_socket;
+ }
+
+ // Destroy a socket implementation.
+ BOOST_ASIO_DECL boost::system::error_code close(
+ base_implementation_type& impl, boost::system::error_code& ec);
+
+ // Release ownership of the socket.
+ BOOST_ASIO_DECL socket_type release(
+ base_implementation_type& impl, boost::system::error_code& ec);
+
+ // Get the native socket representation.
+ native_handle_type native_handle(base_implementation_type& impl)
+ {
+ return impl.socket_;
+ }
+
+ // Cancel all operations associated with the socket.
+ BOOST_ASIO_DECL boost::system::error_code cancel(
+ base_implementation_type& impl, boost::system::error_code& ec);
+
+ // Determine whether the socket is at the out-of-band data mark.
+ bool at_mark(const base_implementation_type& impl,
+ boost::system::error_code& ec) const
+ {
+ return socket_ops::sockatmark(impl.socket_, ec);
+ }
+
+ // Determine the number of bytes available for reading.
+ std::size_t available(const base_implementation_type& impl,
+ boost::system::error_code& ec) const
+ {
+ return socket_ops::available(impl.socket_, ec);
+ }
+
+ // Place the socket into the state where it will listen for new connections.
+ boost::system::error_code listen(base_implementation_type& impl,
+ int backlog, boost::system::error_code& ec)
+ {
+ socket_ops::listen(impl.socket_, backlog, ec);
+ return ec;
+ }
+
+ // Perform an IO control command on the socket.
+ template <typename IO_Control_Command>
+ boost::system::error_code io_control(base_implementation_type& impl,
+ IO_Control_Command& command, boost::system::error_code& ec)
+ {
+ socket_ops::ioctl(impl.socket_, impl.state_, command.name(),
+ static_cast<ioctl_arg_type*>(command.data()), ec);
+ return ec;
+ }
+
+ // Gets the non-blocking mode of the socket.
+ bool non_blocking(const base_implementation_type& impl) const
+ {
+ return (impl.state_ & socket_ops::user_set_non_blocking) != 0;
+ }
+
+ // Sets the non-blocking mode of the socket.
+ boost::system::error_code non_blocking(base_implementation_type& impl,
+ bool mode, boost::system::error_code& ec)
+ {
+ socket_ops::set_user_non_blocking(impl.socket_, impl.state_, mode, ec);
+ return ec;
+ }
+
+ // Gets the non-blocking mode of the native socket implementation.
+ bool native_non_blocking(const base_implementation_type& impl) const
+ {
+ return (impl.state_ & socket_ops::internal_non_blocking) != 0;
+ }
+
+ // Sets the non-blocking mode of the native socket implementation.
+ boost::system::error_code native_non_blocking(base_implementation_type& impl,
+ bool mode, boost::system::error_code& ec)
+ {
+ socket_ops::set_internal_non_blocking(impl.socket_, impl.state_, mode, ec);
+ return ec;
+ }
+
+ // Wait for the socket to become ready to read, ready to write, or to have
+ // pending error conditions.
+ boost::system::error_code wait(base_implementation_type& impl,
+ socket_base::wait_type w, boost::system::error_code& ec)
+ {
+ switch (w)
+ {
+ case socket_base::wait_read:
+ socket_ops::poll_read(impl.socket_, impl.state_, -1, ec);
+ break;
+ case socket_base::wait_write:
+ socket_ops::poll_write(impl.socket_, impl.state_, -1, ec);
+ break;
+ case socket_base::wait_error:
+ socket_ops::poll_error(impl.socket_, impl.state_, -1, ec);
+ break;
+ default:
+ ec = boost::asio::error::invalid_argument;
+ break;
+ }
+
+ return ec;
+ }
+
+ // Asynchronously wait for the socket to become ready to read, ready to
+ // write, or to have pending error conditions.
+ template <typename Handler, typename IoExecutor>
+ void async_wait(base_implementation_type& impl,
+ socket_base::wait_type w, Handler& handler, const IoExecutor& io_ex)
+ {
+ bool is_continuation =
+ boost_asio_handler_cont_helpers::is_continuation(handler);
+
+ // Allocate and construct an operation to wrap the handler.
+ typedef reactive_wait_op<Handler, IoExecutor> op;
+ typename op::ptr p = { boost::asio::detail::addressof(handler),
+ op::ptr::allocate(handler), 0 };
+ p.p = new (p.v) op(success_ec_, handler, io_ex);
+
+ BOOST_ASIO_HANDLER_CREATION((reactor_.context(), *p.p, "socket",
+ &impl, impl.socket_, "async_wait"));
+
+ int op_type;
+ switch (w)
+ {
+ case socket_base::wait_read:
+ op_type = reactor::read_op;
+ break;
+ case socket_base::wait_write:
+ op_type = reactor::write_op;
+ break;
+ case socket_base::wait_error:
+ op_type = reactor::except_op;
+ break;
+ default:
+ p.p->ec_ = boost::asio::error::invalid_argument;
+ reactor_.post_immediate_completion(p.p, is_continuation);
+ p.v = p.p = 0;
+ return;
+ }
+
+ start_op(impl, op_type, p.p, is_continuation, false, false);
+ p.v = p.p = 0;
+ }
+
+ // Send the given data to the peer.
+ template <typename ConstBufferSequence>
+ size_t send(base_implementation_type& impl,
+ const ConstBufferSequence& buffers,
+ socket_base::message_flags flags, boost::system::error_code& ec)
+ {
+ buffer_sequence_adapter<boost::asio::const_buffer,
+ ConstBufferSequence> bufs(buffers);
+
+ return socket_ops::sync_send(impl.socket_, impl.state_,
+ bufs.buffers(), bufs.count(), flags, bufs.all_empty(), ec);
+ }
+
+ // Wait until data can be sent without blocking.
+ size_t send(base_implementation_type& impl, const null_buffers&,
+ socket_base::message_flags, boost::system::error_code& ec)
+ {
+ // Wait for socket to become ready.
+ socket_ops::poll_write(impl.socket_, impl.state_, -1, ec);
+
+ return 0;
+ }
+
+ // Start an asynchronous send. The data being sent must be valid for the
+ // lifetime of the asynchronous operation.
+ template <typename ConstBufferSequence, typename Handler, typename IoExecutor>
+ void async_send(base_implementation_type& impl,
+ const ConstBufferSequence& buffers, socket_base::message_flags flags,
+ Handler& handler, const IoExecutor& io_ex)
+ {
+ bool is_continuation =
+ boost_asio_handler_cont_helpers::is_continuation(handler);
+
+ // Allocate and construct an operation to wrap the handler.
+ typedef reactive_socket_send_op<
+ ConstBufferSequence, Handler, IoExecutor> op;
+ typename op::ptr p = { boost::asio::detail::addressof(handler),
+ op::ptr::allocate(handler), 0 };
+ p.p = new (p.v) op(success_ec_, impl.socket_, impl.state_,
+ buffers, flags, handler, io_ex);
+
+ BOOST_ASIO_HANDLER_CREATION((reactor_.context(), *p.p, "socket",
+ &impl, impl.socket_, "async_send"));
+
+ start_op(impl, reactor::write_op, p.p, is_continuation, true,
+ ((impl.state_ & socket_ops::stream_oriented)
+ && buffer_sequence_adapter<boost::asio::const_buffer,
+ ConstBufferSequence>::all_empty(buffers)));
+ p.v = p.p = 0;
+ }
+
+ // Start an asynchronous wait until data can be sent without blocking.
+ template <typename Handler, typename IoExecutor>
+ void async_send(base_implementation_type& impl, const null_buffers&,
+ socket_base::message_flags, Handler& handler, const IoExecutor& io_ex)
+ {
+ bool is_continuation =
+ boost_asio_handler_cont_helpers::is_continuation(handler);
+
+ // Allocate and construct an operation to wrap the handler.
+ typedef reactive_null_buffers_op<Handler, IoExecutor> op;
+ typename op::ptr p = { boost::asio::detail::addressof(handler),
+ op::ptr::allocate(handler), 0 };
+ p.p = new (p.v) op(success_ec_, handler, io_ex);
+
+ BOOST_ASIO_HANDLER_CREATION((reactor_.context(), *p.p, "socket",
+ &impl, impl.socket_, "async_send(null_buffers)"));
+
+ start_op(impl, reactor::write_op, p.p, is_continuation, false, false);
+ p.v = p.p = 0;
+ }
+
+ // Receive some data from the peer. Returns the number of bytes received.
+ template <typename MutableBufferSequence>
+ size_t receive(base_implementation_type& impl,
+ const MutableBufferSequence& buffers,
+ socket_base::message_flags flags, boost::system::error_code& ec)
+ {
+ buffer_sequence_adapter<boost::asio::mutable_buffer,
+ MutableBufferSequence> bufs(buffers);
+
+ return socket_ops::sync_recv(impl.socket_, impl.state_,
+ bufs.buffers(), bufs.count(), flags, bufs.all_empty(), ec);
+ }
+
+ // Wait until data can be received without blocking.
+ size_t receive(base_implementation_type& impl, const null_buffers&,
+ socket_base::message_flags, boost::system::error_code& ec)
+ {
+ // Wait for socket to become ready.
+ socket_ops::poll_read(impl.socket_, impl.state_, -1, ec);
+
+ return 0;
+ }
+
+ // Start an asynchronous receive. The buffer for the data being received
+ // must be valid for the lifetime of the asynchronous operation.
+ template <typename MutableBufferSequence,
+ typename Handler, typename IoExecutor>
+ void async_receive(base_implementation_type& impl,
+ const MutableBufferSequence& buffers, socket_base::message_flags flags,
+ Handler& handler, const IoExecutor& io_ex)
+ {
+ bool is_continuation =
+ boost_asio_handler_cont_helpers::is_continuation(handler);
+
+ // Allocate and construct an operation to wrap the handler.
+ typedef reactive_socket_recv_op_ext_local<
+ MutableBufferSequence, Handler, IoExecutor> op;
+ typename op::ptr p = { boost::asio::detail::addressof(handler),
+ op::ptr::allocate(handler), 0 };
+ p.p = new (p.v) op(success_ec_, impl.socket_, impl.state_,
+ buffers, flags, handler, io_ex);
+
+ BOOST_ASIO_HANDLER_CREATION((reactor_.context(), *p.p, "socket",
+ &impl, impl.socket_, "async_receive"));
+
+ start_op(impl,
+ (flags & socket_base::message_out_of_band)
+ ? reactor::except_op : reactor::read_op,
+ p.p, is_continuation,
+ (flags & socket_base::message_out_of_band) == 0,
+ ((impl.state_ & socket_ops::stream_oriented)
+ && buffer_sequence_adapter<boost::asio::mutable_buffer,
+ MutableBufferSequence>::all_empty(buffers)));
+ p.v = p.p = 0;
+ }
+
+ // Wait until data can be received without blocking.
+ template <typename Handler, typename IoExecutor>
+ void async_receive(base_implementation_type& impl,
+ const null_buffers&, socket_base::message_flags flags,
+ Handler& handler, const IoExecutor& io_ex)
+ {
+ bool is_continuation =
+ boost_asio_handler_cont_helpers::is_continuation(handler);
+
+ // Allocate and construct an operation to wrap the handler.
+ typedef reactive_null_buffers_op<Handler, IoExecutor> op;
+ typename op::ptr p = { boost::asio::detail::addressof(handler),
+ op::ptr::allocate(handler), 0 };
+ p.p = new (p.v) op(success_ec_, handler, io_ex);
+
+ BOOST_ASIO_HANDLER_CREATION((reactor_.context(), *p.p, "socket",
+ &impl, impl.socket_, "async_receive(null_buffers)"));
+
+ start_op(impl,
+ (flags & socket_base::message_out_of_band)
+ ? reactor::except_op : reactor::read_op,
+ p.p, is_continuation, false, false);
+ p.v = p.p = 0;
+ }
+
+ // Receive some data with associated flags. Returns the number of bytes
+ // received.
+ template <typename MutableBufferSequence>
+ size_t receive_with_flags(base_implementation_type& impl,
+ const MutableBufferSequence& buffers,
+ socket_base::message_flags in_flags,
+ socket_base::message_flags& out_flags, boost::system::error_code& ec)
+ {
+ buffer_sequence_adapter<boost::asio::mutable_buffer,
+ MutableBufferSequence> bufs(buffers);
+
+ return socket_ops::sync_recvmsg(impl.socket_, impl.state_,
+ bufs.buffers(), bufs.count(), in_flags, out_flags, ec);
+ }
+
+ // Wait until data can be received without blocking.
+ size_t receive_with_flags(base_implementation_type& impl,
+ const null_buffers&, socket_base::message_flags,
+ socket_base::message_flags& out_flags, boost::system::error_code& ec)
+ {
+ // Wait for socket to become ready.
+ socket_ops::poll_read(impl.socket_, impl.state_, -1, ec);
+
+ // Clear out_flags, since we cannot give it any other sensible value when
+ // performing a null_buffers operation.
+ out_flags = 0;
+
+ return 0;
+ }
+
+ // Start an asynchronous receive. The buffer for the data being received
+ // must be valid for the lifetime of the asynchronous operation.
+ template <typename MutableBufferSequence,
+ typename Handler, typename IoExecutor>
+ void async_receive_with_flags(base_implementation_type& impl,
+ const MutableBufferSequence& buffers, socket_base::message_flags in_flags,
+ socket_base::message_flags& out_flags, Handler& handler,
+ const IoExecutor& io_ex)
+ {
+ bool is_continuation =
+ boost_asio_handler_cont_helpers::is_continuation(handler);
+
+ // Allocate and construct an operation to wrap the handler.
+ typedef reactive_socket_recvmsg_op_ext_local<
+ MutableBufferSequence, Handler, IoExecutor> op;
+ typename op::ptr p = { boost::asio::detail::addressof(handler),
+ op::ptr::allocate(handler), 0 };
+ p.p = new (p.v) op(success_ec_, impl.socket_, buffers,
+ in_flags, out_flags, handler, io_ex);
+
+ BOOST_ASIO_HANDLER_CREATION((reactor_.context(), *p.p, "socket",
+ &impl, impl.socket_, "async_receive_with_flags"));
+
+ start_op(impl,
+ (in_flags & socket_base::message_out_of_band)
+ ? reactor::except_op : reactor::read_op,
+ p.p, is_continuation,
+ (in_flags & socket_base::message_out_of_band) == 0, false);
+ p.v = p.p = 0;
+ }
+
+ // Wait until data can be received without blocking.
+ template <typename Handler, typename IoExecutor>
+ void async_receive_with_flags(base_implementation_type& impl,
+ const null_buffers&, socket_base::message_flags in_flags,
+ socket_base::message_flags& out_flags, Handler& handler,
+ const IoExecutor& io_ex)
+ {
+ bool is_continuation =
+ boost_asio_handler_cont_helpers::is_continuation(handler);
+
+ // Allocate and construct an operation to wrap the handler.
+ typedef reactive_null_buffers_op<Handler, IoExecutor> op;
+ typename op::ptr p = { boost::asio::detail::addressof(handler),
+ op::ptr::allocate(handler), 0 };
+ p.p = new (p.v) op(success_ec_, handler, io_ex);
+
+ BOOST_ASIO_HANDLER_CREATION((reactor_.context(), *p.p, "socket",
+ &impl, impl.socket_, "async_receive_with_flags(null_buffers)"));
+
+ // Clear out_flags, since we cannot give it any other sensible value when
+ // performing a null_buffers operation.
+ out_flags = 0;
+
+ start_op(impl,
+ (in_flags & socket_base::message_out_of_band)
+ ? reactor::except_op : reactor::read_op,
+ p.p, is_continuation, false, false);
+ p.v = p.p = 0;
+ }
+
+protected:
+ // Open a new socket implementation.
+ BOOST_ASIO_DECL boost::system::error_code do_open(
+ base_implementation_type& impl, int af,
+ int type, int protocol, boost::system::error_code& ec);
+
+ // Assign a native socket to a socket implementation.
+ BOOST_ASIO_DECL boost::system::error_code do_assign(
+ base_implementation_type& impl, int type,
+ const native_handle_type& native_socket, boost::system::error_code& ec);
+
+ // Start the asynchronous read or write operation.
+ BOOST_ASIO_DECL void start_op(base_implementation_type& impl, int op_type,
+ reactor_op* op, bool is_continuation, bool is_non_blocking, bool noop);
+
+ // Start the asynchronous accept operation.
+ BOOST_ASIO_DECL void start_accept_op(base_implementation_type& impl,
+ reactor_op* op, bool is_continuation, bool peer_is_open);
+
+ // Start the asynchronous connect operation.
+ BOOST_ASIO_DECL void start_connect_op(base_implementation_type& impl,
+ reactor_op* op, bool is_continuation,
+ const socket_addr_type* addr, size_t addrlen);
+
+ // The selector that performs event demultiplexing for the service.
+ reactor& reactor_;
+
+ // Cached success value to avoid accessing category singleton.
+ const boost::system::error_code success_ec_;
+};
+
+} // namespace detail
+} // namespace asio
+} // namespace boost
+
+#include <boost/asio/detail/pop_options.hpp>
+
+#if defined(BOOST_ASIO_HEADER_ONLY)
+# include <boost/asio/detail/impl/reactive_socket_service_base_ext_local.ipp>
+#endif // defined(BOOST_ASIO_HEADER_ONLY)
+
+#endif // !defined(BOOST_ASIO_HAS_IOCP)
+ // && !defined(BOOST_ASIO_WINDOWS_RUNTIME)
+
+#endif // BOOST_ASIO_DETAIL_REACTIVE_SOCKET_SERVICE_BASE_EXT_LOCAL_HPP
diff --git a/implementation/helper/1.74/boost/asio/detail/reactive_socket_service_ext.hpp b/implementation/helper/1.74/boost/asio/detail/reactive_socket_service_ext.hpp
new file mode 100644
index 0000000..7254ccd
--- /dev/null
+++ b/implementation/helper/1.74/boost/asio/detail/reactive_socket_service_ext.hpp
@@ -0,0 +1,508 @@
+//
+// detail/reactive_socket_service_ext.hpp
+// ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+//
+// Copyright (c) 2003-2019 Christopher M. Kohlhoff (chris at kohlhoff dot com)
+// Copyright (c) 2019 Bayerische Motoren Werke Aktiengesellschaft (BMW AG)
+//
+// Distributed under the Boost Software License, Version 1.0. (See accompanying
+// file LICENSE_boost or copy at http://www.boost.org/LICENSE_1_0.txt)
+//
+
+#ifndef BOOST_ASIO_DETAIL_REACTIVE_SOCKET_SERVICE_EXT_HPP
+#define BOOST_ASIO_DETAIL_REACTIVE_SOCKET_SERVICE_EXT_HPP
+
+#if defined(_MSC_VER) && (_MSC_VER >= 1200)
+# pragma once
+#endif // defined(_MSC_VER) && (_MSC_VER >= 1200)
+
+#include <boost/asio/detail/config.hpp>
+
+#if !defined(BOOST_ASIO_HAS_IOCP)
+
+#include <boost/asio/buffer.hpp>
+#include <boost/asio/error.hpp>
+#include <boost/asio/execution_context.hpp>
+#include <boost/asio/socket_base.hpp>
+#include <boost/asio/detail/buffer_sequence_adapter.hpp>
+#include <boost/asio/detail/memory.hpp>
+#include <boost/asio/detail/noncopyable.hpp>
+#include <boost/asio/detail/reactive_null_buffers_op.hpp>
+#include <boost/asio/detail/reactive_socket_accept_op.hpp>
+#include <boost/asio/detail/reactive_socket_connect_op.hpp>
+#include <boost/asio/detail/reactive_socket_recvfrom_op_ext.hpp>
+#include <boost/asio/detail/reactive_socket_sendto_op.hpp>
+#include <boost/asio/detail/reactive_socket_service_base_ext.hpp>
+#include <boost/asio/detail/reactor.hpp>
+#include <boost/asio/detail/reactor_op.hpp>
+#include <boost/asio/detail/socket_holder.hpp>
+#include <boost/asio/detail/socket_ops.hpp>
+#include <boost/asio/detail/socket_types.hpp>
+
+#include <boost/asio/detail/push_options.hpp>
+
+namespace boost {
+namespace asio {
+namespace detail {
+
+template <typename Protocol>
+class reactive_socket_service_ext :
+ public execution_context_service_base<reactive_socket_service_ext<Protocol> >,
+ public reactive_socket_service_base_ext
+{
+public:
+ // The protocol type.
+ typedef Protocol protocol_type;
+
+ // The endpoint type.
+ typedef typename Protocol::endpoint endpoint_type;
+
+ // The native type of a socket.
+ typedef socket_type native_handle_type;
+
+ // The implementation type of the socket.
+ struct implementation_type :
+ reactive_socket_service_base_ext::base_implementation_type
+ {
+ // Default constructor.
+ implementation_type()
+ : protocol_(endpoint_type().protocol())
+ {
+ }
+
+ // The protocol associated with the socket.
+ protocol_type protocol_;
+ };
+
+ // Constructor.
+ reactive_socket_service_ext(execution_context& context)
+ : execution_context_service_base<
+ reactive_socket_service_ext<Protocol> >(context),
+ reactive_socket_service_base_ext(context)
+ {
+ }
+
+ // Destroy all user-defined handler objects owned by the service.
+ void shutdown()
+ {
+ this->base_shutdown();
+ }
+
+ // Move-construct a new socket implementation.
+ void move_construct(implementation_type& impl,
+ implementation_type& other_impl)
+ {
+ this->base_move_construct(impl, other_impl);
+
+ impl.protocol_ = other_impl.protocol_;
+ other_impl.protocol_ = endpoint_type().protocol();
+ }
+
+ // Move-assign from another socket implementation.
+ void move_assign(implementation_type& impl,
+ reactive_socket_service_base_ext& other_service,
+ implementation_type& other_impl)
+ {
+ this->base_move_assign(impl, other_service, other_impl);
+
+ impl.protocol_ = other_impl.protocol_;
+ other_impl.protocol_ = endpoint_type().protocol();
+ }
+
+ // Move-construct a new socket implementation from another protocol type.
+ template <typename Protocol1>
+ void converting_move_construct(implementation_type& impl,
+ reactive_socket_service_ext<Protocol1>&,
+ typename reactive_socket_service_ext<
+ Protocol1>::implementation_type& other_impl)
+ {
+ this->base_move_construct(impl, other_impl);
+
+ impl.protocol_ = protocol_type(other_impl.protocol_);
+ other_impl.protocol_ = typename Protocol1::endpoint().protocol();
+ }
+
+ // Open a new socket implementation.
+ boost::system::error_code open(implementation_type& impl,
+ const protocol_type& protocol, boost::system::error_code& ec)
+ {
+ if (!do_open(impl, protocol.family(),
+ protocol.type(), protocol.protocol(), ec))
+ impl.protocol_ = protocol;
+ return ec;
+ }
+
+ // Assign a native socket to a socket implementation.
+ boost::system::error_code assign(implementation_type& impl,
+ const protocol_type& protocol, const native_handle_type& native_socket,
+ boost::system::error_code& ec)
+ {
+ if (!do_assign(impl, protocol.type(), native_socket, ec))
+ impl.protocol_ = protocol;
+ return ec;
+ }
+
+ // Get the native socket representation.
+ native_handle_type native_handle(implementation_type& impl)
+ {
+ return impl.socket_;
+ }
+
+ // Bind the socket to the specified local endpoint.
+ boost::system::error_code bind(implementation_type& impl,
+ const endpoint_type& endpoint, boost::system::error_code& ec)
+ {
+ socket_ops::bind(impl.socket_, endpoint.data(), endpoint.size(), ec);
+ return ec;
+ }
+
+ // Set a socket option.
+ template <typename Option>
+ boost::system::error_code set_option(implementation_type& impl,
+ const Option& option, boost::system::error_code& ec)
+ {
+ socket_ops::setsockopt(impl.socket_, impl.state_,
+ option.level(impl.protocol_), option.name(impl.protocol_),
+ option.data(impl.protocol_), option.size(impl.protocol_), ec);
+ return ec;
+ }
+
+ // Set a socket option.
+ template <typename Option>
+ boost::system::error_code get_option(const implementation_type& impl,
+ Option& option, boost::system::error_code& ec) const
+ {
+ std::size_t size = option.size(impl.protocol_);
+ socket_ops::getsockopt(impl.socket_, impl.state_,
+ option.level(impl.protocol_), option.name(impl.protocol_),
+ option.data(impl.protocol_), &size, ec);
+ if (!ec)
+ option.resize(impl.protocol_, size);
+ return ec;
+ }
+
+ // Get the local endpoint.
+ endpoint_type local_endpoint(const implementation_type& impl,
+ boost::system::error_code& ec) const
+ {
+ endpoint_type endpoint;
+ std::size_t addr_len = endpoint.capacity();
+ if (socket_ops::getsockname(impl.socket_, endpoint.data(), &addr_len, ec))
+ return endpoint_type();
+ endpoint.resize(addr_len);
+ return endpoint;
+ }
+
+ // Get the remote endpoint.
+ endpoint_type remote_endpoint(const implementation_type& impl,
+ boost::system::error_code& ec) const
+ {
+ endpoint_type endpoint;
+ std::size_t addr_len = endpoint.capacity();
+ if (socket_ops::getpeername(impl.socket_,
+ endpoint.data(), &addr_len, false, ec))
+ return endpoint_type();
+ endpoint.resize(addr_len);
+ return endpoint;
+ }
+
+ // Disable sends or receives on the socket.
+ boost::system::error_code shutdown(base_implementation_type& impl,
+ socket_base::shutdown_type what, boost::system::error_code& ec)
+ {
+ socket_ops::shutdown(impl.socket_, what, ec);
+ return ec;
+ }
+
+ // Send a datagram to the specified endpoint. Returns the number of bytes
+ // sent.
+ template <typename ConstBufferSequence>
+ size_t send_to(implementation_type& impl, const ConstBufferSequence& buffers,
+ const endpoint_type& destination, socket_base::message_flags flags,
+ boost::system::error_code& ec)
+ {
+ buffer_sequence_adapter<boost::asio::const_buffer,
+ ConstBufferSequence> bufs(buffers);
+
+ return socket_ops::sync_sendto(impl.socket_, impl.state_,
+ bufs.buffers(), bufs.count(), flags,
+ destination.data(), destination.size(), ec);
+ }
+
+ // Wait until data can be sent without blocking.
+ size_t send_to(implementation_type& impl, const null_buffers&,
+ const endpoint_type&, socket_base::message_flags,
+ boost::system::error_code& ec)
+ {
+ // Wait for socket to become ready.
+ socket_ops::poll_write(impl.socket_, impl.state_, -1, ec);
+
+ return 0;
+ }
+
+ // Start an asynchronous send. The data being sent must be valid for the
+ // lifetime of the asynchronous operation.
+ template <typename ConstBufferSequence, typename Handler, typename IoExecutor>
+ void async_send_to(implementation_type& impl,
+ const ConstBufferSequence& buffers,
+ const endpoint_type& destination, socket_base::message_flags flags,
+ Handler& handler, const IoExecutor& io_ex)
+ {
+ bool is_continuation =
+ boost_asio_handler_cont_helpers::is_continuation(handler);
+
+ // Allocate and construct an operation to wrap the handler.
+ typedef reactive_socket_sendto_op<ConstBufferSequence,
+ endpoint_type, Handler, IoExecutor> op;
+ typename op::ptr p = { boost::asio::detail::addressof(handler),
+ op::ptr::allocate(handler), 0 };
+ p.p = new (p.v) op(success_ec_, impl.socket_, buffers,
+ destination, flags, handler, io_ex);
+
+ BOOST_ASIO_HANDLER_CREATION((reactor_.context(), *p.p, "socket",
+ &impl, impl.socket_, "async_send_to"));
+
+ start_op(impl, reactor::write_op, p.p, is_continuation, true, false);
+ p.v = p.p = 0;
+ }
+
+ // Start an asynchronous wait until data can be sent without blocking.
+ template <typename Handler, typename IoExecutor>
+ void async_send_to(implementation_type& impl, const null_buffers&,
+ const endpoint_type&, socket_base::message_flags,
+ Handler& handler, const IoExecutor& io_ex)
+ {
+ bool is_continuation =
+ boost_asio_handler_cont_helpers::is_continuation(handler);
+
+ // Allocate and construct an operation to wrap the handler.
+ typedef reactive_null_buffers_op<Handler, IoExecutor> op;
+ typename op::ptr p = { boost::asio::detail::addressof(handler),
+ op::ptr::allocate(handler), 0 };
+ p.p = new (p.v) op(success_ec_, handler, io_ex);
+
+ BOOST_ASIO_HANDLER_CREATION((reactor_.context(), *p.p, "socket",
+ &impl, impl.socket_, "async_send_to(null_buffers)"));
+
+ start_op(impl, reactor::write_op, p.p, is_continuation, false, false);
+ p.v = p.p = 0;
+ }
+
+ // Receive a datagram with the endpoint of the sender. Returns the number of
+ // bytes received.
+ template <typename MutableBufferSequence>
+ size_t receive_from(implementation_type& impl,
+ const MutableBufferSequence& buffers,
+ endpoint_type& sender_endpoint, socket_base::message_flags flags,
+ boost::system::error_code& ec)
+ {
+ buffer_sequence_adapter<boost::asio::mutable_buffer,
+ MutableBufferSequence> bufs(buffers);
+
+ std::size_t addr_len = sender_endpoint.capacity();
+ std::size_t bytes_recvd = socket_ops::sync_recvfrom(
+ impl.socket_, impl.state_, bufs.buffers(), bufs.count(),
+ flags, sender_endpoint.data(), &addr_len, ec);
+
+ if (!ec)
+ sender_endpoint.resize(addr_len);
+
+ return bytes_recvd;
+ }
+
+ // Wait until data can be received without blocking.
+ size_t receive_from(implementation_type& impl, const null_buffers&,
+ endpoint_type& sender_endpoint, socket_base::message_flags,
+ boost::system::error_code& ec)
+ {
+ // Wait for socket to become ready.
+ socket_ops::poll_read(impl.socket_, impl.state_, -1, ec);
+
+ // Reset endpoint since it can be given no sensible value at this time.
+ sender_endpoint = endpoint_type();
+
+ return 0;
+ }
+
+ // Start an asynchronous receive. The buffer for the data being received and
+ // the sender_endpoint object must both be valid for the lifetime of the
+ // asynchronous operation.
+ template <typename MutableBufferSequence,
+ typename Handler, typename IoExecutor>
+ void async_receive_from(implementation_type& impl,
+ const MutableBufferSequence& buffers, endpoint_type& sender_endpoint,
+ socket_base::message_flags flags, Handler& handler,
+ const IoExecutor& io_ex)
+ {
+ bool is_continuation =
+ boost_asio_handler_cont_helpers::is_continuation(handler);
+
+ // Allocate and construct an operation to wrap the handler.
+ typedef reactive_socket_recvfrom_op_ext<MutableBufferSequence,
+ endpoint_type, Handler, IoExecutor> op;
+ typename op::ptr p = { boost::asio::detail::addressof(handler),
+ op::ptr::allocate(handler), 0 };
+ int protocol = impl.protocol_.type();
+ p.p = new (p.v) op(success_ec_, impl.socket_, protocol, buffers,
+ sender_endpoint, flags, handler, io_ex);
+
+ BOOST_ASIO_HANDLER_CREATION((reactor_.context(), *p.p, "socket",
+ &impl, impl.socket_, "async_receive_from"));
+
+ start_op(impl,
+ (flags & socket_base::message_out_of_band)
+ ? reactor::except_op : reactor::read_op,
+ p.p, is_continuation, true, false);
+ p.v = p.p = 0;
+ }
+
+ // Wait until data can be received without blocking.
+ template <typename Handler, typename IoExecutor>
+ void async_receive_from(implementation_type& impl, const null_buffers&,
+ endpoint_type& sender_endpoint, socket_base::message_flags flags,
+ Handler& handler, const IoExecutor& io_ex)
+ {
+ bool is_continuation =
+ boost_asio_handler_cont_helpers::is_continuation(handler);
+
+ // Allocate and construct an operation to wrap the handler.
+ typedef reactive_null_buffers_op<Handler, IoExecutor> op;
+ typename op::ptr p = { boost::asio::detail::addressof(handler),
+ op::ptr::allocate(handler), 0 };
+ p.p = new (p.v) op(success_ec_, handler, io_ex);
+
+ BOOST_ASIO_HANDLER_CREATION((reactor_.context(), *p.p, "socket",
+ &impl, impl.socket_, "async_receive_from(null_buffers)"));
+
+ // Reset endpoint since it can be given no sensible value at this time.
+ sender_endpoint = endpoint_type();
+
+ start_op(impl,
+ (flags & socket_base::message_out_of_band)
+ ? reactor::except_op : reactor::read_op,
+ p.p, is_continuation, false, false);
+ p.v = p.p = 0;
+ }
+
+ // Accept a new connection.
+ template <typename Socket>
+ boost::system::error_code accept(implementation_type& impl,
+ Socket& peer, endpoint_type* peer_endpoint, boost::system::error_code& ec)
+ {
+ // We cannot accept a socket that is already open.
+ if (peer.is_open())
+ {
+ ec = boost::asio::error::already_open;
+ return ec;
+ }
+
+ std::size_t addr_len = peer_endpoint ? peer_endpoint->capacity() : 0;
+ socket_holder new_socket(socket_ops::sync_accept(impl.socket_,
+ impl.state_, peer_endpoint ? peer_endpoint->data() : 0,
+ peer_endpoint ? &addr_len : 0, ec));
+
+ // On success, assign new connection to peer socket object.
+ if (new_socket.get() != invalid_socket)
+ {
+ if (peer_endpoint)
+ peer_endpoint->resize(addr_len);
+ peer.assign(impl.protocol_, new_socket.get(), ec);
+ if (!ec)
+ new_socket.release();
+ }
+
+ return ec;
+ }
+
+ // Start an asynchronous accept. The peer and peer_endpoint objects must be
+ // valid until the accept's handler is invoked.
+ template <typename Socket, typename Handler, typename IoExecutor>
+ void async_accept(implementation_type& impl, Socket& peer,
+ endpoint_type* peer_endpoint, Handler& handler, const IoExecutor& io_ex)
+ {
+ bool is_continuation =
+ boost_asio_handler_cont_helpers::is_continuation(handler);
+
+ // Allocate and construct an operation to wrap the handler.
+ typedef reactive_socket_accept_op<Socket, Protocol, Handler, IoExecutor> op;
+ typename op::ptr p = { boost::asio::detail::addressof(handler),
+ op::ptr::allocate(handler), 0 };
+ p.p = new (p.v) op(success_ec_, impl.socket_, impl.state_, peer,
+ impl.protocol_, peer_endpoint, handler, io_ex);
+
+ BOOST_ASIO_HANDLER_CREATION((reactor_.context(), *p.p, "socket",
+ &impl, impl.socket_, "async_accept"));
+
+ start_accept_op(impl, p.p, is_continuation, peer.is_open());
+ p.v = p.p = 0;
+ }
+
+#if defined(BOOST_ASIO_HAS_MOVE)
+ // Start an asynchronous accept. The peer_endpoint object must be valid until
+ // the accept's handler is invoked.
+ template <typename PeerIoExecutor, typename Handler, typename IoExecutor>
+ void async_move_accept(implementation_type& impl,
+ const PeerIoExecutor& peer_io_ex, endpoint_type* peer_endpoint,
+ Handler& handler, const IoExecutor& io_ex)
+ {
+ bool is_continuation =
+ boost_asio_handler_cont_helpers::is_continuation(handler);
+
+ // Allocate and construct an operation to wrap the handler.
+ typedef reactive_socket_move_accept_op<Protocol,
+ PeerIoExecutor, Handler, IoExecutor> op;
+ typename op::ptr p = { boost::asio::detail::addressof(handler),
+ op::ptr::allocate(handler), 0 };
+ p.p = new (p.v) op(success_ec_, peer_io_ex, impl.socket_, impl.state_,
+ impl.protocol_, peer_endpoint, handler, io_ex);
+
+ BOOST_ASIO_HANDLER_CREATION((reactor_.context(), *p.p, "socket",
+ &impl, impl.socket_, "async_accept"));
+
+ start_accept_op(impl, p.p, is_continuation, false);
+ p.v = p.p = 0;
+ }
+#endif // defined(BOOST_ASIO_HAS_MOVE)
+
+ // Connect the socket to the specified endpoint.
+ boost::system::error_code connect(implementation_type& impl,
+ const endpoint_type& peer_endpoint, boost::system::error_code& ec)
+ {
+ socket_ops::sync_connect(impl.socket_,
+ peer_endpoint.data(), peer_endpoint.size(), ec);
+ return ec;
+ }
+
+ // Start an asynchronous connect.
+ template <typename Handler, typename IoExecutor>
+ void async_connect(implementation_type& impl,
+ const endpoint_type& peer_endpoint,
+ Handler& handler, const IoExecutor& io_ex)
+ {
+ bool is_continuation =
+ boost_asio_handler_cont_helpers::is_continuation(handler);
+
+ // Allocate and construct an operation to wrap the handler.
+ typedef reactive_socket_connect_op<Handler, IoExecutor> op;
+ typename op::ptr p = { boost::asio::detail::addressof(handler),
+ op::ptr::allocate(handler), 0 };
+ p.p = new (p.v) op(success_ec_, impl.socket_, handler, io_ex);
+
+ BOOST_ASIO_HANDLER_CREATION((reactor_.context(), *p.p, "socket",
+ &impl, impl.socket_, "async_connect"));
+
+ start_connect_op(impl, p.p, is_continuation,
+ peer_endpoint.data(), peer_endpoint.size());
+ p.v = p.p = 0;
+ }
+};
+
+} // namespace detail
+} // namespace asio
+} // namespace boost
+
+#include <boost/asio/detail/pop_options.hpp>
+
+#endif // !defined(BOOST_ASIO_HAS_IOCP)
+
+#endif // BOOST_ASIO_DETAIL_REACTIVE_SOCKET_SERVICE_EXT_HPP
diff --git a/implementation/helper/1.74/boost/asio/detail/reactive_socket_service_ext_local.hpp b/implementation/helper/1.74/boost/asio/detail/reactive_socket_service_ext_local.hpp
new file mode 100644
index 0000000..8ac3265
--- /dev/null
+++ b/implementation/helper/1.74/boost/asio/detail/reactive_socket_service_ext_local.hpp
@@ -0,0 +1,508 @@
+//
+// detail/reactive_socket_service_ext_local.hpp
+// ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+//
+// Copyright (c) 2003-2019 Christopher M. Kohlhoff (chris at kohlhoff dot com)
+// Copyright (c) 2019 Bayerische Motoren Werke Aktiengesellschaft (BMW AG)
+//
+// Distributed under the Boost Software License, Version 1.0. (See accompanying
+// file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt)
+//
+
+#ifndef BOOST_ASIO_DETAIL_REACTIVE_SOCKET_SERVICE_EXT_LOCAL_HPP
+#define BOOST_ASIO_DETAIL_REACTIVE_SOCKET_SERVICE_EXT_LOCAL_HPP
+
+#if defined(_MSC_VER) && (_MSC_VER >= 1200)
+# pragma once
+#endif // defined(_MSC_VER) && (_MSC_VER >= 1200)
+
+#include <boost/asio/detail/config.hpp>
+
+#if !defined(BOOST_ASIO_HAS_IOCP)
+
+#include <boost/asio/buffer.hpp>
+#include <boost/asio/error.hpp>
+#include <boost/asio/execution_context.hpp>
+#include <boost/asio/socket_base.hpp>
+#include <boost/asio/detail/buffer_sequence_adapter.hpp>
+#include <boost/asio/detail/memory.hpp>
+#include <boost/asio/detail/noncopyable.hpp>
+#include <boost/asio/detail/reactive_null_buffers_op.hpp>
+#include <boost/asio/detail/reactive_socket_accept_op.hpp>
+#include <boost/asio/detail/reactive_socket_connect_op.hpp>
+#include <boost/asio/detail/reactive_socket_recvfrom_op_ext_local.hpp>
+#include <boost/asio/detail/reactive_socket_sendto_op.hpp>
+#include <boost/asio/detail/reactive_socket_service_base_ext_local.hpp>
+#include <boost/asio/detail/reactor.hpp>
+#include <boost/asio/detail/reactor_op.hpp>
+#include <boost/asio/detail/socket_holder.hpp>
+#include <boost/asio/detail/socket_ops.hpp>
+#include <boost/asio/detail/socket_types.hpp>
+
+#include <boost/asio/detail/push_options.hpp>
+
+namespace boost {
+namespace asio {
+namespace detail {
+
+template <typename Protocol>
+class reactive_socket_service_ext_local :
+ public execution_context_service_base<reactive_socket_service_ext_local<Protocol> >,
+ public reactive_socket_service_base_ext_local
+{
+public:
+ // The protocol type.
+ typedef Protocol protocol_type;
+
+ // The endpoint type.
+ typedef typename Protocol::endpoint endpoint_type;
+
+ // The native type of a socket.
+ typedef socket_type native_handle_type;
+
+ // The implementation type of the socket.
+ struct implementation_type :
+ reactive_socket_service_base_ext_local::base_implementation_type
+ {
+ // Default constructor.
+ implementation_type()
+ : protocol_(endpoint_type().protocol())
+ {
+ }
+
+ // The protocol associated with the socket.
+ protocol_type protocol_;
+ };
+
+ // Constructor.
+ reactive_socket_service_ext_local(execution_context& context)
+ : execution_context_service_base<
+ reactive_socket_service_ext_local<Protocol> >(context),
+ reactive_socket_service_base_ext_local(context)
+ {
+ }
+
+ // Destroy all user-defined handler objects owned by the service.
+ void shutdown()
+ {
+ this->base_shutdown();
+ }
+
+ // Move-construct a new socket implementation.
+ void move_construct(implementation_type& impl,
+ implementation_type& other_impl)
+ {
+ this->base_move_construct(impl, other_impl);
+
+ impl.protocol_ = other_impl.protocol_;
+ other_impl.protocol_ = endpoint_type().protocol();
+ }
+
+ // Move-assign from another socket implementation.
+ void move_assign(implementation_type& impl,
+ reactive_socket_service_base_ext_local& other_service,
+ implementation_type& other_impl)
+ {
+ this->base_move_assign(impl, other_service, other_impl);
+
+ impl.protocol_ = other_impl.protocol_;
+ other_impl.protocol_ = endpoint_type().protocol();
+ }
+
+ // Move-construct a new socket implementation from another protocol type.
+ template <typename Protocol1>
+ void converting_move_construct(implementation_type& impl,
+ reactive_socket_service_ext_local<Protocol1>&,
+ typename reactive_socket_service_ext_local<
+ Protocol1>::implementation_type& other_impl)
+ {
+ this->base_move_construct(impl, other_impl);
+
+ impl.protocol_ = protocol_type(other_impl.protocol_);
+ other_impl.protocol_ = typename Protocol1::endpoint().protocol();
+ }
+
+ // Open a new socket implementation.
+ boost::system::error_code open(implementation_type& impl,
+ const protocol_type& protocol, boost::system::error_code& ec)
+ {
+ if (!do_open(impl, protocol.family(),
+ protocol.type(), protocol.protocol(), ec))
+ impl.protocol_ = protocol;
+ return ec;
+ }
+
+ // Assign a native socket to a socket implementation.
+ boost::system::error_code assign(implementation_type& impl,
+ const protocol_type& protocol, const native_handle_type& native_socket,
+ boost::system::error_code& ec)
+ {
+ if (!do_assign(impl, protocol.type(), native_socket, ec))
+ impl.protocol_ = protocol;
+ return ec;
+ }
+
+ // Get the native socket representation.
+ native_handle_type native_handle(implementation_type& impl)
+ {
+ return impl.socket_;
+ }
+
+ // Bind the socket to the specified local endpoint.
+ boost::system::error_code bind(implementation_type& impl,
+ const endpoint_type& endpoint, boost::system::error_code& ec)
+ {
+ socket_ops::bind(impl.socket_, endpoint.data(), endpoint.size(), ec);
+ return ec;
+ }
+
+ // Set a socket option.
+ template <typename Option>
+ boost::system::error_code set_option(implementation_type& impl,
+ const Option& option, boost::system::error_code& ec)
+ {
+ socket_ops::setsockopt(impl.socket_, impl.state_,
+ option.level(impl.protocol_), option.name(impl.protocol_),
+ option.data(impl.protocol_), option.size(impl.protocol_), ec);
+ return ec;
+ }
+
+ // Set a socket option.
+ template <typename Option>
+ boost::system::error_code get_option(const implementation_type& impl,
+ Option& option, boost::system::error_code& ec) const
+ {
+ std::size_t size = option.size(impl.protocol_);
+ socket_ops::getsockopt(impl.socket_, impl.state_,
+ option.level(impl.protocol_), option.name(impl.protocol_),
+ option.data(impl.protocol_), &size, ec);
+ if (!ec)
+ option.resize(impl.protocol_, size);
+ return ec;
+ }
+
+ // Get the local endpoint.
+ endpoint_type local_endpoint(const implementation_type& impl,
+ boost::system::error_code& ec) const
+ {
+ endpoint_type endpoint;
+ std::size_t addr_len = endpoint.capacity();
+ if (socket_ops::getsockname(impl.socket_, endpoint.data(), &addr_len, ec))
+ return endpoint_type();
+ endpoint.resize(addr_len);
+ return endpoint;
+ }
+
+ // Get the remote endpoint.
+ endpoint_type remote_endpoint(const implementation_type& impl,
+ boost::system::error_code& ec) const
+ {
+ endpoint_type endpoint;
+ std::size_t addr_len = endpoint.capacity();
+ if (socket_ops::getpeername(impl.socket_,
+ endpoint.data(), &addr_len, false, ec))
+ return endpoint_type();
+ endpoint.resize(addr_len);
+ return endpoint;
+ }
+
+ // Disable sends or receives on the socket.
+ boost::system::error_code shutdown(base_implementation_type& impl,
+ socket_base::shutdown_type what, boost::system::error_code& ec)
+ {
+ socket_ops::shutdown(impl.socket_, what, ec);
+ return ec;
+ }
+
+ // Send a datagram to the specified endpoint. Returns the number of bytes
+ // sent.
+ template <typename ConstBufferSequence>
+ size_t send_to(implementation_type& impl, const ConstBufferSequence& buffers,
+ const endpoint_type& destination, socket_base::message_flags flags,
+ boost::system::error_code& ec)
+ {
+ buffer_sequence_adapter<boost::asio::const_buffer,
+ ConstBufferSequence> bufs(buffers);
+
+ return socket_ops::sync_sendto(impl.socket_, impl.state_,
+ bufs.buffers(), bufs.count(), flags,
+ destination.data(), destination.size(), ec);
+ }
+
+ // Wait until data can be sent without blocking.
+ size_t send_to(implementation_type& impl, const null_buffers&,
+ const endpoint_type&, socket_base::message_flags,
+ boost::system::error_code& ec)
+ {
+ // Wait for socket to become ready.
+ socket_ops::poll_write(impl.socket_, impl.state_, -1, ec);
+
+ return 0;
+ }
+
+ // Start an asynchronous send. The data being sent must be valid for the
+ // lifetime of the asynchronous operation.
+ template <typename ConstBufferSequence, typename Handler, typename IoExecutor>
+ void async_send_to(implementation_type& impl,
+ const ConstBufferSequence& buffers,
+ const endpoint_type& destination, socket_base::message_flags flags,
+ Handler& handler, const IoExecutor& io_ex)
+ {
+ bool is_continuation =
+ boost_asio_handler_cont_helpers::is_continuation(handler);
+
+ // Allocate and construct an operation to wrap the handler.
+ typedef reactive_socket_sendto_op<ConstBufferSequence,
+ endpoint_type, Handler, IoExecutor> op;
+ typename op::ptr p = { boost::asio::detail::addressof(handler),
+ op::ptr::allocate(handler), 0 };
+ p.p = new (p.v) op(success_ec_, impl.socket_, buffers,
+ destination, flags, handler, io_ex);
+
+ BOOST_ASIO_HANDLER_CREATION((reactor_.context(), *p.p, "socket",
+ &impl, impl.socket_, "async_send_to"));
+
+ start_op(impl, reactor::write_op, p.p, is_continuation, true, false);
+ p.v = p.p = 0;
+ }
+
+ // Start an asynchronous wait until data can be sent without blocking.
+ template <typename Handler, typename IoExecutor>
+ void async_send_to(implementation_type& impl, const null_buffers&,
+ const endpoint_type&, socket_base::message_flags,
+ Handler& handler, const IoExecutor& io_ex)
+ {
+ bool is_continuation =
+ boost_asio_handler_cont_helpers::is_continuation(handler);
+
+ // Allocate and construct an operation to wrap the handler.
+ typedef reactive_null_buffers_op<Handler, IoExecutor> op;
+ typename op::ptr p = { boost::asio::detail::addressof(handler),
+ op::ptr::allocate(handler), 0 };
+ p.p = new (p.v) op(success_ec_, handler, io_ex);
+
+ BOOST_ASIO_HANDLER_CREATION((reactor_.context(), *p.p, "socket",
+ &impl, impl.socket_, "async_send_to(null_buffers)"));
+
+ start_op(impl, reactor::write_op, p.p, is_continuation, false, false);
+ p.v = p.p = 0;
+ }
+
+ // Receive a datagram with the endpoint of the sender. Returns the number of
+ // bytes received.
+ template <typename MutableBufferSequence>
+ size_t receive_from(implementation_type& impl,
+ const MutableBufferSequence& buffers,
+ endpoint_type& sender_endpoint, socket_base::message_flags flags,
+ boost::system::error_code& ec)
+ {
+ buffer_sequence_adapter<boost::asio::mutable_buffer,
+ MutableBufferSequence> bufs(buffers);
+
+ std::size_t addr_len = sender_endpoint.capacity();
+ std::size_t bytes_recvd = socket_ops::sync_recvfrom(
+ impl.socket_, impl.state_, bufs.buffers(), bufs.count(),
+ flags, sender_endpoint.data(), &addr_len, ec);
+
+ if (!ec)
+ sender_endpoint.resize(addr_len);
+
+ return bytes_recvd;
+ }
+
+ // Wait until data can be received without blocking.
+ size_t receive_from(implementation_type& impl, const null_buffers&,
+ endpoint_type& sender_endpoint, socket_base::message_flags,
+ boost::system::error_code& ec)
+ {
+ // Wait for socket to become ready.
+ socket_ops::poll_read(impl.socket_, impl.state_, -1, ec);
+
+ // Reset endpoint since it can be given no sensible value at this time.
+ sender_endpoint = endpoint_type();
+
+ return 0;
+ }
+
+ // Start an asynchronous receive. The buffer for the data being received and
+ // the sender_endpoint object must both be valid for the lifetime of the
+ // asynchronous operation.
+ template <typename MutableBufferSequence,
+ typename Handler, typename IoExecutor>
+ void async_receive_from(implementation_type& impl,
+ const MutableBufferSequence& buffers, endpoint_type& sender_endpoint,
+ socket_base::message_flags flags, Handler& handler,
+ const IoExecutor& io_ex)
+ {
+ bool is_continuation =
+ boost_asio_handler_cont_helpers::is_continuation(handler);
+
+ // Allocate and construct an operation to wrap the handler.
+ typedef reactive_socket_recvfrom_op_ext_local<MutableBufferSequence,
+ endpoint_type, Handler, IoExecutor> op;
+ typename op::ptr p = { boost::asio::detail::addressof(handler),
+ op::ptr::allocate(handler), 0 };
+ int protocol = impl.protocol_.type();
+ p.p = new (p.v) op(success_ec_, impl.socket_, protocol, buffers,
+ sender_endpoint, flags, handler, io_ex);
+
+ BOOST_ASIO_HANDLER_CREATION((reactor_.context(), *p.p, "socket",
+ &impl, impl.socket_, "async_receive_from"));
+
+ start_op(impl,
+ (flags & socket_base::message_out_of_band)
+ ? reactor::except_op : reactor::read_op,
+ p.p, is_continuation, true, false);
+ p.v = p.p = 0;
+ }
+
+ // Wait until data can be received without blocking.
+ template <typename Handler, typename IoExecutor>
+ void async_receive_from(implementation_type& impl, const null_buffers&,
+ endpoint_type& sender_endpoint, socket_base::message_flags flags,
+ Handler& handler, const IoExecutor& io_ex)
+ {
+ bool is_continuation =
+ boost_asio_handler_cont_helpers::is_continuation(handler);
+
+ // Allocate and construct an operation to wrap the handler.
+ typedef reactive_null_buffers_op<Handler, IoExecutor> op;
+ typename op::ptr p = { boost::asio::detail::addressof(handler),
+ op::ptr::allocate(handler), 0 };
+ p.p = new (p.v) op(success_ec_, handler, io_ex);
+
+ BOOST_ASIO_HANDLER_CREATION((reactor_.context(), *p.p, "socket",
+ &impl, impl.socket_, "async_receive_from(null_buffers)"));
+
+ // Reset endpoint since it can be given no sensible value at this time.
+ sender_endpoint = endpoint_type();
+
+ start_op(impl,
+ (flags & socket_base::message_out_of_band)
+ ? reactor::except_op : reactor::read_op,
+ p.p, is_continuation, false, false);
+ p.v = p.p = 0;
+ }
+
+ // Accept a new connection.
+ template <typename Socket>
+ boost::system::error_code accept(implementation_type& impl,
+ Socket& peer, endpoint_type* peer_endpoint, boost::system::error_code& ec)
+ {
+ // We cannot accept a socket that is already open.
+ if (peer.is_open())
+ {
+ ec = boost::asio::error::already_open;
+ return ec;
+ }
+
+ std::size_t addr_len = peer_endpoint ? peer_endpoint->capacity() : 0;
+ socket_holder new_socket(socket_ops::sync_accept(impl.socket_,
+ impl.state_, peer_endpoint ? peer_endpoint->data() : 0,
+ peer_endpoint ? &addr_len : 0, ec));
+
+ // On success, assign new connection to peer socket object.
+ if (new_socket.get() != invalid_socket)
+ {
+ if (peer_endpoint)
+ peer_endpoint->resize(addr_len);
+ peer.assign(impl.protocol_, new_socket.get(), ec);
+ if (!ec)
+ new_socket.release();
+ }
+
+ return ec;
+ }
+
+ // Start an asynchronous accept. The peer and peer_endpoint objects must be
+ // valid until the accept's handler is invoked.
+ template <typename Socket, typename Handler, typename IoExecutor>
+ void async_accept(implementation_type& impl, Socket& peer,
+ endpoint_type* peer_endpoint, Handler& handler, const IoExecutor& io_ex)
+ {
+ bool is_continuation =
+ boost_asio_handler_cont_helpers::is_continuation(handler);
+
+ // Allocate and construct an operation to wrap the handler.
+ typedef reactive_socket_accept_op<Socket, Protocol, Handler, IoExecutor> op;
+ typename op::ptr p = { boost::asio::detail::addressof(handler),
+ op::ptr::allocate(handler), 0 };
+ p.p = new (p.v) op(success_ec_, impl.socket_, impl.state_, peer,
+ impl.protocol_, peer_endpoint, handler, io_ex);
+
+ BOOST_ASIO_HANDLER_CREATION((reactor_.context(), *p.p, "socket",
+ &impl, impl.socket_, "async_accept"));
+
+ start_accept_op(impl, p.p, is_continuation, peer.is_open());
+ p.v = p.p = 0;
+ }
+
+#if defined(BOOST_ASIO_HAS_MOVE)
+ // Start an asynchronous accept. The peer_endpoint object must be valid until
+ // the accept's handler is invoked.
+ template <typename PeerIoExecutor, typename Handler, typename IoExecutor>
+ void async_move_accept(implementation_type& impl,
+ const PeerIoExecutor& peer_io_ex, endpoint_type* peer_endpoint,
+ Handler& handler, const IoExecutor& io_ex)
+ {
+ bool is_continuation =
+ boost_asio_handler_cont_helpers::is_continuation(handler);
+
+ // Allocate and construct an operation to wrap the handler.
+ typedef reactive_socket_move_accept_op<Protocol,
+ PeerIoExecutor, Handler, IoExecutor> op;
+ typename op::ptr p = { boost::asio::detail::addressof(handler),
+ op::ptr::allocate(handler), 0 };
+ p.p = new (p.v) op(success_ec_, peer_io_ex, impl.socket_, impl.state_,
+ impl.protocol_, peer_endpoint, handler, io_ex);
+
+ BOOST_ASIO_HANDLER_CREATION((reactor_.context(), *p.p, "socket",
+ &impl, impl.socket_, "async_accept"));
+
+ start_accept_op(impl, p.p, is_continuation, false);
+ p.v = p.p = 0;
+ }
+#endif // defined(BOOST_ASIO_HAS_MOVE)
+
+ // Connect the socket to the specified endpoint.
+ boost::system::error_code connect(implementation_type& impl,
+ const endpoint_type& peer_endpoint, boost::system::error_code& ec)
+ {
+ socket_ops::sync_connect(impl.socket_,
+ peer_endpoint.data(), peer_endpoint.size(), ec);
+ return ec;
+ }
+
+ // Start an asynchronous connect.
+ template <typename Handler, typename IoExecutor>
+ void async_connect(implementation_type& impl,
+ const endpoint_type& peer_endpoint,
+ Handler& handler, const IoExecutor& io_ex)
+ {
+ bool is_continuation =
+ boost_asio_handler_cont_helpers::is_continuation(handler);
+
+ // Allocate and construct an operation to wrap the handler.
+ typedef reactive_socket_connect_op<Handler, IoExecutor> op;
+ typename op::ptr p = { boost::asio::detail::addressof(handler),
+ op::ptr::allocate(handler), 0 };
+ p.p = new (p.v) op(success_ec_, impl.socket_, handler, io_ex);
+
+ BOOST_ASIO_HANDLER_CREATION((reactor_.context(), *p.p, "socket",
+ &impl, impl.socket_, "async_connect"));
+
+ start_connect_op(impl, p.p, is_continuation,
+ peer_endpoint.data(), peer_endpoint.size());
+ p.v = p.p = 0;
+ }
+};
+
+} // namespace detail
+} // namespace asio
+} // namespace boost
+
+#include <boost/asio/detail/pop_options.hpp>
+
+#endif // !defined(BOOST_ASIO_HAS_IOCP)
+
+#endif // BOOST_ASIO_DETAIL_REACTIVE_SOCKET_SERVICE_EXT_LOCAL_HPP
diff --git a/implementation/helper/1.74/boost/asio/detail/reactor_op_ext.hpp b/implementation/helper/1.74/boost/asio/detail/reactor_op_ext.hpp
new file mode 100644
index 0000000..697cd9f
--- /dev/null
+++ b/implementation/helper/1.74/boost/asio/detail/reactor_op_ext.hpp
@@ -0,0 +1,43 @@
+//
+// detail/reactor_op_ext.hpp
+// ~~~~~~~~~~~~~~~~~~~~~~~~~
+//
+// Copyright (c) 2003-2019 Christopher M. Kohlhoff (chris at kohlhoff dot com)
+// Copyright (c) 2016-2019 Bayerische Motoren Werke Aktiengesellschaft (BMW AG)
+//
+// Distributed under the Boost Software License, Version 1.0. (See accompanying
+// file LICENSE_boost or copy at http://www.boost.org/LICENSE_1_0.txt)
+//
+
+#ifndef BOOST_ASIO_DETAIL_REACTOR_OP_EXT_HPP
+#define BOOST_ASIO_DETAIL_REACTOR_OP_EXT_HPP
+
+#if defined(_MSC_VER) && (_MSC_VER >= 1200)
+# pragma once
+#endif // defined(_MSC_VER) && (_MSC_VER >= 1200)
+
+#include <boost/asio/detail/reactor_op.hpp>
+
+namespace boost {
+namespace asio {
+namespace detail {
+
+class reactor_op_ext
+ : public reactor_op
+{
+public:
+ // The destination address
+ boost::asio::ip::address da_;
+
+ reactor_op_ext(const boost::system::error_code& success_ec,
+ perform_func_type perform_func, func_type complete_func)
+ : reactor_op(success_ec, perform_func, complete_func)
+ {
+ }
+};
+
+} // namespace detail
+} // namespace asio
+} // namespace boost
+
+#endif // BOOST_ASIO_DETAIL_REACTOR_OP_EXT_HPP
diff --git a/implementation/helper/1.74/boost/asio/detail/reactor_op_ext_local.hpp b/implementation/helper/1.74/boost/asio/detail/reactor_op_ext_local.hpp
new file mode 100644
index 0000000..3d9ae5f
--- /dev/null
+++ b/implementation/helper/1.74/boost/asio/detail/reactor_op_ext_local.hpp
@@ -0,0 +1,44 @@
+//
+// detail/reactor_op_ext_local.hpp
+// ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+//
+// Copyright (c) 2003-2019 Christopher M. Kohlhoff (chris at kohlhoff dot com)
+// Copyright (c) 2016-2019 Bayerische Motoren Werke Aktiengesellschaft (BMW AG)
+//
+// Distributed under the Boost Software License, Version 1.0. (See accompanying
+// file LICENSE_boost or copy at http://www.boost.org/LICENSE_1_0.txt)
+//
+
+#ifndef BOOST_ASIO_DETAIL_REACTOR_OP_EXT_LOCAL_HPP
+#define BOOST_ASIO_DETAIL_REACTOR_OP_EXT_LOCAL_HPP
+
+#if defined(_MSC_VER) && (_MSC_VER >= 1200)
+# pragma once
+#endif // defined(_MSC_VER) && (_MSC_VER >= 1200)
+
+#include <boost/asio/detail/reactor_op.hpp>
+
+namespace boost {
+namespace asio {
+namespace detail {
+
+class reactor_op_ext_local
+ : public reactor_op
+{
+public:
+ // Credentials
+ std::uint32_t uid_;
+ std::uint32_t gid_;
+
+ reactor_op_ext_local(const boost::system::error_code& success_ec,
+ perform_func_type perform_func, func_type complete_func)
+ : reactor_op(success_ec, perform_func, complete_func)
+ {
+ }
+};
+
+} // namespace detail
+} // namespace asio
+} // namespace boost
+
+#endif // BOOST_ASIO_DETAIL_REACTOR_OP_EXT_LOCAL_HPP
diff --git a/implementation/helper/1.74/boost/asio/detail/socket_ops_ext.hpp b/implementation/helper/1.74/boost/asio/detail/socket_ops_ext.hpp
new file mode 100644
index 0000000..9285fed
--- /dev/null
+++ b/implementation/helper/1.74/boost/asio/detail/socket_ops_ext.hpp
@@ -0,0 +1,62 @@
+//
+// detail/socket_ops_ext.hpp
+// ~~~~~~~~~~~~~~~~~~~~~~~~~
+//
+// Copyright (c) 2003-2018 Christopher M. Kohlhoff (chris at kohlhoff dot com)
+// Copyright (C) 2016-2019 Bayerische Motoren Werke Aktiengesellschaft (BMW AG)
+//
+// Distributed under the Boost Software License, Version 1.0. (See accompanying
+// file LICENSE_boost or copy at http://www.boost.org/LICENSE_1_0.txt)
+//
+
+#ifndef BOOST_ASIO_DETAIL_SOCKET_OPS_EXT_HPP
+#define BOOST_ASIO_DETAIL_SOCKET_OPS_EXT_HPP
+
+#if defined(_MSC_VER) && (_MSC_VER >= 1200)
+# pragma once
+#endif // defined(_MSC_VER) && (_MSC_VER >= 1200)
+
+#include <boost/asio/detail/socket_ops.hpp>
+
+namespace boost {
+namespace asio {
+namespace detail {
+namespace socket_ops {
+
+BOOST_ASIO_DECL signed_size_type recvfrom(socket_type s, buf* bufs,
+ size_t count, int flags, socket_addr_type* addr,
+ std::size_t* addrlen, boost::system::error_code& ec,
+ boost::asio::ip::address& da);
+
+BOOST_ASIO_DECL size_t sync_recvfrom(socket_type s, state_type state,
+ buf* bufs, size_t count, int flags, socket_addr_type* addr,
+ std::size_t* addrlen, boost::system::error_code& ec, boost::asio::ip::address& da);
+
+#if defined(BOOST_ASIO_HAS_IOCP)
+
+BOOST_ASIO_DECL void complete_iocp_recvfrom(
+ const weak_cancel_token_type& cancel_token,
+ boost::system::error_code& ec,
+ boost::asio::ip::address& da);
+
+#else // defined(BOOST_ASIO_HAS_IOCP)
+
+BOOST_ASIO_DECL bool non_blocking_recvfrom(socket_type s,
+ buf* bufs, size_t count, int flags,
+ socket_addr_type* addr, std::size_t* addrlen,
+ boost::system::error_code& ec, size_t& bytes_transferred,
+ boost::asio::ip::address& da);
+
+#endif // defined(BOOST_ASIO_HAS_IOCP)
+
+} // namespace socket_ops
+} // namespace detail
+} // namespace asio
+} // namespace boost
+
+
+#if defined(BOOST_ASIO_HEADER_ONLY)
+# include <boost/asio/detail/impl/socket_ops_ext.ipp>
+#endif // defined(BOOST_ASIO_HEADER_ONLY)
+
+#endif // BOOST_EXT_ASIO_DETAIL_SOCKET_OPS_HPP
diff --git a/implementation/helper/1.74/boost/asio/detail/socket_ops_ext_local.hpp b/implementation/helper/1.74/boost/asio/detail/socket_ops_ext_local.hpp
new file mode 100644
index 0000000..a937bb6
--- /dev/null
+++ b/implementation/helper/1.74/boost/asio/detail/socket_ops_ext_local.hpp
@@ -0,0 +1,95 @@
+//
+// detail/socket_ops_ext_local.hpp
+// ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+//
+// Copyright (c) 2003-2018 Christopher M. Kohlhoff (chris at kohlhoff dot com)
+// Copyright (C) 2016-2019 Bayerische Motoren Werke Aktiengesellschaft (BMW AG)
+//
+// Distributed under the Boost Software License, Version 1.0. (See accompanying
+// file LICENSE_boost or copy at http://www.boost.org/LICENSE_1_0.txt)
+//
+
+#ifndef BOOST_ASIO_DETAIL_SOCKET_OPS_EXT_LOCAL_HPP
+#define BOOST_ASIO_DETAIL_SOCKET_OPS_EXT_LOCAL_HPP
+
+#if defined(_MSC_VER) && (_MSC_VER >= 1200)
+# pragma once
+#endif // defined(_MSC_VER) && (_MSC_VER >= 1200)
+
+#include <boost/asio/detail/config.hpp>
+
+#include <boost/system/error_code.hpp>
+#include <boost/asio/detail/memory.hpp>
+#include <boost/asio/detail/socket_types.hpp>
+
+#include <boost/asio/detail/push_options.hpp>
+
+namespace boost {
+namespace asio {
+namespace detail {
+namespace socket_ops {
+
+BOOST_ASIO_DECL signed_size_type recv(socket_type s, buf* bufs,
+ size_t count, int flags, boost::system::error_code& ec,
+ std::uint32_t& uid, std::uint32_t& gid);
+
+BOOST_ASIO_DECL size_t sync_recv(socket_type s, state_type state, buf* bufs,
+ size_t count, int flags, bool all_empty, boost::system::error_code& ec,
+ std::uint32_t& uid, std::uint32_t& gid);
+
+#if defined(BOOST_ASIO_HAS_IOCP)
+
+BOOST_ASIO_DECL void complete_iocp_recv(state_type state,
+ const weak_cancel_token_type& cancel_token, bool all_empty,
+ boost::system::error_code& ec, size_t bytes_transferred,
+ std::uint32_t& uid, std::uint32_t& gid);
+
+#else // defined(BOOST_ASIO_HAS_IOCP)
+
+BOOST_ASIO_DECL bool non_blocking_recv(socket_type s,
+ buf* bufs, size_t count, int flags, bool is_stream,
+ boost::system::error_code& ec, size_t& bytes_transferred,
+ std::uint32_t& uid, std::uint32_t& gid);
+
+#endif // defined(BOOST_ASIO_HAS_IOCP)
+
+BOOST_ASIO_DECL signed_size_type recvfrom(socket_type s, buf* bufs,
+ size_t count, int flags, socket_addr_type* addr,
+ std::size_t* addrlen, boost::system::error_code& ec,
+ std::uint32_t& uid, std::uint32_t& gid);
+
+BOOST_ASIO_DECL size_t sync_recvfrom(socket_type s, state_type state,
+ buf* bufs, size_t count, int flags, socket_addr_type* addr,
+ std::size_t* addrlen, boost::system::error_code& ec,
+ std::uint32_t& uid, std::uint32_t& gid);
+
+#if defined(BOOST_ASIO_HAS_IOCP)
+
+BOOST_ASIO_DECL void complete_iocp_recvfrom(
+ const weak_cancel_token_type& cancel_token,
+ boost::system::error_code& ec,
+ std::uint32_t& uid, std::uint32_t& gid);
+
+#else // defined(BOOST_ASIO_HAS_IOCP)
+
+BOOST_ASIO_DECL bool non_blocking_recvfrom(socket_type s,
+ buf* bufs, size_t count, int flags,
+ socket_addr_type* addr, std::size_t* addrlen,
+ boost::system::error_code& ec, size_t& bytes_transferred,
+ std::uint32_t& uid, std::uint32_t& gid);
+
+#endif // defined(BOOST_ASIO_HAS_IOCP)
+
+
+} // namespace socket_ops
+} // namespace detail
+} // namespace asio
+} // namespace boost
+
+#include <boost/asio/detail/pop_options.hpp>
+
+#if defined(BOOST_ASIO_HEADER_ONLY)
+# include <boost/asio/detail/impl/socket_ops_ext_local.ipp>
+#endif // defined(BOOST_ASIO_HEADER_ONLY)
+
+#endif // BOOST_ASIO_DETAIL_SOCKET_OPS_EXT_LOCAL_HPP
diff --git a/implementation/helper/1.74/boost/asio/ip/udp_ext.hpp b/implementation/helper/1.74/boost/asio/ip/udp_ext.hpp
new file mode 100644
index 0000000..6ce2ac4
--- /dev/null
+++ b/implementation/helper/1.74/boost/asio/ip/udp_ext.hpp
@@ -0,0 +1,115 @@
+//
+// ip/udp_ext.hpp
+// ~~~~~~~~~~~~~~
+//
+// Copyright (c) 2003-2017 Christopher M. Kohlhoff (chris at kohlhoff dot com)
+// Copyright (C) 2016-2018 Bayerische Motoren Werke Aktiengesellschaft (BMW AG)
+//
+// Distributed under the Boost Software License, Version 1.0. (See accompanying
+// file LICENSE_boost or copy at http://www.boost.org/LICENSE_1_0.txt)
+//
+
+#ifndef BOOST_ASIO_IP_UDP_EXT_HPP
+#define BOOST_ASIO_IP_UDP_EXT_HPP
+
+#if defined(_MSC_VER) && (_MSC_VER >= 1200)
+# pragma once
+#endif // defined(_MSC_VER) && (_MSC_VER >= 1200)
+
+#include <boost/asio/detail/config.hpp>
+#include <boost/asio/basic_datagram_socket_ext.hpp>
+#include <boost/asio/detail/socket_types.hpp>
+#include <boost/asio/ip/basic_endpoint.hpp>
+#include <boost/asio/ip/basic_resolver.hpp>
+#include <boost/asio/ip/basic_resolver_iterator.hpp>
+#include <boost/asio/ip/basic_resolver_query.hpp>
+#include <boost/asio/ip/udp.hpp>
+
+#include <boost/asio/detail/push_options.hpp>
+
+namespace boost {
+namespace asio {
+namespace ip {
+
+/// Encapsulates the flags needed for UDP.
+/**
+ * The boost::asio::ip::udp_ext class contains flags necessary for UDP sockets.
+ *
+ * @par Thread Safety
+ * @e Distinct @e objects: Safe.@n
+ * @e Shared @e objects: Safe.
+ *
+ * @par Concepts:
+ * Protocol, InternetProtocol.
+ */
+class udp_ext
+{
+public:
+ /// The type of a UDP endpoint.
+ typedef basic_endpoint<udp> endpoint;
+
+ /// Construct to represent the IPv4 UDP protocol.
+ static udp_ext v4()
+ {
+ return udp_ext(BOOST_ASIO_OS_DEF(AF_INET));
+ }
+
+ /// Construct to represent the IPv6 UDP protocol.
+ static udp_ext v6()
+ {
+ return udp_ext(BOOST_ASIO_OS_DEF(AF_INET6));
+ }
+
+ /// Obtain an identifier for the type of the protocol.
+ int type() const
+ {
+ return BOOST_ASIO_OS_DEF(SOCK_DGRAM);
+ }
+
+ /// Obtain an identifier for the protocol.
+ int protocol() const
+ {
+ return BOOST_ASIO_OS_DEF(IPPROTO_UDP);
+ }
+
+ /// Obtain an identifier for the protocol family.
+ int family() const
+ {
+ return family_;
+ }
+
+ /// The UDP socket type.
+ typedef basic_datagram_socket_ext<udp> socket;
+
+ /// The UDP resolver type.
+ typedef basic_resolver<udp> resolver;
+
+ /// Compare two protocols for equality.
+ friend bool operator==(const udp_ext& p1, const udp_ext& p2)
+ {
+ return p1.family_ == p2.family_;
+ }
+
+ /// Compare two protocols for inequality.
+ friend bool operator!=(const udp_ext& p1, const udp_ext& p2)
+ {
+ return p1.family_ != p2.family_;
+ }
+
+private:
+ // Construct with a specific family.
+ explicit udp_ext(int protocol_family)
+ : family_(protocol_family)
+ {
+ }
+
+ int family_;
+};
+
+} // namespace ip
+} // namespace asio
+} // namespace boost
+
+#include <boost/asio/detail/pop_options.hpp>
+
+#endif // BOOST_ASIO_IP_UDP_EXT_HPP
diff --git a/implementation/helper/1.74/boost/asio/local/stream_protocol_ext.hpp b/implementation/helper/1.74/boost/asio/local/stream_protocol_ext.hpp
new file mode 100644
index 0000000..7c57c62
--- /dev/null
+++ b/implementation/helper/1.74/boost/asio/local/stream_protocol_ext.hpp
@@ -0,0 +1,93 @@
+//
+// local/stream_protocol_ext.hpp
+// ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+//
+// Copyright (c) 2003-2019 Christopher M. Kohlhoff (chris at kohlhoff dot com)
+// Copyright (c) 2019 Bayerische Motoren Werke Aktiengesellschaft (BMW AG)
+//
+// Distributed under the Boost Software License, Version 1.0. (See accompanying
+// file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt)
+//
+
+#ifndef BOOST_ASIO_LOCAL_STREAM_PROTOCOL_EXT_HPP
+#define BOOST_ASIO_LOCAL_STREAM_PROTOCOL_EXT_HPP
+
+#if defined(_MSC_VER) && (_MSC_VER >= 1200)
+# pragma once
+#endif // defined(_MSC_VER) && (_MSC_VER >= 1200)
+
+#include <boost/asio/detail/config.hpp>
+
+#if defined(BOOST_ASIO_HAS_LOCAL_SOCKETS) \
+ || defined(GENERATING_DOCUMENTATION)
+
+#include <boost/asio/basic_socket_acceptor_ext.hpp>
+#include <boost/asio/basic_socket_iostream.hpp>
+#include <boost/asio/basic_stream_socket_ext.hpp>
+#include <boost/asio/detail/socket_types.hpp>
+#include <boost/asio/local/basic_endpoint.hpp>
+
+#include <boost/asio/detail/push_options.hpp>
+
+namespace boost {
+namespace asio {
+namespace local {
+
+/// Encapsulates the flags needed for stream-oriented UNIX sockets.
+/**
+ * The boost::asio::local::stream_protocol class contains flags necessary for
+ * stream-oriented UNIX domain sockets.
+ *
+ * @par Thread Safety
+ * @e Distinct @e objects: Safe.@n
+ * @e Shared @e objects: Safe.
+ *
+ * @par Concepts:
+ * Protocol.
+ */
+class stream_protocol_ext
+{
+public:
+ /// Obtain an identifier for the type of the protocol.
+ int type() const
+ {
+ return SOCK_STREAM;
+ }
+
+ /// Obtain an identifier for the protocol.
+ int protocol() const
+ {
+ return 0;
+ }
+
+ /// Obtain an identifier for the protocol family.
+ int family() const
+ {
+ return AF_UNIX;
+ }
+
+ /// The type of a UNIX domain endpoint.
+ typedef basic_endpoint<stream_protocol_ext> endpoint;
+
+ /// The UNIX domain socket type.
+ typedef basic_stream_socket_ext<stream_protocol_ext> socket;
+
+ /// The UNIX domain acceptor type.
+ typedef basic_socket_acceptor_ext<stream_protocol_ext> acceptor;
+
+#if !defined(BOOST_ASIO_NO_IOSTREAM)
+ /// The UNIX domain iostream type.
+ typedef basic_socket_iostream<stream_protocol_ext> iostream;
+#endif // !defined(BOOST_ASIO_NO_IOSTREAM)
+};
+
+} // namespace local
+} // namespace asio
+} // namespace boost
+
+#include <boost/asio/detail/pop_options.hpp>
+
+#endif // defined(BOOST_ASIO_HAS_LOCAL_SOCKETS)
+ // || defined(GENERATING_DOCUMENTATION)
+
+#endif // BOOST_ASIO_LOCAL_STREAM_PROTOCOL_EXT_HPP
diff --git a/implementation/routing/include/routing_manager_impl.hpp b/implementation/routing/include/routing_manager_impl.hpp
index 767d60e..b5f0ea0 100644
--- a/implementation/routing/include/routing_manager_impl.hpp
+++ b/implementation/routing/include/routing_manager_impl.hpp
@@ -168,6 +168,7 @@ public:
void on_subscribe_ack_with_multicast(
service_t _service, instance_t _instance,
+ const boost::asio::ip::address &_sender,
const boost::asio::ip::address &_address, uint16_t _port);
void on_unsubscribe_ack(client_t _client, service_t _service,
instance_t _instance, eventgroup_t _eventgroup,
@@ -282,15 +283,18 @@ public:
bool _reliable);
void on_resend_provided_events_response(pending_remote_offer_id_t _id);
- bool update_security_policy_configuration(uint32_t _uid, uint32_t _gid, const std::shared_ptr<policy>& _policy,
- const std::shared_ptr<payload>& _payload, const security_update_handler_t& _handler);
- bool remove_security_policy_configuration(uint32_t _uid, uint32_t _gid, const security_update_handler_t& _handler);
client_t find_local_client(service_t _service, instance_t _instance);
- void on_security_update_response(pending_security_update_id_t _id, client_t _client);
std::set<client_t> find_local_clients(service_t _service, instance_t _instance);
bool is_subscribe_to_any_event_allowed(credentials_t _credentials, client_t _client,
service_t _service, instance_t _instance, eventgroup_t _eventgroup);
+ bool update_security_policy_configuration(uint32_t _uid, uint32_t _gid,
+ const std::shared_ptr<policy> &_policy,
+ const std::shared_ptr<payload> &_payload,
+ const security_update_handler_t &_handler);
+ bool remove_security_policy_configuration(uint32_t _uid, uint32_t _gid,
+ const security_update_handler_t &_handler);
+
private:
bool offer_service(client_t _client,
service_t _service, instance_t _instance,
@@ -400,29 +404,16 @@ private:
std::pair<service_t, instance_t> pending_remote_offer_remove(
pending_remote_offer_id_t _id);
- void on_security_update_timeout(
- const boost::system::error_code& _error,
- pending_security_update_id_t _id,
- std::shared_ptr<boost::asio::steady_timer> _timer);
-
- pending_security_update_id_t pending_security_update_add(
- const std::unordered_set<client_t>& _clients);
-
- std::unordered_set<client_t> pending_security_update_get(
- pending_security_update_id_t _id);
-
- bool pending_security_update_remove(
- pending_security_update_id_t _id, client_t _client);
-
- bool is_pending_security_update_finished(
- pending_security_update_id_t _id);
-
bool insert_offer_command(service_t _service, instance_t _instance, uint8_t _command,
client_t _client, major_version_t _major, minor_version_t _minor);
bool erase_offer_command(service_t _service, instance_t _instance);
bool is_last_stop_callback(const uint32_t _callback_id);
+ bool insert_event_statistics(service_t _service, instance_t _instance,
+ method_t _method, length_t _length);
+ void statistics_log_timer_cbk(boost::system::error_code const & _error);
+
private:
std::shared_ptr<routing_manager_stub> stub_;
std::shared_ptr<sd::service_discovery> discovery_;
@@ -488,21 +479,20 @@ private:
std::mutex last_resume_mutex_;
std::chrono::steady_clock::time_point last_resume_;
- std::mutex pending_security_updates_mutex_;
- pending_security_update_id_t pending_security_update_id_;
- std::map<pending_security_update_id_t, std::unordered_set<client_t>> pending_security_updates_;
-
- std::recursive_mutex security_update_handlers_mutex_;
- std::map<pending_security_update_id_t, security_update_handler_t> security_update_handlers_;
-
- std::mutex security_update_timers_mutex_;
- std::map<pending_security_update_id_t, std::shared_ptr<boost::asio::steady_timer>> security_update_timers_;
-
std::mutex offer_serialization_mutex_;
std::map<std::pair<service_t, instance_t>, std::deque<std::tuple<uint8_t, client_t, major_version_t, minor_version_t>>> offer_commands_;
std::mutex callback_counts_mutex_;
std::map<uint32_t, uint16_t> callback_counts_;
+
+ std::mutex statistics_log_timer_mutex_;
+ boost::asio::steady_timer statistics_log_timer_;
+
+ std::mutex message_statistics_mutex_;
+ std::map<std::tuple<service_t, instance_t, method_t>,
+ msg_statistic_t> message_statistics_;
+ std::tuple<service_t, instance_t, method_t> message_to_discard_;
+ uint32_t ignored_statistics_counter_;
};
} // namespace vsomeip_v3
diff --git a/implementation/routing/include/routing_manager_proxy.hpp b/implementation/routing/include/routing_manager_proxy.hpp
index 346e733..fd546a0 100644
--- a/implementation/routing/include/routing_manager_proxy.hpp
+++ b/implementation/routing/include/routing_manager_proxy.hpp
@@ -256,6 +256,8 @@ private:
const bool client_side_logging_;
const std::set<std::tuple<service_t, instance_t> > client_side_logging_filter_;
+
+ std::mutex stop_mutex_;
};
} // namespace vsomeip_v3
diff --git a/implementation/routing/include/routing_manager_stub.hpp b/implementation/routing/include/routing_manager_stub.hpp
index 4a37644..4c2ff01 100644
--- a/implementation/routing/include/routing_manager_stub.hpp
+++ b/implementation/routing/include/routing_manager_stub.hpp
@@ -19,6 +19,8 @@
#include <boost/asio/io_service.hpp>
#include <boost/asio/steady_timer.hpp>
+#include <vsomeip/handler.hpp>
+
#include "../../endpoints/include/endpoint_host.hpp"
#include "../include/routing_host.hpp"
@@ -27,6 +29,7 @@
namespace vsomeip_v3 {
class configuration;
+struct policy;
class routing_manager_stub_host;
class routing_manager_stub: public routing_host,
@@ -87,19 +90,31 @@ public:
bool send_provided_event_resend_request(client_t _client,
pending_remote_offer_id_t _id);
- bool is_policy_cached(uint32_t _uid);
+ bool update_security_policy_configuration(uint32_t _uid, uint32_t _gid,
+ const std::shared_ptr<policy> &_policy,
+ const std::shared_ptr<payload> &_payload,
+ const security_update_handler_t &_handler);
+ bool remove_security_policy_configuration(uint32_t _uid, uint32_t _gid,
+ const security_update_handler_t &_handler);
+ void on_security_update_response(pending_security_update_id_t _id,
+ client_t _client);
void policy_cache_add(uint32_t _uid, const std::shared_ptr<payload>& _payload);
-
void policy_cache_remove(uint32_t _uid);
+ bool is_policy_cached(uint32_t _uid);
- bool send_update_security_policy_request(client_t _client, pending_security_update_id_t _update_id,
- uint32_t _uid, const std::shared_ptr<payload>& _payload);
- bool send_remove_security_policy_request(client_t _client, pending_security_update_id_t _update_id,
- uint32_t _uid, uint32_t _gid);
+ bool send_update_security_policy_request(client_t _client,
+ pending_security_update_id_t _update_id, uint32_t _uid,
+ const std::shared_ptr<payload>& _payload);
+ bool send_remove_security_policy_request(client_t _client,
+ pending_security_update_id_t _update_id, uint32_t _uid, uint32_t _gid);
bool send_cached_security_policies(client_t _client);
+ bool add_requester_policies(uid_t _uid, gid_t _gid,
+ const std::set<std::shared_ptr<policy> > &_policies);
+ void remove_requester_policies(uid_t _uid, gid_t _gid);
+
private:
void broadcast(const std::vector<byte_t> &_command) const;
@@ -150,6 +165,34 @@ private:
void on_client_id_timer_expired(boost::system::error_code const &_error);
+ void get_requester_policies(uid_t _uid, gid_t _gid,
+ std::set<std::shared_ptr<policy> > &_policies) const;
+ bool send_requester_policies(const std::unordered_set<client_t> &_clients,
+ const std::set<std::shared_ptr<policy> > &_policies);
+
+ void on_security_update_timeout(
+ const boost::system::error_code &_error,
+ pending_security_update_id_t _id,
+ std::shared_ptr<boost::asio::steady_timer> _timer);
+
+ pending_security_update_id_t pending_security_update_add(
+ const std::unordered_set<client_t> &_clients);
+
+ std::unordered_set<client_t> pending_security_update_get(
+ pending_security_update_id_t _id);
+
+ bool pending_security_update_remove(
+ pending_security_update_id_t _id, client_t _client);
+
+ bool is_pending_security_update_finished(
+ pending_security_update_id_t _id);
+
+ void add_pending_security_update_handler(
+ pending_security_update_id_t _id,
+ security_update_handler_t _handler);
+ void add_pending_security_update_timer(
+ pending_security_update_id_t _id);
+
private:
routing_manager_stub_host *host_;
boost::asio::io_service &io_;
@@ -190,10 +233,25 @@ private:
std::map<client_t, std::vector<byte_t>> offered_services_info_;
std::map<client_t, std::vector<byte_t>> client_credentials_info_;
+ std::mutex pending_security_updates_mutex_;
+ pending_security_update_id_t pending_security_update_id_;
+ std::map<pending_security_update_id_t, std::unordered_set<client_t>> pending_security_updates_;
+
+ std::recursive_mutex security_update_handlers_mutex_;
+ std::map<pending_security_update_id_t, security_update_handler_t> security_update_handlers_;
+
+ std::mutex security_update_timers_mutex_;
+ std::map<pending_security_update_id_t, std::shared_ptr<boost::asio::steady_timer>> security_update_timers_;
std::mutex updated_security_policies_mutex_;
std::map<uint32_t, std::shared_ptr<payload>> updated_security_policies_;
+ mutable std::mutex requester_policies_mutex_;
+ std::map<uint32_t,
+ std::map<uint32_t,
+ std::set<std::shared_ptr<policy> >
+ >
+ > requester_policies_;
};
} // namespace vsomeip_v3
diff --git a/implementation/routing/include/routing_manager_stub_host.hpp b/implementation/routing/include/routing_manager_stub_host.hpp
index b89134d..4707948 100644
--- a/implementation/routing/include/routing_manager_stub_host.hpp
+++ b/implementation/routing/include/routing_manager_stub_host.hpp
@@ -7,8 +7,8 @@
#define VSOMEIP_V3_ROUTING_MANAGER_STUB_HOST_
#include <boost/asio/io_service.hpp>
-#include <vsomeip/handler.hpp>
+#include <vsomeip/handler.hpp>
#include "types.hpp"
namespace vsomeip_v3 {
@@ -97,8 +97,6 @@ public:
virtual void on_resend_provided_events_response(pending_remote_offer_id_t _id) = 0;
- virtual void on_security_update_response(pending_security_update_id_t _id, client_t _client) = 0;
-
virtual client_t find_local_client(service_t _service, instance_t _instance) = 0;
virtual std::set<client_t> find_local_clients(service_t _service, instance_t _instance) = 0;
diff --git a/implementation/routing/include/types.hpp b/implementation/routing/include/types.hpp
index 389b226..c301b33 100644
--- a/implementation/routing/include/types.hpp
+++ b/implementation/routing/include/types.hpp
@@ -50,6 +50,11 @@ enum class remote_subscription_state_e : std::uint8_t {
typedef std::uint16_t remote_subscription_id_t;
typedef std::uint32_t pending_remote_offer_id_t;
+struct msg_statistic_t {
+ uint32_t counter_;
+ length_t avg_length_;
+};
+
}
// namespace vsomeip_v3
diff --git a/implementation/routing/src/routing_manager_base.cpp b/implementation/routing/src/routing_manager_base.cpp
index 5b1149e..e187d93 100644
--- a/implementation/routing/src/routing_manager_base.cpp
+++ b/implementation/routing/src/routing_manager_base.cpp
@@ -176,7 +176,10 @@ void routing_manager_base::release_service(client_t _client,
if (found_service != local_services_history_.end()) {
auto found_instance = found_service->second.find(_instance);
if (found_instance != found_service->second.end()) {
- local_services_history_.erase(_service);
+ found_service->second.erase(_instance);
+ if (found_service->second.empty()) {
+ local_services_history_.erase(_service);
+ }
}
}
}
@@ -1136,10 +1139,11 @@ bool routing_manager_base::send_local_notification(client_t _client,
_data[VSOMEIP_METHOD_POS_MAX]);
service_t its_service = VSOMEIP_BYTES_TO_WORD(
_data[VSOMEIP_SERVICE_POS_MIN], _data[VSOMEIP_SERVICE_POS_MAX]);
+
std::shared_ptr<event> its_event = find_event(its_service, _instance, its_method);
if (its_event && !its_event->is_shadow()) {
-
for (auto its_client : its_event->get_subscribers()) {
+
// local
if (its_client == VSOMEIP_ROUTING_CLIENT) {
has_remote = true;
@@ -1150,6 +1154,7 @@ bool routing_manager_base::send_local_notification(client_t _client,
has_local = true;
}
#endif
+
std::shared_ptr<endpoint> its_local_target = ep_mgr_->find_local(its_client);
if (its_local_target) {
send_local(its_local_target, _client, _data, _size,
diff --git a/implementation/routing/src/routing_manager_impl.cpp b/implementation/routing/src/routing_manager_impl.cpp
index f141c57..74e556c 100644
--- a/implementation/routing/src/routing_manager_impl.cpp
+++ b/implementation/routing/src/routing_manager_impl.cpp
@@ -83,7 +83,8 @@ routing_manager_impl::routing_manager_impl(routing_manager_host *_host) :
ep_mgr_impl_(std::make_shared<endpoint_manager_impl>(this, io_, configuration_)),
pending_remote_offer_id_(0),
last_resume_(std::chrono::steady_clock::now().min()),
- pending_security_update_id_(0)
+ statistics_log_timer_(_host->get_io()),
+ ignored_statistics_counter_(0)
{
}
@@ -212,6 +213,15 @@ void routing_manager_impl::start() {
std::bind(&routing_manager_impl::status_log_timer_cbk, this,
std::placeholders::_1));
}
+
+ if (configuration_->log_statistics()) {
+ std::lock_guard<std::mutex> its_lock(statistics_log_timer_mutex_);
+ boost::system::error_code ec;
+ statistics_log_timer_.expires_from_now(std::chrono::seconds(0), ec);
+ statistics_log_timer_.async_wait(
+ std::bind(&routing_manager_impl::statistics_log_timer_cbk, this,
+ std::placeholders::_1));
+ }
}
void routing_manager_impl::stop() {
@@ -255,13 +265,20 @@ void routing_manager_impl::stop() {
boost::system::error_code ec;
status_log_timer_.cancel(ec);
}
+
+ {
+ std::lock_guard<std::mutex> its_lock(statistics_log_timer_mutex_);
+ boost::system::error_code ec;
+ statistics_log_timer_.cancel(ec);
+ }
+
host_->on_state(state_type_e::ST_DEREGISTERED);
if (discovery_)
discovery_->stop();
stub_->stop();
- for (auto client: ep_mgr_->get_connected_clients()) {
+ for (const auto client : ep_mgr_->get_connected_clients()) {
if (client != VSOMEIP_ROUTING_CLIENT) {
remove_local(client, true);
}
@@ -396,11 +413,14 @@ bool routing_manager_impl::offer_service(client_t _client,
&& ps.major_ == _major) {
insert_subscription(ps.service_, ps.instance_,
ps.eventgroup_, ps.event_, client_, &its_already_subscribed_events);
+#if 0
VSOMEIP_ERROR << __func__
<< ": event="
<< std::hex << ps.service_ << "."
<< std::hex << ps.instance_ << "."
- << std::hex << ps.event_; }
+ << std::hex << ps.event_;
+#endif
+ }
}
send_pending_subscriptions(_service, _instance, _major);
@@ -784,7 +804,8 @@ bool routing_manager_impl::send(client_t _client, const byte_t *_data,
// TODO: Find out how to handle session id here
is_sent = deliver_message(_data, _size, _instance, _reliable, VSOMEIP_ROUTING_CLIENT, _credentials, _status_check);
} else {
- e2e_buffer outputBuffer;
+ e2e_buffer its_buffer;
+
if (e2e_provider_) {
if ( !is_service_discovery) {
service_t its_service = VSOMEIP_BYTES_TO_WORD(
@@ -793,12 +814,18 @@ bool routing_manager_impl::send(client_t _client, const byte_t *_data,
_data[VSOMEIP_METHOD_POS_MIN], _data[VSOMEIP_METHOD_POS_MAX]);
#ifndef ANDROID
if (e2e_provider_->is_protected({its_service, its_method})) {
- outputBuffer.assign(_data, _data + VSOMEIP_PAYLOAD_POS);
- e2e_buffer inputBuffer(_data + VSOMEIP_PAYLOAD_POS, _data +_size);
- e2e_provider_->protect({its_service, its_method}, inputBuffer);
- outputBuffer.resize(inputBuffer.size() + VSOMEIP_PAYLOAD_POS);
- std::copy(inputBuffer.begin(), inputBuffer.end(), outputBuffer.begin() + VSOMEIP_PAYLOAD_POS);
- _data = outputBuffer.data();
+ // Find out where the protected area starts
+ size_t its_base = e2e_provider_->get_protection_base({its_service, its_method});
+
+ // Build a corresponding buffer
+ its_buffer.assign(_data + its_base, _data + _size);
+
+ e2e_provider_->protect({ its_service, its_method }, its_buffer, _instance);
+
+ // Prepend header
+ its_buffer.insert(its_buffer.begin(), _data, _data + its_base);
+
+ _data = its_buffer.data();
}
#endif
}
@@ -979,7 +1006,7 @@ bool routing_manager_impl::send_to(
if (its_serializer->serialize(_message.get())) {
const byte_t *its_data = its_serializer->get_data();
length_t its_size = its_serializer->get_size();
- e2e_buffer its_output_buffer;
+ e2e_buffer its_buffer;
if (e2e_provider_) {
service_t its_service = VSOMEIP_BYTES_TO_WORD(
its_data[VSOMEIP_SERVICE_POS_MIN],
@@ -988,14 +1015,12 @@ bool routing_manager_impl::send_to(
its_data[VSOMEIP_METHOD_POS_MIN],
its_data[VSOMEIP_METHOD_POS_MAX]);
#ifndef ANDROID
- if(e2e_provider_->is_protected({its_service, its_method})) {
- its_output_buffer.assign(its_data, its_data + VSOMEIP_PAYLOAD_POS);
- e2e_buffer its_input_buffer(its_data + VSOMEIP_PAYLOAD_POS, its_data + its_size);
- e2e_provider_->protect({its_service, its_method}, its_input_buffer);
- its_output_buffer.resize(its_input_buffer.size() + VSOMEIP_PAYLOAD_POS);
- std::copy(its_input_buffer.begin(), its_input_buffer.end(),
- its_output_buffer.begin() + VSOMEIP_PAYLOAD_POS);
- its_data = its_output_buffer.data();
+ if (e2e_provider_->is_protected({its_service, its_method})) {
+ auto its_base = e2e_provider_->get_protection_base({its_service, its_method});
+ its_buffer.assign(its_data + its_base, its_data + its_size);
+ e2e_provider_->protect({its_service, its_method}, its_buffer, _message->get_instance());
+ its_buffer.insert(its_buffer.begin(), its_data, its_data + its_base);
+ its_data = its_buffer.data();
}
#endif
}
@@ -1326,7 +1351,11 @@ void routing_manager_impl::on_message(const byte_t *_data, length_t _size,
}
}
} else {
- its_instance = ep_mgr_impl_->find_instance(its_service, _receiver);
+ if(_destination.is_multicast()) {
+ its_instance = ep_mgr_impl_->find_instance_multicast(its_service, _remote_address);
+ } else {
+ its_instance = ep_mgr_impl_->find_instance(its_service, _receiver);
+ }
if (its_instance == 0xFFFF) {
its_method = VSOMEIP_BYTES_TO_WORD(
_data[VSOMEIP_METHOD_POS_MIN],
@@ -1403,17 +1432,19 @@ void routing_manager_impl::on_message(const byte_t *_data, length_t _size,
_data[VSOMEIP_METHOD_POS_MIN],
_data[VSOMEIP_METHOD_POS_MAX]);
#ifndef ANDROID
- if( e2e_provider_->is_checked({its_service, its_method})) {
- e2e_buffer inputBuffer(_data + VSOMEIP_PAYLOAD_POS, _data + _size);
- e2e_provider_->check({its_service, its_method}, inputBuffer, its_check_status);
-
- if ( its_check_status != e2e::profile_interface::generic_check_status::E2E_OK ) {
- VSOMEIP_INFO << std::hex << "E2E protection: CRC check failed for service: " << its_service << " method: " << its_method;
+ if (e2e_provider_->is_checked({its_service, its_method})) {
+ auto its_base = e2e_provider_->get_protection_base({its_service, its_method});
+ e2e_buffer its_buffer(_data + its_base, _data + _size);
+ e2e_provider_->check({its_service, its_method},
+ its_buffer, its_instance, its_check_status);
+
+ if (its_check_status != e2e::profile_interface::generic_check_status::E2E_OK) {
+ VSOMEIP_INFO << "E2E protection: CRC check failed for service: "
+ << std::hex << its_service << " method: " << its_method;
}
}
#endif
}
-
// Common way of message handling
#ifdef USE_DLT
is_forwarded =
@@ -1888,6 +1919,13 @@ bool routing_manager_impl::deliver_notification(
}
}
+ // incoming events statistics
+ (void) insert_event_statistics(
+ _service,
+ _instance,
+ its_event_id,
+ utility::get_payload_size(_data, _length));
+
if (its_event->get_type() != event_type_e::ET_SELECTIVE_EVENT) {
for (const auto its_local_client : its_event->get_subscribers()) {
if (its_local_client == host_->get_client()) {
@@ -2035,11 +2073,12 @@ void routing_manager_impl::init_service_info(
const bool is_someip = configuration_->is_someip(_service, _instance);
uint16_t its_reliable_port = configuration_->get_reliable_port(
_service, _instance);
+ bool _is_found(false);
if (ILLEGAL_PORT != its_reliable_port) {
std::shared_ptr<endpoint> its_reliable_endpoint =
ep_mgr_impl_->find_or_create_server_endpoint(
its_reliable_port, true, is_someip, _service,
- _instance);
+ _instance, _is_found);
if (its_reliable_endpoint) {
its_info->set_endpoint(its_reliable_endpoint, true);
}
@@ -2050,7 +2089,7 @@ void routing_manager_impl::init_service_info(
std::shared_ptr<endpoint> its_unreliable_endpoint =
ep_mgr_impl_->find_or_create_server_endpoint(
its_unreliable_port, false, is_someip, _service,
- _instance);
+ _instance, _is_found);
if (its_unreliable_endpoint) {
its_info->set_endpoint(its_unreliable_endpoint, false);
}
@@ -2570,10 +2609,15 @@ routing_manager_impl::expire_subscriptions(
// Note: get_remote_subscription delivers a copied
// set of subscriptions. Thus, its is possible to
// to remove them within the loop.
- const auto its_ep_definition =
- (_reliable) ? its_subscription->get_reliable() :
+ auto its_ep_definition = (_reliable) ?
+ its_subscription->get_reliable() :
its_subscription->get_unreliable();
+ if (!its_ep_definition && expire_all)
+ its_ep_definition = (!_reliable) ?
+ its_subscription->get_reliable() :
+ its_subscription->get_unreliable();
+
if (its_ep_definition
&& its_ep_definition->get_address() == _address
&& (expire_all ||
@@ -2583,7 +2627,7 @@ routing_manager_impl::expire_subscriptions(
// TODO: Check whether subscriptions to different hosts are valid.
// IF yes, we probably need to simply reset the corresponding
// endpoint instead of removing the subscription...
- VSOMEIP_ERROR << __func__
+ VSOMEIP_INFO << __func__
<< ": removing subscription to "
<< std::hex << its_info->get_service() << "."
<< std::hex << its_info->get_instance() << "."
@@ -2591,21 +2635,23 @@ routing_manager_impl::expire_subscriptions(
<< " from target "
<< its_ep_definition->get_address() << ":"
<< std::dec << its_ep_definition->get_port()
- << " reliable=" << _reliable;
+ << " reliable="
+ << std::boolalpha << its_ep_definition->is_reliable();
if (expire_all) {
- const auto its_ep_definition2 =
- (!_reliable) ? its_subscription->get_reliable() :
- its_subscription->get_unreliable();
- if (its_ep_definition2) {
- VSOMEIP_ERROR << __func__
+ its_ep_definition = (!its_ep_definition->is_reliable()) ?
+ its_subscription->get_reliable() :
+ its_subscription->get_unreliable();
+ if (its_ep_definition) {
+ VSOMEIP_INFO << __func__
<< ": removing subscription to "
<< std::hex << its_info->get_service() << "."
<< std::hex << its_info->get_instance() << "."
<< std::hex << its_info->get_eventgroup()
<< " from target "
- << its_ep_definition2->get_address() << ":"
- << std::dec << its_ep_definition2->get_port()
- << " reliable=" << !_reliable;
+ << its_ep_definition->get_address() << ":"
+ << std::dec << its_ep_definition->get_port()
+ << " reliable="
+ << std::boolalpha << its_ep_definition->is_reliable();
}
}
on_remote_unsubscribe(its_subscription);
@@ -2789,9 +2835,10 @@ void routing_manager_impl::on_remote_unsubscribe(
void routing_manager_impl::on_subscribe_ack_with_multicast(
service_t _service, instance_t _instance,
+ const boost::asio::ip::address &_sender,
const boost::asio::ip::address &_address, uint16_t _port) {
ep_mgr_impl_->find_or_create_multicast_endpoint(_service,
- _instance, _address, _port);
+ _instance, _sender, _address, _port);
}
void routing_manager_impl::on_subscribe_ack(client_t _client,
@@ -4164,307 +4211,6 @@ void routing_manager_impl::on_resend_provided_events_response(
}
}
-void routing_manager_impl::on_security_update_timeout(
- const boost::system::error_code& _error,
- pending_security_update_id_t _id,
- std::shared_ptr<boost::asio::steady_timer> _timer) {
- (void)_timer;
- if (_error) {
- // timer was cancelled
- return;
- }
- security_update_state_e its_state = security_update_state_e::SU_UNKNOWN_USER_ID;
- std::unordered_set<client_t> its_missing_clients = pending_security_update_get(_id);
- {
- // erase timer
- std::lock_guard<std::mutex> its_lock(security_update_timers_mutex_);
- security_update_timers_.erase(_id);
- }
- {
- // print missing responses and check if some clients did not respond because they already disconnected
- if (!its_missing_clients.empty()) {
- for (auto its_client : its_missing_clients) {
- VSOMEIP_INFO << __func__ << ": Client 0x" << std::hex << its_client
- << " did not respond to the policy update / removal with ID: 0x" << std::hex << _id;
- if (!find_local(its_client)) {
- VSOMEIP_INFO << __func__ << ": Client 0x" << std::hex << its_client
- << " is not connected anymore, do not expect answer for policy update / removal with ID: 0x"
- << std::hex << _id;
- pending_security_update_remove(_id, its_client);
- }
- }
- }
-
- its_missing_clients = pending_security_update_get(_id);
- if (its_missing_clients.empty()) {
- VSOMEIP_INFO << __func__ << ": Received all responses for "
- "security update/removal ID: 0x" << std::hex << _id;
- its_state = security_update_state_e::SU_SUCCESS;
- }
- {
- // erase pending security update
- std::lock_guard<std::mutex> its_lock(pending_security_updates_mutex_);
- pending_security_updates_.erase(_id);
- }
-
- // call handler with error on timeout or with SUCCESS if missing clients are not connected
- std::lock_guard<std::recursive_mutex> its_lock(security_update_handlers_mutex_);
- const auto found_handler = security_update_handlers_.find(_id);
- if (found_handler != security_update_handlers_.end()) {
- found_handler->second(its_state);
- security_update_handlers_.erase(found_handler);
- } else {
- VSOMEIP_WARNING << __func__ << ": Callback not found for security update / removal with ID: 0x"
- << std::hex << _id;
- }
- }
-}
-
-bool routing_manager_impl::update_security_policy_configuration(
- uint32_t _uid, uint32_t _gid,
- const std::shared_ptr<policy>& _policy,
- const std::shared_ptr<payload>& _payload,
- const security_update_handler_t& _handler) {
- bool ret(true);
- // cache security policy payload for later distribution to new registering clients
- stub_->policy_cache_add(_uid, _payload);
-
- // update security policy from configuration
- security::get()->update_security_policy(_uid, _gid, _policy);
-
- // determine currently connected clients
- std::unordered_set<client_t> its_clients_to_inform = ep_mgr_impl_->get_connected_clients();
-
- // add handler
- pending_security_update_id_t its_id;
- if (!its_clients_to_inform.empty()) {
- its_id = pending_security_update_add(its_clients_to_inform);
- {
- std::lock_guard<std::recursive_mutex> its_lock(security_update_handlers_mutex_);
- security_update_handlers_[its_id] = _handler;
- }
-
- {
- std::shared_ptr<boost::asio::steady_timer> its_timer =
- std::make_shared<boost::asio::steady_timer>(io_);
- boost::system::error_code ec;
- its_timer->expires_from_now(std::chrono::milliseconds(3000), ec);
- if (!ec) {
- its_timer->async_wait(
- std::bind(
- &routing_manager_impl::on_security_update_timeout,
- std::static_pointer_cast<routing_manager_impl>(
- shared_from_this()),
- std::placeholders::_1, its_id, its_timer));
- } else {
- VSOMEIP_ERROR << __func__ << ": timer creation: " << ec.message();
- }
- std::lock_guard<std::mutex> its_lock(security_update_timers_mutex_);
- security_update_timers_[its_id] = its_timer;
- }
-
- // trigger all currently connected clients to update the security policy
- uint32_t sent_counter(0);
- uint32_t its_tranche =
- uint32_t(its_clients_to_inform.size() >= 10 ? (its_clients_to_inform.size() / 10) : 1);
- VSOMEIP_INFO << __func__ << ": Informing [" << std::dec << its_clients_to_inform.size()
- << "] currently connected clients about policy update for UID: "
- << std::dec << _uid << " with update ID: 0x" << std::hex << its_id;
- for (auto its_client : its_clients_to_inform) {
- if (!stub_->send_update_security_policy_request(its_client, its_id, _uid, _payload)) {
- VSOMEIP_INFO << __func__ << ": Couldn't send update security policy "
- << "request to client 0x" << std::hex << std::setw(4)
- << std::setfill('0') << its_client << " policy UID: "
- << std::hex << std::setw(4) << std::setfill('0') << _uid << " GID: "
- << std::hex << std::setw(4) << std::setfill('0') << _gid
- << " with update ID: 0x" << std::hex << its_id
- << " as client already disconnected";
- // remove client from expected answer list
- pending_security_update_remove(its_id, its_client);
- }
- sent_counter++;
- // Prevent burst
- if (sent_counter % its_tranche == 0) {
- std::this_thread::sleep_for(std::chrono::milliseconds(10));
- }
- }
- } else {
- // if routing manager has no client call the handler directly
- _handler(security_update_state_e::SU_SUCCESS);
- }
- return ret;
-}
-
-bool routing_manager_impl::remove_security_policy_configuration(
- uint32_t _uid, uint32_t _gid, const security_update_handler_t& _handler) {
- bool ret(true);
-
- // remove security policy from configuration (only if there was a updateACL call before)
- if (stub_->is_policy_cached(_uid)) {
- if (!security::get()->remove_security_policy(_uid, _gid)) {
- _handler(security_update_state_e::SU_UNKNOWN_USER_ID);
- ret = false;
- } else {
- // remove policy from cache to prevent sending it to registering clients
- stub_->policy_cache_remove(_uid);
-
- // add handler
- pending_security_update_id_t its_id;
-
- // determine currently connected clients
- std::unordered_set<client_t> its_clients_to_inform = ep_mgr_impl_->get_connected_clients();
-
- if (!its_clients_to_inform.empty()) {
- its_id = pending_security_update_add(its_clients_to_inform);
- {
- std::lock_guard<std::recursive_mutex> its_lock(security_update_handlers_mutex_);
- security_update_handlers_[its_id] = _handler;
- }
-
- {
- std::shared_ptr<boost::asio::steady_timer> its_timer =
- std::make_shared<boost::asio::steady_timer>(io_);
- boost::system::error_code ec;
- its_timer->expires_from_now(std::chrono::milliseconds(3000), ec);
- if (!ec) {
- its_timer->async_wait(
- std::bind(
- &routing_manager_impl::on_security_update_timeout,
- std::static_pointer_cast<routing_manager_impl>(
- shared_from_this()),
- std::placeholders::_1, its_id, its_timer));
- } else {
- VSOMEIP_ERROR << __func__ << ": timer creation: " << ec.message();
- }
- std::lock_guard<std::mutex> its_lock(security_update_timers_mutex_);
- security_update_timers_[its_id] = its_timer;
- }
-
- // trigger all clients to remove the security policy
- uint32_t sent_counter(0);
- uint32_t its_tranche =
- uint32_t(its_clients_to_inform.size() >= 10 ? (its_clients_to_inform.size() / 10) : 1);
- VSOMEIP_INFO << __func__ << ": Informing [" << std::dec << its_clients_to_inform.size()
- << "] currently connected clients about policy removal for UID: "
- << std::dec << _uid << " with update ID: " << its_id;
- for (auto its_client : its_clients_to_inform) {
- if (!stub_->send_remove_security_policy_request(its_client, its_id, _uid, _gid)) {
- VSOMEIP_INFO << __func__ << ": Couldn't send remove security policy "
- << "request to client 0x" << std::hex << std::setw(4)
- << std::setfill('0') << its_client << " policy UID: "
- << std::hex << std::setw(4) << std::setfill('0') << _uid << " GID: "
- << std::hex << std::setw(4) << std::setfill('0') << _gid
- << " with update ID: 0x" << std::hex << its_id
- << " as client already disconnected";
- // remove client from expected answer list
- pending_security_update_remove(its_id, its_client);
- }
- sent_counter++;
- // Prevent burst
- if (sent_counter % its_tranche == 0) {
- std::this_thread::sleep_for(std::chrono::milliseconds(10));
- }
- }
- } else {
- // if routing manager has no client call the handler directly
- _handler(security_update_state_e::SU_SUCCESS);
- }
- }
- }
- else {
- _handler(security_update_state_e::SU_UNKNOWN_USER_ID);
- ret = false;
- }
- return ret;
-}
-
-pending_security_update_id_t routing_manager_impl::pending_security_update_add(
- const std::unordered_set<client_t>& _clients) {
- std::lock_guard<std::mutex> its_lock(pending_security_updates_mutex_);
- if (++pending_security_update_id_ == 0) {
- pending_security_update_id_++;
- }
- pending_security_updates_[pending_security_update_id_] = _clients;
- return pending_security_update_id_;
-}
-
-std::unordered_set<client_t> routing_manager_impl::pending_security_update_get(
- pending_security_update_id_t _id) {
- std::lock_guard<std::mutex> its_lock(pending_security_updates_mutex_);
- std::unordered_set<client_t> its_missing_clients;
- auto found_si = pending_security_updates_.find(_id);
- if (found_si != pending_security_updates_.end()) {
- its_missing_clients = pending_security_updates_[_id];
- }
- return its_missing_clients;
-}
-
-bool routing_manager_impl::pending_security_update_remove(
- pending_security_update_id_t _id, client_t _client) {
- std::lock_guard<std::mutex> its_lock(pending_security_updates_mutex_);
- auto found_si = pending_security_updates_.find(_id);
- if (found_si != pending_security_updates_.end()) {
- if (found_si->second.erase(_client)) {
- return true;
- }
- }
- return false;
-}
-
-bool routing_manager_impl::is_pending_security_update_finished(
- pending_security_update_id_t _id) {
- std::lock_guard<std::mutex> its_lock(pending_security_updates_mutex_);
- bool ret(false);
- auto found_si = pending_security_updates_.find(_id);
- if (found_si != pending_security_updates_.end()) {
- if (!found_si->second.size()) {
- ret = true;
- }
- }
- if (ret) {
- pending_security_updates_.erase(_id);
- }
- return ret;
-}
-
-void routing_manager_impl::on_security_update_response(
- pending_security_update_id_t _id, client_t _client) {
- if (pending_security_update_remove(_id, _client)) {
- if (is_pending_security_update_finished(_id)) {
- // cancel timeout timer
- {
- std::lock_guard<std::mutex> its_lock(security_update_timers_mutex_);
- auto found_timer = security_update_timers_.find(_id);
- if (found_timer != security_update_timers_.end()) {
- boost::system::error_code ec;
- found_timer->second->cancel(ec);
- security_update_timers_.erase(found_timer);
- } else {
- VSOMEIP_WARNING << __func__ << ": Received all responses "
- "for security update/removal ID: 0x"
- << std::hex << _id << " but timeout already happened";
- }
- }
-
- // call handler
- {
- std::lock_guard<std::recursive_mutex> its_lock(security_update_handlers_mutex_);
- auto found_handler = security_update_handlers_.find(_id);
- if (found_handler != security_update_handlers_.end()) {
- found_handler->second(security_update_state_e::SU_SUCCESS);
- security_update_handlers_.erase(found_handler);
- VSOMEIP_INFO << __func__ << ": Received all responses for "
- "security update/removal ID: 0x" << std::hex << _id;
- } else {
- VSOMEIP_WARNING << __func__ << ": Received all responses "
- "for security update/removal ID: 0x"
- << std::hex << _id << " but didn't find handler";
- }
- }
- }
- }
-}
-
void routing_manager_impl::print_stub_status() const {
stub_->print_endpoint_status();
}
@@ -4557,4 +4303,132 @@ routing_manager_impl::send_unsubscription(client_t _offering_client,
}
}
+bool
+routing_manager_impl::update_security_policy_configuration(
+ uint32_t _uid, uint32_t _gid,
+ const std::shared_ptr<policy> &_policy,
+ const std::shared_ptr<payload> &_payload,
+ const security_update_handler_t &_handler) {
+
+ if (stub_)
+ return stub_->update_security_policy_configuration(_uid, _gid,
+ _policy, _payload, _handler);
+
+ return (false);
+}
+
+bool
+routing_manager_impl::remove_security_policy_configuration(
+ uint32_t _uid, uint32_t _gid,
+ const security_update_handler_t &_handler) {
+
+ if (stub_)
+ return stub_->remove_security_policy_configuration(_uid, _gid,
+ _handler);
+
+ return (false);
+}
+
+bool routing_manager_impl::insert_event_statistics(service_t _service, instance_t _instance,
+ method_t _method, length_t _length) {
+
+ static uint32_t its_max_messages = configuration_->get_statistics_max_messages();
+ std::lock_guard<std::mutex> its_lock(message_statistics_mutex_);
+ const auto its_tuple = std::make_tuple(_service, _instance, _method);
+ const auto its_main_s = message_statistics_.find(its_tuple);
+ if (its_main_s != message_statistics_.end()) {
+ // increase counter and calculate moving avergae for payload length
+ its_main_s->second.avg_length_ =
+ (its_main_s->second.avg_length_ * its_main_s->second.counter_ + _length) /
+ (its_main_s->second.counter_ + 1);
+ its_main_s->second.counter_++;
+
+ if (its_tuple == message_to_discard_) {
+ // check list for entry with least counter value
+ uint32_t its_min_count(0xFFFFFFFF);
+ auto its_tuple_to_discard = std::make_tuple(0xFFFF, 0xFFFF, 0xFFFF);
+ for (const auto it : message_statistics_) {
+ if (it.second.counter_ < its_min_count) {
+ its_min_count = it.second.counter_;
+ its_tuple_to_discard = it.first;
+ }
+ }
+ if (its_min_count != 0xFFFF
+ && its_min_count < its_main_s->second.counter_) {
+ // update message to discard with current message
+ message_to_discard_ = its_tuple;
+ }
+ }
+ } else {
+ if (message_statistics_.size() < its_max_messages) {
+ message_statistics_[its_tuple] = {1, _length};
+ message_to_discard_ = its_tuple;
+ } else {
+ // no slot empty
+ const auto it = message_statistics_.find(message_to_discard_);
+ if (it != message_statistics_.end()
+ && it->second.counter_ == 1) {
+ message_statistics_.erase(message_to_discard_);
+ message_statistics_[its_tuple] = {1, _length};
+ message_to_discard_ = its_tuple;
+ } else {
+ // ignore message
+ ignored_statistics_counter_++;
+ return false;
+ }
+ }
+ }
+ return true;
+}
+
+void routing_manager_impl::statistics_log_timer_cbk(boost::system::error_code const & _error) {
+ if (!_error) {
+ static uint32_t its_interval = configuration_->get_statistics_interval();
+ its_interval = its_interval >= 1000 ? its_interval : 1000;
+ static uint32_t its_min_freq = configuration_->get_statistics_min_freq();
+ std::stringstream its_log;
+ {
+ std::lock_guard<std::mutex> its_lock(message_statistics_mutex_);
+ for (const auto s : message_statistics_) {
+ if (s.second.counter_ / (its_interval / 1000) >= its_min_freq) {
+ uint16_t its_subscribed(0);
+ std::shared_ptr<event> its_event = find_event(std::get<0>(s.first), std::get<1>(s.first), std::get<2>(s.first));
+ if (its_event) {
+ if (!its_event->is_provided()) {
+ its_subscribed = static_cast<std::uint16_t>(its_event->get_subscribers().size());
+ }
+ }
+ its_log << std::hex << std::setw(4) << std::setfill('0')
+ << std::get<0>(s.first) << "."
+ << std::get<1>(s.first) << "."
+ << std::get<2>(s.first) << ": #="
+ << std::dec << s.second.counter_ << " L="
+ << s.second.avg_length_ << " S="
+ << std::dec << its_subscribed << ", ";
+ }
+ }
+
+ if (ignored_statistics_counter_) {
+ its_log << std::dec << " #ignored: " << ignored_statistics_counter_;
+ }
+
+ message_statistics_.clear();
+ message_to_discard_ = std::make_tuple(0x00, 0x00, 0x00);
+ ignored_statistics_counter_ = 0;
+ }
+
+ if (its_log.str().length() > 0) {
+ VSOMEIP_INFO << "Received events statistics: [" << its_log.str() << "]";
+ }
+
+ {
+ std::lock_guard<std::mutex> its_lock(statistics_log_timer_mutex_);
+ statistics_log_timer_.expires_from_now(std::chrono::milliseconds(its_interval));
+ statistics_log_timer_.async_wait(
+ std::bind(&routing_manager_impl::statistics_log_timer_cbk,
+ this, std::placeholders::_1));
+ }
+ }
+}
+
} // namespace vsomeip_v3
diff --git a/implementation/routing/src/routing_manager_proxy.cpp b/implementation/routing/src/routing_manager_proxy.cpp
index 3b95a2d..410559b 100644
--- a/implementation/routing/src/routing_manager_proxy.cpp
+++ b/implementation/routing/src/routing_manager_proxy.cpp
@@ -125,7 +125,7 @@ void routing_manager_proxy::stop() {
sender_ = nullptr;
}
- for (auto client: ep_mgr_->get_connected_clients()) {
+ for (const auto client : ep_mgr_->get_connected_clients()) {
if (client != VSOMEIP_ROUTING_CLIENT) {
remove_local(client, true);
}
@@ -202,12 +202,17 @@ void routing_manager_proxy::stop_offer_service(client_t _client,
(void)_client;
- routing_manager_base::stop_offer_service(_client, _service, _instance, _major, _minor);
- clear_remote_subscriber_count(_service, _instance);
+ {
+ // Hold the mutex to ensure no placeholder event is created inbetween.
+ std::lock_guard<std::mutex> its_lock(stop_mutex_);
+
+ routing_manager_base::stop_offer_service(_client, _service, _instance, _major, _minor);
+ clear_remote_subscriber_count(_service, _instance);
- // Reliable/Unreliable unimportant as routing_proxy does not
- // create server endpoints which needs to be freed
- clear_service_info(_service, _instance, false);
+ // Note: The last argument does not matter here as a proxy
+ // does not manage endpoints to the external network.
+ clear_service_info(_service, _instance, false);
+ }
{
std::lock_guard<std::mutex> its_lock(state_mutex_);
@@ -876,6 +881,7 @@ void routing_manager_proxy::on_message(const byte_t *_data, length_t _size,
client_t its_subscriber;
remote_subscription_id_t its_subscription_id(PENDING_SUBSCRIPTION_ID);
std::uint32_t its_remote_subscriber_count(0);
+ bool is_internal_policy_update(false);
std::uint32_t its_sender_uid = std::get<0>(_credentials);
std::uint32_t its_sender_gid = std::get<1>(_credentials);
@@ -1389,6 +1395,9 @@ void routing_manager_proxy::on_message(const byte_t *_data, length_t _size,
<< its_client << ")";
break;
}
+ case VSOMEIP_UPDATE_SECURITY_POLICY_INT:
+ is_internal_policy_update = true;
+ /* Fallthrough */
case VSOMEIP_UPDATE_SECURITY_POLICY: {
if (_size < VSOMEIP_COMMAND_HEADER_SIZE + sizeof(pending_security_update_id_t) ||
_size - VSOMEIP_COMMAND_HEADER_SIZE != its_length) {
@@ -1397,23 +1406,33 @@ void routing_manager_proxy::on_message(const byte_t *_data, length_t _size,
}
if (!its_security->is_enabled() || message_from_routing) {
pending_security_update_id_t its_update_id(0);
- uint32_t its_uid(0);
- uint32_t its_gid(0);
std::memcpy(&its_update_id, &_data[VSOMEIP_COMMAND_PAYLOAD_POS],
sizeof(pending_security_update_id_t));
std::shared_ptr<policy> its_policy(std::make_shared<policy>());
- const byte_t* buffer_ptr = _data + (VSOMEIP_COMMAND_PAYLOAD_POS +
+ const byte_t *its_policy_data = _data + (VSOMEIP_COMMAND_PAYLOAD_POS +
sizeof(pending_security_update_id_t));
- uint32_t its_size = uint32_t(_size - (VSOMEIP_COMMAND_PAYLOAD_POS
+ uint32_t its_policy_size = uint32_t(_size - (VSOMEIP_COMMAND_PAYLOAD_POS
+ sizeof(pending_security_update_id_t)));
- its_security->parse_policy(buffer_ptr, its_size, its_uid, its_gid, its_policy);
- if (its_security->is_policy_update_allowed(its_uid, its_policy)) {
- its_security->update_security_policy(its_uid, its_gid, its_policy);
- send_update_security_policy_response(its_update_id);
+ bool is_valid = its_policy->deserialize(its_policy_data, its_policy_size);
+ if (is_valid) {
+ uint32_t its_uid;
+ uint32_t its_gid;
+ is_valid = its_policy->get_uid_gid(its_uid, its_gid);
+ if (is_valid) {
+ if (is_internal_policy_update
+ || its_security->is_policy_update_allowed(its_uid, its_policy)) {
+ its_security->update_security_policy(its_uid, its_gid, its_policy);
+ send_update_security_policy_response(its_update_id);
+ }
+ } else {
+ VSOMEIP_ERROR << "vSomeIP Security: Policy has no valid uid/gid!";
+ }
+ } else {
+ VSOMEIP_ERROR << "vSomeIP Security: Policy deserialization failed!";
}
} else {
VSOMEIP_WARNING << "vSomeIP Security: Client 0x" << std::hex << get_client()
@@ -2350,21 +2369,29 @@ bool routing_manager_proxy::create_placeholder_event_and_subscribe(
service_t _service, instance_t _instance,
eventgroup_t _eventgroup, event_t _notifier, client_t _client) {
+ std::lock_guard<std::mutex> its_lock(stop_mutex_);
+
bool is_inserted(false);
- // we received a event which was not yet requested/offered
- // create a placeholder field until someone requests/offers this event with
- // full information like eventgroup, field or not etc.
- std::set<eventgroup_t> its_eventgroups({ _eventgroup });
- // routing_manager_proxy: Always register with own client id and shadow = false
- routing_manager_base::register_event(host_->get_client(),
- _service, _instance, _notifier,
- its_eventgroups, event_type_e::ET_UNKNOWN, reliability_type_e::RT_UNKNOWN,
- std::chrono::milliseconds::zero(), false, true, nullptr, false, false,
- true);
- std::shared_ptr<event> its_event = find_event(_service, _instance, _notifier);
- if (its_event) {
- is_inserted = its_event->add_subscriber(_eventgroup, _client, false);
+
+ if (find_service(_service, _instance)) {
+ // We received an event for an existing service which was not yet
+ // requested/offered. Create a placeholder field until someone
+ // requests/offers this event with full information like eventgroup,
+ // field/event, etc.
+ std::set<eventgroup_t> its_eventgroups({ _eventgroup });
+ // routing_manager_proxy: Always register with own client id and shadow = false
+ routing_manager_base::register_event(host_->get_client(),
+ _service, _instance, _notifier,
+ its_eventgroups, event_type_e::ET_UNKNOWN, reliability_type_e::RT_UNKNOWN,
+ std::chrono::milliseconds::zero(), false, true, nullptr, false, false,
+ true);
+
+ std::shared_ptr<event> its_event = find_event(_service, _instance, _notifier);
+ if (its_event) {
+ is_inserted = its_event->add_subscriber(_eventgroup, _client, false);
+ }
}
+
return is_inserted;
}
@@ -2561,7 +2588,8 @@ void routing_manager_proxy::on_update_security_credentials(const byte_t *_data,
uint32_t i = 0;
while ( (i + sizeof(uint32_t) + sizeof(uint32_t)) <= _size) {
std::shared_ptr<policy> its_policy(std::make_shared<policy>());
- ranges_t its_uid_ranges, its_gid_ranges;
+
+ boost::icl::interval_set<uint32_t> its_gid_set;
uint32_t its_uid, its_gid;
std::memcpy(&its_uid, &_data[i], sizeof(uint32_t));
@@ -2569,11 +2597,13 @@ void routing_manager_proxy::on_update_security_credentials(const byte_t *_data,
std::memcpy(&its_gid, &_data[i], sizeof(uint32_t));
i += uint32_t(sizeof(uint32_t));
- its_uid_ranges.insert(std::make_pair(its_uid, its_uid));
- its_gid_ranges.insert(std::make_pair(its_gid, its_gid));
+ its_gid_set.insert(its_gid);
+ its_policy->credentials_ += std::make_pair(
+ boost::icl::interval<uid_t>::closed(its_uid, its_uid), its_gid_set);
its_policy->allow_who_ = true;
- its_policy->ids_.insert(std::make_pair(its_uid_ranges, its_gid_ranges));
+ its_policy->allow_what_ = true;
+
its_security->add_security_credentials(its_uid, its_gid, its_policy, get_client());
}
}
diff --git a/implementation/routing/src/routing_manager_stub.cpp b/implementation/routing/src/routing_manager_stub.cpp
index d7a1dd2..72668ea 100644
--- a/implementation/routing/src/routing_manager_stub.cpp
+++ b/implementation/routing/src/routing_manager_stub.cpp
@@ -47,7 +47,8 @@ routing_manager_stub::routing_manager_stub(
client_registration_running_(false),
max_local_message_size_(configuration_->get_max_message_size_local()),
configured_watchdog_timeout_(configuration_->get_watchdog_timeout()),
- pinged_clients_timer_(io_) {
+ pinged_clients_timer_(io_),
+ pending_security_update_id_(0) {
}
routing_manager_stub::~routing_manager_stub() {
@@ -760,7 +761,7 @@ void routing_manager_stub::on_message(const byte_t *_data, length_t _size,
std::memcpy(&its_pending_security_update_id, &_data[VSOMEIP_COMMAND_PAYLOAD_POS],
sizeof(pending_security_update_id_t));
- host_->on_security_update_response(its_pending_security_update_id ,its_client);
+ on_security_update_response(its_pending_security_update_id ,its_client);
break;
}
case VSOMEIP_REMOVE_SECURITY_POLICY_RESPONSE: {
@@ -773,7 +774,7 @@ void routing_manager_stub::on_message(const byte_t *_data, length_t _size,
std::memcpy(&its_pending_security_update_id, &_data[VSOMEIP_COMMAND_PAYLOAD_POS],
sizeof(pending_security_update_id_t));
- host_->on_security_update_response(its_pending_security_update_id ,its_client);
+ on_security_update_response(its_pending_security_update_id ,its_client);
break;
}
}
@@ -787,9 +788,20 @@ void routing_manager_stub::on_register_application(client_t _client) {
VSOMEIP_WARNING << "Reregistering application: " << std::hex << _client
<< ". Last registration might have been taken too long.";
} else {
- (void)host_->find_or_create_local(_client);
- std::lock_guard<std::mutex> its_lock(routing_info_mutex_);
- routing_info_[_client].first = 0;
+ endpoint = host_->find_or_create_local(_client);
+ {
+ std::lock_guard<std::mutex> its_lock(routing_info_mutex_);
+ routing_info_[_client].first = 0;
+ }
+
+ std::pair<uid_t, gid_t> its_uid_gid;
+ std::set<std::shared_ptr<policy> > its_policies;
+
+ security::get()->get_client_to_uid_gid_mapping(_client, its_uid_gid);
+ get_requester_policies(its_uid_gid.first, its_uid_gid.second, its_policies);
+
+ if (!its_policies.empty())
+ send_requester_policies({ _client }, its_policies);
}
}
@@ -2153,4 +2165,408 @@ bool routing_manager_stub::send_remove_security_policy_request( client_t _client
}
}
+bool
+routing_manager_stub::add_requester_policies(uid_t _uid, gid_t _gid,
+ const std::set<std::shared_ptr<policy> > &_policies) {
+
+ std::lock_guard<std::mutex> its_lock(requester_policies_mutex_);
+ auto found_uid = requester_policies_.find(_uid);
+ if (found_uid != requester_policies_.end()) {
+ auto found_gid = found_uid->second.find(_gid);
+ if (found_gid != found_uid->second.end()) {
+ found_gid->second.insert(_policies.begin(), _policies.end());
+ } else {
+ found_uid->second.insert(std::make_pair(_gid, _policies));
+ }
+ } else {
+ requester_policies_[_uid][_gid] = _policies;
+ }
+
+ // Check whether clients with uid/gid are already registered.
+ // If yes, update their policy
+ std::unordered_set<client_t> its_clients;
+ security::get()->get_clients(_uid, _gid, its_clients);
+
+ if (!its_clients.empty())
+ return send_requester_policies(its_clients, _policies);
+
+ return (true);
+}
+
+void
+routing_manager_stub::remove_requester_policies(uid_t _uid, gid_t _gid) {
+
+ std::lock_guard<std::mutex> its_lock(requester_policies_mutex_);
+ auto found_uid = requester_policies_.find(_uid);
+ if (found_uid != requester_policies_.end()) {
+ found_uid->second.erase(_gid);
+ if (found_uid->second.empty())
+ requester_policies_.erase(_uid);
+ }
+}
+
+void
+routing_manager_stub::get_requester_policies(uid_t _uid, gid_t _gid,
+ std::set<std::shared_ptr<policy> > &_policies) const {
+
+ std::lock_guard<std::mutex> its_lock(requester_policies_mutex_);
+ auto found_uid = requester_policies_.find(_uid);
+ if (found_uid != requester_policies_.end()) {
+ auto found_gid = found_uid->second.find(_gid);
+ if (found_gid != found_uid->second.end())
+ _policies = found_gid->second;
+ }
+}
+
+void
+routing_manager_stub::add_pending_security_update_handler(
+ pending_security_update_id_t _id, security_update_handler_t _handler) {
+
+ std::lock_guard<std::recursive_mutex> its_lock(security_update_handlers_mutex_);
+ security_update_handlers_[_id] = _handler;
+}
+
+void
+routing_manager_stub::add_pending_security_update_timer(
+ pending_security_update_id_t _id) {
+
+ std::shared_ptr<boost::asio::steady_timer> its_timer
+ = std::make_shared<boost::asio::steady_timer>(io_);
+
+ boost::system::error_code ec;
+ its_timer->expires_from_now(std::chrono::milliseconds(3000), ec);
+ if (!ec) {
+ its_timer->async_wait(
+ std::bind(
+ &routing_manager_stub::on_security_update_timeout,
+ shared_from_this(),
+ std::placeholders::_1, _id, its_timer));
+ } else {
+ VSOMEIP_ERROR << __func__
+ << "[" << std::dec << _id << "]: timer creation: "
+ << ec.message();
+ }
+ std::lock_guard<std::mutex> its_lock(security_update_timers_mutex_);
+ security_update_timers_[_id] = its_timer;
+}
+
+bool
+routing_manager_stub::send_requester_policies(const std::unordered_set<client_t> &_clients,
+ const std::set<std::shared_ptr<policy> > &_policies) {
+
+ pending_security_update_id_t its_policy_id;
+
+ // serialize the policies and send them...
+ for (const auto p : _policies) {
+ std::vector<byte_t> its_policy_data;
+ if (p->serialize(its_policy_data)) {
+ std::vector<byte_t> its_message;
+ its_message.push_back(VSOMEIP_UPDATE_SECURITY_POLICY_INT);
+ its_message.push_back(0);
+ its_message.push_back(0);
+
+ uint32_t its_policy_size = static_cast<uint32_t>(its_policy_data.size() + sizeof(uint32_t));
+ its_message.push_back(VSOMEIP_LONG_BYTE0(its_policy_size));
+ its_message.push_back(VSOMEIP_LONG_BYTE1(its_policy_size));
+ its_message.push_back(VSOMEIP_LONG_BYTE2(its_policy_size));
+ its_message.push_back(VSOMEIP_LONG_BYTE3(its_policy_size));
+
+ its_policy_id = pending_security_update_add(_clients);
+ its_message.push_back(VSOMEIP_LONG_BYTE0(its_policy_id));
+ its_message.push_back(VSOMEIP_LONG_BYTE1(its_policy_id));
+ its_message.push_back(VSOMEIP_LONG_BYTE2(its_policy_id));
+ its_message.push_back(VSOMEIP_LONG_BYTE3(its_policy_id));
+
+ its_message.insert(its_message.end(), its_policy_data.begin(), its_policy_data.end());
+
+ for (const auto c : _clients) {
+ std::shared_ptr<endpoint> its_endpoint = host_->find_local(c);
+ if (its_endpoint)
+ its_endpoint->send(&its_message[0], static_cast<uint32_t>(its_message.size()));
+ }
+ }
+ }
+
+ return (true);
+}
+
+void routing_manager_stub::on_security_update_timeout(
+ const boost::system::error_code& _error,
+ pending_security_update_id_t _id,
+ std::shared_ptr<boost::asio::steady_timer> _timer) {
+ (void)_timer;
+ if (_error) {
+ // timer was cancelled
+ return;
+ }
+ security_update_state_e its_state = security_update_state_e::SU_UNKNOWN_USER_ID;
+ std::unordered_set<client_t> its_missing_clients = pending_security_update_get(_id);
+ {
+ // erase timer
+ std::lock_guard<std::mutex> its_lock(security_update_timers_mutex_);
+ security_update_timers_.erase(_id);
+ }
+ {
+ // print missing responses and check if some clients did not respond because they already disconnected
+ if (!its_missing_clients.empty()) {
+ for (auto its_client : its_missing_clients) {
+ VSOMEIP_INFO << __func__ << ": Client 0x" << std::hex << its_client
+ << " did not respond to the policy update / removal with ID: 0x" << std::hex << _id;
+ if (!host_->find_local(its_client)) {
+ VSOMEIP_INFO << __func__ << ": Client 0x" << std::hex << its_client
+ << " is not connected anymore, do not expect answer for policy update / removal with ID: 0x"
+ << std::hex << _id;
+ pending_security_update_remove(_id, its_client);
+ }
+ }
+ }
+
+ its_missing_clients = pending_security_update_get(_id);
+ if (its_missing_clients.empty()) {
+ VSOMEIP_INFO << __func__ << ": Received all responses for "
+ "security update/removal ID: 0x" << std::hex << _id;
+ its_state = security_update_state_e::SU_SUCCESS;
+ }
+ {
+ // erase pending security update
+ std::lock_guard<std::mutex> its_lock(pending_security_updates_mutex_);
+ pending_security_updates_.erase(_id);
+ }
+
+ // call handler with error on timeout or with SUCCESS if missing clients are not connected
+ std::lock_guard<std::recursive_mutex> its_lock(security_update_handlers_mutex_);
+ const auto found_handler = security_update_handlers_.find(_id);
+ if (found_handler != security_update_handlers_.end()) {
+ found_handler->second(its_state);
+ security_update_handlers_.erase(found_handler);
+ } else {
+ VSOMEIP_WARNING << __func__ << ": Callback not found for security update / removal with ID: 0x"
+ << std::hex << _id;
+ }
+ }
+}
+
+bool routing_manager_stub::update_security_policy_configuration(
+ uint32_t _uid, uint32_t _gid,
+ const std::shared_ptr<policy> &_policy,
+ const std::shared_ptr<payload> &_payload,
+ const security_update_handler_t &_handler) {
+
+ bool ret(true);
+
+ // cache security policy payload for later distribution to new registering clients
+ policy_cache_add(_uid, _payload);
+
+ // update security policy from configuration
+ security::get()->update_security_policy(_uid, _gid, _policy);
+
+ // Build requester policies for the services offered by the new policy
+ std::set<std::shared_ptr<policy> > its_requesters;
+ security::get()->get_requester_policies(_policy, its_requesters);
+
+ // and add them to the requester policy cache
+ add_requester_policies(_uid, _gid, its_requesters);
+
+ // determine currently connected clients
+ std::unordered_set<client_t> its_clients_to_inform;
+ auto its_epm = host_->get_endpoint_manager();
+ if (its_epm)
+ its_clients_to_inform = its_epm->get_connected_clients();
+
+ // add handler
+ pending_security_update_id_t its_id;
+ if (!its_clients_to_inform.empty()) {
+ its_id = pending_security_update_add(its_clients_to_inform);
+
+ add_pending_security_update_handler(its_id, _handler);
+ add_pending_security_update_timer(its_id);
+
+ // trigger all currently connected clients to update the security policy
+ uint32_t sent_counter(0);
+ uint32_t its_tranche =
+ uint32_t(its_clients_to_inform.size() >= 10 ? (its_clients_to_inform.size() / 10) : 1);
+ VSOMEIP_INFO << __func__ << ": Informing [" << std::dec << its_clients_to_inform.size()
+ << "] currently connected clients about policy update for UID: "
+ << std::dec << _uid << " with update ID: 0x" << std::hex << its_id;
+ for (auto its_client : its_clients_to_inform) {
+ if (!send_update_security_policy_request(its_client, its_id, _uid, _payload)) {
+ VSOMEIP_INFO << __func__ << ": Couldn't send update security policy "
+ << "request to client 0x" << std::hex << std::setw(4)
+ << std::setfill('0') << its_client << " policy UID: "
+ << std::hex << std::setw(4) << std::setfill('0') << _uid << " GID: "
+ << std::hex << std::setw(4) << std::setfill('0') << _gid
+ << " with update ID: 0x" << std::hex << its_id
+ << " as client already disconnected";
+ // remove client from expected answer list
+ pending_security_update_remove(its_id, its_client);
+ }
+ sent_counter++;
+ // Prevent burst
+ if (sent_counter % its_tranche == 0) {
+ std::this_thread::sleep_for(std::chrono::milliseconds(10));
+ }
+ }
+ } else {
+ // if routing manager has no client call the handler directly
+ _handler(security_update_state_e::SU_SUCCESS);
+ }
+
+ return ret;
+}
+
+bool routing_manager_stub::remove_security_policy_configuration(
+ uint32_t _uid, uint32_t _gid, const security_update_handler_t &_handler) {
+
+ bool ret(true);
+
+ // remove security policy from configuration (only if there was a updateACL call before)
+ if (is_policy_cached(_uid)) {
+ if (!security::get()->remove_security_policy(_uid, _gid)) {
+ _handler(security_update_state_e::SU_UNKNOWN_USER_ID);
+ ret = false;
+ } else {
+ // remove policy from cache to prevent sending it to registering clients
+ policy_cache_remove(_uid);
+
+ // add handler
+ pending_security_update_id_t its_id;
+
+ // determine currently connected clients
+ std::unordered_set<client_t> its_clients_to_inform;
+ auto its_epm = host_->get_endpoint_manager();
+ if (its_epm)
+ its_clients_to_inform = its_epm->get_connected_clients();
+
+ if (!its_clients_to_inform.empty()) {
+ its_id = pending_security_update_add(its_clients_to_inform);
+
+ add_pending_security_update_handler(its_id, _handler);
+ add_pending_security_update_timer(its_id);
+
+ // trigger all clients to remove the security policy
+ uint32_t sent_counter(0);
+ uint32_t its_tranche =
+ uint32_t(its_clients_to_inform.size() >= 10 ? (its_clients_to_inform.size() / 10) : 1);
+ VSOMEIP_INFO << __func__ << ": Informing [" << std::dec << its_clients_to_inform.size()
+ << "] currently connected clients about policy removal for UID: "
+ << std::dec << _uid << " with update ID: " << its_id;
+ for (auto its_client : its_clients_to_inform) {
+ if (!send_remove_security_policy_request(its_client, its_id, _uid, _gid)) {
+ VSOMEIP_INFO << __func__ << ": Couldn't send remove security policy "
+ << "request to client 0x" << std::hex << std::setw(4)
+ << std::setfill('0') << its_client << " policy UID: "
+ << std::hex << std::setw(4) << std::setfill('0') << _uid << " GID: "
+ << std::hex << std::setw(4) << std::setfill('0') << _gid
+ << " with update ID: 0x" << std::hex << its_id
+ << " as client already disconnected";
+ // remove client from expected answer list
+ pending_security_update_remove(its_id, its_client);
+ }
+ sent_counter++;
+ // Prevent burst
+ if (sent_counter % its_tranche == 0) {
+ std::this_thread::sleep_for(std::chrono::milliseconds(10));
+ }
+ }
+ } else {
+ // if routing manager has no client call the handler directly
+ _handler(security_update_state_e::SU_SUCCESS);
+ }
+ }
+ }
+ else {
+ _handler(security_update_state_e::SU_UNKNOWN_USER_ID);
+ ret = false;
+ }
+ return ret;
+}
+
+pending_security_update_id_t routing_manager_stub::pending_security_update_add(
+ const std::unordered_set<client_t>& _clients) {
+ std::lock_guard<std::mutex> its_lock(pending_security_updates_mutex_);
+ if (++pending_security_update_id_ == 0) {
+ pending_security_update_id_++;
+ }
+ pending_security_updates_[pending_security_update_id_] = _clients;
+
+ return pending_security_update_id_;
+}
+
+std::unordered_set<client_t> routing_manager_stub::pending_security_update_get(
+ pending_security_update_id_t _id) {
+ std::lock_guard<std::mutex> its_lock(pending_security_updates_mutex_);
+ std::unordered_set<client_t> its_missing_clients;
+ auto found_si = pending_security_updates_.find(_id);
+ if (found_si != pending_security_updates_.end()) {
+ its_missing_clients = pending_security_updates_[_id];
+ }
+ return its_missing_clients;
+}
+
+bool routing_manager_stub::pending_security_update_remove(
+ pending_security_update_id_t _id, client_t _client) {
+ std::lock_guard<std::mutex> its_lock(pending_security_updates_mutex_);
+ auto found_si = pending_security_updates_.find(_id);
+ if (found_si != pending_security_updates_.end()) {
+ if (found_si->second.erase(_client)) {
+ return true;
+ }
+ }
+ return false;
+}
+
+bool routing_manager_stub::is_pending_security_update_finished(
+ pending_security_update_id_t _id) {
+ std::lock_guard<std::mutex> its_lock(pending_security_updates_mutex_);
+ bool ret(false);
+ auto found_si = pending_security_updates_.find(_id);
+ if (found_si != pending_security_updates_.end()) {
+ if (!found_si->second.size()) {
+ ret = true;
+ }
+ }
+ if (ret) {
+ pending_security_updates_.erase(_id);
+ }
+ return ret;
+}
+
+void routing_manager_stub::on_security_update_response(
+ pending_security_update_id_t _id, client_t _client) {
+ if (pending_security_update_remove(_id, _client)) {
+ if (is_pending_security_update_finished(_id)) {
+ // cancel timeout timer
+ {
+ std::lock_guard<std::mutex> its_lock(security_update_timers_mutex_);
+ auto found_timer = security_update_timers_.find(_id);
+ if (found_timer != security_update_timers_.end()) {
+ boost::system::error_code ec;
+ found_timer->second->cancel(ec);
+ security_update_timers_.erase(found_timer);
+ } else {
+ VSOMEIP_WARNING << __func__ << ": Received all responses "
+ "for security update/removal ID: 0x"
+ << std::hex << _id << " but timeout already happened";
+ }
+ }
+
+ // call handler
+ {
+ std::lock_guard<std::recursive_mutex> its_lock(security_update_handlers_mutex_);
+ auto found_handler = security_update_handlers_.find(_id);
+ if (found_handler != security_update_handlers_.end()) {
+ found_handler->second(security_update_state_e::SU_SUCCESS);
+ security_update_handlers_.erase(found_handler);
+ VSOMEIP_INFO << __func__ << ": Received all responses for "
+ "security update/removal ID: 0x" << std::hex << _id;
+ } else {
+ VSOMEIP_WARNING << __func__ << ": Received all responses "
+ "for security update/removal ID: 0x"
+ << std::hex << _id << " but didn't find handler";
+ }
+ }
+ }
+ }
+}
+
} // namespace vsomeip_v3
diff --git a/implementation/runtime/include/application_impl.hpp b/implementation/runtime/include/application_impl.hpp
index f60c390..37df949 100644
--- a/implementation/runtime/include/application_impl.hpp
+++ b/implementation/runtime/include/application_impl.hpp
@@ -347,7 +347,7 @@ private:
typedef std::map<major_version_t, std::map<minor_version_t, std::pair<availability_handler_t,
bool>>> availability_major_minor_t;
std::map<service_t, std::map<instance_t, availability_major_minor_t>> availability_;
- mutable std::mutex availability_mutex_;
+ mutable std::recursive_mutex availability_mutex_;
// Availability
mutable available_t available_;
@@ -434,6 +434,10 @@ private:
uid_t own_uid_;
gid_t own_gid_;
+
+#ifdef VSOMEIP_HAS_SESSION_HANDLING_CONFIG
+ bool has_session_handling_;
+#endif // VSOMEIP_HAS_SESSION_HANDLING_CONFIG
};
} // namespace vsomeip_v3
diff --git a/implementation/runtime/src/application_impl.cpp b/implementation/runtime/src/application_impl.cpp
index 44b14fd..45ac83f 100644
--- a/implementation/runtime/src/application_impl.cpp
+++ b/implementation/runtime/src/application_impl.cpp
@@ -67,7 +67,11 @@ application_impl::application_impl(const std::string &_name)
is_routing_manager_host_(false),
stopped_called_(false),
watchdog_timer_(io_),
- client_side_logging_(false) {
+ client_side_logging_(false)
+#ifdef VSOMEIP_HAS_SESSION_HANDLING_CONFIG
+ , has_session_handling_(true)
+#endif // VSOMEIP_HAS_SESSION_HANDLING_CONFIG
+{
own_uid_ = ANY_UID;
own_gid_ = ANY_GID;
#ifndef _WIN32
@@ -230,6 +234,13 @@ bool application_impl::init() {
max_dispatchers_ = its_configuration->get_max_dispatchers(name_) + 1;
max_dispatch_time_ = its_configuration->get_max_dispatch_time(name_);
+#ifdef VSOMEIP_HAS_SESSION_HANDLING_CONFIG
+ has_session_handling_ = its_configuration->has_session_handling(name_);
+ if (!has_session_handling_)
+ VSOMEIP_INFO << "application: " << name_
+ << " has session handling switched off!";
+#endif // VSOMEIP_HAS_SESSION_HANDLING_CONFIG
+
std::string its_routing_host = its_configuration->get_routing_host();
if (its_routing_host != "") {
is_routing_manager_host_ = (its_routing_host == name_);
@@ -615,7 +626,7 @@ void application_impl::unsubscribe(service_t _service, instance_t _instance,
bool application_impl::is_available(
service_t _service, instance_t _instance,
major_version_t _major, minor_version_t _minor) const {
- std::lock_guard<std::mutex> its_lock(availability_mutex_);
+ std::lock_guard<std::recursive_mutex> its_lock(availability_mutex_);
return is_available_unlocked(_service, _instance, _major, _minor);
}
@@ -689,7 +700,7 @@ bool application_impl::are_available(
available_t &_available,
service_t _service, instance_t _instance,
major_version_t _major, minor_version_t _minor) const {
- std::lock_guard<std::mutex> its_lock(availability_mutex_);
+ std::lock_guard<std::recursive_mutex> its_lock(availability_mutex_);
return are_available_unlocked(_available, _service, _instance, _major, _minor);
}
@@ -868,7 +879,7 @@ void application_impl::unregister_state_handler() {
void application_impl::register_availability_handler(service_t _service,
instance_t _instance, availability_handler_t _handler,
major_version_t _major, minor_version_t _minor) {
- std::lock_guard<std::mutex> availability_lock(availability_mutex_);
+ std::lock_guard<std::recursive_mutex> availability_lock(availability_mutex_);
if (state_ == state_type_e::ST_REGISTERED) {
do_register_availability_handler(_service, _instance,
_handler, _major, _minor);
@@ -904,7 +915,7 @@ void application_impl::do_register_availability_handler(service_t _service,
void application_impl::unregister_availability_handler(service_t _service,
instance_t _instance, major_version_t _major, minor_version_t _minor) {
- std::lock_guard<std::mutex> its_lock(availability_mutex_);
+ std::lock_guard<std::recursive_mutex> its_lock(availability_mutex_);
auto found_service = availability_.find(_service);
if (found_service != availability_.end()) {
auto found_instance = found_service->second.find(_instance);
@@ -1253,11 +1264,18 @@ void application_impl::set_client(const client_t &_client) {
}
session_t application_impl::get_session() {
+
+#ifdef VSOMEIP_HAS_SESSION_HANDLING_CONFIG
+ if (!has_session_handling_)
+ return (0);
+#endif // VSOMEIP_HAS_SESSION_HANDLING_CONFIG
+
std::lock_guard<std::mutex> its_lock(session_mutex_);
if (0 == ++session_) {
// Smallest allowed session identifier
session_ = 1;
}
+
return session_;
}
@@ -1275,7 +1293,7 @@ boost::asio::io_service & application_impl::get_io() {
void application_impl::on_state(state_type_e _state) {
{
- std::lock_guard<std::mutex> availability_lock(availability_mutex_);
+ std::lock_guard<std::recursive_mutex> availability_lock(availability_mutex_);
if (state_ != _state) {
state_ = _state;
if (state_ == state_type_e::ST_REGISTERED) {
@@ -1294,6 +1312,17 @@ void application_impl::on_state(state_type_e _state) {
}
}
}
+ } else {
+ // Call on_availability callback on each service
+ for (const auto &its_service : availability_) {
+ for (const auto &its_instance : its_service.second) {
+ for (const auto &its_major : its_instance.second) {
+ for (const auto &its_minor : its_major.second) {
+ on_availability(its_service.first, its_instance.first, false, its_major.first, its_minor.first);
+ }
+ }
+ }
+ }
}
}
}
@@ -1322,7 +1351,7 @@ void application_impl::on_availability(service_t _service, instance_t _instance,
bool _is_available, major_version_t _major, minor_version_t _minor) {
std::vector<availability_handler_t> its_handlers;
{
- std::lock_guard<std::mutex> availability_lock(availability_mutex_);
+ std::lock_guard<std::recursive_mutex> availability_lock(availability_mutex_);
if (_is_available == is_available_unlocked(_service, _instance, _major, _minor)) {
return;
}
@@ -1860,7 +1889,7 @@ void application_impl::clear_all_handler() {
}
{
- std::lock_guard<std::mutex> availability_lock(availability_mutex_);
+ std::lock_guard<std::recursive_mutex> availability_lock(availability_mutex_);
availability_.clear();
}
diff --git a/implementation/security/include/policy.hpp b/implementation/security/include/policy.hpp
index f8727f8..82f3eb9 100644
--- a/implementation/security/include/policy.hpp
+++ b/implementation/security/include/policy.hpp
@@ -1,4 +1,4 @@
-// Copyright (C) 2014-2017 Bayerische Motoren Werke Aktiengesellschaft (BMW AG)
+// Copyright (C) 2014-2020 Bayerische Motoren Werke Aktiengesellschaft (BMW AG)
// This Source Code Form is subject to the terms of the Mozilla Public
// License, v. 2.0. If a copy of the MPL was not distributed with this
// file, You can obtain one at http://mozilla.org/MPL/2.0/.
@@ -9,8 +9,11 @@
#include <cstring>
#include <map>
#include <mutex>
-#include <set>
#include <utility>
+#include <vector>
+
+#include <boost/icl/interval_map.hpp>
+#include <boost/icl/interval_set.hpp>
#include <vsomeip/constants.hpp>
#include <vsomeip/primitive_types.hpp>
@@ -18,20 +21,88 @@
namespace vsomeip_v3 {
-typedef std::set<std::pair<uint32_t, uint32_t>> ranges_t;
-typedef std::set<std::pair<ranges_t, ranges_t>> ids_t;
+template<typename T_>
+void get_bounds(const boost::icl::discrete_interval<T_> &_interval,
+ T_ &_lower, T_ &_upper) {
+
+ T_ its_lower, its_upper;
+
+ its_lower = _interval.lower();
+ its_upper = _interval.upper();
+
+ switch (_interval.bounds().bits()) {
+ case boost::icl::interval_bounds::static_open:
+ its_lower++;
+ its_upper--;
+ break;
+ case boost::icl::interval_bounds::static_left_open:
+ its_lower++;
+ break;
+ case boost::icl::interval_bounds::static_right_open:
+ its_upper--;
+ break;
+ default:
+ ;
+ }
+
+ _lower = its_lower;
+ _upper = its_upper;
+}
struct policy {
policy() : allow_who_(false), allow_what_(false) {};
- ids_t ids_;
+ // Returns true if the policy is defined for single uid/gid pair.
+ // uid & gid are copied to the arguments. Otherwise, returns false.
+ bool get_uid_gid(uid_t &_uid, gid_t &_gid) const;
+
+ bool deserialize_uid_gid(const byte_t * &_data, uint32_t &_size,
+ uid_t &_uid, gid_t &_gid) const;
+ bool deserialize(const byte_t * &_data, uint32_t &_size);
+ bool serialize(std::vector<byte_t> &_data) const;
+
+ void print() const;
+
+ // Members
+ boost::icl::interval_map<uid_t,
+ boost::icl::interval_set<gid_t> > credentials_;
bool allow_who_;
- std::map<service_t, ids_t> services_;
- std::map<service_t, ranges_t> offers_;
+ boost::icl::interval_map<service_t,
+ boost::icl::interval_map<instance_t,
+ boost::icl::interval_set<method_t> > > requests_;
+ boost::icl::interval_map<service_t,
+ boost::icl::interval_set<instance_t> > offers_;
bool allow_what_;
- std::mutex mutex_;
+ mutable std::mutex mutex_;
+
+private:
+ bool deserialize_ids(const byte_t * &_data, uint32_t &_size,
+ boost::icl::interval_map<uint16_t,
+ boost::icl::interval_set<uint16_t> > &_ids) const;
+ bool deserialize_id_item_list(const byte_t * &_data, uint32_t &_size,
+ boost::icl::interval_set<uint16_t> &_intervals) const;
+ bool deserialize_id_item(const byte_t * &_data, uint32_t &_size,
+ uint16_t &_low, uint16_t &_high) const;
+
+ bool deserialize_u32(const byte_t * &_data, uint32_t &_size,
+ uint32_t &_value) const;
+ bool deserialize_u16(const byte_t * &_data, uint32_t &_size,
+ uint16_t &_value) const;
+
+ bool serialize_uid_gid(std::vector<byte_t> &_data) const;
+ void serialize_interval_set(
+ const boost::icl::interval_set<uint16_t> &_intervals,
+ std::vector<byte_t> &_data) const;
+ void serialize_interval(
+ const boost::icl::discrete_interval<uint16_t> &_interval,
+ std::vector<byte_t> &_data) const;
+
+ void serialize_u32(uint32_t _value, std::vector<byte_t> &_data) const;
+ void serialize_u32_at(uint32_t _value, std::vector<byte_t> &_data,
+ size_t _pos) const;
+ void serialize_u16(uint16_t _value, std::vector<byte_t> &_data) const;
};
} // namespace vsomeip_v3
diff --git a/implementation/security/include/security.hpp b/implementation/security/include/security.hpp
index 0bac7a0..03406c6 100644
--- a/implementation/security/include/security.hpp
+++ b/implementation/security/include/security.hpp
@@ -7,6 +7,10 @@
#define VSOMEIP_V3_SECURITY_SECURITY_HPP_
#include <memory>
+#include <unordered_set>
+
+#include <vsomeip/payload.hpp>
+#include <vsomeip/primitive_types.hpp>
namespace vsomeip_v3 {
@@ -49,6 +53,11 @@ public:
uint32_t _uid, uint32_t _gid) = 0;
virtual void store_uid_gid_to_client_mapping(uint32_t _uid, uint32_t _gid,
client_t _client) = 0;
+
+ virtual void get_requester_policies(const std::shared_ptr<policy> _policy,
+ std::set<std::shared_ptr<policy> > &_requesters) const = 0;
+ virtual void get_clients(uid_t _uid, gid_t _gid,
+ std::unordered_set<client_t> &_clients) const = 0;
};
} // namespace vsomeip_v3
diff --git a/implementation/security/include/security_impl.hpp b/implementation/security/include/security_impl.hpp
index 564c029..dfeea6b 100644
--- a/implementation/security/include/security_impl.hpp
+++ b/implementation/security/include/security_impl.hpp
@@ -50,8 +50,6 @@ public:
bool is_policy_removal_allowed(uint32_t _uid) const;
- bool parse_uid_gid(const byte_t* &_buffer, uint32_t &_buffer_size,
- uint32_t &_uid, uint32_t &_gid) const;
bool parse_policy(const byte_t* &_buffer, uint32_t &_buffer_size,
uint32_t &_uid, uint32_t &_gid, const std::shared_ptr<policy> &_policy) const;
@@ -62,30 +60,24 @@ public:
bool store_client_to_uid_gid_mapping(client_t _client, uint32_t _uid, uint32_t _gid);
void store_uid_gid_to_client_mapping(uint32_t _uid, uint32_t _gid, client_t _client);
+ void get_requester_policies(const std::shared_ptr<policy> _policy,
+ std::set<std::shared_ptr<policy> > &_requesters) const;
+ void get_clients(uid_t _uid, gid_t _gid, std::unordered_set<client_t> &_clients) const;
+
private:
- // Helper
-
- bool get_struct_length(const byte_t* &_buffer, uint32_t &_buffer_size, uint32_t &_length) const;
- bool get_union_length(const byte_t* &_buffer, uint32_t &_buffer_size, uint32_t &_length) const;
- bool get_array_length(const byte_t* &_buffer, uint32_t &_buffer_size, uint32_t &_length) const;
- bool is_range(const byte_t* &_buffer, uint32_t &_buffer_size) const;
- bool parse_id_item(const byte_t* &_buffer, uint32_t& parsed_ids_bytes,
- ranges_t& its_ranges, uint32_t &_buffer_size) const;
- bool parse_range(const byte_t* &_buffer, uint32_t &_buffer_size,
- uint16_t &_first, uint16_t &_last) const;
- bool parse_id(const byte_t* &_buffer, uint32_t &_buffer_size, uint16_t &_id) const;
// Configuration
void load_policies(const configuration_element &_element);
void load_policy(const boost::property_tree::ptree &_tree);
- void load_credential(const boost::property_tree::ptree &_tree, ids_t &_ids);
+ void load_policy_body(std::shared_ptr<policy> &_policy,
+ const boost::property_tree::ptree::const_iterator &_tree);
+ void load_credential(const boost::property_tree::ptree &_tree,
+ boost::icl::interval_map<uid_t, boost::icl::interval_set<gid_t> > &_ids);
bool load_routing_credentials(const configuration_element &_element);
- void load_ranges(const boost::property_tree::ptree &_tree, ranges_t &_range);
- void load_instance_ranges(const boost::property_tree::ptree &_tree, ranges_t &_range);
-
+ template<typename T_>
+ void load_interval_set(const boost::property_tree::ptree &_tree,
+ boost::icl::interval_set<T_> &_range, bool _exclude_margins = false);
void load_security_update_whitelist(const configuration_element &_element);
- void load_service_ranges(const boost::property_tree::ptree &_tree,
- std::set<std::pair<service_t, service_t>> &_ranges);
private:
client_t routing_client_;
@@ -106,10 +98,10 @@ private:
bool check_whitelist_;
mutable std::mutex service_interface_whitelist_mutex_;
- std::set<std::pair<service_t, service_t>> service_interface_whitelist_;
+ boost::icl::interval_set<service_t> service_interface_whitelist_;
mutable std::mutex uid_whitelist_mutex_;
- ranges_t uid_whitelist_;
+ boost::icl::interval_set<uint32_t> uid_whitelist_;
mutable std::mutex routing_credentials_mutex_;
std::pair<uint32_t, uint32_t> routing_credentials_;
diff --git a/implementation/security/src/policy.cpp b/implementation/security/src/policy.cpp
new file mode 100644
index 0000000..4babd06
--- /dev/null
+++ b/implementation/security/src/policy.cpp
@@ -0,0 +1,499 @@
+// Copyright (C) 2020 Bayerische Motoren Werke Aktiengesellschaft (BMW AG)
+// This Source Code Form is subject to the terms of the Mozilla Public
+// License, v. 2.0. If a copy of the MPL was not distributed with this
+// file, You can obtain one at http://mozilla.org/MPL/2.0/.
+
+#include <iomanip>
+
+#include <vsomeip/internal/logger.hpp>
+
+#include "../include/policy.hpp"
+#include "../../utility/include/byteorder.hpp"
+
+namespace vsomeip_v3 {
+
+bool
+policy::get_uid_gid(uid_t &_uid, gid_t &_gid) const {
+
+ if (credentials_.size() != 1)
+ return (false);
+
+ const auto its_uids = credentials_.begin()->first;
+ const auto its_gids = credentials_.begin()->second;
+
+ if (its_gids.size() != 1)
+ return (false);
+
+ if (its_uids.lower() != its_uids.upper()
+ || its_gids.begin()->lower() != its_gids.begin()->upper())
+ return (false);
+
+ _uid = its_uids.lower();
+ _gid = its_gids.begin()->lower();
+
+ return (true);
+}
+
+bool
+policy::deserialize_uid_gid(const byte_t * &_data, uint32_t &_size,
+ uid_t &_uid, gid_t &_gid) const {
+
+ bool its_result;
+
+ its_result = deserialize_u32(_data, _size, _uid);
+ if (its_result == false)
+ return (false);
+
+ its_result = deserialize_u32(_data, _size, _gid);
+ if (its_result == false)
+ return (false);
+
+ return (true);
+}
+
+bool
+policy::deserialize(const byte_t * &_data, uint32_t &_size) {
+
+ bool its_result;
+ uid_t its_uid;
+ gid_t its_gid;
+
+ std::lock_guard<std::mutex> its_lock(mutex_);
+
+ its_result = deserialize_uid_gid(_data, _size, its_uid, its_gid);
+ if (its_result == false)
+ return (false);
+
+ // Fill policy uid/gid
+ const auto its_uid_interval
+ = boost::icl::interval<uid_t>::closed(its_uid, its_uid);
+ boost::icl::interval_set<gid_t> its_gid_set;
+ its_gid_set.insert(its_gid);
+ credentials_ += std::make_pair(its_uid_interval, its_gid_set);
+
+ // Deserialized policies are always "Allow" - policies
+ allow_who_ = true;
+ allow_what_ = true;
+
+ // Deserialize requests array length
+ uint32_t its_requests_length;
+ its_result = deserialize_u32(_data, _size, its_requests_length);
+ if (its_result == false)
+ return (false);
+
+ // Deserialize requests
+ while (0 < its_requests_length) {
+
+ uint32_t its_current_size(_size);
+
+ uint16_t its_service;
+ its_result = deserialize_u16(_data, _size, its_service);
+ if (its_result == false)
+ return (false);
+
+ if (its_service == 0x0000 || its_service == 0xffff) {
+ VSOMEIP_WARNING << "vSomeIP Security: Policy with service ID: 0x"
+ << std::hex << its_service << " is not allowed!";
+ return (false);
+ }
+
+ const auto its_service_interval
+ = boost::icl::interval<service_t>::closed(its_service, its_service);
+
+ boost::icl::interval_map<instance_t,
+ boost::icl::interval_set<method_t> > its_ids;
+ its_result = deserialize_ids(_data, _size, its_ids);
+ if (its_result == false)
+ return (false);
+
+ requests_ += std::make_pair(its_service_interval, its_ids);
+
+ its_requests_length -= (its_current_size - _size);
+ }
+
+ // Deserialize offers array length
+ uint32_t its_offers_length;
+ its_result = deserialize_u32(_data, _size, its_offers_length);
+ if (its_result == false)
+ return (false);
+
+ while (0 < its_offers_length) {
+
+ uint32_t its_current_size(_size);
+
+ uint16_t its_service;
+ its_result = deserialize_u16(_data, _size, its_service);
+ if (its_result == false)
+ return (false);
+
+ if (its_service == 0x0000 || its_service == 0xFFFF) {
+ VSOMEIP_WARNING << "vSomeIP Security: Policy with service ID: 0x"
+ << std::hex << its_service << " is not allowed!";
+ return false;
+ }
+
+ const auto its_service_interval
+ = boost::icl::interval<service_t>::closed(its_service, its_service);
+
+ boost::icl::interval_set<instance_t> its_instance_interval_set;
+ its_result = deserialize_id_item_list(_data, _size,
+ its_instance_interval_set);
+ if (its_result == false)
+ return (false);
+
+ offers_ += std::make_pair(its_service_interval, its_instance_interval_set);
+
+ its_offers_length -= (its_current_size - _size);
+ }
+
+ return (true);
+}
+
+bool
+policy::deserialize_ids(const byte_t * &_data, uint32_t &_size,
+ boost::icl::interval_map<uint16_t,
+ boost::icl::interval_set<uint16_t> > &_ids) const {
+
+ boost::icl::interval_map<uint16_t,
+ boost::icl::interval_set<uint16_t> > its_ids;
+ uint32_t its_array_length;
+ bool its_result;
+
+ its_result = deserialize_u32(_data, _size, its_array_length);
+ if (its_result == false)
+ return (false);
+
+ while (0 < its_array_length) {
+ uint32_t its_current_size(_size);
+
+ boost::icl::interval_set<uint16_t> its_instances, its_methods;
+ its_result = deserialize_id_item_list(_data, _size, its_instances);
+ if (its_result == false)
+ return (false);
+
+ its_result = deserialize_id_item_list(_data, _size, its_methods);
+ if (its_result == false)
+ return (false);
+
+ for (const auto i : its_instances)
+ its_ids += std::make_pair(i, its_methods);
+
+ its_array_length -= (its_current_size - _size);
+ }
+
+ _ids = std::move(its_ids);
+
+ return (true);
+}
+
+bool
+policy::deserialize_id_item_list(const byte_t * &_data, uint32_t &_size,
+ boost::icl::interval_set<uint16_t> &_intervals) const {
+
+ boost::icl::interval_set<uint16_t> its_intervals;
+ uint32_t its_length;
+ bool its_result;
+
+ its_result = deserialize_u32(_data, _size, its_length);
+ if (its_result == false)
+ return (its_result);
+
+ while (0 < its_length) {
+
+ uint32_t its_current_size(_size);
+
+ uint16_t its_low, its_high;
+ its_result = deserialize_id_item(_data, _size, its_low, its_high);
+ if (its_result == false)
+ return (false);
+
+ its_intervals.insert(boost::icl::interval<uint16_t>::closed(its_low, its_high));
+
+ its_length -= (its_current_size - _size);
+ }
+
+ _intervals = std::move(its_intervals);
+
+ return (true);
+}
+
+bool
+policy::deserialize_id_item(const byte_t * &_data, uint32_t &_size,
+ uint16_t &_low, uint16_t &_high) const {
+
+ uint32_t its_length, its_type;
+ bool its_result;
+
+ its_result = deserialize_u32(_data, _size, its_length);
+ if (its_result == false)
+ return (false);
+
+ its_result = deserialize_u32(_data, _size, its_type);
+ if (its_result == false)
+ return (false);
+
+ if (its_type == 1 && its_length == sizeof(uint16_t)) {
+ its_result = deserialize_u16(_data, _size, _low);
+ if (its_result == false)
+ return (false);
+
+ _high = _low;
+ } else if (its_type == 2
+ && its_length == sizeof(uint16_t) + sizeof(uint16_t)) {
+ its_result = deserialize_u16(_data, _size, _low);
+ if (its_result == false)
+ return (false);
+
+ its_result = deserialize_u16(_data, _size, _high);
+ if (its_result == false)
+ return (false);
+
+ if (_low > _high)
+ return (false);
+ }
+
+ // handle ANY_METHOD configuration
+ if (_low == ANY_METHOD && _high == ANY_METHOD) {
+ _low = 0x01;
+ }
+
+ return (_low != 0x0000);
+}
+
+bool
+policy::deserialize_u16(const byte_t * &_data, uint32_t &_size,
+ uint16_t &_value) const {
+
+ if (_size < sizeof(uint16_t))
+ return (false);
+
+ _value = VSOMEIP_BYTES_TO_WORD(_data[0], _data[1]);
+
+ _data += sizeof(uint16_t);
+ _size -= static_cast<uint16_t>(sizeof(uint16_t));
+
+ return (true);
+}
+
+bool
+policy::deserialize_u32(const byte_t * &_data, uint32_t &_size,
+ uint32_t &_value) const {
+
+ if (_size < sizeof(uint32_t))
+ return (false);
+
+ _value = VSOMEIP_BYTES_TO_LONG(_data[0], _data[1], _data[2], _data[3]);
+
+ _data += sizeof(uint32_t);
+ _size -= static_cast<uint32_t>(sizeof(uint32_t));
+
+ return (true);
+}
+
+bool
+policy::serialize(std::vector<byte_t> &_data) const {
+
+ bool its_result;
+
+ std::lock_guard<std::mutex> its_lock(mutex_);
+
+ its_result = serialize_uid_gid(_data);
+ if (!its_result)
+ return (false);
+
+ size_t its_requests_pos = _data.size();
+ uint32_t its_requests_size(0);
+ serialize_u32(its_requests_size, _data);
+
+ for (const auto its_request : requests_) {
+ for (auto its_service = its_request.first.lower();
+ its_service <= its_request.first.upper();
+ its_service++) {
+
+ serialize_u16(its_service, _data);
+
+ size_t its_pos = _data.size();
+ uint32_t its_instances_size(0);
+ serialize_u32(its_instances_size, _data);
+
+ for (const auto i : its_request.second) {
+ boost::icl::interval_set<instance_t> its_instances;
+ its_instances.insert(i.first);
+ serialize_interval_set(its_instances, _data);
+ serialize_interval_set(i.second, _data);
+ }
+
+ its_instances_size = static_cast<uint32_t>(_data.size() - its_pos - sizeof(uint32_t));
+ serialize_u32_at(its_instances_size, _data, its_pos);
+ }
+ }
+
+ its_requests_size = static_cast<uint32_t>(_data.size() - its_requests_pos - sizeof(uint32_t));
+ serialize_u32_at(its_requests_size, _data, its_requests_pos);
+
+ uint32_t its_offers_size = 0;
+ serialize_u32(its_offers_size, _data);
+
+ return (true);
+}
+
+bool
+policy::serialize_uid_gid(std::vector<byte_t> &_data) const {
+
+ if (credentials_.size() != 1) {
+ VSOMEIP_ERROR << "Unserializable policy (ids).";
+ return (false);
+ }
+
+ auto its_credential = *(credentials_.begin());
+ if (its_credential.second.size() != 1) {
+ VSOMEIP_ERROR << "Unserializable policy (intervals).";
+ return (false);
+ }
+
+ auto its_uid_interval = its_credential.first;
+ if (its_uid_interval.lower() != its_uid_interval.upper()) {
+ VSOMEIP_ERROR << "Unserializable policy (uid).";
+ return (false);
+ }
+
+ auto its_gid_interval = *(its_credential.second.begin());
+ if (its_gid_interval.lower() != its_gid_interval.upper()) {
+ VSOMEIP_ERROR << "Unserializable policy (gid).";
+ return (false);
+ }
+
+ serialize_u32(its_uid_interval.lower(), _data);
+ serialize_u32(its_gid_interval.lower(), _data);
+
+ return (true);
+}
+
+void
+policy::serialize_interval_set(
+ const boost::icl::interval_set<uint16_t> &_intervals,
+ std::vector<byte_t> &_data) const {
+
+ size_t its_pos(_data.size());
+ uint32_t its_interval_set_size(0);
+ serialize_u32(its_interval_set_size, _data);
+
+ for (const auto i : _intervals)
+ serialize_interval(i, _data);
+
+ its_interval_set_size = static_cast<uint32_t>(_data.size()
+ - its_pos - sizeof(uint32_t));
+ serialize_u32_at(its_interval_set_size, _data, its_pos);
+}
+
+void
+policy::serialize_interval(
+ const boost::icl::discrete_interval<uint16_t> &_interval,
+ std::vector<byte_t> &_data) const {
+
+ uint32_t its_union_length, its_union_type;
+
+ if (_interval.lower() == _interval.upper()) { // single value
+ its_union_length = static_cast<uint32_t>(sizeof(uint16_t));
+ its_union_type = 1;
+
+ serialize_u32(its_union_length, _data);
+ serialize_u32(its_union_type, _data);
+
+ serialize_u16(_interval.lower(), _data);
+ } else { // value interval
+ its_union_type = 2;
+ its_union_length = static_cast<uint32_t>(
+ sizeof(uint16_t) + sizeof(uint16_t));
+
+ serialize_u32(its_union_length, _data);
+ serialize_u32(its_union_type, _data);
+
+ serialize_u16(_interval.lower(), _data);
+ serialize_u16(_interval.upper(), _data);
+ }
+}
+
+void
+policy::serialize_u16(uint16_t _value,
+ std::vector<byte_t> &_data) const {
+
+ _data.push_back(VSOMEIP_WORD_BYTE1(_value));
+ _data.push_back(VSOMEIP_WORD_BYTE0(_value));
+}
+
+void
+policy::serialize_u32(uint32_t _value,
+ std::vector<byte_t> &_data) const {
+
+ _data.push_back(VSOMEIP_LONG_BYTE3(_value));
+ _data.push_back(VSOMEIP_LONG_BYTE2(_value));
+ _data.push_back(VSOMEIP_LONG_BYTE1(_value));
+ _data.push_back(VSOMEIP_LONG_BYTE0(_value));
+}
+
+void
+policy::serialize_u32_at(uint32_t _value,
+ std::vector<byte_t> &_data, size_t _pos) const {
+
+ _data[_pos] = VSOMEIP_LONG_BYTE3(_value);
+ _data[_pos+1] = VSOMEIP_LONG_BYTE2(_value);
+ _data[_pos+2] = VSOMEIP_LONG_BYTE1(_value);
+ _data[_pos+3] = VSOMEIP_LONG_BYTE0(_value);
+}
+
+void
+policy::print() const {
+
+ for (auto its_credential : credentials_) {
+ auto its_uid_interval = its_credential.first;
+ if (its_uid_interval.lower() == std::numeric_limits<uint32_t>::max()) {
+ VSOMEIP_INFO << "policy::print Security configuration: UID: any";
+ } else {
+ VSOMEIP_INFO << "policy::print Security configuration: UID: "
+ << std::dec << its_uid_interval.lower();
+ }
+ for (auto its_gid_interval : its_credential.second) {
+ if (its_gid_interval.lower() == std::numeric_limits<uint32_t>::max()) {
+ VSOMEIP_INFO << " policy::print Security configuration: GID: any";
+ } else {
+ VSOMEIP_INFO << " policy::print Security configuration: GID: "
+ << std::dec << its_gid_interval.lower();
+ }
+ }
+ }
+
+ VSOMEIP_INFO << "policy::print Security configuration: REQUESTS POLICY SIZE: "
+ << std::dec << requests_.size();
+ for (auto its_request : requests_) {
+ VSOMEIP_INFO << "policy::print ALLOWED REQUESTS Services:"
+ << std::hex << its_request.first;
+ for (auto its_instance : its_request.second) {
+ VSOMEIP_INFO << "policy::print Instances: ";
+ VSOMEIP_INFO << "policy::print first: 0x"
+ << std::hex << its_instance.first.lower()
+ << " last: 0x" << its_instance.first.upper();
+ VSOMEIP_INFO << "policy::print Methods: ";
+ for (auto its_method : its_instance.second) {
+ VSOMEIP_INFO << "policy::print first: 0x"
+ << std::hex << its_method.lower()
+ << " last: 0x" << its_method.upper();
+ }
+ }
+ }
+
+ VSOMEIP_INFO << "policy::print Security configuration: OFFER POLICY SIZE: "
+ << std::dec << offers_.size();
+ for (auto its_offer : offers_) {
+ VSOMEIP_INFO << "policy::print ALLOWED OFFERS Services:"
+ << std::hex << its_offer.first;
+ for (auto its_instance : its_offer.second) {
+ VSOMEIP_INFO << "policy::print Instances: ";
+ VSOMEIP_INFO << "policy::print first: 0x"
+ << std::hex << its_instance.lower()
+ << " last: 0x" << its_instance.upper();
+ }
+ }
+}
+
+} // namespace vsomeip_v3
diff --git a/implementation/security/src/policy_manager_impl.cpp b/implementation/security/src/policy_manager_impl.cpp
index 7789fcc..a816714 100644
--- a/implementation/security/src/policy_manager_impl.cpp
+++ b/implementation/security/src/policy_manager_impl.cpp
@@ -20,67 +20,17 @@ policy_manager_impl::create_policy() const {
void
policy_manager_impl::print_policy(const std::shared_ptr<policy> &_policy) const {
- for (auto its_credential : _policy->ids_) {
- for (auto its_range : std::get<0>(its_credential)) {
- if (std::get<0>(its_range) == 0xFFFFFFFF) {
- VSOMEIP_INFO << "print_policy Security configuration: UID: any";
- } else {
- VSOMEIP_INFO << "print_policy Security configuration: UID: 0x"
- << std::hex << std::get<0>(its_range);
- }
- }
- for (auto its_range : std::get<1>(its_credential)) {
- if (std::get<0>(its_range) == 0xFFFFFFFF) {
- VSOMEIP_INFO << "print_policy Security configuration: GID: any";
- } else {
- VSOMEIP_INFO << "print_policy Security configuration: GID: 0x"
- << std::hex << std::get<0>(its_range);
- }
- }
- }
-
- VSOMEIP_INFO << "print_policy Security configuration: RQUESTS POLICY SIZE: "
- << std::dec << _policy->services_.size();
- for (auto its_offer : _policy->services_) {
- VSOMEIP_INFO << "print_policy ALLOWED REQUESTS Service: 0x"
- << std::hex << std::get<0>(its_offer);
- for (auto its_ids : std::get<1>(its_offer)) {
- VSOMEIP_INFO << "print_policy Instances: ";
- for (auto its_instance_range : std::get<0>(its_ids)) {
- VSOMEIP_INFO << "print_policy first: 0x"
- << std::hex << std::get<0>(its_instance_range)
- << " last: 0x" << std::get<1>(its_instance_range);
- }
- VSOMEIP_INFO << "print_policy Methods: ";
- for (auto its_method_range : std::get<1>(its_ids)) {
- VSOMEIP_INFO << "print_policy first: 0x"
- << std::hex << std::get<0>(its_method_range)
- << " last: 0x" << std::get<1>(its_method_range);
- }
- }
- }
-
- VSOMEIP_INFO << "print_policy Security configuration: OFFER POLICY SIZE: "
- << std::dec << _policy->offers_.size();
- for (auto its_offer : _policy->offers_) {
- VSOMEIP_INFO << "print_policy ALLOWED OFFERS Service: 0x"
- << std::hex << std::get<0>(its_offer);
- for (auto its_ids : std::get<1>(its_offer)) {
- VSOMEIP_INFO << "print_policy Instances: ";
- VSOMEIP_INFO << "print_policy first: 0x"
- << std::hex << std::get<0>(its_ids)
- << " last: 0x" << std::get<1>(its_ids);
- }
- }
+ if (_policy)
+ _policy->print();
}
bool
-policy_manager_impl::parse_uid_gid(const byte_t* &_buffer, uint32_t &_buffer_size,
- uint32_t &_uid, uint32_t &_gid) const {
+policy_manager_impl::parse_uid_gid(const byte_t* &_buffer,
+ uint32_t &_buffer_size, uint32_t &_uid, uint32_t &_gid) const {
- auto its_security = security_impl::get();
- return (its_security
- && its_security->parse_uid_gid(_buffer, _buffer_size, _uid, _gid));
+ const auto its_policy = std::make_shared<policy>();
+ return (its_policy
+ && its_policy->deserialize_uid_gid(_buffer, _buffer_size, _uid, _gid));
}
bool
diff --git a/implementation/security/src/security_impl.cpp b/implementation/security/src/security_impl.cpp
index ef1404d..12bb9db 100644
--- a/implementation/security/src/security_impl.cpp
+++ b/implementation/security/src/security_impl.cpp
@@ -3,16 +3,18 @@
// License, v. 2.0. If a copy of the MPL was not distributed with this
// file, You can obtain one at http://mozilla.org/MPL/2.0/.
+#include <sstream>
+
#ifdef _WIN32
#define WIN32_LEAN_AND_MEAN
+ #define NOMINMAX
#include <windows.h>
#include <stdlib.h>
- #define bswap_16(x) _byteswap_ushort(x)
- #define bswap_32(x) _byteswap_ulong(x)
-#else
- #include <byteswap.h>
#endif
+#include <algorithm>
+
+#include <vsomeip/internal/policy_manager.hpp>
#include "../include/security_impl.hpp"
#include "../../configuration/include/configuration_element.hpp"
#ifdef ANDROID
@@ -23,16 +25,19 @@
namespace vsomeip_v3 {
-static const std::uint8_t uid_width_ = sizeof(std::uint32_t);
-static const std::uint8_t gid_width_ = sizeof(std::uint32_t);
-static const std::uint8_t id_width_ = sizeof(std::uint16_t);
-static const std::uint8_t range_width_ = sizeof(std::uint32_t);
+template<typename T_>
+void read_data(const std::string &_in, T_ &_out) {
+ std::stringstream its_converter;
+
+ if (_in.size() > 2
+ && _in[0] == '0'
+ && (_in[1] == 'x' || _in[1] == 'X'))
+ its_converter << std::hex << _in;
+ else
+ its_converter << std::dec << _in;
-static const std::uint8_t skip_union_length_ = sizeof(std::uint32_t);
-static const std::uint8_t skip_union_type_ = sizeof(std::uint32_t);
-static const std::uint8_t skip_union_length_type_ = sizeof(std::uint32_t) + sizeof(std::uint32_t);
-static const std::uint8_t skip_struct_length_ = sizeof(std::uint32_t);
-static const std::uint8_t skip_array_length_ = sizeof(std::uint32_t);
+ its_converter >> _out;
+}
security_impl::security_impl()
: policy_enabled_(false),
@@ -67,8 +72,9 @@ security_impl::is_audit() const {
}
bool
-security_impl::check_credentials(client_t _client, uid_t _uid,
- gid_t _gid) {
+security_impl::check_credentials(client_t _client,
+ uid_t _uid, gid_t _gid) {
+
if (!policy_enabled_) {
return true;
}
@@ -82,27 +88,18 @@ security_impl::check_credentials(client_t _client, uid_t _uid,
for (const auto &p : its_policies) {
std::lock_guard<std::mutex> its_policy_lock(p->mutex_);
- for (auto its_credential : p->ids_) {
- bool has_uid(false), has_gid(false);
- for (auto its_range : std::get<0>(its_credential)) {
- if (std::get<0>(its_range) <= _uid && _uid <= std::get<1>(its_range)) {
- has_uid = true;
- break;
- }
- }
- for (auto its_range : std::get<1>(its_credential)) {
- if (std::get<0>(its_range) <= _gid && _gid <= std::get<1>(its_range)) {
- has_gid = true;
- break;
- }
- }
- if (has_uid && has_gid) {
- has_id = true;
- break;
- }
+ bool has_uid, has_gid(false);
+
+ const auto found_uid = p->credentials_.find(_uid);
+ has_uid = (found_uid != p->credentials_.end());
+ if (has_uid) {
+ const auto found_gid = found_uid->second.find(_gid);
+ has_gid = (found_gid != found_uid->second.end());
}
+ has_id = (has_uid && has_gid);
+
if ((has_id && p->allow_who_) || (!has_id && !p->allow_who_)) {
if (!store_client_to_uid_gid_mapping(_client,_uid, _gid)) {
std::string security_mode_text = "!";
@@ -132,8 +129,10 @@ security_impl::check_credentials(client_t _client, uid_t _uid,
}
bool
-security_impl::is_client_allowed(uint32_t _uid, uint32_t _gid, client_t _client, service_t _service,
- instance_t _instance, method_t _method, bool _is_request_service) const {
+security_impl::is_client_allowed(uint32_t _uid, uint32_t _gid, client_t _client,
+ service_t _service, instance_t _instance, method_t _method,
+ bool _is_request_service) const {
+
if (!policy_enabled_) {
return true;
}
@@ -145,8 +144,7 @@ security_impl::is_client_allowed(uint32_t _uid, uint32_t _gid, client_t _client,
its_policies = any_client_policies_;
}
- if (_uid != ANY_UID
- && _gid != ANY_GID) {
+ if (_uid != ANY_UID && _gid != ANY_GID) {
its_uid = _uid;
its_gid = _gid;
} else {
@@ -165,51 +163,27 @@ security_impl::is_client_allowed(uint32_t _uid, uint32_t _gid, client_t _client,
for (const auto &p : its_policies) {
std::lock_guard<std::mutex> its_policy_lock(p->mutex_);
- bool has_uid(false), has_gid(false), has_service(false), has_instance_id(false), has_method_id(false);
- for (auto its_credential : p->ids_) {
- has_uid = has_gid = false;
- for (auto its_range : std::get<0>(its_credential)) {
- if (std::get<0>(its_range) <= its_uid && its_uid <= std::get<1>(its_range)) {
- has_uid = true;
- break;
- }
- }
- for (auto its_range : std::get<1>(its_credential)) {
- if (std::get<0>(its_range) <= its_gid && its_gid <= std::get<1>(its_range)) {
- has_gid = true;
- break;
- }
- }
- if (has_uid && has_gid)
- break;
+ bool has_uid, has_gid(false);
+ bool is_matching(false);
+
+ const auto found_uid = p->credentials_.find(_uid);
+ has_uid = (found_uid != p->credentials_.end());
+ if (has_uid) {
+ const auto found_gid = found_uid->second.find(_gid);
+ has_gid = (found_gid != found_uid->second.end());
}
- auto its_service = p->services_.find(_service);
- if (its_service != p->services_.end()) {
- for (auto its_ids : its_service->second) {
- has_service = has_instance_id = has_method_id = false;
- for (auto its_instance_range : std::get<0>(its_ids)) {
- if (std::get<0>(its_instance_range) <= _instance && _instance <= std::get<1>(its_instance_range)) {
- has_instance_id = true;
- break;
- }
- }
+ const auto found_service = p->requests_.find(_service);
+ if (found_service != p->requests_.end()) {
+ const auto found_instance = found_service->second.find(_instance);
+ if (found_instance != found_service->second.end()) {
if (!_is_request_service) {
- for (auto its_method_range : std::get<1>(its_ids)) {
- if (std::get<0>(its_method_range) <= _method && _method <= std::get<1>(its_method_range)) {
- has_method_id = true;
- break;
- }
- }
+ const auto found_method = found_instance->second.find(_method);
+ is_matching = (found_method != found_instance->second.end());
} else {
// handle VSOMEIP_REQUEST_SERVICE
- has_method_id = true;
- }
-
- if (has_instance_id && has_method_id) {
- has_service = true;
- break;
+ is_matching = true;
}
}
}
@@ -217,17 +191,17 @@ security_impl::is_client_allowed(uint32_t _uid, uint32_t _gid, client_t _client,
if ((has_uid && has_gid && p->allow_who_) || ((!has_uid || !has_gid) && !p->allow_who_)) {
if (p->allow_what_) {
// allow policy
- if (has_service) {
- return true;
+ if (is_matching) {
+ return (true);
}
} else {
// deny policy
// allow client if the service / instance / !ANY_METHOD was not found
- if ((!has_service && (_method != ANY_METHOD))
+ if ((!is_matching && (_method != ANY_METHOD))
// allow client if the service / instance / ANY_METHOD was not found
// and it is a "deny nothing" policy
- || (!has_service && (_method == ANY_METHOD) && p->services_.empty())) {
- return true;
+ || (!is_matching && (_method == ANY_METHOD) && p->requests_.empty())) {
+ return (true);
}
}
}
@@ -244,7 +218,7 @@ security_impl::is_client_allowed(uint32_t _uid, uint32_t _gid, client_t _client,
<< _service << "/" << _instance << "/" << _method
<< security_mode_text;
- return !check_credentials_;
+ return (!check_credentials_);
}
bool
@@ -281,41 +255,25 @@ security_impl::is_offer_allowed(uint32_t _uid, uint32_t _gid, client_t _client,
for (const auto &p : its_policies) {
std::lock_guard<std::mutex> its_policy_lock(p->mutex_);
- bool has_uid(false), has_gid(false), has_offer(false);
- for (auto its_credential : p->ids_) {
- has_uid = has_gid = false;
- for (auto its_range : std::get<0>(its_credential)) {
- if (std::get<0>(its_range) <= its_uid && its_uid <= std::get<1>(its_range)) {
- has_uid = true;
- break;
- }
- }
- for (auto its_range : std::get<1>(its_credential)) {
- if (std::get<0>(its_range) <= its_gid && its_gid <= std::get<1>(its_range)) {
- has_gid = true;
- break;
- }
- }
+ bool has_uid, has_gid(false), has_offer(false);
- if (has_uid && has_gid)
- break;
+ const auto found_uid = p->credentials_.find(_uid);
+ has_uid = (found_uid != p->credentials_.end());
+ if (has_uid) {
+ const auto found_gid = found_uid->second.find(_gid);
+ has_gid = (found_gid != found_uid->second.end());
}
- auto find_service = p->offers_.find(_service);
- if (find_service != p->offers_.end()) {
- for (auto its_instance_range : find_service->second) {
- if (std::get<0>(its_instance_range) <= _instance
- && _instance <= std::get<1>(its_instance_range)) {
- has_offer = true;
- break;
- }
- }
+ const auto found_service = p->offers_.find(_service);
+ if (found_service != p->offers_.end()) {
+ const auto found_instance = found_service->second.find(_instance);
+ has_offer = (found_instance != found_service->second.end());
}
if ((has_uid && has_gid && p->allow_who_)
|| ((!has_uid || !has_gid) && !p->allow_who_)) {
if (p->allow_what_ == has_offer) {
- return true;
+ return (true);
}
}
}
@@ -325,13 +283,15 @@ security_impl::is_offer_allowed(uint32_t _uid, uint32_t _gid, client_t _client,
security_mode_text = " but will be allowed due to audit mode is active!";
}
- VSOMEIP_INFO << "vSomeIP Security: Client 0x" << std::hex << _client
- << " with UID/GID=" << std::dec << its_uid << "/" << its_gid
- << " isn't allowed to offer service/instance " << std::hex
- << _service << "/" << _instance
+ VSOMEIP_INFO << "vSomeIP Security: Client 0x"
+ << std::hex << _client
+ << " with UID/GID="
+ << std::dec << its_uid << "/" << its_gid
+ << " isn't allowed to offer service/instance "
+ << std::hex << _service << "/" << _instance
<< security_mode_text;
- return !check_credentials_;
+ return (!check_credentials_);
}
bool
@@ -456,45 +416,81 @@ security_impl::remove_security_policy(uint32_t _uid, uint32_t _gid) {
if (!any_client_policies_.empty()) {
std::vector<std::shared_ptr<policy>>::iterator p_it = any_client_policies_.begin();
while (p_it != any_client_policies_.end()) {
- std::lock_guard<std::mutex> its_policy_lock((*p_it)->mutex_);
- bool has_uid(false), has_gid(false);
- for (auto its_credential : p_it->get()->ids_) {
- has_uid = has_gid = false;
- for (auto its_range : std::get<0>(its_credential)) {
- if (std::get<0>(its_range) <= _uid && _uid <= std::get<1>(its_range)) {
- has_uid = true;
- break;
- }
- }
- for (auto its_range : std::get<1>(its_credential)) {
- if (std::get<0>(its_range) <= _gid && _gid <= std::get<1>(its_range)) {
- has_gid = true;
- break;
- }
+ bool is_matching(false);
+ {
+ std::lock_guard<std::mutex> its_policy_lock((*p_it)->mutex_);
+ bool has_uid(false), has_gid(false);
+ const auto found_uid = (*p_it)->credentials_.find(_uid);
+ has_uid = (found_uid != (*p_it)->credentials_.end());
+ if (has_uid) {
+ const auto found_gid = found_uid->second.find(_gid);
+ has_gid = (found_gid != found_uid->second.end());
}
+
// only remove "credentials allow" policies to prevent removal of
// blacklist configured in file
- if (has_uid && has_gid && p_it->get()->allow_who_) {
- was_removed = true;
- break;
+ if (has_uid && has_gid && (*p_it)->allow_who_) {
+ is_matching = true;
}
}
- if (was_removed) {
+ if (is_matching) {
+ was_removed = true;
p_it = any_client_policies_.erase(p_it);
- break;
} else {
++p_it;
}
}
}
- return was_removed;
+ return (was_removed);
}
void
-security_impl::update_security_policy(uint32_t _uid, uint32_t _gid, const std::shared_ptr<policy> &_policy) {
- remove_security_policy(_uid, _gid);
+security_impl::update_security_policy(uint32_t _uid, uint32_t _gid,
+ const std::shared_ptr<policy> &_policy) {
+
std::lock_guard<std::mutex> its_lock(any_client_policies_mutex_);
- any_client_policies_.push_back(_policy);
+ std::shared_ptr<policy> its_matching_policy;
+ for (auto p : any_client_policies_) {
+ if (p->credentials_.size() == 1) {
+ const auto its_uids = *(p->credentials_.begin());
+ if (its_uids.first.lower() == _uid
+ && its_uids.first.upper() == _uid) {
+ if (its_uids.second.size() == 1) {
+ const auto its_gids = *(its_uids.second.begin());
+ if (its_gids.lower() == _gid
+ && its_gids.upper() == _gid) {
+ if (p->allow_who_ == _policy->allow_who_) {
+ its_matching_policy = p;
+ break;
+ }
+ }
+ }
+ }
+ }
+ }
+
+ if (its_matching_policy) {
+ for (const auto r : _policy->requests_) {
+ service_t its_lower, its_upper;
+ get_bounds(r.first, its_lower, its_upper);
+ for (auto s = its_lower; s <= its_upper; s++) {
+ boost::icl::discrete_interval<service_t> its_service(s, s,
+ boost::icl::interval_bounds::closed());
+ its_matching_policy->requests_ += std::make_pair(its_service, r.second);
+ }
+ }
+ for (const auto o : _policy->offers_) {
+ service_t its_lower, its_upper;
+ get_bounds(o.first, its_lower, its_upper);
+ for (auto s = its_lower; s <= its_upper; s++) {
+ boost::icl::discrete_interval<service_t> its_service(s, s,
+ boost::icl::interval_bounds::closed());
+ its_matching_policy->offers_ += std::make_pair(its_service, o.second);
+ }
+ }
+ } else {
+ any_client_policies_.push_back(_policy);
+ }
}
void
@@ -504,32 +500,24 @@ security_impl::add_security_credentials(uint32_t _uid, uint32_t _gid,
bool was_found(false);
std::lock_guard<std::mutex> its_lock(any_client_policies_mutex_);
for (const auto &p : any_client_policies_) {
- std::lock_guard<std::mutex> its_policy_lock(p->mutex_);
bool has_uid(false), has_gid(false);
- for (auto its_credential : p->ids_) {
- has_uid = has_gid = false;
- for (auto its_range : std::get<0>(its_credential)) {
- if (std::get<0>(its_range) <= _uid && _uid <= std::get<1>(its_range)) {
- has_uid = true;
- break;
- }
- }
- for (auto its_range : std::get<1>(its_credential)) {
- if (std::get<0>(its_range) <= _gid && _gid <= std::get<1>(its_range)) {
- has_gid = true;
- break;
- }
- }
- if (has_uid && has_gid && p->allow_who_) {
- was_found = true;
- break;
- }
+
+ std::lock_guard<std::mutex> its_policy_lock(p->mutex_);
+ const auto found_uid = p->credentials_.find(_uid);
+ has_uid = (found_uid != p->credentials_.end());
+ if (has_uid) {
+ const auto found_gid = found_uid->second.find(_gid);
+ has_gid = (found_gid != found_uid->second.end());
}
- if (was_found) {
+
+ if (has_uid && has_gid && p->allow_who_) {
+ was_found = true;
break;
}
}
- // Do not add the new (credentials-only-policy) if a allow credentials policy with same credentials was found
+
+ // Do not add the new (credentials-only-policy) if a allow
+ // credentials policy with same credentials was found
if (!was_found) {
any_client_policies_.push_back(_policy);
VSOMEIP_INFO << __func__ << " Added security credentials at client: 0x"
@@ -546,66 +534,46 @@ security_impl::is_remote_client_allowed() const {
}
bool
-security_impl::parse_uid_gid(const byte_t* &_buffer, uint32_t &_buffer_size,
- uint32_t &_uid, uint32_t &_gid) const {
-
- uint32_t its_uid = ANY_UID;
- uint32_t its_gid = ANY_GID;
-
- if (_buffer_size >= sizeof(uint32_t) * 2) {
- std::memcpy(&its_uid, _buffer, sizeof(uint32_t));
- _uid = bswap_32(its_uid);
-
- std::memcpy(&its_gid, _buffer + sizeof(uint32_t), sizeof(uint32_t));
- _gid = bswap_32(its_gid);
-
- _buffer_size -= (uid_width_ + gid_width_);
- _buffer += (uid_width_ + gid_width_);
- return true;
- }
- return false;
-}
-
-bool
security_impl::is_policy_update_allowed(uint32_t _uid, std::shared_ptr<policy> &_policy) const {
- bool uid_allowed(false);
+
+ bool is_uid_allowed(false);
{
std::lock_guard<std::mutex> its_lock(uid_whitelist_mutex_);
- for (auto its_uid_range : uid_whitelist_) {
- if (std::get<0>(its_uid_range) <= _uid && _uid <= std::get<1>(its_uid_range)) {
- uid_allowed = true;
- break;
- }
- }
+ const auto found_uid = uid_whitelist_.find(_uid);
+ is_uid_allowed = (found_uid != uid_whitelist_.end());
}
- if (uid_allowed) {
+ if (is_uid_allowed) {
std::lock_guard<std::mutex> its_lock(service_interface_whitelist_mutex_);
std::lock_guard<std::mutex> its_policy_lock(_policy->mutex_);
- for (auto its_request : _policy->services_) {
- auto its_requested_service = std::get<0>(its_request);
+ for (auto its_request : _policy->requests_) {
bool has_service(false);
- for (auto its_service_range : service_interface_whitelist_) {
- if (std::get<0>(its_service_range) <= its_requested_service
- && its_requested_service <= std::get<1>(its_service_range)) {
- has_service = true;
+
+ service_t its_service(0);
+ for (its_service = its_request.first.lower();
+ its_service <= its_request.first.upper();
+ its_service++) {
+
+ const auto found_service = service_interface_whitelist_.find(its_service);
+ has_service = (found_service != service_interface_whitelist_.end());
+ if (!has_service)
break;
- }
}
+
if (!has_service) {
if (!check_whitelist_) {
VSOMEIP_INFO << "vSomeIP Security: Policy update requesting service ID: "
- << std::hex << its_requested_service
+ << std::hex << its_service
<< " is not allowed, but will be allowed due to whitelist audit mode is active!";
} else {
VSOMEIP_WARNING << "vSomeIP Security: Policy update requesting service ID: "
- << std::hex << its_requested_service
+ << std::hex << its_service
<< " is not allowed! -> ignore update";
}
- return !check_whitelist_;
+ return (!check_whitelist_);
}
}
- return true;
+ return (true);
} else {
if (!check_whitelist_) {
VSOMEIP_INFO << "vSomeIP Security: Policy update for UID: " << std::dec << _uid
@@ -614,7 +582,7 @@ security_impl::is_policy_update_allowed(uint32_t _uid, std::shared_ptr<policy> &
VSOMEIP_WARNING << "vSomeIP Security: Policy update for UID: " << std::dec << _uid
<< " is not allowed! -> ignore update";
}
- return !check_whitelist_;
+ return (!check_whitelist_);
}
}
@@ -622,388 +590,59 @@ bool
security_impl::is_policy_removal_allowed(uint32_t _uid) const {
std::lock_guard<std::mutex> its_lock(uid_whitelist_mutex_);
for (auto its_uid_range : uid_whitelist_) {
- if (std::get<0>(its_uid_range) <= _uid && _uid <= std::get<1>(its_uid_range)) {
- return true;
+ if (its_uid_range.lower() <= _uid && _uid <= its_uid_range.upper()) {
+ return (true);
}
}
if (!check_whitelist_) {
- VSOMEIP_INFO << "vSomeIP Security: Policy removal for UID: " << std::dec << _uid
+ VSOMEIP_INFO << "vSomeIP Security: Policy removal for UID: "
+ << std::dec << _uid
<< " is not allowed, but will be allowed due to whitelist audit mode is active!";
} else {
- VSOMEIP_WARNING << "vSomeIP Security: Policy removal for UID: " << std::dec << _uid
+ VSOMEIP_WARNING << "vSomeIP Security: Policy removal for UID: "
+ << std::dec << _uid
<< " is not allowed! -> ignore removal";
}
- return !check_whitelist_;
+ return (!check_whitelist_);
}
bool
-security_impl::check_routing_credentials(client_t _client, uint32_t _uid, uint32_t _gid) const {
+security_impl::check_routing_credentials(client_t _client,
+ uint32_t _uid, uint32_t _gid) const {
+
std::lock_guard<std::mutex> its_lock(routing_credentials_mutex_);
- if ( std::get<0>(routing_credentials_) == _uid
- && std::get<1>(routing_credentials_) == _gid) {
- return true;
+ if (routing_credentials_.first == _uid
+ && routing_credentials_.second == _gid) {
+
+ return (true);
}
std::string security_mode_text = "!";
if (!check_routing_credentials_) {
+
security_mode_text = " but will be allowed due to audit mode is active!";
}
+
VSOMEIP_INFO << "vSomeIP Security: Client 0x"
- << std::hex << _client << " and UID/GID=" << std::dec << _uid
- << "/" << _gid << " : Check routing credentials failed as "
+ << std::hex << _client << " and UID/GID="
+ << std::dec << _uid << "/" << _gid
+ << " : Check routing credentials failed as "
<< "configured routing manager credentials "
<< "do not match with routing manager credentials"
<< security_mode_text;
- return !check_routing_credentials_;
+ return (!check_routing_credentials_);
}
bool
security_impl::parse_policy(const byte_t* &_buffer, uint32_t &_buffer_size,
uint32_t &_uid, uint32_t &_gid, const std::shared_ptr<policy> &_policy) const {
- uint32_t its_uid = ANY_UID;
- uint32_t its_gid = ANY_GID;
- bool has_error(false);
-
- // get user ID String
- if (parse_uid_gid(_buffer, _buffer_size, its_uid, its_gid)) {
- std::lock_guard<std::mutex> its_policy_lock(_policy->mutex_);
-
- _uid = its_uid;
- _gid = its_gid;
-
- // policy elements
- std::pair<uint32_t, uint32_t> its_uid_range, its_gid_range;
- std::set<std::pair<uint32_t, uint32_t>> its_uids, its_gids;
-
- // fill uid and gid range
- std::get<0>(its_uid_range) = its_uid;
- std::get<1>(its_uid_range) = its_uid;
- std::get<0>(its_gid_range) = its_gid;
- std::get<1>(its_gid_range) = its_gid;
- its_uids.insert(its_uid_range);
- its_gids.insert(its_gid_range);
-
- _policy->ids_.insert(std::make_pair(its_uids, its_gids));
- _policy->allow_who_ = true;
- _policy->allow_what_ = true;
-
- // get struct AclUpdate
- uint32_t acl_length = 0;
- if (get_struct_length(_buffer, _buffer_size, acl_length)) {
- // get requests array length
- uint32_t requests_array_length = 0;
- if (get_array_length(_buffer, _buffer_size, requests_array_length)) {
- // loop through requests array consisting of n x "struct Request"
- uint32_t parsed_req_bytes = 0;
- while (parsed_req_bytes + skip_struct_length_ <= requests_array_length) {
- // get request struct length
- uint32_t req_length = 0;
- if (get_struct_length(_buffer, _buffer_size, req_length)) {
- if (req_length != 0)
- parsed_req_bytes += skip_struct_length_;
-
- uint16_t its_service_id = 0;
- ids_t its_instance_method_ranges;
- // get serviceID
- if (!parse_id(_buffer, _buffer_size, its_service_id)) {
- has_error = true;
- } else {
- if (its_service_id == 0x00
- || its_service_id == 0xFFFF) {
- VSOMEIP_WARNING << std::hex << "vSomeIP Security: Policy with service ID: 0x"
- << its_service_id << " is not allowed!";
- return false;
- }
- // add length of serviceID
- parsed_req_bytes += id_width_;
- }
-
- // get instances array length
- uint32_t instances_array_length = 0;
- if (get_array_length(_buffer, _buffer_size, instances_array_length)) {
- // loop trough instances array consisting of n x "struct Instance"
- uint32_t parsed_inst_bytes = 0;
- while (parsed_inst_bytes + skip_struct_length_ <= instances_array_length) {
- // get instance struct length
- uint32_t inst_length = 0;
- if (get_struct_length(_buffer, _buffer_size, inst_length)) {
- if (inst_length != 0)
- parsed_inst_bytes += skip_struct_length_;
-
- ranges_t its_instance_ranges;
- ranges_t its_method_ranges;
- // get "IdItem[] ids" array length
- uint32_t ids_array_length = 0;
- if (get_array_length(_buffer, _buffer_size, ids_array_length)) {
- uint32_t parsed_ids_bytes = 0;
- while (parsed_ids_bytes + skip_struct_length_ <= ids_array_length) {
- if (!parse_id_item(_buffer, parsed_ids_bytes, its_instance_ranges, _buffer_size)) {
- return false;
- }
- }
- parsed_inst_bytes += (skip_array_length_ + ids_array_length);
- }
- // get "IdItem[] methods" array length
- uint32_t methods_array_length = 0;
- if (get_array_length(_buffer, _buffer_size, methods_array_length)) {
- uint32_t parsed_method_bytes = 0;
- while (parsed_method_bytes + skip_struct_length_ <= methods_array_length) {
- if (!parse_id_item(_buffer, parsed_method_bytes, its_method_ranges, _buffer_size)) {
- return false;
- }
- }
- if (!its_instance_ranges.empty() && !its_method_ranges.empty()) {
- its_instance_method_ranges.insert(std::make_pair(its_instance_ranges, its_method_ranges));
- }
- parsed_inst_bytes += (skip_array_length_ + methods_array_length);
- }
- }
- }
- parsed_req_bytes += (skip_array_length_ + instances_array_length);
- }
- if (!its_instance_method_ranges.empty()) {
- auto find_service = _policy->services_.find(its_service_id);
- if (find_service != _policy->services_.end()) {
- find_service->second.insert(its_instance_method_ranges.begin(),
- its_instance_method_ranges.end());
- } else {
- _policy->services_.insert(
- std::make_pair(its_service_id, its_instance_method_ranges));
- }
- }
- }
- }
- }
- // get offers array length
- uint32_t offers_array_length = 0;
- if (get_array_length(_buffer, _buffer_size, offers_array_length)){
- // loop through offers array
- uint32_t parsed_offers_bytes = 0;
- while (parsed_offers_bytes + skip_struct_length_ <= offers_array_length) {
- // get service ID
- uint16_t its_service_id = 0;
- ranges_t its_instance_ranges;
- // get serviceID
- if (!parse_id(_buffer, _buffer_size, its_service_id)) {
- has_error = true;
- } else {
- if (its_service_id == 0x00
- || its_service_id == 0xFFFF) {
- VSOMEIP_WARNING << std::hex << "vSomeIP Security: Policy with service ID: 0x"
- << its_service_id << " is not allowed!";
- return false;
- }
- // add length of serviceID
- parsed_offers_bytes += id_width_;
- }
-
- // get "IdItem[] ids" array length
- uint32_t ids_array_length = 0;
- if (get_array_length(_buffer, _buffer_size, ids_array_length)) {
- uint32_t parsed_ids_bytes = 0;
- while (parsed_ids_bytes + skip_struct_length_ <= ids_array_length) {
- if (!parse_id_item(_buffer, parsed_ids_bytes, its_instance_ranges, _buffer_size)) {
- return false;
- }
- }
- parsed_offers_bytes += (skip_array_length_ + ids_array_length);
- }
- if (!its_instance_ranges.empty()) {
- auto find_service = _policy->offers_.find(its_service_id);
- if (find_service != _policy->offers_.end()) {
- find_service->second.insert(its_instance_ranges.begin(),
- its_instance_ranges.end());
- } else {
- _policy->offers_.insert(
- std::make_pair(its_service_id, its_instance_ranges));
- }
- }
- }
- }
- } else {
- VSOMEIP_WARNING << std::hex << "vSomeIP Security: Policy with empty request / offer section is not allowed!";
- has_error = true;
- }
- } else {
- VSOMEIP_WARNING << std::hex << "vSomeIP Security: Policy without UID / GID is not allowed!";
- has_error = true;
- }
-
- if (!has_error)
- return true;
- else
- return false;
-}
-
-bool
-security_impl::get_struct_length(const byte_t* &_buffer, uint32_t &_buffer_size, uint32_t &_length) const {
- uint32_t its_length = 0;
- bool length_field_deployed(false);
- // [TR_SOMEIP_00080] d If the length of the length field is not specified, a length of 0
- // has to be assumed and no length field is in the message.
- if (length_field_deployed) {
- if (_buffer_size >= sizeof(uint32_t)) {
- std::memcpy(&its_length, _buffer, sizeof(uint32_t));
- _length = bswap_32(its_length);
- _buffer_size -= skip_struct_length_;
- _buffer += skip_struct_length_;
- return true;
- }
- } else {
- _length = 0;
- return true;
- }
-
- return false;
-}
-
-bool
-security_impl::get_union_length(const byte_t* &_buffer, uint32_t &_buffer_size, uint32_t &_length) const {
- uint32_t its_length = 0;
-
- // [TR_SOMEIP_00125] d If the Interface Specification does not specify the length of the
- // length field for a union, 32 bit length of the length field shall be used.
- if (_buffer_size >= sizeof(uint32_t)) {
- std::memcpy(&its_length, _buffer, sizeof(uint32_t));
- _length = bswap_32(its_length);
- _buffer_size -= skip_union_length_;
- _buffer += skip_union_length_;
- return true;
- }
- return false;
-}
-
-bool
-security_impl::get_array_length(const byte_t* &_buffer, uint32_t &_buffer_size, uint32_t &_length) const {
-
- uint32_t its_length = 0;
-
- // [TR_SOMEIP_00106] d The layout of arrays with dynamic length basically is based on
- // the layout of fixed length arrays. To determine the size of the array the serialization
- // adds a length field (default length 32 bit) in front of the data, which counts the bytes
- // of the array. The length does not include the size of the length field. Thus, when
- // transporting an array with zero elements the length is set to zero.
- if (_buffer_size >= sizeof(uint32_t)) {
- std::memcpy(&its_length, _buffer, sizeof(uint32_t));
- _length = bswap_32(its_length);
- _buffer_size -= skip_array_length_;
- _buffer += skip_array_length_;
- return true;
- }
- return false;
-}
-
-bool
-security_impl::is_range(const byte_t* &_buffer, uint32_t &_buffer_size) const {
-
- uint32_t its_type = 0;
-
- // [TR_SOMEIP_00128] If the Interface Specification does not specify the length of the
- // type field of a union, 32 bit length of the type field shall be used.
- if (_buffer_size >= sizeof(uint32_t)) {
- std::memcpy(&its_type, _buffer, sizeof(uint32_t));
- its_type = bswap_32(its_type);
- _buffer_size -= skip_union_type_;
- _buffer += skip_union_type_;
- if (its_type == 0x02) {
- return true;
- } else {
- return false;
- }
- }
- return false;
-}
-
-bool
-security_impl::parse_id_item(const byte_t* &_buffer, uint32_t& parsed_ids_bytes,
- ranges_t& its_ranges, uint32_t &_buffer_size) const {
-
- // get "union IdItem" length
- uint32_t iditem_length = 0;
- if (get_union_length(_buffer, _buffer_size, iditem_length)) {
- // determine type of union
- uint16_t its_first = 0;
- uint16_t its_last = 0;
- if (is_range(_buffer, _buffer_size)) {
- // get range of instance IDs "struct IdRange" length
- uint32_t range_length = 0;
- if (get_struct_length(_buffer, _buffer_size, range_length)) {
- // read first and last instance range
- if (parse_range(_buffer, _buffer_size, its_first, its_last)) {
- its_ranges.insert(std::make_pair(its_first, its_last));
- } else {
- return false;
- }
- }
- } else {
- // a single instance ID
- if (parse_id(_buffer, _buffer_size, its_first)) {
- if (its_first != ANY_METHOD) {
- if (its_first != 0x00) {
- its_last = its_first;
- its_ranges.insert(std::make_pair(its_first, its_last));
- } else {
- return false;
- }
- } else {
- its_first = 0x01;
- its_last = 0xFFFE;
- its_ranges.insert(std::make_pair(its_first, its_last));
- }
- }
- }
- parsed_ids_bytes += (skip_union_length_type_ + iditem_length);
- }
- return true;
-}
-
-bool
-security_impl::parse_range(const byte_t* &_buffer, uint32_t &_buffer_size,
- uint16_t &_first, uint16_t &_last) const {
-
- uint16_t its_first = 0;
- uint16_t its_last = 0;
-
- if (_buffer_size >= sizeof(uint16_t) * 2) {
- if (parse_id(_buffer, _buffer_size, its_first)) {
- _first = its_first;
- }
- if (parse_id(_buffer, _buffer_size, its_last)) {
- _last = its_last;
- }
- if (_first != _last
- && (_first == ANY_METHOD || _last == ANY_METHOD)) {
- return false;
- }
- if (_first != 0x0 && _last != 0x00
- && _first <= _last) {
- if (_first == ANY_METHOD &&
- _last == ANY_METHOD) {
- _first = 0x01;
- _last = 0xFFFE;
- }
- return true;
- } else {
- return false;
- }
- }
- return false;
-}
-
-bool
-security_impl::parse_id(const byte_t* &_buffer, uint32_t &_buffer_size, uint16_t &_id) const {
- uint16_t its_id = 0;
- if (_buffer_size >= sizeof(uint16_t)) {
- std::memcpy(&its_id, _buffer, sizeof(uint16_t));
- _id = bswap_16(its_id);
- _buffer_size -= id_width_;
- _buffer += id_width_;
- return true;
- }
- return false;
+ bool is_valid = _policy->deserialize(_buffer, _buffer_size);
+ if (is_valid)
+ is_valid = _policy->get_uid_gid(_uid, _gid);
+ return is_valid;
}
///////////////////////////////////////////////////////////////////////////////
@@ -1048,12 +687,15 @@ security_impl::load_policies(const configuration_element &_element) {
void
security_impl::load_policy(const boost::property_tree::ptree &_tree) {
+
std::shared_ptr<policy> policy(std::make_shared<policy>());
bool allow_deny_set(false);
for (auto i = _tree.begin(); i != _tree.end(); ++i) {
if (i->first == "credentials") {
- std::pair<uint32_t, uint32_t> its_uid_range, its_gid_range;
- ranges_t its_uid_ranges, its_gid_ranges;
+ boost::icl::interval_set<uid_t> its_uid_interval_set;
+ boost::icl::interval_set<gid_t> its_gid_interval_set;
+ boost::icl::discrete_interval<uid_t> its_uid_interval;
+ boost::icl::discrete_interval<gid_t> its_gid_interval;
bool has_uid(false), has_gid(false);
bool has_uid_range(false), has_gid_range(false);
@@ -1063,58 +705,62 @@ security_impl::load_policy(const boost::property_tree::ptree &_tree) {
std::string its_value(n->second.data());
if (its_key == "uid") {
if(n->second.data().empty()) {
- load_ranges(n->second, its_uid_ranges);
+ load_interval_set(n->second, its_uid_interval_set);
has_uid_range = true;
} else {
if (its_value != "any") {
uint32_t its_uid;
- std::stringstream its_converter;
- its_converter << std::dec << its_value;
- its_converter >> its_uid;
- std::get<0>(its_uid_range) = its_uid;
- std::get<1>(its_uid_range) = its_uid;
+ read_data(its_value, its_uid);
+ its_uid_interval = boost::icl::construct<
+ boost::icl::discrete_interval<uid_t> >(
+ its_uid, its_uid,
+ boost::icl::interval_bounds::closed());
} else {
- std::get<0>(its_uid_range) = 0;
- std::get<1>(its_uid_range) = 0xFFFFFFFF;
+ its_uid_interval = boost::icl::construct<
+ boost::icl::discrete_interval<uid_t> >(
+ std::numeric_limits<uid_t>::min(),
+ std::numeric_limits<uid_t>::max(),
+ boost::icl::interval_bounds::closed());
}
has_uid = true;
}
} else if (its_key == "gid") {
if(n->second.data().empty()) {
- load_ranges(n->second, its_gid_ranges);
+ load_interval_set(n->second, its_gid_interval_set);
has_gid_range = true;
} else {
if (its_value != "any") {
uint32_t its_gid;
- std::stringstream its_converter;
- its_converter << std::dec << its_value;
- its_converter >> its_gid;
- std::get<0>(its_gid_range) = its_gid;
- std::get<1>(its_gid_range) = its_gid;
+ read_data(its_value, its_gid);
+ its_gid_interval = boost::icl::construct<
+ boost::icl::discrete_interval<gid_t> >(
+ its_gid, its_gid,
+ boost::icl::interval_bounds::closed());
} else {
- std::get<0>(its_gid_range) = 0;
- std::get<1>(its_gid_range) = 0xFFFFFFFF;
+ its_gid_interval = boost::icl::construct<
+ boost::icl::discrete_interval<gid_t> >(
+ std::numeric_limits<gid_t>::min(),
+ std::numeric_limits<gid_t>::max(),
+ boost::icl::interval_bounds::closed());
}
has_gid = true;
}
} else if (its_key == "allow" || its_key == "deny") {
policy->allow_who_ = (its_key == "allow");
- load_credential(n->second, policy->ids_);
+ load_credential(n->second, policy->credentials_);
}
}
if (has_uid && has_gid) {
- std::set<std::pair<uint32_t, uint32_t>> its_uids, its_gids;
-
- its_uids.insert(its_uid_range);
- its_gids.insert(its_gid_range);
+ its_gid_interval_set.insert(its_gid_interval);
+ policy->credentials_ += std::make_pair(its_uid_interval, its_gid_interval_set);
policy->allow_who_ = true;
- policy->ids_.insert(std::make_pair(its_uids, its_gids));
}
if (has_uid_range && has_gid_range) {
+ for (const auto u : its_uid_interval_set)
+ policy->credentials_ += std::make_pair(u, its_gid_interval_set);
policy->allow_who_ = true;
- policy->ids_.insert(std::make_pair(its_uid_ranges, its_gid_ranges));
}
} else if (i->first == "allow") {
if (allow_deny_set) {
@@ -1124,112 +770,7 @@ security_impl::load_policy(const boost::property_tree::ptree &_tree) {
}
allow_deny_set = true;
policy->allow_what_ = true;
- for (auto l = i->second.begin(); l != i->second.end(); ++l) {
- if (l->first == "requests") {
- for (auto n = l->second.begin(); n != l->second.end(); ++n) {
- service_t service = 0x0;
- instance_t instance = 0x0;
- ids_t its_instance_method_ranges;
- for (auto k = n->second.begin(); k != n->second.end(); ++k) {
- std::stringstream its_converter;
- if (k->first == "service") {
- std::string value = k->second.data();
- its_converter << std::hex << value;
- its_converter >> service;
- } else if (k->first == "instance") { // legacy definition for instances
- ranges_t its_instance_ranges;
- ranges_t its_method_ranges;
- std::string value = k->second.data();
- if (value != "any") {
- its_converter << std::hex << value;
- its_converter >> instance;
- if (instance != 0x0) {
- its_instance_ranges.insert(std::make_pair(instance, instance));
- its_method_ranges.insert(std::make_pair(0x01, 0xFFFF));
- }
- } else {
- its_instance_ranges.insert(std::make_pair(0x01, 0xFFFF));
- its_method_ranges.insert(std::make_pair(0x01, 0xFFFF));
- }
- its_instance_method_ranges.insert(std::make_pair(its_instance_ranges, its_method_ranges));
- } else if (k->first == "instances") { // new instances definition
- for (auto p = k->second.begin(); p != k->second.end(); ++p) {
- ranges_t its_instance_ranges;
- ranges_t its_method_ranges;
- for (auto m = p->second.begin(); m != p->second.end(); ++m) {
- if (m->first == "ids") {
- load_instance_ranges(m->second, its_instance_ranges);
- } else if (m->first == "methods") {
- load_instance_ranges(m->second, its_method_ranges);
- }
- if (!its_instance_ranges.empty() && !its_method_ranges.empty()) {
- its_instance_method_ranges.insert(std::make_pair(its_instance_ranges, its_method_ranges));
- }
- }
- }
- if (its_instance_method_ranges.empty()) {
- ranges_t its_legacy_instance_ranges;
- ranges_t its_legacy_method_ranges;
- its_legacy_method_ranges.insert(std::make_pair(0x01, 0xFFFF));
- // try to only load instance ranges with any method to be allowed
- load_instance_ranges(k->second, its_legacy_instance_ranges);
- if (!its_legacy_instance_ranges.empty() && !its_legacy_method_ranges.empty()) {
- its_instance_method_ranges.insert(std::make_pair(its_legacy_instance_ranges,
- its_legacy_method_ranges));
- }
- }
- }
- }
- if (service != 0x0 && !its_instance_method_ranges.empty()) {
- auto find_policy = policy->services_.find(service);
- if (find_policy != policy->services_.end()) {
- find_policy->second.insert(its_instance_method_ranges.begin(),
- its_instance_method_ranges.end());
- } else {
- policy->services_.insert(
- std::make_pair(service, its_instance_method_ranges));
- }
- }
- }
- } else if (l->first == "offers") {
- for (auto n = l->second.begin(); n != l->second.end(); ++n) {
- service_t service = 0x0;
- instance_t instance = 0x0;
- ranges_t its_instance_ranges;
- for (auto k = n->second.begin(); k != n->second.end(); ++k) {
- std::stringstream its_converter;
- if (k->first == "service") {
- std::string value = k->second.data();
- its_converter << std::hex << value;
- its_converter >> service;
- } else if (k->first == "instance") { // legacy definition for instances
- std::string value = k->second.data();
- if (value != "any") {
- its_converter << std::hex << value;
- its_converter >> instance;
- if (instance != 0x0) {
- its_instance_ranges.insert(std::make_pair(instance, instance));
- }
- } else {
- its_instance_ranges.insert(std::make_pair(0x01, 0xFFFF));
- }
- } else if (k->first == "instances") { // new instances definition
- load_instance_ranges(k->second, its_instance_ranges);
- }
- }
- if (service != 0x0 && !its_instance_ranges.empty()) {
- auto find_service = policy->offers_.find(service);
- if (find_service != policy->offers_.end()) {
- find_service->second.insert(its_instance_ranges.begin(),
- its_instance_ranges.end());
- } else {
- policy->offers_.insert(
- std::make_pair(service, its_instance_ranges));
- }
- }
- }
- }
- }
+ load_policy_body(policy, i);
} else if (i->first == "deny") {
if (allow_deny_set) {
VSOMEIP_WARNING << "vSomeIP Security: Security configuration: \"deny\" tag overrides "
@@ -1238,138 +779,160 @@ security_impl::load_policy(const boost::property_tree::ptree &_tree) {
}
allow_deny_set = true;
policy->allow_what_ = false;
- for (auto l = i->second.begin(); l != i->second.end(); ++l) {
- if (l->first == "requests") {
- for (auto n = l->second.begin(); n != l->second.end(); ++n) {
- service_t service = 0x0;
- instance_t instance = 0x0;
- ids_t its_instance_method_ranges;
- for (auto k = n->second.begin(); k != n->second.end(); ++k) {
- std::stringstream its_converter;
- if (k->first == "service") {
- std::string value = k->second.data();
- its_converter << std::hex << value;
- its_converter >> service;
- } else if (k->first == "instance") { // legacy definition for instances
- ranges_t its_instance_ranges;
- ranges_t its_method_ranges;
- std::string value = k->second.data();
- if (value != "any") {
- its_converter << std::hex << value;
- its_converter >> instance;
- if (instance != 0x0) {
- its_instance_ranges.insert(std::make_pair(instance, instance));
- its_method_ranges.insert(std::make_pair(0x01, 0xFFFF));
- }
- } else {
- its_instance_ranges.insert(std::make_pair(0x01, 0xFFFF));
- its_method_ranges.insert(std::make_pair(0x01, 0xFFFF));
- }
- its_instance_method_ranges.insert(std::make_pair(its_instance_ranges, its_method_ranges));
- } else if (k->first == "instances") { // new instances definition
- for (auto p = k->second.begin(); p != k->second.end(); ++p) {
- ranges_t its_instance_ranges;
- ranges_t its_method_ranges;
- for (auto m = p->second.begin(); m != p->second.end(); ++m) {
- if (m->first == "ids") {
- load_instance_ranges(m->second, its_instance_ranges);
- } else if (m->first == "methods") {
- load_instance_ranges(m->second, its_method_ranges);
- }
- if (!its_instance_ranges.empty() && !its_method_ranges.empty()) {
- its_instance_method_ranges.insert(std::make_pair(its_instance_ranges, its_method_ranges));
- }
- }
- }
- if (its_instance_method_ranges.empty()) {
- ranges_t its_legacy_instance_ranges;
- ranges_t its_legacy_method_ranges;
- its_legacy_method_ranges.insert(std::make_pair(0x01, 0xFFFF));
- // try to only load instance ranges with any method to be allowed
- load_instance_ranges(k->second, its_legacy_instance_ranges);
- if (!its_legacy_instance_ranges.empty() && !its_legacy_method_ranges.empty()) {
- its_instance_method_ranges.insert(std::make_pair(its_legacy_instance_ranges,
- its_legacy_method_ranges));
- }
+ load_policy_body(policy, i);
+ }
+ }
+ std::lock_guard<std::mutex> its_lock(any_client_policies_mutex_);
+ any_client_policies_.push_back(policy);
+}
+
+void
+security_impl::load_policy_body(std::shared_ptr<policy> &_policy,
+ const boost::property_tree::ptree::const_iterator &_tree) {
+
+ for (auto l = _tree->second.begin(); l != _tree->second.end(); ++l) {
+ if (l->first == "requests") {
+ for (auto n = l->second.begin(); n != l->second.end(); ++n) {
+ service_t its_service = 0x0;
+ instance_t its_instance = 0x0;
+ boost::icl::interval_map<instance_t,
+ boost::icl::interval_set<method_t> > its_instance_method_intervals;
+ for (auto k = n->second.begin(); k != n->second.end(); ++k) {
+ if (k->first == "service") {
+ read_data(k->second.data(), its_service);
+ } else if (k->first == "instance") { // legacy definition for instances
+ boost::icl::interval_set<instance_t> its_instance_interval_set;
+ boost::icl::interval_set<method_t> its_method_interval_set;
+ boost::icl::discrete_interval<instance_t> all_instances(0x01, 0xFFFF,
+ boost::icl::interval_bounds::closed());
+ boost::icl::discrete_interval<method_t> all_methods(0x01, 0xFFFF,
+ boost::icl::interval_bounds::closed());
+
+ std::string its_value(k->second.data());
+ if (its_value != "any") {
+ read_data(its_value, its_instance);
+ if (its_instance != 0x0) {
+ its_instance_interval_set.insert(its_instance);
+ its_method_interval_set.insert(all_methods);
+ }
+ } else {
+ its_instance_interval_set.insert(all_instances);
+ its_method_interval_set.insert(all_methods);
+ }
+ for (const auto i : its_instance_interval_set) {
+ its_instance_method_intervals
+ += std::make_pair(i, its_method_interval_set);
+ }
+ } else if (k->first == "instances") { // new instances definition
+ for (auto p = k->second.begin(); p != k->second.end(); ++p) {
+ boost::icl::interval_set<instance_t> its_instance_interval_set;
+ boost::icl::interval_set<method_t> its_method_interval_set;
+ boost::icl::discrete_interval<method_t> all_methods(0x01, 0xFFFF,
+ boost::icl::interval_bounds::closed());
+ for (auto m = p->second.begin(); m != p->second.end(); ++m) {
+ if (m->first == "ids") {
+ load_interval_set(m->second, its_instance_interval_set);
+ } else if (m->first == "methods") {
+ load_interval_set(m->second, its_method_interval_set);
}
}
+ if (its_method_interval_set.empty())
+ its_method_interval_set.insert(all_methods);
+ for (const auto i : its_instance_interval_set) {
+ its_instance_method_intervals
+ += std::make_pair(i, its_method_interval_set);
+ }
}
- if (service != 0x0 && !its_instance_method_ranges.empty()) {
- auto find_policy = policy->services_.find(service);
- if (find_policy != policy->services_.end()) {
- find_policy->second.insert(its_instance_method_ranges.begin(),
- its_instance_method_ranges.end());
- } else {
- policy->services_.insert(
- std::make_pair(service, its_instance_method_ranges));
+
+ if (its_instance_method_intervals.empty()) {
+ boost::icl::interval_set<instance_t> its_legacy_instance_interval_set;
+ boost::icl::interval_set<method_t> its_legacy_method_interval_set;
+ boost::icl::discrete_interval<method_t> all_methods(0x01, 0xFFFF,
+ boost::icl::interval_bounds::closed());
+ its_legacy_method_interval_set.insert(all_methods);
+
+ // try to only load instance ranges with any method to be allowed
+ load_interval_set(k->second, its_legacy_instance_interval_set);
+ for (const auto i : its_legacy_instance_interval_set) {
+ its_instance_method_intervals
+ += std::make_pair(i, its_legacy_method_interval_set);
}
}
}
}
- if (l->first == "offers") {
- for (auto n = l->second.begin(); n != l->second.end(); ++n) {
- service_t service = 0x0;
- instance_t instance = 0x0;
- ranges_t its_instance_ranges;
- for (auto k = n->second.begin(); k != n->second.end(); ++k) {
- std::stringstream its_converter;
- if (k->first == "service") {
- std::string value = k->second.data();
- its_converter << std::hex << value;
- its_converter >> service;
- } else if (k->first == "instance") { // legacy definition for instances
- std::string value = k->second.data();
- if (value != "any") {
- its_converter << std::hex << value;
- its_converter >> instance;
- if (instance != 0x0) {
- its_instance_ranges.insert(std::make_pair(instance, instance));
- }
- } else {
- its_instance_ranges.insert(std::make_pair(0x01, 0xFFFF));
- }
- } else if (k->first == "instances") { // new instances definition
- load_instance_ranges(k->second, its_instance_ranges);
- }
- }
- if (service != 0x0 && !its_instance_ranges.empty()) {
- auto find_service = policy->offers_.find(service);
- if (find_service != policy->offers_.end()) {
- find_service->second.insert(its_instance_ranges.begin(),
- its_instance_ranges.end());
- } else {
- policy->offers_.insert(
- std::make_pair(service, its_instance_ranges));
+ if (its_service != 0x0 && !its_instance_method_intervals.empty()) {
+ _policy->requests_ += std::make_pair(
+ boost::icl::discrete_interval<service_t>(
+ its_service, its_service,
+ boost::icl::interval_bounds::closed()),
+ its_instance_method_intervals);
+ }
+ }
+ } else if (l->first == "offers") {
+ for (auto n = l->second.begin(); n != l->second.end(); ++n) {
+ service_t its_service(0x0);
+ instance_t its_instance(0x0);
+ boost::icl::interval_set<instance_t> its_instance_interval_set;
+ for (auto k = n->second.begin(); k != n->second.end(); ++k) {
+ if (k->first == "service") {
+ read_data(k->second.data(), its_service);
+ } else if (k->first == "instance") { // legacy definition for instances
+ std::string its_value(k->second.data());
+ if (its_value != "any") {
+ read_data(its_value, its_instance);
+ if (its_instance != 0x0) {
+ its_instance_interval_set.insert(its_instance);
}
+ } else {
+ its_instance_interval_set.insert(
+ boost::icl::discrete_interval<instance_t>(
+ 0x0001, 0xFFFF));
}
+ } else if (k->first == "instances") { // new instances definition
+ load_interval_set(k->second, its_instance_interval_set);
}
}
+ if (its_service != 0x0 && !its_instance_interval_set.empty()) {
+ _policy->offers_
+ += std::make_pair(
+ boost::icl::discrete_interval<service_t>(
+ its_service, its_service,
+ boost::icl::interval_bounds::closed()),
+ its_instance_interval_set);
+ }
}
}
}
- std::lock_guard<std::mutex> its_lock(any_client_policies_mutex_);
- any_client_policies_.push_back(policy);
}
+
void
security_impl::load_credential(
- const boost::property_tree::ptree &_tree, ids_t &_ids) {
+ const boost::property_tree::ptree &_tree,
+ boost::icl::interval_map<uid_t,
+ boost::icl::interval_set<gid_t> > &_credentials) {
+
for (auto i = _tree.begin(); i != _tree.end(); ++i) {
- ranges_t its_uid_ranges, its_gid_ranges;
+ boost::icl::interval_set<uid_t> its_uid_interval_set;
+ boost::icl::interval_set<gid_t> its_gid_interval_set;
+
for (auto j = i->second.begin(); j != i->second.end(); ++j) {
std::string its_key(j->first);
if (its_key == "uid") {
- load_ranges(j->second, its_uid_ranges);
+ load_interval_set(j->second, its_uid_interval_set);
} else if (its_key == "gid") {
- load_ranges(j->second, its_gid_ranges);
+ load_interval_set(j->second, its_gid_interval_set);
} else {
VSOMEIP_WARNING << "vSomeIP Security: Security configuration: "
<< "Malformed credential (contains illegal key \""
- << its_key << "\"";
+ << its_key << "\")";
}
}
- _ids.insert(std::make_pair(its_uid_ranges, its_gid_ranges));
+ for (const auto its_uid_interval : its_uid_interval_set) {
+ _credentials
+ += std::make_pair(its_uid_interval, its_gid_interval_set);
+ }
}
}
@@ -1386,25 +949,14 @@ security_impl::load_routing_credentials(const configuration_element &_element) {
++i) {
std::string its_key(i->first);
std::string its_value(i->second.data());
- std::stringstream its_converter;
if (its_key == "uid") {
uint32_t its_uid(0);
- if (its_value.find("0x") == 0) {
- its_converter << std::hex << its_value;
- } else {
- its_converter << std::dec << its_value;
- }
- its_converter >> its_uid;
+ read_data(its_value, its_uid);
std::lock_guard<std::mutex> its_lock(routing_credentials_mutex_);
std::get<0>(routing_credentials_) = its_uid;
} else if (its_key == "gid") {
uint32_t its_gid(0);
- if (its_value.find("0x") == 0) {
- its_converter << std::hex << its_value;
- } else {
- its_converter << std::dec << its_value;
- }
- its_converter >> its_gid;
+ read_data(its_value, its_gid);
std::lock_guard<std::mutex> its_lock(routing_credentials_mutex_);
std::get<1>(routing_credentials_) = its_gid;
}
@@ -1436,12 +988,12 @@ security_impl::load_security_update_whitelist(const configuration_element &_elem
if (its_whitelist->first == "uids") {
{
std::lock_guard<std::mutex> its_lock(uid_whitelist_mutex_);
- load_ranges(its_whitelist->second, uid_whitelist_);
+ load_interval_set(its_whitelist->second, uid_whitelist_);
}
} else if (its_whitelist->first == "services") {
{
std::lock_guard<std::mutex> its_lock(service_interface_whitelist_mutex_);
- load_service_ranges(its_whitelist->second, service_interface_whitelist_);
+ load_interval_set(its_whitelist->second, service_interface_whitelist_);
}
} else if (its_whitelist->first == "check-whitelist") {
if (its_whitelist->second.data() == "true") {
@@ -1455,180 +1007,154 @@ security_impl::load_security_update_whitelist(const configuration_element &_elem
}
}
-void
-security_impl::load_ranges(
- const boost::property_tree::ptree &_tree, ranges_t &_range) {
- ranges_t its_ranges;
- for (auto i = _tree.begin(); i != _tree.end(); ++i) {
- auto its_data = i->second;
- if (!its_data.data().empty()) {
- uint32_t its_id;
- std::stringstream its_converter;
- its_converter << std::dec << its_data.data();
- its_converter >> its_id;
- its_ranges.insert(std::make_pair(its_id, its_id));
- } else {
- uint32_t its_first, its_last;
- bool has_first(false), has_last(false);
- for (auto j = its_data.begin(); j != its_data.end(); ++j) {
- std::string its_key(j->first);
- std::string its_value(j->second.data());
- if (its_key == "first") {
- if (its_value == "max") {
- its_first = 0xFFFFFFFF;
- } else {
- std::stringstream its_converter;
- its_converter << std::dec << j->second.data();
- its_converter >> its_first;
- }
- has_first = true;
- } else if (its_key == "last") {
- if (its_value == "max") {
- its_last = 0xFFFFFFFF;
- } else {
- std::stringstream its_converter;
- its_converter << std::dec << j->second.data();
- its_converter >> its_last;
- }
- has_last = true;
- } else {
- VSOMEIP_WARNING << "vSomeIP Security: Security configuration: "
- << " Malformed range. Contains illegal key ("
- << its_key << ")";
- }
- }
+template<typename T_>
+void security_impl::load_interval_set(
+ const boost::property_tree::ptree &_tree,
+ boost::icl::interval_set<T_> &_intervals, bool _exclude_margins) {
- if (has_first && has_last) {
- its_ranges.insert(std::make_pair(its_first, its_last));
- }
- }
- }
-
- _range = its_ranges;
-}
+ boost::icl::interval_set<T_> its_intervals;
+ T_ its_min = std::numeric_limits<T_>::min();
+ T_ its_max = std::numeric_limits<T_>::max();
-void
-security_impl::load_instance_ranges(
- const boost::property_tree::ptree &_tree, ranges_t &_range) {
- ranges_t its_ranges;
- const std::string& key(_tree.data());
- if (key == "any") {
- its_ranges.insert(std::make_pair(0x01, 0xFFFF));
- _range = its_ranges;
- return;
+ if (_exclude_margins) {
+ its_min++;
+ its_max--;
}
- for (auto i = _tree.begin(); i != _tree.end(); ++i) {
- auto its_data = i->second;
- if (!its_data.data().empty()) {
- uint32_t its_id = 0x0;
- std::stringstream its_converter;
- its_converter << std::hex << its_data.data();
- its_converter >> its_id;
- if (its_id != 0x0) {
- its_ranges.insert(std::make_pair(its_id, its_id));
- }
- } else {
- uint32_t its_first, its_last;
- bool has_first(false), has_last(false);
- for (auto j = its_data.begin(); j != its_data.end(); ++j) {
- std::string its_key(j->first);
- std::string its_value(j->second.data());
- if (its_key == "first") {
- if (its_value == "max") {
- its_first = 0xFFFF;
- } else {
- std::stringstream its_converter;
- its_converter << std::hex << j->second.data();
- its_converter >> its_first;
- }
- has_first = true;
- } else if (its_key == "last") {
- if (its_value == "max") {
- its_last = 0xFFFF;
+
+ const std::string its_key(_tree.data());
+ if (its_key == "any") {
+ its_intervals.insert(boost::icl::discrete_interval<T_>::closed(
+ its_min, its_max));
+ } else {
+ for (auto i = _tree.begin(); i != _tree.end(); ++i) {
+ auto its_data = i->second;
+ if (!its_data.data().empty()) {
+ T_ its_id;
+ read_data(its_data.data(), its_id);
+ if (its_id >= its_min && its_id <= its_max)
+ its_intervals.insert(its_id);
+ } else {
+ T_ its_first, its_last;
+ bool has_first(false), has_last(false);
+ for (auto j = its_data.begin(); j != its_data.end(); ++j) {
+ std::string its_key(j->first);
+ std::string its_value(j->second.data());
+ if (its_key == "first") {
+ if (its_value == "min") {
+ its_first = its_min;
+ } else {
+ read_data(its_value, its_first);
+ }
+ has_first = true;
+ } else if (its_key == "last") {
+ if (its_value == "max") {
+ its_last = its_max;
+ } else {
+ read_data(its_value, its_last);
+ }
+ has_last = true;
} else {
- std::stringstream its_converter;
- its_converter << std::hex << j->second.data();
- its_converter >> its_last;
+ VSOMEIP_WARNING << "vSomeIP Security: Security configuration: "
+ << " Malformed range. Contains illegal key ("
+ << its_key << ")";
}
- has_last = true;
- } else {
- VSOMEIP_WARNING << "vSomeIP Security: Security configuration: "
- << " Malformed range. Contains illegal key ("
- << its_key << ")";
}
- }
-
- if (has_first && has_last) {
- if( its_last > its_first) {
- its_ranges.insert(std::make_pair(its_first, its_last));
+ if (has_first && has_last && its_first <= its_last) {
+ its_intervals.insert(
+ boost::icl::discrete_interval<T_>::closed(its_first, its_last));
}
}
}
}
- _range = its_ranges;
+ _intervals = its_intervals;
}
void
-security_impl::load_service_ranges(
- const boost::property_tree::ptree &_tree, std::set<std::pair<service_t, service_t>> &_ranges) {
- std::set<std::pair<service_t, service_t>> its_ranges;
- const std::string& key(_tree.data());
- if (key == "any") {
- its_ranges.insert(std::make_pair(0x01, 0xFFFF));
- _ranges = its_ranges;
- return;
+security_impl::get_requester_policies(const std::shared_ptr<policy> _policy,
+ std::set<std::shared_ptr<policy> > &_requesters) const {
+
+ std::vector<std::shared_ptr<policy> > its_policies;
+ {
+ std::lock_guard<std::mutex> its_lock(any_client_policies_mutex_);
+ its_policies = any_client_policies_;
}
- for (auto i = _tree.begin(); i != _tree.end(); ++i) {
- auto its_data = i->second;
- if (!its_data.data().empty()) {
- service_t its_id = 0x0;
- std::stringstream its_converter;
- its_converter << std::hex << its_data.data();
- its_converter >> its_id;
- if (its_id != 0x0) {
- its_ranges.insert(std::make_pair(its_id, its_id));
- }
- } else {
- service_t its_first, its_last;
- bool has_first(false), has_last(false);
- for (auto j = its_data.begin(); j != its_data.end(); ++j) {
- std::string its_key(j->first);
- std::string its_value(j->second.data());
- if (its_key == "first") {
- if (its_value == "max") {
- its_first = 0xFFFF;
- } else {
- std::stringstream its_converter;
- its_converter << std::hex << j->second.data();
- its_converter >> its_first;
- }
- has_first = true;
- } else if (its_key == "last") {
- if (its_value == "max") {
- its_last = 0xFFFF;
- } else {
- std::stringstream its_converter;
- its_converter << std::hex << j->second.data();
- its_converter >> its_last;
+
+ std::lock_guard<std::mutex> its_lock(_policy->mutex_);
+ for (const auto o : _policy->offers_) {
+ for (const auto p : its_policies) {
+ if (p == _policy)
+ continue;
+
+ std::lock_guard<std::mutex> its_lock(p->mutex_);
+
+ auto its_policy = std::make_shared<policy>();
+ its_policy->credentials_ = p->credentials_;
+
+ for (const auto r : p->requests_) {
+ // o represents an offer by a service interval and its instances
+ // (a set of intervals)
+ // r represents a request by a service interval and its instances
+ // and methods (instance intervals mapped to interval sets of methods)
+ //
+ // Thus, r matches o if their service identifiers as well as their
+ // instances overlap. If r and o match, a new policy must be
+ // created that contains the overlapping services/instances mapping
+ // of r and o together with the methods from r
+ service_t its_o_lower, its_o_upper, its_r_lower, its_r_upper;
+ get_bounds(o.first, its_o_lower, its_o_upper);
+ get_bounds(r.first, its_r_lower, its_r_upper);
+
+ if (its_o_lower <= its_r_upper && its_r_lower <= its_o_upper) {
+ auto its_service_min = std::max(its_o_lower, its_r_lower);
+ auto its_service_max = std::min(its_r_upper, its_o_upper);
+
+ for (const auto i : o.second) {
+ for (const auto j : r.second) {
+ for (const auto k : j.second) {
+ instance_t its_i_lower, its_i_upper, its_k_lower, its_k_upper;
+ get_bounds(i, its_i_lower, its_i_upper);
+ get_bounds(k, its_k_lower, its_k_upper);
+
+ if (its_i_lower <= its_k_upper && its_k_lower <= its_i_upper) {
+ auto its_instance_min = std::max(its_i_lower, its_k_lower);
+ auto its_instance_max = std::min(its_i_upper, its_k_upper);
+
+ boost::icl::interval_map<instance_t,
+ boost::icl::interval_set<method_t> > its_instances_methods;
+ its_instances_methods += std::make_pair(
+ boost::icl::interval<instance_t>::closed(
+ its_instance_min, its_instance_max),
+ j.second);
+
+ its_policy->requests_ += std::make_pair(
+ boost::icl::interval<instance_t>::closed(
+ its_service_min, its_service_max),
+ its_instances_methods);
+ }
+ }
+ }
}
- has_last = true;
- } else {
- VSOMEIP_WARNING << "vSomeIP Security: Security interface whitelist configuration: "
- << " Malformed range. Contains illegal key ("
- << its_key << ")";
}
}
- if (has_first && has_last) {
- if( its_last >= its_first) {
- its_ranges.insert(std::make_pair(its_first, its_last));
- }
+ if (!its_policy->requests_.empty()) {
+ _requesters.insert(its_policy);
+ its_policy->print();
}
}
}
+}
+
+void
+security_impl::get_clients(uid_t _uid, gid_t _gid,
+ std::unordered_set<client_t> &_clients) const {
- _ranges = its_ranges;
+ std::lock_guard<std::mutex> its_lock(ids_mutex_);
+ for (const auto i : ids_) {
+ if (i.second.first == _uid && i.second.second == _gid)
+ _clients.insert(i.first);
+ }
}
////////////////////////////////////////////////////////////////////////////////
diff --git a/implementation/service_discovery/include/service_discovery_host.hpp b/implementation/service_discovery/include/service_discovery_host.hpp
index 88e093b..f864571 100644
--- a/implementation/service_discovery/include/service_discovery_host.hpp
+++ b/implementation/service_discovery/include/service_discovery_host.hpp
@@ -66,6 +66,7 @@ public:
virtual void on_subscribe_ack_with_multicast(
service_t _service, instance_t _instance,
+ const boost::asio::ip::address &_sender,
const boost::asio::ip::address &_address, uint16_t _port) = 0;
virtual std::shared_ptr<endpoint> find_or_create_remote_client(
diff --git a/implementation/service_discovery/include/service_discovery_impl.hpp b/implementation/service_discovery/include/service_discovery_impl.hpp
index 53b18c0..81bb91f 100644
--- a/implementation/service_discovery/include/service_discovery_impl.hpp
+++ b/implementation/service_discovery/include/service_discovery_impl.hpp
@@ -79,6 +79,7 @@ public:
void unsubscribe(service_t _service, instance_t _instance,
eventgroup_t _eventgroup, client_t _client);
void unsubscribe_all(service_t _service, instance_t _instance);
+ void reset_subscriptions(service_t _service, instance_t _instance);
bool send(bool _is_announcing);
@@ -175,6 +176,7 @@ private:
std::shared_ptr<eventgroupentry_impl> &_entry,
const std::vector<std::shared_ptr<option_impl> > &_options,
std::shared_ptr<remote_subscription_ack> &_acknowledgement,
+ const boost::asio::ip::address &_sender,
const boost::asio::ip::address &_destination,
bool _is_stop_subscribe_subscribe, bool _force_initial_events,
const sd_acceptance_state_t& _sd_ac_state);
@@ -194,6 +196,7 @@ private:
instance_t _instance, eventgroup_t _eventgroup,
major_version_t _major, ttl_t _ttl, uint8_t _counter,
const std::set<client_t> &_clients,
+ const boost::asio::ip::address &_sender,
const boost::asio::ip::address &_address, uint16_t _port);
void handle_eventgroup_subscription_nack(service_t _service,
instance_t _instance, eventgroup_t _eventgroup, uint8_t _counter,
diff --git a/implementation/service_discovery/src/service_discovery_impl.cpp b/implementation/service_discovery/src/service_discovery_impl.cpp
index fba2227..b252e62 100644
--- a/implementation/service_discovery/src/service_discovery_impl.cpp
+++ b/implementation/service_discovery/src/service_discovery_impl.cpp
@@ -521,6 +521,28 @@ service_discovery_impl::unsubscribe_all(
serialize_and_send(its_messages, its_address);
}
+void
+service_discovery_impl::reset_subscriptions(
+ service_t _service, instance_t _instance) {
+
+ std::lock_guard<std::mutex> its_lock(subscribed_mutex_);
+ auto found_service = subscribed_.find(_service);
+ if (found_service != subscribed_.end()) {
+ auto found_instance = found_service->second.find(_instance);
+ if (found_instance != found_service->second.end()) {
+ for (auto &its_eventgroup : found_instance->second) {
+ auto its_subscription = its_eventgroup.second;
+ for (auto its_client : its_subscription->get_clients()) {
+ its_subscription->set_state(its_client,
+ subscription_state_e::ST_UNKNOWN);
+ }
+ its_subscription->set_endpoint(nullptr, true);
+ its_subscription->set_endpoint(nullptr, false);
+ }
+ }
+ }
+}
+
std::pair<session_t, bool>
service_discovery_impl::get_session(
const boost::asio::ip::address &_address) {
@@ -1100,7 +1122,7 @@ service_discovery_impl::on_message(
is_stop_subscribe_subscribe =
check_stop_subscribe_subscribe(iter, its_end, its_options);
process_eventgroupentry(its_eventgroup_entry, its_options,
- its_acknowledgement, _destination,
+ its_acknowledgement, _sender, _destination,
is_stop_subscribe_subscribe, force_initial_events,
accept_state);
}
@@ -1249,7 +1271,7 @@ service_discovery_impl::process_serviceentry(
remove_remote_offer_type(its_service, its_instance,
its_reliable_address, its_reliable_port,
its_unreliable_address, its_unreliable_port);
- unsubscribe_all(its_service, its_instance);
+ reset_subscriptions(its_service, its_instance);
if (!is_diagnosis_ && !is_suspended_) {
host_->del_routing_info(its_service, its_instance,
(its_reliable_port != ILLEGAL_PORT),
@@ -1308,6 +1330,7 @@ service_discovery_impl::process_offerservice_serviceentry(
VSOMEIP_WARNING << __func__ << ": Unknown remote offer type ["
<< std::hex << std::setw(4) << std::setfill('0') << _service << "."
<< std::hex << std::setw(4) << std::setfill('0') << _instance << "]";
+ return; // Unknown remote offer type --> no way to access it!
}
if (_sd_ac_state.sd_acceptance_required_) {
@@ -1673,9 +1696,6 @@ service_discovery_impl::insert_offer_service(
its_ttl = ttl_;
its_entry->set_ttl(its_ttl);
- // This would be a clean solution but does _not_ work with the ANDi tool
- // unsubscribe_all(_service, _instance);
-
add_entry_data(_messages, its_data);
} else {
VSOMEIP_ERROR << __func__ << ": Failed to create service entry.";
@@ -1687,6 +1707,7 @@ service_discovery_impl::process_eventgroupentry(
std::shared_ptr<eventgroupentry_impl> &_entry,
const std::vector<std::shared_ptr<option_impl> > &_options,
std::shared_ptr<remote_subscription_ack> &_acknowledgement,
+ const boost::asio::ip::address &_sender,
const boost::asio::ip::address &_destination,
bool _is_stop_subscribe_subscribe, bool _force_initial_events,
const sd_acceptance_state_t& _sd_ac_state) {
@@ -2122,7 +2143,7 @@ service_discovery_impl::process_eventgroupentry(
if (its_ttl > 0) {
handle_eventgroup_subscription_ack(its_service, its_instance,
its_eventgroup, its_major, its_ttl, 0,
- its_clients,
+ its_clients, _sender,
its_first_address, its_first_port);
} else {
handle_eventgroup_subscription_nack(its_service, its_instance, its_eventgroup,
@@ -2383,6 +2404,7 @@ service_discovery_impl::handle_eventgroup_subscription_ack(
service_t _service, instance_t _instance, eventgroup_t _eventgroup,
major_version_t _major, ttl_t _ttl, uint8_t _counter,
const std::set<client_t> &_clients,
+ const boost::asio::ip::address &_sender,
const boost::asio::ip::address &_address, uint16_t _port) {
(void)_major;
(void)_ttl;
@@ -2407,7 +2429,7 @@ service_discovery_impl::handle_eventgroup_subscription_ack(
}
if (_address.is_multicast()) {
host_->on_subscribe_ack_with_multicast(
- _service, _instance, _address, _port);
+ _service, _instance, _sender, _address, _port);
}
}
}
diff --git a/implementation/utility/include/utility.hpp b/implementation/utility/include/utility.hpp
index 9975bf9..db54eb9 100644
--- a/implementation/utility/include/utility.hpp
+++ b/implementation/utility/include/utility.hpp
@@ -145,7 +145,11 @@ private:
#else
static int lock_fd__;
#endif
+#ifndef VSOMEIP_ENABLE_CONFIGURATION_OVERLAYS
static bool is_checked__;
+#else
+ static std::set<std::string> is_checked__;
+#endif
};
} // namespace vsomeip_v3
diff --git a/implementation/utility/src/utility.cpp b/implementation/utility/src/utility.cpp
index 7f05e95..139faef 100644
--- a/implementation/utility/src/utility.cpp
+++ b/implementation/utility/src/utility.cpp
@@ -39,7 +39,11 @@ HANDLE utility::lock_handle__(INVALID_HANDLE_VALUE);
#else
int utility::lock_fd__(-1);
#endif
+#ifndef VSOMEIP_ENABLE_CONFIGURATION_OVERLAYS
bool utility::is_checked__(false);
+#else
+std::set<std::string> utility::is_checked__;
+#endif
uint64_t utility::get_message_size(const byte_t *_data, size_t _size) {
uint64_t its_size(0);
@@ -63,10 +67,17 @@ bool utility::is_routing_manager(const std::shared_ptr<configuration> &_config)
// Only the first caller can become routing manager.
// Therefore, subsequent calls can be immediately answered...
std::lock_guard<std::mutex> its_lock(mutex__);
+#ifndef VSOMEIP_ENABLE_CONFIGURATION_OVERLAYS
if (is_checked__)
return false;
is_checked__ = true;
+#else
+ if (is_checked__.find(_config->get_network()) != is_checked__.end())
+ return false;
+
+ is_checked__.insert(_config->get_network());
+#endif
#ifdef _WIN32
wchar_t its_tmp_folder[MAX_PATH];
if (GetTempPathW(MAX_PATH, its_tmp_folder)) {
@@ -112,8 +123,13 @@ bool utility::is_routing_manager(const std::shared_ptr<configuration> &_config)
void utility::remove_lockfile(const std::shared_ptr<configuration> &_config) {
std::lock_guard<std::mutex> its_lock(mutex__);
+#ifndef VSOMEIP_ENABLE_CONFIGURATION_OVERLAYS
if (!is_checked__) // No need to do anything as automatic
return;
+#else
+ if (is_checked__.find(_config->get_network()) == is_checked__.end()) // No need to do anything as automatic
+ return;
+#endif
#ifdef _WIN32
if (lock_handle__ != INVALID_HANDLE_VALUE) {
@@ -157,7 +173,11 @@ void utility::remove_lockfile(const std::shared_ptr<configuration> &_config) {
<< ": " << std::strerror(errno);
}
#endif
+#ifndef VSOMEIP_ENABLE_CONFIGURATION_OVERLAYS
is_checked__ = false;
+#else
+ is_checked__.erase(_config->get_network());
+#endif
}
bool utility::exists(const std::string &_path) {
diff --git a/test/CMakeLists.txt b/test/CMakeLists.txt
index 8250c1c..23a62aa 100644
--- a/test/CMakeLists.txt
+++ b/test/CMakeLists.txt
@@ -2565,6 +2565,74 @@ if(NOT ${TESTS_BAT})
endif()
##############################################################################
+# e2e profile 04 test
+##############################################################################
+
+if(NOT ${TESTS_BAT} AND ${TEST_E2E_PROFILE_04})
+ set(TEST_E2E_PROFILE_04_NAME e2e_profile_04_test)
+ set(TEST_E2E_PROFILE_04_SERVICE e2e_profile_04_test_service)
+ set(TEST_E2E_PROFILE_04_CLIENT e2e_profile_04_test_client)
+
+ add_executable(${TEST_E2E_PROFILE_04_SERVICE} e2e_tests/${TEST_E2E_PROFILE_04_SERVICE}.cpp)
+ target_link_libraries(${TEST_E2E_PROFILE_04_SERVICE}
+ vsomeip3
+ ${Boost_LIBRARIES}
+ ${DL_LIBRARY}
+ ${TEST_LINK_LIBRARIES}
+ )
+
+ add_executable(${TEST_E2E_PROFILE_04_CLIENT}
+ e2e_tests/${TEST_E2E_PROFILE_04_CLIENT}.cpp
+ )
+ target_link_libraries(${TEST_E2E_PROFILE_04_CLIENT}
+ vsomeip3
+ ${Boost_LIBRARIES}
+ ${DL_LIBRARY}
+ ${TEST_LINK_LIBRARIES}
+ )
+
+ # Copy service config file for external allow tests into $BUILDDIR/test
+ set(TEST_E2E_PROFILE_04_SERVICE_CONFIG_FILE_EXTERNAL ${TEST_E2E_PROFILE_04_NAME}_service_external.json)
+ configure_file(
+ ${PROJECT_SOURCE_DIR}/test/e2e_tests/conf/${TEST_E2E_PROFILE_04_SERVICE_CONFIG_FILE_EXTERNAL}.in
+ ${PROJECT_SOURCE_DIR}/test/e2e_tests/${TEST_E2E_PROFILE_04_SERVICE_CONFIG_FILE_EXTERNAL}
+ @ONLY)
+ copy_to_builddir(
+ ${PROJECT_SOURCE_DIR}/test/e2e_tests/${TEST_E2E_PROFILE_04_SERVICE_CONFIG_FILE_EXTERNAL}
+ ${PROJECT_BINARY_DIR}/test/${TEST_E2E_PROFILE_04_SERVICE_CONFIG_FILE_EXTERNAL}
+ ${TEST_E2E_PROFILE_04_SERVICE}
+ )
+
+ # Copy client config file for external allow tests into $BUILDDIR/test
+ set(TEST_E2E_PROFILE_04_CLIENT_CONFIG_FILE_EXTERNAL ${TEST_E2E_PROFILE_04_NAME}_client_external.json)
+ configure_file(
+ ${PROJECT_SOURCE_DIR}/test/e2e_tests/conf/${TEST_E2E_PROFILE_04_CLIENT_CONFIG_FILE_EXTERNAL}.in
+ ${PROJECT_SOURCE_DIR}/test/e2e_tests/${TEST_E2E_PROFILE_04_CLIENT_CONFIG_FILE_EXTERNAL}
+ @ONLY)
+ copy_to_builddir(
+ ${PROJECT_SOURCE_DIR}/test/e2e_tests/${TEST_E2E_PROFILE_04_CLIENT_CONFIG_FILE_EXTERNAL}
+ ${PROJECT_BINARY_DIR}/test/${TEST_E2E_PROFILE_04_CLIENT_CONFIG_FILE_EXTERNAL}
+ ${TEST_E2E_PROFILE_04_SERVICE}
+ )
+
+ # Copy bashscript to start external tests (master) into $BUILDDIR/test
+ set(TEST_E2E_PROFILE_04_EXTERNAL_MASTER_START_SCRIPT ${TEST_E2E_PROFILE_04_NAME}_external_master_start.sh)
+ copy_to_builddir(
+ ${PROJECT_SOURCE_DIR}/test/e2e_tests/${TEST_E2E_PROFILE_04_EXTERNAL_MASTER_START_SCRIPT}
+ ${PROJECT_BINARY_DIR}/test/${TEST_E2E_PROFILE_04_EXTERNAL_MASTER_START_SCRIPT}
+ ${TEST_E2E_PROFILE_04_SERVICE}
+ )
+
+ # Copy bashscript to start external tests (slave) into $BUILDDIR/test
+ set(TEST_E2E_PROFILE_04_EXTERNAL_SLAVE_START_SCRIPT ${TEST_E2E_PROFILE_04_NAME}_external_slave_start.sh)
+ copy_to_builddir(
+ ${PROJECT_SOURCE_DIR}/test/e2e_tests/${TEST_E2E_PROFILE_04_EXTERNAL_SLAVE_START_SCRIPT}
+ ${PROJECT_BINARY_DIR}/test/${TEST_E2E_PROFILE_04_EXTERNAL_SLAVE_START_SCRIPT}
+ ${TEST_E2E_PROFILE_04_SERVICE}
+ )
+endif()
+
+##############################################################################
# event tests
##############################################################################
@@ -3053,6 +3121,10 @@ if(NOT ${TESTS_BAT})
endif()
add_dependencies(${TEST_E2E_SERVICE} gtest)
add_dependencies(${TEST_E2E_CLIENT} gtest)
+ if (${TEST_E2E_PROFILE_04})
+ add_dependencies(${TEST_E2E_PROFILE_04_SERVICE} gtest)
+ add_dependencies(${TEST_E2E_PROFILE_04_CLIENT} gtest)
+ endif()
add_dependencies(${TEST_EVENT_SERVICE} gtest)
add_dependencies(${TEST_EVENT_CLIENT} gtest)
add_dependencies(${TEST_NPDU_SERVICE_ONE} gtest)
@@ -3129,6 +3201,10 @@ if(NOT ${TESTS_BAT})
add_dependencies(build_tests ${TEST_MALICIOUS_DATA_CLIENT})
add_dependencies(build_tests ${TEST_E2E_SERVICE})
add_dependencies(build_tests ${TEST_E2E_CLIENT})
+ if (${TEST_E2E_PROFILE_04})
+ add_dependencies(build_tests ${TEST_E2E_PROFILE_04_SERVICE})
+ add_dependencies(build_tests ${TEST_E2E_PROFILE_04_CLIENT})
+ endif()
add_dependencies(build_tests ${TEST_EVENT_SERVICE})
add_dependencies(build_tests ${TEST_EVENT_CLIENT})
add_dependencies(build_tests ${TEST_NPDU_SERVICE_ONE})
@@ -3594,11 +3670,17 @@ if(NOT ${TESTS_BAT})
COMMAND ${PROJECT_BINARY_DIR}/test/${TEST_NPDU_STARTER} TCP sync)
set_tests_properties(${TEST_NPDU_NAME}_tcp PROPERTIES TIMEOUT 840)
- # e2e test
+ # e2e tests
add_test(NAME ${TEST_E2E_NAME}_external
COMMAND ${PROJECT_BINARY_DIR}/test/${TEST_E2E_EXTERNAL_MASTER_START_SCRIPT} e2e_test_client_external.json)
set_tests_properties(${TEST_E2E_NAME}_external PROPERTIES TIMEOUT 180)
+ if (${TEST_E2E_PROFILE_04})
+ add_test(NAME ${TEST_E2E_PROFILE_04_NAME}_external
+ COMMAND ${PROJECT_BINARY_DIR}/test/${TEST_E2E_PROFILE_04_EXTERNAL_MASTER_START_SCRIPT} e2e_profile_04_test_client_external.json)
+ set_tests_properties(${TEST_E2E_PROFILE_04_NAME}_external PROPERTIES TIMEOUT 180)
+ endif ()
+
# event tests
add_test(NAME ${TEST_EVENT_NAME}_payload_fixed_udp
COMMAND ${PROJECT_BINARY_DIR}/test/${TEST_EVENT_MASTER_START_SCRIPT} PAYLOAD_FIXED UDP)
diff --git a/test/configuration_tests/configuration-test-deprecated.json b/test/configuration_tests/configuration-test-deprecated.json
index f9b23d8..5a8b0ee 100644
--- a/test/configuration_tests/configuration-test-deprecated.json
+++ b/test/configuration_tests/configuration-test-deprecated.json
@@ -321,7 +321,7 @@
},
{
"service" : "0x1236",
- "instances" : [{ "first" : "0x5675", "last" : "0x5677"}, "5678"]
+ "instances" : [{ "first" : "0x5675", "last" : "0x5677"}, "0x5678"]
}
]
}
@@ -390,7 +390,7 @@
},
{
"service" : "0x1236",
- "instances" : [{ "first" : "0x5675", "last" : "0x5677"}, "5678"]
+ "instances" : [{ "first" : "0x5675", "last" : "0x5677"}, "0x5678"]
}
]
}
diff --git a/test/configuration_tests/configuration-test.cpp b/test/configuration_tests/configuration-test.cpp
index 4056664..ad4faa7 100644
--- a/test/configuration_tests/configuration-test.cpp
+++ b/test/configuration_tests/configuration-test.cpp
@@ -638,46 +638,49 @@ void check_file(const std::string &_config_file,
uint32_t its_gid = 1000;
// policy elements
- std::pair<uint32_t, uint32_t> its_uid_range, its_gid_range;
- std::set<std::pair<uint32_t, uint32_t>> its_uids, its_gids;
-
- // fill uid and gid range
- std::get<0>(its_uid_range) = its_uid;
- std::get<1>(its_uid_range) = its_uid;
- std::get<0>(its_gid_range) = its_gid;
- std::get<1>(its_gid_range) = its_gid;
- its_uids.insert(its_uid_range);
- its_gids.insert(its_gid_range);
-
- _policy->ids_.insert(std::make_pair(its_uids, its_gids));
+ boost::icl::discrete_interval<uid_t> its_uids(its_uid, its_uid);
+ boost::icl::interval_set<gid_t> its_gids;
+ its_gids.insert(boost::icl::interval<gid_t>::closed(its_gid, its_gid));
+
+ _policy->credentials_ += std::make_pair(its_uids, its_gids);
_policy->allow_who_ = true;
_policy->allow_what_ = true;
- uint16_t its_service_id = 0x1234;
- vsomeip::ids_t its_instance_method_ranges;
- vsomeip::ranges_t its_instance_ranges;
- its_instance_ranges.insert(std::make_pair(0x01, 0x2));
+ vsomeip::service_t its_service(0x1234);
- vsomeip::ranges_t its_method_ranges;
- its_method_ranges.insert(std::make_pair(0x01, 0x2));
+ boost::icl::discrete_interval<vsomeip::instance_t> its_instances(0x1, 0x2);
+ boost::icl::interval_set<vsomeip::method_t> its_methods;
+ its_methods.insert(boost::icl::interval<vsomeip::method_t>::closed(0x01, 0x2));
+ boost::icl::interval_map<vsomeip::instance_t,
+ boost::icl::interval_set<vsomeip::method_t> > its_instances_methods;
+ its_instances_methods += std::make_pair(its_instances, its_methods);
- _policy->services_.insert(
- std::make_pair(its_service_id, its_instance_method_ranges));
+ _policy->requests_ += std::make_pair(
+ boost::icl::discrete_interval<vsomeip::service_t>(
+ its_service, its_service,
+ boost::icl::interval_bounds::closed()),
+ its_instances_methods);
EXPECT_TRUE(its_security->is_policy_update_allowed(1000, _policy));
// test valid policy that holds a single service id which is whitelisted
- its_service_id = 0x7800;
- _policy->services_.insert(
- std::make_pair(its_service_id, its_instance_method_ranges));
+ vsomeip::service_t its_second_service(0x7800);
+ _policy->requests_ += std::make_pair(
+ boost::icl::discrete_interval<vsomeip::service_t>(
+ its_second_service, its_second_service,
+ boost::icl::interval_bounds::closed()),
+ its_instances_methods);
EXPECT_TRUE(its_security->is_policy_update_allowed(1000, _policy));
// test invalid UID which is not whitelisted
EXPECT_FALSE(its_security->is_policy_update_allowed(2002, _policy));
// test invalid policy that additionally holds a service id which is not whitelisted
- its_service_id = 0x8888;
- _policy->services_.insert(
- std::make_pair(its_service_id, its_instance_method_ranges));
+ vsomeip::service_t its_third_service(0x8888);
+ _policy->requests_ += std::make_pair(
+ boost::icl::discrete_interval<vsomeip::service_t>(
+ its_third_service, its_third_service,
+ boost::icl::interval_bounds::closed()),
+ its_instances_methods);
EXPECT_FALSE(its_security->is_policy_update_allowed(1000, _policy));
// TCP connection setting:
diff --git a/test/configuration_tests/configuration-test.json b/test/configuration_tests/configuration-test.json
index 70c34e3..e18026e 100644
--- a/test/configuration_tests/configuration-test.json
+++ b/test/configuration_tests/configuration-test.json
@@ -310,7 +310,7 @@
},
{
"service" : "0x1236",
- "instances" : [{ "first" : "0x5676", "last" : "0x5677"}, "5678"]
+ "instances" : [{ "first" : "0x5676", "last" : "0x5677"}, "0x5678"]
}
]
}
@@ -379,7 +379,7 @@
},
{
"service" : "0x1236",
- "instances" : [{ "first" : "0x5675", "last" : "0x5677"}, "5678"]
+ "instances" : [{ "first" : "0x5675", "last" : "0x5677"}, "0x5678"]
}
]
}
diff --git a/test/e2e_tests/conf/e2e_profile_04_test_client_external.json.in b/test/e2e_tests/conf/e2e_profile_04_test_client_external.json.in
new file mode 100644
index 0000000..6952459
--- /dev/null
+++ b/test/e2e_tests/conf/e2e_profile_04_test_client_external.json.in
@@ -0,0 +1,56 @@
+{
+ "unicast" : "@TEST_IP_MASTER@",
+ "netmask" : "255.255.255.0",
+ "logging" :
+ {
+ "level" : "info",
+ "console" : "true",
+ "file" : { "enable" : "false", "path" : "/tmp/vsomeip.log" },
+ "dlt" : "false"
+ },
+ "applications" :
+ [
+ {
+ "name" : "client-sample",
+ "id" : "0x1255"
+ }
+ ],
+ "e2e" :
+ {
+ "e2e_enabled" : "true",
+ "protected" :
+ [
+ {
+ "service_id" : "0xd025",
+ "event_id" : "0x0001",
+ "profile" : "P04",
+ "variant" : "checker",
+ "crc_offset" : "64",
+ "data_id" : "0x2d"
+ },
+ {
+ "service_id" : "0xd025",
+ "event_id" : "0x8001",
+ "profile" : "P04",
+ "variant" : "checker",
+ "crc_offset" : "64",
+ "data_id" : "0x2d"
+ }
+ ]
+ },
+ "routing" : "client-sample",
+ "service-discovery" :
+ {
+ "enable" : "true",
+ "multicast" : "224.0.0.1",
+ "port" : "30490",
+ "protocol" : "udp",
+ "initial_delay_min" : "10",
+ "initial_delay_max" : "100",
+ "repetitions_base_delay" : "200",
+ "repetitions_max" : "3",
+ "ttl" : "3",
+ "cyclic_offer_delay" : "1000",
+ "request_response_delay" : "1500"
+ }
+}
diff --git a/test/e2e_tests/conf/e2e_profile_04_test_service_external.json.in b/test/e2e_tests/conf/e2e_profile_04_test_service_external.json.in
new file mode 100644
index 0000000..efeffef
--- /dev/null
+++ b/test/e2e_tests/conf/e2e_profile_04_test_service_external.json.in
@@ -0,0 +1,57 @@
+{
+ "unicast" : "@TEST_IP_SLAVE@",
+ "netmask" : "255.255.255.0",
+ "logging" :
+ {
+ "level" : "info",
+ "console" : "true",
+ "file" : { "enable" : "false", "path" : "/tmp/vsomeip.log" },
+ "dlt" : "false"
+ },
+ "applications" :
+ [
+ {
+ "name" : "service-sample",
+ "id" : "0x1277",
+ "has_session_handling" : "false"
+ }
+ ],
+ "services" :
+ [
+ {
+ "service" : "0xd025",
+ "instance" : "0x0001",
+ "unreliable" : "30501"
+ }
+ ],
+ "e2e" :
+ {
+ "e2e_enabled" : "true",
+ "protected" :
+ [
+ {
+ "service_id" : "0xd025",
+ "event_id" : "0x0001",
+ "profile" : "P04",
+ "variant" : "protector",
+ "crc_offset" : "64",
+ "data_id" : "0x2d"
+ }
+ ]
+ },
+ "routing" : "service-sample",
+ "service-discovery" :
+ {
+ "enable" : "true",
+ "multicast" : "224.0.0.1",
+ "port" : "30490",
+ "protocol" : "udp",
+ "initial_delay_min" : "10",
+ "initial_delay_max" : "100",
+ "repetitions_base_delay" : "200",
+ "repetitions_max" : "3",
+ "ttl" : "3",
+ "cyclic_offer_delay" : "2000",
+ "request_response_delay" : "1500"
+ }
+}
diff --git a/test/e2e_tests/e2e_profile_04_test_client.cpp b/test/e2e_tests/e2e_profile_04_test_client.cpp
new file mode 100644
index 0000000..7056e16
--- /dev/null
+++ b/test/e2e_tests/e2e_profile_04_test_client.cpp
@@ -0,0 +1,313 @@
+// Copyright (C) 2020 Bayerische Motoren Werke Aktiengesellschaft (BMW AG)
+// This Source Code Form is subject to the terms of the Mozilla Public
+// License, v. 2.0. If a copy of the MPL was not distributed with this
+// file, You can obtain one at http://mozilla.org/MPL/2.0/.
+
+#include "e2e_profile_04_test_common.hpp"
+#include "e2e_profile_04_test_client.hpp"
+
+#include <vsomeip/internal/logger.hpp>
+
+std::vector<std::vector<vsomeip::byte_t>> responses_;
+std::vector<std::vector<vsomeip::byte_t>> events_;
+
+std::map<vsomeip::method_t, uint32_t> counters_;
+
+
+e2e_profile_04_test_client::e2e_profile_04_test_client()
+ : app_(vsomeip::runtime::get()->create_application()),
+ is_available_(false),
+ sender_(std::bind(&e2e_profile_04_test_client::run, this)),
+ received_(0) {
+
+}
+
+bool
+e2e_profile_04_test_client::init() {
+
+ if (!app_->init()) {
+ ADD_FAILURE() << __func__ << ": Cannot initialize application";
+ return (false);
+ }
+
+ app_->register_state_handler(
+ std::bind(&e2e_profile_04_test_client::on_state, this,
+ std::placeholders::_1));
+
+ app_->register_message_handler(
+ PROFILE_04_SERVICE, PROFILE_04_INSTANCE, vsomeip::ANY_METHOD,
+ std::bind(&e2e_profile_04_test_client::on_message, this,
+ std::placeholders::_1));
+
+ app_->register_availability_handler(
+ PROFILE_04_SERVICE, PROFILE_04_INSTANCE,
+ std::bind(&e2e_profile_04_test_client::on_availability, this,
+ std::placeholders::_1, std::placeholders::_2,
+ std::placeholders::_3));
+
+ return (true);
+}
+
+void
+e2e_profile_04_test_client::start() {
+
+ VSOMEIP_INFO << __func__ << ": Starting...";
+ app_->start();
+}
+
+void
+e2e_profile_04_test_client::stop() {
+
+ VSOMEIP_INFO << __func__ << ": Stopping...";
+ shutdown_service();
+ app_->clear_all_handler();
+ app_->stop();
+}
+
+void
+e2e_profile_04_test_client::on_state(vsomeip::state_type_e _state) {
+
+ if (_state == vsomeip::state_type_e::ST_REGISTERED) {
+ app_->request_service(PROFILE_04_SERVICE, PROFILE_04_INSTANCE, false);
+
+ // request event 0x8001, that is protected by E2E Profile 04
+ app_->request_event(PROFILE_04_SERVICE, PROFILE_04_INSTANCE,
+ PROFILE_04_EVENT, { PROFILE_04_EVENTGROUP },
+ vsomeip::event_type_e::ET_FIELD,
+ vsomeip::reliability_type_e::RT_UNRELIABLE);
+ }
+}
+
+void
+e2e_profile_04_test_client::on_availability(
+ vsomeip::service_t _service, vsomeip::instance_t _instance,
+ bool _is_available) {
+
+ VSOMEIP_INFO << __func__ << ": Client "
+ << std::hex << std::setw(4) << std::setfill('0')
+ << app_->get_client()
+ << " : Service [" << _service << "." << _instance
+ << "] is " << (_is_available ? "available." : "NOT available.");
+
+ // check that correct service / instance ID gets available
+ if (_is_available) {
+ EXPECT_EQ(PROFILE_04_SERVICE, _service);
+ EXPECT_EQ(PROFILE_04_INSTANCE, _instance);
+ }
+
+ if (PROFILE_04_SERVICE == _service && PROFILE_04_INSTANCE == _instance) {
+ std::unique_lock<std::mutex> its_lock(mutex_);
+ if (is_available_ && !_is_available) {
+ is_available_ = false;
+ } else if(_is_available && !is_available_) {
+ is_available_ = true;
+
+ std::this_thread::sleep_for(std::chrono::milliseconds(1000));
+ app_->subscribe(PROFILE_04_SERVICE, PROFILE_04_INSTANCE,
+ PROFILE_04_EVENTGROUP, PROFILE_04_MAJOR);
+ std::this_thread::sleep_for(std::chrono::milliseconds(1000));
+ condition_.notify_one();
+ }
+ }
+}
+
+void
+e2e_profile_04_test_client::on_message(const std::shared_ptr<vsomeip::message> &_message) {
+
+ VSOMEIP_INFO << __func__ << ": Received a message from Service ["
+ << std::setw(4) << std::setfill('0') << std::hex
+ << _message->get_service() << "." << _message->get_instance()
+ << "] to Client/Session ["
+ << _message->get_client() << "/" << _message->get_session()
+ << "]";
+
+ EXPECT_EQ(PROFILE_04_SERVICE, _message->get_service());
+ EXPECT_EQ(PROFILE_04_INSTANCE, _message->get_instance());
+
+ // check fixed payload / CRC in response for service: d025 method: 0001
+ if (vsomeip::message_type_e::MT_RESPONSE == _message->get_message_type()
+ && PROFILE_04_METHOD == _message->get_method()) {
+ // check for calculated CRC status OK for the predefined fixed payload sent by service
+ VSOMEIP_INFO << "Method ID 0x0001 -> IS_VALID_CRC = "
+ << std::boolalpha << _message->is_valid_crc();
+ EXPECT_EQ(true, _message->is_valid_crc());
+
+ // check if payload is as expected as well (including CRC / counter / data ID)
+ std::shared_ptr<vsomeip::payload> its_payload = _message->get_payload();
+ const auto its_data = its_payload->get_data();
+ for (size_t i = 0; i < its_payload->get_length(); i++)
+ EXPECT_EQ(its_data[i], responses_[counters_[PROFILE_04_METHOD]
+ % PROFILE_O4_NUM_MESSAGES][i]);
+
+ counters_[PROFILE_04_METHOD]++;
+
+ } else if (vsomeip::message_type_e::MT_NOTIFICATION == _message->get_message_type()
+ && PROFILE_04_EVENT == _message->get_method()) {
+
+ // check CRC / payload calculated by sender for event 0x8001 against expected payload
+ // check for calculated CRC status OK for the calculated CRC / payload sent by service
+ VSOMEIP_INFO << __func__ << ": Event 0x8001 -> IS_VALID_CRC = "
+ << std::boolalpha << _message->is_valid_crc();
+ EXPECT_EQ(true, _message->is_valid_crc());
+
+ // check if payload is as expected as well (including CRC / counter / data ID nibble)
+ std::shared_ptr<vsomeip::payload> its_payload = _message->get_payload();
+ const auto its_data = its_payload->get_data();
+ for (size_t i = 0; i< its_payload->get_length(); i++)
+ EXPECT_EQ(its_data[i], events_[counters_[PROFILE_04_EVENT]
+ % PROFILE_O4_NUM_MESSAGES][i]);
+
+ counters_[PROFILE_04_EVENT]++;
+ }
+
+ received_++;
+ if (received_ == PROFILE_O4_NUM_MESSAGES * 2) {
+ VSOMEIP_WARNING << __func__ << ": Client"
+ << std::setw(4) << std::setfill('0') << std::hex
+ << app_->get_client()
+ << " received all messages ~> going down!";
+ }
+}
+
+void
+e2e_profile_04_test_client::run() {
+
+ for (int i = 0; i < PROFILE_O4_NUM_MESSAGES; ++i) {
+ {
+ std::unique_lock<std::mutex> its_lock(mutex_);
+ while (!is_available_) {
+ condition_.wait(its_lock);
+ }
+ }
+
+ auto request = vsomeip::runtime::get()->create_request(false);
+ request->set_service(PROFILE_04_SERVICE);
+ request->set_instance(PROFILE_04_INSTANCE);
+ request->set_interface_version(PROFILE_04_MAJOR);
+
+ // send a request which is not e2e protected and expect an
+ // protected answer holding a fixed payload (E2E Profile 04)
+ // this call triggers also an event 0x8001 which holds a
+ // calculated payload
+ request->set_method(PROFILE_04_METHOD);
+
+ app_->send(request);
+
+ std::this_thread::sleep_for(std::chrono::milliseconds(250));
+ }
+
+ stop();
+}
+
+void
+e2e_profile_04_test_client::join_sender_thread() {
+
+ if (sender_.joinable()) {
+ sender_.join();
+ }
+}
+
+void
+e2e_profile_04_test_client::shutdown_service() {
+
+ auto request = vsomeip::runtime::get()->create_request(false);
+ request->set_service(PROFILE_04_SERVICE);
+ request->set_instance(PROFILE_04_INSTANCE);
+ request->set_method(PROFILE_04_SHUTDOWN);
+ request->set_interface_version(PROFILE_04_MAJOR);
+
+ app_->send(request);
+
+ std::this_thread::sleep_for(std::chrono::milliseconds(250));
+
+ // expect 10 responses + 10 events
+ EXPECT_EQ(received_, PROFILE_O4_NUM_MESSAGES * 2);
+}
+
+TEST(someip_e2e_profile_04_test, test_crc_calculation) {
+
+ e2e_profile_04_test_client test_client;
+
+ if (test_client.init()) {
+ test_client.start();
+ test_client.join_sender_thread();
+ }
+}
+
+int main(int argc, char** argv) {
+
+ responses_ = {
+ {
+ 0x00, 0x50, 0x00, 0x00, 0x01, 0x00, 0x00, 0x2d,
+ 0xaa, 0x1d, 0x3f, 0xdf, 0x08, 0xb7, 0xf4, 0x4c,
+ 0x00, 0x00, 0x09, 0x3d, 0x00, 0x01, 0x06, 0xfe,
+ 0x01, 0x3e, 0x4c, 0xcc, 0xcd, 0x80, 0x3f, 0xb2,
+ 0x3d, 0x83, 0x3e, 0xba, 0x68, 0xed, 0x3f, 0xb3,
+ 0x7a, 0xf2, 0xbd, 0x96, 0xc1, 0x42, 0x3d, 0x25,
+ 0x1a, 0x62, 0xbd, 0xae, 0x77, 0xf3, 0x3f, 0x80,
+ 0x00, 0x00, 0xfc, 0x01, 0x01, 0x3c, 0x1d, 0xbd,
+ 0x4e, 0x01, 0x01, 0x3c, 0x2b, 0x87, 0xed, 0x00
+ },
+ {
+ 0x00, 0x50, 0x00, 0x01, 0x01, 0x00, 0x00, 0x2d,
+ 0xe7, 0xb7, 0x13, 0x87, 0x0c, 0x69, 0x02, 0x1c,
+ 0x00, 0x00, 0x09, 0x3d, 0x00, 0x01, 0x06, 0xfe,
+ 0x01, 0x3e, 0x4c, 0xcc, 0xcd, 0x80, 0x3f, 0xb2,
+ 0x3c, 0x2f, 0x3e, 0xba, 0x46, 0x81, 0x3f, 0xb3,
+ 0x73, 0x8d, 0xbd, 0x93, 0xcb, 0xae, 0x3c, 0xf7,
+ 0xd2, 0x58, 0xbd, 0xa2, 0x6e, 0xcd, 0x3f, 0x80,
+ 0x00, 0x00, 0xfc, 0x01, 0x01, 0x3c, 0x1c, 0x89,
+ 0x24, 0x01, 0x01, 0x3c, 0x2b, 0x24, 0x45, 0x00
+ },
+ {
+ 0x00, 0x50, 0x00, 0x02, 0x01, 0x00, 0x00, 0x2d,
+ 0xb6, 0x19, 0x94, 0x2c, 0x10, 0x1b, 0x28, 0xae,
+ 0x00, 0x00, 0x09, 0x3d, 0x00, 0x01, 0x06, 0xfe,
+ 0x01, 0x3e, 0x4c, 0xcc, 0xcd, 0x80, 0x3f, 0xb2,
+ 0x3e, 0xf3, 0x3e, 0xba, 0x97, 0x45, 0x3f, 0xb3,
+ 0x86, 0x81, 0xbd, 0x8a, 0xda, 0xc2, 0x3c, 0xf6,
+ 0x00, 0x7a, 0xbd, 0xb4, 0xf9, 0xb9, 0x3f, 0x80,
+ 0x00, 0x00, 0xfc, 0x01, 0x01, 0x3c, 0x1c, 0x1b,
+ 0x72, 0x01, 0x01, 0x3c, 0x2a, 0x9e, 0x1f, 0x00
+ }
+ };
+
+ events_ = {
+ {
+ 0x00, 0x50, 0x8f, 0x81, 0x01, 0x00, 0x00, 0x2d,
+ 0xed, 0x6e, 0x78, 0x8d, 0x08, 0xb7, 0xf4, 0x4c,
+ 0x00, 0x00, 0x09, 0x3d, 0x00, 0x01, 0x06, 0xfe,
+ 0x01, 0x3e, 0x4c, 0xcc, 0xcd, 0x80, 0x3f, 0xb2,
+ 0x3d, 0x83, 0x3e, 0xba, 0x68, 0xed, 0x3f, 0xb3,
+ 0x7a, 0xf2, 0xbd, 0x96, 0xc1, 0x42, 0x3d, 0x25,
+ 0x1a, 0x62, 0xbd, 0xae, 0x77, 0xf3, 0x3f, 0x80,
+ 0x00, 0x00, 0xfc, 0x01, 0x01, 0x3c, 0x1d, 0xbd,
+ 0x4e, 0x01, 0x01, 0x3c, 0x2b, 0x87, 0xed, 0x00
+ },
+ {
+ 0x00, 0x50, 0x8f, 0x82, 0x01, 0x00, 0x00, 0x2d,
+ 0x9d, 0xbb, 0x49, 0x3f, 0x0c, 0x69, 0x02, 0x1c,
+ 0x00, 0x00, 0x09, 0x3d, 0x00, 0x01, 0x06, 0xfe,
+ 0x01, 0x3e, 0x4c, 0xcc, 0xcd, 0x80, 0x3f, 0xb2,
+ 0x3c, 0x2f, 0x3e, 0xba, 0x46, 0x81, 0x3f, 0xb3,
+ 0x73, 0x8d, 0xbd, 0x93, 0xcb, 0xae, 0x3c, 0xf7,
+ 0xd2, 0x58, 0xbd, 0xa2, 0x6e, 0xcd, 0x3f, 0x80,
+ 0x00, 0x00, 0xfc, 0x01, 0x01, 0x3c, 0x1c, 0x89,
+ 0x24, 0x01, 0x01, 0x3c, 0x2b, 0x24, 0x45, 0x00
+ },
+ {
+ 0x00, 0x50, 0x8f, 0x83, 0x01, 0x00, 0x00, 0x2d,
+ 0x13, 0x04, 0xf8, 0x81, 0x10, 0x1b, 0x28, 0xae,
+ 0x00, 0x00, 0x09, 0x3d, 0x00, 0x01, 0x06, 0xfe,
+ 0x01, 0x3e, 0x4c, 0xcc, 0xcd, 0x80, 0x3f, 0xb2,
+ 0x3e, 0xf3, 0x3e, 0xba, 0x97, 0x45, 0x3f, 0xb3,
+ 0x86, 0x81, 0xbd, 0x8a, 0xda, 0xc2, 0x3c, 0xf6,
+ 0x00, 0x7a, 0xbd, 0xb4, 0xf9, 0xb9, 0x3f, 0x80,
+ 0x00, 0x00, 0xfc, 0x01, 0x01, 0x3c, 0x1c, 0x1b,
+ 0x72, 0x01, 0x01, 0x3c, 0x2a, 0x9e, 0x1f, 0x00
+ }
+ };
+
+ ::testing::InitGoogleTest(&argc, argv);
+ return RUN_ALL_TESTS();
+}
diff --git a/test/e2e_tests/e2e_profile_04_test_client.hpp b/test/e2e_tests/e2e_profile_04_test_client.hpp
new file mode 100644
index 0000000..ad00291
--- /dev/null
+++ b/test/e2e_tests/e2e_profile_04_test_client.hpp
@@ -0,0 +1,48 @@
+// Copyright (C) 2020 Bayerische Motoren Werke Aktiengesellschaft (BMW AG)
+// This Source Code Form is subject to the terms of the Mozilla Public
+// License, v. 2.0. If a copy of the MPL was not distributed with this
+// file, You can obtain one at http://mozilla.org/MPL/2.0/.
+
+#ifndef E2E_PROFILE_04_TEST_CLIENT_HPP_
+#define E2E_PROFILE_04_TEST_CLIENT_HPP_
+
+#include <gtest/gtest.h>
+
+#include <vsomeip/vsomeip.hpp>
+
+#include <thread>
+#include <mutex>
+#include <condition_variable>
+#include <atomic>
+
+class e2e_profile_04_test_client {
+public:
+ e2e_profile_04_test_client();
+
+ bool init();
+ void start();
+ void stop();
+
+ void on_state(vsomeip::state_type_e _state);
+ void on_availability(vsomeip::service_t _service,
+ vsomeip::instance_t _instance, bool _is_available);
+ void on_message(const std::shared_ptr<vsomeip::message> &_response);
+
+ void run();
+ void join_sender_thread();
+
+private:
+ void shutdown_service();
+
+ std::shared_ptr<vsomeip::application> app_;
+
+ std::mutex mutex_;
+ std::condition_variable condition_;
+ bool is_available_;
+
+ std::thread sender_;
+
+ std::atomic<uint32_t> received_;
+};
+
+#endif // E2E_PROFILE_04_TEST_CLIENT_HPP_
diff --git a/test/e2e_tests/e2e_profile_04_test_common.hpp b/test/e2e_tests/e2e_profile_04_test_common.hpp
new file mode 100644
index 0000000..04cba23
--- /dev/null
+++ b/test/e2e_tests/e2e_profile_04_test_common.hpp
@@ -0,0 +1,24 @@
+// Copyright (C) 2020 Bayerische Motoren Werke Aktiengesellschaft (BMW AG)
+// This Source Code Form is subject to the terms of the Mozilla Public
+// License, v. 2.0. If a copy of the MPL was not distributed with this
+// file, You can obtain one at http://mozilla.org/MPL/2.0/.
+
+#ifndef E2E_PROFILE_04_TEST_COMMON_HPP_
+#define E2E_PROFILE_04_TEST_COMMON_HPP_
+
+#include <vsomeip/vsomeip.hpp>
+
+const vsomeip::service_t PROFILE_04_SERVICE = 0xd025;
+const vsomeip::instance_t PROFILE_04_INSTANCE = 0x0001;
+const vsomeip::major_version_t PROFILE_04_MAJOR = 0x01;
+const vsomeip::minor_version_t PROFILE_04_MINOR = 0x00000000;
+
+const vsomeip::method_t PROFILE_04_METHOD = 0x0001;
+const vsomeip::method_t PROFILE_04_SHUTDOWN = 0x0002;
+
+const vsomeip::eventgroup_t PROFILE_04_EVENTGROUP = 0x0001;
+const vsomeip::event_t PROFILE_04_EVENT = 0x8001;
+
+#define PROFILE_O4_NUM_MESSAGES 3
+
+#endif // E2E_PROFILE_04_TEST_COMMON_HPP_
diff --git a/test/e2e_tests/e2e_profile_04_test_external_master_start.sh b/test/e2e_tests/e2e_profile_04_test_external_master_start.sh
new file mode 100755
index 0000000..ce16d71
--- /dev/null
+++ b/test/e2e_tests/e2e_profile_04_test_external_master_start.sh
@@ -0,0 +1,76 @@
+#!/bin/bash
+# Copyright (C) 2015-2018 Bayerische Motoren Werke Aktiengesellschaft (BMW AG)
+# This Source Code Form is subject to the terms of the Mozilla Public
+# License, v. 2.0. If a copy of the MPL was not distributed with this
+# file, You can obtain one at http://mozilla.org/MPL/2.0/.
+
+# Purpose: This script is needed to start the services with
+# one command. This is necessary as ctest - which is used to run the
+# tests - isn't able to start multiple binaries for one testcase. Therefore
+# the testcase simply executes this script. This script then runs the services
+# and checks that all exit successfully.
+
+if [ $# -lt 1 ]
+then
+ echo "Please pass a json file to this script"
+ echo "For example: $0 e2e_profile_04_test_client_external.json"
+ exit 1
+fi
+
+MASTER_JSON_FILE=$1
+SERVICE_JSON_FILE=${MASTER_JSON_FILE/client/service}
+ALLOW_DENY=$2
+
+FAIL=0
+
+export VSOMEIP_CONFIGURATION=$1
+export VSOMEIP_APPLICATION_NAME=client-sample
+./e2e_profile_04_test_client --remote &
+PID_CLIENT=$!
+
+
+if [ ! -z "$USE_LXC_TEST" ]; then
+ echo "starting external e2e profile 04 test on slave LXC"
+ ssh -tt -i $SANDBOX_ROOT_DIR/commonapi_main/lxc-config/.ssh/mgc_lxc/rsa_key_file.pub -o StrictHostKeyChecking=no root@$LXC_TEST_SLAVE_IP "bash -ci \"set -m; cd \\\$SANDBOX_TARGET_DIR/vsomeip_lib/test; ./e2e_profile_04_test_external_slave_start.sh $SERVICE_JSON_FILE\"" &
+elif [ ! -z "$USE_DOCKER" ]; then
+ docker run --name citms --cap-add NET_ADMIN $DOCKER_IMAGE sh -c "route add -net 224.0.0.0/4 dev eth0 && cd $DOCKER_TESTS && ./e2e_profile_04_test_external_slave_start.sh $SERVICE_JSON_FILE" &
+else
+cat <<End-of-message
+*******************************************************************************
+*******************************************************************************
+** Please now run:
+** e2e_profile_04_test_external_slave_start.sh $SERVICE_JSON_FILE
+** from an external host to successfully complete this test.
+**
+** You probably will need to adapt the 'unicast' settings in
+** e2e_profile_04_test_service_external.json and
+** e2e_profile_04_test_client_external.json to your personal setup.
+*******************************************************************************
+*******************************************************************************
+End-of-message
+fi
+
+# Wait until client and service are finished
+for client_pid in "${PID_CLIENT}"
+do
+ if [ -n "$client_pid" ]; then
+ # Fail gets incremented if either client or service exit
+ # with a non-zero exit code
+ wait "$client_pid" || ((FAIL+=1))
+ fi
+done
+
+if [ ! -z "$USE_DOCKER" ]; then
+ docker stop citms
+ docker rm citms
+fi
+
+kill $PID_CLIENT
+
+# Check if both exited successfully
+if [ $FAIL -eq 0 ]
+then
+ exit 0
+else
+ exit 1
+fi
diff --git a/test/e2e_tests/e2e_profile_04_test_external_slave_start.sh b/test/e2e_tests/e2e_profile_04_test_external_slave_start.sh
new file mode 100755
index 0000000..afd692b
--- /dev/null
+++ b/test/e2e_tests/e2e_profile_04_test_external_slave_start.sh
@@ -0,0 +1,50 @@
+#!/bin/bash
+# Copyright (C) 2015-2018 Bayerische Motoren Werke Aktiengesellschaft (BMW AG)
+# This Source Code Form is subject to the terms of the Mozilla Public
+# License, v. 2.0. If a copy of the MPL was not distributed with this
+# file, You can obtain one at http://mozilla.org/MPL/2.0/.
+
+# Purpose: This script is needed to start the services with
+# one command. This is necessary as ctest - which is used to run the
+# tests - isn't able to start multiple binaries for one testcase. Therefore
+# the testcase simply executes this script. This script then runs the services
+# and checks that all exit successfully.
+
+if [ $# -lt 1 ]
+then
+ echo "Please pass a json file to this script"
+ echo "For example: $0 e2e_profile_04_test_service_external.json"
+ exit 1
+fi
+
+FAIL=0
+
+export VSOMEIP_CONFIGURATION=$1
+export VSOMEIP_APPLICATION_NAME=service-sample
+./e2e_profile_04_test_service --remote &
+PID_SERVICE=$!
+
+# Wait until client and service are finished
+for client_pid in "${PID_SERVICE}"
+do
+ if [ -n "$client_pid" ]; then
+ # Fail gets incremented if either client or service exit
+ # with a non-zero exit code
+ wait "$client_pid" || ((FAIL+=1))
+ fi
+done
+
+if [ ! -z "$USE_DOCKER" ]; then
+ docker stop citms
+ docker rm citms
+fi
+
+kill $PID_SERVICE
+
+# Check if both exited successfully
+if [ $FAIL -eq 0 ]
+then
+ exit 0
+else
+ exit 1
+fi
diff --git a/test/e2e_tests/e2e_profile_04_test_service.cpp b/test/e2e_tests/e2e_profile_04_test_service.cpp
new file mode 100644
index 0000000..ca54084
--- /dev/null
+++ b/test/e2e_tests/e2e_profile_04_test_service.cpp
@@ -0,0 +1,324 @@
+// Copyright (C) 2020 Bayerische Motoren Werke Aktiengesellschaft (BMW AG)
+// This Source Code Form is subject to the terms of the Mozilla Public
+// License, v. 2.0. If a copy of the MPL was not distributed with this
+// file, You can obtain one at http://mozilla.org/MPL/2.0/.
+
+#include "e2e_profile_04_test_common.hpp"
+#include "e2e_profile_04_test_service.hpp"
+
+static bool is_remote_test = false;
+static bool remote_client_allowed = true;
+
+std::vector<std::vector<vsomeip::byte_t> > responses_;
+std::vector<std::vector<vsomeip::byte_t> > events_;
+
+std::map<vsomeip::method_t, uint32_t> counters_;
+
+e2e_profile_04_test_service::e2e_profile_04_test_service()
+ : app_(vsomeip::runtime::get()->create_application()),
+ is_registered_(false),
+ blocked_(false),
+ offer_thread_(std::bind(&e2e_profile_04_test_service::run, this)),
+ received_(0) {
+}
+
+bool
+e2e_profile_04_test_service::init() {
+
+ std::lock_guard<std::mutex> its_lock(mutex_);
+
+ if (!app_->init()) {
+ ADD_FAILURE() << __func__ << ": Cannot initialize application.";
+ return false;
+ }
+
+ app_->register_message_handler(PROFILE_04_SERVICE, PROFILE_04_INSTANCE,
+ PROFILE_04_METHOD,
+ std::bind(&e2e_profile_04_test_service::on_message, this,
+ std::placeholders::_1));
+
+ app_->register_message_handler(PROFILE_04_SERVICE, PROFILE_04_INSTANCE,
+ PROFILE_04_SHUTDOWN,
+ std::bind(&e2e_profile_04_test_service::on_message_shutdown, this,
+ std::placeholders::_1));
+
+ app_->register_state_handler(
+ std::bind(&e2e_profile_04_test_service::on_state, this,
+ std::placeholders::_1));
+
+ // E2E Profile 04: Event 8001
+ app_->offer_event(PROFILE_04_SERVICE, PROFILE_04_INSTANCE,
+ PROFILE_04_EVENT, { PROFILE_04_EVENTGROUP },
+ vsomeip::event_type_e::ET_FIELD, std::chrono::milliseconds::zero(),
+ false, true, nullptr, vsomeip::reliability_type_e::RT_UNRELIABLE);
+
+ // Initialize the attribute
+ auto its_payload = vsomeip::runtime::get()->create_payload();
+ vsomeip::byte_t its_data[] = {
+ 0x00, 0x50, 0x8f, 0x80, 0x01, 0x00, 0x00, 0x2d,
+ 0xf3, 0x2a, 0x8c, 0x89, 0x05, 0x04, 0xcc, 0x46,
+ 0x00, 0x00, 0x09, 0x3d, 0x00, 0x01, 0x06, 0xfe,
+ 0x01, 0x3e, 0x4c, 0xcc, 0xcd, 0x80, 0x3f, 0xb2,
+ 0x40, 0xb1, 0x3e, 0xba, 0xc4, 0x76, 0x3f, 0xb3,
+ 0x7b, 0x03, 0xbd, 0x95, 0x74, 0x53, 0x3d, 0x32,
+ 0x4b, 0x9d, 0xbd, 0xbc, 0xd6, 0x3b, 0x3f, 0x80,
+ 0x00, 0x00, 0xfc, 0x01, 0x01, 0x3c, 0x1f, 0xf5,
+ 0xf6, 0x01, 0x01, 0x3c, 0x2b, 0xb1, 0xa2, 0x00
+ };
+ its_payload->set_data(its_data, sizeof(its_data));
+
+ app_->notify(vsomeip_test::TEST_SERVICE_SERVICE_ID, vsomeip_test::TEST_SERVICE_INSTANCE_ID,
+ static_cast<vsomeip::event_t>(0x8001), its_payload);
+
+ return (true);
+}
+
+void
+e2e_profile_04_test_service::start() {
+
+ VSOMEIP_INFO << __func__ << ": Starting...";
+ app_->start();
+}
+
+void
+e2e_profile_04_test_service::stop() {
+
+ VSOMEIP_INFO << __func__ << ": Stopping...";
+ app_->clear_all_handler();
+ app_->stop();
+}
+
+void
+e2e_profile_04_test_service::join_offer_thread() {
+
+ if (offer_thread_.joinable()) {
+ offer_thread_.join();
+ }
+}
+
+void
+e2e_profile_04_test_service::offer() {
+
+ app_->offer_service(PROFILE_04_SERVICE, PROFILE_04_INSTANCE,
+ PROFILE_04_MAJOR, PROFILE_04_MINOR);
+}
+
+void
+e2e_profile_04_test_service::stop_offer() {
+
+ app_->stop_offer_service(PROFILE_04_SERVICE, PROFILE_04_INSTANCE,
+ PROFILE_04_MAJOR, PROFILE_04_MINOR);
+}
+
+void
+e2e_profile_04_test_service::on_state(vsomeip::state_type_e _state) {
+
+ VSOMEIP_INFO << __func__ << ": Application "
+ << app_->get_name() << " is "
+ << (_state == vsomeip::state_type_e::ST_REGISTERED ?
+ "registered." : "deregistered.");
+
+ if (_state == vsomeip::state_type_e::ST_REGISTERED) {
+ if (!is_registered_) {
+ is_registered_ = true;
+
+ std::lock_guard<std::mutex> its_lock(mutex_);
+ blocked_ = true;
+
+ // "start" the run method thread
+ condition_.notify_one();
+ }
+ } else {
+ is_registered_ = false;
+ }
+}
+
+void
+e2e_profile_04_test_service::on_message(
+ const std::shared_ptr<vsomeip::message> &_request) {
+
+ ASSERT_EQ(PROFILE_04_SERVICE, _request->get_service());
+ ASSERT_EQ(PROFILE_04_INSTANCE, _request->get_instance());
+
+ VSOMEIP_INFO << "Received a message with Client/Session ["
+ << std::setw(4) << std::setfill('0') << std::hex
+ << _request->get_client() << "/" << _request->get_session()
+ << "] method: " << _request->get_method() ;
+
+ std::shared_ptr<vsomeip::message> its_response =
+ vsomeip::runtime::get()->create_response(_request);
+ std::shared_ptr< vsomeip::payload > its_response_payload =
+ vsomeip::runtime::get()->create_payload();
+ std::shared_ptr<vsomeip::payload> its_event_payload =
+ vsomeip::runtime::get()->create_payload();
+
+ // send fixed payload for profile 01 CRC8
+ if (PROFILE_04_METHOD == _request->get_method()) {
+ its_response_payload->set_data(responses_[counters_[PROFILE_04_METHOD] % PROFILE_O4_NUM_MESSAGES]);
+ its_response->set_payload(its_response_payload);
+ app_->send(its_response);
+
+ counters_[PROFILE_04_METHOD]++;
+
+ // set value to field which gets filled by e2e protection with CRC on sending
+ its_event_payload->set_data(events_[counters_[PROFILE_04_EVENT] % PROFILE_O4_NUM_MESSAGES]);
+ app_->notify(PROFILE_04_SERVICE, PROFILE_04_INSTANCE, PROFILE_04_EVENT, its_event_payload);
+
+ counters_[PROFILE_04_EVENT]++;
+ }
+
+ received_++;
+ if (received_ == PROFILE_O4_NUM_MESSAGES) {
+ VSOMEIP_INFO << __func__ << ": Received all messages!";
+ }
+}
+
+void
+e2e_profile_04_test_service::on_message_shutdown(
+ const std::shared_ptr<vsomeip::message> &_request) {
+
+ (void)_request;
+ VSOMEIP_INFO << __func__ << ": Shutdown method was called, going down now.";
+ stop();
+}
+
+void
+e2e_profile_04_test_service::run() {
+
+ std::unique_lock<std::mutex> its_lock(mutex_);
+ while (!blocked_)
+ condition_.wait(its_lock);
+
+ offer();
+}
+
+TEST(someip_e2e_profile_04_test, basic_subscribe_request_response) {
+ e2e_profile_04_test_service test_service;
+ if (test_service.init()) {
+ test_service.start();
+ test_service.join_offer_thread();
+ }
+}
+
+#ifndef _WIN32
+int main(int argc, char** argv) {
+
+
+ counters_[PROFILE_04_METHOD] = 0;
+ counters_[PROFILE_04_EVENT] = 0;
+
+ std::string test_remote("--remote");
+ std::string test_local("--local");
+ std::string test_allow_remote_client("--allow");
+ std::string test_deny_remote_client("--deny");
+ std::string help("--help");
+
+ int i = 1;
+ while (i < argc)
+ {
+ if(test_remote == argv[i])
+ {
+ is_remote_test = true;
+ }
+ else if(test_local == argv[i])
+ {
+ is_remote_test = false;
+ }
+ else if(test_allow_remote_client == argv[i])
+ {
+ remote_client_allowed = true;
+ }
+ else if(test_deny_remote_client == argv[i])
+ {
+ remote_client_allowed = false;
+ }
+ else if(help == argv[i])
+ {
+ VSOMEIP_INFO << "Parameters:\n"
+ << "--remote: Run test between two hosts\n"
+ << "--local: Run test locally\n"
+ << "--allow: test is started with a policy that allows remote messages sent by this test client to the service\n"
+ << "--deny: test is started with a policy that denies remote messages sent by this test client to the service\n"
+ << "--help: print this help";
+ }
+ i++;
+ }
+
+ // Payloads (without counter, data id and crc)
+ responses_ = {
+ {
+ 0x00, 0x50, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x08, 0xb7, 0xf4, 0x4c,
+ 0x00, 0x00, 0x09, 0x3d, 0x00, 0x01, 0x06, 0xfe,
+ 0x01, 0x3e, 0x4c, 0xcc, 0xcd, 0x80, 0x3f, 0xb2,
+ 0x3d, 0x83, 0x3e, 0xba, 0x68, 0xed, 0x3f, 0xb3,
+ 0x7a, 0xf2, 0xbd, 0x96, 0xc1, 0x42, 0x3d, 0x25,
+ 0x1a, 0x62, 0xbd, 0xae, 0x77, 0xf3, 0x3f, 0x80,
+ 0x00, 0x00, 0xfc, 0x01, 0x01, 0x3c, 0x1d, 0xbd,
+ 0x4e, 0x01, 0x01, 0x3c, 0x2b, 0x87, 0xed, 0x00
+ },
+ {
+ 0x00, 0x50, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x0c, 0x69, 0x02, 0x1c,
+ 0x00, 0x00, 0x09, 0x3d, 0x00, 0x01, 0x06, 0xfe,
+ 0x01, 0x3e, 0x4c, 0xcc, 0xcd, 0x80, 0x3f, 0xb2,
+ 0x3c, 0x2f, 0x3e, 0xba, 0x46, 0x81, 0x3f, 0xb3,
+ 0x73, 0x8d, 0xbd, 0x93, 0xcb, 0xae, 0x3c, 0xf7,
+ 0xd2, 0x58, 0xbd, 0xa2, 0x6e, 0xcd, 0x3f, 0x80,
+ 0x00, 0x00, 0xfc, 0x01, 0x01, 0x3c, 0x1c, 0x89,
+ 0x24, 0x01, 0x01, 0x3c, 0x2b, 0x24, 0x45, 0x00
+ },
+ {
+ 0x00, 0x50, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x10, 0x1b, 0x28, 0xae,
+ 0x00, 0x00, 0x09, 0x3d, 0x00, 0x01, 0x06, 0xfe,
+ 0x01, 0x3e, 0x4c, 0xcc, 0xcd, 0x80, 0x3f, 0xb2,
+ 0x3e, 0xf3, 0x3e, 0xba, 0x97, 0x45, 0x3f, 0xb3,
+ 0x86, 0x81, 0xbd, 0x8a, 0xda, 0xc2, 0x3c, 0xf6,
+ 0x00, 0x7a, 0xbd, 0xb4, 0xf9, 0xb9, 0x3f, 0x80,
+ 0x00, 0x00, 0xfc, 0x01, 0x01, 0x3c, 0x1c, 0x1b,
+ 0x72, 0x01, 0x01, 0x3c, 0x2a, 0x9e, 0x1f, 0x00
+ }
+ };
+
+ // Payloads (full data with counter, data id and crc to be sent raw)
+ events_ = {
+ {
+ 0x00, 0x50, 0x8f, 0x81, 0x01, 0x00, 0x00, 0x2d,
+ 0xed, 0x6e, 0x78, 0x8d, 0x08, 0xb7, 0xf4, 0x4c,
+ 0x00, 0x00, 0x09, 0x3d, 0x00, 0x01, 0x06, 0xfe,
+ 0x01, 0x3e, 0x4c, 0xcc, 0xcd, 0x80, 0x3f, 0xb2,
+ 0x3d, 0x83, 0x3e, 0xba, 0x68, 0xed, 0x3f, 0xb3,
+ 0x7a, 0xf2, 0xbd, 0x96, 0xc1, 0x42, 0x3d, 0x25,
+ 0x1a, 0x62, 0xbd, 0xae, 0x77, 0xf3, 0x3f, 0x80,
+ 0x00, 0x00, 0xfc, 0x01, 0x01, 0x3c, 0x1d, 0xbd,
+ 0x4e, 0x01, 0x01, 0x3c, 0x2b, 0x87, 0xed, 0x00
+ },
+ {
+ 0x00, 0x50, 0x8f, 0x82, 0x01, 0x00, 0x00, 0x2d,
+ 0x9d, 0xbb, 0x49, 0x3f, 0x0c, 0x69, 0x02, 0x1c,
+ 0x00, 0x00, 0x09, 0x3d, 0x00, 0x01, 0x06, 0xfe,
+ 0x01, 0x3e, 0x4c, 0xcc, 0xcd, 0x80, 0x3f, 0xb2,
+ 0x3c, 0x2f, 0x3e, 0xba, 0x46, 0x81, 0x3f, 0xb3,
+ 0x73, 0x8d, 0xbd, 0x93, 0xcb, 0xae, 0x3c, 0xf7,
+ 0xd2, 0x58, 0xbd, 0xa2, 0x6e, 0xcd, 0x3f, 0x80,
+ 0x00, 0x00, 0xfc, 0x01, 0x01, 0x3c, 0x1c, 0x89,
+ 0x24, 0x01, 0x01, 0x3c, 0x2b, 0x24, 0x45, 0x00
+ },
+ {
+ 0x00, 0x50, 0x8f, 0x83, 0x01, 0x00, 0x00, 0x2d,
+ 0x13, 0x04, 0xf8, 0x81, 0x10, 0x1b, 0x28, 0xae,
+ 0x00, 0x00, 0x09, 0x3d, 0x00, 0x01, 0x06, 0xfe,
+ 0x01, 0x3e, 0x4c, 0xcc, 0xcd, 0x80, 0x3f, 0xb2,
+ 0x3e, 0xf3, 0x3e, 0xba, 0x97, 0x45, 0x3f, 0xb3,
+ 0x86, 0x81, 0xbd, 0x8a, 0xda, 0xc2, 0x3c, 0xf6,
+ 0x00, 0x7a, 0xbd, 0xb4, 0xf9, 0xb9, 0x3f, 0x80,
+ 0x00, 0x00, 0xfc, 0x01, 0x01, 0x3c, 0x1c, 0x1b,
+ 0x72, 0x01, 0x01, 0x3c, 0x2a, 0x9e, 0x1f, 0x00
+ }
+ };
+
+ ::testing::InitGoogleTest(&argc, argv);
+ return RUN_ALL_TESTS();
+}
+#endif
diff --git a/test/e2e_tests/e2e_profile_04_test_service.hpp b/test/e2e_tests/e2e_profile_04_test_service.hpp
new file mode 100644
index 0000000..626db05
--- /dev/null
+++ b/test/e2e_tests/e2e_profile_04_test_service.hpp
@@ -0,0 +1,48 @@
+// Copyright (C) 2020 Bayerische Motoren Werke Aktiengesellschaft (BMW AG)
+// This Source Code Form is subject to the terms of the Mozilla Public
+// License, v. 2.0. If a copy of the MPL was not distributed with this
+// file, You can obtain one at http://mozilla.org/MPL/2.0/.
+
+#ifndef E2E_PROFILE_04_TEST_SERVICE_HPP_
+#define E2E_PROFILE_04_TEST_SERVICE_HPP_
+
+#include <gtest/gtest.h>
+
+#include <vsomeip/vsomeip.hpp>
+
+#include "../someip_test_globals.hpp"
+
+#include <atomic>
+#include <condition_variable>
+#include <mutex>
+#include <thread>
+
+class e2e_profile_04_test_service {
+public:
+ e2e_profile_04_test_service();
+
+ bool init();
+ void start();
+ void stop();
+ void offer();
+ void stop_offer();
+ void join_offer_thread();
+ void on_state(vsomeip::state_type_e _state);
+ void on_message(const std::shared_ptr<vsomeip::message> &_request);
+ void on_message_shutdown(const std::shared_ptr<vsomeip::message> &_request);
+ void run();
+
+private:
+ std::shared_ptr<vsomeip::application> app_;
+ bool is_registered_;
+
+ bool blocked_;
+ std::mutex mutex_;
+ std::condition_variable condition_;
+
+ std::thread offer_thread_;
+
+ std::atomic<uint32_t> received_;
+};
+
+#endif // E2E_PROFILE_04_TEST_SERVICE_HPP_