summaryrefslogtreecommitdiffstats
path: root/lib/asio/detail
diff options
context:
space:
mode:
Diffstat (limited to 'lib/asio/detail')
-rw-r--r--lib/asio/detail/array.hpp38
-rw-r--r--lib/asio/detail/array_fwd.hpp34
-rw-r--r--lib/asio/detail/assert.hpp32
-rw-r--r--lib/asio/detail/atomic_count.hpp45
-rw-r--r--lib/asio/detail/base_from_completion_cond.hpp68
-rw-r--r--lib/asio/detail/bind_handler.hpp816
-rw-r--r--lib/asio/detail/buffer_resize_guard.hpp66
-rw-r--r--lib/asio/detail/buffer_sequence_adapter.hpp544
-rw-r--r--lib/asio/detail/buffered_stream_storage.hpp126
-rw-r--r--lib/asio/detail/call_stack.hpp125
-rw-r--r--lib/asio/detail/chrono.hpp66
-rw-r--r--lib/asio/detail/chrono_time_traits.hpp190
-rw-r--r--lib/asio/detail/completion_handler.hpp83
-rw-r--r--lib/asio/detail/concurrency_hint.hpp94
-rw-r--r--lib/asio/detail/conditionally_enabled_event.hpp112
-rw-r--r--lib/asio/detail/conditionally_enabled_mutex.hpp149
-rw-r--r--lib/asio/detail/config.hpp1437
-rw-r--r--lib/asio/detail/consuming_buffers.hpp414
-rw-r--r--lib/asio/detail/cstddef.hpp31
-rw-r--r--lib/asio/detail/cstdint.hpp60
-rw-r--r--lib/asio/detail/date_time_fwd.hpp34
-rw-r--r--lib/asio/detail/deadline_timer_service.hpp278
-rw-r--r--lib/asio/detail/dependent_type.hpp36
-rw-r--r--lib/asio/detail/descriptor_ops.hpp121
-rw-r--r--lib/asio/detail/descriptor_read_op.hpp128
-rw-r--r--lib/asio/detail/descriptor_write_op.hpp128
-rw-r--r--lib/asio/detail/dev_poll_reactor.hpp218
-rw-r--r--lib/asio/detail/epoll_reactor.hpp266
-rw-r--r--lib/asio/detail/event.hpp48
-rw-r--r--lib/asio/detail/eventfd_select_interrupter.hpp83
-rw-r--r--lib/asio/detail/executor_op.hpp84
-rw-r--r--lib/asio/detail/fd_set_adapter.hpp39
-rw-r--r--lib/asio/detail/fenced_block.hpp80
-rw-r--r--lib/asio/detail/functional.hpp38
-rw-r--r--lib/asio/detail/gcc_arm_fenced_block.hpp91
-rw-r--r--lib/asio/detail/gcc_hppa_fenced_block.hpp68
-rw-r--r--lib/asio/detail/gcc_sync_fenced_block.hpp65
-rw-r--r--lib/asio/detail/gcc_x86_fenced_block.hpp99
-rw-r--r--lib/asio/detail/global.hpp52
-rw-r--r--lib/asio/detail/handler_alloc_helpers.hpp235
-rw-r--r--lib/asio/detail/handler_cont_helpers.hpp45
-rw-r--r--lib/asio/detail/handler_invoke_helpers.hpp57
-rw-r--r--lib/asio/detail/handler_tracking.hpp238
-rw-r--r--lib/asio/detail/handler_type_requirements.hpp556
-rw-r--r--lib/asio/detail/handler_work.hpp95
-rw-r--r--lib/asio/detail/hash_map.hpp331
-rw-r--r--lib/asio/detail/impl/buffer_sequence_adapter.ipp118
-rw-r--r--lib/asio/detail/impl/descriptor_ops.ipp474
-rw-r--r--lib/asio/detail/impl/dev_poll_reactor.hpp91
-rw-r--r--lib/asio/detail/impl/dev_poll_reactor.ipp446
-rw-r--r--lib/asio/detail/impl/epoll_reactor.hpp89
-rw-r--r--lib/asio/detail/impl/epoll_reactor.ipp787
-rw-r--r--lib/asio/detail/impl/eventfd_select_interrupter.ipp165
-rw-r--r--lib/asio/detail/impl/handler_tracking.ipp358
-rw-r--r--lib/asio/detail/impl/kqueue_reactor.hpp93
-rw-r--r--lib/asio/detail/impl/kqueue_reactor.ipp566
-rw-r--r--lib/asio/detail/impl/null_event.ipp74
-rw-r--r--lib/asio/detail/impl/pipe_select_interrupter.ipp124
-rw-r--r--lib/asio/detail/impl/posix_event.ipp59
-rw-r--r--lib/asio/detail/impl/posix_mutex.ipp46
-rw-r--r--lib/asio/detail/impl/posix_thread.ipp84
-rw-r--r--lib/asio/detail/impl/posix_tss_ptr.ipp46
-rw-r--r--lib/asio/detail/impl/reactive_descriptor_service.ipp222
-rw-r--r--lib/asio/detail/impl/reactive_serial_port_service.ipp152
-rw-r--r--lib/asio/detail/impl/reactive_socket_service_base.ipp300
-rw-r--r--lib/asio/detail/impl/resolver_service_base.ipp154
-rw-r--r--lib/asio/detail/impl/scheduler.ipp571
-rw-r--r--lib/asio/detail/impl/select_reactor.hpp100
-rw-r--r--lib/asio/detail/impl/select_reactor.ipp333
-rw-r--r--lib/asio/detail/impl/service_registry.hpp94
-rw-r--r--lib/asio/detail/impl/service_registry.ipp197
-rw-r--r--lib/asio/detail/impl/signal_set_service.ipp669
-rw-r--r--lib/asio/detail/impl/socket_ops.ipp3571
-rw-r--r--lib/asio/detail/impl/socket_select_interrupter.ipp176
-rw-r--r--lib/asio/detail/impl/strand_executor_service.hpp179
-rw-r--r--lib/asio/detail/impl/strand_executor_service.ipp134
-rw-r--r--lib/asio/detail/impl/strand_service.hpp118
-rw-r--r--lib/asio/detail/impl/strand_service.ipp177
-rw-r--r--lib/asio/detail/impl/throw_error.ipp60
-rw-r--r--lib/asio/detail/impl/timer_queue_ptime.ipp91
-rw-r--r--lib/asio/detail/impl/timer_queue_set.ipp101
-rw-r--r--lib/asio/detail/impl/win_event.ipp76
-rw-r--r--lib/asio/detail/impl/win_iocp_handle_service.ipp525
-rw-r--r--lib/asio/detail/impl/win_iocp_io_context.hpp103
-rw-r--r--lib/asio/detail/impl/win_iocp_io_context.ipp554
-rw-r--r--lib/asio/detail/impl/win_iocp_serial_port_service.ipp181
-rw-r--r--lib/asio/detail/impl/win_iocp_socket_service_base.ipp799
-rw-r--r--lib/asio/detail/impl/win_mutex.ipp84
-rw-r--r--lib/asio/detail/impl/win_object_handle_service.ipp449
-rw-r--r--lib/asio/detail/impl/win_static_mutex.ipp136
-rw-r--r--lib/asio/detail/impl/win_thread.ipp150
-rw-r--r--lib/asio/detail/impl/win_tss_ptr.ipp57
-rw-r--r--lib/asio/detail/impl/winrt_ssocket_service_base.ipp629
-rw-r--r--lib/asio/detail/impl/winrt_timer_scheduler.hpp92
-rw-r--r--lib/asio/detail/impl/winrt_timer_scheduler.ipp122
-rw-r--r--lib/asio/detail/impl/winsock_init.ipp82
-rw-r--r--lib/asio/detail/io_control.hpp84
-rw-r--r--lib/asio/detail/is_buffer_sequence.hpp239
-rw-r--r--lib/asio/detail/is_executor.hpp126
-rw-r--r--lib/asio/detail/keyword_tss_ptr.hpp70
-rw-r--r--lib/asio/detail/kqueue_reactor.hpp242
-rw-r--r--lib/asio/detail/limits.hpp26
-rw-r--r--lib/asio/detail/local_free_on_block_exit.hpp59
-rw-r--r--lib/asio/detail/macos_fenced_block.hpp62
-rw-r--r--lib/asio/detail/memory.hpp70
-rw-r--r--lib/asio/detail/mutex.hpp48
-rw-r--r--lib/asio/detail/noncopyable.hpp43
-rw-r--r--lib/asio/detail/null_event.hpp100
-rw-r--r--lib/asio/detail/null_fenced_block.hpp47
-rw-r--r--lib/asio/detail/null_global.hpp59
-rw-r--r--lib/asio/detail/null_mutex.hpp64
-rw-r--r--lib/asio/detail/null_reactor.hpp68
-rw-r--r--lib/asio/detail/null_signal_blocker.hpp69
-rw-r--r--lib/asio/detail/null_socket_service.hpp508
-rw-r--r--lib/asio/detail/null_static_mutex.hpp60
-rw-r--r--lib/asio/detail/null_thread.hpp67
-rw-r--r--lib/asio/detail/null_tss_ptr.hpp68
-rw-r--r--lib/asio/detail/object_pool.hpp171
-rw-r--r--lib/asio/detail/old_win_sdk_compat.hpp214
-rw-r--r--lib/asio/detail/op_queue.hpp162
-rw-r--r--lib/asio/detail/operation.hpp38
-rw-r--r--lib/asio/detail/pipe_select_interrupter.hpp89
-rw-r--r--lib/asio/detail/pop_options.hpp135
-rw-r--r--lib/asio/detail/posix_event.hpp162
-rw-r--r--lib/asio/detail/posix_fd_set_adapter.hpp118
-rw-r--r--lib/asio/detail/posix_global.hpp80
-rw-r--r--lib/asio/detail/posix_mutex.hpp76
-rw-r--r--lib/asio/detail/posix_signal_blocker.hpp85
-rw-r--r--lib/asio/detail/posix_static_mutex.hpp64
-rw-r--r--lib/asio/detail/posix_thread.hpp109
-rw-r--r--lib/asio/detail/posix_tss_ptr.hpp79
-rw-r--r--lib/asio/detail/push_options.hpp175
-rw-r--r--lib/asio/detail/reactive_descriptor_service.hpp388
-rw-r--r--lib/asio/detail/reactive_null_buffers_op.hpp90
-rw-r--r--lib/asio/detail/reactive_serial_port_service.hpp236
-rw-r--r--lib/asio/detail/reactive_socket_accept_op.hpp217
-rw-r--r--lib/asio/detail/reactive_socket_connect_op.hpp113
-rw-r--r--lib/asio/detail/reactive_socket_recv_op.hpp135
-rw-r--r--lib/asio/detail/reactive_socket_recvfrom_op.hpp138
-rw-r--r--lib/asio/detail/reactive_socket_recvmsg_op.hpp132
-rw-r--r--lib/asio/detail/reactive_socket_send_op.hpp134
-rw-r--r--lib/asio/detail/reactive_socket_sendto_op.hpp130
-rw-r--r--lib/asio/detail/reactive_socket_service.hpp526
-rw-r--r--lib/asio/detail/reactive_socket_service_base.hpp511
-rw-r--r--lib/asio/detail/reactive_wait_op.hpp90
-rw-r--r--lib/asio/detail/reactor.hpp32
-rw-r--r--lib/asio/detail/reactor_fwd.hpp40
-rw-r--r--lib/asio/detail/reactor_op.hpp65
-rw-r--r--lib/asio/detail/reactor_op_queue.hpp168
-rw-r--r--lib/asio/detail/recycling_allocator.hpp104
-rw-r--r--lib/asio/detail/regex_fwd.hpp35
-rw-r--r--lib/asio/detail/resolve_endpoint_op.hpp122
-rw-r--r--lib/asio/detail/resolve_op.hpp45
-rw-r--r--lib/asio/detail/resolve_query_op.hpp134
-rw-r--r--lib/asio/detail/resolver_service.hpp145
-rw-r--r--lib/asio/detail/resolver_service_base.hpp140
-rw-r--r--lib/asio/detail/scheduler.hpp213
-rw-r--r--lib/asio/detail/scheduler_operation.hpp78
-rw-r--r--lib/asio/detail/scheduler_thread_info.hpp40
-rw-r--r--lib/asio/detail/scoped_lock.hpp101
-rw-r--r--lib/asio/detail/scoped_ptr.hpp87
-rw-r--r--lib/asio/detail/select_interrupter.hpp46
-rw-r--r--lib/asio/detail/select_reactor.hpp238
-rw-r--r--lib/asio/detail/service_registry.hpp164
-rw-r--r--lib/asio/detail/signal_blocker.hpp44
-rw-r--r--lib/asio/detail/signal_handler.hpp86
-rw-r--r--lib/asio/detail/signal_init.hpp47
-rw-r--r--lib/asio/detail/signal_op.hpp49
-rw-r--r--lib/asio/detail/signal_set_service.hpp217
-rw-r--r--lib/asio/detail/socket_holder.hpp98
-rw-r--r--lib/asio/detail/socket_ops.hpp337
-rw-r--r--lib/asio/detail/socket_option.hpp316
-rw-r--r--lib/asio/detail/socket_select_interrupter.hpp91
-rw-r--r--lib/asio/detail/socket_types.hpp416
-rw-r--r--lib/asio/detail/solaris_fenced_block.hpp62
-rw-r--r--lib/asio/detail/static_mutex.hpp52
-rw-r--r--lib/asio/detail/std_event.hpp176
-rw-r--r--lib/asio/detail/std_fenced_block.hpp62
-rw-r--r--lib/asio/detail/std_global.hpp70
-rw-r--r--lib/asio/detail/std_mutex.hpp73
-rw-r--r--lib/asio/detail/std_static_mutex.hpp81
-rw-r--r--lib/asio/detail/std_thread.hpp71
-rw-r--r--lib/asio/detail/strand_executor_service.hpp142
-rw-r--r--lib/asio/detail/strand_service.hpp142
-rw-r--r--lib/asio/detail/string_view.hpp47
-rw-r--r--lib/asio/detail/thread.hpp60
-rw-r--r--lib/asio/detail/thread_context.hpp42
-rw-r--r--lib/asio/detail/thread_group.hpp89
-rw-r--r--lib/asio/detail/thread_info_base.hpp121
-rw-r--r--lib/asio/detail/throw_error.hpp53
-rw-r--r--lib/asio/detail/throw_exception.hpp51
-rw-r--r--lib/asio/detail/timer_queue.hpp358
-rw-r--r--lib/asio/detail/timer_queue_base.hpp68
-rw-r--r--lib/asio/detail/timer_queue_ptime.hpp99
-rw-r--r--lib/asio/detail/timer_queue_set.hpp66
-rw-r--r--lib/asio/detail/timer_scheduler.hpp35
-rw-r--r--lib/asio/detail/timer_scheduler_fwd.hpp40
-rw-r--r--lib/asio/detail/tss_ptr.hpp69
-rw-r--r--lib/asio/detail/type_traits.hpp86
-rw-r--r--lib/asio/detail/variadic_templates.hpp119
-rw-r--r--lib/asio/detail/wait_handler.hpp85
-rw-r--r--lib/asio/detail/wait_op.hpp45
-rw-r--r--lib/asio/detail/win_event.hpp151
-rw-r--r--lib/asio/detail/win_fd_set_adapter.hpp149
-rw-r--r--lib/asio/detail/win_fenced_block.hpp90
-rw-r--r--lib/asio/detail/win_global.hpp73
-rw-r--r--lib/asio/detail/win_iocp_handle_read_op.hpp111
-rw-r--r--lib/asio/detail/win_iocp_handle_service.hpp323
-rw-r--r--lib/asio/detail/win_iocp_handle_write_op.hpp103
-rw-r--r--lib/asio/detail/win_iocp_io_context.hpp328
-rw-r--r--lib/asio/detail/win_iocp_null_buffers_op.hpp121
-rw-r--r--lib/asio/detail/win_iocp_operation.hpp96
-rw-r--r--lib/asio/detail/win_iocp_overlapped_op.hpp90
-rw-r--r--lib/asio/detail/win_iocp_overlapped_ptr.hpp143
-rw-r--r--lib/asio/detail/win_iocp_serial_port_service.hpp230
-rw-r--r--lib/asio/detail/win_iocp_socket_accept_op.hpp297
-rw-r--r--lib/asio/detail/win_iocp_socket_connect_op.hpp127
-rw-r--r--lib/asio/detail/win_iocp_socket_recv_op.hpp117
-rw-r--r--lib/asio/detail/win_iocp_socket_recvfrom_op.hpp125
-rw-r--r--lib/asio/detail/win_iocp_socket_recvmsg_op.hpp118
-rw-r--r--lib/asio/detail/win_iocp_socket_send_op.hpp111
-rw-r--r--lib/asio/detail/win_iocp_socket_service.hpp599
-rw-r--r--lib/asio/detail/win_iocp_socket_service_base.hpp591
-rw-r--r--lib/asio/detail/win_iocp_thread_info.hpp34
-rw-r--r--lib/asio/detail/win_iocp_wait_op.hpp121
-rw-r--r--lib/asio/detail/win_mutex.hpp78
-rw-r--r--lib/asio/detail/win_object_handle_service.hpp184
-rw-r--r--lib/asio/detail/win_static_mutex.hpp74
-rw-r--r--lib/asio/detail/win_thread.hpp147
-rw-r--r--lib/asio/detail/win_tss_ptr.hpp79
-rw-r--r--lib/asio/detail/winapp_thread.hpp124
-rw-r--r--lib/asio/detail/wince_thread.hpp124
-rw-r--r--lib/asio/detail/winrt_async_manager.hpp294
-rw-r--r--lib/asio/detail/winrt_async_op.hpp65
-rw-r--r--lib/asio/detail/winrt_resolve_op.hpp118
-rw-r--r--lib/asio/detail/winrt_resolver_service.hpp198
-rw-r--r--lib/asio/detail/winrt_socket_connect_op.hpp92
-rw-r--r--lib/asio/detail/winrt_socket_recv_op.hpp112
-rw-r--r--lib/asio/detail/winrt_socket_send_op.hpp103
-rw-r--r--lib/asio/detail/winrt_ssocket_service.hpp241
-rw-r--r--lib/asio/detail/winrt_ssocket_service_base.hpp359
-rw-r--r--lib/asio/detail/winrt_timer_scheduler.hpp137
-rw-r--r--lib/asio/detail/winrt_utils.hpp106
-rw-r--r--lib/asio/detail/winsock_init.hpp128
-rw-r--r--lib/asio/detail/work_dispatcher.hpp72
-rw-r--r--lib/asio/detail/wrapped_handler.hpp291
246 files changed, 43413 insertions, 0 deletions
diff --git a/lib/asio/detail/array.hpp b/lib/asio/detail/array.hpp
new file mode 100644
index 0000000..ba42974
--- /dev/null
+++ b/lib/asio/detail/array.hpp
@@ -0,0 +1,38 @@
+//
+// detail/array.hpp
+// ~~~~~~~~~~~~~~~~
+//
+// Copyright (c) 2003-2018 Christopher M. Kohlhoff (chris at kohlhoff dot com)
+//
+// 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 ASIO_DETAIL_ARRAY_HPP
+#define ASIO_DETAIL_ARRAY_HPP
+
+#if defined(_MSC_VER) && (_MSC_VER >= 1200)
+# pragma once
+#endif // defined(_MSC_VER) && (_MSC_VER >= 1200)
+
+#include "asio/detail/config.hpp"
+
+#if defined(ASIO_HAS_STD_ARRAY)
+# include <array>
+#else // defined(ASIO_HAS_STD_ARRAY)
+# include <boost/array.hpp>
+#endif // defined(ASIO_HAS_STD_ARRAY)
+
+namespace asio {
+namespace detail {
+
+#if defined(ASIO_HAS_STD_ARRAY)
+using std::array;
+#else // defined(ASIO_HAS_STD_ARRAY)
+using boost::array;
+#endif // defined(ASIO_HAS_STD_ARRAY)
+
+} // namespace detail
+} // namespace asio
+
+#endif // ASIO_DETAIL_ARRAY_HPP
diff --git a/lib/asio/detail/array_fwd.hpp b/lib/asio/detail/array_fwd.hpp
new file mode 100644
index 0000000..4161db0
--- /dev/null
+++ b/lib/asio/detail/array_fwd.hpp
@@ -0,0 +1,34 @@
+//
+// detail/array_fwd.hpp
+// ~~~~~~~~~~~~~~~~~~~~
+//
+// Copyright (c) 2003-2018 Christopher M. Kohlhoff (chris at kohlhoff dot com)
+//
+// 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 ASIO_DETAIL_ARRAY_FWD_HPP
+#define ASIO_DETAIL_ARRAY_FWD_HPP
+
+#if defined(_MSC_VER) && (_MSC_VER >= 1200)
+# pragma once
+#endif // defined(_MSC_VER) && (_MSC_VER >= 1200)
+
+#include "asio/detail/config.hpp"
+
+namespace boost {
+
+template<class T, std::size_t N>
+class array;
+
+} // namespace boost
+
+// Standard library components can't be forward declared, so we'll have to
+// include the array header. Fortunately, it's fairly lightweight and doesn't
+// add significantly to the compile time.
+#if defined(ASIO_HAS_STD_ARRAY)
+# include <array>
+#endif // defined(ASIO_HAS_STD_ARRAY)
+
+#endif // ASIO_DETAIL_ARRAY_FWD_HPP
diff --git a/lib/asio/detail/assert.hpp b/lib/asio/detail/assert.hpp
new file mode 100644
index 0000000..a952a44
--- /dev/null
+++ b/lib/asio/detail/assert.hpp
@@ -0,0 +1,32 @@
+//
+// detail/assert.hpp
+// ~~~~~~~~~~~~~~~~~
+//
+// Copyright (c) 2003-2018 Christopher M. Kohlhoff (chris at kohlhoff dot com)
+//
+// 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 ASIO_DETAIL_ASSERT_HPP
+#define ASIO_DETAIL_ASSERT_HPP
+
+#if defined(_MSC_VER) && (_MSC_VER >= 1200)
+# pragma once
+#endif // defined(_MSC_VER) && (_MSC_VER >= 1200)
+
+#include "asio/detail/config.hpp"
+
+#if defined(ASIO_HAS_BOOST_ASSERT)
+# include <boost/assert.hpp>
+#else // defined(ASIO_HAS_BOOST_ASSERT)
+# include <cassert>
+#endif // defined(ASIO_HAS_BOOST_ASSERT)
+
+#if defined(ASIO_HAS_BOOST_ASSERT)
+# define ASIO_ASSERT(expr) BOOST_ASSERT(expr)
+#else // defined(ASIO_HAS_BOOST_ASSERT)
+# define ASIO_ASSERT(expr) assert(expr)
+#endif // defined(ASIO_HAS_BOOST_ASSERT)
+
+#endif // ASIO_DETAIL_ASSERT_HPP
diff --git a/lib/asio/detail/atomic_count.hpp b/lib/asio/detail/atomic_count.hpp
new file mode 100644
index 0000000..2bf75a5
--- /dev/null
+++ b/lib/asio/detail/atomic_count.hpp
@@ -0,0 +1,45 @@
+//
+// detail/atomic_count.hpp
+// ~~~~~~~~~~~~~~~~~~~~~~~
+//
+// Copyright (c) 2003-2018 Christopher M. Kohlhoff (chris at kohlhoff dot com)
+//
+// 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 ASIO_DETAIL_ATOMIC_COUNT_HPP
+#define ASIO_DETAIL_ATOMIC_COUNT_HPP
+
+#if defined(_MSC_VER) && (_MSC_VER >= 1200)
+# pragma once
+#endif // defined(_MSC_VER) && (_MSC_VER >= 1200)
+
+#include "asio/detail/config.hpp"
+
+#if !defined(ASIO_HAS_THREADS)
+// Nothing to include.
+#elif defined(ASIO_HAS_STD_ATOMIC)
+# include <atomic>
+#else // defined(ASIO_HAS_STD_ATOMIC)
+# include <boost/detail/atomic_count.hpp>
+#endif // defined(ASIO_HAS_STD_ATOMIC)
+
+namespace asio {
+namespace detail {
+
+#if !defined(ASIO_HAS_THREADS)
+typedef long atomic_count;
+inline void increment(atomic_count& a, long b) { a += b; }
+#elif defined(ASIO_HAS_STD_ATOMIC)
+typedef std::atomic<long> atomic_count;
+inline void increment(atomic_count& a, long b) { a += b; }
+#else // defined(ASIO_HAS_STD_ATOMIC)
+typedef boost::detail::atomic_count atomic_count;
+inline void increment(atomic_count& a, long b) { while (b > 0) ++a, --b; }
+#endif // defined(ASIO_HAS_STD_ATOMIC)
+
+} // namespace detail
+} // namespace asio
+
+#endif // ASIO_DETAIL_ATOMIC_COUNT_HPP
diff --git a/lib/asio/detail/base_from_completion_cond.hpp b/lib/asio/detail/base_from_completion_cond.hpp
new file mode 100644
index 0000000..73b4a95
--- /dev/null
+++ b/lib/asio/detail/base_from_completion_cond.hpp
@@ -0,0 +1,68 @@
+//
+// detail/base_from_completion_cond.hpp
+// ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+//
+// Copyright (c) 2003-2018 Christopher M. Kohlhoff (chris at kohlhoff dot com)
+//
+// 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 ASIO_DETAIL_BASE_FROM_COMPLETION_COND_HPP
+#define ASIO_DETAIL_BASE_FROM_COMPLETION_COND_HPP
+
+#if defined(_MSC_VER) && (_MSC_VER >= 1200)
+# pragma once
+#endif // defined(_MSC_VER) && (_MSC_VER >= 1200)
+
+#include "asio/detail/config.hpp"
+#include "asio/completion_condition.hpp"
+
+#include "asio/detail/push_options.hpp"
+
+namespace asio {
+namespace detail {
+
+template <typename CompletionCondition>
+class base_from_completion_cond
+{
+protected:
+ explicit base_from_completion_cond(CompletionCondition completion_condition)
+ : completion_condition_(completion_condition)
+ {
+ }
+
+ std::size_t check_for_completion(
+ const asio::error_code& ec,
+ std::size_t total_transferred)
+ {
+ return detail::adapt_completion_condition_result(
+ completion_condition_(ec, total_transferred));
+ }
+
+private:
+ CompletionCondition completion_condition_;
+};
+
+template <>
+class base_from_completion_cond<transfer_all_t>
+{
+protected:
+ explicit base_from_completion_cond(transfer_all_t)
+ {
+ }
+
+ static std::size_t check_for_completion(
+ const asio::error_code& ec,
+ std::size_t total_transferred)
+ {
+ return transfer_all_t()(ec, total_transferred);
+ }
+};
+
+} // namespace detail
+} // namespace asio
+
+#include "asio/detail/pop_options.hpp"
+
+#endif // ASIO_DETAIL_BASE_FROM_COMPLETION_COND_HPP
diff --git a/lib/asio/detail/bind_handler.hpp b/lib/asio/detail/bind_handler.hpp
new file mode 100644
index 0000000..0f4f066
--- /dev/null
+++ b/lib/asio/detail/bind_handler.hpp
@@ -0,0 +1,816 @@
+//
+// detail/bind_handler.hpp
+// ~~~~~~~~~~~~~~~~~~~~~~~
+//
+// Copyright (c) 2003-2018 Christopher M. Kohlhoff (chris at kohlhoff dot com)
+//
+// 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 ASIO_DETAIL_BIND_HANDLER_HPP
+#define ASIO_DETAIL_BIND_HANDLER_HPP
+
+#if defined(_MSC_VER) && (_MSC_VER >= 1200)
+# pragma once
+#endif // defined(_MSC_VER) && (_MSC_VER >= 1200)
+
+#include "asio/detail/config.hpp"
+#include "asio/associated_allocator.hpp"
+#include "asio/associated_executor.hpp"
+#include "asio/detail/handler_alloc_helpers.hpp"
+#include "asio/detail/handler_cont_helpers.hpp"
+#include "asio/detail/handler_invoke_helpers.hpp"
+#include "asio/detail/type_traits.hpp"
+
+#include "asio/detail/push_options.hpp"
+
+namespace asio {
+namespace detail {
+
+template <typename Handler, typename Arg1>
+class binder1
+{
+public:
+ template <typename T>
+ binder1(int, ASIO_MOVE_ARG(T) handler, const Arg1& arg1)
+ : handler_(ASIO_MOVE_CAST(T)(handler)),
+ arg1_(arg1)
+ {
+ }
+
+ binder1(Handler& handler, const Arg1& arg1)
+ : handler_(ASIO_MOVE_CAST(Handler)(handler)),
+ arg1_(arg1)
+ {
+ }
+
+#if defined(ASIO_HAS_MOVE)
+ binder1(const binder1& other)
+ : handler_(other.handler_),
+ arg1_(other.arg1_)
+ {
+ }
+
+ binder1(binder1&& other)
+ : handler_(ASIO_MOVE_CAST(Handler)(other.handler_)),
+ arg1_(ASIO_MOVE_CAST(Arg1)(other.arg1_))
+ {
+ }
+#endif // defined(ASIO_HAS_MOVE)
+
+ void operator()()
+ {
+ handler_(static_cast<const Arg1&>(arg1_));
+ }
+
+ void operator()() const
+ {
+ handler_(arg1_);
+ }
+
+//private:
+ Handler handler_;
+ Arg1 arg1_;
+};
+
+template <typename Handler, typename Arg1>
+inline void* asio_handler_allocate(std::size_t size,
+ binder1<Handler, Arg1>* this_handler)
+{
+ return asio_handler_alloc_helpers::allocate(
+ size, this_handler->handler_);
+}
+
+template <typename Handler, typename Arg1>
+inline void asio_handler_deallocate(void* pointer, std::size_t size,
+ binder1<Handler, Arg1>* this_handler)
+{
+ asio_handler_alloc_helpers::deallocate(
+ pointer, size, this_handler->handler_);
+}
+
+template <typename Handler, typename Arg1>
+inline bool asio_handler_is_continuation(
+ binder1<Handler, Arg1>* this_handler)
+{
+ return asio_handler_cont_helpers::is_continuation(
+ this_handler->handler_);
+}
+
+template <typename Function, typename Handler, typename Arg1>
+inline void asio_handler_invoke(Function& function,
+ binder1<Handler, Arg1>* this_handler)
+{
+ asio_handler_invoke_helpers::invoke(
+ function, this_handler->handler_);
+}
+
+template <typename Function, typename Handler, typename Arg1>
+inline void asio_handler_invoke(const Function& function,
+ binder1<Handler, Arg1>* this_handler)
+{
+ asio_handler_invoke_helpers::invoke(
+ function, this_handler->handler_);
+}
+
+template <typename Handler, typename Arg1>
+inline binder1<typename decay<Handler>::type, Arg1> bind_handler(
+ ASIO_MOVE_ARG(Handler) handler, const Arg1& arg1)
+{
+ return binder1<typename decay<Handler>::type, Arg1>(0,
+ ASIO_MOVE_CAST(Handler)(handler), arg1);
+}
+
+template <typename Handler, typename Arg1, typename Arg2>
+class binder2
+{
+public:
+ template <typename T>
+ binder2(int, ASIO_MOVE_ARG(T) handler,
+ const Arg1& arg1, const Arg2& arg2)
+ : handler_(ASIO_MOVE_CAST(T)(handler)),
+ arg1_(arg1),
+ arg2_(arg2)
+ {
+ }
+
+ binder2(Handler& handler, const Arg1& arg1, const Arg2& arg2)
+ : handler_(ASIO_MOVE_CAST(Handler)(handler)),
+ arg1_(arg1),
+ arg2_(arg2)
+ {
+ }
+
+#if defined(ASIO_HAS_MOVE)
+ binder2(const binder2& other)
+ : handler_(other.handler_),
+ arg1_(other.arg1_),
+ arg2_(other.arg2_)
+ {
+ }
+
+ binder2(binder2&& other)
+ : handler_(ASIO_MOVE_CAST(Handler)(other.handler_)),
+ arg1_(ASIO_MOVE_CAST(Arg1)(other.arg1_)),
+ arg2_(ASIO_MOVE_CAST(Arg2)(other.arg2_))
+ {
+ }
+#endif // defined(ASIO_HAS_MOVE)
+
+ void operator()()
+ {
+ handler_(static_cast<const Arg1&>(arg1_),
+ static_cast<const Arg2&>(arg2_));
+ }
+
+ void operator()() const
+ {
+ handler_(arg1_, arg2_);
+ }
+
+//private:
+ Handler handler_;
+ Arg1 arg1_;
+ Arg2 arg2_;
+};
+
+template <typename Handler, typename Arg1, typename Arg2>
+inline void* asio_handler_allocate(std::size_t size,
+ binder2<Handler, Arg1, Arg2>* this_handler)
+{
+ return asio_handler_alloc_helpers::allocate(
+ size, this_handler->handler_);
+}
+
+template <typename Handler, typename Arg1, typename Arg2>
+inline void asio_handler_deallocate(void* pointer, std::size_t size,
+ binder2<Handler, Arg1, Arg2>* this_handler)
+{
+ asio_handler_alloc_helpers::deallocate(
+ pointer, size, this_handler->handler_);
+}
+
+template <typename Handler, typename Arg1, typename Arg2>
+inline bool asio_handler_is_continuation(
+ binder2<Handler, Arg1, Arg2>* this_handler)
+{
+ return asio_handler_cont_helpers::is_continuation(
+ this_handler->handler_);
+}
+
+template <typename Function, typename Handler, typename Arg1, typename Arg2>
+inline void asio_handler_invoke(Function& function,
+ binder2<Handler, Arg1, Arg2>* this_handler)
+{
+ asio_handler_invoke_helpers::invoke(
+ function, this_handler->handler_);
+}
+
+template <typename Function, typename Handler, typename Arg1, typename Arg2>
+inline void asio_handler_invoke(const Function& function,
+ binder2<Handler, Arg1, Arg2>* this_handler)
+{
+ asio_handler_invoke_helpers::invoke(
+ function, this_handler->handler_);
+}
+
+template <typename Handler, typename Arg1, typename Arg2>
+inline binder2<typename decay<Handler>::type, Arg1, Arg2> bind_handler(
+ ASIO_MOVE_ARG(Handler) handler, const Arg1& arg1, const Arg2& arg2)
+{
+ return binder2<typename decay<Handler>::type, Arg1, Arg2>(0,
+ ASIO_MOVE_CAST(Handler)(handler), arg1, arg2);
+}
+
+template <typename Handler, typename Arg1, typename Arg2, typename Arg3>
+class binder3
+{
+public:
+ template <typename T>
+ binder3(int, ASIO_MOVE_ARG(T) handler, const Arg1& arg1,
+ const Arg2& arg2, const Arg3& arg3)
+ : handler_(ASIO_MOVE_CAST(T)(handler)),
+ arg1_(arg1),
+ arg2_(arg2),
+ arg3_(arg3)
+ {
+ }
+
+ binder3(Handler& handler, const Arg1& arg1,
+ const Arg2& arg2, const Arg3& arg3)
+ : handler_(ASIO_MOVE_CAST(Handler)(handler)),
+ arg1_(arg1),
+ arg2_(arg2),
+ arg3_(arg3)
+ {
+ }
+
+#if defined(ASIO_HAS_MOVE)
+ binder3(const binder3& other)
+ : handler_(other.handler_),
+ arg1_(other.arg1_),
+ arg2_(other.arg2_),
+ arg3_(other.arg3_)
+ {
+ }
+
+ binder3(binder3&& other)
+ : handler_(ASIO_MOVE_CAST(Handler)(other.handler_)),
+ arg1_(ASIO_MOVE_CAST(Arg1)(other.arg1_)),
+ arg2_(ASIO_MOVE_CAST(Arg2)(other.arg2_)),
+ arg3_(ASIO_MOVE_CAST(Arg3)(other.arg3_))
+ {
+ }
+#endif // defined(ASIO_HAS_MOVE)
+
+ void operator()()
+ {
+ handler_(static_cast<const Arg1&>(arg1_),
+ static_cast<const Arg2&>(arg2_), static_cast<const Arg3&>(arg3_));
+ }
+
+ void operator()() const
+ {
+ handler_(arg1_, arg2_, arg3_);
+ }
+
+//private:
+ Handler handler_;
+ Arg1 arg1_;
+ Arg2 arg2_;
+ Arg3 arg3_;
+};
+
+template <typename Handler, typename Arg1, typename Arg2, typename Arg3>
+inline void* asio_handler_allocate(std::size_t size,
+ binder3<Handler, Arg1, Arg2, Arg3>* this_handler)
+{
+ return asio_handler_alloc_helpers::allocate(
+ size, this_handler->handler_);
+}
+
+template <typename Handler, typename Arg1, typename Arg2, typename Arg3>
+inline void asio_handler_deallocate(void* pointer, std::size_t size,
+ binder3<Handler, Arg1, Arg2, Arg3>* this_handler)
+{
+ asio_handler_alloc_helpers::deallocate(
+ pointer, size, this_handler->handler_);
+}
+
+template <typename Handler, typename Arg1, typename Arg2, typename Arg3>
+inline bool asio_handler_is_continuation(
+ binder3<Handler, Arg1, Arg2, Arg3>* this_handler)
+{
+ return asio_handler_cont_helpers::is_continuation(
+ this_handler->handler_);
+}
+
+template <typename Function, typename Handler,
+ typename Arg1, typename Arg2, typename Arg3>
+inline void asio_handler_invoke(Function& function,
+ binder3<Handler, Arg1, Arg2, Arg3>* this_handler)
+{
+ asio_handler_invoke_helpers::invoke(
+ function, this_handler->handler_);
+}
+
+template <typename Function, typename Handler,
+ typename Arg1, typename Arg2, typename Arg3>
+inline void asio_handler_invoke(const Function& function,
+ binder3<Handler, Arg1, Arg2, Arg3>* this_handler)
+{
+ asio_handler_invoke_helpers::invoke(
+ function, this_handler->handler_);
+}
+
+template <typename Handler, typename Arg1, typename Arg2, typename Arg3>
+inline binder3<typename decay<Handler>::type, Arg1, Arg2, Arg3> bind_handler(
+ ASIO_MOVE_ARG(Handler) handler, const Arg1& arg1, const Arg2& arg2,
+ const Arg3& arg3)
+{
+ return binder3<typename decay<Handler>::type, Arg1, Arg2, Arg3>(0,
+ ASIO_MOVE_CAST(Handler)(handler), arg1, arg2, arg3);
+}
+
+template <typename Handler, typename Arg1,
+ typename Arg2, typename Arg3, typename Arg4>
+class binder4
+{
+public:
+ template <typename T>
+ binder4(int, ASIO_MOVE_ARG(T) handler, const Arg1& arg1,
+ const Arg2& arg2, const Arg3& arg3, const Arg4& arg4)
+ : handler_(ASIO_MOVE_CAST(T)(handler)),
+ arg1_(arg1),
+ arg2_(arg2),
+ arg3_(arg3),
+ arg4_(arg4)
+ {
+ }
+
+ binder4(Handler& handler, const Arg1& arg1,
+ const Arg2& arg2, const Arg3& arg3, const Arg4& arg4)
+ : handler_(ASIO_MOVE_CAST(Handler)(handler)),
+ arg1_(arg1),
+ arg2_(arg2),
+ arg3_(arg3),
+ arg4_(arg4)
+ {
+ }
+
+#if defined(ASIO_HAS_MOVE)
+ binder4(const binder4& other)
+ : handler_(other.handler_),
+ arg1_(other.arg1_),
+ arg2_(other.arg2_),
+ arg3_(other.arg3_),
+ arg4_(other.arg4_)
+ {
+ }
+
+ binder4(binder4&& other)
+ : handler_(ASIO_MOVE_CAST(Handler)(other.handler_)),
+ arg1_(ASIO_MOVE_CAST(Arg1)(other.arg1_)),
+ arg2_(ASIO_MOVE_CAST(Arg2)(other.arg2_)),
+ arg3_(ASIO_MOVE_CAST(Arg3)(other.arg3_)),
+ arg4_(ASIO_MOVE_CAST(Arg4)(other.arg4_))
+ {
+ }
+#endif // defined(ASIO_HAS_MOVE)
+
+ void operator()()
+ {
+ handler_(static_cast<const Arg1&>(arg1_),
+ static_cast<const Arg2&>(arg2_), static_cast<const Arg3&>(arg3_),
+ static_cast<const Arg4&>(arg4_));
+ }
+
+ void operator()() const
+ {
+ handler_(arg1_, arg2_, arg3_, arg4_);
+ }
+
+//private:
+ Handler handler_;
+ Arg1 arg1_;
+ Arg2 arg2_;
+ Arg3 arg3_;
+ Arg4 arg4_;
+};
+
+template <typename Handler, typename Arg1,
+ typename Arg2, typename Arg3, typename Arg4>
+inline void* asio_handler_allocate(std::size_t size,
+ binder4<Handler, Arg1, Arg2, Arg3, Arg4>* this_handler)
+{
+ return asio_handler_alloc_helpers::allocate(
+ size, this_handler->handler_);
+}
+
+template <typename Handler, typename Arg1,
+ typename Arg2, typename Arg3, typename Arg4>
+inline void asio_handler_deallocate(void* pointer, std::size_t size,
+ binder4<Handler, Arg1, Arg2, Arg3, Arg4>* this_handler)
+{
+ asio_handler_alloc_helpers::deallocate(
+ pointer, size, this_handler->handler_);
+}
+
+template <typename Handler, typename Arg1,
+ typename Arg2, typename Arg3, typename Arg4>
+inline bool asio_handler_is_continuation(
+ binder4<Handler, Arg1, Arg2, Arg3, Arg4>* this_handler)
+{
+ return asio_handler_cont_helpers::is_continuation(
+ this_handler->handler_);
+}
+
+template <typename Function, typename Handler, typename Arg1,
+ typename Arg2, typename Arg3, typename Arg4>
+inline void asio_handler_invoke(Function& function,
+ binder4<Handler, Arg1, Arg2, Arg3, Arg4>* this_handler)
+{
+ asio_handler_invoke_helpers::invoke(
+ function, this_handler->handler_);
+}
+
+template <typename Function, typename Handler, typename Arg1,
+ typename Arg2, typename Arg3, typename Arg4>
+inline void asio_handler_invoke(const Function& function,
+ binder4<Handler, Arg1, Arg2, Arg3, Arg4>* this_handler)
+{
+ asio_handler_invoke_helpers::invoke(
+ function, this_handler->handler_);
+}
+
+template <typename Handler, typename Arg1,
+ typename Arg2, typename Arg3, typename Arg4>
+inline binder4<typename decay<Handler>::type, Arg1, Arg2, Arg3, Arg4>
+bind_handler(ASIO_MOVE_ARG(Handler) handler, const Arg1& arg1,
+ const Arg2& arg2, const Arg3& arg3, const Arg4& arg4)
+{
+ return binder4<typename decay<Handler>::type, Arg1, Arg2, Arg3, Arg4>(0,
+ ASIO_MOVE_CAST(Handler)(handler), arg1, arg2, arg3, arg4);
+}
+
+template <typename Handler, typename Arg1, typename Arg2,
+ typename Arg3, typename Arg4, typename Arg5>
+class binder5
+{
+public:
+ template <typename T>
+ binder5(int, ASIO_MOVE_ARG(T) handler, const Arg1& arg1,
+ const Arg2& arg2, const Arg3& arg3, const Arg4& arg4, const Arg5& arg5)
+ : handler_(ASIO_MOVE_CAST(T)(handler)),
+ arg1_(arg1),
+ arg2_(arg2),
+ arg3_(arg3),
+ arg4_(arg4),
+ arg5_(arg5)
+ {
+ }
+
+ binder5(Handler& handler, const Arg1& arg1, const Arg2& arg2,
+ const Arg3& arg3, const Arg4& arg4, const Arg5& arg5)
+ : handler_(ASIO_MOVE_CAST(Handler)(handler)),
+ arg1_(arg1),
+ arg2_(arg2),
+ arg3_(arg3),
+ arg4_(arg4),
+ arg5_(arg5)
+ {
+ }
+
+#if defined(ASIO_HAS_MOVE)
+ binder5(const binder5& other)
+ : handler_(other.handler_),
+ arg1_(other.arg1_),
+ arg2_(other.arg2_),
+ arg3_(other.arg3_),
+ arg4_(other.arg4_),
+ arg5_(other.arg5_)
+ {
+ }
+
+ binder5(binder5&& other)
+ : handler_(ASIO_MOVE_CAST(Handler)(other.handler_)),
+ arg1_(ASIO_MOVE_CAST(Arg1)(other.arg1_)),
+ arg2_(ASIO_MOVE_CAST(Arg2)(other.arg2_)),
+ arg3_(ASIO_MOVE_CAST(Arg3)(other.arg3_)),
+ arg4_(ASIO_MOVE_CAST(Arg4)(other.arg4_)),
+ arg5_(ASIO_MOVE_CAST(Arg5)(other.arg5_))
+ {
+ }
+#endif // defined(ASIO_HAS_MOVE)
+
+ void operator()()
+ {
+ handler_(static_cast<const Arg1&>(arg1_),
+ static_cast<const Arg2&>(arg2_), static_cast<const Arg3&>(arg3_),
+ static_cast<const Arg4&>(arg4_), static_cast<const Arg5&>(arg5_));
+ }
+
+ void operator()() const
+ {
+ handler_(arg1_, arg2_, arg3_, arg4_, arg5_);
+ }
+
+//private:
+ Handler handler_;
+ Arg1 arg1_;
+ Arg2 arg2_;
+ Arg3 arg3_;
+ Arg4 arg4_;
+ Arg5 arg5_;
+};
+
+template <typename Handler, typename Arg1, typename Arg2,
+ typename Arg3, typename Arg4, typename Arg5>
+inline void* asio_handler_allocate(std::size_t size,
+ binder5<Handler, Arg1, Arg2, Arg3, Arg4, Arg5>* this_handler)
+{
+ return asio_handler_alloc_helpers::allocate(
+ size, this_handler->handler_);
+}
+
+template <typename Handler, typename Arg1, typename Arg2,
+ typename Arg3, typename Arg4, typename Arg5>
+inline void asio_handler_deallocate(void* pointer, std::size_t size,
+ binder5<Handler, Arg1, Arg2, Arg3, Arg4, Arg5>* this_handler)
+{
+ asio_handler_alloc_helpers::deallocate(
+ pointer, size, this_handler->handler_);
+}
+
+template <typename Handler, typename Arg1, typename Arg2,
+ typename Arg3, typename Arg4, typename Arg5>
+inline bool asio_handler_is_continuation(
+ binder5<Handler, Arg1, Arg2, Arg3, Arg4, Arg5>* this_handler)
+{
+ return asio_handler_cont_helpers::is_continuation(
+ this_handler->handler_);
+}
+
+template <typename Function, typename Handler, typename Arg1,
+ typename Arg2, typename Arg3, typename Arg4, typename Arg5>
+inline void asio_handler_invoke(Function& function,
+ binder5<Handler, Arg1, Arg2, Arg3, Arg4, Arg5>* this_handler)
+{
+ asio_handler_invoke_helpers::invoke(
+ function, this_handler->handler_);
+}
+
+template <typename Function, typename Handler, typename Arg1,
+ typename Arg2, typename Arg3, typename Arg4, typename Arg5>
+inline void asio_handler_invoke(const Function& function,
+ binder5<Handler, Arg1, Arg2, Arg3, Arg4, Arg5>* this_handler)
+{
+ asio_handler_invoke_helpers::invoke(
+ function, this_handler->handler_);
+}
+
+template <typename Handler, typename Arg1, typename Arg2,
+ typename Arg3, typename Arg4, typename Arg5>
+inline binder5<typename decay<Handler>::type, Arg1, Arg2, Arg3, Arg4, Arg5>
+bind_handler(ASIO_MOVE_ARG(Handler) handler, const Arg1& arg1,
+ const Arg2& arg2, const Arg3& arg3, const Arg4& arg4, const Arg5& arg5)
+{
+ return binder5<typename decay<Handler>::type, Arg1, Arg2, Arg3, Arg4, Arg5>(0,
+ ASIO_MOVE_CAST(Handler)(handler), arg1, arg2, arg3, arg4, arg5);
+}
+
+#if defined(ASIO_HAS_MOVE)
+
+template <typename Handler, typename Arg1>
+class move_binder1
+{
+public:
+ move_binder1(int, ASIO_MOVE_ARG(Handler) handler,
+ ASIO_MOVE_ARG(Arg1) arg1)
+ : handler_(ASIO_MOVE_CAST(Handler)(handler)),
+ arg1_(ASIO_MOVE_CAST(Arg1)(arg1))
+ {
+ }
+
+ move_binder1(move_binder1&& other)
+ : handler_(ASIO_MOVE_CAST(Handler)(other.handler_)),
+ arg1_(ASIO_MOVE_CAST(Arg1)(other.arg1_))
+ {
+ }
+
+ void operator()()
+ {
+ handler_(ASIO_MOVE_CAST(Arg1)(arg1_));
+ }
+
+//private:
+ Handler handler_;
+ Arg1 arg1_;
+};
+
+template <typename Handler, typename Arg1>
+inline void* asio_handler_allocate(std::size_t size,
+ move_binder1<Handler, Arg1>* this_handler)
+{
+ return asio_handler_alloc_helpers::allocate(
+ size, this_handler->handler_);
+}
+
+template <typename Handler, typename Arg1>
+inline void asio_handler_deallocate(void* pointer, std::size_t size,
+ move_binder1<Handler, Arg1>* this_handler)
+{
+ asio_handler_alloc_helpers::deallocate(
+ pointer, size, this_handler->handler_);
+}
+
+template <typename Handler, typename Arg1>
+inline bool asio_handler_is_continuation(
+ move_binder1<Handler, Arg1>* this_handler)
+{
+ return asio_handler_cont_helpers::is_continuation(
+ this_handler->handler_);
+}
+
+template <typename Function, typename Handler, typename Arg1>
+inline void asio_handler_invoke(ASIO_MOVE_ARG(Function) function,
+ move_binder1<Handler, Arg1>* this_handler)
+{
+ asio_handler_invoke_helpers::invoke(
+ ASIO_MOVE_CAST(Function)(function), this_handler->handler_);
+}
+
+template <typename Handler, typename Arg1, typename Arg2>
+class move_binder2
+{
+public:
+ move_binder2(int, ASIO_MOVE_ARG(Handler) handler,
+ const Arg1& arg1, ASIO_MOVE_ARG(Arg2) arg2)
+ : handler_(ASIO_MOVE_CAST(Handler)(handler)),
+ arg1_(arg1),
+ arg2_(ASIO_MOVE_CAST(Arg2)(arg2))
+ {
+ }
+
+ move_binder2(move_binder2&& other)
+ : handler_(ASIO_MOVE_CAST(Handler)(other.handler_)),
+ arg1_(ASIO_MOVE_CAST(Arg1)(other.arg1_)),
+ arg2_(ASIO_MOVE_CAST(Arg2)(other.arg2_))
+ {
+ }
+
+ void operator()()
+ {
+ handler_(static_cast<const Arg1&>(arg1_),
+ ASIO_MOVE_CAST(Arg2)(arg2_));
+ }
+
+//private:
+ Handler handler_;
+ Arg1 arg1_;
+ Arg2 arg2_;
+};
+
+template <typename Handler, typename Arg1, typename Arg2>
+inline void* asio_handler_allocate(std::size_t size,
+ move_binder2<Handler, Arg1, Arg2>* this_handler)
+{
+ return asio_handler_alloc_helpers::allocate(
+ size, this_handler->handler_);
+}
+
+template <typename Handler, typename Arg1, typename Arg2>
+inline void asio_handler_deallocate(void* pointer, std::size_t size,
+ move_binder2<Handler, Arg1, Arg2>* this_handler)
+{
+ asio_handler_alloc_helpers::deallocate(
+ pointer, size, this_handler->handler_);
+}
+
+template <typename Handler, typename Arg1, typename Arg2>
+inline bool asio_handler_is_continuation(
+ move_binder2<Handler, Arg1, Arg2>* this_handler)
+{
+ return asio_handler_cont_helpers::is_continuation(
+ this_handler->handler_);
+}
+
+template <typename Function, typename Handler, typename Arg1, typename Arg2>
+inline void asio_handler_invoke(ASIO_MOVE_ARG(Function) function,
+ move_binder2<Handler, Arg1, Arg2>* this_handler)
+{
+ asio_handler_invoke_helpers::invoke(
+ ASIO_MOVE_CAST(Function)(function), this_handler->handler_);
+}
+
+#endif // defined(ASIO_HAS_MOVE)
+
+} // namespace detail
+
+template <typename Handler, typename Arg1, typename Allocator>
+struct associated_allocator<detail::binder1<Handler, Arg1>, Allocator>
+{
+ typedef typename associated_allocator<Handler, Allocator>::type type;
+
+ static type get(const detail::binder1<Handler, Arg1>& h,
+ const Allocator& a = Allocator()) ASIO_NOEXCEPT
+ {
+ return associated_allocator<Handler, Allocator>::get(h.handler_, a);
+ }
+};
+
+template <typename Handler, typename Arg1, typename Arg2, typename Allocator>
+struct associated_allocator<detail::binder2<Handler, Arg1, Arg2>, Allocator>
+{
+ typedef typename associated_allocator<Handler, Allocator>::type type;
+
+ static type get(const detail::binder2<Handler, Arg1, Arg2>& h,
+ const Allocator& a = Allocator()) ASIO_NOEXCEPT
+ {
+ return associated_allocator<Handler, Allocator>::get(h.handler_, a);
+ }
+};
+
+template <typename Handler, typename Arg1, typename Executor>
+struct associated_executor<detail::binder1<Handler, Arg1>, Executor>
+{
+ typedef typename associated_executor<Handler, Executor>::type type;
+
+ static type get(const detail::binder1<Handler, Arg1>& h,
+ const Executor& ex = Executor()) ASIO_NOEXCEPT
+ {
+ return associated_executor<Handler, Executor>::get(h.handler_, ex);
+ }
+};
+
+template <typename Handler, typename Arg1, typename Arg2, typename Executor>
+struct associated_executor<detail::binder2<Handler, Arg1, Arg2>, Executor>
+{
+ typedef typename associated_executor<Handler, Executor>::type type;
+
+ static type get(const detail::binder2<Handler, Arg1, Arg2>& h,
+ const Executor& ex = Executor()) ASIO_NOEXCEPT
+ {
+ return associated_executor<Handler, Executor>::get(h.handler_, ex);
+ }
+};
+
+#if defined(ASIO_HAS_MOVE)
+
+template <typename Handler, typename Arg1, typename Allocator>
+struct associated_allocator<detail::move_binder1<Handler, Arg1>, Allocator>
+{
+ typedef typename associated_allocator<Handler, Allocator>::type type;
+
+ static type get(const detail::move_binder1<Handler, Arg1>& h,
+ const Allocator& a = Allocator()) ASIO_NOEXCEPT
+ {
+ return associated_allocator<Handler, Allocator>::get(h.handler_, a);
+ }
+};
+
+template <typename Handler, typename Arg1, typename Arg2, typename Allocator>
+struct associated_allocator<
+ detail::move_binder2<Handler, Arg1, Arg2>, Allocator>
+{
+ typedef typename associated_allocator<Handler, Allocator>::type type;
+
+ static type get(const detail::move_binder2<Handler, Arg1, Arg2>& h,
+ const Allocator& a = Allocator()) ASIO_NOEXCEPT
+ {
+ return associated_allocator<Handler, Allocator>::get(h.handler_, a);
+ }
+};
+
+template <typename Handler, typename Arg1, typename Executor>
+struct associated_executor<detail::move_binder1<Handler, Arg1>, Executor>
+{
+ typedef typename associated_executor<Handler, Executor>::type type;
+
+ static type get(const detail::move_binder1<Handler, Arg1>& h,
+ const Executor& ex = Executor()) ASIO_NOEXCEPT
+ {
+ return associated_executor<Handler, Executor>::get(h.handler_, ex);
+ }
+};
+
+template <typename Handler, typename Arg1, typename Arg2, typename Executor>
+struct associated_executor<detail::move_binder2<Handler, Arg1, Arg2>, Executor>
+{
+ typedef typename associated_executor<Handler, Executor>::type type;
+
+ static type get(const detail::move_binder2<Handler, Arg1, Arg2>& h,
+ const Executor& ex = Executor()) ASIO_NOEXCEPT
+ {
+ return associated_executor<Handler, Executor>::get(h.handler_, ex);
+ }
+};
+
+#endif // defined(ASIO_HAS_MOVE)
+
+} // namespace asio
+
+#include "asio/detail/pop_options.hpp"
+
+#endif // ASIO_DETAIL_BIND_HANDLER_HPP
diff --git a/lib/asio/detail/buffer_resize_guard.hpp b/lib/asio/detail/buffer_resize_guard.hpp
new file mode 100644
index 0000000..58ebc4c
--- /dev/null
+++ b/lib/asio/detail/buffer_resize_guard.hpp
@@ -0,0 +1,66 @@
+//
+// detail/buffer_resize_guard.hpp
+// ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+//
+// Copyright (c) 2003-2018 Christopher M. Kohlhoff (chris at kohlhoff dot com)
+//
+// 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 ASIO_DETAIL_BUFFER_RESIZE_GUARD_HPP
+#define ASIO_DETAIL_BUFFER_RESIZE_GUARD_HPP
+
+#if defined(_MSC_VER) && (_MSC_VER >= 1200)
+# pragma once
+#endif // defined(_MSC_VER) && (_MSC_VER >= 1200)
+
+#include "asio/detail/config.hpp"
+#include "asio/detail/limits.hpp"
+
+#include "asio/detail/push_options.hpp"
+
+namespace asio {
+namespace detail {
+
+// Helper class to manage buffer resizing in an exception safe way.
+template <typename Buffer>
+class buffer_resize_guard
+{
+public:
+ // Constructor.
+ buffer_resize_guard(Buffer& buffer)
+ : buffer_(buffer),
+ old_size_(buffer.size())
+ {
+ }
+
+ // Destructor rolls back the buffer resize unless commit was called.
+ ~buffer_resize_guard()
+ {
+ if (old_size_ != (std::numeric_limits<size_t>::max)())
+ {
+ buffer_.resize(old_size_);
+ }
+ }
+
+ // Commit the resize transaction.
+ void commit()
+ {
+ old_size_ = (std::numeric_limits<size_t>::max)();
+ }
+
+private:
+ // The buffer being managed.
+ Buffer& buffer_;
+
+ // The size of the buffer at the time the guard was constructed.
+ size_t old_size_;
+};
+
+} // namespace detail
+} // namespace asio
+
+#include "asio/detail/pop_options.hpp"
+
+#endif // ASIO_DETAIL_BUFFER_RESIZE_GUARD_HPP
diff --git a/lib/asio/detail/buffer_sequence_adapter.hpp b/lib/asio/detail/buffer_sequence_adapter.hpp
new file mode 100644
index 0000000..92a8e3d
--- /dev/null
+++ b/lib/asio/detail/buffer_sequence_adapter.hpp
@@ -0,0 +1,544 @@
+//
+// detail/buffer_sequence_adapter.hpp
+// ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+//
+// Copyright (c) 2003-2018 Christopher M. Kohlhoff (chris at kohlhoff dot com)
+//
+// 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 ASIO_DETAIL_BUFFER_SEQUENCE_ADAPTER_HPP
+#define ASIO_DETAIL_BUFFER_SEQUENCE_ADAPTER_HPP
+
+#if defined(_MSC_VER) && (_MSC_VER >= 1200)
+# pragma once
+#endif // defined(_MSC_VER) && (_MSC_VER >= 1200)
+
+#include "asio/detail/config.hpp"
+#include "asio/buffer.hpp"
+#include "asio/detail/array_fwd.hpp"
+#include "asio/detail/socket_types.hpp"
+
+#include "asio/detail/push_options.hpp"
+
+namespace asio {
+namespace detail {
+
+class buffer_sequence_adapter_base
+{
+#if defined(ASIO_WINDOWS_RUNTIME)
+public:
+ // The maximum number of buffers to support in a single operation.
+ enum { max_buffers = 1 };
+
+protected:
+ typedef Windows::Storage::Streams::IBuffer^ native_buffer_type;
+
+ ASIO_DECL static void init_native_buffer(
+ native_buffer_type& buf,
+ const asio::mutable_buffer& buffer);
+
+ ASIO_DECL static void init_native_buffer(
+ native_buffer_type& buf,
+ const asio::const_buffer& buffer);
+#elif defined(ASIO_WINDOWS) || defined(__CYGWIN__)
+public:
+ // The maximum number of buffers to support in a single operation.
+ enum { max_buffers = 64 < max_iov_len ? 64 : max_iov_len };
+
+protected:
+ typedef WSABUF native_buffer_type;
+
+ static void init_native_buffer(WSABUF& buf,
+ const asio::mutable_buffer& buffer)
+ {
+ buf.buf = static_cast<char*>(buffer.data());
+ buf.len = static_cast<ULONG>(buffer.size());
+ }
+
+ static void init_native_buffer(WSABUF& buf,
+ const asio::const_buffer& buffer)
+ {
+ buf.buf = const_cast<char*>(static_cast<const char*>(buffer.data()));
+ buf.len = static_cast<ULONG>(buffer.size());
+ }
+#else // defined(ASIO_WINDOWS) || defined(__CYGWIN__)
+public:
+ // The maximum number of buffers to support in a single operation.
+ enum { max_buffers = 64 < max_iov_len ? 64 : max_iov_len };
+
+protected:
+ typedef iovec native_buffer_type;
+
+ static void init_iov_base(void*& base, void* addr)
+ {
+ base = addr;
+ }
+
+ template <typename T>
+ static void init_iov_base(T& base, void* addr)
+ {
+ base = static_cast<T>(addr);
+ }
+
+ static void init_native_buffer(iovec& iov,
+ const asio::mutable_buffer& buffer)
+ {
+ init_iov_base(iov.iov_base, buffer.data());
+ iov.iov_len = buffer.size();
+ }
+
+ static void init_native_buffer(iovec& iov,
+ const asio::const_buffer& buffer)
+ {
+ init_iov_base(iov.iov_base, const_cast<void*>(buffer.data()));
+ iov.iov_len = buffer.size();
+ }
+#endif // defined(ASIO_WINDOWS) || defined(__CYGWIN__)
+};
+
+// Helper class to translate buffers into the native buffer representation.
+template <typename Buffer, typename Buffers>
+class buffer_sequence_adapter
+ : buffer_sequence_adapter_base
+{
+public:
+ explicit buffer_sequence_adapter(const Buffers& buffer_sequence)
+ : count_(0), total_buffer_size_(0)
+ {
+ buffer_sequence_adapter::init(
+ asio::buffer_sequence_begin(buffer_sequence),
+ asio::buffer_sequence_end(buffer_sequence));
+ }
+
+ native_buffer_type* buffers()
+ {
+ return buffers_;
+ }
+
+ std::size_t count() const
+ {
+ return count_;
+ }
+
+ std::size_t total_size() const
+ {
+ return total_buffer_size_;
+ }
+
+ bool all_empty() const
+ {
+ return total_buffer_size_ == 0;
+ }
+
+ static bool all_empty(const Buffers& buffer_sequence)
+ {
+ return buffer_sequence_adapter::all_empty(
+ asio::buffer_sequence_begin(buffer_sequence),
+ asio::buffer_sequence_end(buffer_sequence));
+ }
+
+ static void validate(const Buffers& buffer_sequence)
+ {
+ buffer_sequence_adapter::validate(
+ asio::buffer_sequence_begin(buffer_sequence),
+ asio::buffer_sequence_end(buffer_sequence));
+ }
+
+ static Buffer first(const Buffers& buffer_sequence)
+ {
+ return buffer_sequence_adapter::first(
+ asio::buffer_sequence_begin(buffer_sequence),
+ asio::buffer_sequence_end(buffer_sequence));
+ }
+
+private:
+ template <typename Iterator>
+ void init(Iterator begin, Iterator end)
+ {
+ Iterator iter = begin;
+ for (; iter != end && count_ < max_buffers; ++iter, ++count_)
+ {
+ Buffer buffer(*iter);
+ init_native_buffer(buffers_[count_], buffer);
+ total_buffer_size_ += buffer.size();
+ }
+ }
+
+ template <typename Iterator>
+ static bool all_empty(Iterator begin, Iterator end)
+ {
+ Iterator iter = begin;
+ std::size_t i = 0;
+ for (; iter != end && i < max_buffers; ++iter, ++i)
+ if (Buffer(*iter).size() > 0)
+ return false;
+ return true;
+ }
+
+ template <typename Iterator>
+ static void validate(Iterator begin, Iterator end)
+ {
+ Iterator iter = begin;
+ for (; iter != end; ++iter)
+ {
+ Buffer buffer(*iter);
+ buffer.data();
+ }
+ }
+
+ template <typename Iterator>
+ static Buffer first(Iterator begin, Iterator end)
+ {
+ Iterator iter = begin;
+ for (; iter != end; ++iter)
+ {
+ Buffer buffer(*iter);
+ if (buffer.size() != 0)
+ return buffer;
+ }
+ return Buffer();
+ }
+
+ native_buffer_type buffers_[max_buffers];
+ std::size_t count_;
+ std::size_t total_buffer_size_;
+};
+
+template <typename Buffer>
+class buffer_sequence_adapter<Buffer, asio::mutable_buffer>
+ : buffer_sequence_adapter_base
+{
+public:
+ explicit buffer_sequence_adapter(
+ const asio::mutable_buffer& buffer_sequence)
+ {
+ init_native_buffer(buffer_, Buffer(buffer_sequence));
+ total_buffer_size_ = buffer_sequence.size();
+ }
+
+ native_buffer_type* buffers()
+ {
+ return &buffer_;
+ }
+
+ std::size_t count() const
+ {
+ return 1;
+ }
+
+ std::size_t total_size() const
+ {
+ return total_buffer_size_;
+ }
+
+ bool all_empty() const
+ {
+ return total_buffer_size_ == 0;
+ }
+
+ static bool all_empty(const asio::mutable_buffer& buffer_sequence)
+ {
+ return buffer_sequence.size() == 0;
+ }
+
+ static void validate(const asio::mutable_buffer& buffer_sequence)
+ {
+ buffer_sequence.data();
+ }
+
+ static Buffer first(const asio::mutable_buffer& buffer_sequence)
+ {
+ return Buffer(buffer_sequence);
+ }
+
+private:
+ native_buffer_type buffer_;
+ std::size_t total_buffer_size_;
+};
+
+template <typename Buffer>
+class buffer_sequence_adapter<Buffer, asio::const_buffer>
+ : buffer_sequence_adapter_base
+{
+public:
+ explicit buffer_sequence_adapter(
+ const asio::const_buffer& buffer_sequence)
+ {
+ init_native_buffer(buffer_, Buffer(buffer_sequence));
+ total_buffer_size_ = buffer_sequence.size();
+ }
+
+ native_buffer_type* buffers()
+ {
+ return &buffer_;
+ }
+
+ std::size_t count() const
+ {
+ return 1;
+ }
+
+ std::size_t total_size() const
+ {
+ return total_buffer_size_;
+ }
+
+ bool all_empty() const
+ {
+ return total_buffer_size_ == 0;
+ }
+
+ static bool all_empty(const asio::const_buffer& buffer_sequence)
+ {
+ return buffer_sequence.size() == 0;
+ }
+
+ static void validate(const asio::const_buffer& buffer_sequence)
+ {
+ buffer_sequence.data();
+ }
+
+ static Buffer first(const asio::const_buffer& buffer_sequence)
+ {
+ return Buffer(buffer_sequence);
+ }
+
+private:
+ native_buffer_type buffer_;
+ std::size_t total_buffer_size_;
+};
+
+#if !defined(ASIO_NO_DEPRECATED)
+
+template <typename Buffer>
+class buffer_sequence_adapter<Buffer, asio::mutable_buffers_1>
+ : buffer_sequence_adapter_base
+{
+public:
+ explicit buffer_sequence_adapter(
+ const asio::mutable_buffers_1& buffer_sequence)
+ {
+ init_native_buffer(buffer_, Buffer(buffer_sequence));
+ total_buffer_size_ = buffer_sequence.size();
+ }
+
+ native_buffer_type* buffers()
+ {
+ return &buffer_;
+ }
+
+ std::size_t count() const
+ {
+ return 1;
+ }
+
+ std::size_t total_size() const
+ {
+ return total_buffer_size_;
+ }
+
+ bool all_empty() const
+ {
+ return total_buffer_size_ == 0;
+ }
+
+ static bool all_empty(const asio::mutable_buffers_1& buffer_sequence)
+ {
+ return buffer_sequence.size() == 0;
+ }
+
+ static void validate(const asio::mutable_buffers_1& buffer_sequence)
+ {
+ buffer_sequence.data();
+ }
+
+ static Buffer first(const asio::mutable_buffers_1& buffer_sequence)
+ {
+ return Buffer(buffer_sequence);
+ }
+
+private:
+ native_buffer_type buffer_;
+ std::size_t total_buffer_size_;
+};
+
+template <typename Buffer>
+class buffer_sequence_adapter<Buffer, asio::const_buffers_1>
+ : buffer_sequence_adapter_base
+{
+public:
+ explicit buffer_sequence_adapter(
+ const asio::const_buffers_1& buffer_sequence)
+ {
+ init_native_buffer(buffer_, Buffer(buffer_sequence));
+ total_buffer_size_ = buffer_sequence.size();
+ }
+
+ native_buffer_type* buffers()
+ {
+ return &buffer_;
+ }
+
+ std::size_t count() const
+ {
+ return 1;
+ }
+
+ std::size_t total_size() const
+ {
+ return total_buffer_size_;
+ }
+
+ bool all_empty() const
+ {
+ return total_buffer_size_ == 0;
+ }
+
+ static bool all_empty(const asio::const_buffers_1& buffer_sequence)
+ {
+ return buffer_sequence.size() == 0;
+ }
+
+ static void validate(const asio::const_buffers_1& buffer_sequence)
+ {
+ buffer_sequence.data();
+ }
+
+ static Buffer first(const asio::const_buffers_1& buffer_sequence)
+ {
+ return Buffer(buffer_sequence);
+ }
+
+private:
+ native_buffer_type buffer_;
+ std::size_t total_buffer_size_;
+};
+
+#endif // !defined(ASIO_NO_DEPRECATED)
+
+template <typename Buffer, typename Elem>
+class buffer_sequence_adapter<Buffer, boost::array<Elem, 2> >
+ : buffer_sequence_adapter_base
+{
+public:
+ explicit buffer_sequence_adapter(
+ const boost::array<Elem, 2>& buffer_sequence)
+ {
+ init_native_buffer(buffers_[0], Buffer(buffer_sequence[0]));
+ init_native_buffer(buffers_[1], Buffer(buffer_sequence[1]));
+ total_buffer_size_ = buffer_sequence[0].size() + buffer_sequence[1].size();
+ }
+
+ native_buffer_type* buffers()
+ {
+ return buffers_;
+ }
+
+ std::size_t count() const
+ {
+ return 2;
+ }
+
+ std::size_t total_size() const
+ {
+ return total_buffer_size_;
+ }
+
+ bool all_empty() const
+ {
+ return total_buffer_size_ == 0;
+ }
+
+ static bool all_empty(const boost::array<Elem, 2>& buffer_sequence)
+ {
+ return buffer_sequence[0].size() == 0 && buffer_sequence[1].size() == 0;
+ }
+
+ static void validate(const boost::array<Elem, 2>& buffer_sequence)
+ {
+ buffer_sequence[0].data();
+ buffer_sequence[1].data();
+ }
+
+ static Buffer first(const boost::array<Elem, 2>& buffer_sequence)
+ {
+ return Buffer(buffer_sequence[0].size() != 0
+ ? buffer_sequence[0] : buffer_sequence[1]);
+ }
+
+private:
+ native_buffer_type buffers_[2];
+ std::size_t total_buffer_size_;
+};
+
+#if defined(ASIO_HAS_STD_ARRAY)
+
+template <typename Buffer, typename Elem>
+class buffer_sequence_adapter<Buffer, std::array<Elem, 2> >
+ : buffer_sequence_adapter_base
+{
+public:
+ explicit buffer_sequence_adapter(
+ const std::array<Elem, 2>& buffer_sequence)
+ {
+ init_native_buffer(buffers_[0], Buffer(buffer_sequence[0]));
+ init_native_buffer(buffers_[1], Buffer(buffer_sequence[1]));
+ total_buffer_size_ = buffer_sequence[0].size() + buffer_sequence[1].size();
+ }
+
+ native_buffer_type* buffers()
+ {
+ return buffers_;
+ }
+
+ std::size_t count() const
+ {
+ return 2;
+ }
+
+ std::size_t total_size() const
+ {
+ return total_buffer_size_;
+ }
+
+ bool all_empty() const
+ {
+ return total_buffer_size_ == 0;
+ }
+
+ static bool all_empty(const std::array<Elem, 2>& buffer_sequence)
+ {
+ return buffer_sequence[0].size() == 0 && buffer_sequence[1].size() == 0;
+ }
+
+ static void validate(const std::array<Elem, 2>& buffer_sequence)
+ {
+ buffer_sequence[0].data();
+ buffer_sequence[1].data();
+ }
+
+ static Buffer first(const std::array<Elem, 2>& buffer_sequence)
+ {
+ return Buffer(buffer_sequence[0].size() != 0
+ ? buffer_sequence[0] : buffer_sequence[1]);
+ }
+
+private:
+ native_buffer_type buffers_[2];
+ std::size_t total_buffer_size_;
+};
+
+#endif // defined(ASIO_HAS_STD_ARRAY)
+
+} // namespace detail
+} // namespace asio
+
+#include "asio/detail/pop_options.hpp"
+
+#if defined(ASIO_HEADER_ONLY)
+# include "asio/detail/impl/buffer_sequence_adapter.ipp"
+#endif // defined(ASIO_HEADER_ONLY)
+
+#endif // ASIO_DETAIL_BUFFER_SEQUENCE_ADAPTER_HPP
diff --git a/lib/asio/detail/buffered_stream_storage.hpp b/lib/asio/detail/buffered_stream_storage.hpp
new file mode 100644
index 0000000..c5eb081
--- /dev/null
+++ b/lib/asio/detail/buffered_stream_storage.hpp
@@ -0,0 +1,126 @@
+//
+// detail/buffered_stream_storage.hpp
+// ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+//
+// Copyright (c) 2003-2018 Christopher M. Kohlhoff (chris at kohlhoff dot com)
+//
+// 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 ASIO_DETAIL_BUFFERED_STREAM_STORAGE_HPP
+#define ASIO_DETAIL_BUFFERED_STREAM_STORAGE_HPP
+
+#if defined(_MSC_VER) && (_MSC_VER >= 1200)
+# pragma once
+#endif // defined(_MSC_VER) && (_MSC_VER >= 1200)
+
+#include "asio/detail/config.hpp"
+#include "asio/buffer.hpp"
+#include "asio/detail/assert.hpp"
+#include <cstddef>
+#include <cstring>
+#include <vector>
+
+#include "asio/detail/push_options.hpp"
+
+namespace asio {
+namespace detail {
+
+class buffered_stream_storage
+{
+public:
+ // The type of the bytes stored in the buffer.
+ typedef unsigned char byte_type;
+
+ // The type used for offsets into the buffer.
+ typedef std::size_t size_type;
+
+ // Constructor.
+ explicit buffered_stream_storage(std::size_t buffer_capacity)
+ : begin_offset_(0),
+ end_offset_(0),
+ buffer_(buffer_capacity)
+ {
+ }
+
+ /// Clear the buffer.
+ void clear()
+ {
+ begin_offset_ = 0;
+ end_offset_ = 0;
+ }
+
+ // Return a pointer to the beginning of the unread data.
+ mutable_buffer data()
+ {
+ return asio::buffer(buffer_) + begin_offset_;
+ }
+
+ // Return a pointer to the beginning of the unread data.
+ const_buffer data() const
+ {
+ return asio::buffer(buffer_) + begin_offset_;
+ }
+
+ // Is there no unread data in the buffer.
+ bool empty() const
+ {
+ return begin_offset_ == end_offset_;
+ }
+
+ // Return the amount of unread data the is in the buffer.
+ size_type size() const
+ {
+ return end_offset_ - begin_offset_;
+ }
+
+ // Resize the buffer to the specified length.
+ void resize(size_type length)
+ {
+ ASIO_ASSERT(length <= capacity());
+ if (begin_offset_ + length <= capacity())
+ {
+ end_offset_ = begin_offset_ + length;
+ }
+ else
+ {
+ using namespace std; // For memmove.
+ memmove(&buffer_[0], &buffer_[0] + begin_offset_, size());
+ end_offset_ = length;
+ begin_offset_ = 0;
+ }
+ }
+
+ // Return the maximum size for data in the buffer.
+ size_type capacity() const
+ {
+ return buffer_.size();
+ }
+
+ // Consume multiple bytes from the beginning of the buffer.
+ void consume(size_type count)
+ {
+ ASIO_ASSERT(begin_offset_ + count <= end_offset_);
+ begin_offset_ += count;
+ if (empty())
+ clear();
+ }
+
+private:
+ // The offset to the beginning of the unread data.
+ size_type begin_offset_;
+
+ // The offset to the end of the unread data.
+ size_type end_offset_;
+
+ // The data in the buffer.
+ std::vector<byte_type> buffer_;
+};
+
+} // namespace detail
+} // namespace asio
+
+#include "asio/detail/pop_options.hpp"
+
+#endif // ASIO_DETAIL_BUFFERED_STREAM_STORAGE_HPP
diff --git a/lib/asio/detail/call_stack.hpp b/lib/asio/detail/call_stack.hpp
new file mode 100644
index 0000000..5725a10
--- /dev/null
+++ b/lib/asio/detail/call_stack.hpp
@@ -0,0 +1,125 @@
+//
+// detail/call_stack.hpp
+// ~~~~~~~~~~~~~~~~~~~~~
+//
+// Copyright (c) 2003-2018 Christopher M. Kohlhoff (chris at kohlhoff dot com)
+//
+// 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 ASIO_DETAIL_CALL_STACK_HPP
+#define ASIO_DETAIL_CALL_STACK_HPP
+
+#if defined(_MSC_VER) && (_MSC_VER >= 1200)
+# pragma once
+#endif // defined(_MSC_VER) && (_MSC_VER >= 1200)
+
+#include "asio/detail/config.hpp"
+#include "asio/detail/noncopyable.hpp"
+#include "asio/detail/tss_ptr.hpp"
+
+#include "asio/detail/push_options.hpp"
+
+namespace asio {
+namespace detail {
+
+// Helper class to determine whether or not the current thread is inside an
+// invocation of io_context::run() for a specified io_context object.
+template <typename Key, typename Value = unsigned char>
+class call_stack
+{
+public:
+ // Context class automatically pushes the key/value pair on to the stack.
+ class context
+ : private noncopyable
+ {
+ public:
+ // Push the key on to the stack.
+ explicit context(Key* k)
+ : key_(k),
+ next_(call_stack<Key, Value>::top_)
+ {
+ value_ = reinterpret_cast<unsigned char*>(this);
+ call_stack<Key, Value>::top_ = this;
+ }
+
+ // Push the key/value pair on to the stack.
+ context(Key* k, Value& v)
+ : key_(k),
+ value_(&v),
+ next_(call_stack<Key, Value>::top_)
+ {
+ call_stack<Key, Value>::top_ = this;
+ }
+
+ // Pop the key/value pair from the stack.
+ ~context()
+ {
+ call_stack<Key, Value>::top_ = next_;
+ }
+
+ // Find the next context with the same key.
+ Value* next_by_key() const
+ {
+ context* elem = next_;
+ while (elem)
+ {
+ if (elem->key_ == key_)
+ return elem->value_;
+ elem = elem->next_;
+ }
+ return 0;
+ }
+
+ private:
+ friend class call_stack<Key, Value>;
+
+ // The key associated with the context.
+ Key* key_;
+
+ // The value associated with the context.
+ Value* value_;
+
+ // The next element in the stack.
+ context* next_;
+ };
+
+ friend class context;
+
+ // Determine whether the specified owner is on the stack. Returns address of
+ // key if present, 0 otherwise.
+ static Value* contains(Key* k)
+ {
+ context* elem = top_;
+ while (elem)
+ {
+ if (elem->key_ == k)
+ return elem->value_;
+ elem = elem->next_;
+ }
+ return 0;
+ }
+
+ // Obtain the value at the top of the stack.
+ static Value* top()
+ {
+ context* elem = top_;
+ return elem ? elem->value_ : 0;
+ }
+
+private:
+ // The top of the stack of calls for the current thread.
+ static tss_ptr<context> top_;
+};
+
+template <typename Key, typename Value>
+tss_ptr<typename call_stack<Key, Value>::context>
+call_stack<Key, Value>::top_;
+
+} // namespace detail
+} // namespace asio
+
+#include "asio/detail/pop_options.hpp"
+
+#endif // ASIO_DETAIL_CALL_STACK_HPP
diff --git a/lib/asio/detail/chrono.hpp b/lib/asio/detail/chrono.hpp
new file mode 100644
index 0000000..8f56bee
--- /dev/null
+++ b/lib/asio/detail/chrono.hpp
@@ -0,0 +1,66 @@
+//
+// detail/chrono.hpp
+// ~~~~~~~~~~~~~~~~~
+//
+// Copyright (c) 2003-2018 Christopher M. Kohlhoff (chris at kohlhoff dot com)
+//
+// 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 ASIO_DETAIL_CHRONO_HPP
+#define ASIO_DETAIL_CHRONO_HPP
+
+#if defined(_MSC_VER) && (_MSC_VER >= 1200)
+# pragma once
+#endif // defined(_MSC_VER) && (_MSC_VER >= 1200)
+
+#include "asio/detail/config.hpp"
+
+#if defined(ASIO_HAS_STD_CHRONO)
+# include <chrono>
+#elif defined(ASIO_HAS_BOOST_CHRONO)
+# include <boost/chrono/system_clocks.hpp>
+#endif // defined(ASIO_HAS_BOOST_CHRONO)
+
+namespace asio {
+namespace chrono {
+
+#if defined(ASIO_HAS_STD_CHRONO)
+using std::chrono::duration;
+using std::chrono::time_point;
+using std::chrono::duration_cast;
+using std::chrono::nanoseconds;
+using std::chrono::microseconds;
+using std::chrono::milliseconds;
+using std::chrono::seconds;
+using std::chrono::minutes;
+using std::chrono::hours;
+using std::chrono::time_point_cast;
+#if defined(ASIO_HAS_STD_CHRONO_MONOTONIC_CLOCK)
+typedef std::chrono::monotonic_clock steady_clock;
+#else // defined(ASIO_HAS_STD_CHRONO_MONOTONIC_CLOCK)
+using std::chrono::steady_clock;
+#endif // defined(ASIO_HAS_STD_CHRONO_MONOTONIC_CLOCK)
+using std::chrono::system_clock;
+using std::chrono::high_resolution_clock;
+#elif defined(ASIO_HAS_BOOST_CHRONO)
+using boost::chrono::duration;
+using boost::chrono::time_point;
+using boost::chrono::duration_cast;
+using boost::chrono::nanoseconds;
+using boost::chrono::microseconds;
+using boost::chrono::milliseconds;
+using boost::chrono::seconds;
+using boost::chrono::minutes;
+using boost::chrono::hours;
+using boost::chrono::time_point_cast;
+using boost::chrono::system_clock;
+using boost::chrono::steady_clock;
+using boost::chrono::high_resolution_clock;
+#endif // defined(ASIO_HAS_BOOST_CHRONO)
+
+} // namespace chrono
+} // namespace asio
+
+#endif // ASIO_DETAIL_CHRONO_HPP
diff --git a/lib/asio/detail/chrono_time_traits.hpp b/lib/asio/detail/chrono_time_traits.hpp
new file mode 100644
index 0000000..d1528f7
--- /dev/null
+++ b/lib/asio/detail/chrono_time_traits.hpp
@@ -0,0 +1,190 @@
+//
+// detail/chrono_time_traits.hpp
+// ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+//
+// Copyright (c) 2003-2018 Christopher M. Kohlhoff (chris at kohlhoff dot com)
+//
+// 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 ASIO_DETAIL_CHRONO_TIME_TRAITS_HPP
+#define ASIO_DETAIL_CHRONO_TIME_TRAITS_HPP
+
+#if defined(_MSC_VER) && (_MSC_VER >= 1200)
+# pragma once
+#endif // defined(_MSC_VER) && (_MSC_VER >= 1200)
+
+#include "asio/detail/cstdint.hpp"
+
+#include "asio/detail/push_options.hpp"
+
+namespace asio {
+namespace detail {
+
+// Helper template to compute the greatest common divisor.
+template <int64_t v1, int64_t v2>
+struct gcd { enum { value = gcd<v2, v1 % v2>::value }; };
+
+template <int64_t v1>
+struct gcd<v1, 0> { enum { value = v1 }; };
+
+// Adapts std::chrono clocks for use with a deadline timer.
+template <typename Clock, typename WaitTraits>
+struct chrono_time_traits
+{
+ // The clock type.
+ typedef Clock clock_type;
+
+ // The duration type of the clock.
+ typedef typename clock_type::duration duration_type;
+
+ // The time point type of the clock.
+ typedef typename clock_type::time_point time_type;
+
+ // The period of the clock.
+ typedef typename duration_type::period period_type;
+
+ // Get the current time.
+ static time_type now()
+ {
+ return clock_type::now();
+ }
+
+ // Add a duration to a time.
+ static time_type add(const time_type& t, const duration_type& d)
+ {
+ const time_type epoch;
+ if (t >= epoch)
+ {
+ if ((time_type::max)() - t < d)
+ return (time_type::max)();
+ }
+ else // t < epoch
+ {
+ if (-(t - (time_type::min)()) > d)
+ return (time_type::min)();
+ }
+
+ return t + d;
+ }
+
+ // Subtract one time from another.
+ static duration_type subtract(const time_type& t1, const time_type& t2)
+ {
+ const time_type epoch;
+ if (t1 >= epoch)
+ {
+ if (t2 >= epoch)
+ {
+ return t1 - t2;
+ }
+ else if (t2 == (time_type::min)())
+ {
+ return (duration_type::max)();
+ }
+ else if ((time_type::max)() - t1 < epoch - t2)
+ {
+ return (duration_type::max)();
+ }
+ else
+ {
+ return t1 - t2;
+ }
+ }
+ else // t1 < epoch
+ {
+ if (t2 < epoch)
+ {
+ return t1 - t2;
+ }
+ else if (t1 == (time_type::min)())
+ {
+ return (duration_type::min)();
+ }
+ else if ((time_type::max)() - t2 < epoch - t1)
+ {
+ return (duration_type::min)();
+ }
+ else
+ {
+ return -(t2 - t1);
+ }
+ }
+ }
+
+ // Test whether one time is less than another.
+ static bool less_than(const time_type& t1, const time_type& t2)
+ {
+ return t1 < t2;
+ }
+
+ // Implement just enough of the posix_time::time_duration interface to supply
+ // what the timer_queue requires.
+ class posix_time_duration
+ {
+ public:
+ explicit posix_time_duration(const duration_type& d)
+ : d_(d)
+ {
+ }
+
+ int64_t ticks() const
+ {
+ return d_.count();
+ }
+
+ int64_t total_seconds() const
+ {
+ return duration_cast<1, 1>();
+ }
+
+ int64_t total_milliseconds() const
+ {
+ return duration_cast<1, 1000>();
+ }
+
+ int64_t total_microseconds() const
+ {
+ return duration_cast<1, 1000000>();
+ }
+
+ private:
+ template <int64_t Num, int64_t Den>
+ int64_t duration_cast() const
+ {
+ const int64_t num1 = period_type::num / gcd<period_type::num, Num>::value;
+ const int64_t num2 = Num / gcd<period_type::num, Num>::value;
+
+ const int64_t den1 = period_type::den / gcd<period_type::den, Den>::value;
+ const int64_t den2 = Den / gcd<period_type::den, Den>::value;
+
+ const int64_t num = num1 * den2;
+ const int64_t den = num2 * den1;
+
+ if (num == 1 && den == 1)
+ return ticks();
+ else if (num != 1 && den == 1)
+ return ticks() * num;
+ else if (num == 1 && period_type::den != 1)
+ return ticks() / den;
+ else
+ return ticks() * num / den;
+ }
+
+ duration_type d_;
+ };
+
+ // Convert to POSIX duration type.
+ static posix_time_duration to_posix_duration(const duration_type& d)
+ {
+ return posix_time_duration(WaitTraits::to_wait_duration(d));
+ }
+};
+
+} // namespace detail
+} // namespace asio
+
+#include "asio/detail/pop_options.hpp"
+
+#endif // ASIO_DETAIL_CHRONO_TIME_TRAITS_HPP
diff --git a/lib/asio/detail/completion_handler.hpp b/lib/asio/detail/completion_handler.hpp
new file mode 100644
index 0000000..58a2e6d
--- /dev/null
+++ b/lib/asio/detail/completion_handler.hpp
@@ -0,0 +1,83 @@
+//
+// detail/completion_handler.hpp
+// ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+//
+// Copyright (c) 2003-2018 Christopher M. Kohlhoff (chris at kohlhoff dot com)
+//
+// 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 ASIO_DETAIL_COMPLETION_HANDLER_HPP
+#define ASIO_DETAIL_COMPLETION_HANDLER_HPP
+
+#if defined(_MSC_VER) && (_MSC_VER >= 1200)
+# pragma once
+#endif // defined(_MSC_VER) && (_MSC_VER >= 1200)
+
+#include "asio/detail/config.hpp"
+#include "asio/detail/fenced_block.hpp"
+#include "asio/detail/handler_alloc_helpers.hpp"
+#include "asio/detail/handler_work.hpp"
+#include "asio/detail/memory.hpp"
+#include "asio/detail/operation.hpp"
+
+#include "asio/detail/push_options.hpp"
+
+namespace asio {
+namespace detail {
+
+template <typename Handler>
+class completion_handler : public operation
+{
+public:
+ ASIO_DEFINE_HANDLER_PTR(completion_handler);
+
+ completion_handler(Handler& h)
+ : operation(&completion_handler::do_complete),
+ handler_(ASIO_MOVE_CAST(Handler)(h))
+ {
+ handler_work<Handler>::start(handler_);
+ }
+
+ static void do_complete(void* owner, operation* base,
+ const asio::error_code& /*ec*/,
+ std::size_t /*bytes_transferred*/)
+ {
+ // Take ownership of the handler object.
+ completion_handler* h(static_cast<completion_handler*>(base));
+ ptr p = { asio::detail::addressof(h->handler_), h, h };
+ handler_work<Handler> w(h->handler_);
+
+ ASIO_HANDLER_COMPLETION((*h));
+
+ // 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.
+ Handler handler(ASIO_MOVE_CAST(Handler)(h->handler_));
+ p.h = asio::detail::addressof(handler);
+ p.reset();
+
+ // Make the upcall if required.
+ if (owner)
+ {
+ fenced_block b(fenced_block::half);
+ ASIO_HANDLER_INVOCATION_BEGIN(());
+ w.complete(handler, handler);
+ ASIO_HANDLER_INVOCATION_END;
+ }
+ }
+
+private:
+ Handler handler_;
+};
+
+} // namespace detail
+} // namespace asio
+
+#include "asio/detail/pop_options.hpp"
+
+#endif // ASIO_DETAIL_COMPLETION_HANDLER_HPP
diff --git a/lib/asio/detail/concurrency_hint.hpp b/lib/asio/detail/concurrency_hint.hpp
new file mode 100644
index 0000000..229124d
--- /dev/null
+++ b/lib/asio/detail/concurrency_hint.hpp
@@ -0,0 +1,94 @@
+//
+// detail/concurrency_hint.hpp
+// ~~~~~~~~~~~~~~~~~~~~~~~~~~~
+//
+// Copyright (c) 2003-2018 Christopher M. Kohlhoff (chris at kohlhoff dot com)
+//
+// 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 ASIO_DETAIL_CONCURRENCY_HINT_HPP
+#define ASIO_DETAIL_CONCURRENCY_HINT_HPP
+
+#if defined(_MSC_VER) && (_MSC_VER >= 1200)
+# pragma once
+#endif // defined(_MSC_VER) && (_MSC_VER >= 1200)
+
+#include "asio/detail/config.hpp"
+#include "asio/detail/noncopyable.hpp"
+
+// The concurrency hint ID and mask are used to identify when a "well-known"
+// concurrency hint value has been passed to the io_context.
+#define ASIO_CONCURRENCY_HINT_ID 0xA5100000u
+#define ASIO_CONCURRENCY_HINT_ID_MASK 0xFFFF0000u
+
+// If set, this bit indicates that the scheduler should perform locking.
+#define ASIO_CONCURRENCY_HINT_LOCKING_SCHEDULER 0x1u
+
+// If set, this bit indicates that the reactor should perform locking when
+// managing descriptor registrations.
+#define ASIO_CONCURRENCY_HINT_LOCKING_REACTOR_REGISTRATION 0x2u
+
+// If set, this bit indicates that the reactor should perform locking for I/O.
+#define ASIO_CONCURRENCY_HINT_LOCKING_REACTOR_IO 0x4u
+
+// Helper macro to determine if we have a special concurrency hint.
+#define ASIO_CONCURRENCY_HINT_IS_SPECIAL(hint) \
+ ((static_cast<unsigned>(hint) \
+ & ASIO_CONCURRENCY_HINT_ID_MASK) \
+ == ASIO_CONCURRENCY_HINT_ID)
+
+// Helper macro to determine if locking is enabled for a given facility.
+#define ASIO_CONCURRENCY_HINT_IS_LOCKING(facility, hint) \
+ (((static_cast<unsigned>(hint) \
+ & (ASIO_CONCURRENCY_HINT_ID_MASK \
+ | ASIO_CONCURRENCY_HINT_LOCKING_ ## facility)) \
+ ^ ASIO_CONCURRENCY_HINT_ID) != 0)
+
+// This special concurrency hint disables locking in both the scheduler and
+// reactor I/O. This hint has the following restrictions:
+//
+// - Care must be taken to ensure that all operations on the io_context and any
+// of its associated I/O objects (such as sockets and timers) occur in only
+// one thread at a time.
+//
+// - Asynchronous resolve operations fail with operation_not_supported.
+//
+// - If a signal_set is used with the io_context, signal_set objects cannot be
+// used with any other io_context in the program.
+#define ASIO_CONCURRENCY_HINT_UNSAFE \
+ static_cast<int>(ASIO_CONCURRENCY_HINT_ID)
+
+// This special concurrency hint disables locking in the reactor I/O. This hint
+// has the following restrictions:
+//
+// - Care must be taken to ensure that run functions on the io_context, and all
+// operations on the io_context's associated I/O objects (such as sockets and
+// timers), occur in only one thread at a time.
+#define ASIO_CONCURRENCY_HINT_UNSAFE_IO \
+ static_cast<int>(ASIO_CONCURRENCY_HINT_ID \
+ | ASIO_CONCURRENCY_HINT_LOCKING_SCHEDULER \
+ | ASIO_CONCURRENCY_HINT_LOCKING_REACTOR_REGISTRATION)
+
+// The special concurrency hint provides full thread safety.
+#define ASIO_CONCURRENCY_HINT_SAFE \
+ static_cast<int>(ASIO_CONCURRENCY_HINT_ID \
+ | ASIO_CONCURRENCY_HINT_LOCKING_SCHEDULER \
+ | ASIO_CONCURRENCY_HINT_LOCKING_REACTOR_REGISTRATION \
+ | ASIO_CONCURRENCY_HINT_LOCKING_REACTOR_IO)
+
+// This #define may be overridden at compile time to specify a program-wide
+// default concurrency hint, used by the zero-argument io_context constructor.
+#if !defined(ASIO_CONCURRENCY_HINT_DEFAULT)
+# define ASIO_CONCURRENCY_HINT_DEFAULT -1
+#endif // !defined(ASIO_CONCURRENCY_HINT_DEFAULT)
+
+// This #define may be overridden at compile time to specify a program-wide
+// concurrency hint, used by the one-argument io_context constructor when
+// passed a value of 1.
+#if !defined(ASIO_CONCURRENCY_HINT_1)
+# define ASIO_CONCURRENCY_HINT_1 1
+#endif // !defined(ASIO_CONCURRENCY_HINT_DEFAULT)
+
+#endif // ASIO_DETAIL_CONCURRENCY_HINT_HPP
diff --git a/lib/asio/detail/conditionally_enabled_event.hpp b/lib/asio/detail/conditionally_enabled_event.hpp
new file mode 100644
index 0000000..0fda401
--- /dev/null
+++ b/lib/asio/detail/conditionally_enabled_event.hpp
@@ -0,0 +1,112 @@
+//
+// detail/conditionally_enabled_event.hpp
+// ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+//
+// Copyright (c) 2003-2018 Christopher M. Kohlhoff (chris at kohlhoff dot com)
+//
+// 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 ASIO_DETAIL_CONDITIONALLY_ENABLED_EVENT_HPP
+#define ASIO_DETAIL_CONDITIONALLY_ENABLED_EVENT_HPP
+
+#if defined(_MSC_VER) && (_MSC_VER >= 1200)
+# pragma once
+#endif // defined(_MSC_VER) && (_MSC_VER >= 1200)
+
+#include "asio/detail/config.hpp"
+#include "asio/detail/conditionally_enabled_mutex.hpp"
+#include "asio/detail/event.hpp"
+#include "asio/detail/noncopyable.hpp"
+#include "asio/detail/null_event.hpp"
+#include "asio/detail/scoped_lock.hpp"
+
+#include "asio/detail/push_options.hpp"
+
+namespace asio {
+namespace detail {
+
+// Mutex adapter used to conditionally enable or disable locking.
+class conditionally_enabled_event
+ : private noncopyable
+{
+public:
+ // Constructor.
+ conditionally_enabled_event()
+ {
+ }
+
+ // Destructor.
+ ~conditionally_enabled_event()
+ {
+ }
+
+ // Signal the event. (Retained for backward compatibility.)
+ void signal(conditionally_enabled_mutex::scoped_lock& lock)
+ {
+ if (lock.mutex_.enabled_)
+ event_.signal(lock);
+ }
+
+ // Signal all waiters.
+ void signal_all(conditionally_enabled_mutex::scoped_lock& lock)
+ {
+ if (lock.mutex_.enabled_)
+ event_.signal_all(lock);
+ }
+
+ // Unlock the mutex and signal one waiter.
+ void unlock_and_signal_one(
+ conditionally_enabled_mutex::scoped_lock& lock)
+ {
+ if (lock.mutex_.enabled_)
+ event_.unlock_and_signal_one(lock);
+ }
+
+ // If there's a waiter, unlock the mutex and signal it.
+ bool maybe_unlock_and_signal_one(
+ conditionally_enabled_mutex::scoped_lock& lock)
+ {
+ if (lock.mutex_.enabled_)
+ return event_.maybe_unlock_and_signal_one(lock);
+ else
+ return false;
+ }
+
+ // Reset the event.
+ void clear(conditionally_enabled_mutex::scoped_lock& lock)
+ {
+ if (lock.mutex_.enabled_)
+ event_.clear(lock);
+ }
+
+ // Wait for the event to become signalled.
+ void wait(conditionally_enabled_mutex::scoped_lock& lock)
+ {
+ if (lock.mutex_.enabled_)
+ event_.wait(lock);
+ else
+ null_event().wait(lock);
+ }
+
+ // Timed wait for the event to become signalled.
+ bool wait_for_usec(
+ conditionally_enabled_mutex::scoped_lock& lock, long usec)
+ {
+ if (lock.mutex_.enabled_)
+ return event_.wait_for_usec(lock, usec);
+ else
+ return null_event().wait_for_usec(lock, usec);
+ }
+
+private:
+ asio::detail::event event_;
+};
+
+} // namespace detail
+} // namespace asio
+
+#include "asio/detail/pop_options.hpp"
+
+#endif // ASIO_DETAIL_CONDITIONALLY_ENABLED_EVENT_HPP
diff --git a/lib/asio/detail/conditionally_enabled_mutex.hpp b/lib/asio/detail/conditionally_enabled_mutex.hpp
new file mode 100644
index 0000000..2872db9
--- /dev/null
+++ b/lib/asio/detail/conditionally_enabled_mutex.hpp
@@ -0,0 +1,149 @@
+//
+// detail/conditionally_enabled_mutex.hpp
+// ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+//
+// Copyright (c) 2003-2018 Christopher M. Kohlhoff (chris at kohlhoff dot com)
+//
+// 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 ASIO_DETAIL_CONDITIONALLY_ENABLED_MUTEX_HPP
+#define ASIO_DETAIL_CONDITIONALLY_ENABLED_MUTEX_HPP
+
+#if defined(_MSC_VER) && (_MSC_VER >= 1200)
+# pragma once
+#endif // defined(_MSC_VER) && (_MSC_VER >= 1200)
+
+#include "asio/detail/config.hpp"
+#include "asio/detail/mutex.hpp"
+#include "asio/detail/noncopyable.hpp"
+#include "asio/detail/scoped_lock.hpp"
+
+#include "asio/detail/push_options.hpp"
+
+namespace asio {
+namespace detail {
+
+// Mutex adapter used to conditionally enable or disable locking.
+class conditionally_enabled_mutex
+ : private noncopyable
+{
+public:
+ // Helper class to lock and unlock a mutex automatically.
+ class scoped_lock
+ : private noncopyable
+ {
+ public:
+ // Tag type used to distinguish constructors.
+ enum adopt_lock_t { adopt_lock };
+
+ // Constructor adopts a lock that is already held.
+ scoped_lock(conditionally_enabled_mutex& m, adopt_lock_t)
+ : mutex_(m),
+ locked_(m.enabled_)
+ {
+ }
+
+ // Constructor acquires the lock.
+ explicit scoped_lock(conditionally_enabled_mutex& m)
+ : mutex_(m)
+ {
+ if (m.enabled_)
+ {
+ mutex_.mutex_.lock();
+ locked_ = true;
+ }
+ else
+ locked_ = false;
+ }
+
+ // Destructor releases the lock.
+ ~scoped_lock()
+ {
+ if (locked_)
+ mutex_.mutex_.unlock();
+ }
+
+ // Explicitly acquire the lock.
+ void lock()
+ {
+ if (mutex_.enabled_ && !locked_)
+ {
+ mutex_.mutex_.lock();
+ locked_ = true;
+ }
+ }
+
+ // Explicitly release the lock.
+ void unlock()
+ {
+ if (locked_)
+ {
+ mutex_.unlock();
+ locked_ = false;
+ }
+ }
+
+ // Test whether the lock is held.
+ bool locked() const
+ {
+ return locked_;
+ }
+
+ // Get the underlying mutex.
+ asio::detail::mutex& mutex()
+ {
+ return mutex_.mutex_;
+ }
+
+ private:
+ friend class conditionally_enabled_event;
+ conditionally_enabled_mutex& mutex_;
+ bool locked_;
+ };
+
+ // Constructor.
+ explicit conditionally_enabled_mutex(bool enabled)
+ : enabled_(enabled)
+ {
+ }
+
+ // Destructor.
+ ~conditionally_enabled_mutex()
+ {
+ }
+
+ // Determine whether locking is enabled.
+ bool enabled() const
+ {
+ return enabled_;
+ }
+
+ // Lock the mutex.
+ void lock()
+ {
+ if (enabled_)
+ mutex_.lock();
+ }
+
+ // Unlock the mutex.
+ void unlock()
+ {
+ if (enabled_)
+ mutex_.unlock();
+ }
+
+private:
+ friend class scoped_lock;
+ friend class conditionally_enabled_event;
+ asio::detail::mutex mutex_;
+ const bool enabled_;
+};
+
+} // namespace detail
+} // namespace asio
+
+#include "asio/detail/pop_options.hpp"
+
+#endif // ASIO_DETAIL_CONDITIONALLY_ENABLED_MUTEX_HPP
diff --git a/lib/asio/detail/config.hpp b/lib/asio/detail/config.hpp
new file mode 100644
index 0000000..cde334e
--- /dev/null
+++ b/lib/asio/detail/config.hpp
@@ -0,0 +1,1437 @@
+//
+// detail/config.hpp
+// ~~~~~~~~~~~~~~~~~
+//
+// Copyright (c) 2003-2018 Christopher M. Kohlhoff (chris at kohlhoff dot com)
+//
+// 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 ASIO_DETAIL_CONFIG_HPP
+#define ASIO_DETAIL_CONFIG_HPP
+
+#if defined(ASIO_STANDALONE)
+# define ASIO_DISABLE_BOOST_ARRAY 1
+# define ASIO_DISABLE_BOOST_ASSERT 1
+# define ASIO_DISABLE_BOOST_BIND 1
+# define ASIO_DISABLE_BOOST_CHRONO 1
+# define ASIO_DISABLE_BOOST_DATE_TIME 1
+# define ASIO_DISABLE_BOOST_LIMITS 1
+# define ASIO_DISABLE_BOOST_REGEX 1
+# define ASIO_DISABLE_BOOST_STATIC_CONSTANT 1
+# define ASIO_DISABLE_BOOST_THROW_EXCEPTION 1
+# define ASIO_DISABLE_BOOST_WORKAROUND 1
+#else // defined(ASIO_STANDALONE)
+# include <boost/config.hpp>
+# include <boost/version.hpp>
+# define ASIO_HAS_BOOST_CONFIG 1
+#endif // defined(ASIO_STANDALONE)
+
+// Default to a header-only implementation. The user must specifically request
+// separate compilation by defining either ASIO_SEPARATE_COMPILATION or
+// ASIO_DYN_LINK (as a DLL/shared library implies separate compilation).
+#if !defined(ASIO_HEADER_ONLY)
+# if !defined(ASIO_SEPARATE_COMPILATION)
+# if !defined(ASIO_DYN_LINK)
+# define ASIO_HEADER_ONLY 1
+# endif // !defined(ASIO_DYN_LINK)
+# endif // !defined(ASIO_SEPARATE_COMPILATION)
+#endif // !defined(ASIO_HEADER_ONLY)
+
+#if defined(ASIO_HEADER_ONLY)
+# define ASIO_DECL inline
+#else // defined(ASIO_HEADER_ONLY)
+# if defined(_MSC_VER) || defined(__BORLANDC__) || defined(__CODEGEARC__)
+// We need to import/export our code only if the user has specifically asked
+// for it by defining ASIO_DYN_LINK.
+# if defined(ASIO_DYN_LINK)
+// Export if this is our own source, otherwise import.
+# if defined(ASIO_SOURCE)
+# define ASIO_DECL __declspec(dllexport)
+# else // defined(ASIO_SOURCE)
+# define ASIO_DECL __declspec(dllimport)
+# endif // defined(ASIO_SOURCE)
+# endif // defined(ASIO_DYN_LINK)
+# endif // defined(_MSC_VER) || defined(__BORLANDC__) || defined(__CODEGEARC__)
+#endif // defined(ASIO_HEADER_ONLY)
+
+// If ASIO_DECL isn't defined yet define it now.
+#if !defined(ASIO_DECL)
+# define ASIO_DECL
+#endif // !defined(ASIO_DECL)
+
+// Microsoft Visual C++ detection.
+#if !defined(ASIO_MSVC)
+# if defined(ASIO_HAS_BOOST_CONFIG) && defined(BOOST_MSVC)
+# define ASIO_MSVC BOOST_MSVC
+# elif defined(_MSC_VER) && (defined(__INTELLISENSE__) \
+ || (!defined(__MWERKS__) && !defined(__EDG_VERSION__)))
+# define ASIO_MSVC _MSC_VER
+# endif // defined(ASIO_HAS_BOOST_CONFIG) && defined(BOOST_MSVC)
+#endif // !defined(ASIO_MSVC)
+#if defined(ASIO_MSVC)
+# include <ciso646> // Needed for _HAS_CXX17.
+#endif // defined(ASIO_MSVC)
+
+// Clang / libc++ detection.
+#if defined(__clang__)
+# if (__cplusplus >= 201103)
+# if __has_include(<__config>)
+# include <__config>
+# if defined(_LIBCPP_VERSION)
+# define ASIO_HAS_CLANG_LIBCXX 1
+# endif // defined(_LIBCPP_VERSION)
+# endif // __has_include(<__config>)
+# endif // (__cplusplus >= 201103)
+#endif // defined(__clang__)
+
+// Android platform detection.
+#if defined(__ANDROID__)
+# include <android/api-level.h>
+#endif // defined(__ANDROID__)
+
+// Support move construction and assignment on compilers known to allow it.
+#if !defined(ASIO_HAS_MOVE)
+# if !defined(ASIO_DISABLE_MOVE)
+# if defined(__clang__)
+# if __has_feature(__cxx_rvalue_references__)
+# define ASIO_HAS_MOVE 1
+# endif // __has_feature(__cxx_rvalue_references__)
+# endif // defined(__clang__)
+# if defined(__GNUC__)
+# if ((__GNUC__ == 4) && (__GNUC_MINOR__ >= 5)) || (__GNUC__ > 4)
+# if defined(__GXX_EXPERIMENTAL_CXX0X__)
+# define ASIO_HAS_MOVE 1
+# endif // defined(__GXX_EXPERIMENTAL_CXX0X__)
+# endif // ((__GNUC__ == 4) && (__GNUC_MINOR__ >= 5)) || (__GNUC__ > 4)
+# endif // defined(__GNUC__)
+# if defined(ASIO_MSVC)
+# if (_MSC_VER >= 1700)
+# define ASIO_HAS_MOVE 1
+# endif // (_MSC_VER >= 1700)
+# endif // defined(ASIO_MSVC)
+# endif // !defined(ASIO_DISABLE_MOVE)
+#endif // !defined(ASIO_HAS_MOVE)
+
+// If ASIO_MOVE_CAST isn't defined, and move support is available, define
+// ASIO_MOVE_ARG and ASIO_MOVE_CAST to take advantage of rvalue
+// references and perfect forwarding.
+#if defined(ASIO_HAS_MOVE) && !defined(ASIO_MOVE_CAST)
+# define ASIO_MOVE_ARG(type) type&&
+# define ASIO_MOVE_ARG2(type1, type2) type1, type2&&
+# define ASIO_MOVE_CAST(type) static_cast<type&&>
+# define ASIO_MOVE_CAST2(type1, type2) static_cast<type1, type2&&>
+#endif // defined(ASIO_HAS_MOVE) && !defined(ASIO_MOVE_CAST)
+
+// If ASIO_MOVE_CAST still isn't defined, default to a C++03-compatible
+// implementation. Note that older g++ and MSVC versions don't like it when you
+// pass a non-member function through a const reference, so for most compilers
+// we'll play it safe and stick with the old approach of passing the handler by
+// value.
+#if !defined(ASIO_MOVE_CAST)
+# if defined(__GNUC__)
+# if ((__GNUC__ == 4) && (__GNUC_MINOR__ >= 1)) || (__GNUC__ > 4)
+# define ASIO_MOVE_ARG(type) const type&
+# else // ((__GNUC__ == 4) && (__GNUC_MINOR__ >= 1)) || (__GNUC__ > 4)
+# define ASIO_MOVE_ARG(type) type
+# endif // ((__GNUC__ == 4) && (__GNUC_MINOR__ >= 1)) || (__GNUC__ > 4)
+# elif defined(ASIO_MSVC)
+# if (_MSC_VER >= 1400)
+# define ASIO_MOVE_ARG(type) const type&
+# else // (_MSC_VER >= 1400)
+# define ASIO_MOVE_ARG(type) type
+# endif // (_MSC_VER >= 1400)
+# else
+# define ASIO_MOVE_ARG(type) type
+# endif
+# define ASIO_MOVE_CAST(type) static_cast<const type&>
+# define ASIO_MOVE_CAST2(type1, type2) static_cast<const type1, type2&>
+#endif // !defined(ASIO_MOVE_CAST)
+
+// Support variadic templates on compilers known to allow it.
+#if !defined(ASIO_HAS_VARIADIC_TEMPLATES)
+# if !defined(ASIO_DISABLE_VARIADIC_TEMPLATES)
+# if defined(__clang__)
+# if __has_feature(__cxx_variadic_templates__)
+# define ASIO_HAS_VARIADIC_TEMPLATES 1
+# endif // __has_feature(__cxx_variadic_templates__)
+# endif // defined(__clang__)
+# if defined(__GNUC__)
+# if ((__GNUC__ == 4) && (__GNUC_MINOR__ >= 3)) || (__GNUC__ > 4)
+# if defined(__GXX_EXPERIMENTAL_CXX0X__)
+# define ASIO_HAS_VARIADIC_TEMPLATES 1
+# endif // defined(__GXX_EXPERIMENTAL_CXX0X__)
+# endif // ((__GNUC__ == 4) && (__GNUC_MINOR__ >= 3)) || (__GNUC__ > 4)
+# endif // defined(__GNUC__)
+# if defined(ASIO_MSVC)
+# if (_MSC_VER >= 1900)
+# define ASIO_HAS_VARIADIC_TEMPLATES 1
+# endif // (_MSC_VER >= 1900)
+# endif // defined(ASIO_MSVC)
+# endif // !defined(ASIO_DISABLE_VARIADIC_TEMPLATES)
+#endif // !defined(ASIO_HAS_VARIADIC_TEMPLATES)
+
+// Support deleted functions on compilers known to allow it.
+#if !defined(ASIO_DELETED)
+# if defined(__GNUC__)
+# if ((__GNUC__ == 4) && (__GNUC_MINOR__ >= 7)) || (__GNUC__ > 4)
+# if defined(__GXX_EXPERIMENTAL_CXX0X__)
+# define ASIO_DELETED = delete
+# endif // defined(__GXX_EXPERIMENTAL_CXX0X__)
+# endif // ((__GNUC__ == 4) && (__GNUC_MINOR__ >= 7)) || (__GNUC__ > 4)
+# endif // defined(__GNUC__)
+# if defined(__clang__)
+# if __has_feature(__cxx_deleted_functions__)
+# define ASIO_DELETED = delete
+# endif // __has_feature(__cxx_deleted_functions__)
+# endif // defined(__clang__)
+# if defined(ASIO_MSVC)
+# if (_MSC_VER >= 1900)
+# define ASIO_DELETED = delete
+# endif // (_MSC_VER >= 1900)
+# endif // defined(ASIO_MSVC)
+# if !defined(ASIO_DELETED)
+# define ASIO_DELETED
+# endif // !defined(ASIO_DELETED)
+#endif // !defined(ASIO_DELETED)
+
+// Support constexpr on compilers known to allow it.
+#if !defined(ASIO_HAS_CONSTEXPR)
+# if !defined(ASIO_DISABLE_CONSTEXPR)
+# if defined(__clang__)
+# if __has_feature(__cxx_constexpr__)
+# define ASIO_HAS_CONSTEXPR 1
+# endif // __has_feature(__cxx_constexr__)
+# endif // defined(__clang__)
+# if defined(__GNUC__)
+# if ((__GNUC__ == 4) && (__GNUC_MINOR__ >= 6)) || (__GNUC__ > 4)
+# if defined(__GXX_EXPERIMENTAL_CXX0X__)
+# define ASIO_HAS_CONSTEXPR 1
+# endif // defined(__GXX_EXPERIMENTAL_CXX0X__)
+# endif // ((__GNUC__ == 4) && (__GNUC_MINOR__ >= 6)) || (__GNUC__ > 4)
+# endif // defined(__GNUC__)
+# if defined(ASIO_MSVC)
+# if (_MSC_VER >= 1900)
+# define ASIO_HAS_CONSTEXPR 1
+# endif // (_MSC_VER >= 1900)
+# endif // defined(ASIO_MSVC)
+# endif // !defined(ASIO_DISABLE_CONSTEXPR)
+#endif // !defined(ASIO_HAS_CONSTEXPR)
+#if !defined(ASIO_CONSTEXPR)
+# if defined(ASIO_HAS_CONSTEXPR)
+# define ASIO_CONSTEXPR constexpr
+# else // defined(ASIO_HAS_CONSTEXPR)
+# define ASIO_CONSTEXPR
+# endif // defined(ASIO_HAS_CONSTEXPR)
+#endif // !defined(ASIO_CONSTEXPR)
+
+// Support noexcept on compilers known to allow it.
+#if !defined(ASIO_NOEXCEPT)
+# if !defined(ASIO_DISABLE_NOEXCEPT)
+# if (BOOST_VERSION >= 105300)
+# define ASIO_NOEXCEPT BOOST_NOEXCEPT
+# define ASIO_NOEXCEPT_OR_NOTHROW BOOST_NOEXCEPT_OR_NOTHROW
+# elif defined(__clang__)
+# if __has_feature(__cxx_noexcept__)
+# define ASIO_NOEXCEPT noexcept(true)
+# define ASIO_NOEXCEPT_OR_NOTHROW noexcept(true)
+# endif // __has_feature(__cxx_noexcept__)
+# elif defined(__GNUC__)
+# if ((__GNUC__ == 4) && (__GNUC_MINOR__ >= 7)) || (__GNUC__ > 4)
+# if defined(__GXX_EXPERIMENTAL_CXX0X__)
+# define ASIO_NOEXCEPT noexcept(true)
+# define ASIO_NOEXCEPT_OR_NOTHROW noexcept(true)
+# endif // defined(__GXX_EXPERIMENTAL_CXX0X__)
+# endif // ((__GNUC__ == 4) && (__GNUC_MINOR__ >= 7)) || (__GNUC__ > 4)
+# elif defined(ASIO_MSVC)
+# if (_MSC_VER >= 1900)
+# define ASIO_NOEXCEPT noexcept(true)
+# define ASIO_NOEXCEPT_OR_NOTHROW noexcept(true)
+# endif // (_MSC_VER >= 1900)
+# endif // defined(ASIO_MSVC)
+# endif // !defined(ASIO_DISABLE_NOEXCEPT)
+# if !defined(ASIO_NOEXCEPT)
+# define ASIO_NOEXCEPT
+# endif // !defined(ASIO_NOEXCEPT)
+# if !defined(ASIO_NOEXCEPT_OR_NOTHROW)
+# define ASIO_NOEXCEPT_OR_NOTHROW throw()
+# endif // !defined(ASIO_NOEXCEPT_OR_NOTHROW)
+#endif // !defined(ASIO_NOEXCEPT)
+
+// Support automatic type deduction on compilers known to support it.
+#if !defined(ASIO_HAS_DECLTYPE)
+# if !defined(ASIO_DISABLE_DECLTYPE)
+# if defined(__clang__)
+# if __has_feature(__cxx_decltype__)
+# define ASIO_HAS_DECLTYPE 1
+# endif // __has_feature(__cxx_decltype__)
+# endif // defined(__clang__)
+# if defined(__GNUC__)
+# if ((__GNUC__ == 4) && (__GNUC_MINOR__ >= 6)) || (__GNUC__ > 4)
+# if defined(__GXX_EXPERIMENTAL_CXX0X__)
+# define ASIO_HAS_DECLTYPE 1
+# endif // defined(__GXX_EXPERIMENTAL_CXX0X__)
+# endif // ((__GNUC__ == 4) && (__GNUC_MINOR__ >= 6)) || (__GNUC__ > 4)
+# endif // defined(__GNUC__)
+# if defined(ASIO_MSVC)
+# if (_MSC_VER >= 1700)
+# define ASIO_HAS_DECLTYPE 1
+# endif // (_MSC_VER >= 1700)
+# endif // defined(ASIO_MSVC)
+# endif // !defined(ASIO_DISABLE_DECLTYPE)
+#endif // !defined(ASIO_HAS_DECLTYPE)
+
+// Support alias templates on compilers known to allow it.
+#if !defined(ASIO_HAS_ALIAS_TEMPLATES)
+# if !defined(ASIO_DISABLE_ALIAS_TEMPLATES)
+# if defined(__clang__)
+# if __has_feature(__cxx_alias_templates__)
+# define ASIO_HAS_ALIAS_TEMPLATES 1
+# endif // __has_feature(__cxx_alias_templates__)
+# endif // defined(__clang__)
+# if defined(__GNUC__)
+# if ((__GNUC__ == 4) && (__GNUC_MINOR__ >= 7)) || (__GNUC__ > 4)
+# if defined(__GXX_EXPERIMENTAL_CXX0X__)
+# define ASIO_HAS_ALIAS_TEMPLATES 1
+# endif // defined(__GXX_EXPERIMENTAL_CXX0X__)
+# endif // ((__GNUC__ == 4) && (__GNUC_MINOR__ >= 7)) || (__GNUC__ > 4)
+# endif // defined(__GNUC__)
+# if defined(ASIO_MSVC)
+# if (_MSC_VER >= 1900)
+# define ASIO_HAS_ALIAS_TEMPLATES 1
+# endif // (_MSC_VER >= 1900)
+# endif // defined(ASIO_MSVC)
+# endif // !defined(ASIO_DISABLE_ALIAS_TEMPLATES)
+#endif // !defined(ASIO_HAS_ALIAS_TEMPLATES)
+
+// Standard library support for system errors.
+#if !defined(ASIO_HAS_STD_SYSTEM_ERROR)
+# if !defined(ASIO_DISABLE_STD_SYSTEM_ERROR)
+# if defined(__clang__)
+# if defined(ASIO_HAS_CLANG_LIBCXX)
+# define ASIO_HAS_STD_SYSTEM_ERROR 1
+# elif (__cplusplus >= 201103)
+# if __has_include(<system_error>)
+# define ASIO_HAS_STD_SYSTEM_ERROR 1
+# endif // __has_include(<system_error>)
+# endif // (__cplusplus >= 201103)
+# endif // defined(__clang__)
+# if defined(__GNUC__)
+# if ((__GNUC__ == 4) && (__GNUC_MINOR__ >= 6)) || (__GNUC__ > 4)
+# if defined(__GXX_EXPERIMENTAL_CXX0X__)
+# define ASIO_HAS_STD_SYSTEM_ERROR 1
+# endif // defined(__GXX_EXPERIMENTAL_CXX0X__)
+# endif // ((__GNUC__ == 4) && (__GNUC_MINOR__ >= 6)) || (__GNUC__ > 4)
+# endif // defined(__GNUC__)
+# if defined(ASIO_MSVC)
+# if (_MSC_VER >= 1700)
+# define ASIO_HAS_STD_SYSTEM_ERROR 1
+# endif // (_MSC_VER >= 1700)
+# endif // defined(ASIO_MSVC)
+# endif // !defined(ASIO_DISABLE_STD_SYSTEM_ERROR)
+#endif // !defined(ASIO_HAS_STD_SYSTEM_ERROR)
+
+// Compliant C++11 compilers put noexcept specifiers on error_category members.
+#if !defined(ASIO_ERROR_CATEGORY_NOEXCEPT)
+# if (BOOST_VERSION >= 105300)
+# define ASIO_ERROR_CATEGORY_NOEXCEPT BOOST_NOEXCEPT
+# elif defined(__clang__)
+# if __has_feature(__cxx_noexcept__)
+# define ASIO_ERROR_CATEGORY_NOEXCEPT noexcept(true)
+# endif // __has_feature(__cxx_noexcept__)
+# elif defined(__GNUC__)
+# if ((__GNUC__ == 4) && (__GNUC_MINOR__ >= 7)) || (__GNUC__ > 4)
+# if defined(__GXX_EXPERIMENTAL_CXX0X__)
+# define ASIO_ERROR_CATEGORY_NOEXCEPT noexcept(true)
+# endif // defined(__GXX_EXPERIMENTAL_CXX0X__)
+# endif // ((__GNUC__ == 4) && (__GNUC_MINOR__ >= 7)) || (__GNUC__ > 4)
+# elif defined(ASIO_MSVC)
+# if (_MSC_VER >= 1900)
+# define ASIO_ERROR_CATEGORY_NOEXCEPT noexcept(true)
+# endif // (_MSC_VER >= 1900)
+# endif // defined(ASIO_MSVC)
+# if !defined(ASIO_ERROR_CATEGORY_NOEXCEPT)
+# define ASIO_ERROR_CATEGORY_NOEXCEPT
+# endif // !defined(ASIO_ERROR_CATEGORY_NOEXCEPT)
+#endif // !defined(ASIO_ERROR_CATEGORY_NOEXCEPT)
+
+// Standard library support for arrays.
+#if !defined(ASIO_HAS_STD_ARRAY)
+# if !defined(ASIO_DISABLE_STD_ARRAY)
+# if defined(__clang__)
+# if defined(ASIO_HAS_CLANG_LIBCXX)
+# define ASIO_HAS_STD_ARRAY 1
+# elif (__cplusplus >= 201103)
+# if __has_include(<array>)
+# define ASIO_HAS_STD_ARRAY 1
+# endif // __has_include(<array>)
+# endif // (__cplusplus >= 201103)
+# endif // defined(__clang__)
+# if defined(__GNUC__)
+# if ((__GNUC__ == 4) && (__GNUC_MINOR__ >= 3)) || (__GNUC__ > 4)
+# if defined(__GXX_EXPERIMENTAL_CXX0X__)
+# define ASIO_HAS_STD_ARRAY 1
+# endif // defined(__GXX_EXPERIMENTAL_CXX0X__)
+# endif // ((__GNUC__ == 4) && (__GNUC_MINOR__ >= 3)) || (__GNUC__ > 4)
+# endif // defined(__GNUC__)
+# if defined(ASIO_MSVC)
+# if (_MSC_VER >= 1600)
+# define ASIO_HAS_STD_ARRAY 1
+# endif // (_MSC_VER >= 1600)
+# endif // defined(ASIO_MSVC)
+# endif // !defined(ASIO_DISABLE_STD_ARRAY)
+#endif // !defined(ASIO_HAS_STD_ARRAY)
+
+// Standard library support for shared_ptr and weak_ptr.
+#if !defined(ASIO_HAS_STD_SHARED_PTR)
+# if !defined(ASIO_DISABLE_STD_SHARED_PTR)
+# if defined(__clang__)
+# if defined(ASIO_HAS_CLANG_LIBCXX)
+# define ASIO_HAS_STD_SHARED_PTR 1
+# elif (__cplusplus >= 201103)
+# define ASIO_HAS_STD_SHARED_PTR 1
+# endif // (__cplusplus >= 201103)
+# endif // defined(__clang__)
+# if defined(__GNUC__)
+# if ((__GNUC__ == 4) && (__GNUC_MINOR__ >= 3)) || (__GNUC__ > 4)
+# if defined(__GXX_EXPERIMENTAL_CXX0X__)
+# define ASIO_HAS_STD_SHARED_PTR 1
+# endif // defined(__GXX_EXPERIMENTAL_CXX0X__)
+# endif // ((__GNUC__ == 4) && (__GNUC_MINOR__ >= 3)) || (__GNUC__ > 4)
+# endif // defined(__GNUC__)
+# if defined(ASIO_MSVC)
+# if (_MSC_VER >= 1600)
+# define ASIO_HAS_STD_SHARED_PTR 1
+# endif // (_MSC_VER >= 1600)
+# endif // defined(ASIO_MSVC)
+# endif // !defined(ASIO_DISABLE_STD_SHARED_PTR)
+#endif // !defined(ASIO_HAS_STD_SHARED_PTR)
+
+// Standard library support for allocator_arg_t.
+#if !defined(ASIO_HAS_STD_ALLOCATOR_ARG)
+# if !defined(ASIO_DISABLE_STD_ALLOCATOR_ARG)
+# if defined(__clang__)
+# if defined(ASIO_HAS_CLANG_LIBCXX)
+# define ASIO_HAS_STD_ALLOCATOR_ARG 1
+# elif (__cplusplus >= 201103)
+# define ASIO_HAS_STD_ALLOCATOR_ARG 1
+# endif // (__cplusplus >= 201103)
+# endif // defined(__clang__)
+# if defined(__GNUC__)
+# if ((__GNUC__ == 4) && (__GNUC_MINOR__ >= 6)) || (__GNUC__ > 4)
+# if defined(__GXX_EXPERIMENTAL_CXX0X__)
+# define ASIO_HAS_STD_ALLOCATOR_ARG 1
+# endif // defined(__GXX_EXPERIMENTAL_CXX0X__)
+# endif // ((__GNUC__ == 4) && (__GNUC_MINOR__ >= 6)) || (__GNUC__ > 4)
+# endif // defined(__GNUC__)
+# if defined(ASIO_MSVC)
+# if (_MSC_VER >= 1600)
+# define ASIO_HAS_STD_ALLOCATOR_ARG 1
+# endif // (_MSC_VER >= 1600)
+# endif // defined(ASIO_MSVC)
+# endif // !defined(ASIO_DISABLE_STD_ALLOCATOR_ARG)
+#endif // !defined(ASIO_HAS_STD_ALLOCATOR_ARG)
+
+// Standard library support for atomic operations.
+#if !defined(ASIO_HAS_STD_ATOMIC)
+# if !defined(ASIO_DISABLE_STD_ATOMIC)
+# if defined(__clang__)
+# if defined(ASIO_HAS_CLANG_LIBCXX)
+# define ASIO_HAS_STD_ATOMIC 1
+# elif (__cplusplus >= 201103)
+# if __has_include(<atomic>)
+# define ASIO_HAS_STD_ATOMIC 1
+# endif // __has_include(<atomic>)
+# endif // (__cplusplus >= 201103)
+# endif // defined(__clang__)
+# if defined(__GNUC__)
+# if ((__GNUC__ == 4) && (__GNUC_MINOR__ >= 7)) || (__GNUC__ > 4)
+# if defined(__GXX_EXPERIMENTAL_CXX0X__)
+# define ASIO_HAS_STD_ATOMIC 1
+# endif // defined(__GXX_EXPERIMENTAL_CXX0X__)
+# endif // ((__GNUC__ == 4) && (__GNUC_MINOR__ >= 7)) || (__GNUC__ > 4)
+# endif // defined(__GNUC__)
+# if defined(ASIO_MSVC)
+# if (_MSC_VER >= 1700)
+# define ASIO_HAS_STD_ATOMIC 1
+# endif // (_MSC_VER >= 1700)
+# endif // defined(ASIO_MSVC)
+# endif // !defined(ASIO_DISABLE_STD_ATOMIC)
+#endif // !defined(ASIO_HAS_STD_ATOMIC)
+
+// Standard library support for chrono. Some standard libraries (such as the
+// libstdc++ shipped with gcc 4.6) provide monotonic_clock as per early C++0x
+// drafts, rather than the eventually standardised name of steady_clock.
+#if !defined(ASIO_HAS_STD_CHRONO)
+# if !defined(ASIO_DISABLE_STD_CHRONO)
+# if defined(__clang__)
+# if defined(ASIO_HAS_CLANG_LIBCXX)
+# define ASIO_HAS_STD_CHRONO 1
+# elif (__cplusplus >= 201103)
+# if __has_include(<chrono>)
+# define ASIO_HAS_STD_CHRONO 1
+# endif // __has_include(<chrono>)
+# endif // (__cplusplus >= 201103)
+# endif // defined(__clang__)
+# if defined(__GNUC__)
+# if ((__GNUC__ == 4) && (__GNUC_MINOR__ >= 6)) || (__GNUC__ > 4)
+# if defined(__GXX_EXPERIMENTAL_CXX0X__)
+# define ASIO_HAS_STD_CHRONO 1
+# if ((__GNUC__ == 4) && (__GNUC_MINOR__ == 6))
+# define ASIO_HAS_STD_CHRONO_MONOTONIC_CLOCK 1
+# endif // ((__GNUC__ == 4) && (__GNUC_MINOR__ == 6))
+# endif // defined(__GXX_EXPERIMENTAL_CXX0X__)
+# endif // ((__GNUC__ == 4) && (__GNUC_MINOR__ >= 6)) || (__GNUC__ > 4)
+# endif // defined(__GNUC__)
+# if defined(ASIO_MSVC)
+# if (_MSC_VER >= 1700)
+# define ASIO_HAS_STD_CHRONO 1
+# endif // (_MSC_VER >= 1700)
+# endif // defined(ASIO_MSVC)
+# endif // !defined(ASIO_DISABLE_STD_CHRONO)
+#endif // !defined(ASIO_HAS_STD_CHRONO)
+
+// Boost support for chrono.
+#if !defined(ASIO_HAS_BOOST_CHRONO)
+# if !defined(ASIO_DISABLE_BOOST_CHRONO)
+# if (BOOST_VERSION >= 104700)
+# define ASIO_HAS_BOOST_CHRONO 1
+# endif // (BOOST_VERSION >= 104700)
+# endif // !defined(ASIO_DISABLE_BOOST_CHRONO)
+#endif // !defined(ASIO_HAS_BOOST_CHRONO)
+
+// Some form of chrono library is available.
+#if !defined(ASIO_HAS_CHRONO)
+# if defined(ASIO_HAS_STD_CHRONO) \
+ || defined(ASIO_HAS_BOOST_CHRONO)
+# define ASIO_HAS_CHRONO 1
+# endif // defined(ASIO_HAS_STD_CHRONO)
+ // || defined(ASIO_HAS_BOOST_CHRONO)
+#endif // !defined(ASIO_HAS_CHRONO)
+
+// Boost support for the DateTime library.
+#if !defined(ASIO_HAS_BOOST_DATE_TIME)
+# if !defined(ASIO_DISABLE_BOOST_DATE_TIME)
+# define ASIO_HAS_BOOST_DATE_TIME 1
+# endif // !defined(ASIO_DISABLE_BOOST_DATE_TIME)
+#endif // !defined(ASIO_HAS_BOOST_DATE_TIME)
+
+// Standard library support for addressof.
+#if !defined(ASIO_HAS_STD_ADDRESSOF)
+# if !defined(ASIO_DISABLE_STD_ADDRESSOF)
+# if defined(__clang__)
+# if defined(ASIO_HAS_CLANG_LIBCXX)
+# define ASIO_HAS_STD_ADDRESSOF 1
+# elif (__cplusplus >= 201103)
+# define ASIO_HAS_STD_ADDRESSOF 1
+# endif // (__cplusplus >= 201103)
+# endif // defined(__clang__)
+# if defined(__GNUC__)
+# if ((__GNUC__ == 4) && (__GNUC_MINOR__ >= 6)) || (__GNUC__ > 4)
+# if defined(__GXX_EXPERIMENTAL_CXX0X__)
+# define ASIO_HAS_STD_ADDRESSOF 1
+# endif // defined(__GXX_EXPERIMENTAL_CXX0X__)
+# endif // ((__GNUC__ == 4) && (__GNUC_MINOR__ >= 6)) || (__GNUC__ > 4)
+# endif // defined(__GNUC__)
+# if defined(ASIO_MSVC)
+# if (_MSC_VER >= 1700)
+# define ASIO_HAS_STD_ADDRESSOF 1
+# endif // (_MSC_VER >= 1700)
+# endif // defined(ASIO_MSVC)
+# endif // !defined(ASIO_DISABLE_STD_ADDRESSOF)
+#endif // !defined(ASIO_HAS_STD_ADDRESSOF)
+
+// Standard library support for the function class.
+#if !defined(ASIO_HAS_STD_FUNCTION)
+# if !defined(ASIO_DISABLE_STD_FUNCTION)
+# if defined(__clang__)
+# if defined(ASIO_HAS_CLANG_LIBCXX)
+# define ASIO_HAS_STD_FUNCTION 1
+# elif (__cplusplus >= 201103)
+# define ASIO_HAS_STD_FUNCTION 1
+# endif // (__cplusplus >= 201103)
+# endif // defined(__clang__)
+# if defined(__GNUC__)
+# if ((__GNUC__ == 4) && (__GNUC_MINOR__ >= 5)) || (__GNUC__ > 4)
+# if defined(__GXX_EXPERIMENTAL_CXX0X__)
+# define ASIO_HAS_STD_FUNCTION 1
+# endif // defined(__GXX_EXPERIMENTAL_CXX0X__)
+# endif // ((__GNUC__ == 4) && (__GNUC_MINOR__ >= 5)) || (__GNUC__ > 4)
+# endif // defined(__GNUC__)
+# if defined(ASIO_MSVC)
+# if (_MSC_VER >= 1700)
+# define ASIO_HAS_STD_FUNCTION 1
+# endif // (_MSC_VER >= 1700)
+# endif // defined(ASIO_MSVC)
+# endif // !defined(ASIO_DISABLE_STD_FUNCTION)
+#endif // !defined(ASIO_HAS_STD_FUNCTION)
+
+// Standard library support for type traits.
+#if !defined(ASIO_HAS_STD_TYPE_TRAITS)
+# if !defined(ASIO_DISABLE_STD_TYPE_TRAITS)
+# if defined(__clang__)
+# if defined(ASIO_HAS_CLANG_LIBCXX)
+# define ASIO_HAS_STD_TYPE_TRAITS 1
+# elif (__cplusplus >= 201103)
+# if __has_include(<type_traits>)
+# define ASIO_HAS_STD_TYPE_TRAITS 1
+# endif // __has_include(<type_traits>)
+# endif // (__cplusplus >= 201103)
+# endif // defined(__clang__)
+# if defined(__GNUC__)
+# if ((__GNUC__ == 4) && (__GNUC_MINOR__ >= 5)) || (__GNUC__ > 4)
+# if defined(__GXX_EXPERIMENTAL_CXX0X__)
+# define ASIO_HAS_STD_TYPE_TRAITS 1
+# endif // defined(__GXX_EXPERIMENTAL_CXX0X__)
+# endif // ((__GNUC__ == 4) && (__GNUC_MINOR__ >= 5)) || (__GNUC__ > 4)
+# endif // defined(__GNUC__)
+# if defined(ASIO_MSVC)
+# if (_MSC_VER >= 1700)
+# define ASIO_HAS_STD_TYPE_TRAITS 1
+# endif // (_MSC_VER >= 1700)
+# endif // defined(ASIO_MSVC)
+# endif // !defined(ASIO_DISABLE_STD_TYPE_TRAITS)
+#endif // !defined(ASIO_HAS_STD_TYPE_TRAITS)
+
+// Standard library support for the nullptr_t type.
+#if !defined(ASIO_HAS_NULLPTR)
+# if !defined(ASIO_DISABLE_NULLPTR)
+# if defined(__clang__)
+# if __has_feature(__cxx_nullptr__)
+# define ASIO_HAS_NULLPTR 1
+# endif // __has_feature(__cxx_rvalue_references__)
+# elif defined(__GNUC__)
+# if ((__GNUC__ == 4) && (__GNUC_MINOR__ >= 6)) || (__GNUC__ > 4)
+# if defined(__GXX_EXPERIMENTAL_CXX0X__)
+# define ASIO_HAS_NULLPTR 1
+# endif // defined(__GXX_EXPERIMENTAL_CXX0X__)
+# endif // ((__GNUC__ == 4) && (__GNUC_MINOR__ >= 6)) || (__GNUC__ > 4)
+# endif // defined(__GNUC__)
+# if defined(ASIO_MSVC)
+# if (_MSC_VER >= 1700)
+# define ASIO_HAS_NULLPTR 1
+# endif // (_MSC_VER >= 1700)
+# endif // defined(ASIO_MSVC)
+# endif // !defined(ASIO_DISABLE_NULLPTR)
+#endif // !defined(ASIO_HAS_NULLPTR)
+
+// Standard library support for the C++11 allocator additions.
+#if !defined(ASIO_HAS_CXX11_ALLOCATORS)
+# if !defined(ASIO_DISABLE_CXX11_ALLOCATORS)
+# if defined(__clang__)
+# if defined(ASIO_HAS_CLANG_LIBCXX)
+# define ASIO_HAS_CXX11_ALLOCATORS 1
+# elif (__cplusplus >= 201103)
+# define ASIO_HAS_CXX11_ALLOCATORS 1
+# endif // (__cplusplus >= 201103)
+# elif defined(__GNUC__)
+# if ((__GNUC__ == 4) && (__GNUC_MINOR__ >= 7)) || (__GNUC__ > 4)
+# if defined(__GXX_EXPERIMENTAL_CXX0X__)
+# define ASIO_HAS_CXX11_ALLOCATORS 1
+# endif // defined(__GXX_EXPERIMENTAL_CXX0X__)
+# endif // ((__GNUC__ == 4) && (__GNUC_MINOR__ >= 7)) || (__GNUC__ > 4)
+# endif // defined(__GNUC__)
+# if defined(ASIO_MSVC)
+# if (_MSC_VER >= 1800)
+# define ASIO_HAS_CXX11_ALLOCATORS 1
+# endif // (_MSC_VER >= 1800)
+# endif // defined(ASIO_MSVC)
+# endif // !defined(ASIO_DISABLE_CXX11_ALLOCATORS)
+#endif // !defined(ASIO_HAS_CXX11_ALLOCATORS)
+
+// Standard library support for the cstdint header.
+#if !defined(ASIO_HAS_CSTDINT)
+# if !defined(ASIO_DISABLE_CSTDINT)
+# if defined(__clang__)
+# if defined(ASIO_HAS_CLANG_LIBCXX)
+# define ASIO_HAS_CSTDINT 1
+# elif (__cplusplus >= 201103)
+# define ASIO_HAS_CSTDINT 1
+# endif // (__cplusplus >= 201103)
+# endif // defined(__clang__)
+# if defined(__GNUC__)
+# if ((__GNUC__ == 4) && (__GNUC_MINOR__ >= 5)) || (__GNUC__ > 4)
+# if defined(__GXX_EXPERIMENTAL_CXX0X__)
+# define ASIO_HAS_CSTDINT 1
+# endif // defined(__GXX_EXPERIMENTAL_CXX0X__)
+# endif // ((__GNUC__ == 4) && (__GNUC_MINOR__ >= 5)) || (__GNUC__ > 4)
+# endif // defined(__GNUC__)
+# if defined(ASIO_MSVC)
+# if (_MSC_VER >= 1700)
+# define ASIO_HAS_CSTDINT 1
+# endif // (_MSC_VER >= 1700)
+# endif // defined(ASIO_MSVC)
+# endif // !defined(ASIO_DISABLE_CSTDINT)
+#endif // !defined(ASIO_HAS_CSTDINT)
+
+// Standard library support for the thread class.
+#if !defined(ASIO_HAS_STD_THREAD)
+# if !defined(ASIO_DISABLE_STD_THREAD)
+# if defined(__clang__)
+# if defined(ASIO_HAS_CLANG_LIBCXX)
+# define ASIO_HAS_STD_THREAD 1
+# elif (__cplusplus >= 201103)
+# if __has_include(<thread>)
+# define ASIO_HAS_STD_THREAD 1
+# endif // __has_include(<thread>)
+# endif // (__cplusplus >= 201103)
+# endif // defined(__clang__)
+# if defined(__GNUC__)
+# if ((__GNUC__ == 4) && (__GNUC_MINOR__ >= 7)) || (__GNUC__ > 4)
+# if defined(__GXX_EXPERIMENTAL_CXX0X__)
+# define ASIO_HAS_STD_THREAD 1
+# endif // defined(__GXX_EXPERIMENTAL_CXX0X__)
+# endif // ((__GNUC__ == 4) && (__GNUC_MINOR__ >= 7)) || (__GNUC__ > 4)
+# endif // defined(__GNUC__)
+# if defined(ASIO_MSVC)
+# if (_MSC_VER >= 1700)
+# define ASIO_HAS_STD_THREAD 1
+# endif // (_MSC_VER >= 1700)
+# endif // defined(ASIO_MSVC)
+# endif // !defined(ASIO_DISABLE_STD_THREAD)
+#endif // !defined(ASIO_HAS_STD_THREAD)
+
+// Standard library support for the mutex and condition variable classes.
+#if !defined(ASIO_HAS_STD_MUTEX_AND_CONDVAR)
+# if !defined(ASIO_DISABLE_STD_MUTEX_AND_CONDVAR)
+# if defined(__clang__)
+# if defined(ASIO_HAS_CLANG_LIBCXX)
+# define ASIO_HAS_STD_MUTEX_AND_CONDVAR 1
+# elif (__cplusplus >= 201103)
+# if __has_include(<mutex>)
+# define ASIO_HAS_STD_MUTEX_AND_CONDVAR 1
+# endif // __has_include(<mutex>)
+# endif // (__cplusplus >= 201103)
+# endif // defined(__clang__)
+# if defined(__GNUC__)
+# if ((__GNUC__ == 4) && (__GNUC_MINOR__ >= 7)) || (__GNUC__ > 4)
+# if defined(__GXX_EXPERIMENTAL_CXX0X__)
+# define ASIO_HAS_STD_MUTEX_AND_CONDVAR 1
+# endif // defined(__GXX_EXPERIMENTAL_CXX0X__)
+# endif // ((__GNUC__ == 4) && (__GNUC_MINOR__ >= 7)) || (__GNUC__ > 4)
+# endif // defined(__GNUC__)
+# if defined(ASIO_MSVC)
+# if (_MSC_VER >= 1700)
+# define ASIO_HAS_STD_MUTEX_AND_CONDVAR 1
+# endif // (_MSC_VER >= 1700)
+# endif // defined(ASIO_MSVC)
+# endif // !defined(ASIO_DISABLE_STD_MUTEX_AND_CONDVAR)
+#endif // !defined(ASIO_HAS_STD_MUTEX_AND_CONDVAR)
+
+// Standard library support for the call_once function.
+#if !defined(ASIO_HAS_STD_CALL_ONCE)
+# if !defined(ASIO_DISABLE_STD_CALL_ONCE)
+# if defined(__clang__)
+# if defined(ASIO_HAS_CLANG_LIBCXX)
+# define ASIO_HAS_STD_CALL_ONCE 1
+# elif (__cplusplus >= 201103)
+# if __has_include(<mutex>)
+# define ASIO_HAS_STD_CALL_ONCE 1
+# endif // __has_include(<mutex>)
+# endif // (__cplusplus >= 201103)
+# endif // defined(__clang__)
+# if defined(__GNUC__)
+# if ((__GNUC__ == 4) && (__GNUC_MINOR__ >= 7)) || (__GNUC__ > 4)
+# if defined(__GXX_EXPERIMENTAL_CXX0X__)
+# define ASIO_HAS_STD_CALL_ONCE 1
+# endif // defined(__GXX_EXPERIMENTAL_CXX0X__)
+# endif // ((__GNUC__ == 4) && (__GNUC_MINOR__ >= 7)) || (__GNUC__ > 4)
+# endif // defined(__GNUC__)
+# if defined(ASIO_MSVC)
+# if (_MSC_VER >= 1700)
+# define ASIO_HAS_STD_CALL_ONCE 1
+# endif // (_MSC_VER >= 1700)
+# endif // defined(ASIO_MSVC)
+# endif // !defined(ASIO_DISABLE_STD_CALL_ONCE)
+#endif // !defined(ASIO_HAS_STD_CALL_ONCE)
+
+// Standard library support for futures.
+#if !defined(ASIO_HAS_STD_FUTURE)
+# if !defined(ASIO_DISABLE_STD_FUTURE)
+# if defined(__clang__)
+# if defined(ASIO_HAS_CLANG_LIBCXX)
+# define ASIO_HAS_STD_FUTURE 1
+# elif (__cplusplus >= 201103)
+# if __has_include(<future>)
+# define ASIO_HAS_STD_FUTURE 1
+# endif // __has_include(<mutex>)
+# endif // (__cplusplus >= 201103)
+# endif // defined(__clang__)
+# if defined(__GNUC__)
+# if ((__GNUC__ == 4) && (__GNUC_MINOR__ >= 7)) || (__GNUC__ > 4)
+# if defined(__GXX_EXPERIMENTAL_CXX0X__)
+# if defined(_GLIBCXX_HAS_GTHREADS)
+# define ASIO_HAS_STD_FUTURE 1
+# endif // defined(_GLIBCXX_HAS_GTHREADS)
+# endif // defined(__GXX_EXPERIMENTAL_CXX0X__)
+# endif // ((__GNUC__ == 4) && (__GNUC_MINOR__ >= 7)) || (__GNUC__ > 4)
+# endif // defined(__GNUC__)
+# if defined(ASIO_MSVC)
+# if (_MSC_VER >= 1700)
+# define ASIO_HAS_STD_FUTURE 1
+# endif // (_MSC_VER >= 1700)
+# endif // defined(ASIO_MSVC)
+# endif // !defined(ASIO_DISABLE_STD_FUTURE)
+#endif // !defined(ASIO_HAS_STD_FUTURE)
+
+// Standard library support for std::string_view.
+#if !defined(ASIO_HAS_STD_STRING_VIEW)
+# if !defined(ASIO_DISABLE_STD_STRING_VIEW)
+# if defined(__clang__)
+# if (__cplusplus >= 201703)
+# if __has_include(<string_view>)
+# define ASIO_HAS_STD_STRING_VIEW 1
+# endif // __has_include(<string_view>)
+# endif // (__cplusplus >= 201703)
+# endif // defined(__clang__)
+# if defined(__GNUC__)
+# if (__GNUC__ >= 7)
+# if (__cplusplus >= 201703)
+# define ASIO_HAS_STD_STRING_VIEW 1
+# endif // (__cplusplus >= 201703)
+# endif // (__GNUC__ >= 7)
+# endif // defined(__GNUC__)
+# if defined(ASIO_MSVC)
+# if (_MSC_VER >= 1910 && _HAS_CXX17)
+# define ASIO_HAS_STD_STRING_VIEW
+# endif // (_MSC_VER >= 1910 && _HAS_CXX17)
+# endif // defined(ASIO_MSVC)
+# endif // !defined(ASIO_DISABLE_STD_STRING_VIEW)
+#endif // !defined(ASIO_HAS_STD_STRING_VIEW)
+
+// Standard library support for std::experimental::string_view.
+#if !defined(ASIO_HAS_STD_EXPERIMENTAL_STRING_VIEW)
+# if !defined(ASIO_DISABLE_STD_EXPERIMENTAL_STRING_VIEW)
+# if defined(__clang__)
+# if (__cplusplus >= 201402)
+# if __has_include(<experimental/string_view>)
+# define ASIO_HAS_STD_EXPERIMENTAL_STRING_VIEW 1
+# endif // __has_include(<experimental/string_view>)
+# endif // (__cplusplus >= 201402)
+# endif // defined(__clang__)
+# if defined(__GNUC__)
+# if ((__GNUC__ == 4) && (__GNUC_MINOR__ >= 9)) || (__GNUC__ > 4)
+# if (__cplusplus >= 201402)
+# define ASIO_HAS_STD_EXPERIMENTAL_STRING_VIEW 1
+# endif // (__cplusplus >= 201402)
+# endif // ((__GNUC__ == 4) && (__GNUC_MINOR__ >= 9)) || (__GNUC__ > 4)
+# endif // defined(__GNUC__)
+# endif // !defined(ASIO_DISABLE_STD_EXPERIMENTAL_STRING_VIEW)
+#endif // !defined(ASIO_HAS_STD_EXPERIMENTAL_STRING_VIEW)
+
+// Standard library has a string_view that we can use.
+#if !defined(ASIO_HAS_STRING_VIEW)
+# if !defined(ASIO_DISABLE_STRING_VIEW)
+# if defined(ASIO_HAS_STD_STRING_VIEW)
+# define ASIO_HAS_STRING_VIEW 1
+# elif defined(ASIO_HAS_STD_EXPERIMENTAL_STRING_VIEW)
+# define ASIO_HAS_STRING_VIEW 1
+# endif // defined(ASIO_HAS_STD_EXPERIMENTAL_STRING_VIEW)
+# endif // !defined(ASIO_DISABLE_STRING_VIEW)
+#endif // !defined(ASIO_HAS_STRING_VIEW)
+
+// Standard library support for iostream move construction and assignment.
+#if !defined(ASIO_HAS_STD_IOSTREAM_MOVE)
+# if !defined(ASIO_DISABLE_STD_IOSTREAM_MOVE)
+# if defined(__GNUC__)
+# if (__GNUC__ > 4)
+# if defined(__GXX_EXPERIMENTAL_CXX0X__)
+# define ASIO_HAS_STD_IOSTREAM_MOVE 1
+# endif // defined(__GXX_EXPERIMENTAL_CXX0X__)
+# endif // (__GNUC__ > 4)
+# endif // defined(__GNUC__)
+# if defined(ASIO_MSVC)
+# if (_MSC_VER >= 1700)
+# define ASIO_HAS_STD_IOSTREAM_MOVE 1
+# endif // (_MSC_VER >= 1700)
+# endif // defined(ASIO_MSVC)
+# endif // !defined(ASIO_DISABLE_STD_IOSTREAM_MOVE)
+#endif // !defined(ASIO_HAS_STD_IOSTREAM_MOVE)
+
+// Standard library has invoke_result (which supersedes result_of).
+#if !defined(ASIO_HAS_STD_INVOKE_RESULT)
+# if !defined(ASIO_DISABLE_STD_INVOKE_RESULT)
+# if defined(ASIO_MSVC)
+# if (_MSC_VER >= 1910 && _HAS_CXX17)
+# define ASIO_HAS_STD_INVOKE_RESULT 1
+# endif // (_MSC_VER >= 1910 && _HAS_CXX17)
+# endif // defined(ASIO_MSVC)
+# endif // !defined(ASIO_DISABLE_STD_INVOKE_RESULT)
+#endif // !defined(ASIO_HAS_STD_INVOKE_RESULT)
+
+// Windows App target. Windows but with a limited API.
+#if !defined(ASIO_WINDOWS_APP)
+# if defined(_WIN32_WINNT) && (_WIN32_WINNT >= 0x0603)
+# include <winapifamily.h>
+# if WINAPI_FAMILY_PARTITION(WINAPI_PARTITION_APP) \
+ && !WINAPI_FAMILY_PARTITION(WINAPI_PARTITION_DESKTOP)
+# define ASIO_WINDOWS_APP 1
+# endif // WINAPI_FAMILY_PARTITION(WINAPI_PARTITION_APP)
+ // && !WINAPI_FAMILY_PARTITION(WINAPI_PARTITION_DESKTOP)
+# endif // defined(_WIN32_WINNT) && (_WIN32_WINNT >= 0x0603)
+#endif // !defined(ASIO_WINDOWS_APP)
+
+// Legacy WinRT target. Windows App is preferred.
+#if !defined(ASIO_WINDOWS_RUNTIME)
+# if !defined(ASIO_WINDOWS_APP)
+# if defined(__cplusplus_winrt)
+# include <winapifamily.h>
+# if WINAPI_FAMILY_PARTITION(WINAPI_PARTITION_APP) \
+ && !WINAPI_FAMILY_PARTITION(WINAPI_PARTITION_DESKTOP)
+# define ASIO_WINDOWS_RUNTIME 1
+# endif // WINAPI_FAMILY_PARTITION(WINAPI_PARTITION_APP)
+ // && !WINAPI_FAMILY_PARTITION(WINAPI_PARTITION_DESKTOP)
+# endif // defined(__cplusplus_winrt)
+# endif // !defined(ASIO_WINDOWS_APP)
+#endif // !defined(ASIO_WINDOWS_RUNTIME)
+
+// Windows target. Excludes WinRT but includes Windows App targets.
+#if !defined(ASIO_WINDOWS)
+# if !defined(ASIO_WINDOWS_RUNTIME)
+# if defined(ASIO_HAS_BOOST_CONFIG) && defined(BOOST_WINDOWS)
+# define ASIO_WINDOWS 1
+# elif defined(WIN32) || defined(_WIN32) || defined(__WIN32__)
+# define ASIO_WINDOWS 1
+# elif defined(ASIO_WINDOWS_APP)
+# define ASIO_WINDOWS 1
+# endif // defined(ASIO_HAS_BOOST_CONFIG) && defined(BOOST_WINDOWS)
+# endif // !defined(ASIO_WINDOWS_RUNTIME)
+#endif // !defined(ASIO_WINDOWS)
+
+// Windows: target OS version.
+#if defined(ASIO_WINDOWS) || defined(__CYGWIN__)
+# if !defined(_WIN32_WINNT) && !defined(_WIN32_WINDOWS)
+# if defined(_MSC_VER) || defined(__BORLANDC__)
+# pragma message( \
+ "Please define _WIN32_WINNT or _WIN32_WINDOWS appropriately. For example:\n"\
+ "- add -D_WIN32_WINNT=0x0501 to the compiler command line; or\n"\
+ "- add _WIN32_WINNT=0x0501 to your project's Preprocessor Definitions.\n"\
+ "Assuming _WIN32_WINNT=0x0501 (i.e. Windows XP target).")
+# else // defined(_MSC_VER) || defined(__BORLANDC__)
+# warning Please define _WIN32_WINNT or _WIN32_WINDOWS appropriately.
+# warning For example, add -D_WIN32_WINNT=0x0501 to the compiler command line.
+# warning Assuming _WIN32_WINNT=0x0501 (i.e. Windows XP target).
+# endif // defined(_MSC_VER) || defined(__BORLANDC__)
+# define _WIN32_WINNT 0x0501
+# endif // !defined(_WIN32_WINNT) && !defined(_WIN32_WINDOWS)
+# if defined(_MSC_VER)
+# if defined(_WIN32) && !defined(WIN32)
+# if !defined(_WINSOCK2API_)
+# define WIN32 // Needed for correct types in winsock2.h
+# else // !defined(_WINSOCK2API_)
+# error Please define the macro WIN32 in your compiler options
+# endif // !defined(_WINSOCK2API_)
+# endif // defined(_WIN32) && !defined(WIN32)
+# endif // defined(_MSC_VER)
+# if defined(__BORLANDC__)
+# if defined(__WIN32__) && !defined(WIN32)
+# if !defined(_WINSOCK2API_)
+# define WIN32 // Needed for correct types in winsock2.h
+# else // !defined(_WINSOCK2API_)
+# error Please define the macro WIN32 in your compiler options
+# endif // !defined(_WINSOCK2API_)
+# endif // defined(__WIN32__) && !defined(WIN32)
+# endif // defined(__BORLANDC__)
+# if defined(__CYGWIN__)
+# if !defined(__USE_W32_SOCKETS)
+# error You must add -D__USE_W32_SOCKETS to your compiler options.
+# endif // !defined(__USE_W32_SOCKETS)
+# endif // defined(__CYGWIN__)
+#endif // defined(ASIO_WINDOWS) || defined(__CYGWIN__)
+
+// Windows: minimise header inclusion.
+#if defined(ASIO_WINDOWS) || defined(__CYGWIN__)
+# if !defined(ASIO_NO_WIN32_LEAN_AND_MEAN)
+# if !defined(WIN32_LEAN_AND_MEAN)
+# define WIN32_LEAN_AND_MEAN
+# endif // !defined(WIN32_LEAN_AND_MEAN)
+# endif // !defined(ASIO_NO_WIN32_LEAN_AND_MEAN)
+#endif // defined(ASIO_WINDOWS) || defined(__CYGWIN__)
+
+// Windows: suppress definition of "min" and "max" macros.
+#if defined(ASIO_WINDOWS) || defined(__CYGWIN__)
+# if !defined(ASIO_NO_NOMINMAX)
+# if !defined(NOMINMAX)
+# define NOMINMAX 1
+# endif // !defined(NOMINMAX)
+# endif // !defined(ASIO_NO_NOMINMAX)
+#endif // defined(ASIO_WINDOWS) || defined(__CYGWIN__)
+
+// Windows: IO Completion Ports.
+#if !defined(ASIO_HAS_IOCP)
+# if defined(ASIO_WINDOWS) || defined(__CYGWIN__)
+# if defined(_WIN32_WINNT) && (_WIN32_WINNT >= 0x0400)
+# if !defined(UNDER_CE) && !defined(ASIO_WINDOWS_APP)
+# if !defined(ASIO_DISABLE_IOCP)
+# define ASIO_HAS_IOCP 1
+# endif // !defined(ASIO_DISABLE_IOCP)
+# endif // !defined(UNDER_CE) && !defined(ASIO_WINDOWS_APP)
+# endif // defined(_WIN32_WINNT) && (_WIN32_WINNT >= 0x0400)
+# endif // defined(ASIO_WINDOWS) || defined(__CYGWIN__)
+#endif // !defined(ASIO_HAS_IOCP)
+
+// On POSIX (and POSIX-like) platforms we need to include unistd.h in order to
+// get access to the various platform feature macros, e.g. to be able to test
+// for threads support.
+#if !defined(ASIO_HAS_UNISTD_H)
+# if !defined(ASIO_HAS_BOOST_CONFIG)
+# if defined(unix) \
+ || defined(__unix) \
+ || defined(_XOPEN_SOURCE) \
+ || defined(_POSIX_SOURCE) \
+ || (defined(__MACH__) && defined(__APPLE__)) \
+ || defined(__FreeBSD__) \
+ || defined(__NetBSD__) \
+ || defined(__OpenBSD__) \
+ || defined(__linux__)
+# define ASIO_HAS_UNISTD_H 1
+# endif
+# endif // !defined(ASIO_HAS_BOOST_CONFIG)
+#endif // !defined(ASIO_HAS_UNISTD_H)
+#if defined(ASIO_HAS_UNISTD_H)
+# include <unistd.h>
+#endif // defined(ASIO_HAS_UNISTD_H)
+
+// Linux: epoll, eventfd and timerfd.
+#if defined(__linux__)
+# include <linux/version.h>
+# if !defined(ASIO_HAS_EPOLL)
+# if !defined(ASIO_DISABLE_EPOLL)
+# if LINUX_VERSION_CODE >= KERNEL_VERSION(2,5,45)
+# define ASIO_HAS_EPOLL 1
+# endif // LINUX_VERSION_CODE >= KERNEL_VERSION(2,5,45)
+# endif // !defined(ASIO_DISABLE_EPOLL)
+# endif // !defined(ASIO_HAS_EPOLL)
+# if !defined(ASIO_HAS_EVENTFD)
+# if !defined(ASIO_DISABLE_EVENTFD)
+# if LINUX_VERSION_CODE >= KERNEL_VERSION(2,6,22)
+# define ASIO_HAS_EVENTFD 1
+# endif // LINUX_VERSION_CODE >= KERNEL_VERSION(2,6,22)
+# endif // !defined(ASIO_DISABLE_EVENTFD)
+# endif // !defined(ASIO_HAS_EVENTFD)
+# if !defined(ASIO_HAS_TIMERFD)
+# if defined(ASIO_HAS_EPOLL)
+# if (__GLIBC__ > 2) || (__GLIBC__ == 2 && __GLIBC_MINOR__ >= 8)
+# define ASIO_HAS_TIMERFD 1
+# endif // (__GLIBC__ > 2) || (__GLIBC__ == 2 && __GLIBC_MINOR__ >= 8)
+# endif // defined(ASIO_HAS_EPOLL)
+# endif // !defined(ASIO_HAS_TIMERFD)
+#endif // defined(__linux__)
+
+// Mac OS X, FreeBSD, NetBSD, OpenBSD: kqueue.
+#if (defined(__MACH__) && defined(__APPLE__)) \
+ || defined(__FreeBSD__) \
+ || defined(__NetBSD__) \
+ || defined(__OpenBSD__)
+# if !defined(ASIO_HAS_KQUEUE)
+# if !defined(ASIO_DISABLE_KQUEUE)
+# define ASIO_HAS_KQUEUE 1
+# endif // !defined(ASIO_DISABLE_KQUEUE)
+# endif // !defined(ASIO_HAS_KQUEUE)
+#endif // (defined(__MACH__) && defined(__APPLE__))
+ // || defined(__FreeBSD__)
+ // || defined(__NetBSD__)
+ // || defined(__OpenBSD__)
+
+// Solaris: /dev/poll.
+#if defined(__sun)
+# if !defined(ASIO_HAS_DEV_POLL)
+# if !defined(ASIO_DISABLE_DEV_POLL)
+# define ASIO_HAS_DEV_POLL 1
+# endif // !defined(ASIO_DISABLE_DEV_POLL)
+# endif // !defined(ASIO_HAS_DEV_POLL)
+#endif // defined(__sun)
+
+// Serial ports.
+#if !defined(ASIO_HAS_SERIAL_PORT)
+# if defined(ASIO_HAS_IOCP) \
+ || !defined(ASIO_WINDOWS) \
+ && !defined(ASIO_WINDOWS_RUNTIME) \
+ && !defined(__CYGWIN__)
+# if !defined(__SYMBIAN32__)
+# if !defined(ASIO_DISABLE_SERIAL_PORT)
+# define ASIO_HAS_SERIAL_PORT 1
+# endif // !defined(ASIO_DISABLE_SERIAL_PORT)
+# endif // !defined(__SYMBIAN32__)
+# endif // defined(ASIO_HAS_IOCP)
+ // || !defined(ASIO_WINDOWS)
+ // && !defined(ASIO_WINDOWS_RUNTIME)
+ // && !defined(__CYGWIN__)
+#endif // !defined(ASIO_HAS_SERIAL_PORT)
+
+// Windows: stream handles.
+#if !defined(ASIO_HAS_WINDOWS_STREAM_HANDLE)
+# if !defined(ASIO_DISABLE_WINDOWS_STREAM_HANDLE)
+# if defined(ASIO_HAS_IOCP)
+# define ASIO_HAS_WINDOWS_STREAM_HANDLE 1
+# endif // defined(ASIO_HAS_IOCP)
+# endif // !defined(ASIO_DISABLE_WINDOWS_STREAM_HANDLE)
+#endif // !defined(ASIO_HAS_WINDOWS_STREAM_HANDLE)
+
+// Windows: random access handles.
+#if !defined(ASIO_HAS_WINDOWS_RANDOM_ACCESS_HANDLE)
+# if !defined(ASIO_DISABLE_WINDOWS_RANDOM_ACCESS_HANDLE)
+# if defined(ASIO_HAS_IOCP)
+# define ASIO_HAS_WINDOWS_RANDOM_ACCESS_HANDLE 1
+# endif // defined(ASIO_HAS_IOCP)
+# endif // !defined(ASIO_DISABLE_WINDOWS_RANDOM_ACCESS_HANDLE)
+#endif // !defined(ASIO_HAS_WINDOWS_RANDOM_ACCESS_HANDLE)
+
+// Windows: object handles.
+#if !defined(ASIO_HAS_WINDOWS_OBJECT_HANDLE)
+# if !defined(ASIO_DISABLE_WINDOWS_OBJECT_HANDLE)
+# if defined(ASIO_WINDOWS) || defined(__CYGWIN__)
+# if !defined(UNDER_CE) && !defined(ASIO_WINDOWS_APP)
+# define ASIO_HAS_WINDOWS_OBJECT_HANDLE 1
+# endif // !defined(UNDER_CE) && !defined(ASIO_WINDOWS_APP)
+# endif // defined(ASIO_WINDOWS) || defined(__CYGWIN__)
+# endif // !defined(ASIO_DISABLE_WINDOWS_OBJECT_HANDLE)
+#endif // !defined(ASIO_HAS_WINDOWS_OBJECT_HANDLE)
+
+// Windows: OVERLAPPED wrapper.
+#if !defined(ASIO_HAS_WINDOWS_OVERLAPPED_PTR)
+# if !defined(ASIO_DISABLE_WINDOWS_OVERLAPPED_PTR)
+# if defined(ASIO_HAS_IOCP)
+# define ASIO_HAS_WINDOWS_OVERLAPPED_PTR 1
+# endif // defined(ASIO_HAS_IOCP)
+# endif // !defined(ASIO_DISABLE_WINDOWS_OVERLAPPED_PTR)
+#endif // !defined(ASIO_HAS_WINDOWS_OVERLAPPED_PTR)
+
+// POSIX: stream-oriented file descriptors.
+#if !defined(ASIO_HAS_POSIX_STREAM_DESCRIPTOR)
+# if !defined(ASIO_DISABLE_POSIX_STREAM_DESCRIPTOR)
+# if !defined(ASIO_WINDOWS) \
+ && !defined(ASIO_WINDOWS_RUNTIME) \
+ && !defined(__CYGWIN__)
+# define ASIO_HAS_POSIX_STREAM_DESCRIPTOR 1
+# endif // !defined(ASIO_WINDOWS)
+ // && !defined(ASIO_WINDOWS_RUNTIME)
+ // && !defined(__CYGWIN__)
+# endif // !defined(ASIO_DISABLE_POSIX_STREAM_DESCRIPTOR)
+#endif // !defined(ASIO_HAS_POSIX_STREAM_DESCRIPTOR)
+
+// UNIX domain sockets.
+#if !defined(ASIO_HAS_LOCAL_SOCKETS)
+# if !defined(ASIO_DISABLE_LOCAL_SOCKETS)
+# if !defined(ASIO_WINDOWS) \
+ && !defined(ASIO_WINDOWS_RUNTIME) \
+ && !defined(__CYGWIN__)
+# define ASIO_HAS_LOCAL_SOCKETS 1
+# endif // !defined(ASIO_WINDOWS)
+ // && !defined(ASIO_WINDOWS_RUNTIME)
+ // && !defined(__CYGWIN__)
+# endif // !defined(ASIO_DISABLE_LOCAL_SOCKETS)
+#endif // !defined(ASIO_HAS_LOCAL_SOCKETS)
+
+// Can use sigaction() instead of signal().
+#if !defined(ASIO_HAS_SIGACTION)
+# if !defined(ASIO_DISABLE_SIGACTION)
+# if !defined(ASIO_WINDOWS) \
+ && !defined(ASIO_WINDOWS_RUNTIME) \
+ && !defined(__CYGWIN__)
+# define ASIO_HAS_SIGACTION 1
+# endif // !defined(ASIO_WINDOWS)
+ // && !defined(ASIO_WINDOWS_RUNTIME)
+ // && !defined(__CYGWIN__)
+# endif // !defined(ASIO_DISABLE_SIGACTION)
+#endif // !defined(ASIO_HAS_SIGACTION)
+
+// Can use signal().
+#if !defined(ASIO_HAS_SIGNAL)
+# if !defined(ASIO_DISABLE_SIGNAL)
+# if !defined(UNDER_CE)
+# define ASIO_HAS_SIGNAL 1
+# endif // !defined(UNDER_CE)
+# endif // !defined(ASIO_DISABLE_SIGNAL)
+#endif // !defined(ASIO_HAS_SIGNAL)
+
+// Can use getaddrinfo() and getnameinfo().
+#if !defined(ASIO_HAS_GETADDRINFO)
+# if !defined(ASIO_DISABLE_GETADDRINFO)
+# if defined(ASIO_WINDOWS) || defined(__CYGWIN__)
+# if defined(_WIN32_WINNT) && (_WIN32_WINNT >= 0x0501)
+# define ASIO_HAS_GETADDRINFO 1
+# elif defined(UNDER_CE)
+# define ASIO_HAS_GETADDRINFO 1
+# endif // defined(UNDER_CE)
+# elif defined(__MACH__) && defined(__APPLE__)
+# if defined(__MAC_OS_X_VERSION_MIN_REQUIRED)
+# if (__MAC_OS_X_VERSION_MIN_REQUIRED >= 1050)
+# define ASIO_HAS_GETADDRINFO 1
+# endif // (__MAC_OS_X_VERSION_MIN_REQUIRED >= 1050)
+# else // defined(__MAC_OS_X_VERSION_MIN_REQUIRED)
+# define ASIO_HAS_GETADDRINFO 1
+# endif // defined(__MAC_OS_X_VERSION_MIN_REQUIRED)
+# else // defined(__MACH__) && defined(__APPLE__)
+# define ASIO_HAS_GETADDRINFO 1
+# endif // defined(__MACH__) && defined(__APPLE__)
+# endif // !defined(ASIO_DISABLE_GETADDRINFO)
+#endif // !defined(ASIO_HAS_GETADDRINFO)
+
+// Whether standard iostreams are disabled.
+#if !defined(ASIO_NO_IOSTREAM)
+# if defined(ASIO_HAS_BOOST_CONFIG) && defined(BOOST_NO_IOSTREAM)
+# define ASIO_NO_IOSTREAM 1
+# endif // !defined(BOOST_NO_IOSTREAM)
+#endif // !defined(ASIO_NO_IOSTREAM)
+
+// Whether exception handling is disabled.
+#if !defined(ASIO_NO_EXCEPTIONS)
+# if defined(ASIO_HAS_BOOST_CONFIG) && defined(BOOST_NO_EXCEPTIONS)
+# define ASIO_NO_EXCEPTIONS 1
+# endif // !defined(BOOST_NO_EXCEPTIONS)
+#endif // !defined(ASIO_NO_EXCEPTIONS)
+
+// Whether the typeid operator is supported.
+#if !defined(ASIO_NO_TYPEID)
+# if defined(ASIO_HAS_BOOST_CONFIG) && defined(BOOST_NO_TYPEID)
+# define ASIO_NO_TYPEID 1
+# endif // !defined(BOOST_NO_TYPEID)
+#endif // !defined(ASIO_NO_TYPEID)
+
+// Threads.
+#if !defined(ASIO_HAS_THREADS)
+# if !defined(ASIO_DISABLE_THREADS)
+# if defined(ASIO_HAS_BOOST_CONFIG) && defined(BOOST_HAS_THREADS)
+# define ASIO_HAS_THREADS 1
+# elif defined(__GNUC__) && !defined(__MINGW32__) \
+ && !defined(linux) && !defined(__linux) && !defined(__linux__)
+# define ASIO_HAS_THREADS 1
+# elif defined(_MT) || defined(__MT__)
+# define ASIO_HAS_THREADS 1
+# elif defined(_REENTRANT)
+# define ASIO_HAS_THREADS 1
+# elif defined(__APPLE__)
+# define ASIO_HAS_THREADS 1
+# elif defined(_POSIX_THREADS) && (_POSIX_THREADS + 0 >= 0)
+# define ASIO_HAS_THREADS 1
+# elif defined(_PTHREADS)
+# define ASIO_HAS_THREADS 1
+# endif // defined(ASIO_HAS_BOOST_CONFIG) && defined(BOOST_HAS_THREADS)
+# endif // !defined(ASIO_DISABLE_THREADS)
+#endif // !defined(ASIO_HAS_THREADS)
+
+// POSIX threads.
+#if !defined(ASIO_HAS_PTHREADS)
+# if defined(ASIO_HAS_THREADS)
+# if defined(ASIO_HAS_BOOST_CONFIG) && defined(BOOST_HAS_PTHREADS)
+# define ASIO_HAS_PTHREADS 1
+# elif defined(_POSIX_THREADS) && (_POSIX_THREADS + 0 >= 0)
+# define ASIO_HAS_PTHREADS 1
+# endif // defined(ASIO_HAS_BOOST_CONFIG) && defined(BOOST_HAS_PTHREADS)
+# endif // defined(ASIO_HAS_THREADS)
+#endif // !defined(ASIO_HAS_PTHREADS)
+
+// Helper to prevent macro expansion.
+#define ASIO_PREVENT_MACRO_SUBSTITUTION
+
+// Helper to define in-class constants.
+#if !defined(ASIO_STATIC_CONSTANT)
+# if !defined(ASIO_DISABLE_BOOST_STATIC_CONSTANT)
+# define ASIO_STATIC_CONSTANT(type, assignment) \
+ BOOST_STATIC_CONSTANT(type, assignment)
+# else // !defined(ASIO_DISABLE_BOOST_STATIC_CONSTANT)
+# define ASIO_STATIC_CONSTANT(type, assignment) \
+ static const type assignment
+# endif // !defined(ASIO_DISABLE_BOOST_STATIC_CONSTANT)
+#endif // !defined(ASIO_STATIC_CONSTANT)
+
+// Boost array library.
+#if !defined(ASIO_HAS_BOOST_ARRAY)
+# if !defined(ASIO_DISABLE_BOOST_ARRAY)
+# define ASIO_HAS_BOOST_ARRAY 1
+# endif // !defined(ASIO_DISABLE_BOOST_ARRAY)
+#endif // !defined(ASIO_HAS_BOOST_ARRAY)
+
+// Boost assert macro.
+#if !defined(ASIO_HAS_BOOST_ASSERT)
+# if !defined(ASIO_DISABLE_BOOST_ASSERT)
+# define ASIO_HAS_BOOST_ASSERT 1
+# endif // !defined(ASIO_DISABLE_BOOST_ASSERT)
+#endif // !defined(ASIO_HAS_BOOST_ASSERT)
+
+// Boost limits header.
+#if !defined(ASIO_HAS_BOOST_LIMITS)
+# if !defined(ASIO_DISABLE_BOOST_LIMITS)
+# define ASIO_HAS_BOOST_LIMITS 1
+# endif // !defined(ASIO_DISABLE_BOOST_LIMITS)
+#endif // !defined(ASIO_HAS_BOOST_LIMITS)
+
+// Boost throw_exception function.
+#if !defined(ASIO_HAS_BOOST_THROW_EXCEPTION)
+# if !defined(ASIO_DISABLE_BOOST_THROW_EXCEPTION)
+# define ASIO_HAS_BOOST_THROW_EXCEPTION 1
+# endif // !defined(ASIO_DISABLE_BOOST_THROW_EXCEPTION)
+#endif // !defined(ASIO_HAS_BOOST_THROW_EXCEPTION)
+
+// Boost regex library.
+#if !defined(ASIO_HAS_BOOST_REGEX)
+# if !defined(ASIO_DISABLE_BOOST_REGEX)
+# define ASIO_HAS_BOOST_REGEX 1
+# endif // !defined(ASIO_DISABLE_BOOST_REGEX)
+#endif // !defined(ASIO_HAS_BOOST_REGEX)
+
+// Boost bind function.
+#if !defined(ASIO_HAS_BOOST_BIND)
+# if !defined(ASIO_DISABLE_BOOST_BIND)
+# define ASIO_HAS_BOOST_BIND 1
+# endif // !defined(ASIO_DISABLE_BOOST_BIND)
+#endif // !defined(ASIO_HAS_BOOST_BIND)
+
+// Boost's BOOST_WORKAROUND macro.
+#if !defined(ASIO_HAS_BOOST_WORKAROUND)
+# if !defined(ASIO_DISABLE_BOOST_WORKAROUND)
+# define ASIO_HAS_BOOST_WORKAROUND 1
+# endif // !defined(ASIO_DISABLE_BOOST_WORKAROUND)
+#endif // !defined(ASIO_HAS_BOOST_WORKAROUND)
+
+// Microsoft Visual C++'s secure C runtime library.
+#if !defined(ASIO_HAS_SECURE_RTL)
+# if !defined(ASIO_DISABLE_SECURE_RTL)
+# if defined(ASIO_MSVC) \
+ && (ASIO_MSVC >= 1400) \
+ && !defined(UNDER_CE)
+# define ASIO_HAS_SECURE_RTL 1
+# endif // defined(ASIO_MSVC)
+ // && (ASIO_MSVC >= 1400)
+ // && !defined(UNDER_CE)
+# endif // !defined(ASIO_DISABLE_SECURE_RTL)
+#endif // !defined(ASIO_HAS_SECURE_RTL)
+
+// Handler hooking. Disabled for ancient Borland C++ and gcc compilers.
+#if !defined(ASIO_HAS_HANDLER_HOOKS)
+# if !defined(ASIO_DISABLE_HANDLER_HOOKS)
+# if defined(__GNUC__)
+# if (__GNUC__ >= 3)
+# define ASIO_HAS_HANDLER_HOOKS 1
+# endif // (__GNUC__ >= 3)
+# elif !defined(__BORLANDC__)
+# define ASIO_HAS_HANDLER_HOOKS 1
+# endif // !defined(__BORLANDC__)
+# endif // !defined(ASIO_DISABLE_HANDLER_HOOKS)
+#endif // !defined(ASIO_HAS_HANDLER_HOOKS)
+
+// Support for the __thread keyword extension.
+#if !defined(ASIO_DISABLE_THREAD_KEYWORD_EXTENSION)
+# if defined(__linux__)
+# if defined(__GNUC__) && (defined(__i386__) || defined(__x86_64__))
+# if ((__GNUC__ == 3) && (__GNUC_MINOR__ >= 3)) || (__GNUC__ > 3)
+# if !defined(__INTEL_COMPILER) && !defined(__ICL) \
+ && !(defined(__clang__) && defined(__ANDROID__))
+# define ASIO_HAS_THREAD_KEYWORD_EXTENSION 1
+# define ASIO_THREAD_KEYWORD __thread
+# elif defined(__INTEL_COMPILER) && (__INTEL_COMPILER >= 1100)
+# define ASIO_HAS_THREAD_KEYWORD_EXTENSION 1
+# endif // defined(__INTEL_COMPILER) && (__INTEL_COMPILER >= 1100)
+ // && !(defined(__clang__) && defined(__ANDROID__))
+# endif // ((__GNUC__ == 3) && (__GNUC_MINOR__ >= 3)) || (__GNUC__ > 3)
+# endif // defined(__GNUC__) && (defined(__i386__) || defined(__x86_64__))
+# endif // defined(__linux__)
+# if defined(ASIO_MSVC) && defined(ASIO_WINDOWS_RUNTIME)
+# if (_MSC_VER >= 1700)
+# define ASIO_HAS_THREAD_KEYWORD_EXTENSION 1
+# define ASIO_THREAD_KEYWORD __declspec(thread)
+# endif // (_MSC_VER >= 1700)
+# endif // defined(ASIO_MSVC) && defined(ASIO_WINDOWS_RUNTIME)
+#endif // !defined(ASIO_DISABLE_THREAD_KEYWORD_EXTENSION)
+#if !defined(ASIO_THREAD_KEYWORD)
+# define ASIO_THREAD_KEYWORD __thread
+#endif // !defined(ASIO_THREAD_KEYWORD)
+
+// Support for POSIX ssize_t typedef.
+#if !defined(ASIO_DISABLE_SSIZE_T)
+# if defined(__linux__) \
+ || (defined(__MACH__) && defined(__APPLE__))
+# define ASIO_HAS_SSIZE_T 1
+# endif // defined(__linux__)
+ // || (defined(__MACH__) && defined(__APPLE__))
+#endif // !defined(ASIO_DISABLE_SSIZE_T)
+
+// Helper macros to manage the transition away from the old services-based API.
+#if defined(ASIO_ENABLE_OLD_SERVICES)
+# define ASIO_SVC_TPARAM , typename Service
+# define ASIO_SVC_TPARAM_DEF1(d1) , typename Service d1
+# define ASIO_SVC_TPARAM_DEF2(d1, d2) , typename Service d1, d2
+# define ASIO_SVC_TARG , Service
+# define ASIO_SVC_T Service
+# define ASIO_SVC_TPARAM1 , typename Service1
+# define ASIO_SVC_TPARAM1_DEF1(d1) , typename Service1 d1
+# define ASIO_SVC_TPARAM1_DEF2(d1, d2) , typename Service1 d1, d2
+# define ASIO_SVC_TARG1 , Service1
+# define ASIO_SVC_T1 Service1
+# define ASIO_SVC_ACCESS public
+#else // defined(ASIO_ENABLE_OLD_SERVICES)
+# define ASIO_SVC_TPARAM
+# define ASIO_SVC_TPARAM_DEF1(d1)
+# define ASIO_SVC_TPARAM_DEF2(d1, d2)
+# define ASIO_SVC_TARG
+// ASIO_SVC_T is defined at each point of use.
+# define ASIO_SVC_TPARAM1
+# define ASIO_SVC_TPARAM1_DEF1(d1)
+# define ASIO_SVC_TPARAM1_DEF2(d1, d2)
+# define ASIO_SVC_TARG1
+// ASIO_SVC_T1 is defined at each point of use.
+# define ASIO_SVC_ACCESS protected
+#endif // defined(ASIO_ENABLE_OLD_SERVICES)
+
+// Helper macros to manage transition away from error_code return values.
+#if defined(ASIO_NO_DEPRECATED)
+# define ASIO_SYNC_OP_VOID void
+# define ASIO_SYNC_OP_VOID_RETURN(e) return
+#else // defined(ASIO_NO_DEPRECATED)
+# define ASIO_SYNC_OP_VOID asio::error_code
+# define ASIO_SYNC_OP_VOID_RETURN(e) return e
+#endif // defined(ASIO_NO_DEPRECATED)
+
+// Newer gcc, clang need special treatment to suppress unused typedef warnings.
+#if defined(__clang__)
+# if defined(__apple_build_version__)
+# if (__clang_major__ >= 7)
+# define ASIO_UNUSED_TYPEDEF __attribute__((__unused__))
+# endif // (__clang_major__ >= 7)
+# elif ((__clang_major__ == 3) && (__clang_minor__ >= 6)) \
+ || (__clang_major__ > 3)
+# define ASIO_UNUSED_TYPEDEF __attribute__((__unused__))
+# endif // ((__clang_major__ == 3) && (__clang_minor__ >= 6))
+ // || (__clang_major__ > 3)
+#elif defined(__GNUC__)
+# if ((__GNUC__ == 4) && (__GNUC_MINOR__ >= 8)) || (__GNUC__ > 4)
+# define ASIO_UNUSED_TYPEDEF __attribute__((__unused__))
+# endif // ((__GNUC__ == 4) && (__GNUC_MINOR__ >= 8)) || (__GNUC__ > 4)
+#endif // defined(__GNUC__)
+#if !defined(ASIO_UNUSED_TYPEDEF)
+# define ASIO_UNUSED_TYPEDEF
+#endif // !defined(ASIO_UNUSED_TYPEDEF)
+
+// Some versions of gcc generate spurious warnings about unused variables.
+#if defined(__GNUC__)
+# if (__GNUC__ >= 4)
+# define ASIO_UNUSED_VARIABLE __attribute__((__unused__))
+# endif // (__GNUC__ >= 4)
+#endif // defined(__GNUC__)
+#if !defined(ASIO_UNUSED_VARIABLE)
+# define ASIO_UNUSED_VARIABLE
+#endif // !defined(ASIO_UNUSED_VARIABLE)
+
+// Support co_await on compilers known to allow it.
+#if !defined(ASIO_HAS_CO_AWAIT)
+# if !defined(ASIO_DISABLE_CO_AWAIT)
+# if defined(ASIO_MSVC)
+# if (_MSC_FULL_VER >= 190023506)
+# if defined(_RESUMABLE_FUNCTIONS_SUPPORTED)
+# define ASIO_HAS_CO_AWAIT 1
+# endif // defined(_RESUMABLE_FUNCTIONS_SUPPORTED)
+# endif // (_MSC_FULL_VER >= 190023506)
+# endif // defined(ASIO_MSVC)
+# endif // !defined(ASIO_DISABLE_CO_AWAIT)
+# if defined(__clang__)
+# if (__cpp_coroutines >= 201703)
+# if __has_include(<experimental/coroutine>)
+# define ASIO_HAS_CO_AWAIT 1
+# endif // __has_include(<experimental/coroutine>)
+# endif // (__cpp_coroutines >= 201703)
+# endif // defined(__clang__)
+#endif // !defined(ASIO_HAS_CO_AWAIT)
+
+#endif // ASIO_DETAIL_CONFIG_HPP
diff --git a/lib/asio/detail/consuming_buffers.hpp b/lib/asio/detail/consuming_buffers.hpp
new file mode 100644
index 0000000..8127ae7
--- /dev/null
+++ b/lib/asio/detail/consuming_buffers.hpp
@@ -0,0 +1,414 @@
+//
+// detail/consuming_buffers.hpp
+// ~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+//
+// Copyright (c) 2003-2018 Christopher M. Kohlhoff (chris at kohlhoff dot com)
+//
+// 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 ASIO_DETAIL_CONSUMING_BUFFERS_HPP
+#define ASIO_DETAIL_CONSUMING_BUFFERS_HPP
+
+#if defined(_MSC_VER) && (_MSC_VER >= 1200)
+# pragma once
+#endif // defined(_MSC_VER) && (_MSC_VER >= 1200)
+
+#include "asio/detail/config.hpp"
+#include <cstddef>
+#include "asio/buffer.hpp"
+#include "asio/detail/buffer_sequence_adapter.hpp"
+#include "asio/detail/limits.hpp"
+
+#include "asio/detail/push_options.hpp"
+
+namespace asio {
+namespace detail {
+
+// Helper template to determine the maximum number of prepared buffers.
+template <typename Buffers>
+struct prepared_buffers_max
+{
+ enum { value = buffer_sequence_adapter_base::max_buffers };
+};
+
+template <typename Elem, std::size_t N>
+struct prepared_buffers_max<boost::array<Elem, N> >
+{
+ enum { value = N };
+};
+
+#if defined(ASIO_HAS_STD_ARRAY)
+
+template <typename Elem, std::size_t N>
+struct prepared_buffers_max<std::array<Elem, N> >
+{
+ enum { value = N };
+};
+
+#endif // defined(ASIO_HAS_STD_ARRAY)
+
+// A buffer sequence used to represent a subsequence of the buffers.
+template <typename Buffer, std::size_t MaxBuffers>
+struct prepared_buffers
+{
+ typedef Buffer value_type;
+ typedef const Buffer* const_iterator;
+
+ enum { max_buffers = MaxBuffers < 16 ? MaxBuffers : 16 };
+
+ prepared_buffers() : count(0) {}
+ const_iterator begin() const { return elems; }
+ const_iterator end() const { return elems + count; }
+
+ Buffer elems[max_buffers];
+ std::size_t count;
+};
+
+// A proxy for a sub-range in a list of buffers.
+template <typename Buffer, typename Buffers, typename Buffer_Iterator>
+class consuming_buffers
+{
+public:
+ typedef prepared_buffers<Buffer, prepared_buffers_max<Buffers>::value>
+ prepared_buffers_type;
+
+ // Construct to represent the entire list of buffers.
+ explicit consuming_buffers(const Buffers& buffers)
+ : buffers_(buffers),
+ total_consumed_(0),
+ next_elem_(0),
+ next_elem_offset_(0)
+ {
+ using asio::buffer_size;
+ total_size_ = buffer_size(buffers);
+ }
+
+ // Determine if we are at the end of the buffers.
+ bool empty() const
+ {
+ return total_consumed_ >= total_size_;
+ }
+
+ // Get the buffer for a single transfer, with a size.
+ prepared_buffers_type prepare(std::size_t max_size)
+ {
+ prepared_buffers_type result;
+
+ Buffer_Iterator next = asio::buffer_sequence_begin(buffers_);
+ Buffer_Iterator end = asio::buffer_sequence_end(buffers_);
+
+ std::advance(next, next_elem_);
+ std::size_t elem_offset = next_elem_offset_;
+ while (next != end && max_size > 0 && (result.count) < result.max_buffers)
+ {
+ Buffer next_buf = Buffer(*next) + elem_offset;
+ result.elems[result.count] = asio::buffer(next_buf, max_size);
+ max_size -= result.elems[result.count].size();
+ elem_offset = 0;
+ if (result.elems[result.count].size() > 0)
+ ++result.count;
+ ++next;
+ }
+
+ return result;
+ }
+
+ // Consume the specified number of bytes from the buffers.
+ void consume(std::size_t size)
+ {
+ total_consumed_ += size;
+
+ Buffer_Iterator next = asio::buffer_sequence_begin(buffers_);
+ Buffer_Iterator end = asio::buffer_sequence_end(buffers_);
+
+ std::advance(next, next_elem_);
+ while (next != end && size > 0)
+ {
+ Buffer next_buf = Buffer(*next) + next_elem_offset_;
+ if (size < next_buf.size())
+ {
+ next_elem_offset_ += size;
+ size = 0;
+ }
+ else
+ {
+ size -= next_buf.size();
+ next_elem_offset_ = 0;
+ ++next_elem_;
+ ++next;
+ }
+ }
+ }
+
+ // Get the total number of bytes consumed from the buffers.
+ std::size_t total_consumed() const
+ {
+ return total_consumed_;
+ }
+
+private:
+ Buffers buffers_;
+ std::size_t total_size_;
+ std::size_t total_consumed_;
+ std::size_t next_elem_;
+ std::size_t next_elem_offset_;
+};
+
+// Base class of all consuming_buffers specialisations for single buffers.
+template <typename Buffer>
+class consuming_single_buffer
+{
+public:
+ // Construct to represent the entire list of buffers.
+ template <typename Buffer1>
+ explicit consuming_single_buffer(const Buffer1& buffer)
+ : buffer_(buffer),
+ total_consumed_(0)
+ {
+ }
+
+ // Determine if we are at the end of the buffers.
+ bool empty() const
+ {
+ return total_consumed_ >= buffer_.size();
+ }
+
+ // Get the buffer for a single transfer, with a size.
+ Buffer prepare(std::size_t max_size)
+ {
+ return asio::buffer(buffer_ + total_consumed_, max_size);
+ }
+
+ // Consume the specified number of bytes from the buffers.
+ void consume(std::size_t size)
+ {
+ total_consumed_ += size;
+ }
+
+ // Get the total number of bytes consumed from the buffers.
+ std::size_t total_consumed() const
+ {
+ return total_consumed_;
+ }
+
+private:
+ Buffer buffer_;
+ std::size_t total_consumed_;
+};
+
+template <>
+class consuming_buffers<mutable_buffer, mutable_buffer, const mutable_buffer*>
+ : public consuming_single_buffer<ASIO_MUTABLE_BUFFER>
+{
+public:
+ explicit consuming_buffers(const mutable_buffer& buffer)
+ : consuming_single_buffer<ASIO_MUTABLE_BUFFER>(buffer)
+ {
+ }
+};
+
+template <>
+class consuming_buffers<const_buffer, mutable_buffer, const mutable_buffer*>
+ : public consuming_single_buffer<ASIO_CONST_BUFFER>
+{
+public:
+ explicit consuming_buffers(const mutable_buffer& buffer)
+ : consuming_single_buffer<ASIO_CONST_BUFFER>(buffer)
+ {
+ }
+};
+
+template <>
+class consuming_buffers<const_buffer, const_buffer, const const_buffer*>
+ : public consuming_single_buffer<ASIO_CONST_BUFFER>
+{
+public:
+ explicit consuming_buffers(const const_buffer& buffer)
+ : consuming_single_buffer<ASIO_CONST_BUFFER>(buffer)
+ {
+ }
+};
+
+#if !defined(ASIO_NO_DEPRECATED)
+
+template <>
+class consuming_buffers<mutable_buffer,
+ mutable_buffers_1, const mutable_buffer*>
+ : public consuming_single_buffer<ASIO_MUTABLE_BUFFER>
+{
+public:
+ explicit consuming_buffers(const mutable_buffers_1& buffer)
+ : consuming_single_buffer<ASIO_MUTABLE_BUFFER>(buffer)
+ {
+ }
+};
+
+template <>
+class consuming_buffers<const_buffer, mutable_buffers_1, const mutable_buffer*>
+ : public consuming_single_buffer<ASIO_CONST_BUFFER>
+{
+public:
+ explicit consuming_buffers(const mutable_buffers_1& buffer)
+ : consuming_single_buffer<ASIO_CONST_BUFFER>(buffer)
+ {
+ }
+};
+
+template <>
+class consuming_buffers<const_buffer, const_buffers_1, const const_buffer*>
+ : public consuming_single_buffer<ASIO_CONST_BUFFER>
+{
+public:
+ explicit consuming_buffers(const const_buffers_1& buffer)
+ : consuming_single_buffer<ASIO_CONST_BUFFER>(buffer)
+ {
+ }
+};
+
+#endif // !defined(ASIO_NO_DEPRECATED)
+
+template <typename Buffer, typename Elem>
+class consuming_buffers<Buffer, boost::array<Elem, 2>,
+ typename boost::array<Elem, 2>::const_iterator>
+{
+public:
+ // Construct to represent the entire list of buffers.
+ explicit consuming_buffers(const boost::array<Elem, 2>& buffers)
+ : buffers_(buffers),
+ total_consumed_(0)
+ {
+ }
+
+ // Determine if we are at the end of the buffers.
+ bool empty() const
+ {
+ return total_consumed_ >=
+ Buffer(buffers_[0]).size() + Buffer(buffers_[1]).size();
+ }
+
+ // Get the buffer for a single transfer, with a size.
+ boost::array<Buffer, 2> prepare(std::size_t max_size)
+ {
+ boost::array<Buffer, 2> result = {{
+ Buffer(buffers_[0]), Buffer(buffers_[1]) }};
+ std::size_t buffer0_size = result[0].size();
+ result[0] = asio::buffer(result[0] + total_consumed_, max_size);
+ result[1] = asio::buffer(
+ result[1] + (total_consumed_ < buffer0_size
+ ? 0 : total_consumed_ - buffer0_size),
+ max_size - result[0].size());
+ return result;
+ }
+
+ // Consume the specified number of bytes from the buffers.
+ void consume(std::size_t size)
+ {
+ total_consumed_ += size;
+ }
+
+ // Get the total number of bytes consumed from the buffers.
+ std::size_t total_consumed() const
+ {
+ return total_consumed_;
+ }
+
+private:
+ boost::array<Elem, 2> buffers_;
+ std::size_t total_consumed_;
+};
+
+#if defined(ASIO_HAS_STD_ARRAY)
+
+template <typename Buffer, typename Elem>
+class consuming_buffers<Buffer, std::array<Elem, 2>,
+ typename std::array<Elem, 2>::const_iterator>
+{
+public:
+ // Construct to represent the entire list of buffers.
+ explicit consuming_buffers(const std::array<Elem, 2>& buffers)
+ : buffers_(buffers),
+ total_consumed_(0)
+ {
+ }
+
+ // Determine if we are at the end of the buffers.
+ bool empty() const
+ {
+ return total_consumed_ >=
+ Buffer(buffers_[0]).size() + Buffer(buffers_[1]).size();
+ }
+
+ // Get the buffer for a single transfer, with a size.
+ std::array<Buffer, 2> prepare(std::size_t max_size)
+ {
+ std::array<Buffer, 2> result = {{
+ Buffer(buffers_[0]), Buffer(buffers_[1]) }};
+ std::size_t buffer0_size = result[0].size();
+ result[0] = asio::buffer(result[0] + total_consumed_, max_size);
+ result[1] = asio::buffer(
+ result[1] + (total_consumed_ < buffer0_size
+ ? 0 : total_consumed_ - buffer0_size),
+ max_size - result[0].size());
+ return result;
+ }
+
+ // Consume the specified number of bytes from the buffers.
+ void consume(std::size_t size)
+ {
+ total_consumed_ += size;
+ }
+
+ // Get the total number of bytes consumed from the buffers.
+ std::size_t total_consumed() const
+ {
+ return total_consumed_;
+ }
+
+private:
+ std::array<Elem, 2> buffers_;
+ std::size_t total_consumed_;
+};
+
+#endif // defined(ASIO_HAS_STD_ARRAY)
+
+// Specialisation for null_buffers to ensure that the null_buffers type is
+// always passed through to the underlying read or write operation.
+template <typename Buffer>
+class consuming_buffers<Buffer, null_buffers, const mutable_buffer*>
+ : public asio::null_buffers
+{
+public:
+ consuming_buffers(const null_buffers&)
+ {
+ // No-op.
+ }
+
+ bool empty()
+ {
+ return false;
+ }
+
+ null_buffers prepare(std::size_t)
+ {
+ return null_buffers();
+ }
+
+ void consume(std::size_t)
+ {
+ // No-op.
+ }
+
+ std::size_t total_consumed() const
+ {
+ return 0;
+ }
+};
+
+} // namespace detail
+} // namespace asio
+
+#include "asio/detail/pop_options.hpp"
+
+#endif // ASIO_DETAIL_CONSUMING_BUFFERS_HPP
diff --git a/lib/asio/detail/cstddef.hpp b/lib/asio/detail/cstddef.hpp
new file mode 100644
index 0000000..3912da4
--- /dev/null
+++ b/lib/asio/detail/cstddef.hpp
@@ -0,0 +1,31 @@
+//
+// detail/cstddef.hpp
+// ~~~~~~~~~~~~~~~~~~
+//
+// Copyright (c) 2003-2018 Christopher M. Kohlhoff (chris at kohlhoff dot com)
+//
+// 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 ASIO_DETAIL_CSTDDEF_HPP
+#define ASIO_DETAIL_CSTDDEF_HPP
+
+#if defined(_MSC_VER) && (_MSC_VER >= 1200)
+# pragma once
+#endif // defined(_MSC_VER) && (_MSC_VER >= 1200)
+
+#include "asio/detail/config.hpp"
+#include <cstddef>
+
+namespace asio {
+
+#if defined(ASIO_HAS_NULLPTR)
+using std::nullptr_t;
+#else // defined(ASIO_HAS_NULLPTR)
+struct nullptr_t {};
+#endif // defined(ASIO_HAS_NULLPTR)
+
+} // namespace asio
+
+#endif // ASIO_DETAIL_CSTDDEF_HPP
diff --git a/lib/asio/detail/cstdint.hpp b/lib/asio/detail/cstdint.hpp
new file mode 100644
index 0000000..62342b2
--- /dev/null
+++ b/lib/asio/detail/cstdint.hpp
@@ -0,0 +1,60 @@
+//
+// detail/cstdint.hpp
+// ~~~~~~~~~~~~~~~~~~
+//
+// Copyright (c) 2003-2018 Christopher M. Kohlhoff (chris at kohlhoff dot com)
+//
+// 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 ASIO_DETAIL_CSTDINT_HPP
+#define ASIO_DETAIL_CSTDINT_HPP
+
+#if defined(_MSC_VER) && (_MSC_VER >= 1200)
+# pragma once
+#endif // defined(_MSC_VER) && (_MSC_VER >= 1200)
+
+#include "asio/detail/config.hpp"
+
+#if defined(ASIO_HAS_CSTDINT)
+# include <cstdint>
+#else // defined(ASIO_HAS_CSTDINT)
+# include <boost/cstdint.hpp>
+#endif // defined(ASIO_HAS_CSTDINT)
+
+namespace asio {
+
+#if defined(ASIO_HAS_CSTDINT)
+using std::int16_t;
+using std::int_least16_t;
+using std::uint16_t;
+using std::uint_least16_t;
+using std::int32_t;
+using std::int_least32_t;
+using std::uint32_t;
+using std::uint_least32_t;
+using std::int64_t;
+using std::int_least64_t;
+using std::uint64_t;
+using std::uint_least64_t;
+using std::uintmax_t;
+#else // defined(ASIO_HAS_CSTDINT)
+using boost::int16_t;
+using boost::int_least16_t;
+using boost::uint16_t;
+using boost::uint_least16_t;
+using boost::int32_t;
+using boost::int_least32_t;
+using boost::uint32_t;
+using boost::uint_least32_t;
+using boost::int64_t;
+using boost::int_least64_t;
+using boost::uint64_t;
+using boost::uint_least64_t;
+using boost::uintmax_t;
+#endif // defined(ASIO_HAS_CSTDINT)
+
+} // namespace asio
+
+#endif // ASIO_DETAIL_CSTDINT_HPP
diff --git a/lib/asio/detail/date_time_fwd.hpp b/lib/asio/detail/date_time_fwd.hpp
new file mode 100644
index 0000000..a159562
--- /dev/null
+++ b/lib/asio/detail/date_time_fwd.hpp
@@ -0,0 +1,34 @@
+//
+// detail/date_time_fwd.hpp
+// ~~~~~~~~~~~~~~~~~~~~~~~~
+//
+// Copyright (c) 2003-2018 Christopher M. Kohlhoff (chris at kohlhoff dot com)
+//
+// 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 ASIO_DETAIL_DATE_TIME_FWD_HPP
+#define ASIO_DETAIL_DATE_TIME_FWD_HPP
+
+#if defined(_MSC_VER) && (_MSC_VER >= 1200)
+# pragma once
+#endif // defined(_MSC_VER) && (_MSC_VER >= 1200)
+
+#include "asio/detail/config.hpp"
+
+namespace boost {
+namespace date_time {
+
+template<class T, class TimeSystem>
+class base_time;
+
+} // namespace date_time
+namespace posix_time {
+
+class ptime;
+
+} // namespace posix_time
+} // namespace boost
+
+#endif // ASIO_DETAIL_DATE_TIME_FWD_HPP
diff --git a/lib/asio/detail/deadline_timer_service.hpp b/lib/asio/detail/deadline_timer_service.hpp
new file mode 100644
index 0000000..f58a6e0
--- /dev/null
+++ b/lib/asio/detail/deadline_timer_service.hpp
@@ -0,0 +1,278 @@
+//
+// detail/deadline_timer_service.hpp
+// ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+//
+// Copyright (c) 2003-2018 Christopher M. Kohlhoff (chris at kohlhoff dot com)
+//
+// 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 ASIO_DETAIL_DEADLINE_TIMER_SERVICE_HPP
+#define ASIO_DETAIL_DEADLINE_TIMER_SERVICE_HPP
+
+#if defined(_MSC_VER) && (_MSC_VER >= 1200)
+# pragma once
+#endif // defined(_MSC_VER) && (_MSC_VER >= 1200)
+
+#include "asio/detail/config.hpp"
+#include <cstddef>
+#include "asio/error.hpp"
+#include "asio/io_context.hpp"
+#include "asio/detail/bind_handler.hpp"
+#include "asio/detail/fenced_block.hpp"
+#include "asio/detail/memory.hpp"
+#include "asio/detail/noncopyable.hpp"
+#include "asio/detail/socket_ops.hpp"
+#include "asio/detail/socket_types.hpp"
+#include "asio/detail/timer_queue.hpp"
+#include "asio/detail/timer_queue_ptime.hpp"
+#include "asio/detail/timer_scheduler.hpp"
+#include "asio/detail/wait_handler.hpp"
+#include "asio/detail/wait_op.hpp"
+
+#if defined(ASIO_WINDOWS_RUNTIME)
+# include <chrono>
+# include <thread>
+#endif // defined(ASIO_WINDOWS_RUNTIME)
+
+#include "asio/detail/push_options.hpp"
+
+namespace asio {
+namespace detail {
+
+template <typename Time_Traits>
+class deadline_timer_service
+ : public service_base<deadline_timer_service<Time_Traits> >
+{
+public:
+ // The time type.
+ typedef typename Time_Traits::time_type time_type;
+
+ // The duration type.
+ typedef typename Time_Traits::duration_type duration_type;
+
+ // The implementation type of the timer. This type is dependent on the
+ // underlying implementation of the timer service.
+ struct implementation_type
+ : private asio::detail::noncopyable
+ {
+ time_type expiry;
+ bool might_have_pending_waits;
+ typename timer_queue<Time_Traits>::per_timer_data timer_data;
+ };
+
+ // Constructor.
+ deadline_timer_service(asio::io_context& io_context)
+ : service_base<deadline_timer_service<Time_Traits> >(io_context),
+ scheduler_(asio::use_service<timer_scheduler>(io_context))
+ {
+ scheduler_.init_task();
+ scheduler_.add_timer_queue(timer_queue_);
+ }
+
+ // Destructor.
+ ~deadline_timer_service()
+ {
+ scheduler_.remove_timer_queue(timer_queue_);
+ }
+
+ // Destroy all user-defined handler objects owned by the service.
+ void shutdown()
+ {
+ }
+
+ // Construct a new timer implementation.
+ void construct(implementation_type& impl)
+ {
+ impl.expiry = time_type();
+ impl.might_have_pending_waits = false;
+ }
+
+ // Destroy a timer implementation.
+ void destroy(implementation_type& impl)
+ {
+ asio::error_code ec;
+ cancel(impl, ec);
+ }
+
+ // Move-construct a new serial port implementation.
+ void move_construct(implementation_type& impl,
+ implementation_type& other_impl)
+ {
+ scheduler_.move_timer(timer_queue_, impl.timer_data, other_impl.timer_data);
+
+ impl.expiry = other_impl.expiry;
+ other_impl.expiry = time_type();
+
+ impl.might_have_pending_waits = other_impl.might_have_pending_waits;
+ other_impl.might_have_pending_waits = false;
+ }
+
+ // Move-assign from another serial port implementation.
+ void move_assign(implementation_type& impl,
+ deadline_timer_service& other_service,
+ implementation_type& other_impl)
+ {
+ if (this != &other_service)
+ if (impl.might_have_pending_waits)
+ scheduler_.cancel_timer(timer_queue_, impl.timer_data);
+
+ other_service.scheduler_.move_timer(other_service.timer_queue_,
+ impl.timer_data, other_impl.timer_data);
+
+ impl.expiry = other_impl.expiry;
+ other_impl.expiry = time_type();
+
+ impl.might_have_pending_waits = other_impl.might_have_pending_waits;
+ other_impl.might_have_pending_waits = false;
+ }
+
+ // Cancel any asynchronous wait operations associated with the timer.
+ std::size_t cancel(implementation_type& impl, asio::error_code& ec)
+ {
+ if (!impl.might_have_pending_waits)
+ {
+ ec = asio::error_code();
+ return 0;
+ }
+
+ ASIO_HANDLER_OPERATION((scheduler_.context(),
+ "deadline_timer", &impl, 0, "cancel"));
+
+ std::size_t count = scheduler_.cancel_timer(timer_queue_, impl.timer_data);
+ impl.might_have_pending_waits = false;
+ ec = asio::error_code();
+ return count;
+ }
+
+ // Cancels one asynchronous wait operation associated with the timer.
+ std::size_t cancel_one(implementation_type& impl,
+ asio::error_code& ec)
+ {
+ if (!impl.might_have_pending_waits)
+ {
+ ec = asio::error_code();
+ return 0;
+ }
+
+ ASIO_HANDLER_OPERATION((scheduler_.context(),
+ "deadline_timer", &impl, 0, "cancel_one"));
+
+ std::size_t count = scheduler_.cancel_timer(
+ timer_queue_, impl.timer_data, 1);
+ if (count == 0)
+ impl.might_have_pending_waits = false;
+ ec = asio::error_code();
+ return count;
+ }
+
+ // Get the expiry time for the timer as an absolute time.
+ time_type expiry(const implementation_type& impl) const
+ {
+ return impl.expiry;
+ }
+
+ // Get the expiry time for the timer as an absolute time.
+ time_type expires_at(const implementation_type& impl) const
+ {
+ return impl.expiry;
+ }
+
+ // Get the expiry time for the timer relative to now.
+ duration_type expires_from_now(const implementation_type& impl) const
+ {
+ return Time_Traits::subtract(this->expiry(impl), Time_Traits::now());
+ }
+
+ // Set the expiry time for the timer as an absolute time.
+ std::size_t expires_at(implementation_type& impl,
+ const time_type& expiry_time, asio::error_code& ec)
+ {
+ std::size_t count = cancel(impl, ec);
+ impl.expiry = expiry_time;
+ ec = asio::error_code();
+ return count;
+ }
+
+ // Set the expiry time for the timer relative to now.
+ std::size_t expires_after(implementation_type& impl,
+ const duration_type& expiry_time, asio::error_code& ec)
+ {
+ return expires_at(impl,
+ Time_Traits::add(Time_Traits::now(), expiry_time), ec);
+ }
+
+ // Set the expiry time for the timer relative to now.
+ std::size_t expires_from_now(implementation_type& impl,
+ const duration_type& expiry_time, asio::error_code& ec)
+ {
+ return expires_at(impl,
+ Time_Traits::add(Time_Traits::now(), expiry_time), ec);
+ }
+
+ // Perform a blocking wait on the timer.
+ void wait(implementation_type& impl, asio::error_code& ec)
+ {
+ time_type now = Time_Traits::now();
+ ec = asio::error_code();
+ while (Time_Traits::less_than(now, impl.expiry) && !ec)
+ {
+ this->do_wait(Time_Traits::to_posix_duration(
+ Time_Traits::subtract(impl.expiry, now)), ec);
+ now = Time_Traits::now();
+ }
+ }
+
+ // Start an asynchronous wait on the timer.
+ template <typename Handler>
+ void async_wait(implementation_type& impl, Handler& handler)
+ {
+ // Allocate and construct an operation to wrap the handler.
+ typedef wait_handler<Handler> op;
+ typename op::ptr p = { asio::detail::addressof(handler),
+ op::ptr::allocate(handler), 0 };
+ p.p = new (p.v) op(handler);
+
+ impl.might_have_pending_waits = true;
+
+ ASIO_HANDLER_CREATION((scheduler_.context(),
+ *p.p, "deadline_timer", &impl, 0, "async_wait"));
+
+ scheduler_.schedule_timer(timer_queue_, impl.expiry, impl.timer_data, p.p);
+ p.v = p.p = 0;
+ }
+
+private:
+ // Helper function to wait given a duration type. The duration type should
+ // either be of type boost::posix_time::time_duration, or implement the
+ // required subset of its interface.
+ template <typename Duration>
+ void do_wait(const Duration& timeout, asio::error_code& ec)
+ {
+#if defined(ASIO_WINDOWS_RUNTIME)
+ std::this_thread::sleep_for(
+ std::chrono::seconds(timeout.total_seconds())
+ + std::chrono::microseconds(timeout.total_microseconds()));
+ ec = asio::error_code();
+#else // defined(ASIO_WINDOWS_RUNTIME)
+ ::timeval tv;
+ tv.tv_sec = timeout.total_seconds();
+ tv.tv_usec = timeout.total_microseconds() % 1000000;
+ socket_ops::select(0, 0, 0, 0, &tv, ec);
+#endif // defined(ASIO_WINDOWS_RUNTIME)
+ }
+
+ // The queue of timers.
+ timer_queue<Time_Traits> timer_queue_;
+
+ // The object that schedules and executes timers. Usually a reactor.
+ timer_scheduler& scheduler_;
+};
+
+} // namespace detail
+} // namespace asio
+
+#include "asio/detail/pop_options.hpp"
+
+#endif // ASIO_DETAIL_DEADLINE_TIMER_SERVICE_HPP
diff --git a/lib/asio/detail/dependent_type.hpp b/lib/asio/detail/dependent_type.hpp
new file mode 100644
index 0000000..85b41c8
--- /dev/null
+++ b/lib/asio/detail/dependent_type.hpp
@@ -0,0 +1,36 @@
+//
+// detail/dependent_type.hpp
+// ~~~~~~~~~~~~~~~~~~~~~~~~~
+//
+// Copyright (c) 2003-2018 Christopher M. Kohlhoff (chris at kohlhoff dot com)
+//
+// 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 ASIO_DETAIL_DEPENDENT_TYPE_HPP
+#define ASIO_DETAIL_DEPENDENT_TYPE_HPP
+
+#if defined(_MSC_VER) && (_MSC_VER >= 1200)
+# pragma once
+#endif // defined(_MSC_VER) && (_MSC_VER >= 1200)
+
+#include "asio/detail/config.hpp"
+
+#include "asio/detail/push_options.hpp"
+
+namespace asio {
+namespace detail {
+
+template <typename DependsOn, typename T>
+struct dependent_type
+{
+ typedef T type;
+};
+
+} // namespace detail
+} // namespace asio
+
+#include "asio/detail/pop_options.hpp"
+
+#endif // ASIO_DETAIL_DEPENDENT_TYPE_HPP
diff --git a/lib/asio/detail/descriptor_ops.hpp b/lib/asio/detail/descriptor_ops.hpp
new file mode 100644
index 0000000..9c0560a
--- /dev/null
+++ b/lib/asio/detail/descriptor_ops.hpp
@@ -0,0 +1,121 @@
+//
+// detail/descriptor_ops.hpp
+// ~~~~~~~~~~~~~~~~~~~~~~~~~
+//
+// Copyright (c) 2003-2018 Christopher M. Kohlhoff (chris at kohlhoff dot com)
+//
+// 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 ASIO_DETAIL_DESCRIPTOR_OPS_HPP
+#define ASIO_DETAIL_DESCRIPTOR_OPS_HPP
+
+#if defined(_MSC_VER) && (_MSC_VER >= 1200)
+# pragma once
+#endif // defined(_MSC_VER) && (_MSC_VER >= 1200)
+
+#include "asio/detail/config.hpp"
+
+#if !defined(ASIO_WINDOWS) \
+ && !defined(ASIO_WINDOWS_RUNTIME) \
+ && !defined(__CYGWIN__)
+
+#include <cstddef>
+#include "asio/error.hpp"
+#include "asio/error_code.hpp"
+#include "asio/detail/socket_types.hpp"
+
+#include "asio/detail/push_options.hpp"
+
+namespace asio {
+namespace detail {
+namespace descriptor_ops {
+
+// Descriptor state bits.
+enum
+{
+ // The user wants a non-blocking descriptor.
+ user_set_non_blocking = 1,
+
+ // The descriptor has been set non-blocking.
+ internal_non_blocking = 2,
+
+ // Helper "state" used to determine whether the descriptor is non-blocking.
+ non_blocking = user_set_non_blocking | internal_non_blocking,
+
+ // The descriptor may have been dup()-ed.
+ possible_dup = 4
+};
+
+typedef unsigned char state_type;
+
+template <typename ReturnType>
+inline ReturnType error_wrapper(ReturnType return_value,
+ asio::error_code& ec)
+{
+ ec = asio::error_code(errno,
+ asio::error::get_system_category());
+ return return_value;
+}
+
+ASIO_DECL int open(const char* path, int flags,
+ asio::error_code& ec);
+
+ASIO_DECL int close(int d, state_type& state,
+ asio::error_code& ec);
+
+ASIO_DECL bool set_user_non_blocking(int d,
+ state_type& state, bool value, asio::error_code& ec);
+
+ASIO_DECL bool set_internal_non_blocking(int d,
+ state_type& state, bool value, asio::error_code& ec);
+
+typedef iovec buf;
+
+ASIO_DECL std::size_t sync_read(int d, state_type state, buf* bufs,
+ std::size_t count, bool all_empty, asio::error_code& ec);
+
+ASIO_DECL bool non_blocking_read(int d, buf* bufs, std::size_t count,
+ asio::error_code& ec, std::size_t& bytes_transferred);
+
+ASIO_DECL std::size_t sync_write(int d, state_type state,
+ const buf* bufs, std::size_t count, bool all_empty,
+ asio::error_code& ec);
+
+ASIO_DECL bool non_blocking_write(int d,
+ const buf* bufs, std::size_t count,
+ asio::error_code& ec, std::size_t& bytes_transferred);
+
+ASIO_DECL int ioctl(int d, state_type& state, long cmd,
+ ioctl_arg_type* arg, asio::error_code& ec);
+
+ASIO_DECL int fcntl(int d, int cmd, asio::error_code& ec);
+
+ASIO_DECL int fcntl(int d, int cmd,
+ long arg, asio::error_code& ec);
+
+ASIO_DECL int poll_read(int d,
+ state_type state, asio::error_code& ec);
+
+ASIO_DECL int poll_write(int d,
+ state_type state, asio::error_code& ec);
+
+ASIO_DECL int poll_error(int d,
+ state_type state, asio::error_code& ec);
+
+} // namespace descriptor_ops
+} // namespace detail
+} // namespace asio
+
+#include "asio/detail/pop_options.hpp"
+
+#if defined(ASIO_HEADER_ONLY)
+# include "asio/detail/impl/descriptor_ops.ipp"
+#endif // defined(ASIO_HEADER_ONLY)
+
+#endif // !defined(ASIO_WINDOWS)
+ // && !defined(ASIO_WINDOWS_RUNTIME)
+ // && !defined(__CYGWIN__)
+
+#endif // ASIO_DETAIL_DESCRIPTOR_OPS_HPP
diff --git a/lib/asio/detail/descriptor_read_op.hpp b/lib/asio/detail/descriptor_read_op.hpp
new file mode 100644
index 0000000..6db4bfb
--- /dev/null
+++ b/lib/asio/detail/descriptor_read_op.hpp
@@ -0,0 +1,128 @@
+//
+// detail/descriptor_read_op.hpp
+// ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+//
+// Copyright (c) 2003-2018 Christopher M. Kohlhoff (chris at kohlhoff dot com)
+//
+// 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 ASIO_DETAIL_DESCRIPTOR_READ_OP_HPP
+#define ASIO_DETAIL_DESCRIPTOR_READ_OP_HPP
+
+#if defined(_MSC_VER) && (_MSC_VER >= 1200)
+# pragma once
+#endif // defined(_MSC_VER) && (_MSC_VER >= 1200)
+
+#include "asio/detail/config.hpp"
+
+#if !defined(ASIO_WINDOWS) && !defined(__CYGWIN__)
+
+#include "asio/detail/bind_handler.hpp"
+#include "asio/detail/buffer_sequence_adapter.hpp"
+#include "asio/detail/descriptor_ops.hpp"
+#include "asio/detail/fenced_block.hpp"
+#include "asio/detail/handler_work.hpp"
+#include "asio/detail/memory.hpp"
+#include "asio/detail/reactor_op.hpp"
+
+#include "asio/detail/push_options.hpp"
+
+namespace asio {
+namespace detail {
+
+template <typename MutableBufferSequence>
+class descriptor_read_op_base : public reactor_op
+{
+public:
+ descriptor_read_op_base(int descriptor,
+ const MutableBufferSequence& buffers, func_type complete_func)
+ : reactor_op(&descriptor_read_op_base::do_perform, complete_func),
+ descriptor_(descriptor),
+ buffers_(buffers)
+ {
+ }
+
+ static status do_perform(reactor_op* base)
+ {
+ descriptor_read_op_base* o(static_cast<descriptor_read_op_base*>(base));
+
+ buffer_sequence_adapter<asio::mutable_buffer,
+ MutableBufferSequence> bufs(o->buffers_);
+
+ status result = descriptor_ops::non_blocking_read(o->descriptor_,
+ bufs.buffers(), bufs.count(), o->ec_, o->bytes_transferred_)
+ ? done : not_done;
+
+ ASIO_HANDLER_REACTOR_OPERATION((*o, "non_blocking_read",
+ o->ec_, o->bytes_transferred_));
+
+ return result;
+ }
+
+private:
+ int descriptor_;
+ MutableBufferSequence buffers_;
+};
+
+template <typename MutableBufferSequence, typename Handler>
+class descriptor_read_op
+ : public descriptor_read_op_base<MutableBufferSequence>
+{
+public:
+ ASIO_DEFINE_HANDLER_PTR(descriptor_read_op);
+
+ descriptor_read_op(int descriptor,
+ const MutableBufferSequence& buffers, Handler& handler)
+ : descriptor_read_op_base<MutableBufferSequence>(
+ descriptor, buffers, &descriptor_read_op::do_complete),
+ handler_(ASIO_MOVE_CAST(Handler)(handler))
+ {
+ handler_work<Handler>::start(handler_);
+ }
+
+ static void do_complete(void* owner, operation* base,
+ const asio::error_code& /*ec*/,
+ std::size_t /*bytes_transferred*/)
+ {
+ // Take ownership of the handler object.
+ descriptor_read_op* o(static_cast<descriptor_read_op*>(base));
+ ptr p = { asio::detail::addressof(o->handler_), o, o };
+ handler_work<Handler> w(o->handler_);
+
+ ASIO_HANDLER_COMPLETION((*o));
+
+ // 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::binder2<Handler, asio::error_code, std::size_t>
+ handler(o->handler_, o->ec_, o->bytes_transferred_);
+ p.h = asio::detail::addressof(handler.handler_);
+ p.reset();
+
+ // Make the upcall if required.
+ if (owner)
+ {
+ fenced_block b(fenced_block::half);
+ ASIO_HANDLER_INVOCATION_BEGIN((handler.arg1_, handler.arg2_));
+ w.complete(handler, handler.handler_);
+ ASIO_HANDLER_INVOCATION_END;
+ }
+ }
+
+private:
+ Handler handler_;
+};
+
+} // namespace detail
+} // namespace asio
+
+#include "asio/detail/pop_options.hpp"
+
+#endif // !defined(ASIO_WINDOWS) && !defined(__CYGWIN__)
+
+#endif // ASIO_DETAIL_DESCRIPTOR_READ_OP_HPP
diff --git a/lib/asio/detail/descriptor_write_op.hpp b/lib/asio/detail/descriptor_write_op.hpp
new file mode 100644
index 0000000..a9ec2a9
--- /dev/null
+++ b/lib/asio/detail/descriptor_write_op.hpp
@@ -0,0 +1,128 @@
+//
+// detail/descriptor_write_op.hpp
+// ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+//
+// Copyright (c) 2003-2018 Christopher M. Kohlhoff (chris at kohlhoff dot com)
+//
+// 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 ASIO_DETAIL_DESCRIPTOR_WRITE_OP_HPP
+#define ASIO_DETAIL_DESCRIPTOR_WRITE_OP_HPP
+
+#if defined(_MSC_VER) && (_MSC_VER >= 1200)
+# pragma once
+#endif // defined(_MSC_VER) && (_MSC_VER >= 1200)
+
+#include "asio/detail/config.hpp"
+
+#if !defined(ASIO_WINDOWS) && !defined(__CYGWIN__)
+
+#include "asio/detail/bind_handler.hpp"
+#include "asio/detail/buffer_sequence_adapter.hpp"
+#include "asio/detail/descriptor_ops.hpp"
+#include "asio/detail/fenced_block.hpp"
+#include "asio/detail/handler_work.hpp"
+#include "asio/detail/memory.hpp"
+#include "asio/detail/reactor_op.hpp"
+
+#include "asio/detail/push_options.hpp"
+
+namespace asio {
+namespace detail {
+
+template <typename ConstBufferSequence>
+class descriptor_write_op_base : public reactor_op
+{
+public:
+ descriptor_write_op_base(int descriptor,
+ const ConstBufferSequence& buffers, func_type complete_func)
+ : reactor_op(&descriptor_write_op_base::do_perform, complete_func),
+ descriptor_(descriptor),
+ buffers_(buffers)
+ {
+ }
+
+ static status do_perform(reactor_op* base)
+ {
+ descriptor_write_op_base* o(static_cast<descriptor_write_op_base*>(base));
+
+ buffer_sequence_adapter<asio::const_buffer,
+ ConstBufferSequence> bufs(o->buffers_);
+
+ status result = descriptor_ops::non_blocking_write(o->descriptor_,
+ bufs.buffers(), bufs.count(), o->ec_, o->bytes_transferred_)
+ ? done : not_done;
+
+ ASIO_HANDLER_REACTOR_OPERATION((*o, "non_blocking_write",
+ o->ec_, o->bytes_transferred_));
+
+ return result;
+ }
+
+private:
+ int descriptor_;
+ ConstBufferSequence buffers_;
+};
+
+template <typename ConstBufferSequence, typename Handler>
+class descriptor_write_op
+ : public descriptor_write_op_base<ConstBufferSequence>
+{
+public:
+ ASIO_DEFINE_HANDLER_PTR(descriptor_write_op);
+
+ descriptor_write_op(int descriptor,
+ const ConstBufferSequence& buffers, Handler& handler)
+ : descriptor_write_op_base<ConstBufferSequence>(
+ descriptor, buffers, &descriptor_write_op::do_complete),
+ handler_(ASIO_MOVE_CAST(Handler)(handler))
+ {
+ handler_work<Handler>::start(handler_);
+ }
+
+ static void do_complete(void* owner, operation* base,
+ const asio::error_code& /*ec*/,
+ std::size_t /*bytes_transferred*/)
+ {
+ // Take ownership of the handler object.
+ descriptor_write_op* o(static_cast<descriptor_write_op*>(base));
+ ptr p = { asio::detail::addressof(o->handler_), o, o };
+ handler_work<Handler> w(o->handler_);
+
+ ASIO_HANDLER_COMPLETION((*o));
+
+ // 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::binder2<Handler, asio::error_code, std::size_t>
+ handler(o->handler_, o->ec_, o->bytes_transferred_);
+ p.h = asio::detail::addressof(handler.handler_);
+ p.reset();
+
+ // Make the upcall if required.
+ if (owner)
+ {
+ fenced_block b(fenced_block::half);
+ ASIO_HANDLER_INVOCATION_BEGIN((handler.arg1_, handler.arg2_));
+ w.complete(handler, handler.handler_);
+ ASIO_HANDLER_INVOCATION_END;
+ }
+ }
+
+private:
+ Handler handler_;
+};
+
+} // namespace detail
+} // namespace asio
+
+#include "asio/detail/pop_options.hpp"
+
+#endif // !defined(ASIO_WINDOWS) && !defined(__CYGWIN__)
+
+#endif // ASIO_DETAIL_DESCRIPTOR_WRITE_OP_HPP
diff --git a/lib/asio/detail/dev_poll_reactor.hpp b/lib/asio/detail/dev_poll_reactor.hpp
new file mode 100644
index 0000000..e9e4e29
--- /dev/null
+++ b/lib/asio/detail/dev_poll_reactor.hpp
@@ -0,0 +1,218 @@
+//
+// detail/dev_poll_reactor.hpp
+// ~~~~~~~~~~~~~~~~~~~~~~~~~~~
+//
+// Copyright (c) 2003-2018 Christopher M. Kohlhoff (chris at kohlhoff dot com)
+//
+// 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 ASIO_DETAIL_DEV_POLL_REACTOR_HPP
+#define ASIO_DETAIL_DEV_POLL_REACTOR_HPP
+
+#if defined(_MSC_VER) && (_MSC_VER >= 1200)
+# pragma once
+#endif // defined(_MSC_VER) && (_MSC_VER >= 1200)
+
+#include "asio/detail/config.hpp"
+
+#if defined(ASIO_HAS_DEV_POLL)
+
+#include <cstddef>
+#include <vector>
+#include <sys/devpoll.h>
+#include "asio/detail/hash_map.hpp"
+#include "asio/detail/limits.hpp"
+#include "asio/detail/mutex.hpp"
+#include "asio/detail/op_queue.hpp"
+#include "asio/detail/reactor_op.hpp"
+#include "asio/detail/reactor_op_queue.hpp"
+#include "asio/detail/select_interrupter.hpp"
+#include "asio/detail/socket_types.hpp"
+#include "asio/detail/timer_queue_base.hpp"
+#include "asio/detail/timer_queue_set.hpp"
+#include "asio/detail/wait_op.hpp"
+#include "asio/execution_context.hpp"
+
+#include "asio/detail/push_options.hpp"
+
+namespace asio {
+namespace detail {
+
+class dev_poll_reactor
+ : public execution_context_service_base<dev_poll_reactor>
+{
+public:
+ enum op_types { read_op = 0, write_op = 1,
+ connect_op = 1, except_op = 2, max_ops = 3 };
+
+ // Per-descriptor data.
+ struct per_descriptor_data
+ {
+ };
+
+ // Constructor.
+ ASIO_DECL dev_poll_reactor(asio::execution_context& ctx);
+
+ // Destructor.
+ ASIO_DECL ~dev_poll_reactor();
+
+ // Destroy all user-defined handler objects owned by the service.
+ ASIO_DECL void shutdown();
+
+ // Recreate internal descriptors following a fork.
+ ASIO_DECL void notify_fork(
+ asio::execution_context::fork_event fork_ev);
+
+ // Initialise the task.
+ ASIO_DECL void init_task();
+
+ // Register a socket with the reactor. Returns 0 on success, system error
+ // code on failure.
+ ASIO_DECL int register_descriptor(socket_type, per_descriptor_data&);
+
+ // Register a descriptor with an associated single operation. Returns 0 on
+ // success, system error code on failure.
+ ASIO_DECL int register_internal_descriptor(
+ int op_type, socket_type descriptor,
+ per_descriptor_data& descriptor_data, reactor_op* op);
+
+ // Move descriptor registration from one descriptor_data object to another.
+ ASIO_DECL void move_descriptor(socket_type descriptor,
+ per_descriptor_data& target_descriptor_data,
+ per_descriptor_data& source_descriptor_data);
+
+ // Post a reactor operation for immediate completion.
+ void post_immediate_completion(reactor_op* op, bool is_continuation)
+ {
+ scheduler_.post_immediate_completion(op, is_continuation);
+ }
+
+ // Start a new operation. The reactor operation will be performed when the
+ // given descriptor is flagged as ready, or an error has occurred.
+ ASIO_DECL void start_op(int op_type, socket_type descriptor,
+ per_descriptor_data&, reactor_op* op,
+ bool is_continuation, bool allow_speculative);
+
+ // Cancel all operations associated with the given descriptor. The
+ // handlers associated with the descriptor will be invoked with the
+ // operation_aborted error.
+ ASIO_DECL void cancel_ops(socket_type descriptor, per_descriptor_data&);
+
+ // Cancel any operations that are running against the descriptor and remove
+ // its registration from the reactor. The reactor resources associated with
+ // the descriptor must be released by calling cleanup_descriptor_data.
+ ASIO_DECL void deregister_descriptor(socket_type descriptor,
+ per_descriptor_data&, bool closing);
+
+ // Remove the descriptor's registration from the reactor. The reactor
+ // resources associated with the descriptor must be released by calling
+ // cleanup_descriptor_data.
+ ASIO_DECL void deregister_internal_descriptor(
+ socket_type descriptor, per_descriptor_data&);
+
+ // Perform any post-deregistration cleanup tasks associated with the
+ // descriptor data.
+ ASIO_DECL void cleanup_descriptor_data(per_descriptor_data&);
+
+ // Add a new timer queue to the reactor.
+ template <typename Time_Traits>
+ void add_timer_queue(timer_queue<Time_Traits>& queue);
+
+ // Remove a timer queue from the reactor.
+ template <typename Time_Traits>
+ void remove_timer_queue(timer_queue<Time_Traits>& queue);
+
+ // Schedule a new operation in the given timer queue to expire at the
+ // specified absolute time.
+ template <typename Time_Traits>
+ void schedule_timer(timer_queue<Time_Traits>& queue,
+ const typename Time_Traits::time_type& time,
+ typename timer_queue<Time_Traits>::per_timer_data& timer, wait_op* op);
+
+ // Cancel the timer operations associated with the given token. Returns the
+ // number of operations that have been posted or dispatched.
+ template <typename Time_Traits>
+ std::size_t cancel_timer(timer_queue<Time_Traits>& queue,
+ typename timer_queue<Time_Traits>::per_timer_data& timer,
+ std::size_t max_cancelled = (std::numeric_limits<std::size_t>::max)());
+
+ // Move the timer operations associated with the given timer.
+ template <typename Time_Traits>
+ void move_timer(timer_queue<Time_Traits>& queue,
+ typename timer_queue<Time_Traits>::per_timer_data& target,
+ typename timer_queue<Time_Traits>::per_timer_data& source);
+
+ // Run /dev/poll once until interrupted or events are ready to be dispatched.
+ ASIO_DECL void run(long usec, op_queue<operation>& ops);
+
+ // Interrupt the select loop.
+ ASIO_DECL void interrupt();
+
+private:
+ // Create the /dev/poll file descriptor. Throws an exception if the descriptor
+ // cannot be created.
+ ASIO_DECL static int do_dev_poll_create();
+
+ // Helper function to add a new timer queue.
+ ASIO_DECL void do_add_timer_queue(timer_queue_base& queue);
+
+ // Helper function to remove a timer queue.
+ ASIO_DECL void do_remove_timer_queue(timer_queue_base& queue);
+
+ // Get the timeout value for the /dev/poll DP_POLL operation. The timeout
+ // value is returned as a number of milliseconds. A return value of -1
+ // indicates that the poll should block indefinitely.
+ ASIO_DECL int get_timeout(int msec);
+
+ // Cancel all operations associated with the given descriptor. The do_cancel
+ // function of the handler objects will be invoked. This function does not
+ // acquire the dev_poll_reactor's mutex.
+ ASIO_DECL void cancel_ops_unlocked(socket_type descriptor,
+ const asio::error_code& ec);
+
+ // Add a pending event entry for the given descriptor.
+ ASIO_DECL ::pollfd& add_pending_event_change(int descriptor);
+
+ // The scheduler implementation used to post completions.
+ scheduler& scheduler_;
+
+ // Mutex to protect access to internal data.
+ asio::detail::mutex mutex_;
+
+ // The /dev/poll file descriptor.
+ int dev_poll_fd_;
+
+ // Vector of /dev/poll events waiting to be written to the descriptor.
+ std::vector< ::pollfd> pending_event_changes_;
+
+ // Hash map to associate a descriptor with a pending event change index.
+ hash_map<int, std::size_t> pending_event_change_index_;
+
+ // The interrupter is used to break a blocking DP_POLL operation.
+ select_interrupter interrupter_;
+
+ // The queues of read, write and except operations.
+ reactor_op_queue<socket_type> op_queue_[max_ops];
+
+ // The timer queues.
+ timer_queue_set timer_queues_;
+
+ // Whether the service has been shut down.
+ bool shutdown_;
+};
+
+} // namespace detail
+} // namespace asio
+
+#include "asio/detail/pop_options.hpp"
+
+#include "asio/detail/impl/dev_poll_reactor.hpp"
+#if defined(ASIO_HEADER_ONLY)
+# include "asio/detail/impl/dev_poll_reactor.ipp"
+#endif // defined(ASIO_HEADER_ONLY)
+
+#endif // defined(ASIO_HAS_DEV_POLL)
+
+#endif // ASIO_DETAIL_DEV_POLL_REACTOR_HPP
diff --git a/lib/asio/detail/epoll_reactor.hpp b/lib/asio/detail/epoll_reactor.hpp
new file mode 100644
index 0000000..5f58109
--- /dev/null
+++ b/lib/asio/detail/epoll_reactor.hpp
@@ -0,0 +1,266 @@
+//
+// detail/epoll_reactor.hpp
+// ~~~~~~~~~~~~~~~~~~~~~~~~
+//
+// Copyright (c) 2003-2018 Christopher M. Kohlhoff (chris at kohlhoff dot com)
+//
+// 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 ASIO_DETAIL_EPOLL_REACTOR_HPP
+#define ASIO_DETAIL_EPOLL_REACTOR_HPP
+
+#if defined(_MSC_VER) && (_MSC_VER >= 1200)
+# pragma once
+#endif // defined(_MSC_VER) && (_MSC_VER >= 1200)
+
+#include "asio/detail/config.hpp"
+
+#if defined(ASIO_HAS_EPOLL)
+
+#include "asio/detail/atomic_count.hpp"
+#include "asio/detail/conditionally_enabled_mutex.hpp"
+#include "asio/detail/limits.hpp"
+#include "asio/detail/object_pool.hpp"
+#include "asio/detail/op_queue.hpp"
+#include "asio/detail/reactor_op.hpp"
+#include "asio/detail/select_interrupter.hpp"
+#include "asio/detail/socket_types.hpp"
+#include "asio/detail/timer_queue_base.hpp"
+#include "asio/detail/timer_queue_set.hpp"
+#include "asio/detail/wait_op.hpp"
+#include "asio/execution_context.hpp"
+
+#if defined(ASIO_HAS_TIMERFD)
+# include <sys/timerfd.h>
+#endif // defined(ASIO_HAS_TIMERFD)
+
+#include "asio/detail/push_options.hpp"
+
+namespace asio {
+namespace detail {
+
+class epoll_reactor
+ : public execution_context_service_base<epoll_reactor>
+{
+private:
+ // The mutex type used by this reactor.
+ typedef conditionally_enabled_mutex mutex;
+
+public:
+ enum op_types { read_op = 0, write_op = 1,
+ connect_op = 1, except_op = 2, max_ops = 3 };
+
+ // Per-descriptor queues.
+ class descriptor_state : operation
+ {
+ friend class epoll_reactor;
+ friend class object_pool_access;
+
+ descriptor_state* next_;
+ descriptor_state* prev_;
+
+ mutex mutex_;
+ epoll_reactor* reactor_;
+ int descriptor_;
+ uint32_t registered_events_;
+ op_queue<reactor_op> op_queue_[max_ops];
+ bool try_speculative_[max_ops];
+ bool shutdown_;
+
+ ASIO_DECL descriptor_state(bool locking);
+ void set_ready_events(uint32_t events) { task_result_ = events; }
+ void add_ready_events(uint32_t events) { task_result_ |= events; }
+ ASIO_DECL operation* perform_io(uint32_t events);
+ ASIO_DECL static void do_complete(
+ void* owner, operation* base,
+ const asio::error_code& ec, std::size_t bytes_transferred);
+ };
+
+ // Per-descriptor data.
+ typedef descriptor_state* per_descriptor_data;
+
+ // Constructor.
+ ASIO_DECL epoll_reactor(asio::execution_context& ctx);
+
+ // Destructor.
+ ASIO_DECL ~epoll_reactor();
+
+ // Destroy all user-defined handler objects owned by the service.
+ ASIO_DECL void shutdown();
+
+ // Recreate internal descriptors following a fork.
+ ASIO_DECL void notify_fork(
+ asio::execution_context::fork_event fork_ev);
+
+ // Initialise the task.
+ ASIO_DECL void init_task();
+
+ // Register a socket with the reactor. Returns 0 on success, system error
+ // code on failure.
+ ASIO_DECL int register_descriptor(socket_type descriptor,
+ per_descriptor_data& descriptor_data);
+
+ // Register a descriptor with an associated single operation. Returns 0 on
+ // success, system error code on failure.
+ ASIO_DECL int register_internal_descriptor(
+ int op_type, socket_type descriptor,
+ per_descriptor_data& descriptor_data, reactor_op* op);
+
+ // Move descriptor registration from one descriptor_data object to another.
+ ASIO_DECL void move_descriptor(socket_type descriptor,
+ per_descriptor_data& target_descriptor_data,
+ per_descriptor_data& source_descriptor_data);
+
+ // Post a reactor operation for immediate completion.
+ void post_immediate_completion(reactor_op* op, bool is_continuation)
+ {
+ scheduler_.post_immediate_completion(op, is_continuation);
+ }
+
+ // Start a new operation. The reactor operation will be performed when the
+ // given descriptor is flagged as ready, or an error has occurred.
+ ASIO_DECL void start_op(int op_type, socket_type descriptor,
+ per_descriptor_data& descriptor_data, reactor_op* op,
+ bool is_continuation, bool allow_speculative);
+
+ // Cancel all operations associated with the given descriptor. The
+ // handlers associated with the descriptor will be invoked with the
+ // operation_aborted error.
+ ASIO_DECL void cancel_ops(socket_type descriptor,
+ per_descriptor_data& descriptor_data);
+
+ // Cancel any operations that are running against the descriptor and remove
+ // its registration from the reactor. The reactor resources associated with
+ // the descriptor must be released by calling cleanup_descriptor_data.
+ ASIO_DECL void deregister_descriptor(socket_type descriptor,
+ per_descriptor_data& descriptor_data, bool closing);
+
+ // Remove the descriptor's registration from the reactor. The reactor
+ // resources associated with the descriptor must be released by calling
+ // cleanup_descriptor_data.
+ ASIO_DECL void deregister_internal_descriptor(
+ socket_type descriptor, per_descriptor_data& descriptor_data);
+
+ // Perform any post-deregistration cleanup tasks associated with the
+ // descriptor data.
+ ASIO_DECL void cleanup_descriptor_data(
+ per_descriptor_data& descriptor_data);
+
+ // Add a new timer queue to the reactor.
+ template <typename Time_Traits>
+ void add_timer_queue(timer_queue<Time_Traits>& timer_queue);
+
+ // Remove a timer queue from the reactor.
+ template <typename Time_Traits>
+ void remove_timer_queue(timer_queue<Time_Traits>& timer_queue);
+
+ // Schedule a new operation in the given timer queue to expire at the
+ // specified absolute time.
+ template <typename Time_Traits>
+ void schedule_timer(timer_queue<Time_Traits>& queue,
+ const typename Time_Traits::time_type& time,
+ typename timer_queue<Time_Traits>::per_timer_data& timer, wait_op* op);
+
+ // Cancel the timer operations associated with the given token. Returns the
+ // number of operations that have been posted or dispatched.
+ template <typename Time_Traits>
+ std::size_t cancel_timer(timer_queue<Time_Traits>& queue,
+ typename timer_queue<Time_Traits>::per_timer_data& timer,
+ std::size_t max_cancelled = (std::numeric_limits<std::size_t>::max)());
+
+ // Move the timer operations associated with the given timer.
+ template <typename Time_Traits>
+ void move_timer(timer_queue<Time_Traits>& queue,
+ typename timer_queue<Time_Traits>::per_timer_data& target,
+ typename timer_queue<Time_Traits>::per_timer_data& source);
+
+ // Run epoll once until interrupted or events are ready to be dispatched.
+ ASIO_DECL void run(long usec, op_queue<operation>& ops);
+
+ // Interrupt the select loop.
+ ASIO_DECL void interrupt();
+
+private:
+ // The hint to pass to epoll_create to size its data structures.
+ enum { epoll_size = 20000 };
+
+ // Create the epoll file descriptor. Throws an exception if the descriptor
+ // cannot be created.
+ ASIO_DECL static int do_epoll_create();
+
+ // Create the timerfd file descriptor. Does not throw.
+ ASIO_DECL static int do_timerfd_create();
+
+ // Allocate a new descriptor state object.
+ ASIO_DECL descriptor_state* allocate_descriptor_state();
+
+ // Free an existing descriptor state object.
+ ASIO_DECL void free_descriptor_state(descriptor_state* s);
+
+ // Helper function to add a new timer queue.
+ ASIO_DECL void do_add_timer_queue(timer_queue_base& queue);
+
+ // Helper function to remove a timer queue.
+ ASIO_DECL void do_remove_timer_queue(timer_queue_base& queue);
+
+ // Called to recalculate and update the timeout.
+ ASIO_DECL void update_timeout();
+
+ // Get the timeout value for the epoll_wait call. The timeout value is
+ // returned as a number of milliseconds. A return value of -1 indicates
+ // that epoll_wait should block indefinitely.
+ ASIO_DECL int get_timeout(int msec);
+
+#if defined(ASIO_HAS_TIMERFD)
+ // Get the timeout value for the timer descriptor. The return value is the
+ // flag argument to be used when calling timerfd_settime.
+ ASIO_DECL int get_timeout(itimerspec& ts);
+#endif // defined(ASIO_HAS_TIMERFD)
+
+ // The scheduler implementation used to post completions.
+ scheduler& scheduler_;
+
+ // Mutex to protect access to internal data.
+ mutex mutex_;
+
+ // The interrupter is used to break a blocking epoll_wait call.
+ select_interrupter interrupter_;
+
+ // The epoll file descriptor.
+ int epoll_fd_;
+
+ // The timer file descriptor.
+ int timer_fd_;
+
+ // The timer queues.
+ timer_queue_set timer_queues_;
+
+ // Whether the service has been shut down.
+ bool shutdown_;
+
+ // Mutex to protect access to the registered descriptors.
+ mutex registered_descriptors_mutex_;
+
+ // Keep track of all registered descriptors.
+ object_pool<descriptor_state> registered_descriptors_;
+
+ // Helper class to do post-perform_io cleanup.
+ struct perform_io_cleanup_on_block_exit;
+ friend struct perform_io_cleanup_on_block_exit;
+};
+
+} // namespace detail
+} // namespace asio
+
+#include "asio/detail/pop_options.hpp"
+
+#include "asio/detail/impl/epoll_reactor.hpp"
+#if defined(ASIO_HEADER_ONLY)
+# include "asio/detail/impl/epoll_reactor.ipp"
+#endif // defined(ASIO_HEADER_ONLY)
+
+#endif // defined(ASIO_HAS_EPOLL)
+
+#endif // ASIO_DETAIL_EPOLL_REACTOR_HPP
diff --git a/lib/asio/detail/event.hpp b/lib/asio/detail/event.hpp
new file mode 100644
index 0000000..da8fa77
--- /dev/null
+++ b/lib/asio/detail/event.hpp
@@ -0,0 +1,48 @@
+//
+// detail/event.hpp
+// ~~~~~~~~~~~~~~~~
+//
+// Copyright (c) 2003-2018 Christopher M. Kohlhoff (chris at kohlhoff dot com)
+//
+// 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 ASIO_DETAIL_EVENT_HPP
+#define ASIO_DETAIL_EVENT_HPP
+
+#if defined(_MSC_VER) && (_MSC_VER >= 1200)
+# pragma once
+#endif // defined(_MSC_VER) && (_MSC_VER >= 1200)
+
+#include "asio/detail/config.hpp"
+
+#if !defined(ASIO_HAS_THREADS)
+# include "asio/detail/null_event.hpp"
+#elif defined(ASIO_WINDOWS)
+# include "asio/detail/win_event.hpp"
+#elif defined(ASIO_HAS_PTHREADS)
+# include "asio/detail/posix_event.hpp"
+#elif defined(ASIO_HAS_STD_MUTEX_AND_CONDVAR)
+# include "asio/detail/std_event.hpp"
+#else
+# error Only Windows, POSIX and std::condition_variable are supported!
+#endif
+
+namespace asio {
+namespace detail {
+
+#if !defined(ASIO_HAS_THREADS)
+typedef null_event event;
+#elif defined(ASIO_WINDOWS)
+typedef win_event event;
+#elif defined(ASIO_HAS_PTHREADS)
+typedef posix_event event;
+#elif defined(ASIO_HAS_STD_MUTEX_AND_CONDVAR)
+typedef std_event event;
+#endif
+
+} // namespace detail
+} // namespace asio
+
+#endif // ASIO_DETAIL_EVENT_HPP
diff --git a/lib/asio/detail/eventfd_select_interrupter.hpp b/lib/asio/detail/eventfd_select_interrupter.hpp
new file mode 100644
index 0000000..f6e594b
--- /dev/null
+++ b/lib/asio/detail/eventfd_select_interrupter.hpp
@@ -0,0 +1,83 @@
+//
+// detail/eventfd_select_interrupter.hpp
+// ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+//
+// Copyright (c) 2003-2018 Christopher M. Kohlhoff (chris at kohlhoff dot com)
+// Copyright (c) 2008 Roelof Naude (roelof.naude at gmail dot com)
+//
+// 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 ASIO_DETAIL_EVENTFD_SELECT_INTERRUPTER_HPP
+#define ASIO_DETAIL_EVENTFD_SELECT_INTERRUPTER_HPP
+
+#if defined(_MSC_VER) && (_MSC_VER >= 1200)
+# pragma once
+#endif // defined(_MSC_VER) && (_MSC_VER >= 1200)
+
+#include "asio/detail/config.hpp"
+
+#if defined(ASIO_HAS_EVENTFD)
+
+#include "asio/detail/push_options.hpp"
+
+namespace asio {
+namespace detail {
+
+class eventfd_select_interrupter
+{
+public:
+ // Constructor.
+ ASIO_DECL eventfd_select_interrupter();
+
+ // Destructor.
+ ASIO_DECL ~eventfd_select_interrupter();
+
+ // Recreate the interrupter's descriptors. Used after a fork.
+ ASIO_DECL void recreate();
+
+ // Interrupt the select call.
+ ASIO_DECL void interrupt();
+
+ // Reset the select interrupt. Returns true if the call was interrupted.
+ ASIO_DECL bool reset();
+
+ // Get the read descriptor to be passed to select.
+ int read_descriptor() const
+ {
+ return read_descriptor_;
+ }
+
+private:
+ // Open the descriptors. Throws on error.
+ ASIO_DECL void open_descriptors();
+
+ // Close the descriptors.
+ ASIO_DECL void close_descriptors();
+
+ // The read end of a connection used to interrupt the select call. This file
+ // descriptor is passed to select such that when it is time to stop, a single
+ // 64bit value will be written on the other end of the connection and this
+ // descriptor will become readable.
+ int read_descriptor_;
+
+ // The write end of a connection used to interrupt the select call. A single
+ // 64bit non-zero value may be written to this to wake up the select which is
+ // waiting for the other end to become readable. This descriptor will only
+ // differ from the read descriptor when a pipe is used.
+ int write_descriptor_;
+};
+
+} // namespace detail
+} // namespace asio
+
+#include "asio/detail/pop_options.hpp"
+
+#if defined(ASIO_HEADER_ONLY)
+# include "asio/detail/impl/eventfd_select_interrupter.ipp"
+#endif // defined(ASIO_HEADER_ONLY)
+
+#endif // defined(ASIO_HAS_EVENTFD)
+
+#endif // ASIO_DETAIL_EVENTFD_SELECT_INTERRUPTER_HPP
diff --git a/lib/asio/detail/executor_op.hpp b/lib/asio/detail/executor_op.hpp
new file mode 100644
index 0000000..2d5c7e8
--- /dev/null
+++ b/lib/asio/detail/executor_op.hpp
@@ -0,0 +1,84 @@
+//
+// detail/executor_op.hpp
+// ~~~~~~~~~~~~~~~~~~~~~~
+//
+// Copyright (c) 2003-2018 Christopher M. Kohlhoff (chris at kohlhoff dot com)
+//
+// 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 ASIO_DETAIL_EXECUTOR_OP_HPP
+#define ASIO_DETAIL_EXECUTOR_OP_HPP
+
+#if defined(_MSC_VER) && (_MSC_VER >= 1200)
+# pragma once
+#endif // defined(_MSC_VER) && (_MSC_VER >= 1200)
+
+#include "asio/detail/config.hpp"
+#include "asio/detail/fenced_block.hpp"
+#include "asio/detail/handler_alloc_helpers.hpp"
+#include "asio/detail/handler_invoke_helpers.hpp"
+#include "asio/detail/scheduler_operation.hpp"
+
+#include "asio/detail/push_options.hpp"
+
+namespace asio {
+namespace detail {
+
+template <typename Handler, typename Alloc,
+ typename Operation = scheduler_operation>
+class executor_op : public Operation
+{
+public:
+ ASIO_DEFINE_HANDLER_ALLOCATOR_PTR(executor_op);
+
+ template <typename H>
+ executor_op(ASIO_MOVE_ARG(H) h, const Alloc& allocator)
+ : Operation(&executor_op::do_complete),
+ handler_(ASIO_MOVE_CAST(H)(h)),
+ allocator_(allocator)
+ {
+ }
+
+ static void do_complete(void* owner, Operation* base,
+ const asio::error_code& /*ec*/,
+ std::size_t /*bytes_transferred*/)
+ {
+ // Take ownership of the handler object.
+ executor_op* o(static_cast<executor_op*>(base));
+ Alloc allocator(o->allocator_);
+ ptr p = { detail::addressof(allocator), o, o };
+
+ ASIO_HANDLER_COMPLETION((*o));
+
+ // 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.
+ Handler handler(ASIO_MOVE_CAST(Handler)(o->handler_));
+ p.reset();
+
+ // Make the upcall if required.
+ if (owner)
+ {
+ fenced_block b(fenced_block::half);
+ ASIO_HANDLER_INVOCATION_BEGIN(());
+ asio_handler_invoke_helpers::invoke(handler, handler);
+ ASIO_HANDLER_INVOCATION_END;
+ }
+ }
+
+private:
+ Handler handler_;
+ Alloc allocator_;
+};
+
+} // namespace detail
+} // namespace asio
+
+#include "asio/detail/pop_options.hpp"
+
+#endif // ASIO_DETAIL_EXECUTOR_OP_HPP
diff --git a/lib/asio/detail/fd_set_adapter.hpp b/lib/asio/detail/fd_set_adapter.hpp
new file mode 100644
index 0000000..fd373da
--- /dev/null
+++ b/lib/asio/detail/fd_set_adapter.hpp
@@ -0,0 +1,39 @@
+//
+// detail/fd_set_adapter.hpp
+// ~~~~~~~~~~~~~~~~~~~~~~~~~
+//
+// Copyright (c) 2003-2018 Christopher M. Kohlhoff (chris at kohlhoff dot com)
+//
+// 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 ASIO_DETAIL_FD_SET_ADAPTER_HPP
+#define ASIO_DETAIL_FD_SET_ADAPTER_HPP
+
+#if defined(_MSC_VER) && (_MSC_VER >= 1200)
+# pragma once
+#endif // defined(_MSC_VER) && (_MSC_VER >= 1200)
+
+#include "asio/detail/config.hpp"
+
+#if !defined(ASIO_WINDOWS_RUNTIME)
+
+#include "asio/detail/posix_fd_set_adapter.hpp"
+#include "asio/detail/win_fd_set_adapter.hpp"
+
+namespace asio {
+namespace detail {
+
+#if defined(ASIO_WINDOWS) || defined(__CYGWIN__)
+typedef win_fd_set_adapter fd_set_adapter;
+#else
+typedef posix_fd_set_adapter fd_set_adapter;
+#endif
+
+} // namespace detail
+} // namespace asio
+
+#endif // !defined(ASIO_WINDOWS_RUNTIME)
+
+#endif // ASIO_DETAIL_FD_SET_ADAPTER_HPP
diff --git a/lib/asio/detail/fenced_block.hpp b/lib/asio/detail/fenced_block.hpp
new file mode 100644
index 0000000..dc34bd9
--- /dev/null
+++ b/lib/asio/detail/fenced_block.hpp
@@ -0,0 +1,80 @@
+//
+// detail/fenced_block.hpp
+// ~~~~~~~~~~~~~~~~~~~~~~~
+//
+// Copyright (c) 2003-2018 Christopher M. Kohlhoff (chris at kohlhoff dot com)
+//
+// 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 ASIO_DETAIL_FENCED_BLOCK_HPP
+#define ASIO_DETAIL_FENCED_BLOCK_HPP
+
+#if defined(_MSC_VER) && (_MSC_VER >= 1200)
+# pragma once
+#endif // defined(_MSC_VER) && (_MSC_VER >= 1200)
+
+#include "asio/detail/config.hpp"
+
+#if !defined(ASIO_HAS_THREADS) \
+ || defined(ASIO_DISABLE_FENCED_BLOCK)
+# include "asio/detail/null_fenced_block.hpp"
+#elif defined(ASIO_HAS_STD_ATOMIC)
+# include "asio/detail/std_fenced_block.hpp"
+#elif defined(__MACH__) && defined(__APPLE__)
+# include "asio/detail/macos_fenced_block.hpp"
+#elif defined(__sun)
+# include "asio/detail/solaris_fenced_block.hpp"
+#elif defined(__GNUC__) && defined(__arm__) \
+ && !defined(__GCC_HAVE_SYNC_COMPARE_AND_SWAP_4)
+# include "asio/detail/gcc_arm_fenced_block.hpp"
+#elif defined(__GNUC__) && (defined(__hppa) || defined(__hppa__))
+# include "asio/detail/gcc_hppa_fenced_block.hpp"
+#elif defined(__GNUC__) && (defined(__i386__) || defined(__x86_64__))
+# include "asio/detail/gcc_x86_fenced_block.hpp"
+#elif defined(__GNUC__) \
+ && ((__GNUC__ == 4 && __GNUC_MINOR__ >= 1) || (__GNUC__ > 4)) \
+ && !defined(__INTEL_COMPILER) && !defined(__ICL) \
+ && !defined(__ICC) && !defined(__ECC) && !defined(__PATHSCALE__)
+# include "asio/detail/gcc_sync_fenced_block.hpp"
+#elif defined(ASIO_WINDOWS) && !defined(UNDER_CE)
+# include "asio/detail/win_fenced_block.hpp"
+#else
+# include "asio/detail/null_fenced_block.hpp"
+#endif
+
+namespace asio {
+namespace detail {
+
+#if !defined(ASIO_HAS_THREADS) \
+ || defined(ASIO_DISABLE_FENCED_BLOCK)
+typedef null_fenced_block fenced_block;
+#elif defined(ASIO_HAS_STD_ATOMIC)
+typedef std_fenced_block fenced_block;
+#elif defined(__MACH__) && defined(__APPLE__)
+typedef macos_fenced_block fenced_block;
+#elif defined(__sun)
+typedef solaris_fenced_block fenced_block;
+#elif defined(__GNUC__) && defined(__arm__) \
+ && !defined(__GCC_HAVE_SYNC_COMPARE_AND_SWAP_4)
+typedef gcc_arm_fenced_block fenced_block;
+#elif defined(__GNUC__) && (defined(__hppa) || defined(__hppa__))
+typedef gcc_hppa_fenced_block fenced_block;
+#elif defined(__GNUC__) && (defined(__i386__) || defined(__x86_64__))
+typedef gcc_x86_fenced_block fenced_block;
+#elif defined(__GNUC__) \
+ && ((__GNUC__ == 4 && __GNUC_MINOR__ >= 1) || (__GNUC__ > 4)) \
+ && !defined(__INTEL_COMPILER) && !defined(__ICL) \
+ && !defined(__ICC) && !defined(__ECC) && !defined(__PATHSCALE__)
+typedef gcc_sync_fenced_block fenced_block;
+#elif defined(ASIO_WINDOWS) && !defined(UNDER_CE)
+typedef win_fenced_block fenced_block;
+#else
+typedef null_fenced_block fenced_block;
+#endif
+
+} // namespace detail
+} // namespace asio
+
+#endif // ASIO_DETAIL_FENCED_BLOCK_HPP
diff --git a/lib/asio/detail/functional.hpp b/lib/asio/detail/functional.hpp
new file mode 100644
index 0000000..a37e9e6
--- /dev/null
+++ b/lib/asio/detail/functional.hpp
@@ -0,0 +1,38 @@
+//
+// detail/functional.hpp
+// ~~~~~~~~~~~~~~~~~~~~~
+//
+// Copyright (c) 2003-2018 Christopher M. Kohlhoff (chris at kohlhoff dot com)
+//
+// 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 ASIO_DETAIL_FUNCTIONAL_HPP
+#define ASIO_DETAIL_FUNCTIONAL_HPP
+
+#if defined(_MSC_VER) && (_MSC_VER >= 1200)
+# pragma once
+#endif // defined(_MSC_VER) && (_MSC_VER >= 1200)
+
+#include "asio/detail/config.hpp"
+
+#include <functional>
+
+#if !defined(ASIO_HAS_STD_FUNCTION)
+# include <boost/function.hpp>
+#endif // !defined(ASIO_HAS_STD_FUNCTION)
+
+namespace asio {
+namespace detail {
+
+#if defined(ASIO_HAS_STD_FUNCTION)
+using std::function;
+#else // defined(ASIO_HAS_STD_FUNCTION)
+using boost::function;
+#endif // defined(ASIO_HAS_STD_FUNCTION)
+
+} // namespace detail
+} // namespace asio
+
+#endif // ASIO_DETAIL_FUNCTIONAL_HPP
diff --git a/lib/asio/detail/gcc_arm_fenced_block.hpp b/lib/asio/detail/gcc_arm_fenced_block.hpp
new file mode 100644
index 0000000..7919a55
--- /dev/null
+++ b/lib/asio/detail/gcc_arm_fenced_block.hpp
@@ -0,0 +1,91 @@
+//
+// detail/gcc_arm_fenced_block.hpp
+// ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+//
+// Copyright (c) 2003-2018 Christopher M. Kohlhoff (chris at kohlhoff dot com)
+//
+// 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 ASIO_DETAIL_GCC_ARM_FENCED_BLOCK_HPP
+#define ASIO_DETAIL_GCC_ARM_FENCED_BLOCK_HPP
+
+#if defined(_MSC_VER) && (_MSC_VER >= 1200)
+# pragma once
+#endif // defined(_MSC_VER) && (_MSC_VER >= 1200)
+
+#include "asio/detail/config.hpp"
+
+#if defined(__GNUC__) && defined(__arm__)
+
+#include "asio/detail/noncopyable.hpp"
+
+#include "asio/detail/push_options.hpp"
+
+namespace asio {
+namespace detail {
+
+class gcc_arm_fenced_block
+ : private noncopyable
+{
+public:
+ enum half_t { half };
+ enum full_t { full };
+
+ // Constructor for a half fenced block.
+ explicit gcc_arm_fenced_block(half_t)
+ {
+ }
+
+ // Constructor for a full fenced block.
+ explicit gcc_arm_fenced_block(full_t)
+ {
+ barrier();
+ }
+
+ // Destructor.
+ ~gcc_arm_fenced_block()
+ {
+ barrier();
+ }
+
+private:
+ static void barrier()
+ {
+#if defined(__ARM_ARCH_4__) \
+ || defined(__ARM_ARCH_4T__) \
+ || defined(__ARM_ARCH_5__) \
+ || defined(__ARM_ARCH_5E__) \
+ || defined(__ARM_ARCH_5T__) \
+ || defined(__ARM_ARCH_5TE__) \
+ || defined(__ARM_ARCH_5TEJ__) \
+ || defined(__ARM_ARCH_6__) \
+ || defined(__ARM_ARCH_6J__) \
+ || defined(__ARM_ARCH_6K__) \
+ || defined(__ARM_ARCH_6Z__) \
+ || defined(__ARM_ARCH_6ZK__) \
+ || defined(__ARM_ARCH_6T2__)
+# if defined(__thumb__)
+ // This is just a placeholder and almost certainly not sufficient.
+ __asm__ __volatile__ ("" : : : "memory");
+# else // defined(__thumb__)
+ int a = 0, b = 0;
+ __asm__ __volatile__ ("swp %0, %1, [%2]"
+ : "=&r"(a) : "r"(1), "r"(&b) : "memory", "cc");
+# endif // defined(__thumb__)
+#else
+ // ARMv7 and later.
+ __asm__ __volatile__ ("dmb" : : : "memory");
+#endif
+ }
+};
+
+} // namespace detail
+} // namespace asio
+
+#include "asio/detail/pop_options.hpp"
+
+#endif // defined(__GNUC__) && defined(__arm__)
+
+#endif // ASIO_DETAIL_GCC_ARM_FENCED_BLOCK_HPP
diff --git a/lib/asio/detail/gcc_hppa_fenced_block.hpp b/lib/asio/detail/gcc_hppa_fenced_block.hpp
new file mode 100644
index 0000000..d3957ce
--- /dev/null
+++ b/lib/asio/detail/gcc_hppa_fenced_block.hpp
@@ -0,0 +1,68 @@
+//
+// detail/gcc_hppa_fenced_block.hpp
+// ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+//
+// Copyright (c) 2003-2018 Christopher M. Kohlhoff (chris at kohlhoff dot com)
+//
+// 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 ASIO_DETAIL_GCC_HPPA_FENCED_BLOCK_HPP
+#define ASIO_DETAIL_GCC_HPPA_FENCED_BLOCK_HPP
+
+#if defined(_MSC_VER) && (_MSC_VER >= 1200)
+# pragma once
+#endif // defined(_MSC_VER) && (_MSC_VER >= 1200)
+
+#include "asio/detail/config.hpp"
+
+#if defined(__GNUC__) && (defined(__hppa) || defined(__hppa__))
+
+#include "asio/detail/noncopyable.hpp"
+
+#include "asio/detail/push_options.hpp"
+
+namespace asio {
+namespace detail {
+
+class gcc_hppa_fenced_block
+ : private noncopyable
+{
+public:
+ enum half_t { half };
+ enum full_t { full };
+
+ // Constructor for a half fenced block.
+ explicit gcc_hppa_fenced_block(half_t)
+ {
+ }
+
+ // Constructor for a full fenced block.
+ explicit gcc_hppa_fenced_block(full_t)
+ {
+ barrier();
+ }
+
+ // Destructor.
+ ~gcc_hppa_fenced_block()
+ {
+ barrier();
+ }
+
+private:
+ static void barrier()
+ {
+ // This is just a placeholder and almost certainly not sufficient.
+ __asm__ __volatile__ ("" : : : "memory");
+ }
+};
+
+} // namespace detail
+} // namespace asio
+
+#include "asio/detail/pop_options.hpp"
+
+#endif // defined(__GNUC__) && (defined(__hppa) || defined(__hppa__))
+
+#endif // ASIO_DETAIL_GCC_HPPA_FENCED_BLOCK_HPP
diff --git a/lib/asio/detail/gcc_sync_fenced_block.hpp b/lib/asio/detail/gcc_sync_fenced_block.hpp
new file mode 100644
index 0000000..90d176f
--- /dev/null
+++ b/lib/asio/detail/gcc_sync_fenced_block.hpp
@@ -0,0 +1,65 @@
+//
+// detail/gcc_sync_fenced_block.hpp
+// ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+//
+// Copyright (c) 2003-2018 Christopher M. Kohlhoff (chris at kohlhoff dot com)
+//
+// 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 ASIO_DETAIL_GCC_SYNC_FENCED_BLOCK_HPP
+#define ASIO_DETAIL_GCC_SYNC_FENCED_BLOCK_HPP
+
+#if defined(_MSC_VER) && (_MSC_VER >= 1200)
+# pragma once
+#endif // defined(_MSC_VER) && (_MSC_VER >= 1200)
+
+#include "asio/detail/config.hpp"
+
+#if defined(__GNUC__) \
+ && ((__GNUC__ == 4 && __GNUC_MINOR__ >= 1) || (__GNUC__ > 4)) \
+ && !defined(__INTEL_COMPILER) && !defined(__ICL) \
+ && !defined(__ICC) && !defined(__ECC) && !defined(__PATHSCALE__)
+
+#include "asio/detail/noncopyable.hpp"
+
+#include "asio/detail/push_options.hpp"
+
+namespace asio {
+namespace detail {
+
+class gcc_sync_fenced_block
+ : private noncopyable
+{
+public:
+ enum half_or_full_t { half, full };
+
+ // Constructor.
+ explicit gcc_sync_fenced_block(half_or_full_t)
+ : value_(0)
+ {
+ __sync_lock_test_and_set(&value_, 1);
+ }
+
+ // Destructor.
+ ~gcc_sync_fenced_block()
+ {
+ __sync_lock_release(&value_);
+ }
+
+private:
+ int value_;
+};
+
+} // namespace detail
+} // namespace asio
+
+#include "asio/detail/pop_options.hpp"
+
+#endif // defined(__GNUC__)
+ // && ((__GNUC__ == 4 && __GNUC_MINOR__ >= 1) || (__GNUC__ > 4))
+ // && !defined(__INTEL_COMPILER) && !defined(__ICL)
+ // && !defined(__ICC) && !defined(__ECC) && !defined(__PATHSCALE__)
+
+#endif // ASIO_DETAIL_GCC_SYNC_FENCED_BLOCK_HPP
diff --git a/lib/asio/detail/gcc_x86_fenced_block.hpp b/lib/asio/detail/gcc_x86_fenced_block.hpp
new file mode 100644
index 0000000..1366def
--- /dev/null
+++ b/lib/asio/detail/gcc_x86_fenced_block.hpp
@@ -0,0 +1,99 @@
+//
+// detail/gcc_x86_fenced_block.hpp
+// ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+//
+// Copyright (c) 2003-2018 Christopher M. Kohlhoff (chris at kohlhoff dot com)
+//
+// 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 ASIO_DETAIL_GCC_X86_FENCED_BLOCK_HPP
+#define ASIO_DETAIL_GCC_X86_FENCED_BLOCK_HPP
+
+#if defined(_MSC_VER) && (_MSC_VER >= 1200)
+# pragma once
+#endif // defined(_MSC_VER) && (_MSC_VER >= 1200)
+
+#include "asio/detail/config.hpp"
+
+#if defined(__GNUC__) && (defined(__i386__) || defined(__x86_64__))
+
+#include "asio/detail/noncopyable.hpp"
+
+#include "asio/detail/push_options.hpp"
+
+namespace asio {
+namespace detail {
+
+class gcc_x86_fenced_block
+ : private noncopyable
+{
+public:
+ enum half_t { half };
+ enum full_t { full };
+
+ // Constructor for a half fenced block.
+ explicit gcc_x86_fenced_block(half_t)
+ {
+ }
+
+ // Constructor for a full fenced block.
+ explicit gcc_x86_fenced_block(full_t)
+ {
+ lbarrier();
+ }
+
+ // Destructor.
+ ~gcc_x86_fenced_block()
+ {
+ sbarrier();
+ }
+
+private:
+ static int barrier()
+ {
+ int r = 0, m = 1;
+ __asm__ __volatile__ (
+ "xchgl %0, %1" :
+ "=r"(r), "=m"(m) :
+ "0"(1), "m"(m) :
+ "memory", "cc");
+ return r;
+ }
+
+ static void lbarrier()
+ {
+#if defined(__SSE2__)
+# if (__GNUC__ >= 4) && !defined(__INTEL_COMPILER) && !defined(__ICL)
+ __builtin_ia32_lfence();
+# else // (__GNUC__ >= 4) && !defined(__INTEL_COMPILER) && !defined(__ICL)
+ __asm__ __volatile__ ("lfence" ::: "memory");
+# endif // (__GNUC__ >= 4) && !defined(__INTEL_COMPILER) && !defined(__ICL)
+#else // defined(__SSE2__)
+ barrier();
+#endif // defined(__SSE2__)
+ }
+
+ static void sbarrier()
+ {
+#if defined(__SSE2__)
+# if (__GNUC__ >= 4) && !defined(__INTEL_COMPILER) && !defined(__ICL)
+ __builtin_ia32_sfence();
+# else // (__GNUC__ >= 4) && !defined(__INTEL_COMPILER) && !defined(__ICL)
+ __asm__ __volatile__ ("sfence" ::: "memory");
+# endif // (__GNUC__ >= 4) && !defined(__INTEL_COMPILER) && !defined(__ICL)
+#else // defined(__SSE2__)
+ barrier();
+#endif // defined(__SSE2__)
+ }
+};
+
+} // namespace detail
+} // namespace asio
+
+#include "asio/detail/pop_options.hpp"
+
+#endif // defined(__GNUC__) && (defined(__i386__) || defined(__x86_64__))
+
+#endif // ASIO_DETAIL_GCC_X86_FENCED_BLOCK_HPP
diff --git a/lib/asio/detail/global.hpp b/lib/asio/detail/global.hpp
new file mode 100644
index 0000000..085ac64
--- /dev/null
+++ b/lib/asio/detail/global.hpp
@@ -0,0 +1,52 @@
+//
+// detail/global.hpp
+// ~~~~~~~~~~~~~~~~~
+//
+// Copyright (c) 2003-2018 Christopher M. Kohlhoff (chris at kohlhoff dot com)
+//
+// 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 ASIO_DETAIL_GLOBAL_HPP
+#define ASIO_DETAIL_GLOBAL_HPP
+
+#if defined(_MSC_VER) && (_MSC_VER >= 1200)
+# pragma once
+#endif // defined(_MSC_VER) && (_MSC_VER >= 1200)
+
+#include "asio/detail/config.hpp"
+
+#if !defined(ASIO_HAS_THREADS)
+# include "asio/detail/null_global.hpp"
+#elif defined(ASIO_WINDOWS)
+# include "asio/detail/win_global.hpp"
+#elif defined(ASIO_HAS_PTHREADS)
+# include "asio/detail/posix_global.hpp"
+#elif defined(ASIO_HAS_STD_CALL_ONCE)
+# include "asio/detail/std_global.hpp"
+#else
+# error Only Windows, POSIX and std::call_once are supported!
+#endif
+
+namespace asio {
+namespace detail {
+
+template <typename T>
+inline T& global()
+{
+#if !defined(ASIO_HAS_THREADS)
+ return null_global<T>();
+#elif defined(ASIO_WINDOWS)
+ return win_global<T>();
+#elif defined(ASIO_HAS_PTHREADS)
+ return posix_global<T>();
+#elif defined(ASIO_HAS_STD_CALL_ONCE)
+ return std_global<T>();
+#endif
+}
+
+} // namespace detail
+} // namespace asio
+
+#endif // ASIO_DETAIL_GLOBAL_HPP
diff --git a/lib/asio/detail/handler_alloc_helpers.hpp b/lib/asio/detail/handler_alloc_helpers.hpp
new file mode 100644
index 0000000..afefb4d
--- /dev/null
+++ b/lib/asio/detail/handler_alloc_helpers.hpp
@@ -0,0 +1,235 @@
+//
+// detail/handler_alloc_helpers.hpp
+// ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+//
+// Copyright (c) 2003-2018 Christopher M. Kohlhoff (chris at kohlhoff dot com)
+//
+// 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 ASIO_DETAIL_HANDLER_ALLOC_HELPERS_HPP
+#define ASIO_DETAIL_HANDLER_ALLOC_HELPERS_HPP
+
+#if defined(_MSC_VER) && (_MSC_VER >= 1200)
+# pragma once
+#endif // defined(_MSC_VER) && (_MSC_VER >= 1200)
+
+#include "asio/detail/config.hpp"
+#include "asio/detail/memory.hpp"
+#include "asio/detail/noncopyable.hpp"
+#include "asio/detail/recycling_allocator.hpp"
+#include "asio/associated_allocator.hpp"
+#include "asio/handler_alloc_hook.hpp"
+
+#include "asio/detail/push_options.hpp"
+
+// Calls to asio_handler_allocate and asio_handler_deallocate must be made from
+// a namespace that does not contain any overloads of these functions. The
+// asio_handler_alloc_helpers namespace is defined here for that purpose.
+namespace asio_handler_alloc_helpers {
+
+template <typename Handler>
+inline void* allocate(std::size_t s, Handler& h)
+{
+#if !defined(ASIO_HAS_HANDLER_HOOKS)
+ return ::operator new(s);
+#else
+ using asio::asio_handler_allocate;
+ return asio_handler_allocate(s, asio::detail::addressof(h));
+#endif
+}
+
+template <typename Handler>
+inline void deallocate(void* p, std::size_t s, Handler& h)
+{
+#if !defined(ASIO_HAS_HANDLER_HOOKS)
+ ::operator delete(p);
+#else
+ using asio::asio_handler_deallocate;
+ asio_handler_deallocate(p, s, asio::detail::addressof(h));
+#endif
+}
+
+} // namespace asio_handler_alloc_helpers
+
+namespace asio {
+namespace detail {
+
+template <typename Handler, typename T>
+class hook_allocator
+{
+public:
+ typedef T value_type;
+
+ template <typename U>
+ struct rebind
+ {
+ typedef hook_allocator<Handler, U> other;
+ };
+
+ explicit hook_allocator(Handler& h)
+ : handler_(h)
+ {
+ }
+
+ template <typename U>
+ hook_allocator(const hook_allocator<Handler, U>& a)
+ : handler_(a.handler_)
+ {
+ }
+
+ T* allocate(std::size_t n)
+ {
+ return static_cast<T*>(
+ asio_handler_alloc_helpers::allocate(sizeof(T) * n, handler_));
+ }
+
+ void deallocate(T* p, std::size_t n)
+ {
+ asio_handler_alloc_helpers::deallocate(p, sizeof(T) * n, handler_);
+ }
+
+//private:
+ Handler& handler_;
+};
+
+template <typename Handler>
+class hook_allocator<Handler, void>
+{
+public:
+ typedef void value_type;
+
+ template <typename U>
+ struct rebind
+ {
+ typedef hook_allocator<Handler, U> other;
+ };
+
+ explicit hook_allocator(Handler& h)
+ : handler_(h)
+ {
+ }
+
+ template <typename U>
+ hook_allocator(const hook_allocator<Handler, U>& a)
+ : handler_(a.handler_)
+ {
+ }
+
+//private:
+ Handler& handler_;
+};
+
+template <typename Handler, typename Allocator>
+struct get_hook_allocator
+{
+ typedef Allocator type;
+
+ static type get(Handler&, const Allocator& a)
+ {
+ return a;
+ }
+};
+
+template <typename Handler, typename T>
+struct get_hook_allocator<Handler, std::allocator<T> >
+{
+ typedef hook_allocator<Handler, T> type;
+
+ static type get(Handler& handler, const std::allocator<T>&)
+ {
+ return type(handler);
+ }
+};
+
+} // namespace detail
+} // namespace asio
+
+#define ASIO_DEFINE_HANDLER_PTR(op) \
+ struct ptr \
+ { \
+ Handler* h; \
+ op* v; \
+ op* p; \
+ ~ptr() \
+ { \
+ reset(); \
+ } \
+ static op* allocate(Handler& handler) \
+ { \
+ typedef typename ::asio::associated_allocator< \
+ Handler>::type associated_allocator_type; \
+ typedef typename ::asio::detail::get_hook_allocator< \
+ Handler, associated_allocator_type>::type hook_allocator_type; \
+ ASIO_REBIND_ALLOC(hook_allocator_type, op) a( \
+ ::asio::detail::get_hook_allocator< \
+ Handler, associated_allocator_type>::get( \
+ handler, ::asio::get_associated_allocator(handler))); \
+ return a.allocate(1); \
+ } \
+ void reset() \
+ { \
+ if (p) \
+ { \
+ p->~op(); \
+ p = 0; \
+ } \
+ if (v) \
+ { \
+ typedef typename ::asio::associated_allocator< \
+ Handler>::type associated_allocator_type; \
+ typedef typename ::asio::detail::get_hook_allocator< \
+ Handler, associated_allocator_type>::type hook_allocator_type; \
+ ASIO_REBIND_ALLOC(hook_allocator_type, op) a( \
+ ::asio::detail::get_hook_allocator< \
+ Handler, associated_allocator_type>::get( \
+ *h, ::asio::get_associated_allocator(*h))); \
+ a.deallocate(static_cast<op*>(v), 1); \
+ v = 0; \
+ } \
+ } \
+ } \
+ /**/
+
+#define ASIO_DEFINE_HANDLER_ALLOCATOR_PTR(op) \
+ struct ptr \
+ { \
+ const Alloc* a; \
+ void* v; \
+ op* p; \
+ ~ptr() \
+ { \
+ reset(); \
+ } \
+ static op* allocate(const Alloc& a) \
+ { \
+ typedef typename ::asio::detail::get_recycling_allocator< \
+ Alloc>::type recycling_allocator_type; \
+ ASIO_REBIND_ALLOC(recycling_allocator_type, op) a1( \
+ ::asio::detail::get_recycling_allocator<Alloc>::get(a)); \
+ return a1.allocate(1); \
+ } \
+ void reset() \
+ { \
+ if (p) \
+ { \
+ p->~op(); \
+ p = 0; \
+ } \
+ if (v) \
+ { \
+ typedef typename ::asio::detail::get_recycling_allocator< \
+ Alloc>::type recycling_allocator_type; \
+ ASIO_REBIND_ALLOC(recycling_allocator_type, op) a1( \
+ ::asio::detail::get_recycling_allocator<Alloc>::get(*a)); \
+ a1.deallocate(static_cast<op*>(v), 1); \
+ v = 0; \
+ } \
+ } \
+ } \
+ /**/
+
+#include "asio/detail/pop_options.hpp"
+
+#endif // ASIO_DETAIL_HANDLER_ALLOC_HELPERS_HPP
diff --git a/lib/asio/detail/handler_cont_helpers.hpp b/lib/asio/detail/handler_cont_helpers.hpp
new file mode 100644
index 0000000..110ba94
--- /dev/null
+++ b/lib/asio/detail/handler_cont_helpers.hpp
@@ -0,0 +1,45 @@
+//
+// detail/handler_cont_helpers.hpp
+// ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+//
+// Copyright (c) 2003-2018 Christopher M. Kohlhoff (chris at kohlhoff dot com)
+//
+// 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 ASIO_DETAIL_HANDLER_CONT_HELPERS_HPP
+#define ASIO_DETAIL_HANDLER_CONT_HELPERS_HPP
+
+#if defined(_MSC_VER) && (_MSC_VER >= 1200)
+# pragma once
+#endif // defined(_MSC_VER) && (_MSC_VER >= 1200)
+
+#include "asio/detail/config.hpp"
+#include "asio/detail/memory.hpp"
+#include "asio/handler_continuation_hook.hpp"
+
+#include "asio/detail/push_options.hpp"
+
+// Calls to asio_handler_is_continuation must be made from a namespace that
+// does not contain overloads of this function. This namespace is defined here
+// for that purpose.
+namespace asio_handler_cont_helpers {
+
+template <typename Context>
+inline bool is_continuation(Context& context)
+{
+#if !defined(ASIO_HAS_HANDLER_HOOKS)
+ return false;
+#else
+ using asio::asio_handler_is_continuation;
+ return asio_handler_is_continuation(
+ asio::detail::addressof(context));
+#endif
+}
+
+} // namespace asio_handler_cont_helpers
+
+#include "asio/detail/pop_options.hpp"
+
+#endif // ASIO_DETAIL_HANDLER_CONT_HELPERS_HPP
diff --git a/lib/asio/detail/handler_invoke_helpers.hpp b/lib/asio/detail/handler_invoke_helpers.hpp
new file mode 100644
index 0000000..4c65c4c
--- /dev/null
+++ b/lib/asio/detail/handler_invoke_helpers.hpp
@@ -0,0 +1,57 @@
+//
+// detail/handler_invoke_helpers.hpp
+// ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+//
+// Copyright (c) 2003-2018 Christopher M. Kohlhoff (chris at kohlhoff dot com)
+//
+// 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 ASIO_DETAIL_HANDLER_INVOKE_HELPERS_HPP
+#define ASIO_DETAIL_HANDLER_INVOKE_HELPERS_HPP
+
+#if defined(_MSC_VER) && (_MSC_VER >= 1200)
+# pragma once
+#endif // defined(_MSC_VER) && (_MSC_VER >= 1200)
+
+#include "asio/detail/config.hpp"
+#include "asio/detail/memory.hpp"
+#include "asio/handler_invoke_hook.hpp"
+
+#include "asio/detail/push_options.hpp"
+
+// Calls to asio_handler_invoke must be made from a namespace that does not
+// contain overloads of this function. The asio_handler_invoke_helpers
+// namespace is defined here for that purpose.
+namespace asio_handler_invoke_helpers {
+
+template <typename Function, typename Context>
+inline void invoke(Function& function, Context& context)
+{
+#if !defined(ASIO_HAS_HANDLER_HOOKS)
+ Function tmp(function);
+ tmp();
+#else
+ using asio::asio_handler_invoke;
+ asio_handler_invoke(function, asio::detail::addressof(context));
+#endif
+}
+
+template <typename Function, typename Context>
+inline void invoke(const Function& function, Context& context)
+{
+#if !defined(ASIO_HAS_HANDLER_HOOKS)
+ Function tmp(function);
+ tmp();
+#else
+ using asio::asio_handler_invoke;
+ asio_handler_invoke(function, asio::detail::addressof(context));
+#endif
+}
+
+} // namespace asio_handler_invoke_helpers
+
+#include "asio/detail/pop_options.hpp"
+
+#endif // ASIO_DETAIL_HANDLER_INVOKE_HELPERS_HPP
diff --git a/lib/asio/detail/handler_tracking.hpp b/lib/asio/detail/handler_tracking.hpp
new file mode 100644
index 0000000..83f820e
--- /dev/null
+++ b/lib/asio/detail/handler_tracking.hpp
@@ -0,0 +1,238 @@
+//
+// detail/handler_tracking.hpp
+// ~~~~~~~~~~~~~~~~~~~~~~~~~~~
+//
+// Copyright (c) 2003-2018 Christopher M. Kohlhoff (chris at kohlhoff dot com)
+//
+// 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 ASIO_DETAIL_HANDLER_TRACKING_HPP
+#define ASIO_DETAIL_HANDLER_TRACKING_HPP
+
+#if defined(_MSC_VER) && (_MSC_VER >= 1200)
+# pragma once
+#endif // defined(_MSC_VER) && (_MSC_VER >= 1200)
+
+#include "asio/detail/config.hpp"
+
+namespace asio {
+
+class execution_context;
+
+} // namespace asio
+
+#if defined(ASIO_CUSTOM_HANDLER_TRACKING)
+# include ASIO_CUSTOM_HANDLER_TRACKING
+#elif defined(ASIO_ENABLE_HANDLER_TRACKING)
+# include "asio/error_code.hpp"
+# include "asio/detail/cstdint.hpp"
+# include "asio/detail/static_mutex.hpp"
+# include "asio/detail/tss_ptr.hpp"
+#endif // defined(ASIO_ENABLE_HANDLER_TRACKING)
+
+#include "asio/detail/push_options.hpp"
+
+namespace asio {
+namespace detail {
+
+#if defined(ASIO_CUSTOM_HANDLER_TRACKING)
+
+// The user-specified header must define the following macros:
+// - ASIO_INHERIT_TRACKED_HANDLER
+// - ASIO_ALSO_INHERIT_TRACKED_HANDLER
+// - ASIO_HANDLER_TRACKING_INIT
+// - ASIO_HANDLER_CREATION(args)
+// - ASIO_HANDLER_COMPLETION(args)
+// - ASIO_HANDLER_INVOCATION_BEGIN(args)
+// - ASIO_HANDLER_INVOCATION_END
+// - ASIO_HANDLER_OPERATION(args)
+// - ASIO_HANDLER_REACTOR_REGISTRATION(args)
+// - ASIO_HANDLER_REACTOR_DEREGISTRATION(args)
+// - ASIO_HANDLER_REACTOR_READ_EVENT
+// - ASIO_HANDLER_REACTOR_WRITE_EVENT
+// - ASIO_HANDLER_REACTOR_ERROR_EVENT
+// - ASIO_HANDLER_REACTOR_EVENTS(args)
+// - ASIO_HANDLER_REACTOR_OPERATION(args)
+
+# if !defined(ASIO_ENABLE_HANDLER_TRACKING)
+# define ASIO_ENABLE_HANDLER_TRACKING 1
+# endif /// !defined(ASIO_ENABLE_HANDLER_TRACKING)
+
+#elif defined(ASIO_ENABLE_HANDLER_TRACKING)
+
+class handler_tracking
+{
+public:
+ class completion;
+
+ // Base class for objects containing tracked handlers.
+ class tracked_handler
+ {
+ private:
+ // Only the handler_tracking class will have access to the id.
+ friend class handler_tracking;
+ friend class completion;
+ uint64_t id_;
+
+ protected:
+ // Constructor initialises with no id.
+ tracked_handler() : id_(0) {}
+
+ // Prevent deletion through this type.
+ ~tracked_handler() {}
+ };
+
+ // Initialise the tracking system.
+ ASIO_DECL static void init();
+
+ // Record the creation of a tracked handler.
+ ASIO_DECL static void creation(
+ execution_context& context, tracked_handler& h,
+ const char* object_type, void* object,
+ uintmax_t native_handle, const char* op_name);
+
+ class completion
+ {
+ public:
+ // Constructor records that handler is to be invoked with no arguments.
+ ASIO_DECL explicit completion(const tracked_handler& h);
+
+ // Destructor records only when an exception is thrown from the handler, or
+ // if the memory is being freed without the handler having been invoked.
+ ASIO_DECL ~completion();
+
+ // Records that handler is to be invoked with no arguments.
+ ASIO_DECL void invocation_begin();
+
+ // Records that handler is to be invoked with one arguments.
+ ASIO_DECL void invocation_begin(const asio::error_code& ec);
+
+ // Constructor records that handler is to be invoked with two arguments.
+ ASIO_DECL void invocation_begin(
+ const asio::error_code& ec, std::size_t bytes_transferred);
+
+ // Constructor records that handler is to be invoked with two arguments.
+ ASIO_DECL void invocation_begin(
+ const asio::error_code& ec, int signal_number);
+
+ // Constructor records that handler is to be invoked with two arguments.
+ ASIO_DECL void invocation_begin(
+ const asio::error_code& ec, const char* arg);
+
+ // Record that handler invocation has ended.
+ ASIO_DECL void invocation_end();
+
+ private:
+ friend class handler_tracking;
+ uint64_t id_;
+ bool invoked_;
+ completion* next_;
+ };
+
+ // Record an operation that is not directly associated with a handler.
+ ASIO_DECL static void operation(execution_context& context,
+ const char* object_type, void* object,
+ uintmax_t native_handle, const char* op_name);
+
+ // Record that a descriptor has been registered with the reactor.
+ ASIO_DECL static void reactor_registration(execution_context& context,
+ uintmax_t native_handle, uintmax_t registration);
+
+ // Record that a descriptor has been deregistered from the reactor.
+ ASIO_DECL static void reactor_deregistration(execution_context& context,
+ uintmax_t native_handle, uintmax_t registration);
+
+ // Record a reactor-based operation that is associated with a handler.
+ ASIO_DECL static void reactor_events(execution_context& context,
+ uintmax_t registration, unsigned events);
+
+ // Record a reactor-based operation that is associated with a handler.
+ ASIO_DECL static void reactor_operation(
+ const tracked_handler& h, const char* op_name,
+ const asio::error_code& ec);
+
+ // Record a reactor-based operation that is associated with a handler.
+ ASIO_DECL static void reactor_operation(
+ const tracked_handler& h, const char* op_name,
+ const asio::error_code& ec, std::size_t bytes_transferred);
+
+ // Write a line of output.
+ ASIO_DECL static void write_line(const char* format, ...);
+
+private:
+ struct tracking_state;
+ ASIO_DECL static tracking_state* get_state();
+};
+
+# define ASIO_INHERIT_TRACKED_HANDLER \
+ : public asio::detail::handler_tracking::tracked_handler
+
+# define ASIO_ALSO_INHERIT_TRACKED_HANDLER \
+ , public asio::detail::handler_tracking::tracked_handler
+
+# define ASIO_HANDLER_TRACKING_INIT \
+ asio::detail::handler_tracking::init()
+
+# define ASIO_HANDLER_CREATION(args) \
+ asio::detail::handler_tracking::creation args
+
+# define ASIO_HANDLER_COMPLETION(args) \
+ asio::detail::handler_tracking::completion tracked_completion args
+
+# define ASIO_HANDLER_INVOCATION_BEGIN(args) \
+ tracked_completion.invocation_begin args
+
+# define ASIO_HANDLER_INVOCATION_END \
+ tracked_completion.invocation_end()
+
+# define ASIO_HANDLER_OPERATION(args) \
+ asio::detail::handler_tracking::operation args
+
+# define ASIO_HANDLER_REACTOR_REGISTRATION(args) \
+ asio::detail::handler_tracking::reactor_registration args
+
+# define ASIO_HANDLER_REACTOR_DEREGISTRATION(args) \
+ asio::detail::handler_tracking::reactor_deregistration args
+
+# define ASIO_HANDLER_REACTOR_READ_EVENT 1
+# define ASIO_HANDLER_REACTOR_WRITE_EVENT 2
+# define ASIO_HANDLER_REACTOR_ERROR_EVENT 4
+
+# define ASIO_HANDLER_REACTOR_EVENTS(args) \
+ asio::detail::handler_tracking::reactor_events args
+
+# define ASIO_HANDLER_REACTOR_OPERATION(args) \
+ asio::detail::handler_tracking::reactor_operation args
+
+#else // defined(ASIO_ENABLE_HANDLER_TRACKING)
+
+# define ASIO_INHERIT_TRACKED_HANDLER
+# define ASIO_ALSO_INHERIT_TRACKED_HANDLER
+# define ASIO_HANDLER_TRACKING_INIT (void)0
+# define ASIO_HANDLER_CREATION(args) (void)0
+# define ASIO_HANDLER_COMPLETION(args) (void)0
+# define ASIO_HANDLER_INVOCATION_BEGIN(args) (void)0
+# define ASIO_HANDLER_INVOCATION_END (void)0
+# define ASIO_HANDLER_OPERATION(args) (void)0
+# define ASIO_HANDLER_REACTOR_REGISTRATION(args) (void)0
+# define ASIO_HANDLER_REACTOR_DEREGISTRATION(args) (void)0
+# define ASIO_HANDLER_REACTOR_READ_EVENT 0
+# define ASIO_HANDLER_REACTOR_WRITE_EVENT 0
+# define ASIO_HANDLER_REACTOR_ERROR_EVENT 0
+# define ASIO_HANDLER_REACTOR_EVENTS(args) (void)0
+# define ASIO_HANDLER_REACTOR_OPERATION(args) (void)0
+
+#endif // defined(ASIO_ENABLE_HANDLER_TRACKING)
+
+} // namespace detail
+} // namespace asio
+
+#include "asio/detail/pop_options.hpp"
+
+#if defined(ASIO_HEADER_ONLY)
+# include "asio/detail/impl/handler_tracking.ipp"
+#endif // defined(ASIO_HEADER_ONLY)
+
+#endif // ASIO_DETAIL_HANDLER_TRACKING_HPP
diff --git a/lib/asio/detail/handler_type_requirements.hpp b/lib/asio/detail/handler_type_requirements.hpp
new file mode 100644
index 0000000..9181bc5
--- /dev/null
+++ b/lib/asio/detail/handler_type_requirements.hpp
@@ -0,0 +1,556 @@
+//
+// detail/handler_type_requirements.hpp
+// ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+//
+// Copyright (c) 2003-2018 Christopher M. Kohlhoff (chris at kohlhoff dot com)
+//
+// 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 ASIO_DETAIL_HANDLER_TYPE_REQUIREMENTS_HPP
+#define ASIO_DETAIL_HANDLER_TYPE_REQUIREMENTS_HPP
+
+#if defined(_MSC_VER) && (_MSC_VER >= 1200)
+# pragma once
+#endif // defined(_MSC_VER) && (_MSC_VER >= 1200)
+
+#include "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(ASIO_DISABLE_HANDLER_TYPE_REQUIREMENTS)
+# if !defined(__GNUC__) || (__GNUC__ >= 4)
+# define ASIO_ENABLE_HANDLER_TYPE_REQUIREMENTS 1
+# endif // !defined(__GNUC__) || (__GNUC__ >= 4)
+#endif // !defined(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(ASIO_DISABLE_HANDLER_TYPE_REQUIREMENTS_ASSERT)
+# if defined(__GNUC__)
+# if ((__GNUC__ == 4) && (__GNUC_MINOR__ >= 5)) || (__GNUC__ > 4)
+# if defined(__GXX_EXPERIMENTAL_CXX0X__)
+# define 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(ASIO_MSVC)
+# if (_MSC_VER >= 1600)
+# define ASIO_ENABLE_HANDLER_TYPE_REQUIREMENTS_ASSERT 1
+# endif // (_MSC_VER >= 1600)
+# endif // defined(ASIO_MSVC)
+# if defined(__clang__)
+# if __has_feature(__cxx_static_assert__)
+# define ASIO_ENABLE_HANDLER_TYPE_REQUIREMENTS_ASSERT 1
+# endif // __has_feature(cxx_static_assert)
+# endif // defined(__clang__)
+#endif // !defined(ASIO_DISABLE_HANDLER_TYPE_REQUIREMENTS)
+
+#if defined(ASIO_ENABLE_HANDLER_TYPE_REQUIREMENTS)
+# include "asio/async_result.hpp"
+#endif // defined(ASIO_ENABLE_HANDLER_TYPE_REQUIREMENTS)
+
+namespace asio {
+namespace detail {
+
+#if defined(ASIO_ENABLE_HANDLER_TYPE_REQUIREMENTS)
+
+# if defined(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(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(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(ASIO_MOVE_CAST(Handler)(h))),
+ ((h)(*a1, ASIO_MOVE_CAST(Arg2)(*a2))),
+ char(0));
+
+template <typename Handler>
+char (&two_arg_move_handler_test(Handler, ...))[2];
+
+# define ASIO_HANDLER_TYPE_REQUIREMENTS_ASSERT(expr, msg) \
+ static_assert(expr, msg);
+
+# else // defined(ASIO_ENABLE_HANDLER_TYPE_REQUIREMENTS_ASSERT)
+
+# define ASIO_HANDLER_TYPE_REQUIREMENTS_ASSERT(expr, msg)
+
+# endif // defined(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(ASIO_HAS_MOVE)
+template <typename T> T rvref();
+template <typename T> T rvref(T);
+#else // defined(ASIO_HAS_MOVE)
+template <typename T> const T& rvref();
+template <typename T> const T& rvref(T);
+#endif // defined(ASIO_HAS_MOVE)
+template <typename T> char argbyv(T);
+
+template <int>
+struct handler_type_requirements
+{
+};
+
+#define ASIO_LEGACY_COMPLETION_HANDLER_CHECK( \
+ handler_type, handler) \
+ \
+ typedef ASIO_HANDLER_TYPE(handler_type, \
+ void()) asio_true_handler_type; \
+ \
+ ASIO_HANDLER_TYPE_REQUIREMENTS_ASSERT( \
+ sizeof(asio::detail::zero_arg_copyable_handler_test( \
+ asio::detail::clvref< \
+ asio_true_handler_type>(), 0)) == 1, \
+ "CompletionHandler type requirements not met") \
+ \
+ typedef asio::detail::handler_type_requirements< \
+ sizeof( \
+ asio::detail::argbyv( \
+ asio::detail::clvref< \
+ asio_true_handler_type>())) + \
+ sizeof( \
+ asio::detail::lvref< \
+ asio_true_handler_type>()(), \
+ char(0))> ASIO_UNUSED_TYPEDEF
+
+#define ASIO_READ_HANDLER_CHECK( \
+ handler_type, handler) \
+ \
+ typedef ASIO_HANDLER_TYPE(handler_type, \
+ void(asio::error_code, std::size_t)) \
+ asio_true_handler_type; \
+ \
+ ASIO_HANDLER_TYPE_REQUIREMENTS_ASSERT( \
+ sizeof(asio::detail::two_arg_handler_test( \
+ asio::detail::rvref< \
+ asio_true_handler_type>(), \
+ static_cast<const asio::error_code*>(0), \
+ static_cast<const std::size_t*>(0))) == 1, \
+ "ReadHandler type requirements not met") \
+ \
+ typedef asio::detail::handler_type_requirements< \
+ sizeof( \
+ asio::detail::argbyv( \
+ asio::detail::rvref< \
+ asio_true_handler_type>())) + \
+ sizeof( \
+ asio::detail::lvref< \
+ asio_true_handler_type>()( \
+ asio::detail::lvref<const asio::error_code>(), \
+ asio::detail::lvref<const std::size_t>()), \
+ char(0))> ASIO_UNUSED_TYPEDEF
+
+#define ASIO_WRITE_HANDLER_CHECK( \
+ handler_type, handler) \
+ \
+ typedef ASIO_HANDLER_TYPE(handler_type, \
+ void(asio::error_code, std::size_t)) \
+ asio_true_handler_type; \
+ \
+ ASIO_HANDLER_TYPE_REQUIREMENTS_ASSERT( \
+ sizeof(asio::detail::two_arg_handler_test( \
+ asio::detail::rvref< \
+ asio_true_handler_type>(), \
+ static_cast<const asio::error_code*>(0), \
+ static_cast<const std::size_t*>(0))) == 1, \
+ "WriteHandler type requirements not met") \
+ \
+ typedef asio::detail::handler_type_requirements< \
+ sizeof( \
+ asio::detail::argbyv( \
+ asio::detail::rvref< \
+ asio_true_handler_type>())) + \
+ sizeof( \
+ asio::detail::lvref< \
+ asio_true_handler_type>()( \
+ asio::detail::lvref<const asio::error_code>(), \
+ asio::detail::lvref<const std::size_t>()), \
+ char(0))> ASIO_UNUSED_TYPEDEF
+
+#define ASIO_ACCEPT_HANDLER_CHECK( \
+ handler_type, handler) \
+ \
+ typedef ASIO_HANDLER_TYPE(handler_type, \
+ void(asio::error_code)) \
+ asio_true_handler_type; \
+ \
+ ASIO_HANDLER_TYPE_REQUIREMENTS_ASSERT( \
+ sizeof(asio::detail::one_arg_handler_test( \
+ asio::detail::rvref< \
+ asio_true_handler_type>(), \
+ static_cast<const asio::error_code*>(0))) == 1, \
+ "AcceptHandler type requirements not met") \
+ \
+ typedef asio::detail::handler_type_requirements< \
+ sizeof( \
+ asio::detail::argbyv( \
+ asio::detail::rvref< \
+ asio_true_handler_type>())) + \
+ sizeof( \
+ asio::detail::lvref< \
+ asio_true_handler_type>()( \
+ asio::detail::lvref<const asio::error_code>()), \
+ char(0))> ASIO_UNUSED_TYPEDEF
+
+#define ASIO_MOVE_ACCEPT_HANDLER_CHECK( \
+ handler_type, handler, socket_type) \
+ \
+ typedef ASIO_HANDLER_TYPE(handler_type, \
+ void(asio::error_code, socket_type)) \
+ asio_true_handler_type; \
+ \
+ ASIO_HANDLER_TYPE_REQUIREMENTS_ASSERT( \
+ sizeof(asio::detail::two_arg_move_handler_test( \
+ asio::detail::rvref< \
+ asio_true_handler_type>(), \
+ static_cast<const asio::error_code*>(0), \
+ static_cast<socket_type*>(0))) == 1, \
+ "MoveAcceptHandler type requirements not met") \
+ \
+ typedef asio::detail::handler_type_requirements< \
+ sizeof( \
+ asio::detail::argbyv( \
+ asio::detail::rvref< \
+ asio_true_handler_type>())) + \
+ sizeof( \
+ asio::detail::lvref< \
+ asio_true_handler_type>()( \
+ asio::detail::lvref<const asio::error_code>(), \
+ asio::detail::rvref<socket_type>()), \
+ char(0))> ASIO_UNUSED_TYPEDEF
+
+#define ASIO_CONNECT_HANDLER_CHECK( \
+ handler_type, handler) \
+ \
+ typedef ASIO_HANDLER_TYPE(handler_type, \
+ void(asio::error_code)) \
+ asio_true_handler_type; \
+ \
+ ASIO_HANDLER_TYPE_REQUIREMENTS_ASSERT( \
+ sizeof(asio::detail::one_arg_handler_test( \
+ asio::detail::rvref< \
+ asio_true_handler_type>(), \
+ static_cast<const asio::error_code*>(0))) == 1, \
+ "ConnectHandler type requirements not met") \
+ \
+ typedef asio::detail::handler_type_requirements< \
+ sizeof( \
+ asio::detail::argbyv( \
+ asio::detail::rvref< \
+ asio_true_handler_type>())) + \
+ sizeof( \
+ asio::detail::lvref< \
+ asio_true_handler_type>()( \
+ asio::detail::lvref<const asio::error_code>()), \
+ char(0))> ASIO_UNUSED_TYPEDEF
+
+#define ASIO_RANGE_CONNECT_HANDLER_CHECK( \
+ handler_type, handler, endpoint_type) \
+ \
+ typedef ASIO_HANDLER_TYPE(handler_type, \
+ void(asio::error_code, endpoint_type)) \
+ asio_true_handler_type; \
+ \
+ ASIO_HANDLER_TYPE_REQUIREMENTS_ASSERT( \
+ sizeof(asio::detail::two_arg_handler_test( \
+ asio::detail::rvref< \
+ asio_true_handler_type>(), \
+ static_cast<const asio::error_code*>(0), \
+ static_cast<const endpoint_type*>(0))) == 1, \
+ "RangeConnectHandler type requirements not met") \
+ \
+ typedef asio::detail::handler_type_requirements< \
+ sizeof( \
+ asio::detail::argbyv( \
+ asio::detail::rvref< \
+ asio_true_handler_type>())) + \
+ sizeof( \
+ asio::detail::lvref< \
+ asio_true_handler_type>()( \
+ asio::detail::lvref<const asio::error_code>(), \
+ asio::detail::lvref<const endpoint_type>()), \
+ char(0))> ASIO_UNUSED_TYPEDEF
+
+#define ASIO_ITERATOR_CONNECT_HANDLER_CHECK( \
+ handler_type, handler, iter_type) \
+ \
+ typedef ASIO_HANDLER_TYPE(handler_type, \
+ void(asio::error_code, iter_type)) \
+ asio_true_handler_type; \
+ \
+ ASIO_HANDLER_TYPE_REQUIREMENTS_ASSERT( \
+ sizeof(asio::detail::two_arg_handler_test( \
+ asio::detail::rvref< \
+ asio_true_handler_type>(), \
+ static_cast<const asio::error_code*>(0), \
+ static_cast<const iter_type*>(0))) == 1, \
+ "IteratorConnectHandler type requirements not met") \
+ \
+ typedef asio::detail::handler_type_requirements< \
+ sizeof( \
+ asio::detail::argbyv( \
+ asio::detail::rvref< \
+ asio_true_handler_type>())) + \
+ sizeof( \
+ asio::detail::lvref< \
+ asio_true_handler_type>()( \
+ asio::detail::lvref<const asio::error_code>(), \
+ asio::detail::lvref<const iter_type>()), \
+ char(0))> ASIO_UNUSED_TYPEDEF
+
+#define ASIO_RESOLVE_HANDLER_CHECK( \
+ handler_type, handler, range_type) \
+ \
+ typedef ASIO_HANDLER_TYPE(handler_type, \
+ void(asio::error_code, range_type)) \
+ asio_true_handler_type; \
+ \
+ ASIO_HANDLER_TYPE_REQUIREMENTS_ASSERT( \
+ sizeof(asio::detail::two_arg_handler_test( \
+ asio::detail::rvref< \
+ asio_true_handler_type>(), \
+ static_cast<const asio::error_code*>(0), \
+ static_cast<const range_type*>(0))) == 1, \
+ "ResolveHandler type requirements not met") \
+ \
+ typedef asio::detail::handler_type_requirements< \
+ sizeof( \
+ asio::detail::argbyv( \
+ asio::detail::rvref< \
+ asio_true_handler_type>())) + \
+ sizeof( \
+ asio::detail::lvref< \
+ asio_true_handler_type>()( \
+ asio::detail::lvref<const asio::error_code>(), \
+ asio::detail::lvref<const range_type>()), \
+ char(0))> ASIO_UNUSED_TYPEDEF
+
+#define ASIO_WAIT_HANDLER_CHECK( \
+ handler_type, handler) \
+ \
+ typedef ASIO_HANDLER_TYPE(handler_type, \
+ void(asio::error_code)) \
+ asio_true_handler_type; \
+ \
+ ASIO_HANDLER_TYPE_REQUIREMENTS_ASSERT( \
+ sizeof(asio::detail::one_arg_handler_test( \
+ asio::detail::rvref< \
+ asio_true_handler_type>(), \
+ static_cast<const asio::error_code*>(0))) == 1, \
+ "WaitHandler type requirements not met") \
+ \
+ typedef asio::detail::handler_type_requirements< \
+ sizeof( \
+ asio::detail::argbyv( \
+ asio::detail::rvref< \
+ asio_true_handler_type>())) + \
+ sizeof( \
+ asio::detail::lvref< \
+ asio_true_handler_type>()( \
+ asio::detail::lvref<const asio::error_code>()), \
+ char(0))> ASIO_UNUSED_TYPEDEF
+
+#define ASIO_SIGNAL_HANDLER_CHECK( \
+ handler_type, handler) \
+ \
+ typedef ASIO_HANDLER_TYPE(handler_type, \
+ void(asio::error_code, int)) \
+ asio_true_handler_type; \
+ \
+ ASIO_HANDLER_TYPE_REQUIREMENTS_ASSERT( \
+ sizeof(asio::detail::two_arg_handler_test( \
+ asio::detail::rvref< \
+ asio_true_handler_type>(), \
+ static_cast<const asio::error_code*>(0), \
+ static_cast<const int*>(0))) == 1, \
+ "SignalHandler type requirements not met") \
+ \
+ typedef asio::detail::handler_type_requirements< \
+ sizeof( \
+ asio::detail::argbyv( \
+ asio::detail::rvref< \
+ asio_true_handler_type>())) + \
+ sizeof( \
+ asio::detail::lvref< \
+ asio_true_handler_type>()( \
+ asio::detail::lvref<const asio::error_code>(), \
+ asio::detail::lvref<const int>()), \
+ char(0))> ASIO_UNUSED_TYPEDEF
+
+#define ASIO_HANDSHAKE_HANDLER_CHECK( \
+ handler_type, handler) \
+ \
+ typedef ASIO_HANDLER_TYPE(handler_type, \
+ void(asio::error_code)) \
+ asio_true_handler_type; \
+ \
+ ASIO_HANDLER_TYPE_REQUIREMENTS_ASSERT( \
+ sizeof(asio::detail::one_arg_handler_test( \
+ asio::detail::rvref< \
+ asio_true_handler_type>(), \
+ static_cast<const asio::error_code*>(0))) == 1, \
+ "HandshakeHandler type requirements not met") \
+ \
+ typedef asio::detail::handler_type_requirements< \
+ sizeof( \
+ asio::detail::argbyv( \
+ asio::detail::rvref< \
+ asio_true_handler_type>())) + \
+ sizeof( \
+ asio::detail::lvref< \
+ asio_true_handler_type>()( \
+ asio::detail::lvref<const asio::error_code>()), \
+ char(0))> ASIO_UNUSED_TYPEDEF
+
+#define ASIO_BUFFERED_HANDSHAKE_HANDLER_CHECK( \
+ handler_type, handler) \
+ \
+ typedef ASIO_HANDLER_TYPE(handler_type, \
+ void(asio::error_code, std::size_t)) \
+ asio_true_handler_type; \
+ \
+ ASIO_HANDLER_TYPE_REQUIREMENTS_ASSERT( \
+ sizeof(asio::detail::two_arg_handler_test( \
+ asio::detail::rvref< \
+ asio_true_handler_type>(), \
+ static_cast<const asio::error_code*>(0), \
+ static_cast<const std::size_t*>(0))) == 1, \
+ "BufferedHandshakeHandler type requirements not met") \
+ \
+ typedef asio::detail::handler_type_requirements< \
+ sizeof( \
+ asio::detail::argbyv( \
+ asio::detail::rvref< \
+ asio_true_handler_type>())) + \
+ sizeof( \
+ asio::detail::lvref< \
+ asio_true_handler_type>()( \
+ asio::detail::lvref<const asio::error_code>(), \
+ asio::detail::lvref<const std::size_t>()), \
+ char(0))> ASIO_UNUSED_TYPEDEF
+
+#define ASIO_SHUTDOWN_HANDLER_CHECK( \
+ handler_type, handler) \
+ \
+ typedef ASIO_HANDLER_TYPE(handler_type, \
+ void(asio::error_code)) \
+ asio_true_handler_type; \
+ \
+ ASIO_HANDLER_TYPE_REQUIREMENTS_ASSERT( \
+ sizeof(asio::detail::one_arg_handler_test( \
+ asio::detail::rvref< \
+ asio_true_handler_type>(), \
+ static_cast<const asio::error_code*>(0))) == 1, \
+ "ShutdownHandler type requirements not met") \
+ \
+ typedef asio::detail::handler_type_requirements< \
+ sizeof( \
+ asio::detail::argbyv( \
+ asio::detail::rvref< \
+ asio_true_handler_type>())) + \
+ sizeof( \
+ asio::detail::lvref< \
+ asio_true_handler_type>()( \
+ asio::detail::lvref<const asio::error_code>()), \
+ char(0))> ASIO_UNUSED_TYPEDEF
+
+#else // !defined(ASIO_ENABLE_HANDLER_TYPE_REQUIREMENTS)
+
+#define ASIO_LEGACY_COMPLETION_HANDLER_CHECK( \
+ handler_type, handler) \
+ typedef int ASIO_UNUSED_TYPEDEF
+
+#define ASIO_READ_HANDLER_CHECK( \
+ handler_type, handler) \
+ typedef int ASIO_UNUSED_TYPEDEF
+
+#define ASIO_WRITE_HANDLER_CHECK( \
+ handler_type, handler) \
+ typedef int ASIO_UNUSED_TYPEDEF
+
+#define ASIO_ACCEPT_HANDLER_CHECK( \
+ handler_type, handler) \
+ typedef int ASIO_UNUSED_TYPEDEF
+
+#define ASIO_MOVE_ACCEPT_HANDLER_CHECK( \
+ handler_type, handler, socket_type) \
+ typedef int ASIO_UNUSED_TYPEDEF
+
+#define ASIO_CONNECT_HANDLER_CHECK( \
+ handler_type, handler) \
+ typedef int ASIO_UNUSED_TYPEDEF
+
+#define ASIO_RANGE_CONNECT_HANDLER_CHECK( \
+ handler_type, handler, iter_type) \
+ typedef int ASIO_UNUSED_TYPEDEF
+
+#define ASIO_ITERATOR_CONNECT_HANDLER_CHECK( \
+ handler_type, handler, iter_type) \
+ typedef int ASIO_UNUSED_TYPEDEF
+
+#define ASIO_RESOLVE_HANDLER_CHECK( \
+ handler_type, handler, iter_type) \
+ typedef int ASIO_UNUSED_TYPEDEF
+
+#define ASIO_WAIT_HANDLER_CHECK( \
+ handler_type, handler) \
+ typedef int ASIO_UNUSED_TYPEDEF
+
+#define ASIO_SIGNAL_HANDLER_CHECK( \
+ handler_type, handler) \
+ typedef int ASIO_UNUSED_TYPEDEF
+
+#define ASIO_HANDSHAKE_HANDLER_CHECK( \
+ handler_type, handler) \
+ typedef int ASIO_UNUSED_TYPEDEF
+
+#define ASIO_BUFFERED_HANDSHAKE_HANDLER_CHECK( \
+ handler_type, handler) \
+ typedef int ASIO_UNUSED_TYPEDEF
+
+#define ASIO_SHUTDOWN_HANDLER_CHECK( \
+ handler_type, handler) \
+ typedef int ASIO_UNUSED_TYPEDEF
+
+#endif // !defined(ASIO_ENABLE_HANDLER_TYPE_REQUIREMENTS)
+
+} // namespace detail
+} // namespace asio
+
+#endif // ASIO_DETAIL_HANDLER_TYPE_REQUIREMENTS_HPP
diff --git a/lib/asio/detail/handler_work.hpp b/lib/asio/detail/handler_work.hpp
new file mode 100644
index 0000000..cce5c4b
--- /dev/null
+++ b/lib/asio/detail/handler_work.hpp
@@ -0,0 +1,95 @@
+//
+// detail/handler_work.hpp
+// ~~~~~~~~~~~~~~~~~~~~~~~
+//
+// Copyright (c) 2003-2018 Christopher M. Kohlhoff (chris at kohlhoff dot com)
+//
+// 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 ASIO_DETAIL_HANDLER_WORK_HPP
+#define ASIO_DETAIL_HANDLER_WORK_HPP
+
+#if defined(_MSC_VER) && (_MSC_VER >= 1200)
+# pragma once
+#endif // defined(_MSC_VER) && (_MSC_VER >= 1200)
+
+#include "asio/detail/config.hpp"
+#include "asio/associated_executor.hpp"
+#include "asio/detail/handler_invoke_helpers.hpp"
+
+#include "asio/detail/push_options.hpp"
+
+namespace asio {
+namespace detail {
+
+// A helper class template to allow completion handlers to be dispatched
+// through either the new executors framework or the old invocaton hook. The
+// primary template uses the new executors framework.
+template <typename Handler, typename Executor
+ = typename associated_executor<Handler>::type>
+class handler_work
+{
+public:
+ explicit handler_work(Handler& handler) ASIO_NOEXCEPT
+ : executor_(associated_executor<Handler>::get(handler))
+ {
+ }
+
+ static void start(Handler& handler) ASIO_NOEXCEPT
+ {
+ Executor ex(associated_executor<Handler>::get(handler));
+ ex.on_work_started();
+ }
+
+ ~handler_work()
+ {
+ executor_.on_work_finished();
+ }
+
+ template <typename Function>
+ void complete(Function& function, Handler& handler)
+ {
+ executor_.dispatch(ASIO_MOVE_CAST(Function)(function),
+ associated_allocator<Handler>::get(handler));
+ }
+
+private:
+ // Disallow copying and assignment.
+ handler_work(const handler_work&);
+ handler_work& operator=(const handler_work&);
+
+ typename associated_executor<Handler>::type executor_;
+};
+
+// This specialisation dispatches a handler through the old invocation hook.
+// The specialisation is not strictly required for correctness, as the
+// system_executor will dispatch through the hook anyway. However, by doing
+// this we avoid an extra copy of the handler.
+template <typename Handler>
+class handler_work<Handler, system_executor>
+{
+public:
+ explicit handler_work(Handler&) ASIO_NOEXCEPT {}
+ static void start(Handler&) ASIO_NOEXCEPT {}
+ ~handler_work() {}
+
+ template <typename Function>
+ void complete(Function& function, Handler& handler)
+ {
+ asio_handler_invoke_helpers::invoke(function, handler);
+ }
+
+private:
+ // Disallow copying and assignment.
+ handler_work(const handler_work&);
+ handler_work& operator=(const handler_work&);
+};
+
+} // namespace detail
+} // namespace asio
+
+#include "asio/detail/pop_options.hpp"
+
+#endif // ASIO_DETAIL_HANDLER_WORK_HPP
diff --git a/lib/asio/detail/hash_map.hpp b/lib/asio/detail/hash_map.hpp
new file mode 100644
index 0000000..e70970d
--- /dev/null
+++ b/lib/asio/detail/hash_map.hpp
@@ -0,0 +1,331 @@
+//
+// detail/hash_map.hpp
+// ~~~~~~~~~~~~~~~~~~~
+//
+// Copyright (c) 2003-2018 Christopher M. Kohlhoff (chris at kohlhoff dot com)
+//
+// 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 ASIO_DETAIL_HASH_MAP_HPP
+#define ASIO_DETAIL_HASH_MAP_HPP
+
+#if defined(_MSC_VER) && (_MSC_VER >= 1200)
+# pragma once
+#endif // defined(_MSC_VER) && (_MSC_VER >= 1200)
+
+#include "asio/detail/config.hpp"
+#include <list>
+#include <utility>
+#include "asio/detail/assert.hpp"
+#include "asio/detail/noncopyable.hpp"
+
+#if defined(ASIO_WINDOWS) || defined(__CYGWIN__)
+# include "asio/detail/socket_types.hpp"
+#endif // defined(ASIO_WINDOWS) || defined(__CYGWIN__)
+
+#include "asio/detail/push_options.hpp"
+
+namespace asio {
+namespace detail {
+
+inline std::size_t calculate_hash_value(int i)
+{
+ return static_cast<std::size_t>(i);
+}
+
+inline std::size_t calculate_hash_value(void* p)
+{
+ return reinterpret_cast<std::size_t>(p)
+ + (reinterpret_cast<std::size_t>(p) >> 3);
+}
+
+#if defined(ASIO_WINDOWS) || defined(__CYGWIN__)
+inline std::size_t calculate_hash_value(SOCKET s)
+{
+ return static_cast<std::size_t>(s);
+}
+#endif // defined(ASIO_WINDOWS) || defined(__CYGWIN__)
+
+// Note: assumes K and V are POD types.
+template <typename K, typename V>
+class hash_map
+ : private noncopyable
+{
+public:
+ // The type of a value in the map.
+ typedef std::pair<K, V> value_type;
+
+ // The type of a non-const iterator over the hash map.
+ typedef typename std::list<value_type>::iterator iterator;
+
+ // The type of a const iterator over the hash map.
+ typedef typename std::list<value_type>::const_iterator const_iterator;
+
+ // Constructor.
+ hash_map()
+ : size_(0),
+ buckets_(0),
+ num_buckets_(0)
+ {
+ }
+
+ // Destructor.
+ ~hash_map()
+ {
+ delete[] buckets_;
+ }
+
+ // Get an iterator for the beginning of the map.
+ iterator begin()
+ {
+ return values_.begin();
+ }
+
+ // Get an iterator for the beginning of the map.
+ const_iterator begin() const
+ {
+ return values_.begin();
+ }
+
+ // Get an iterator for the end of the map.
+ iterator end()
+ {
+ return values_.end();
+ }
+
+ // Get an iterator for the end of the map.
+ const_iterator end() const
+ {
+ return values_.end();
+ }
+
+ // Check whether the map is empty.
+ bool empty() const
+ {
+ return values_.empty();
+ }
+
+ // Find an entry in the map.
+ iterator find(const K& k)
+ {
+ if (num_buckets_)
+ {
+ size_t bucket = calculate_hash_value(k) % num_buckets_;
+ iterator it = buckets_[bucket].first;
+ if (it == values_.end())
+ return values_.end();
+ iterator end_it = buckets_[bucket].last;
+ ++end_it;
+ while (it != end_it)
+ {
+ if (it->first == k)
+ return it;
+ ++it;
+ }
+ }
+ return values_.end();
+ }
+
+ // Find an entry in the map.
+ const_iterator find(const K& k) const
+ {
+ if (num_buckets_)
+ {
+ size_t bucket = calculate_hash_value(k) % num_buckets_;
+ const_iterator it = buckets_[bucket].first;
+ if (it == values_.end())
+ return it;
+ const_iterator end_it = buckets_[bucket].last;
+ ++end_it;
+ while (it != end_it)
+ {
+ if (it->first == k)
+ return it;
+ ++it;
+ }
+ }
+ return values_.end();
+ }
+
+ // Insert a new entry into the map.
+ std::pair<iterator, bool> insert(const value_type& v)
+ {
+ if (size_ + 1 >= num_buckets_)
+ rehash(hash_size(size_ + 1));
+ size_t bucket = calculate_hash_value(v.first) % num_buckets_;
+ iterator it = buckets_[bucket].first;
+ if (it == values_.end())
+ {
+ buckets_[bucket].first = buckets_[bucket].last =
+ values_insert(values_.end(), v);
+ ++size_;
+ return std::pair<iterator, bool>(buckets_[bucket].last, true);
+ }
+ iterator end_it = buckets_[bucket].last;
+ ++end_it;
+ while (it != end_it)
+ {
+ if (it->first == v.first)
+ return std::pair<iterator, bool>(it, false);
+ ++it;
+ }
+ buckets_[bucket].last = values_insert(end_it, v);
+ ++size_;
+ return std::pair<iterator, bool>(buckets_[bucket].last, true);
+ }
+
+ // Erase an entry from the map.
+ void erase(iterator it)
+ {
+ ASIO_ASSERT(it != values_.end());
+ ASIO_ASSERT(num_buckets_ != 0);
+
+ size_t bucket = calculate_hash_value(it->first) % num_buckets_;
+ bool is_first = (it == buckets_[bucket].first);
+ bool is_last = (it == buckets_[bucket].last);
+ if (is_first && is_last)
+ buckets_[bucket].first = buckets_[bucket].last = values_.end();
+ else if (is_first)
+ ++buckets_[bucket].first;
+ else if (is_last)
+ --buckets_[bucket].last;
+
+ values_erase(it);
+ --size_;
+ }
+
+ // Erase a key from the map.
+ void erase(const K& k)
+ {
+ iterator it = find(k);
+ if (it != values_.end())
+ erase(it);
+ }
+
+ // Remove all entries from the map.
+ void clear()
+ {
+ // Clear the values.
+ values_.clear();
+ size_ = 0;
+
+ // Initialise all buckets to empty.
+ iterator end_it = values_.end();
+ for (size_t i = 0; i < num_buckets_; ++i)
+ buckets_[i].first = buckets_[i].last = end_it;
+ }
+
+private:
+ // Calculate the hash size for the specified number of elements.
+ static std::size_t hash_size(std::size_t num_elems)
+ {
+ static std::size_t sizes[] =
+ {
+#if defined(ASIO_HASH_MAP_BUCKETS)
+ ASIO_HASH_MAP_BUCKETS
+#else // ASIO_HASH_MAP_BUCKETS
+ 3, 13, 23, 53, 97, 193, 389, 769, 1543, 3079, 6151, 12289, 24593,
+ 49157, 98317, 196613, 393241, 786433, 1572869, 3145739, 6291469,
+ 12582917, 25165843
+#endif // ASIO_HASH_MAP_BUCKETS
+ };
+ const std::size_t nth_size = sizeof(sizes) / sizeof(std::size_t) - 1;
+ for (std::size_t i = 0; i < nth_size; ++i)
+ if (num_elems < sizes[i])
+ return sizes[i];
+ return sizes[nth_size];
+ }
+
+ // Re-initialise the hash from the values already contained in the list.
+ void rehash(std::size_t num_buckets)
+ {
+ if (num_buckets == num_buckets_)
+ return;
+ ASIO_ASSERT(num_buckets != 0);
+
+ iterator end_iter = values_.end();
+
+ // Update number of buckets and initialise all buckets to empty.
+ bucket_type* tmp = new bucket_type[num_buckets];
+ delete[] buckets_;
+ buckets_ = tmp;
+ num_buckets_ = num_buckets;
+ for (std::size_t i = 0; i < num_buckets_; ++i)
+ buckets_[i].first = buckets_[i].last = end_iter;
+
+ // Put all values back into the hash.
+ iterator iter = values_.begin();
+ while (iter != end_iter)
+ {
+ std::size_t bucket = calculate_hash_value(iter->first) % num_buckets_;
+ if (buckets_[bucket].last == end_iter)
+ {
+ buckets_[bucket].first = buckets_[bucket].last = iter++;
+ }
+ else if (++buckets_[bucket].last == iter)
+ {
+ ++iter;
+ }
+ else
+ {
+ values_.splice(buckets_[bucket].last, values_, iter++);
+ --buckets_[bucket].last;
+ }
+ }
+ }
+
+ // Insert an element into the values list by splicing from the spares list,
+ // if a spare is available, and otherwise by inserting a new element.
+ iterator values_insert(iterator it, const value_type& v)
+ {
+ if (spares_.empty())
+ {
+ return values_.insert(it, v);
+ }
+ else
+ {
+ spares_.front() = v;
+ values_.splice(it, spares_, spares_.begin());
+ return --it;
+ }
+ }
+
+ // Erase an element from the values list by splicing it to the spares list.
+ void values_erase(iterator it)
+ {
+ *it = value_type();
+ spares_.splice(spares_.begin(), values_, it);
+ }
+
+ // The number of elements in the hash.
+ std::size_t size_;
+
+ // The list of all values in the hash map.
+ std::list<value_type> values_;
+
+ // The list of spare nodes waiting to be recycled. Assumes that POD types only
+ // are stored in the hash map.
+ std::list<value_type> spares_;
+
+ // The type for a bucket in the hash table.
+ struct bucket_type
+ {
+ iterator first;
+ iterator last;
+ };
+
+ // The buckets in the hash.
+ bucket_type* buckets_;
+
+ // The number of buckets in the hash.
+ std::size_t num_buckets_;
+};
+
+} // namespace detail
+} // namespace asio
+
+#include "asio/detail/pop_options.hpp"
+
+#endif // ASIO_DETAIL_HASH_MAP_HPP
diff --git a/lib/asio/detail/impl/buffer_sequence_adapter.ipp b/lib/asio/detail/impl/buffer_sequence_adapter.ipp
new file mode 100644
index 0000000..323c8ad
--- /dev/null
+++ b/lib/asio/detail/impl/buffer_sequence_adapter.ipp
@@ -0,0 +1,118 @@
+//
+// detail/impl/buffer_sequence_adapter.ipp
+// ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+//
+// Copyright (c) 2003-2018 Christopher M. Kohlhoff (chris at kohlhoff dot com)
+//
+// 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 ASIO_DETAIL_IMPL_BUFFER_SEQUENCE_ADAPTER_IPP
+#define ASIO_DETAIL_IMPL_BUFFER_SEQUENCE_ADAPTER_IPP
+
+#if defined(_MSC_VER) && (_MSC_VER >= 1200)
+# pragma once
+#endif // defined(_MSC_VER) && (_MSC_VER >= 1200)
+
+#include "asio/detail/config.hpp"
+
+#if defined(ASIO_WINDOWS_RUNTIME)
+
+#include <robuffer.h>
+#include <windows.storage.streams.h>
+#include <wrl/implements.h>
+#include "asio/detail/buffer_sequence_adapter.hpp"
+
+#include "asio/detail/push_options.hpp"
+
+namespace asio {
+namespace detail {
+
+class winrt_buffer_impl :
+ public Microsoft::WRL::RuntimeClass<
+ Microsoft::WRL::RuntimeClassFlags<
+ Microsoft::WRL::RuntimeClassType::WinRtClassicComMix>,
+ ABI::Windows::Storage::Streams::IBuffer,
+ Windows::Storage::Streams::IBufferByteAccess>
+{
+public:
+ explicit winrt_buffer_impl(const asio::const_buffer& b)
+ {
+ bytes_ = const_cast<byte*>(static_cast<const byte*>(b.data()));
+ length_ = b.size();
+ capacity_ = b.size();
+ }
+
+ explicit winrt_buffer_impl(const asio::mutable_buffer& b)
+ {
+ bytes_ = static_cast<byte*>(b.data());
+ length_ = 0;
+ capacity_ = b.size();
+ }
+
+ ~winrt_buffer_impl()
+ {
+ }
+
+ STDMETHODIMP Buffer(byte** value)
+ {
+ *value = bytes_;
+ return S_OK;
+ }
+
+ STDMETHODIMP get_Capacity(UINT32* value)
+ {
+ *value = capacity_;
+ return S_OK;
+ }
+
+ STDMETHODIMP get_Length(UINT32 *value)
+ {
+ *value = length_;
+ return S_OK;
+ }
+
+ STDMETHODIMP put_Length(UINT32 value)
+ {
+ if (value > capacity_)
+ return E_INVALIDARG;
+ length_ = value;
+ return S_OK;
+ }
+
+private:
+ byte* bytes_;
+ UINT32 length_;
+ UINT32 capacity_;
+};
+
+void buffer_sequence_adapter_base::init_native_buffer(
+ buffer_sequence_adapter_base::native_buffer_type& buf,
+ const asio::mutable_buffer& buffer)
+{
+ std::memset(&buf, 0, sizeof(native_buffer_type));
+ Microsoft::WRL::ComPtr<IInspectable> insp
+ = Microsoft::WRL::Make<winrt_buffer_impl>(buffer);
+ buf = reinterpret_cast<Windows::Storage::Streams::IBuffer^>(insp.Get());
+}
+
+void buffer_sequence_adapter_base::init_native_buffer(
+ buffer_sequence_adapter_base::native_buffer_type& buf,
+ const asio::const_buffer& buffer)
+{
+ std::memset(&buf, 0, sizeof(native_buffer_type));
+ Microsoft::WRL::ComPtr<IInspectable> insp
+ = Microsoft::WRL::Make<winrt_buffer_impl>(buffer);
+ Platform::Object^ buf_obj = reinterpret_cast<Platform::Object^>(insp.Get());
+ buf = reinterpret_cast<Windows::Storage::Streams::IBuffer^>(insp.Get());
+}
+
+} // namespace detail
+} // namespace asio
+
+#include "asio/detail/pop_options.hpp"
+
+#endif // defined(ASIO_WINDOWS_RUNTIME)
+
+#endif // ASIO_DETAIL_IMPL_BUFFER_SEQUENCE_ADAPTER_IPP
diff --git a/lib/asio/detail/impl/descriptor_ops.ipp b/lib/asio/detail/impl/descriptor_ops.ipp
new file mode 100644
index 0000000..1af643f
--- /dev/null
+++ b/lib/asio/detail/impl/descriptor_ops.ipp
@@ -0,0 +1,474 @@
+//
+// detail/impl/descriptor_ops.ipp
+// ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+//
+// Copyright (c) 2003-2018 Christopher M. Kohlhoff (chris at kohlhoff dot com)
+//
+// 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 ASIO_DETAIL_IMPL_DESCRIPTOR_OPS_IPP
+#define ASIO_DETAIL_IMPL_DESCRIPTOR_OPS_IPP
+
+#if defined(_MSC_VER) && (_MSC_VER >= 1200)
+# pragma once
+#endif // defined(_MSC_VER) && (_MSC_VER >= 1200)
+
+#include "asio/detail/config.hpp"
+#include <cerrno>
+#include "asio/detail/descriptor_ops.hpp"
+#include "asio/error.hpp"
+
+#if !defined(ASIO_WINDOWS) \
+ && !defined(ASIO_WINDOWS_RUNTIME) \
+ && !defined(__CYGWIN__)
+
+#include "asio/detail/push_options.hpp"
+
+namespace asio {
+namespace detail {
+namespace descriptor_ops {
+
+int open(const char* path, int flags, asio::error_code& ec)
+{
+ errno = 0;
+ int result = error_wrapper(::open(path, flags), ec);
+ if (result >= 0)
+ ec = asio::error_code();
+ return result;
+}
+
+int close(int d, state_type& state, asio::error_code& ec)
+{
+ int result = 0;
+ if (d != -1)
+ {
+ errno = 0;
+ result = error_wrapper(::close(d), ec);
+
+ if (result != 0
+ && (ec == asio::error::would_block
+ || ec == asio::error::try_again))
+ {
+ // According to UNIX Network Programming Vol. 1, it is possible for
+ // close() to fail with EWOULDBLOCK under certain circumstances. What
+ // isn't clear is the state of the descriptor after this error. The one
+ // current OS where this behaviour is seen, Windows, says that the socket
+ // remains open. Therefore we'll put the descriptor back into blocking
+ // mode and have another attempt at closing it.
+#if defined(__SYMBIAN32__)
+ int flags = ::fcntl(d, F_GETFL, 0);
+ if (flags >= 0)
+ ::fcntl(d, F_SETFL, flags & ~O_NONBLOCK);
+#else // defined(__SYMBIAN32__)
+ ioctl_arg_type arg = 0;
+ ::ioctl(d, FIONBIO, &arg);
+#endif // defined(__SYMBIAN32__)
+ state &= ~non_blocking;
+
+ errno = 0;
+ result = error_wrapper(::close(d), ec);
+ }
+ }
+
+ if (result == 0)
+ ec = asio::error_code();
+ return result;
+}
+
+bool set_user_non_blocking(int d, state_type& state,
+ bool value, asio::error_code& ec)
+{
+ if (d == -1)
+ {
+ ec = asio::error::bad_descriptor;
+ return false;
+ }
+
+ errno = 0;
+#if defined(__SYMBIAN32__)
+ int result = error_wrapper(::fcntl(d, F_GETFL, 0), ec);
+ if (result >= 0)
+ {
+ errno = 0;
+ int flag = (value ? (result | O_NONBLOCK) : (result & ~O_NONBLOCK));
+ result = error_wrapper(::fcntl(d, F_SETFL, flag), ec);
+ }
+#else // defined(__SYMBIAN32__)
+ ioctl_arg_type arg = (value ? 1 : 0);
+ int result = error_wrapper(::ioctl(d, FIONBIO, &arg), ec);
+#endif // defined(__SYMBIAN32__)
+
+ if (result >= 0)
+ {
+ ec = asio::error_code();
+ if (value)
+ state |= user_set_non_blocking;
+ else
+ {
+ // Clearing the user-set non-blocking mode always overrides any
+ // internally-set non-blocking flag. Any subsequent asynchronous
+ // operations will need to re-enable non-blocking I/O.
+ state &= ~(user_set_non_blocking | internal_non_blocking);
+ }
+ return true;
+ }
+
+ return false;
+}
+
+bool set_internal_non_blocking(int d, state_type& state,
+ bool value, asio::error_code& ec)
+{
+ if (d == -1)
+ {
+ ec = asio::error::bad_descriptor;
+ return false;
+ }
+
+ if (!value && (state & user_set_non_blocking))
+ {
+ // It does not make sense to clear the internal non-blocking flag if the
+ // user still wants non-blocking behaviour. Return an error and let the
+ // caller figure out whether to update the user-set non-blocking flag.
+ ec = asio::error::invalid_argument;
+ return false;
+ }
+
+ errno = 0;
+#if defined(__SYMBIAN32__)
+ int result = error_wrapper(::fcntl(d, F_GETFL, 0), ec);
+ if (result >= 0)
+ {
+ errno = 0;
+ int flag = (value ? (result | O_NONBLOCK) : (result & ~O_NONBLOCK));
+ result = error_wrapper(::fcntl(d, F_SETFL, flag), ec);
+ }
+#else // defined(__SYMBIAN32__)
+ ioctl_arg_type arg = (value ? 1 : 0);
+ int result = error_wrapper(::ioctl(d, FIONBIO, &arg), ec);
+#endif // defined(__SYMBIAN32__)
+
+ if (result >= 0)
+ {
+ ec = asio::error_code();
+ if (value)
+ state |= internal_non_blocking;
+ else
+ state &= ~internal_non_blocking;
+ return true;
+ }
+
+ return false;
+}
+
+std::size_t sync_read(int d, state_type state, buf* bufs,
+ std::size_t count, bool all_empty, asio::error_code& ec)
+{
+ if (d == -1)
+ {
+ ec = asio::error::bad_descriptor;
+ return 0;
+ }
+
+ // A request to read 0 bytes on a stream is a no-op.
+ if (all_empty)
+ {
+ ec = asio::error_code();
+ return 0;
+ }
+
+ // Read some data.
+ for (;;)
+ {
+ // Try to complete the operation without blocking.
+ errno = 0;
+ signed_size_type bytes = error_wrapper(::readv(
+ d, bufs, static_cast<int>(count)), ec);
+
+ // Check if operation succeeded.
+ if (bytes > 0)
+ return bytes;
+
+ // Check for EOF.
+ if (bytes == 0)
+ {
+ ec = asio::error::eof;
+ return 0;
+ }
+
+ // Operation failed.
+ if ((state & user_set_non_blocking)
+ || (ec != asio::error::would_block
+ && ec != asio::error::try_again))
+ return 0;
+
+ // Wait for descriptor to become ready.
+ if (descriptor_ops::poll_read(d, 0, ec) < 0)
+ return 0;
+ }
+}
+
+bool non_blocking_read(int d, buf* bufs, std::size_t count,
+ asio::error_code& ec, std::size_t& bytes_transferred)
+{
+ for (;;)
+ {
+ // Read some data.
+ errno = 0;
+ signed_size_type bytes = error_wrapper(::readv(
+ d, bufs, static_cast<int>(count)), ec);
+
+ // Check for end of stream.
+ if (bytes == 0)
+ {
+ ec = asio::error::eof;
+ return true;
+ }
+
+ // Retry operation if interrupted by signal.
+ if (ec == asio::error::interrupted)
+ continue;
+
+ // Check if we need to run the operation again.
+ if (ec == asio::error::would_block
+ || ec == asio::error::try_again)
+ return false;
+
+ // Operation is complete.
+ if (bytes > 0)
+ {
+ ec = asio::error_code();
+ bytes_transferred = bytes;
+ }
+ else
+ bytes_transferred = 0;
+
+ return true;
+ }
+}
+
+std::size_t sync_write(int d, state_type state, const buf* bufs,
+ std::size_t count, bool all_empty, asio::error_code& ec)
+{
+ if (d == -1)
+ {
+ ec = asio::error::bad_descriptor;
+ return 0;
+ }
+
+ // A request to write 0 bytes on a stream is a no-op.
+ if (all_empty)
+ {
+ ec = asio::error_code();
+ return 0;
+ }
+
+ // Write some data.
+ for (;;)
+ {
+ // Try to complete the operation without blocking.
+ errno = 0;
+ signed_size_type bytes = error_wrapper(::writev(
+ d, bufs, static_cast<int>(count)), ec);
+
+ // Check if operation succeeded.
+ if (bytes > 0)
+ return bytes;
+
+ // Operation failed.
+ if ((state & user_set_non_blocking)
+ || (ec != asio::error::would_block
+ && ec != asio::error::try_again))
+ return 0;
+
+ // Wait for descriptor to become ready.
+ if (descriptor_ops::poll_write(d, 0, ec) < 0)
+ return 0;
+ }
+}
+
+bool non_blocking_write(int d, const buf* bufs, std::size_t count,
+ asio::error_code& ec, std::size_t& bytes_transferred)
+{
+ for (;;)
+ {
+ // Write some data.
+ errno = 0;
+ signed_size_type bytes = error_wrapper(::writev(
+ d, bufs, static_cast<int>(count)), ec);
+
+ // Retry operation if interrupted by signal.
+ if (ec == asio::error::interrupted)
+ continue;
+
+ // Check if we need to run the operation again.
+ if (ec == asio::error::would_block
+ || ec == asio::error::try_again)
+ return false;
+
+ // Operation is complete.
+ if (bytes >= 0)
+ {
+ ec = asio::error_code();
+ bytes_transferred = bytes;
+ }
+ else
+ bytes_transferred = 0;
+
+ return true;
+ }
+}
+
+int ioctl(int d, state_type& state, long cmd,
+ ioctl_arg_type* arg, asio::error_code& ec)
+{
+ if (d == -1)
+ {
+ ec = asio::error::bad_descriptor;
+ return -1;
+ }
+
+ errno = 0;
+ int result = error_wrapper(::ioctl(d, cmd, arg), ec);
+
+ if (result >= 0)
+ {
+ ec = asio::error_code();
+
+ // When updating the non-blocking mode we always perform the ioctl syscall,
+ // even if the flags would otherwise indicate that the descriptor is
+ // already in the correct state. This ensures that the underlying
+ // descriptor is put into the state that has been requested by the user. If
+ // the ioctl syscall was successful then we need to update the flags to
+ // match.
+ if (cmd == static_cast<long>(FIONBIO))
+ {
+ if (*arg)
+ {
+ state |= user_set_non_blocking;
+ }
+ else
+ {
+ // Clearing the non-blocking mode always overrides any internally-set
+ // non-blocking flag. Any subsequent asynchronous operations will need
+ // to re-enable non-blocking I/O.
+ state &= ~(user_set_non_blocking | internal_non_blocking);
+ }
+ }
+ }
+
+ return result;
+}
+
+int fcntl(int d, int cmd, asio::error_code& ec)
+{
+ if (d == -1)
+ {
+ ec = asio::error::bad_descriptor;
+ return -1;
+ }
+
+ errno = 0;
+ int result = error_wrapper(::fcntl(d, cmd), ec);
+ if (result != -1)
+ ec = asio::error_code();
+ return result;
+}
+
+int fcntl(int d, int cmd, long arg, asio::error_code& ec)
+{
+ if (d == -1)
+ {
+ ec = asio::error::bad_descriptor;
+ return -1;
+ }
+
+ errno = 0;
+ int result = error_wrapper(::fcntl(d, cmd, arg), ec);
+ if (result != -1)
+ ec = asio::error_code();
+ return result;
+}
+
+int poll_read(int d, state_type state, asio::error_code& ec)
+{
+ if (d == -1)
+ {
+ ec = asio::error::bad_descriptor;
+ return -1;
+ }
+
+ pollfd fds;
+ fds.fd = d;
+ fds.events = POLLIN;
+ fds.revents = 0;
+ int timeout = (state & user_set_non_blocking) ? 0 : -1;
+ errno = 0;
+ int result = error_wrapper(::poll(&fds, 1, timeout), ec);
+ if (result == 0)
+ ec = (state & user_set_non_blocking)
+ ? asio::error::would_block : asio::error_code();
+ else if (result > 0)
+ ec = asio::error_code();
+ return result;
+}
+
+int poll_write(int d, state_type state, asio::error_code& ec)
+{
+ if (d == -1)
+ {
+ ec = asio::error::bad_descriptor;
+ return -1;
+ }
+
+ pollfd fds;
+ fds.fd = d;
+ fds.events = POLLOUT;
+ fds.revents = 0;
+ int timeout = (state & user_set_non_blocking) ? 0 : -1;
+ errno = 0;
+ int result = error_wrapper(::poll(&fds, 1, timeout), ec);
+ if (result == 0)
+ ec = (state & user_set_non_blocking)
+ ? asio::error::would_block : asio::error_code();
+ else if (result > 0)
+ ec = asio::error_code();
+ return result;
+}
+
+int poll_error(int d, state_type state, asio::error_code& ec)
+{
+ if (d == -1)
+ {
+ ec = asio::error::bad_descriptor;
+ return -1;
+ }
+
+ pollfd fds;
+ fds.fd = d;
+ fds.events = POLLPRI | POLLERR | POLLHUP;
+ fds.revents = 0;
+ int timeout = (state & user_set_non_blocking) ? 0 : -1;
+ errno = 0;
+ int result = error_wrapper(::poll(&fds, 1, timeout), ec);
+ if (result == 0)
+ ec = (state & user_set_non_blocking)
+ ? asio::error::would_block : asio::error_code();
+ else if (result > 0)
+ ec = asio::error_code();
+ return result;
+}
+
+} // namespace descriptor_ops
+} // namespace detail
+} // namespace asio
+
+#include "asio/detail/pop_options.hpp"
+
+#endif // !defined(ASIO_WINDOWS)
+ // && !defined(ASIO_WINDOWS_RUNTIME)
+ // && !defined(__CYGWIN__)
+
+#endif // ASIO_DETAIL_IMPL_DESCRIPTOR_OPS_IPP
diff --git a/lib/asio/detail/impl/dev_poll_reactor.hpp b/lib/asio/detail/impl/dev_poll_reactor.hpp
new file mode 100644
index 0000000..4cd8aaf
--- /dev/null
+++ b/lib/asio/detail/impl/dev_poll_reactor.hpp
@@ -0,0 +1,91 @@
+//
+// detail/impl/dev_poll_reactor.hpp
+// ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+//
+// Copyright (c) 2003-2018 Christopher M. Kohlhoff (chris at kohlhoff dot com)
+//
+// 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 ASIO_DETAIL_IMPL_DEV_POLL_REACTOR_HPP
+#define ASIO_DETAIL_IMPL_DEV_POLL_REACTOR_HPP
+
+#if defined(_MSC_VER) && (_MSC_VER >= 1200)
+# pragma once
+#endif // defined(_MSC_VER) && (_MSC_VER >= 1200)
+
+#include "asio/detail/config.hpp"
+
+#if defined(ASIO_HAS_DEV_POLL)
+
+#include "asio/detail/push_options.hpp"
+
+namespace asio {
+namespace detail {
+
+template <typename Time_Traits>
+void dev_poll_reactor::add_timer_queue(timer_queue<Time_Traits>& queue)
+{
+ do_add_timer_queue(queue);
+}
+
+template <typename Time_Traits>
+void dev_poll_reactor::remove_timer_queue(timer_queue<Time_Traits>& queue)
+{
+ do_remove_timer_queue(queue);
+}
+
+template <typename Time_Traits>
+void dev_poll_reactor::schedule_timer(timer_queue<Time_Traits>& queue,
+ const typename Time_Traits::time_type& time,
+ typename timer_queue<Time_Traits>::per_timer_data& timer, wait_op* op)
+{
+ asio::detail::mutex::scoped_lock lock(mutex_);
+
+ if (shutdown_)
+ {
+ scheduler_.post_immediate_completion(op, false);
+ return;
+ }
+
+ bool earliest = queue.enqueue_timer(time, timer, op);
+ scheduler_.work_started();
+ if (earliest)
+ interrupter_.interrupt();
+}
+
+template <typename Time_Traits>
+std::size_t dev_poll_reactor::cancel_timer(timer_queue<Time_Traits>& queue,
+ typename timer_queue<Time_Traits>::per_timer_data& timer,
+ std::size_t max_cancelled)
+{
+ asio::detail::mutex::scoped_lock lock(mutex_);
+ op_queue<operation> ops;
+ std::size_t n = queue.cancel_timer(timer, ops, max_cancelled);
+ lock.unlock();
+ scheduler_.post_deferred_completions(ops);
+ return n;
+}
+
+template <typename Time_Traits>
+void dev_poll_reactor::move_timer(timer_queue<Time_Traits>& queue,
+ typename timer_queue<Time_Traits>::per_timer_data& target,
+ typename timer_queue<Time_Traits>::per_timer_data& source)
+{
+ asio::detail::mutex::scoped_lock lock(mutex_);
+ op_queue<operation> ops;
+ queue.cancel_timer(target, ops);
+ queue.move_timer(target, source);
+ lock.unlock();
+ scheduler_.post_deferred_completions(ops);
+}
+
+} // namespace detail
+} // namespace asio
+
+#include "asio/detail/pop_options.hpp"
+
+#endif // defined(ASIO_HAS_DEV_POLL)
+
+#endif // ASIO_DETAIL_IMPL_DEV_POLL_REACTOR_HPP
diff --git a/lib/asio/detail/impl/dev_poll_reactor.ipp b/lib/asio/detail/impl/dev_poll_reactor.ipp
new file mode 100644
index 0000000..1ca376c
--- /dev/null
+++ b/lib/asio/detail/impl/dev_poll_reactor.ipp
@@ -0,0 +1,446 @@
+//
+// detail/impl/dev_poll_reactor.ipp
+// ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+//
+// Copyright (c) 2003-2018 Christopher M. Kohlhoff (chris at kohlhoff dot com)
+//
+// 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 ASIO_DETAIL_IMPL_DEV_POLL_REACTOR_IPP
+#define ASIO_DETAIL_IMPL_DEV_POLL_REACTOR_IPP
+
+#if defined(_MSC_VER) && (_MSC_VER >= 1200)
+# pragma once
+#endif // defined(_MSC_VER) && (_MSC_VER >= 1200)
+
+#include "asio/detail/config.hpp"
+
+#if defined(ASIO_HAS_DEV_POLL)
+
+#include "asio/detail/dev_poll_reactor.hpp"
+#include "asio/detail/assert.hpp"
+#include "asio/detail/throw_error.hpp"
+#include "asio/error.hpp"
+
+#include "asio/detail/push_options.hpp"
+
+namespace asio {
+namespace detail {
+
+dev_poll_reactor::dev_poll_reactor(asio::execution_context& ctx)
+ : asio::detail::execution_context_service_base<dev_poll_reactor>(ctx),
+ scheduler_(use_service<scheduler>(ctx)),
+ mutex_(),
+ dev_poll_fd_(do_dev_poll_create()),
+ interrupter_(),
+ shutdown_(false)
+{
+ // Add the interrupter's descriptor to /dev/poll.
+ ::pollfd ev = { 0, 0, 0 };
+ ev.fd = interrupter_.read_descriptor();
+ ev.events = POLLIN | POLLERR;
+ ev.revents = 0;
+ ::write(dev_poll_fd_, &ev, sizeof(ev));
+}
+
+dev_poll_reactor::~dev_poll_reactor()
+{
+ shutdown();
+ ::close(dev_poll_fd_);
+}
+
+void dev_poll_reactor::shutdown()
+{
+ asio::detail::mutex::scoped_lock lock(mutex_);
+ shutdown_ = true;
+ lock.unlock();
+
+ op_queue<operation> ops;
+
+ for (int i = 0; i < max_ops; ++i)
+ op_queue_[i].get_all_operations(ops);
+
+ timer_queues_.get_all_timers(ops);
+
+ scheduler_.abandon_operations(ops);
+}
+
+void dev_poll_reactor::notify_fork(
+ asio::execution_context::fork_event fork_ev)
+{
+ if (fork_ev == asio::execution_context::fork_child)
+ {
+ detail::mutex::scoped_lock lock(mutex_);
+
+ if (dev_poll_fd_ != -1)
+ ::close(dev_poll_fd_);
+ dev_poll_fd_ = -1;
+ dev_poll_fd_ = do_dev_poll_create();
+
+ interrupter_.recreate();
+
+ // Add the interrupter's descriptor to /dev/poll.
+ ::pollfd ev = { 0, 0, 0 };
+ ev.fd = interrupter_.read_descriptor();
+ ev.events = POLLIN | POLLERR;
+ ev.revents = 0;
+ ::write(dev_poll_fd_, &ev, sizeof(ev));
+
+ // Re-register all descriptors with /dev/poll. The changes will be written
+ // to the /dev/poll descriptor the next time the reactor is run.
+ for (int i = 0; i < max_ops; ++i)
+ {
+ reactor_op_queue<socket_type>::iterator iter = op_queue_[i].begin();
+ reactor_op_queue<socket_type>::iterator end = op_queue_[i].end();
+ for (; iter != end; ++iter)
+ {
+ ::pollfd& pending_ev = add_pending_event_change(iter->first);
+ pending_ev.events |= POLLERR | POLLHUP;
+ switch (i)
+ {
+ case read_op: pending_ev.events |= POLLIN; break;
+ case write_op: pending_ev.events |= POLLOUT; break;
+ case except_op: pending_ev.events |= POLLPRI; break;
+ default: break;
+ }
+ }
+ }
+ interrupter_.interrupt();
+ }
+}
+
+void dev_poll_reactor::init_task()
+{
+ scheduler_.init_task();
+}
+
+int dev_poll_reactor::register_descriptor(socket_type, per_descriptor_data&)
+{
+ return 0;
+}
+
+int dev_poll_reactor::register_internal_descriptor(int op_type,
+ socket_type descriptor, per_descriptor_data&, reactor_op* op)
+{
+ asio::detail::mutex::scoped_lock lock(mutex_);
+
+ op_queue_[op_type].enqueue_operation(descriptor, op);
+ ::pollfd& ev = add_pending_event_change(descriptor);
+ ev.events = POLLERR | POLLHUP;
+ switch (op_type)
+ {
+ case read_op: ev.events |= POLLIN; break;
+ case write_op: ev.events |= POLLOUT; break;
+ case except_op: ev.events |= POLLPRI; break;
+ default: break;
+ }
+ interrupter_.interrupt();
+
+ return 0;
+}
+
+void dev_poll_reactor::move_descriptor(socket_type,
+ dev_poll_reactor::per_descriptor_data&,
+ dev_poll_reactor::per_descriptor_data&)
+{
+}
+
+void dev_poll_reactor::start_op(int op_type, socket_type descriptor,
+ dev_poll_reactor::per_descriptor_data&, reactor_op* op,
+ bool is_continuation, bool allow_speculative)
+{
+ asio::detail::mutex::scoped_lock lock(mutex_);
+
+ if (shutdown_)
+ {
+ post_immediate_completion(op, is_continuation);
+ return;
+ }
+
+ if (allow_speculative)
+ {
+ if (op_type != read_op || !op_queue_[except_op].has_operation(descriptor))
+ {
+ if (!op_queue_[op_type].has_operation(descriptor))
+ {
+ if (op->perform())
+ {
+ lock.unlock();
+ scheduler_.post_immediate_completion(op, is_continuation);
+ return;
+ }
+ }
+ }
+ }
+
+ bool first = op_queue_[op_type].enqueue_operation(descriptor, op);
+ scheduler_.work_started();
+ if (first)
+ {
+ ::pollfd& ev = add_pending_event_change(descriptor);
+ ev.events = POLLERR | POLLHUP;
+ if (op_type == read_op
+ || op_queue_[read_op].has_operation(descriptor))
+ ev.events |= POLLIN;
+ if (op_type == write_op
+ || op_queue_[write_op].has_operation(descriptor))
+ ev.events |= POLLOUT;
+ if (op_type == except_op
+ || op_queue_[except_op].has_operation(descriptor))
+ ev.events |= POLLPRI;
+ interrupter_.interrupt();
+ }
+}
+
+void dev_poll_reactor::cancel_ops(socket_type descriptor,
+ dev_poll_reactor::per_descriptor_data&)
+{
+ asio::detail::mutex::scoped_lock lock(mutex_);
+ cancel_ops_unlocked(descriptor, asio::error::operation_aborted);
+}
+
+void dev_poll_reactor::deregister_descriptor(socket_type descriptor,
+ dev_poll_reactor::per_descriptor_data&, bool)
+{
+ asio::detail::mutex::scoped_lock lock(mutex_);
+
+ // Remove the descriptor from /dev/poll.
+ ::pollfd& ev = add_pending_event_change(descriptor);
+ ev.events = POLLREMOVE;
+ interrupter_.interrupt();
+
+ // Cancel any outstanding operations associated with the descriptor.
+ cancel_ops_unlocked(descriptor, asio::error::operation_aborted);
+}
+
+void dev_poll_reactor::deregister_internal_descriptor(
+ socket_type descriptor, dev_poll_reactor::per_descriptor_data&)
+{
+ asio::detail::mutex::scoped_lock lock(mutex_);
+
+ // Remove the descriptor from /dev/poll. Since this function is only called
+ // during a fork, we can apply the change immediately.
+ ::pollfd ev = { 0, 0, 0 };
+ ev.fd = descriptor;
+ ev.events = POLLREMOVE;
+ ev.revents = 0;
+ ::write(dev_poll_fd_, &ev, sizeof(ev));
+
+ // Destroy all operations associated with the descriptor.
+ op_queue<operation> ops;
+ asio::error_code ec;
+ for (int i = 0; i < max_ops; ++i)
+ op_queue_[i].cancel_operations(descriptor, ops, ec);
+}
+
+void dev_poll_reactor::cleanup_descriptor_data(
+ dev_poll_reactor::per_descriptor_data&)
+{
+}
+
+void dev_poll_reactor::run(long usec, op_queue<operation>& ops)
+{
+ asio::detail::mutex::scoped_lock lock(mutex_);
+
+ // We can return immediately if there's no work to do and the reactor is
+ // not supposed to block.
+ if (usec == 0 && op_queue_[read_op].empty() && op_queue_[write_op].empty()
+ && op_queue_[except_op].empty() && timer_queues_.all_empty())
+ return;
+
+ // Write the pending event registration changes to the /dev/poll descriptor.
+ std::size_t events_size = sizeof(::pollfd) * pending_event_changes_.size();
+ if (events_size > 0)
+ {
+ errno = 0;
+ int result = ::write(dev_poll_fd_,
+ &pending_event_changes_[0], events_size);
+ if (result != static_cast<int>(events_size))
+ {
+ asio::error_code ec = asio::error_code(
+ errno, asio::error::get_system_category());
+ for (std::size_t i = 0; i < pending_event_changes_.size(); ++i)
+ {
+ int descriptor = pending_event_changes_[i].fd;
+ for (int j = 0; j < max_ops; ++j)
+ op_queue_[j].cancel_operations(descriptor, ops, ec);
+ }
+ }
+ pending_event_changes_.clear();
+ pending_event_change_index_.clear();
+ }
+
+ // Calculate timeout.
+ int timeout;
+ if (usec == 0)
+ timeout = 0;
+ else
+ {
+ timeout = (usec < 0) ? -1 : ((usec - 1) / 1000 + 1);
+ timeout = get_timeout(timeout);
+ }
+ lock.unlock();
+
+ // Block on the /dev/poll descriptor.
+ ::pollfd events[128] = { { 0, 0, 0 } };
+ ::dvpoll dp = { 0, 0, 0 };
+ dp.dp_fds = events;
+ dp.dp_nfds = 128;
+ dp.dp_timeout = timeout;
+ int num_events = ::ioctl(dev_poll_fd_, DP_POLL, &dp);
+
+ lock.lock();
+
+ // Dispatch the waiting events.
+ for (int i = 0; i < num_events; ++i)
+ {
+ int descriptor = events[i].fd;
+ if (descriptor == interrupter_.read_descriptor())
+ {
+ interrupter_.reset();
+ }
+ else
+ {
+ bool more_reads = false;
+ bool more_writes = false;
+ bool more_except = false;
+
+ // Exception operations must be processed first to ensure that any
+ // out-of-band data is read before normal data.
+ if (events[i].events & (POLLPRI | POLLERR | POLLHUP))
+ more_except =
+ op_queue_[except_op].perform_operations(descriptor, ops);
+ else
+ more_except = op_queue_[except_op].has_operation(descriptor);
+
+ if (events[i].events & (POLLIN | POLLERR | POLLHUP))
+ more_reads = op_queue_[read_op].perform_operations(descriptor, ops);
+ else
+ more_reads = op_queue_[read_op].has_operation(descriptor);
+
+ if (events[i].events & (POLLOUT | POLLERR | POLLHUP))
+ more_writes = op_queue_[write_op].perform_operations(descriptor, ops);
+ else
+ more_writes = op_queue_[write_op].has_operation(descriptor);
+
+ if ((events[i].events & (POLLERR | POLLHUP)) != 0
+ && !more_except && !more_reads && !more_writes)
+ {
+ // If we have an event and no operations associated with the
+ // descriptor then we need to delete the descriptor from /dev/poll.
+ // The poll operation can produce POLLHUP or POLLERR events when there
+ // is no operation pending, so if we do not remove the descriptor we
+ // can end up in a tight polling loop.
+ ::pollfd ev = { 0, 0, 0 };
+ ev.fd = descriptor;
+ ev.events = POLLREMOVE;
+ ev.revents = 0;
+ ::write(dev_poll_fd_, &ev, sizeof(ev));
+ }
+ else
+ {
+ ::pollfd ev = { 0, 0, 0 };
+ ev.fd = descriptor;
+ ev.events = POLLERR | POLLHUP;
+ if (more_reads)
+ ev.events |= POLLIN;
+ if (more_writes)
+ ev.events |= POLLOUT;
+ if (more_except)
+ ev.events |= POLLPRI;
+ ev.revents = 0;
+ int result = ::write(dev_poll_fd_, &ev, sizeof(ev));
+ if (result != sizeof(ev))
+ {
+ asio::error_code ec(errno,
+ asio::error::get_system_category());
+ for (int j = 0; j < max_ops; ++j)
+ op_queue_[j].cancel_operations(descriptor, ops, ec);
+ }
+ }
+ }
+ }
+ timer_queues_.get_ready_timers(ops);
+}
+
+void dev_poll_reactor::interrupt()
+{
+ interrupter_.interrupt();
+}
+
+int dev_poll_reactor::do_dev_poll_create()
+{
+ int fd = ::open("/dev/poll", O_RDWR);
+ if (fd == -1)
+ {
+ asio::error_code ec(errno,
+ asio::error::get_system_category());
+ asio::detail::throw_error(ec, "/dev/poll");
+ }
+ return fd;
+}
+
+void dev_poll_reactor::do_add_timer_queue(timer_queue_base& queue)
+{
+ mutex::scoped_lock lock(mutex_);
+ timer_queues_.insert(&queue);
+}
+
+void dev_poll_reactor::do_remove_timer_queue(timer_queue_base& queue)
+{
+ mutex::scoped_lock lock(mutex_);
+ timer_queues_.erase(&queue);
+}
+
+int dev_poll_reactor::get_timeout(int msec)
+{
+ // By default we will wait no longer than 5 minutes. This will ensure that
+ // any changes to the system clock are detected after no longer than this.
+ const int max_msec = 5 * 60 * 1000;
+ return timer_queues_.wait_duration_msec(
+ (msec < 0 || max_msec < msec) ? max_msec : msec);
+}
+
+void dev_poll_reactor::cancel_ops_unlocked(socket_type descriptor,
+ const asio::error_code& ec)
+{
+ bool need_interrupt = false;
+ op_queue<operation> ops;
+ for (int i = 0; i < max_ops; ++i)
+ need_interrupt = op_queue_[i].cancel_operations(
+ descriptor, ops, ec) || need_interrupt;
+ scheduler_.post_deferred_completions(ops);
+ if (need_interrupt)
+ interrupter_.interrupt();
+}
+
+::pollfd& dev_poll_reactor::add_pending_event_change(int descriptor)
+{
+ hash_map<int, std::size_t>::iterator iter
+ = pending_event_change_index_.find(descriptor);
+ if (iter == pending_event_change_index_.end())
+ {
+ std::size_t index = pending_event_changes_.size();
+ pending_event_changes_.reserve(pending_event_changes_.size() + 1);
+ pending_event_change_index_.insert(std::make_pair(descriptor, index));
+ pending_event_changes_.push_back(::pollfd());
+ pending_event_changes_[index].fd = descriptor;
+ pending_event_changes_[index].revents = 0;
+ return pending_event_changes_[index];
+ }
+ else
+ {
+ return pending_event_changes_[iter->second];
+ }
+}
+
+} // namespace detail
+} // namespace asio
+
+#include "asio/detail/pop_options.hpp"
+
+#endif // defined(ASIO_HAS_DEV_POLL)
+
+#endif // ASIO_DETAIL_IMPL_DEV_POLL_REACTOR_IPP
diff --git a/lib/asio/detail/impl/epoll_reactor.hpp b/lib/asio/detail/impl/epoll_reactor.hpp
new file mode 100644
index 0000000..f990059
--- /dev/null
+++ b/lib/asio/detail/impl/epoll_reactor.hpp
@@ -0,0 +1,89 @@
+//
+// detail/impl/epoll_reactor.hpp
+// ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+//
+// Copyright (c) 2003-2018 Christopher M. Kohlhoff (chris at kohlhoff dot com)
+//
+// 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 ASIO_DETAIL_IMPL_EPOLL_REACTOR_HPP
+#define ASIO_DETAIL_IMPL_EPOLL_REACTOR_HPP
+
+#if defined(_MSC_VER) && (_MSC_VER >= 1200)
+# pragma once
+#endif // defined(_MSC_VER) && (_MSC_VER >= 1200)
+
+#if defined(ASIO_HAS_EPOLL)
+
+#include "asio/detail/push_options.hpp"
+
+namespace asio {
+namespace detail {
+
+template <typename Time_Traits>
+void epoll_reactor::add_timer_queue(timer_queue<Time_Traits>& queue)
+{
+ do_add_timer_queue(queue);
+}
+
+template <typename Time_Traits>
+void epoll_reactor::remove_timer_queue(timer_queue<Time_Traits>& queue)
+{
+ do_remove_timer_queue(queue);
+}
+
+template <typename Time_Traits>
+void epoll_reactor::schedule_timer(timer_queue<Time_Traits>& queue,
+ const typename Time_Traits::time_type& time,
+ typename timer_queue<Time_Traits>::per_timer_data& timer, wait_op* op)
+{
+ mutex::scoped_lock lock(mutex_);
+
+ if (shutdown_)
+ {
+ scheduler_.post_immediate_completion(op, false);
+ return;
+ }
+
+ bool earliest = queue.enqueue_timer(time, timer, op);
+ scheduler_.work_started();
+ if (earliest)
+ update_timeout();
+}
+
+template <typename Time_Traits>
+std::size_t epoll_reactor::cancel_timer(timer_queue<Time_Traits>& queue,
+ typename timer_queue<Time_Traits>::per_timer_data& timer,
+ std::size_t max_cancelled)
+{
+ mutex::scoped_lock lock(mutex_);
+ op_queue<operation> ops;
+ std::size_t n = queue.cancel_timer(timer, ops, max_cancelled);
+ lock.unlock();
+ scheduler_.post_deferred_completions(ops);
+ return n;
+}
+
+template <typename Time_Traits>
+void epoll_reactor::move_timer(timer_queue<Time_Traits>& queue,
+ typename timer_queue<Time_Traits>::per_timer_data& target,
+ typename timer_queue<Time_Traits>::per_timer_data& source)
+{
+ mutex::scoped_lock lock(mutex_);
+ op_queue<operation> ops;
+ queue.cancel_timer(target, ops);
+ queue.move_timer(target, source);
+ lock.unlock();
+ scheduler_.post_deferred_completions(ops);
+}
+
+} // namespace detail
+} // namespace asio
+
+#include "asio/detail/pop_options.hpp"
+
+#endif // defined(ASIO_HAS_EPOLL)
+
+#endif // ASIO_DETAIL_IMPL_EPOLL_REACTOR_HPP
diff --git a/lib/asio/detail/impl/epoll_reactor.ipp b/lib/asio/detail/impl/epoll_reactor.ipp
new file mode 100644
index 0000000..65584a4
--- /dev/null
+++ b/lib/asio/detail/impl/epoll_reactor.ipp
@@ -0,0 +1,787 @@
+//
+// detail/impl/epoll_reactor.ipp
+// ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+//
+// Copyright (c) 2003-2018 Christopher M. Kohlhoff (chris at kohlhoff dot com)
+//
+// 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 ASIO_DETAIL_IMPL_EPOLL_REACTOR_IPP
+#define ASIO_DETAIL_IMPL_EPOLL_REACTOR_IPP
+
+#if defined(_MSC_VER) && (_MSC_VER >= 1200)
+# pragma once
+#endif // defined(_MSC_VER) && (_MSC_VER >= 1200)
+
+#include "asio/detail/config.hpp"
+
+#if defined(ASIO_HAS_EPOLL)
+
+#include <cstddef>
+#include <sys/epoll.h>
+#include "asio/detail/epoll_reactor.hpp"
+#include "asio/detail/throw_error.hpp"
+#include "asio/error.hpp"
+
+#if defined(ASIO_HAS_TIMERFD)
+# include <sys/timerfd.h>
+#endif // defined(ASIO_HAS_TIMERFD)
+
+#include "asio/detail/push_options.hpp"
+
+namespace asio {
+namespace detail {
+
+epoll_reactor::epoll_reactor(asio::execution_context& ctx)
+ : execution_context_service_base<epoll_reactor>(ctx),
+ scheduler_(use_service<scheduler>(ctx)),
+ mutex_(ASIO_CONCURRENCY_HINT_IS_LOCKING(
+ REACTOR_REGISTRATION, scheduler_.concurrency_hint())),
+ interrupter_(),
+ epoll_fd_(do_epoll_create()),
+ timer_fd_(do_timerfd_create()),
+ shutdown_(false),
+ registered_descriptors_mutex_(mutex_.enabled())
+{
+ // Add the interrupter's descriptor to epoll.
+ epoll_event ev = { 0, { 0 } };
+ ev.events = EPOLLIN | EPOLLERR | EPOLLET;
+ ev.data.ptr = &interrupter_;
+ epoll_ctl(epoll_fd_, EPOLL_CTL_ADD, interrupter_.read_descriptor(), &ev);
+ interrupter_.interrupt();
+
+ // Add the timer descriptor to epoll.
+ if (timer_fd_ != -1)
+ {
+ ev.events = EPOLLIN | EPOLLERR;
+ ev.data.ptr = &timer_fd_;
+ epoll_ctl(epoll_fd_, EPOLL_CTL_ADD, timer_fd_, &ev);
+ }
+}
+
+epoll_reactor::~epoll_reactor()
+{
+ if (epoll_fd_ != -1)
+ close(epoll_fd_);
+ if (timer_fd_ != -1)
+ close(timer_fd_);
+}
+
+void epoll_reactor::shutdown()
+{
+ mutex::scoped_lock lock(mutex_);
+ shutdown_ = true;
+ lock.unlock();
+
+ op_queue<operation> ops;
+
+ while (descriptor_state* state = registered_descriptors_.first())
+ {
+ for (int i = 0; i < max_ops; ++i)
+ ops.push(state->op_queue_[i]);
+ state->shutdown_ = true;
+ registered_descriptors_.free(state);
+ }
+
+ timer_queues_.get_all_timers(ops);
+
+ scheduler_.abandon_operations(ops);
+}
+
+void epoll_reactor::notify_fork(
+ asio::execution_context::fork_event fork_ev)
+{
+ if (fork_ev == asio::execution_context::fork_child)
+ {
+ if (epoll_fd_ != -1)
+ ::close(epoll_fd_);
+ epoll_fd_ = -1;
+ epoll_fd_ = do_epoll_create();
+
+ if (timer_fd_ != -1)
+ ::close(timer_fd_);
+ timer_fd_ = -1;
+ timer_fd_ = do_timerfd_create();
+
+ interrupter_.recreate();
+
+ // Add the interrupter's descriptor to epoll.
+ epoll_event ev = { 0, { 0 } };
+ ev.events = EPOLLIN | EPOLLERR | EPOLLET;
+ ev.data.ptr = &interrupter_;
+ epoll_ctl(epoll_fd_, EPOLL_CTL_ADD, interrupter_.read_descriptor(), &ev);
+ interrupter_.interrupt();
+
+ // Add the timer descriptor to epoll.
+ if (timer_fd_ != -1)
+ {
+ ev.events = EPOLLIN | EPOLLERR;
+ ev.data.ptr = &timer_fd_;
+ epoll_ctl(epoll_fd_, EPOLL_CTL_ADD, timer_fd_, &ev);
+ }
+
+ update_timeout();
+
+ // Re-register all descriptors with epoll.
+ mutex::scoped_lock descriptors_lock(registered_descriptors_mutex_);
+ for (descriptor_state* state = registered_descriptors_.first();
+ state != 0; state = state->next_)
+ {
+ ev.events = state->registered_events_;
+ ev.data.ptr = state;
+ int result = epoll_ctl(epoll_fd_, EPOLL_CTL_ADD, state->descriptor_, &ev);
+ if (result != 0)
+ {
+ asio::error_code ec(errno,
+ asio::error::get_system_category());
+ asio::detail::throw_error(ec, "epoll re-registration");
+ }
+ }
+ }
+}
+
+void epoll_reactor::init_task()
+{
+ scheduler_.init_task();
+}
+
+int epoll_reactor::register_descriptor(socket_type descriptor,
+ epoll_reactor::per_descriptor_data& descriptor_data)
+{
+ descriptor_data = allocate_descriptor_state();
+
+ ASIO_HANDLER_REACTOR_REGISTRATION((
+ context(), static_cast<uintmax_t>(descriptor),
+ reinterpret_cast<uintmax_t>(descriptor_data)));
+
+ {
+ mutex::scoped_lock descriptor_lock(descriptor_data->mutex_);
+
+ descriptor_data->reactor_ = this;
+ descriptor_data->descriptor_ = descriptor;
+ descriptor_data->shutdown_ = false;
+ for (int i = 0; i < max_ops; ++i)
+ descriptor_data->try_speculative_[i] = true;
+ }
+
+ epoll_event ev = { 0, { 0 } };
+ ev.events = EPOLLIN | EPOLLERR | EPOLLHUP | EPOLLPRI | EPOLLET;
+ descriptor_data->registered_events_ = ev.events;
+ ev.data.ptr = descriptor_data;
+ int result = epoll_ctl(epoll_fd_, EPOLL_CTL_ADD, descriptor, &ev);
+ if (result != 0)
+ {
+ if (errno == EPERM)
+ {
+ // This file descriptor type is not supported by epoll. However, if it is
+ // a regular file then operations on it will not block. We will allow
+ // this descriptor to be used and fail later if an operation on it would
+ // otherwise require a trip through the reactor.
+ descriptor_data->registered_events_ = 0;
+ return 0;
+ }
+ return errno;
+ }
+
+ return 0;
+}
+
+int epoll_reactor::register_internal_descriptor(
+ int op_type, socket_type descriptor,
+ epoll_reactor::per_descriptor_data& descriptor_data, reactor_op* op)
+{
+ descriptor_data = allocate_descriptor_state();
+
+ ASIO_HANDLER_REACTOR_REGISTRATION((
+ context(), static_cast<uintmax_t>(descriptor),
+ reinterpret_cast<uintmax_t>(descriptor_data)));
+
+ {
+ mutex::scoped_lock descriptor_lock(descriptor_data->mutex_);
+
+ descriptor_data->reactor_ = this;
+ descriptor_data->descriptor_ = descriptor;
+ descriptor_data->shutdown_ = false;
+ descriptor_data->op_queue_[op_type].push(op);
+ for (int i = 0; i < max_ops; ++i)
+ descriptor_data->try_speculative_[i] = true;
+ }
+
+ epoll_event ev = { 0, { 0 } };
+ ev.events = EPOLLIN | EPOLLERR | EPOLLHUP | EPOLLPRI | EPOLLET;
+ descriptor_data->registered_events_ = ev.events;
+ ev.data.ptr = descriptor_data;
+ int result = epoll_ctl(epoll_fd_, EPOLL_CTL_ADD, descriptor, &ev);
+ if (result != 0)
+ return errno;
+
+ return 0;
+}
+
+void epoll_reactor::move_descriptor(socket_type,
+ epoll_reactor::per_descriptor_data& target_descriptor_data,
+ epoll_reactor::per_descriptor_data& source_descriptor_data)
+{
+ target_descriptor_data = source_descriptor_data;
+ source_descriptor_data = 0;
+}
+
+void epoll_reactor::start_op(int op_type, socket_type descriptor,
+ epoll_reactor::per_descriptor_data& descriptor_data, reactor_op* op,
+ bool is_continuation, bool allow_speculative)
+{
+ if (!descriptor_data)
+ {
+ op->ec_ = asio::error::bad_descriptor;
+ post_immediate_completion(op, is_continuation);
+ return;
+ }
+
+ mutex::scoped_lock descriptor_lock(descriptor_data->mutex_);
+
+ if (descriptor_data->shutdown_)
+ {
+ post_immediate_completion(op, is_continuation);
+ return;
+ }
+
+ if (descriptor_data->op_queue_[op_type].empty())
+ {
+ if (allow_speculative
+ && (op_type != read_op
+ || descriptor_data->op_queue_[except_op].empty()))
+ {
+ if (descriptor_data->try_speculative_[op_type])
+ {
+ if (reactor_op::status status = op->perform())
+ {
+ if (status == reactor_op::done_and_exhausted)
+ if (descriptor_data->registered_events_ != 0)
+ descriptor_data->try_speculative_[op_type] = false;
+ descriptor_lock.unlock();
+ scheduler_.post_immediate_completion(op, is_continuation);
+ return;
+ }
+ }
+
+ if (descriptor_data->registered_events_ == 0)
+ {
+ op->ec_ = asio::error::operation_not_supported;
+ scheduler_.post_immediate_completion(op, is_continuation);
+ return;
+ }
+
+ if (op_type == write_op)
+ {
+ if ((descriptor_data->registered_events_ & EPOLLOUT) == 0)
+ {
+ epoll_event ev = { 0, { 0 } };
+ ev.events = descriptor_data->registered_events_ | EPOLLOUT;
+ ev.data.ptr = descriptor_data;
+ if (epoll_ctl(epoll_fd_, EPOLL_CTL_MOD, descriptor, &ev) == 0)
+ {
+ descriptor_data->registered_events_ |= ev.events;
+ }
+ else
+ {
+ op->ec_ = asio::error_code(errno,
+ asio::error::get_system_category());
+ scheduler_.post_immediate_completion(op, is_continuation);
+ return;
+ }
+ }
+ }
+ }
+ else if (descriptor_data->registered_events_ == 0)
+ {
+ op->ec_ = asio::error::operation_not_supported;
+ scheduler_.post_immediate_completion(op, is_continuation);
+ return;
+ }
+ else
+ {
+ if (op_type == write_op)
+ {
+ descriptor_data->registered_events_ |= EPOLLOUT;
+ }
+
+ epoll_event ev = { 0, { 0 } };
+ ev.events = descriptor_data->registered_events_;
+ ev.data.ptr = descriptor_data;
+ epoll_ctl(epoll_fd_, EPOLL_CTL_MOD, descriptor, &ev);
+ }
+ }
+
+ descriptor_data->op_queue_[op_type].push(op);
+ scheduler_.work_started();
+}
+
+void epoll_reactor::cancel_ops(socket_type,
+ epoll_reactor::per_descriptor_data& descriptor_data)
+{
+ if (!descriptor_data)
+ return;
+
+ mutex::scoped_lock descriptor_lock(descriptor_data->mutex_);
+
+ op_queue<operation> ops;
+ for (int i = 0; i < max_ops; ++i)
+ {
+ while (reactor_op* op = descriptor_data->op_queue_[i].front())
+ {
+ op->ec_ = asio::error::operation_aborted;
+ descriptor_data->op_queue_[i].pop();
+ ops.push(op);
+ }
+ }
+
+ descriptor_lock.unlock();
+
+ scheduler_.post_deferred_completions(ops);
+}
+
+void epoll_reactor::deregister_descriptor(socket_type descriptor,
+ epoll_reactor::per_descriptor_data& descriptor_data, bool closing)
+{
+ if (!descriptor_data)
+ return;
+
+ mutex::scoped_lock descriptor_lock(descriptor_data->mutex_);
+
+ if (!descriptor_data->shutdown_)
+ {
+ if (closing)
+ {
+ // The descriptor will be automatically removed from the epoll set when
+ // it is closed.
+ }
+ else if (descriptor_data->registered_events_ != 0)
+ {
+ epoll_event ev = { 0, { 0 } };
+ epoll_ctl(epoll_fd_, EPOLL_CTL_DEL, descriptor, &ev);
+ }
+
+ op_queue<operation> ops;
+ for (int i = 0; i < max_ops; ++i)
+ {
+ while (reactor_op* op = descriptor_data->op_queue_[i].front())
+ {
+ op->ec_ = asio::error::operation_aborted;
+ descriptor_data->op_queue_[i].pop();
+ ops.push(op);
+ }
+ }
+
+ descriptor_data->descriptor_ = -1;
+ descriptor_data->shutdown_ = true;
+
+ descriptor_lock.unlock();
+
+ ASIO_HANDLER_REACTOR_DEREGISTRATION((
+ context(), static_cast<uintmax_t>(descriptor),
+ reinterpret_cast<uintmax_t>(descriptor_data)));
+
+ scheduler_.post_deferred_completions(ops);
+
+ // Leave descriptor_data set so that it will be freed by the subsequent
+ // call to cleanup_descriptor_data.
+ }
+ else
+ {
+ // We are shutting down, so prevent cleanup_descriptor_data from freeing
+ // the descriptor_data object and let the destructor free it instead.
+ descriptor_data = 0;
+ }
+}
+
+void epoll_reactor::deregister_internal_descriptor(socket_type descriptor,
+ epoll_reactor::per_descriptor_data& descriptor_data)
+{
+ if (!descriptor_data)
+ return;
+
+ mutex::scoped_lock descriptor_lock(descriptor_data->mutex_);
+
+ if (!descriptor_data->shutdown_)
+ {
+ epoll_event ev = { 0, { 0 } };
+ epoll_ctl(epoll_fd_, EPOLL_CTL_DEL, descriptor, &ev);
+
+ op_queue<operation> ops;
+ for (int i = 0; i < max_ops; ++i)
+ ops.push(descriptor_data->op_queue_[i]);
+
+ descriptor_data->descriptor_ = -1;
+ descriptor_data->shutdown_ = true;
+
+ descriptor_lock.unlock();
+
+ ASIO_HANDLER_REACTOR_DEREGISTRATION((
+ context(), static_cast<uintmax_t>(descriptor),
+ reinterpret_cast<uintmax_t>(descriptor_data)));
+
+ // Leave descriptor_data set so that it will be freed by the subsequent
+ // call to cleanup_descriptor_data.
+ }
+ else
+ {
+ // We are shutting down, so prevent cleanup_descriptor_data from freeing
+ // the descriptor_data object and let the destructor free it instead.
+ descriptor_data = 0;
+ }
+}
+
+void epoll_reactor::cleanup_descriptor_data(
+ per_descriptor_data& descriptor_data)
+{
+ if (descriptor_data)
+ {
+ free_descriptor_state(descriptor_data);
+ descriptor_data = 0;
+ }
+}
+
+void epoll_reactor::run(long usec, op_queue<operation>& ops)
+{
+ // This code relies on the fact that the scheduler queues the reactor task
+ // behind all descriptor operations generated by this function. This means,
+ // that by the time we reach this point, any previously returned descriptor
+ // operations have already been dequeued. Therefore it is now safe for us to
+ // reuse and return them for the scheduler to queue again.
+
+ // Calculate timeout. Check the timer queues only if timerfd is not in use.
+ int timeout;
+ if (usec == 0)
+ timeout = 0;
+ else
+ {
+ timeout = (usec < 0) ? -1 : ((usec - 1) / 1000 + 1);
+ if (timer_fd_ == -1)
+ {
+ mutex::scoped_lock lock(mutex_);
+ timeout = get_timeout(timeout);
+ }
+ }
+
+ // Block on the epoll descriptor.
+ epoll_event events[128];
+ int num_events = epoll_wait(epoll_fd_, events, 128, timeout);
+
+#if defined(ASIO_ENABLE_HANDLER_TRACKING)
+ // Trace the waiting events.
+ for (int i = 0; i < num_events; ++i)
+ {
+ void* ptr = events[i].data.ptr;
+ if (ptr == &interrupter_)
+ {
+ // Ignore.
+ }
+# if defined(ASIO_HAS_TIMERFD)
+ else if (ptr == &timer_fd_)
+ {
+ // Ignore.
+ }
+# endif // defined(ASIO_HAS_TIMERFD)
+ else
+ {
+ unsigned event_mask = 0;
+ if ((events[i].events & EPOLLIN) != 0)
+ event_mask |= ASIO_HANDLER_REACTOR_READ_EVENT;
+ if ((events[i].events & EPOLLOUT))
+ event_mask |= ASIO_HANDLER_REACTOR_WRITE_EVENT;
+ if ((events[i].events & (EPOLLERR | EPOLLHUP)) != 0)
+ event_mask |= ASIO_HANDLER_REACTOR_ERROR_EVENT;
+ ASIO_HANDLER_REACTOR_EVENTS((context(),
+ reinterpret_cast<uintmax_t>(ptr), event_mask));
+ }
+ }
+#endif // defined(ASIO_ENABLE_HANDLER_TRACKING)
+
+#if defined(ASIO_HAS_TIMERFD)
+ bool check_timers = (timer_fd_ == -1);
+#else // defined(ASIO_HAS_TIMERFD)
+ bool check_timers = true;
+#endif // defined(ASIO_HAS_TIMERFD)
+
+ // Dispatch the waiting events.
+ for (int i = 0; i < num_events; ++i)
+ {
+ void* ptr = events[i].data.ptr;
+ if (ptr == &interrupter_)
+ {
+ // No need to reset the interrupter since we're leaving the descriptor
+ // in a ready-to-read state and relying on edge-triggered notifications
+ // to make it so that we only get woken up when the descriptor's epoll
+ // registration is updated.
+
+#if defined(ASIO_HAS_TIMERFD)
+ if (timer_fd_ == -1)
+ check_timers = true;
+#else // defined(ASIO_HAS_TIMERFD)
+ check_timers = true;
+#endif // defined(ASIO_HAS_TIMERFD)
+ }
+#if defined(ASIO_HAS_TIMERFD)
+ else if (ptr == &timer_fd_)
+ {
+ check_timers = true;
+ }
+#endif // defined(ASIO_HAS_TIMERFD)
+ else
+ {
+ // The descriptor operation doesn't count as work in and of itself, so we
+ // don't call work_started() here. This still allows the scheduler to
+ // stop if the only remaining operations are descriptor operations.
+ descriptor_state* descriptor_data = static_cast<descriptor_state*>(ptr);
+ if (!ops.is_enqueued(descriptor_data))
+ {
+ descriptor_data->set_ready_events(events[i].events);
+ ops.push(descriptor_data);
+ }
+ else
+ {
+ descriptor_data->add_ready_events(events[i].events);
+ }
+ }
+ }
+
+ if (check_timers)
+ {
+ mutex::scoped_lock common_lock(mutex_);
+ timer_queues_.get_ready_timers(ops);
+
+#if defined(ASIO_HAS_TIMERFD)
+ if (timer_fd_ != -1)
+ {
+ itimerspec new_timeout;
+ itimerspec old_timeout;
+ int flags = get_timeout(new_timeout);
+ timerfd_settime(timer_fd_, flags, &new_timeout, &old_timeout);
+ }
+#endif // defined(ASIO_HAS_TIMERFD)
+ }
+}
+
+void epoll_reactor::interrupt()
+{
+ epoll_event ev = { 0, { 0 } };
+ ev.events = EPOLLIN | EPOLLERR | EPOLLET;
+ ev.data.ptr = &interrupter_;
+ epoll_ctl(epoll_fd_, EPOLL_CTL_MOD, interrupter_.read_descriptor(), &ev);
+}
+
+int epoll_reactor::do_epoll_create()
+{
+#if defined(EPOLL_CLOEXEC)
+ int fd = epoll_create1(EPOLL_CLOEXEC);
+#else // defined(EPOLL_CLOEXEC)
+ int fd = -1;
+ errno = EINVAL;
+#endif // defined(EPOLL_CLOEXEC)
+
+ if (fd == -1 && (errno == EINVAL || errno == ENOSYS))
+ {
+ fd = epoll_create(epoll_size);
+ if (fd != -1)
+ ::fcntl(fd, F_SETFD, FD_CLOEXEC);
+ }
+
+ if (fd == -1)
+ {
+ asio::error_code ec(errno,
+ asio::error::get_system_category());
+ asio::detail::throw_error(ec, "epoll");
+ }
+
+ return fd;
+}
+
+int epoll_reactor::do_timerfd_create()
+{
+#if defined(ASIO_HAS_TIMERFD)
+# if defined(TFD_CLOEXEC)
+ int fd = timerfd_create(CLOCK_MONOTONIC, TFD_CLOEXEC);
+# else // defined(TFD_CLOEXEC)
+ int fd = -1;
+ errno = EINVAL;
+# endif // defined(TFD_CLOEXEC)
+
+ if (fd == -1 && errno == EINVAL)
+ {
+ fd = timerfd_create(CLOCK_MONOTONIC, 0);
+ if (fd != -1)
+ ::fcntl(fd, F_SETFD, FD_CLOEXEC);
+ }
+
+ return fd;
+#else // defined(ASIO_HAS_TIMERFD)
+ return -1;
+#endif // defined(ASIO_HAS_TIMERFD)
+}
+
+epoll_reactor::descriptor_state* epoll_reactor::allocate_descriptor_state()
+{
+ mutex::scoped_lock descriptors_lock(registered_descriptors_mutex_);
+ return registered_descriptors_.alloc(ASIO_CONCURRENCY_HINT_IS_LOCKING(
+ REACTOR_IO, scheduler_.concurrency_hint()));
+}
+
+void epoll_reactor::free_descriptor_state(epoll_reactor::descriptor_state* s)
+{
+ mutex::scoped_lock descriptors_lock(registered_descriptors_mutex_);
+ registered_descriptors_.free(s);
+}
+
+void epoll_reactor::do_add_timer_queue(timer_queue_base& queue)
+{
+ mutex::scoped_lock lock(mutex_);
+ timer_queues_.insert(&queue);
+}
+
+void epoll_reactor::do_remove_timer_queue(timer_queue_base& queue)
+{
+ mutex::scoped_lock lock(mutex_);
+ timer_queues_.erase(&queue);
+}
+
+void epoll_reactor::update_timeout()
+{
+#if defined(ASIO_HAS_TIMERFD)
+ if (timer_fd_ != -1)
+ {
+ itimerspec new_timeout;
+ itimerspec old_timeout;
+ int flags = get_timeout(new_timeout);
+ timerfd_settime(timer_fd_, flags, &new_timeout, &old_timeout);
+ return;
+ }
+#endif // defined(ASIO_HAS_TIMERFD)
+ interrupt();
+}
+
+int epoll_reactor::get_timeout(int msec)
+{
+ // By default we will wait no longer than 5 minutes. This will ensure that
+ // any changes to the system clock are detected after no longer than this.
+ const int max_msec = 5 * 60 * 1000;
+ return timer_queues_.wait_duration_msec(
+ (msec < 0 || max_msec < msec) ? max_msec : msec);
+}
+
+#if defined(ASIO_HAS_TIMERFD)
+int epoll_reactor::get_timeout(itimerspec& ts)
+{
+ ts.it_interval.tv_sec = 0;
+ ts.it_interval.tv_nsec = 0;
+
+ long usec = timer_queues_.wait_duration_usec(5 * 60 * 1000 * 1000);
+ ts.it_value.tv_sec = usec / 1000000;
+ ts.it_value.tv_nsec = usec ? (usec % 1000000) * 1000 : 1;
+
+ return usec ? 0 : TFD_TIMER_ABSTIME;
+}
+#endif // defined(ASIO_HAS_TIMERFD)
+
+struct epoll_reactor::perform_io_cleanup_on_block_exit
+{
+ explicit perform_io_cleanup_on_block_exit(epoll_reactor* r)
+ : reactor_(r), first_op_(0)
+ {
+ }
+
+ ~perform_io_cleanup_on_block_exit()
+ {
+ if (first_op_)
+ {
+ // Post the remaining completed operations for invocation.
+ if (!ops_.empty())
+ reactor_->scheduler_.post_deferred_completions(ops_);
+
+ // A user-initiated operation has completed, but there's no need to
+ // explicitly call work_finished() here. Instead, we'll take advantage of
+ // the fact that the scheduler will call work_finished() once we return.
+ }
+ else
+ {
+ // No user-initiated operations have completed, so we need to compensate
+ // for the work_finished() call that the scheduler will make once this
+ // operation returns.
+ reactor_->scheduler_.compensating_work_started();
+ }
+ }
+
+ epoll_reactor* reactor_;
+ op_queue<operation> ops_;
+ operation* first_op_;
+};
+
+epoll_reactor::descriptor_state::descriptor_state(bool locking)
+ : operation(&epoll_reactor::descriptor_state::do_complete),
+ mutex_(locking)
+{
+}
+
+operation* epoll_reactor::descriptor_state::perform_io(uint32_t events)
+{
+ mutex_.lock();
+ perform_io_cleanup_on_block_exit io_cleanup(reactor_);
+ mutex::scoped_lock descriptor_lock(mutex_, mutex::scoped_lock::adopt_lock);
+
+ // Exception operations must be processed first to ensure that any
+ // out-of-band data is read before normal data.
+ static const int flag[max_ops] = { EPOLLIN, EPOLLOUT, EPOLLPRI };
+ for (int j = max_ops - 1; j >= 0; --j)
+ {
+ if (events & (flag[j] | EPOLLERR | EPOLLHUP))
+ {
+ try_speculative_[j] = true;
+ while (reactor_op* op = op_queue_[j].front())
+ {
+ if (reactor_op::status status = op->perform())
+ {
+ op_queue_[j].pop();
+ io_cleanup.ops_.push(op);
+ if (status == reactor_op::done_and_exhausted)
+ {
+ try_speculative_[j] = false;
+ break;
+ }
+ }
+ else
+ break;
+ }
+ }
+ }
+
+ // The first operation will be returned for completion now. The others will
+ // be posted for later by the io_cleanup object's destructor.
+ io_cleanup.first_op_ = io_cleanup.ops_.front();
+ io_cleanup.ops_.pop();
+ return io_cleanup.first_op_;
+}
+
+void epoll_reactor::descriptor_state::do_complete(
+ void* owner, operation* base,
+ const asio::error_code& ec, std::size_t bytes_transferred)
+{
+ if (owner)
+ {
+ descriptor_state* descriptor_data = static_cast<descriptor_state*>(base);
+ uint32_t events = static_cast<uint32_t>(bytes_transferred);
+ if (operation* op = descriptor_data->perform_io(events))
+ {
+ op->complete(owner, ec, 0);
+ }
+ }
+}
+
+} // namespace detail
+} // namespace asio
+
+#include "asio/detail/pop_options.hpp"
+
+#endif // defined(ASIO_HAS_EPOLL)
+
+#endif // ASIO_DETAIL_IMPL_EPOLL_REACTOR_IPP
diff --git a/lib/asio/detail/impl/eventfd_select_interrupter.ipp b/lib/asio/detail/impl/eventfd_select_interrupter.ipp
new file mode 100644
index 0000000..c56e89a
--- /dev/null
+++ b/lib/asio/detail/impl/eventfd_select_interrupter.ipp
@@ -0,0 +1,165 @@
+//
+// detail/impl/eventfd_select_interrupter.ipp
+// ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+//
+// Copyright (c) 2003-2018 Christopher M. Kohlhoff (chris at kohlhoff dot com)
+// Copyright (c) 2008 Roelof Naude (roelof.naude at gmail dot com)
+//
+// 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 ASIO_DETAIL_IMPL_EVENTFD_SELECT_INTERRUPTER_IPP
+#define ASIO_DETAIL_IMPL_EVENTFD_SELECT_INTERRUPTER_IPP
+
+#if defined(_MSC_VER) && (_MSC_VER >= 1200)
+# pragma once
+#endif // defined(_MSC_VER) && (_MSC_VER >= 1200)
+
+#include "asio/detail/config.hpp"
+
+#if defined(ASIO_HAS_EVENTFD)
+
+#include <sys/stat.h>
+#include <sys/types.h>
+#include <fcntl.h>
+#if __GLIBC__ == 2 && __GLIBC_MINOR__ < 8
+# include <asm/unistd.h>
+#else // __GLIBC__ == 2 && __GLIBC_MINOR__ < 8
+# include <sys/eventfd.h>
+#endif // __GLIBC__ == 2 && __GLIBC_MINOR__ < 8
+#include "asio/detail/cstdint.hpp"
+#include "asio/detail/eventfd_select_interrupter.hpp"
+#include "asio/detail/throw_error.hpp"
+#include "asio/error.hpp"
+
+#include "asio/detail/push_options.hpp"
+
+namespace asio {
+namespace detail {
+
+eventfd_select_interrupter::eventfd_select_interrupter()
+{
+ open_descriptors();
+}
+
+void eventfd_select_interrupter::open_descriptors()
+{
+#if __GLIBC__ == 2 && __GLIBC_MINOR__ < 8
+ write_descriptor_ = read_descriptor_ = syscall(__NR_eventfd, 0);
+ if (read_descriptor_ != -1)
+ {
+ ::fcntl(read_descriptor_, F_SETFL, O_NONBLOCK);
+ ::fcntl(read_descriptor_, F_SETFD, FD_CLOEXEC);
+ }
+#else // __GLIBC__ == 2 && __GLIBC_MINOR__ < 8
+# if defined(EFD_CLOEXEC) && defined(EFD_NONBLOCK)
+ write_descriptor_ = read_descriptor_ =
+ ::eventfd(0, EFD_CLOEXEC | EFD_NONBLOCK);
+# else // defined(EFD_CLOEXEC) && defined(EFD_NONBLOCK)
+ errno = EINVAL;
+ write_descriptor_ = read_descriptor_ = -1;
+# endif // defined(EFD_CLOEXEC) && defined(EFD_NONBLOCK)
+ if (read_descriptor_ == -1 && errno == EINVAL)
+ {
+ write_descriptor_ = read_descriptor_ = ::eventfd(0, 0);
+ if (read_descriptor_ != -1)
+ {
+ ::fcntl(read_descriptor_, F_SETFL, O_NONBLOCK);
+ ::fcntl(read_descriptor_, F_SETFD, FD_CLOEXEC);
+ }
+ }
+#endif // __GLIBC__ == 2 && __GLIBC_MINOR__ < 8
+
+ if (read_descriptor_ == -1)
+ {
+ int pipe_fds[2];
+ if (pipe(pipe_fds) == 0)
+ {
+ read_descriptor_ = pipe_fds[0];
+ ::fcntl(read_descriptor_, F_SETFL, O_NONBLOCK);
+ ::fcntl(read_descriptor_, F_SETFD, FD_CLOEXEC);
+ write_descriptor_ = pipe_fds[1];
+ ::fcntl(write_descriptor_, F_SETFL, O_NONBLOCK);
+ ::fcntl(write_descriptor_, F_SETFD, FD_CLOEXEC);
+ }
+ else
+ {
+ asio::error_code ec(errno,
+ asio::error::get_system_category());
+ asio::detail::throw_error(ec, "eventfd_select_interrupter");
+ }
+ }
+}
+
+eventfd_select_interrupter::~eventfd_select_interrupter()
+{
+ close_descriptors();
+}
+
+void eventfd_select_interrupter::close_descriptors()
+{
+ if (write_descriptor_ != -1 && write_descriptor_ != read_descriptor_)
+ ::close(write_descriptor_);
+ if (read_descriptor_ != -1)
+ ::close(read_descriptor_);
+}
+
+void eventfd_select_interrupter::recreate()
+{
+ close_descriptors();
+
+ write_descriptor_ = -1;
+ read_descriptor_ = -1;
+
+ open_descriptors();
+}
+
+void eventfd_select_interrupter::interrupt()
+{
+ uint64_t counter(1UL);
+ int result = ::write(write_descriptor_, &counter, sizeof(uint64_t));
+ (void)result;
+}
+
+bool eventfd_select_interrupter::reset()
+{
+ if (write_descriptor_ == read_descriptor_)
+ {
+ for (;;)
+ {
+ // Only perform one read. The kernel maintains an atomic counter.
+ uint64_t counter(0);
+ errno = 0;
+ int bytes_read = ::read(read_descriptor_, &counter, sizeof(uint64_t));
+ if (bytes_read < 0 && errno == EINTR)
+ continue;
+ bool was_interrupted = (bytes_read > 0);
+ return was_interrupted;
+ }
+ }
+ else
+ {
+ for (;;)
+ {
+ // Clear all data from the pipe.
+ char data[1024];
+ int bytes_read = ::read(read_descriptor_, data, sizeof(data));
+ if (bytes_read < 0 && errno == EINTR)
+ continue;
+ bool was_interrupted = (bytes_read > 0);
+ while (bytes_read == sizeof(data))
+ bytes_read = ::read(read_descriptor_, data, sizeof(data));
+ return was_interrupted;
+ }
+ }
+}
+
+} // namespace detail
+} // namespace asio
+
+#include "asio/detail/pop_options.hpp"
+
+#endif // defined(ASIO_HAS_EVENTFD)
+
+#endif // ASIO_DETAIL_IMPL_EVENTFD_SELECT_INTERRUPTER_IPP
diff --git a/lib/asio/detail/impl/handler_tracking.ipp b/lib/asio/detail/impl/handler_tracking.ipp
new file mode 100644
index 0000000..5a4ff6f
--- /dev/null
+++ b/lib/asio/detail/impl/handler_tracking.ipp
@@ -0,0 +1,358 @@
+//
+// detail/impl/handler_tracking.ipp
+// ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+//
+// Copyright (c) 2003-2018 Christopher M. Kohlhoff (chris at kohlhoff dot com)
+//
+// 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 ASIO_DETAIL_IMPL_HANDLER_TRACKING_IPP
+#define ASIO_DETAIL_IMPL_HANDLER_TRACKING_IPP
+
+#if defined(_MSC_VER) && (_MSC_VER >= 1200)
+# pragma once
+#endif // defined(_MSC_VER) && (_MSC_VER >= 1200)
+
+#include "asio/detail/config.hpp"
+
+#if defined(ASIO_CUSTOM_HANDLER_TRACKING)
+
+// The handler tracking implementation is provided by the user-specified header.
+
+#elif defined(ASIO_ENABLE_HANDLER_TRACKING)
+
+#include <cstdarg>
+#include <cstdio>
+#include "asio/detail/handler_tracking.hpp"
+
+#if defined(ASIO_HAS_BOOST_DATE_TIME)
+# include "asio/time_traits.hpp"
+#elif defined(ASIO_HAS_CHRONO)
+# include "asio/detail/chrono.hpp"
+# include "asio/detail/chrono_time_traits.hpp"
+# include "asio/wait_traits.hpp"
+#endif // defined(ASIO_HAS_BOOST_DATE_TIME)
+
+#if defined(ASIO_WINDOWS_RUNTIME)
+# include "asio/detail/socket_types.hpp"
+#elif !defined(ASIO_WINDOWS)
+# include <unistd.h>
+#endif // !defined(ASIO_WINDOWS)
+
+#include "asio/detail/push_options.hpp"
+
+namespace asio {
+namespace detail {
+
+struct handler_tracking_timestamp
+{
+ uint64_t seconds;
+ uint64_t microseconds;
+
+ handler_tracking_timestamp()
+ {
+#if defined(ASIO_HAS_BOOST_DATE_TIME)
+ boost::posix_time::ptime epoch(boost::gregorian::date(1970, 1, 1));
+ boost::posix_time::time_duration now =
+ boost::posix_time::microsec_clock::universal_time() - epoch;
+#elif defined(ASIO_HAS_CHRONO)
+ typedef chrono_time_traits<chrono::system_clock,
+ asio::wait_traits<chrono::system_clock> > traits_helper;
+ traits_helper::posix_time_duration now(
+ chrono::system_clock::now().time_since_epoch());
+#endif
+ seconds = static_cast<uint64_t>(now.total_seconds());
+ microseconds = static_cast<uint64_t>(now.total_microseconds() % 1000000);
+ }
+};
+
+struct handler_tracking::tracking_state
+{
+ static_mutex mutex_;
+ uint64_t next_id_;
+ tss_ptr<completion>* current_completion_;
+};
+
+handler_tracking::tracking_state* handler_tracking::get_state()
+{
+ static tracking_state state = { ASIO_STATIC_MUTEX_INIT, 1, 0 };
+ return &state;
+}
+
+void handler_tracking::init()
+{
+ static tracking_state* state = get_state();
+
+ state->mutex_.init();
+
+ static_mutex::scoped_lock lock(state->mutex_);
+ if (state->current_completion_ == 0)
+ state->current_completion_ = new tss_ptr<completion>;
+}
+
+void handler_tracking::creation(execution_context&,
+ handler_tracking::tracked_handler& h,
+ const char* object_type, void* object,
+ uintmax_t /*native_handle*/, const char* op_name)
+{
+ static tracking_state* state = get_state();
+
+ static_mutex::scoped_lock lock(state->mutex_);
+ h.id_ = state->next_id_++;
+ lock.unlock();
+
+ handler_tracking_timestamp timestamp;
+
+ uint64_t current_id = 0;
+ if (completion* current_completion = *state->current_completion_)
+ current_id = current_completion->id_;
+
+ write_line(
+#if defined(ASIO_WINDOWS)
+ "@asio|%I64u.%06I64u|%I64u*%I64u|%.20s@%p.%.50s\n",
+#else // defined(ASIO_WINDOWS)
+ "@asio|%llu.%06llu|%llu*%llu|%.20s@%p.%.50s\n",
+#endif // defined(ASIO_WINDOWS)
+ timestamp.seconds, timestamp.microseconds,
+ current_id, h.id_, object_type, object, op_name);
+}
+
+handler_tracking::completion::completion(
+ const handler_tracking::tracked_handler& h)
+ : id_(h.id_),
+ invoked_(false),
+ next_(*get_state()->current_completion_)
+{
+ *get_state()->current_completion_ = this;
+}
+
+handler_tracking::completion::~completion()
+{
+ if (id_)
+ {
+ handler_tracking_timestamp timestamp;
+
+ write_line(
+#if defined(ASIO_WINDOWS)
+ "@asio|%I64u.%06I64u|%c%I64u|\n",
+#else // defined(ASIO_WINDOWS)
+ "@asio|%llu.%06llu|%c%llu|\n",
+#endif // defined(ASIO_WINDOWS)
+ timestamp.seconds, timestamp.microseconds,
+ invoked_ ? '!' : '~', id_);
+ }
+
+ *get_state()->current_completion_ = next_;
+}
+
+void handler_tracking::completion::invocation_begin()
+{
+ handler_tracking_timestamp timestamp;
+
+ write_line(
+#if defined(ASIO_WINDOWS)
+ "@asio|%I64u.%06I64u|>%I64u|\n",
+#else // defined(ASIO_WINDOWS)
+ "@asio|%llu.%06llu|>%llu|\n",
+#endif // defined(ASIO_WINDOWS)
+ timestamp.seconds, timestamp.microseconds, id_);
+
+ invoked_ = true;
+}
+
+void handler_tracking::completion::invocation_begin(
+ const asio::error_code& ec)
+{
+ handler_tracking_timestamp timestamp;
+
+ write_line(
+#if defined(ASIO_WINDOWS)
+ "@asio|%I64u.%06I64u|>%I64u|ec=%.20s:%d\n",
+#else // defined(ASIO_WINDOWS)
+ "@asio|%llu.%06llu|>%llu|ec=%.20s:%d\n",
+#endif // defined(ASIO_WINDOWS)
+ timestamp.seconds, timestamp.microseconds,
+ id_, ec.category().name(), ec.value());
+
+ invoked_ = true;
+}
+
+void handler_tracking::completion::invocation_begin(
+ const asio::error_code& ec, std::size_t bytes_transferred)
+{
+ handler_tracking_timestamp timestamp;
+
+ write_line(
+#if defined(ASIO_WINDOWS)
+ "@asio|%I64u.%06I64u|>%I64u|ec=%.20s:%d,bytes_transferred=%I64u\n",
+#else // defined(ASIO_WINDOWS)
+ "@asio|%llu.%06llu|>%llu|ec=%.20s:%d,bytes_transferred=%llu\n",
+#endif // defined(ASIO_WINDOWS)
+ timestamp.seconds, timestamp.microseconds,
+ id_, ec.category().name(), ec.value(),
+ static_cast<uint64_t>(bytes_transferred));
+
+ invoked_ = true;
+}
+
+void handler_tracking::completion::invocation_begin(
+ const asio::error_code& ec, int signal_number)
+{
+ handler_tracking_timestamp timestamp;
+
+ write_line(
+#if defined(ASIO_WINDOWS)
+ "@asio|%I64u.%06I64u|>%I64u|ec=%.20s:%d,signal_number=%d\n",
+#else // defined(ASIO_WINDOWS)
+ "@asio|%llu.%06llu|>%llu|ec=%.20s:%d,signal_number=%d\n",
+#endif // defined(ASIO_WINDOWS)
+ timestamp.seconds, timestamp.microseconds,
+ id_, ec.category().name(), ec.value(), signal_number);
+
+ invoked_ = true;
+}
+
+void handler_tracking::completion::invocation_begin(
+ const asio::error_code& ec, const char* arg)
+{
+ handler_tracking_timestamp timestamp;
+
+ write_line(
+#if defined(ASIO_WINDOWS)
+ "@asio|%I64u.%06I64u|>%I64u|ec=%.20s:%d,%.50s\n",
+#else // defined(ASIO_WINDOWS)
+ "@asio|%llu.%06llu|>%llu|ec=%.20s:%d,%.50s\n",
+#endif // defined(ASIO_WINDOWS)
+ timestamp.seconds, timestamp.microseconds,
+ id_, ec.category().name(), ec.value(), arg);
+
+ invoked_ = true;
+}
+
+void handler_tracking::completion::invocation_end()
+{
+ if (id_)
+ {
+ handler_tracking_timestamp timestamp;
+
+ write_line(
+#if defined(ASIO_WINDOWS)
+ "@asio|%I64u.%06I64u|<%I64u|\n",
+#else // defined(ASIO_WINDOWS)
+ "@asio|%llu.%06llu|<%llu|\n",
+#endif // defined(ASIO_WINDOWS)
+ timestamp.seconds, timestamp.microseconds, id_);
+
+ id_ = 0;
+ }
+}
+
+void handler_tracking::operation(execution_context&,
+ const char* object_type, void* object,
+ uintmax_t /*native_handle*/, const char* op_name)
+{
+ static tracking_state* state = get_state();
+
+ handler_tracking_timestamp timestamp;
+
+ unsigned long long current_id = 0;
+ if (completion* current_completion = *state->current_completion_)
+ current_id = current_completion->id_;
+
+ write_line(
+#if defined(ASIO_WINDOWS)
+ "@asio|%I64u.%06I64u|%I64u|%.20s@%p.%.50s\n",
+#else // defined(ASIO_WINDOWS)
+ "@asio|%llu.%06llu|%llu|%.20s@%p.%.50s\n",
+#endif // defined(ASIO_WINDOWS)
+ timestamp.seconds, timestamp.microseconds,
+ current_id, object_type, object, op_name);
+}
+
+void handler_tracking::reactor_registration(execution_context& /*context*/,
+ uintmax_t /*native_handle*/, uintmax_t /*registration*/)
+{
+}
+
+void handler_tracking::reactor_deregistration(execution_context& /*context*/,
+ uintmax_t /*native_handle*/, uintmax_t /*registration*/)
+{
+}
+
+void handler_tracking::reactor_events(execution_context& /*context*/,
+ uintmax_t /*native_handle*/, unsigned /*events*/)
+{
+}
+
+void handler_tracking::reactor_operation(
+ const tracked_handler& h, const char* op_name,
+ const asio::error_code& ec)
+{
+ handler_tracking_timestamp timestamp;
+
+ write_line(
+#if defined(ASIO_WINDOWS)
+ "@asio|%I64u.%06I64u|.%I64u|%s,ec=%.20s:%d\n",
+#else // defined(ASIO_WINDOWS)
+ "@asio|%llu.%06llu|.%llu|%s,ec=%.20s:%d\n",
+#endif // defined(ASIO_WINDOWS)
+ timestamp.seconds, timestamp.microseconds,
+ h.id_, op_name, ec.category().name(), ec.value());
+}
+
+void handler_tracking::reactor_operation(
+ const tracked_handler& h, const char* op_name,
+ const asio::error_code& ec, std::size_t bytes_transferred)
+{
+ handler_tracking_timestamp timestamp;
+
+ write_line(
+#if defined(ASIO_WINDOWS)
+ "@asio|%I64u.%06I64u|.%I64u|%s,ec=%.20s:%d,bytes_transferred=%I64u\n",
+#else // defined(ASIO_WINDOWS)
+ "@asio|%llu.%06llu|.%llu|%s,ec=%.20s:%d,bytes_transferred=%llu\n",
+#endif // defined(ASIO_WINDOWS)
+ timestamp.seconds, timestamp.microseconds,
+ h.id_, op_name, ec.category().name(), ec.value(),
+ static_cast<uint64_t>(bytes_transferred));
+}
+
+void handler_tracking::write_line(const char* format, ...)
+{
+ using namespace std; // For sprintf (or equivalent).
+
+ va_list args;
+ va_start(args, format);
+
+ char line[256] = "";
+#if defined(ASIO_HAS_SECURE_RTL)
+ int length = vsprintf_s(line, sizeof(line), format, args);
+#else // defined(ASIO_HAS_SECURE_RTL)
+ int length = vsprintf(line, format, args);
+#endif // defined(ASIO_HAS_SECURE_RTL)
+
+ va_end(args);
+
+#if defined(ASIO_WINDOWS_RUNTIME)
+ wchar_t wline[256] = L"";
+ mbstowcs_s(0, wline, sizeof(wline) / sizeof(wchar_t), line, length);
+ ::OutputDebugStringW(wline);
+#elif defined(ASIO_WINDOWS)
+ HANDLE stderr_handle = ::GetStdHandle(STD_ERROR_HANDLE);
+ DWORD bytes_written = 0;
+ ::WriteFile(stderr_handle, line, length, &bytes_written, 0);
+#else // defined(ASIO_WINDOWS)
+ ::write(STDERR_FILENO, line, length);
+#endif // defined(ASIO_WINDOWS)
+}
+
+} // namespace detail
+} // namespace asio
+
+#include "asio/detail/pop_options.hpp"
+
+#endif // defined(ASIO_ENABLE_HANDLER_TRACKING)
+
+#endif // ASIO_DETAIL_IMPL_HANDLER_TRACKING_IPP
diff --git a/lib/asio/detail/impl/kqueue_reactor.hpp b/lib/asio/detail/impl/kqueue_reactor.hpp
new file mode 100644
index 0000000..136d167
--- /dev/null
+++ b/lib/asio/detail/impl/kqueue_reactor.hpp
@@ -0,0 +1,93 @@
+//
+// detail/impl/kqueue_reactor.hpp
+// ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+//
+// Copyright (c) 2003-2018 Christopher M. Kohlhoff (chris at kohlhoff dot com)
+// Copyright (c) 2005 Stefan Arentz (stefan at soze dot com)
+//
+// 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 ASIO_DETAIL_IMPL_KQUEUE_REACTOR_HPP
+#define ASIO_DETAIL_IMPL_KQUEUE_REACTOR_HPP
+
+#if defined(_MSC_VER) && (_MSC_VER >= 1200)
+# pragma once
+#endif // defined(_MSC_VER) && (_MSC_VER >= 1200)
+
+#include "asio/detail/config.hpp"
+
+#if defined(ASIO_HAS_KQUEUE)
+
+#include "asio/detail/push_options.hpp"
+
+namespace asio {
+namespace detail {
+
+template <typename Time_Traits>
+void kqueue_reactor::add_timer_queue(timer_queue<Time_Traits>& queue)
+{
+ do_add_timer_queue(queue);
+}
+
+// Remove a timer queue from the reactor.
+template <typename Time_Traits>
+void kqueue_reactor::remove_timer_queue(timer_queue<Time_Traits>& queue)
+{
+ do_remove_timer_queue(queue);
+}
+
+template <typename Time_Traits>
+void kqueue_reactor::schedule_timer(timer_queue<Time_Traits>& queue,
+ const typename Time_Traits::time_type& time,
+ typename timer_queue<Time_Traits>::per_timer_data& timer, wait_op* op)
+{
+ mutex::scoped_lock lock(mutex_);
+
+ if (shutdown_)
+ {
+ scheduler_.post_immediate_completion(op, false);
+ return;
+ }
+
+ bool earliest = queue.enqueue_timer(time, timer, op);
+ scheduler_.work_started();
+ if (earliest)
+ interrupt();
+}
+
+template <typename Time_Traits>
+std::size_t kqueue_reactor::cancel_timer(timer_queue<Time_Traits>& queue,
+ typename timer_queue<Time_Traits>::per_timer_data& timer,
+ std::size_t max_cancelled)
+{
+ mutex::scoped_lock lock(mutex_);
+ op_queue<operation> ops;
+ std::size_t n = queue.cancel_timer(timer, ops, max_cancelled);
+ lock.unlock();
+ scheduler_.post_deferred_completions(ops);
+ return n;
+}
+
+template <typename Time_Traits>
+void kqueue_reactor::move_timer(timer_queue<Time_Traits>& queue,
+ typename timer_queue<Time_Traits>::per_timer_data& target,
+ typename timer_queue<Time_Traits>::per_timer_data& source)
+{
+ mutex::scoped_lock lock(mutex_);
+ op_queue<operation> ops;
+ queue.cancel_timer(target, ops);
+ queue.move_timer(target, source);
+ lock.unlock();
+ scheduler_.post_deferred_completions(ops);
+}
+
+} // namespace detail
+} // namespace asio
+
+#include "asio/detail/pop_options.hpp"
+
+#endif // defined(ASIO_HAS_KQUEUE)
+
+#endif // ASIO_DETAIL_IMPL_KQUEUE_REACTOR_HPP
diff --git a/lib/asio/detail/impl/kqueue_reactor.ipp b/lib/asio/detail/impl/kqueue_reactor.ipp
new file mode 100644
index 0000000..73986e0
--- /dev/null
+++ b/lib/asio/detail/impl/kqueue_reactor.ipp
@@ -0,0 +1,566 @@
+//
+// detail/impl/kqueue_reactor.ipp
+// ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+//
+// Copyright (c) 2003-2018 Christopher M. Kohlhoff (chris at kohlhoff dot com)
+// Copyright (c) 2005 Stefan Arentz (stefan at soze dot com)
+//
+// 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 ASIO_DETAIL_IMPL_KQUEUE_REACTOR_IPP
+#define ASIO_DETAIL_IMPL_KQUEUE_REACTOR_IPP
+
+#if defined(_MSC_VER) && (_MSC_VER >= 1200)
+# pragma once
+#endif // defined(_MSC_VER) && (_MSC_VER >= 1200)
+
+#include "asio/detail/config.hpp"
+
+#if defined(ASIO_HAS_KQUEUE)
+
+#include "asio/detail/kqueue_reactor.hpp"
+#include "asio/detail/scheduler.hpp"
+#include "asio/detail/throw_error.hpp"
+#include "asio/error.hpp"
+
+#include "asio/detail/push_options.hpp"
+
+#if defined(__NetBSD__)
+# define ASIO_KQUEUE_EV_SET(ev, ident, filt, flags, fflags, data, udata) \
+ EV_SET(ev, ident, filt, flags, fflags, data, \
+ reinterpret_cast<intptr_t>(static_cast<void*>(udata)))
+#else
+# define ASIO_KQUEUE_EV_SET(ev, ident, filt, flags, fflags, data, udata) \
+ EV_SET(ev, ident, filt, flags, fflags, data, udata)
+#endif
+
+namespace asio {
+namespace detail {
+
+kqueue_reactor::kqueue_reactor(asio::execution_context& ctx)
+ : execution_context_service_base<kqueue_reactor>(ctx),
+ scheduler_(use_service<scheduler>(ctx)),
+ mutex_(ASIO_CONCURRENCY_HINT_IS_LOCKING(
+ REACTOR_REGISTRATION, scheduler_.concurrency_hint())),
+ kqueue_fd_(do_kqueue_create()),
+ interrupter_(),
+ shutdown_(false),
+ registered_descriptors_mutex_(mutex_.enabled())
+{
+ struct kevent events[1];
+ ASIO_KQUEUE_EV_SET(&events[0], interrupter_.read_descriptor(),
+ EVFILT_READ, EV_ADD, 0, 0, &interrupter_);
+ if (::kevent(kqueue_fd_, events, 1, 0, 0, 0) == -1)
+ {
+ asio::error_code error(errno,
+ asio::error::get_system_category());
+ asio::detail::throw_error(error);
+ }
+}
+
+kqueue_reactor::~kqueue_reactor()
+{
+ close(kqueue_fd_);
+}
+
+void kqueue_reactor::shutdown()
+{
+ mutex::scoped_lock lock(mutex_);
+ shutdown_ = true;
+ lock.unlock();
+
+ op_queue<operation> ops;
+
+ while (descriptor_state* state = registered_descriptors_.first())
+ {
+ for (int i = 0; i < max_ops; ++i)
+ ops.push(state->op_queue_[i]);
+ state->shutdown_ = true;
+ registered_descriptors_.free(state);
+ }
+
+ timer_queues_.get_all_timers(ops);
+
+ scheduler_.abandon_operations(ops);
+}
+
+void kqueue_reactor::notify_fork(
+ asio::execution_context::fork_event fork_ev)
+{
+ if (fork_ev == asio::execution_context::fork_child)
+ {
+ // The kqueue descriptor is automatically closed in the child.
+ kqueue_fd_ = -1;
+ kqueue_fd_ = do_kqueue_create();
+
+ interrupter_.recreate();
+
+ struct kevent events[2];
+ ASIO_KQUEUE_EV_SET(&events[0], interrupter_.read_descriptor(),
+ EVFILT_READ, EV_ADD, 0, 0, &interrupter_);
+ if (::kevent(kqueue_fd_, events, 1, 0, 0, 0) == -1)
+ {
+ asio::error_code ec(errno,
+ asio::error::get_system_category());
+ asio::detail::throw_error(ec, "kqueue interrupter registration");
+ }
+
+ // Re-register all descriptors with kqueue.
+ mutex::scoped_lock descriptors_lock(registered_descriptors_mutex_);
+ for (descriptor_state* state = registered_descriptors_.first();
+ state != 0; state = state->next_)
+ {
+ if (state->num_kevents_ > 0)
+ {
+ ASIO_KQUEUE_EV_SET(&events[0], state->descriptor_,
+ EVFILT_READ, EV_ADD | EV_CLEAR, 0, 0, state);
+ ASIO_KQUEUE_EV_SET(&events[1], state->descriptor_,
+ EVFILT_WRITE, EV_ADD | EV_CLEAR, 0, 0, state);
+ if (::kevent(kqueue_fd_, events, state->num_kevents_, 0, 0, 0) == -1)
+ {
+ asio::error_code ec(errno,
+ asio::error::get_system_category());
+ asio::detail::throw_error(ec, "kqueue re-registration");
+ }
+ }
+ }
+ }
+}
+
+void kqueue_reactor::init_task()
+{
+ scheduler_.init_task();
+}
+
+int kqueue_reactor::register_descriptor(socket_type descriptor,
+ kqueue_reactor::per_descriptor_data& descriptor_data)
+{
+ descriptor_data = allocate_descriptor_state();
+
+ ASIO_HANDLER_REACTOR_REGISTRATION((
+ context(), static_cast<uintmax_t>(descriptor),
+ reinterpret_cast<uintmax_t>(descriptor_data)));
+
+ mutex::scoped_lock lock(descriptor_data->mutex_);
+
+ descriptor_data->descriptor_ = descriptor;
+ descriptor_data->num_kevents_ = 0;
+ descriptor_data->shutdown_ = false;
+
+ return 0;
+}
+
+int kqueue_reactor::register_internal_descriptor(
+ int op_type, socket_type descriptor,
+ kqueue_reactor::per_descriptor_data& descriptor_data, reactor_op* op)
+{
+ descriptor_data = allocate_descriptor_state();
+
+ ASIO_HANDLER_REACTOR_REGISTRATION((
+ context(), static_cast<uintmax_t>(descriptor),
+ reinterpret_cast<uintmax_t>(descriptor_data)));
+
+ mutex::scoped_lock lock(descriptor_data->mutex_);
+
+ descriptor_data->descriptor_ = descriptor;
+ descriptor_data->num_kevents_ = 1;
+ descriptor_data->shutdown_ = false;
+ descriptor_data->op_queue_[op_type].push(op);
+
+ struct kevent events[1];
+ ASIO_KQUEUE_EV_SET(&events[0], descriptor, EVFILT_READ,
+ EV_ADD | EV_CLEAR, 0, 0, descriptor_data);
+ if (::kevent(kqueue_fd_, events, 1, 0, 0, 0) == -1)
+ return errno;
+
+ return 0;
+}
+
+void kqueue_reactor::move_descriptor(socket_type,
+ kqueue_reactor::per_descriptor_data& target_descriptor_data,
+ kqueue_reactor::per_descriptor_data& source_descriptor_data)
+{
+ target_descriptor_data = source_descriptor_data;
+ source_descriptor_data = 0;
+}
+
+void kqueue_reactor::start_op(int op_type, socket_type descriptor,
+ kqueue_reactor::per_descriptor_data& descriptor_data, reactor_op* op,
+ bool is_continuation, bool allow_speculative)
+{
+ if (!descriptor_data)
+ {
+ op->ec_ = asio::error::bad_descriptor;
+ post_immediate_completion(op, is_continuation);
+ return;
+ }
+
+ mutex::scoped_lock descriptor_lock(descriptor_data->mutex_);
+
+ if (descriptor_data->shutdown_)
+ {
+ post_immediate_completion(op, is_continuation);
+ return;
+ }
+
+ if (descriptor_data->op_queue_[op_type].empty())
+ {
+ static const int num_kevents[max_ops] = { 1, 2, 1 };
+
+ if (allow_speculative
+ && (op_type != read_op
+ || descriptor_data->op_queue_[except_op].empty()))
+ {
+ if (op->perform())
+ {
+ descriptor_lock.unlock();
+ scheduler_.post_immediate_completion(op, is_continuation);
+ return;
+ }
+
+ if (descriptor_data->num_kevents_ < num_kevents[op_type])
+ {
+ struct kevent events[2];
+ ASIO_KQUEUE_EV_SET(&events[0], descriptor, EVFILT_READ,
+ EV_ADD | EV_CLEAR, 0, 0, descriptor_data);
+ ASIO_KQUEUE_EV_SET(&events[1], descriptor, EVFILT_WRITE,
+ EV_ADD | EV_CLEAR, 0, 0, descriptor_data);
+ if (::kevent(kqueue_fd_, events, num_kevents[op_type], 0, 0, 0) != -1)
+ {
+ descriptor_data->num_kevents_ = num_kevents[op_type];
+ }
+ else
+ {
+ op->ec_ = asio::error_code(errno,
+ asio::error::get_system_category());
+ scheduler_.post_immediate_completion(op, is_continuation);
+ return;
+ }
+ }
+ }
+ else
+ {
+ if (descriptor_data->num_kevents_ < num_kevents[op_type])
+ descriptor_data->num_kevents_ = num_kevents[op_type];
+
+ struct kevent events[2];
+ ASIO_KQUEUE_EV_SET(&events[0], descriptor, EVFILT_READ,
+ EV_ADD | EV_CLEAR, 0, 0, descriptor_data);
+ ASIO_KQUEUE_EV_SET(&events[1], descriptor, EVFILT_WRITE,
+ EV_ADD | EV_CLEAR, 0, 0, descriptor_data);
+ ::kevent(kqueue_fd_, events, descriptor_data->num_kevents_, 0, 0, 0);
+ }
+ }
+
+ descriptor_data->op_queue_[op_type].push(op);
+ scheduler_.work_started();
+}
+
+void kqueue_reactor::cancel_ops(socket_type,
+ kqueue_reactor::per_descriptor_data& descriptor_data)
+{
+ if (!descriptor_data)
+ return;
+
+ mutex::scoped_lock descriptor_lock(descriptor_data->mutex_);
+
+ op_queue<operation> ops;
+ for (int i = 0; i < max_ops; ++i)
+ {
+ while (reactor_op* op = descriptor_data->op_queue_[i].front())
+ {
+ op->ec_ = asio::error::operation_aborted;
+ descriptor_data->op_queue_[i].pop();
+ ops.push(op);
+ }
+ }
+
+ descriptor_lock.unlock();
+
+ scheduler_.post_deferred_completions(ops);
+}
+
+void kqueue_reactor::deregister_descriptor(socket_type descriptor,
+ kqueue_reactor::per_descriptor_data& descriptor_data, bool closing)
+{
+ if (!descriptor_data)
+ return;
+
+ mutex::scoped_lock descriptor_lock(descriptor_data->mutex_);
+
+ if (!descriptor_data->shutdown_)
+ {
+ if (closing)
+ {
+ // The descriptor will be automatically removed from the kqueue when it
+ // is closed.
+ }
+ else
+ {
+ struct kevent events[2];
+ ASIO_KQUEUE_EV_SET(&events[0], descriptor,
+ EVFILT_READ, EV_DELETE, 0, 0, 0);
+ ASIO_KQUEUE_EV_SET(&events[1], descriptor,
+ EVFILT_WRITE, EV_DELETE, 0, 0, 0);
+ ::kevent(kqueue_fd_, events, descriptor_data->num_kevents_, 0, 0, 0);
+ }
+
+ op_queue<operation> ops;
+ for (int i = 0; i < max_ops; ++i)
+ {
+ while (reactor_op* op = descriptor_data->op_queue_[i].front())
+ {
+ op->ec_ = asio::error::operation_aborted;
+ descriptor_data->op_queue_[i].pop();
+ ops.push(op);
+ }
+ }
+
+ descriptor_data->descriptor_ = -1;
+ descriptor_data->shutdown_ = true;
+
+ descriptor_lock.unlock();
+
+ ASIO_HANDLER_REACTOR_DEREGISTRATION((
+ context(), static_cast<uintmax_t>(descriptor),
+ reinterpret_cast<uintmax_t>(descriptor_data)));
+
+ scheduler_.post_deferred_completions(ops);
+
+ // Leave descriptor_data set so that it will be freed by the subsequent
+ // call to cleanup_descriptor_data.
+ }
+ else
+ {
+ // We are shutting down, so prevent cleanup_descriptor_data from freeing
+ // the descriptor_data object and let the destructor free it instead.
+ descriptor_data = 0;
+ }
+}
+
+void kqueue_reactor::deregister_internal_descriptor(socket_type descriptor,
+ kqueue_reactor::per_descriptor_data& descriptor_data)
+{
+ if (!descriptor_data)
+ return;
+
+ mutex::scoped_lock descriptor_lock(descriptor_data->mutex_);
+
+ if (!descriptor_data->shutdown_)
+ {
+ struct kevent events[2];
+ ASIO_KQUEUE_EV_SET(&events[0], descriptor,
+ EVFILT_READ, EV_DELETE, 0, 0, 0);
+ ASIO_KQUEUE_EV_SET(&events[1], descriptor,
+ EVFILT_WRITE, EV_DELETE, 0, 0, 0);
+ ::kevent(kqueue_fd_, events, descriptor_data->num_kevents_, 0, 0, 0);
+
+ op_queue<operation> ops;
+ for (int i = 0; i < max_ops; ++i)
+ ops.push(descriptor_data->op_queue_[i]);
+
+ descriptor_data->descriptor_ = -1;
+ descriptor_data->shutdown_ = true;
+
+ descriptor_lock.unlock();
+
+ ASIO_HANDLER_REACTOR_DEREGISTRATION((
+ context(), static_cast<uintmax_t>(descriptor),
+ reinterpret_cast<uintmax_t>(descriptor_data)));
+
+ // Leave descriptor_data set so that it will be freed by the subsequent
+ // call to cleanup_descriptor_data.
+ }
+ else
+ {
+ // We are shutting down, so prevent cleanup_descriptor_data from freeing
+ // the descriptor_data object and let the destructor free it instead.
+ descriptor_data = 0;
+ }
+}
+
+void kqueue_reactor::cleanup_descriptor_data(
+ per_descriptor_data& descriptor_data)
+{
+ if (descriptor_data)
+ {
+ free_descriptor_state(descriptor_data);
+ descriptor_data = 0;
+ }
+}
+
+void kqueue_reactor::run(long usec, op_queue<operation>& ops)
+{
+ mutex::scoped_lock lock(mutex_);
+
+ // Determine how long to block while waiting for events.
+ timespec timeout_buf = { 0, 0 };
+ timespec* timeout = usec ? get_timeout(usec, timeout_buf) : &timeout_buf;
+
+ lock.unlock();
+
+ // Block on the kqueue descriptor.
+ struct kevent events[128];
+ int num_events = kevent(kqueue_fd_, 0, 0, events, 128, timeout);
+
+#if defined(ASIO_ENABLE_HANDLER_TRACKING)
+ // Trace the waiting events.
+ for (int i = 0; i < num_events; ++i)
+ {
+ void* ptr = reinterpret_cast<void*>(events[i].udata);
+ if (ptr != &interrupter_)
+ {
+ unsigned event_mask = 0;
+ switch (events[i].filter)
+ {
+ case EVFILT_READ:
+ event_mask |= ASIO_HANDLER_REACTOR_READ_EVENT;
+ break;
+ case EVFILT_WRITE:
+ event_mask |= ASIO_HANDLER_REACTOR_WRITE_EVENT;
+ break;
+ }
+ if ((events[i].flags & (EV_ERROR | EV_OOBAND)) != 0)
+ event_mask |= ASIO_HANDLER_REACTOR_ERROR_EVENT;
+ ASIO_HANDLER_REACTOR_EVENTS((context(),
+ reinterpret_cast<uintmax_t>(ptr), event_mask));
+ }
+ }
+#endif // defined(ASIO_ENABLE_HANDLER_TRACKING)
+
+ // Dispatch the waiting events.
+ for (int i = 0; i < num_events; ++i)
+ {
+ void* ptr = reinterpret_cast<void*>(events[i].udata);
+ if (ptr == &interrupter_)
+ {
+ interrupter_.reset();
+ }
+ else
+ {
+ descriptor_state* descriptor_data = static_cast<descriptor_state*>(ptr);
+ mutex::scoped_lock descriptor_lock(descriptor_data->mutex_);
+
+ if (events[i].filter == EVFILT_WRITE
+ && descriptor_data->num_kevents_ == 2
+ && descriptor_data->op_queue_[write_op].empty())
+ {
+ // Some descriptor types, like serial ports, don't seem to support
+ // EV_CLEAR with EVFILT_WRITE. Since we have no pending write
+ // operations we'll remove the EVFILT_WRITE registration here so that
+ // we don't end up in a tight spin.
+ struct kevent delete_events[1];
+ ASIO_KQUEUE_EV_SET(&delete_events[0],
+ descriptor_data->descriptor_, EVFILT_WRITE, EV_DELETE, 0, 0, 0);
+ ::kevent(kqueue_fd_, delete_events, 1, 0, 0, 0);
+ descriptor_data->num_kevents_ = 1;
+ }
+
+ // Exception operations must be processed first to ensure that any
+ // out-of-band data is read before normal data.
+#if defined(__NetBSD__)
+ static const unsigned int filter[max_ops] =
+#else
+ static const int filter[max_ops] =
+#endif
+ { EVFILT_READ, EVFILT_WRITE, EVFILT_READ };
+ for (int j = max_ops - 1; j >= 0; --j)
+ {
+ if (events[i].filter == filter[j])
+ {
+ if (j != except_op || events[i].flags & EV_OOBAND)
+ {
+ while (reactor_op* op = descriptor_data->op_queue_[j].front())
+ {
+ if (events[i].flags & EV_ERROR)
+ {
+ op->ec_ = asio::error_code(
+ static_cast<int>(events[i].data),
+ asio::error::get_system_category());
+ descriptor_data->op_queue_[j].pop();
+ ops.push(op);
+ }
+ if (op->perform())
+ {
+ descriptor_data->op_queue_[j].pop();
+ ops.push(op);
+ }
+ else
+ break;
+ }
+ }
+ }
+ }
+ }
+ }
+
+ lock.lock();
+ timer_queues_.get_ready_timers(ops);
+}
+
+void kqueue_reactor::interrupt()
+{
+ interrupter_.interrupt();
+}
+
+int kqueue_reactor::do_kqueue_create()
+{
+ int fd = ::kqueue();
+ if (fd == -1)
+ {
+ asio::error_code ec(errno,
+ asio::error::get_system_category());
+ asio::detail::throw_error(ec, "kqueue");
+ }
+ return fd;
+}
+
+kqueue_reactor::descriptor_state* kqueue_reactor::allocate_descriptor_state()
+{
+ mutex::scoped_lock descriptors_lock(registered_descriptors_mutex_);
+ return registered_descriptors_.alloc(ASIO_CONCURRENCY_HINT_IS_LOCKING(
+ REACTOR_IO, scheduler_.concurrency_hint()));
+}
+
+void kqueue_reactor::free_descriptor_state(kqueue_reactor::descriptor_state* s)
+{
+ mutex::scoped_lock descriptors_lock(registered_descriptors_mutex_);
+ registered_descriptors_.free(s);
+}
+
+void kqueue_reactor::do_add_timer_queue(timer_queue_base& queue)
+{
+ mutex::scoped_lock lock(mutex_);
+ timer_queues_.insert(&queue);
+}
+
+void kqueue_reactor::do_remove_timer_queue(timer_queue_base& queue)
+{
+ mutex::scoped_lock lock(mutex_);
+ timer_queues_.erase(&queue);
+}
+
+timespec* kqueue_reactor::get_timeout(long usec, timespec& ts)
+{
+ // By default we will wait no longer than 5 minutes. This will ensure that
+ // any changes to the system clock are detected after no longer than this.
+ const long max_usec = 5 * 60 * 1000 * 1000;
+ usec = timer_queues_.wait_duration_usec(
+ (usec < 0 || max_usec < usec) ? max_usec : usec);
+ ts.tv_sec = usec / 1000000;
+ ts.tv_nsec = (usec % 1000000) * 1000;
+ return &ts;
+}
+
+} // namespace detail
+} // namespace asio
+
+#undef ASIO_KQUEUE_EV_SET
+
+#include "asio/detail/pop_options.hpp"
+
+#endif // defined(ASIO_HAS_KQUEUE)
+
+#endif // ASIO_DETAIL_IMPL_KQUEUE_REACTOR_IPP
diff --git a/lib/asio/detail/impl/null_event.ipp b/lib/asio/detail/impl/null_event.ipp
new file mode 100644
index 0000000..22ade40
--- /dev/null
+++ b/lib/asio/detail/impl/null_event.ipp
@@ -0,0 +1,74 @@
+//
+// detail/impl/null_event.ipp
+// ~~~~~~~~~~~~~~~~~~~~~~~~~~
+//
+// Copyright (c) 2003-2018 Christopher M. Kohlhoff (chris at kohlhoff dot com)
+//
+// 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 ASIO_DETAIL_IMPL_NULL_EVENT_IPP
+#define ASIO_DETAIL_IMPL_NULL_EVENT_IPP
+
+#if defined(_MSC_VER) && (_MSC_VER >= 1200)
+# pragma once
+#endif // defined(_MSC_VER) && (_MSC_VER >= 1200)
+
+#include "asio/detail/config.hpp"
+
+#if defined(ASIO_WINDOWS_RUNTIME)
+# include <thread>
+#elif defined(ASIO_WINDOWS) || defined(__CYGWIN__)
+# include "asio/detail/socket_types.hpp"
+#else
+# include <unistd.h>
+# if defined(__hpux)
+# include <sys/time.h>
+# endif
+# if !defined(__hpux) || defined(__SELECT)
+# include <sys/select.h>
+# endif
+#endif
+
+#include "asio/detail/push_options.hpp"
+
+namespace asio {
+namespace detail {
+
+void null_event::do_wait()
+{
+#if defined(ASIO_WINDOWS_RUNTIME)
+ std::this_thread::sleep_until((std::chrono::steady_clock::time_point::max)());
+#elif defined(ASIO_WINDOWS) || defined(__CYGWIN__)
+ ::Sleep(INFINITE);
+#else
+ ::pause();
+#endif
+}
+
+void null_event::do_wait_for_usec(long usec)
+{
+#if defined(ASIO_WINDOWS_RUNTIME)
+ std::this_thread::sleep_for(std::chrono::microseconds(usec));
+#elif defined(ASIO_WINDOWS) || defined(__CYGWIN__)
+ ::Sleep(usec / 1000);
+#elif defined(__hpux) && defined(__SELECT)
+ timespec ts;
+ ts.tv_sec = usec / 1000000;
+ ts.tv_nsec = (usec % 1000000) * 1000;
+ ::pselect(0, 0, 0, 0, &ts, 0);
+#else
+ timeval tv;
+ tv.tv_sec = usec / 1000000;
+ tv.tv_usec = usec % 1000000;
+ ::select(0, 0, 0, 0, &tv);
+#endif
+}
+
+} // namespace detail
+} // namespace asio
+
+#include "asio/detail/pop_options.hpp"
+
+#endif // ASIO_DETAIL_IMPL_NULL_EVENT_IPP
diff --git a/lib/asio/detail/impl/pipe_select_interrupter.ipp b/lib/asio/detail/impl/pipe_select_interrupter.ipp
new file mode 100644
index 0000000..13931ab
--- /dev/null
+++ b/lib/asio/detail/impl/pipe_select_interrupter.ipp
@@ -0,0 +1,124 @@
+//
+// detail/impl/pipe_select_interrupter.ipp
+// ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+//
+// Copyright (c) 2003-2018 Christopher M. Kohlhoff (chris at kohlhoff dot com)
+//
+// 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 ASIO_DETAIL_IMPL_PIPE_SELECT_INTERRUPTER_IPP
+#define ASIO_DETAIL_IMPL_PIPE_SELECT_INTERRUPTER_IPP
+
+#if defined(_MSC_VER) && (_MSC_VER >= 1200)
+# pragma once
+#endif // defined(_MSC_VER) && (_MSC_VER >= 1200)
+
+#include "asio/detail/config.hpp"
+
+#if !defined(ASIO_WINDOWS_RUNTIME)
+#if !defined(ASIO_WINDOWS)
+#if !defined(__CYGWIN__)
+#if !defined(__SYMBIAN32__)
+#if !defined(ASIO_HAS_EVENTFD)
+
+#include <fcntl.h>
+#include <sys/stat.h>
+#include <sys/types.h>
+#include <unistd.h>
+#include "asio/detail/pipe_select_interrupter.hpp"
+#include "asio/detail/socket_types.hpp"
+#include "asio/detail/throw_error.hpp"
+#include "asio/error.hpp"
+
+#include "asio/detail/push_options.hpp"
+
+namespace asio {
+namespace detail {
+
+pipe_select_interrupter::pipe_select_interrupter()
+{
+ open_descriptors();
+}
+
+void pipe_select_interrupter::open_descriptors()
+{
+ int pipe_fds[2];
+ if (pipe(pipe_fds) == 0)
+ {
+ read_descriptor_ = pipe_fds[0];
+ ::fcntl(read_descriptor_, F_SETFL, O_NONBLOCK);
+ write_descriptor_ = pipe_fds[1];
+ ::fcntl(write_descriptor_, F_SETFL, O_NONBLOCK);
+
+#if defined(FD_CLOEXEC)
+ ::fcntl(read_descriptor_, F_SETFD, FD_CLOEXEC);
+ ::fcntl(write_descriptor_, F_SETFD, FD_CLOEXEC);
+#endif // defined(FD_CLOEXEC)
+ }
+ else
+ {
+ asio::error_code ec(errno,
+ asio::error::get_system_category());
+ asio::detail::throw_error(ec, "pipe_select_interrupter");
+ }
+}
+
+pipe_select_interrupter::~pipe_select_interrupter()
+{
+ close_descriptors();
+}
+
+void pipe_select_interrupter::close_descriptors()
+{
+ if (read_descriptor_ != -1)
+ ::close(read_descriptor_);
+ if (write_descriptor_ != -1)
+ ::close(write_descriptor_);
+}
+
+void pipe_select_interrupter::recreate()
+{
+ close_descriptors();
+
+ write_descriptor_ = -1;
+ read_descriptor_ = -1;
+
+ open_descriptors();
+}
+
+void pipe_select_interrupter::interrupt()
+{
+ char byte = 0;
+ signed_size_type result = ::write(write_descriptor_, &byte, 1);
+ (void)result;
+}
+
+bool pipe_select_interrupter::reset()
+{
+ for (;;)
+ {
+ char data[1024];
+ signed_size_type bytes_read = ::read(read_descriptor_, data, sizeof(data));
+ if (bytes_read < 0 && errno == EINTR)
+ continue;
+ bool was_interrupted = (bytes_read > 0);
+ while (bytes_read == sizeof(data))
+ bytes_read = ::read(read_descriptor_, data, sizeof(data));
+ return was_interrupted;
+ }
+}
+
+} // namespace detail
+} // namespace asio
+
+#include "asio/detail/pop_options.hpp"
+
+#endif // !defined(ASIO_HAS_EVENTFD)
+#endif // !defined(__SYMBIAN32__)
+#endif // !defined(__CYGWIN__)
+#endif // !defined(ASIO_WINDOWS)
+#endif // !defined(ASIO_WINDOWS_RUNTIME)
+
+#endif // ASIO_DETAIL_IMPL_PIPE_SELECT_INTERRUPTER_IPP
diff --git a/lib/asio/detail/impl/posix_event.ipp b/lib/asio/detail/impl/posix_event.ipp
new file mode 100644
index 0000000..4b46ab0
--- /dev/null
+++ b/lib/asio/detail/impl/posix_event.ipp
@@ -0,0 +1,59 @@
+//
+// detail/impl/posix_event.ipp
+// ~~~~~~~~~~~~~~~~~~~~~~~~~~~
+//
+// Copyright (c) 2003-2018 Christopher M. Kohlhoff (chris at kohlhoff dot com)
+//
+// 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 ASIO_DETAIL_IMPL_POSIX_EVENT_IPP
+#define ASIO_DETAIL_IMPL_POSIX_EVENT_IPP
+
+#if defined(_MSC_VER) && (_MSC_VER >= 1200)
+# pragma once
+#endif // defined(_MSC_VER) && (_MSC_VER >= 1200)
+
+#include "asio/detail/config.hpp"
+
+#if defined(ASIO_HAS_PTHREADS)
+
+#include "asio/detail/posix_event.hpp"
+#include "asio/detail/throw_error.hpp"
+#include "asio/error.hpp"
+
+#include "asio/detail/push_options.hpp"
+
+namespace asio {
+namespace detail {
+
+posix_event::posix_event()
+ : state_(0)
+{
+#if (defined(__MACH__) && defined(__APPLE__)) \
+ || (defined(__ANDROID__) && (__ANDROID_API__ < 21))
+ int error = ::pthread_cond_init(&cond_, 0);
+#else // (defined(__MACH__) && defined(__APPLE__))
+ // || (defined(__ANDROID__) && (__ANDROID_API__ < 21))
+ ::pthread_condattr_t attr;
+ ::pthread_condattr_init(&attr);
+ int error = ::pthread_condattr_setclock(&attr, CLOCK_MONOTONIC);
+ if (error == 0)
+ error = ::pthread_cond_init(&cond_, &attr);
+#endif // (defined(__MACH__) && defined(__APPLE__))
+ // || (defined(__ANDROID__) && (__ANDROID_API__ < 21))
+
+ asio::error_code ec(error,
+ asio::error::get_system_category());
+ asio::detail::throw_error(ec, "event");
+}
+
+} // namespace detail
+} // namespace asio
+
+#include "asio/detail/pop_options.hpp"
+
+#endif // defined(ASIO_HAS_PTHREADS)
+
+#endif // ASIO_DETAIL_IMPL_POSIX_EVENT_IPP
diff --git a/lib/asio/detail/impl/posix_mutex.ipp b/lib/asio/detail/impl/posix_mutex.ipp
new file mode 100644
index 0000000..27272b5
--- /dev/null
+++ b/lib/asio/detail/impl/posix_mutex.ipp
@@ -0,0 +1,46 @@
+//
+// detail/impl/posix_mutex.ipp
+// ~~~~~~~~~~~~~~~~~~~~~~~~~~~
+//
+// Copyright (c) 2003-2018 Christopher M. Kohlhoff (chris at kohlhoff dot com)
+//
+// 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 ASIO_DETAIL_IMPL_POSIX_MUTEX_IPP
+#define ASIO_DETAIL_IMPL_POSIX_MUTEX_IPP
+
+#if defined(_MSC_VER) && (_MSC_VER >= 1200)
+# pragma once
+#endif // defined(_MSC_VER) && (_MSC_VER >= 1200)
+
+#include "asio/detail/config.hpp"
+
+#if defined(ASIO_HAS_PTHREADS)
+
+#include "asio/detail/posix_mutex.hpp"
+#include "asio/detail/throw_error.hpp"
+#include "asio/error.hpp"
+
+#include "asio/detail/push_options.hpp"
+
+namespace asio {
+namespace detail {
+
+posix_mutex::posix_mutex()
+{
+ int error = ::pthread_mutex_init(&mutex_, 0);
+ asio::error_code ec(error,
+ asio::error::get_system_category());
+ asio::detail::throw_error(ec, "mutex");
+}
+
+} // namespace detail
+} // namespace asio
+
+#include "asio/detail/pop_options.hpp"
+
+#endif // defined(ASIO_HAS_PTHREADS)
+
+#endif // ASIO_DETAIL_IMPL_POSIX_MUTEX_IPP
diff --git a/lib/asio/detail/impl/posix_thread.ipp b/lib/asio/detail/impl/posix_thread.ipp
new file mode 100644
index 0000000..69bd16f
--- /dev/null
+++ b/lib/asio/detail/impl/posix_thread.ipp
@@ -0,0 +1,84 @@
+//
+// detail/impl/posix_thread.ipp
+// ~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+//
+// Copyright (c) 2003-2018 Christopher M. Kohlhoff (chris at kohlhoff dot com)
+//
+// 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 ASIO_DETAIL_IMPL_POSIX_THREAD_IPP
+#define ASIO_DETAIL_IMPL_POSIX_THREAD_IPP
+
+#if defined(_MSC_VER) && (_MSC_VER >= 1200)
+# pragma once
+#endif // defined(_MSC_VER) && (_MSC_VER >= 1200)
+
+#include "asio/detail/config.hpp"
+
+#if defined(ASIO_HAS_PTHREADS)
+
+#include "asio/detail/posix_thread.hpp"
+#include "asio/detail/throw_error.hpp"
+#include "asio/error.hpp"
+
+#include "asio/detail/push_options.hpp"
+
+namespace asio {
+namespace detail {
+
+posix_thread::~posix_thread()
+{
+ if (!joined_)
+ ::pthread_detach(thread_);
+}
+
+void posix_thread::join()
+{
+ if (!joined_)
+ {
+ ::pthread_join(thread_, 0);
+ joined_ = true;
+ }
+}
+
+std::size_t posix_thread::hardware_concurrency()
+{
+#if defined(_SC_NPROCESSORS_ONLN)
+ long result = sysconf(_SC_NPROCESSORS_ONLN);
+ if (result > 0)
+ return result;
+#endif // defined(_SC_NPROCESSORS_ONLN)
+ return 0;
+}
+
+void posix_thread::start_thread(func_base* arg)
+{
+ int error = ::pthread_create(&thread_, 0,
+ asio_detail_posix_thread_function, arg);
+ if (error != 0)
+ {
+ delete arg;
+ asio::error_code ec(error,
+ asio::error::get_system_category());
+ asio::detail::throw_error(ec, "thread");
+ }
+}
+
+void* asio_detail_posix_thread_function(void* arg)
+{
+ posix_thread::auto_func_base_ptr func = {
+ static_cast<posix_thread::func_base*>(arg) };
+ func.ptr->run();
+ return 0;
+}
+
+} // namespace detail
+} // namespace asio
+
+#include "asio/detail/pop_options.hpp"
+
+#endif // defined(ASIO_HAS_PTHREADS)
+
+#endif // ASIO_DETAIL_IMPL_POSIX_THREAD_IPP
diff --git a/lib/asio/detail/impl/posix_tss_ptr.ipp b/lib/asio/detail/impl/posix_tss_ptr.ipp
new file mode 100644
index 0000000..54b58bd
--- /dev/null
+++ b/lib/asio/detail/impl/posix_tss_ptr.ipp
@@ -0,0 +1,46 @@
+//
+// detail/impl/posix_tss_ptr.ipp
+// ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+//
+// Copyright (c) 2003-2018 Christopher M. Kohlhoff (chris at kohlhoff dot com)
+//
+// 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 ASIO_DETAIL_IMPL_POSIX_TSS_PTR_IPP
+#define ASIO_DETAIL_IMPL_POSIX_TSS_PTR_IPP
+
+#if defined(_MSC_VER) && (_MSC_VER >= 1200)
+# pragma once
+#endif // defined(_MSC_VER) && (_MSC_VER >= 1200)
+
+#include "asio/detail/config.hpp"
+
+#if defined(ASIO_HAS_PTHREADS)
+
+#include "asio/detail/posix_tss_ptr.hpp"
+#include "asio/detail/throw_error.hpp"
+#include "asio/error.hpp"
+
+#include "asio/detail/push_options.hpp"
+
+namespace asio {
+namespace detail {
+
+void posix_tss_ptr_create(pthread_key_t& key)
+{
+ int error = ::pthread_key_create(&key, 0);
+ asio::error_code ec(error,
+ asio::error::get_system_category());
+ asio::detail::throw_error(ec, "tss");
+}
+
+} // namespace detail
+} // namespace asio
+
+#include "asio/detail/pop_options.hpp"
+
+#endif // defined(ASIO_HAS_PTHREADS)
+
+#endif // ASIO_DETAIL_IMPL_POSIX_TSS_PTR_IPP
diff --git a/lib/asio/detail/impl/reactive_descriptor_service.ipp b/lib/asio/detail/impl/reactive_descriptor_service.ipp
new file mode 100644
index 0000000..f9505ca
--- /dev/null
+++ b/lib/asio/detail/impl/reactive_descriptor_service.ipp
@@ -0,0 +1,222 @@
+//
+// detail/impl/reactive_descriptor_service.ipp
+// ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+//
+// Copyright (c) 2003-2018 Christopher M. Kohlhoff (chris at kohlhoff dot com)
+//
+// 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 ASIO_DETAIL_IMPL_REACTIVE_DESCRIPTOR_SERVICE_IPP
+#define ASIO_DETAIL_IMPL_REACTIVE_DESCRIPTOR_SERVICE_IPP
+
+#if defined(_MSC_VER) && (_MSC_VER >= 1200)
+# pragma once
+#endif // defined(_MSC_VER) && (_MSC_VER >= 1200)
+
+#include "asio/detail/config.hpp"
+
+#if !defined(ASIO_WINDOWS) \
+ && !defined(ASIO_WINDOWS_RUNTIME) \
+ && !defined(__CYGWIN__)
+
+#include "asio/error.hpp"
+#include "asio/detail/reactive_descriptor_service.hpp"
+
+#include "asio/detail/push_options.hpp"
+
+namespace asio {
+namespace detail {
+
+reactive_descriptor_service::reactive_descriptor_service(
+ asio::io_context& io_context)
+ : service_base<reactive_descriptor_service>(io_context),
+ reactor_(asio::use_service<reactor>(io_context))
+{
+ reactor_.init_task();
+}
+
+void reactive_descriptor_service::shutdown()
+{
+}
+
+void reactive_descriptor_service::construct(
+ reactive_descriptor_service::implementation_type& impl)
+{
+ impl.descriptor_ = -1;
+ impl.state_ = 0;
+}
+
+void reactive_descriptor_service::move_construct(
+ reactive_descriptor_service::implementation_type& impl,
+ reactive_descriptor_service::implementation_type& other_impl)
+{
+ impl.descriptor_ = other_impl.descriptor_;
+ other_impl.descriptor_ = -1;
+
+ impl.state_ = other_impl.state_;
+ other_impl.state_ = 0;
+
+ reactor_.move_descriptor(impl.descriptor_,
+ impl.reactor_data_, other_impl.reactor_data_);
+}
+
+void reactive_descriptor_service::move_assign(
+ reactive_descriptor_service::implementation_type& impl,
+ reactive_descriptor_service& other_service,
+ reactive_descriptor_service::implementation_type& other_impl)
+{
+ destroy(impl);
+
+ impl.descriptor_ = other_impl.descriptor_;
+ other_impl.descriptor_ = -1;
+
+ impl.state_ = other_impl.state_;
+ other_impl.state_ = 0;
+
+ other_service.reactor_.move_descriptor(impl.descriptor_,
+ impl.reactor_data_, other_impl.reactor_data_);
+}
+
+void reactive_descriptor_service::destroy(
+ reactive_descriptor_service::implementation_type& impl)
+{
+ if (is_open(impl))
+ {
+ ASIO_HANDLER_OPERATION((reactor_.context(),
+ "descriptor", &impl, impl.descriptor_, "close"));
+
+ reactor_.deregister_descriptor(impl.descriptor_, impl.reactor_data_,
+ (impl.state_ & descriptor_ops::possible_dup) == 0);
+
+ asio::error_code ignored_ec;
+ descriptor_ops::close(impl.descriptor_, impl.state_, ignored_ec);
+
+ reactor_.cleanup_descriptor_data(impl.reactor_data_);
+ }
+}
+
+asio::error_code reactive_descriptor_service::assign(
+ reactive_descriptor_service::implementation_type& impl,
+ const native_handle_type& native_descriptor, asio::error_code& ec)
+{
+ if (is_open(impl))
+ {
+ ec = asio::error::already_open;
+ return ec;
+ }
+
+ if (int err = reactor_.register_descriptor(
+ native_descriptor, impl.reactor_data_))
+ {
+ ec = asio::error_code(err,
+ asio::error::get_system_category());
+ return ec;
+ }
+
+ impl.descriptor_ = native_descriptor;
+ impl.state_ = descriptor_ops::possible_dup;
+ ec = asio::error_code();
+ return ec;
+}
+
+asio::error_code reactive_descriptor_service::close(
+ reactive_descriptor_service::implementation_type& impl,
+ asio::error_code& ec)
+{
+ if (is_open(impl))
+ {
+ ASIO_HANDLER_OPERATION((reactor_.context(),
+ "descriptor", &impl, impl.descriptor_, "close"));
+
+ reactor_.deregister_descriptor(impl.descriptor_, impl.reactor_data_,
+ (impl.state_ & descriptor_ops::possible_dup) == 0);
+
+ descriptor_ops::close(impl.descriptor_, impl.state_, ec);
+
+ reactor_.cleanup_descriptor_data(impl.reactor_data_);
+ }
+ else
+ {
+ ec = asio::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.)
+ construct(impl);
+
+ return ec;
+}
+
+reactive_descriptor_service::native_handle_type
+reactive_descriptor_service::release(
+ reactive_descriptor_service::implementation_type& impl)
+{
+ native_handle_type descriptor = impl.descriptor_;
+
+ if (is_open(impl))
+ {
+ ASIO_HANDLER_OPERATION((reactor_.context(),
+ "descriptor", &impl, impl.descriptor_, "release"));
+
+ reactor_.deregister_descriptor(impl.descriptor_, impl.reactor_data_, false);
+ reactor_.cleanup_descriptor_data(impl.reactor_data_);
+ construct(impl);
+ }
+
+ return descriptor;
+}
+
+asio::error_code reactive_descriptor_service::cancel(
+ reactive_descriptor_service::implementation_type& impl,
+ asio::error_code& ec)
+{
+ if (!is_open(impl))
+ {
+ ec = asio::error::bad_descriptor;
+ return ec;
+ }
+
+ ASIO_HANDLER_OPERATION((reactor_.context(),
+ "descriptor", &impl, impl.descriptor_, "cancel"));
+
+ reactor_.cancel_ops(impl.descriptor_, impl.reactor_data_);
+ ec = asio::error_code();
+ return ec;
+}
+
+void reactive_descriptor_service::start_op(
+ reactive_descriptor_service::implementation_type& impl,
+ int op_type, reactor_op* op, bool is_continuation,
+ bool is_non_blocking, bool noop)
+{
+ if (!noop)
+ {
+ if ((impl.state_ & descriptor_ops::non_blocking) ||
+ descriptor_ops::set_internal_non_blocking(
+ impl.descriptor_, impl.state_, true, op->ec_))
+ {
+ reactor_.start_op(op_type, impl.descriptor_,
+ impl.reactor_data_, op, is_continuation, is_non_blocking);
+ return;
+ }
+ }
+
+ reactor_.post_immediate_completion(op, is_continuation);
+}
+
+} // namespace detail
+} // namespace asio
+
+#include "asio/detail/pop_options.hpp"
+
+#endif // !defined(ASIO_WINDOWS)
+ // && !defined(ASIO_WINDOWS_RUNTIME)
+ // && !defined(__CYGWIN__)
+
+#endif // ASIO_DETAIL_IMPL_REACTIVE_DESCRIPTOR_SERVICE_IPP
diff --git a/lib/asio/detail/impl/reactive_serial_port_service.ipp b/lib/asio/detail/impl/reactive_serial_port_service.ipp
new file mode 100644
index 0000000..c907835
--- /dev/null
+++ b/lib/asio/detail/impl/reactive_serial_port_service.ipp
@@ -0,0 +1,152 @@
+//
+// detail/impl/reactive_serial_port_service.ipp
+// ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+//
+// Copyright (c) 2003-2018 Christopher M. Kohlhoff (chris at kohlhoff dot com)
+// Copyright (c) 2008 Rep Invariant Systems, Inc. (info@repinvariant.com)
+//
+// 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 ASIO_DETAIL_IMPL_REACTIVE_SERIAL_PORT_SERVICE_IPP
+#define ASIO_DETAIL_IMPL_REACTIVE_SERIAL_PORT_SERVICE_IPP
+
+#if defined(_MSC_VER) && (_MSC_VER >= 1200)
+# pragma once
+#endif // defined(_MSC_VER) && (_MSC_VER >= 1200)
+
+#include "asio/detail/config.hpp"
+
+#if defined(ASIO_HAS_SERIAL_PORT)
+#if !defined(ASIO_WINDOWS) && !defined(__CYGWIN__)
+
+#include <cstring>
+#include "asio/detail/reactive_serial_port_service.hpp"
+
+#include "asio/detail/push_options.hpp"
+
+namespace asio {
+namespace detail {
+
+reactive_serial_port_service::reactive_serial_port_service(
+ asio::io_context& io_context)
+ : service_base<reactive_serial_port_service>(io_context),
+ descriptor_service_(io_context)
+{
+}
+
+void reactive_serial_port_service::shutdown()
+{
+ descriptor_service_.shutdown();
+}
+
+asio::error_code reactive_serial_port_service::open(
+ reactive_serial_port_service::implementation_type& impl,
+ const std::string& device, asio::error_code& ec)
+{
+ if (is_open(impl))
+ {
+ ec = asio::error::already_open;
+ return ec;
+ }
+
+ descriptor_ops::state_type state = 0;
+ int fd = descriptor_ops::open(device.c_str(),
+ O_RDWR | O_NONBLOCK | O_NOCTTY, ec);
+ if (fd < 0)
+ return ec;
+
+ int s = descriptor_ops::fcntl(fd, F_GETFL, ec);
+ if (s >= 0)
+ s = descriptor_ops::fcntl(fd, F_SETFL, s | O_NONBLOCK, ec);
+ if (s < 0)
+ {
+ asio::error_code ignored_ec;
+ descriptor_ops::close(fd, state, ignored_ec);
+ return ec;
+ }
+
+ // Set up default serial port options.
+ termios ios;
+ errno = 0;
+ s = descriptor_ops::error_wrapper(::tcgetattr(fd, &ios), ec);
+ if (s >= 0)
+ {
+#if defined(_BSD_SOURCE) || defined(_DEFAULT_SOURCE)
+ ::cfmakeraw(&ios);
+#else
+ ios.c_iflag &= ~(IGNBRK | BRKINT | PARMRK
+ | ISTRIP | INLCR | IGNCR | ICRNL | IXON);
+ ios.c_oflag &= ~OPOST;
+ ios.c_lflag &= ~(ECHO | ECHONL | ICANON | ISIG | IEXTEN);
+ ios.c_cflag &= ~(CSIZE | PARENB);
+ ios.c_cflag |= CS8;
+#endif
+ ios.c_iflag |= IGNPAR;
+ ios.c_cflag |= CREAD | CLOCAL;
+ errno = 0;
+ s = descriptor_ops::error_wrapper(::tcsetattr(fd, TCSANOW, &ios), ec);
+ }
+ if (s < 0)
+ {
+ asio::error_code ignored_ec;
+ descriptor_ops::close(fd, state, ignored_ec);
+ return ec;
+ }
+
+ // We're done. Take ownership of the serial port descriptor.
+ if (descriptor_service_.assign(impl, fd, ec))
+ {
+ asio::error_code ignored_ec;
+ descriptor_ops::close(fd, state, ignored_ec);
+ }
+
+ return ec;
+}
+
+asio::error_code reactive_serial_port_service::do_set_option(
+ reactive_serial_port_service::implementation_type& impl,
+ reactive_serial_port_service::store_function_type store,
+ const void* option, asio::error_code& ec)
+{
+ termios ios;
+ errno = 0;
+ descriptor_ops::error_wrapper(::tcgetattr(
+ descriptor_service_.native_handle(impl), &ios), ec);
+ if (ec)
+ return ec;
+
+ if (store(option, ios, ec))
+ return ec;
+
+ errno = 0;
+ descriptor_ops::error_wrapper(::tcsetattr(
+ descriptor_service_.native_handle(impl), TCSANOW, &ios), ec);
+ return ec;
+}
+
+asio::error_code reactive_serial_port_service::do_get_option(
+ const reactive_serial_port_service::implementation_type& impl,
+ reactive_serial_port_service::load_function_type load,
+ void* option, asio::error_code& ec) const
+{
+ termios ios;
+ errno = 0;
+ descriptor_ops::error_wrapper(::tcgetattr(
+ descriptor_service_.native_handle(impl), &ios), ec);
+ if (ec)
+ return ec;
+
+ return load(option, ios, ec);
+}
+
+} // namespace detail
+} // namespace asio
+
+#include "asio/detail/pop_options.hpp"
+
+#endif // !defined(ASIO_WINDOWS) && !defined(__CYGWIN__)
+#endif // defined(ASIO_HAS_SERIAL_PORT)
+
+#endif // ASIO_DETAIL_IMPL_REACTIVE_SERIAL_PORT_SERVICE_IPP
diff --git a/lib/asio/detail/impl/reactive_socket_service_base.ipp b/lib/asio/detail/impl/reactive_socket_service_base.ipp
new file mode 100644
index 0000000..129b851
--- /dev/null
+++ b/lib/asio/detail/impl/reactive_socket_service_base.ipp
@@ -0,0 +1,300 @@
+//
+// detail/reactive_socket_service_base.ipp
+// ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+//
+// Copyright (c) 2003-2018 Christopher M. Kohlhoff (chris at kohlhoff dot com)
+//
+// 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 ASIO_DETAIL_IMPL_REACTIVE_SOCKET_SERVICE_BASE_IPP
+#define ASIO_DETAIL_IMPL_REACTIVE_SOCKET_SERVICE_BASE_IPP
+
+#if defined(_MSC_VER) && (_MSC_VER >= 1200)
+# pragma once
+#endif // defined(_MSC_VER) && (_MSC_VER >= 1200)
+
+#include "asio/detail/config.hpp"
+
+#if !defined(ASIO_HAS_IOCP) \
+ && !defined(ASIO_WINDOWS_RUNTIME)
+
+#include "asio/detail/reactive_socket_service_base.hpp"
+
+#include "asio/detail/push_options.hpp"
+
+namespace asio {
+namespace detail {
+
+reactive_socket_service_base::reactive_socket_service_base(
+ asio::io_context& io_context)
+ : io_context_(io_context),
+ reactor_(use_service<reactor>(io_context))
+{
+ reactor_.init_task();
+}
+
+void reactive_socket_service_base::base_shutdown()
+{
+}
+
+void reactive_socket_service_base::construct(
+ reactive_socket_service_base::base_implementation_type& impl)
+{
+ impl.socket_ = invalid_socket;
+ impl.state_ = 0;
+}
+
+void reactive_socket_service_base::base_move_construct(
+ reactive_socket_service_base::base_implementation_type& impl,
+ reactive_socket_service_base::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::base_move_assign(
+ reactive_socket_service_base::base_implementation_type& impl,
+ reactive_socket_service_base& other_service,
+ reactive_socket_service_base::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::destroy(
+ reactive_socket_service_base::base_implementation_type& impl)
+{
+ if (impl.socket_ != invalid_socket)
+ {
+ 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);
+
+ asio::error_code ignored_ec;
+ socket_ops::close(impl.socket_, impl.state_, true, ignored_ec);
+
+ reactor_.cleanup_descriptor_data(impl.reactor_data_);
+ }
+}
+
+asio::error_code reactive_socket_service_base::close(
+ reactive_socket_service_base::base_implementation_type& impl,
+ asio::error_code& ec)
+{
+ if (is_open(impl))
+ {
+ 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 = asio::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,
+ asio::error_code& ec)
+{
+ if (!is_open(impl))
+ {
+ ec = asio::error::bad_descriptor;
+ return invalid_socket;
+ }
+
+ 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 = asio::error_code();
+ return sock;
+}
+
+asio::error_code reactive_socket_service_base::cancel(
+ reactive_socket_service_base::base_implementation_type& impl,
+ asio::error_code& ec)
+{
+ if (!is_open(impl))
+ {
+ ec = asio::error::bad_descriptor;
+ return ec;
+ }
+
+ ASIO_HANDLER_OPERATION((reactor_.context(),
+ "socket", &impl, impl.socket_, "cancel"));
+
+ reactor_.cancel_ops(impl.socket_, impl.reactor_data_);
+ ec = asio::error_code();
+ return ec;
+}
+
+asio::error_code reactive_socket_service_base::do_open(
+ reactive_socket_service_base::base_implementation_type& impl,
+ int af, int type, int protocol, asio::error_code& ec)
+{
+ if (is_open(impl))
+ {
+ ec = 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 = asio::error_code(err,
+ 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 = asio::error_code();
+ return ec;
+}
+
+asio::error_code reactive_socket_service_base::do_assign(
+ reactive_socket_service_base::base_implementation_type& impl, int type,
+ const reactive_socket_service_base::native_handle_type& native_socket,
+ asio::error_code& ec)
+{
+ if (is_open(impl))
+ {
+ ec = asio::error::already_open;
+ return ec;
+ }
+
+ if (int err = reactor_.register_descriptor(
+ native_socket, impl.reactor_data_))
+ {
+ ec = asio::error_code(err,
+ 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 = asio::error_code();
+ return ec;
+}
+
+void reactive_socket_service_base::start_op(
+ reactive_socket_service_base::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::start_accept_op(
+ reactive_socket_service_base::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_ = asio::error::already_open;
+ reactor_.post_immediate_completion(op, is_continuation);
+ }
+}
+
+void reactive_socket_service_base::start_connect_op(
+ reactive_socket_service_base::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_ == asio::error::in_progress
+ || op->ec_ == asio::error::would_block)
+ {
+ op->ec_ = asio::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
+
+#include "asio/detail/pop_options.hpp"
+
+#endif // !defined(ASIO_HAS_IOCP)
+ // && !defined(ASIO_WINDOWS_RUNTIME)
+
+#endif // ASIO_DETAIL_IMPL_REACTIVE_SOCKET_SERVICE_BASE_IPP
diff --git a/lib/asio/detail/impl/resolver_service_base.ipp b/lib/asio/detail/impl/resolver_service_base.ipp
new file mode 100644
index 0000000..540bb66
--- /dev/null
+++ b/lib/asio/detail/impl/resolver_service_base.ipp
@@ -0,0 +1,154 @@
+//
+// detail/impl/resolver_service_base.ipp
+// ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+//
+// Copyright (c) 2003-2018 Christopher M. Kohlhoff (chris at kohlhoff dot com)
+//
+// 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 ASIO_DETAIL_IMPL_RESOLVER_SERVICE_BASE_IPP
+#define ASIO_DETAIL_IMPL_RESOLVER_SERVICE_BASE_IPP
+
+#if defined(_MSC_VER) && (_MSC_VER >= 1200)
+# pragma once
+#endif // defined(_MSC_VER) && (_MSC_VER >= 1200)
+
+#include "asio/detail/config.hpp"
+#include "asio/detail/resolver_service_base.hpp"
+
+#include "asio/detail/push_options.hpp"
+
+namespace asio {
+namespace detail {
+
+class resolver_service_base::work_io_context_runner
+{
+public:
+ work_io_context_runner(asio::io_context& io_context)
+ : io_context_(io_context) {}
+ void operator()() { io_context_.run(); }
+private:
+ asio::io_context& io_context_;
+};
+
+resolver_service_base::resolver_service_base(
+ asio::io_context& io_context)
+ : io_context_impl_(asio::use_service<io_context_impl>(io_context)),
+ work_io_context_(new asio::io_context(-1)),
+ work_io_context_impl_(asio::use_service<
+ io_context_impl>(*work_io_context_)),
+ work_(asio::make_work_guard(*work_io_context_)),
+ work_thread_(0)
+{
+}
+
+resolver_service_base::~resolver_service_base()
+{
+ base_shutdown();
+}
+
+void resolver_service_base::base_shutdown()
+{
+ work_.reset();
+ if (work_io_context_.get())
+ {
+ work_io_context_->stop();
+ if (work_thread_.get())
+ {
+ work_thread_->join();
+ work_thread_.reset();
+ }
+ work_io_context_.reset();
+ }
+}
+
+void resolver_service_base::base_notify_fork(
+ asio::io_context::fork_event fork_ev)
+{
+ if (work_thread_.get())
+ {
+ if (fork_ev == asio::io_context::fork_prepare)
+ {
+ work_io_context_->stop();
+ work_thread_->join();
+ }
+ else
+ {
+ work_io_context_->restart();
+ work_thread_.reset(new asio::detail::thread(
+ work_io_context_runner(*work_io_context_)));
+ }
+ }
+}
+
+void resolver_service_base::construct(
+ resolver_service_base::implementation_type& impl)
+{
+ impl.reset(static_cast<void*>(0), socket_ops::noop_deleter());
+}
+
+void resolver_service_base::destroy(
+ resolver_service_base::implementation_type& impl)
+{
+ ASIO_HANDLER_OPERATION((io_context_impl_.context(),
+ "resolver", &impl, 0, "cancel"));
+
+ impl.reset();
+}
+
+void resolver_service_base::move_construct(implementation_type& impl,
+ implementation_type& other_impl)
+{
+ impl = ASIO_MOVE_CAST(implementation_type)(other_impl);
+}
+
+void resolver_service_base::move_assign(implementation_type& impl,
+ resolver_service_base&, implementation_type& other_impl)
+{
+ destroy(impl);
+ impl = ASIO_MOVE_CAST(implementation_type)(other_impl);
+}
+
+void resolver_service_base::cancel(
+ resolver_service_base::implementation_type& impl)
+{
+ ASIO_HANDLER_OPERATION((io_context_impl_.context(),
+ "resolver", &impl, 0, "cancel"));
+
+ impl.reset(static_cast<void*>(0), socket_ops::noop_deleter());
+}
+
+void resolver_service_base::start_resolve_op(resolve_op* op)
+{
+ if (ASIO_CONCURRENCY_HINT_IS_LOCKING(SCHEDULER,
+ io_context_impl_.concurrency_hint()))
+ {
+ start_work_thread();
+ io_context_impl_.work_started();
+ work_io_context_impl_.post_immediate_completion(op, false);
+ }
+ else
+ {
+ op->ec_ = asio::error::operation_not_supported;
+ io_context_impl_.post_immediate_completion(op, false);
+ }
+}
+
+void resolver_service_base::start_work_thread()
+{
+ asio::detail::mutex::scoped_lock lock(mutex_);
+ if (!work_thread_.get())
+ {
+ work_thread_.reset(new asio::detail::thread(
+ work_io_context_runner(*work_io_context_)));
+ }
+}
+
+} // namespace detail
+} // namespace asio
+
+#include "asio/detail/pop_options.hpp"
+
+#endif // ASIO_DETAIL_IMPL_RESOLVER_SERVICE_BASE_IPP
diff --git a/lib/asio/detail/impl/scheduler.ipp b/lib/asio/detail/impl/scheduler.ipp
new file mode 100644
index 0000000..35bc678
--- /dev/null
+++ b/lib/asio/detail/impl/scheduler.ipp
@@ -0,0 +1,571 @@
+//
+// detail/impl/scheduler.ipp
+// ~~~~~~~~~~~~~~~~~~~~~~~~~
+//
+// Copyright (c) 2003-2018 Christopher M. Kohlhoff (chris at kohlhoff dot com)
+//
+// 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 ASIO_DETAIL_IMPL_SCHEDULER_IPP
+#define ASIO_DETAIL_IMPL_SCHEDULER_IPP
+
+#if defined(_MSC_VER) && (_MSC_VER >= 1200)
+# pragma once
+#endif // defined(_MSC_VER) && (_MSC_VER >= 1200)
+
+#include "asio/detail/config.hpp"
+
+#include "asio/detail/concurrency_hint.hpp"
+#include "asio/detail/event.hpp"
+#include "asio/detail/limits.hpp"
+#include "asio/detail/reactor.hpp"
+#include "asio/detail/scheduler.hpp"
+#include "asio/detail/scheduler_thread_info.hpp"
+
+#include "asio/detail/push_options.hpp"
+
+namespace asio {
+namespace detail {
+
+struct scheduler::task_cleanup
+{
+ ~task_cleanup()
+ {
+ if (this_thread_->private_outstanding_work > 0)
+ {
+ asio::detail::increment(
+ scheduler_->outstanding_work_,
+ this_thread_->private_outstanding_work);
+ }
+ this_thread_->private_outstanding_work = 0;
+
+ // Enqueue the completed operations and reinsert the task at the end of
+ // the operation queue.
+ lock_->lock();
+ scheduler_->task_interrupted_ = true;
+ scheduler_->op_queue_.push(this_thread_->private_op_queue);
+ scheduler_->op_queue_.push(&scheduler_->task_operation_);
+ }
+
+ scheduler* scheduler_;
+ mutex::scoped_lock* lock_;
+ thread_info* this_thread_;
+};
+
+struct scheduler::work_cleanup
+{
+ ~work_cleanup()
+ {
+ if (this_thread_->private_outstanding_work > 1)
+ {
+ asio::detail::increment(
+ scheduler_->outstanding_work_,
+ this_thread_->private_outstanding_work - 1);
+ }
+ else if (this_thread_->private_outstanding_work < 1)
+ {
+ scheduler_->work_finished();
+ }
+ this_thread_->private_outstanding_work = 0;
+
+#if defined(ASIO_HAS_THREADS)
+ if (!this_thread_->private_op_queue.empty())
+ {
+ lock_->lock();
+ scheduler_->op_queue_.push(this_thread_->private_op_queue);
+ }
+#endif // defined(ASIO_HAS_THREADS)
+ }
+
+ scheduler* scheduler_;
+ mutex::scoped_lock* lock_;
+ thread_info* this_thread_;
+};
+
+scheduler::scheduler(
+ asio::execution_context& ctx, int concurrency_hint)
+ : asio::detail::execution_context_service_base<scheduler>(ctx),
+ one_thread_(concurrency_hint == 1
+ || !ASIO_CONCURRENCY_HINT_IS_LOCKING(
+ SCHEDULER, concurrency_hint)
+ || !ASIO_CONCURRENCY_HINT_IS_LOCKING(
+ REACTOR_IO, concurrency_hint)),
+ mutex_(ASIO_CONCURRENCY_HINT_IS_LOCKING(
+ SCHEDULER, concurrency_hint)),
+ task_(0),
+ task_interrupted_(true),
+ outstanding_work_(0),
+ stopped_(false),
+ shutdown_(false),
+ concurrency_hint_(concurrency_hint)
+{
+ ASIO_HANDLER_TRACKING_INIT;
+}
+
+void scheduler::shutdown()
+{
+ mutex::scoped_lock lock(mutex_);
+ shutdown_ = true;
+ lock.unlock();
+
+ // Destroy handler objects.
+ while (!op_queue_.empty())
+ {
+ operation* o = op_queue_.front();
+ op_queue_.pop();
+ if (o != &task_operation_)
+ o->destroy();
+ }
+
+ // Reset to initial state.
+ task_ = 0;
+}
+
+void scheduler::init_task()
+{
+ mutex::scoped_lock lock(mutex_);
+ if (!shutdown_ && !task_)
+ {
+ task_ = &use_service<reactor>(this->context());
+ op_queue_.push(&task_operation_);
+ wake_one_thread_and_unlock(lock);
+ }
+}
+
+std::size_t scheduler::run(asio::error_code& ec)
+{
+ ec = asio::error_code();
+ if (outstanding_work_ == 0)
+ {
+ stop();
+ return 0;
+ }
+
+ thread_info this_thread;
+ this_thread.private_outstanding_work = 0;
+ thread_call_stack::context ctx(this, this_thread);
+
+ mutex::scoped_lock lock(mutex_);
+
+ std::size_t n = 0;
+ for (; do_run_one(lock, this_thread, ec); lock.lock())
+ if (n != (std::numeric_limits<std::size_t>::max)())
+ ++n;
+ return n;
+}
+
+std::size_t scheduler::run_one(asio::error_code& ec)
+{
+ ec = asio::error_code();
+ if (outstanding_work_ == 0)
+ {
+ stop();
+ return 0;
+ }
+
+ thread_info this_thread;
+ this_thread.private_outstanding_work = 0;
+ thread_call_stack::context ctx(this, this_thread);
+
+ mutex::scoped_lock lock(mutex_);
+
+ return do_run_one(lock, this_thread, ec);
+}
+
+std::size_t scheduler::wait_one(long usec, asio::error_code& ec)
+{
+ ec = asio::error_code();
+ if (outstanding_work_ == 0)
+ {
+ stop();
+ return 0;
+ }
+
+ thread_info this_thread;
+ this_thread.private_outstanding_work = 0;
+ thread_call_stack::context ctx(this, this_thread);
+
+ mutex::scoped_lock lock(mutex_);
+
+ return do_wait_one(lock, this_thread, usec, ec);
+}
+
+std::size_t scheduler::poll(asio::error_code& ec)
+{
+ ec = asio::error_code();
+ if (outstanding_work_ == 0)
+ {
+ stop();
+ return 0;
+ }
+
+ thread_info this_thread;
+ this_thread.private_outstanding_work = 0;
+ thread_call_stack::context ctx(this, this_thread);
+
+ mutex::scoped_lock lock(mutex_);
+
+#if defined(ASIO_HAS_THREADS)
+ // We want to support nested calls to poll() and poll_one(), so any handlers
+ // that are already on a thread-private queue need to be put on to the main
+ // queue now.
+ if (one_thread_)
+ if (thread_info* outer_info = static_cast<thread_info*>(ctx.next_by_key()))
+ op_queue_.push(outer_info->private_op_queue);
+#endif // defined(ASIO_HAS_THREADS)
+
+ std::size_t n = 0;
+ for (; do_poll_one(lock, this_thread, ec); lock.lock())
+ if (n != (std::numeric_limits<std::size_t>::max)())
+ ++n;
+ return n;
+}
+
+std::size_t scheduler::poll_one(asio::error_code& ec)
+{
+ ec = asio::error_code();
+ if (outstanding_work_ == 0)
+ {
+ stop();
+ return 0;
+ }
+
+ thread_info this_thread;
+ this_thread.private_outstanding_work = 0;
+ thread_call_stack::context ctx(this, this_thread);
+
+ mutex::scoped_lock lock(mutex_);
+
+#if defined(ASIO_HAS_THREADS)
+ // We want to support nested calls to poll() and poll_one(), so any handlers
+ // that are already on a thread-private queue need to be put on to the main
+ // queue now.
+ if (one_thread_)
+ if (thread_info* outer_info = static_cast<thread_info*>(ctx.next_by_key()))
+ op_queue_.push(outer_info->private_op_queue);
+#endif // defined(ASIO_HAS_THREADS)
+
+ return do_poll_one(lock, this_thread, ec);
+}
+
+void scheduler::stop()
+{
+ mutex::scoped_lock lock(mutex_);
+ stop_all_threads(lock);
+}
+
+bool scheduler::stopped() const
+{
+ mutex::scoped_lock lock(mutex_);
+ return stopped_;
+}
+
+void scheduler::restart()
+{
+ mutex::scoped_lock lock(mutex_);
+ stopped_ = false;
+}
+
+void scheduler::compensating_work_started()
+{
+ thread_info_base* this_thread = thread_call_stack::contains(this);
+ ++static_cast<thread_info*>(this_thread)->private_outstanding_work;
+}
+
+void scheduler::post_immediate_completion(
+ scheduler::operation* op, bool is_continuation)
+{
+#if defined(ASIO_HAS_THREADS)
+ if (one_thread_ || is_continuation)
+ {
+ if (thread_info_base* this_thread = thread_call_stack::contains(this))
+ {
+ ++static_cast<thread_info*>(this_thread)->private_outstanding_work;
+ static_cast<thread_info*>(this_thread)->private_op_queue.push(op);
+ return;
+ }
+ }
+#else // defined(ASIO_HAS_THREADS)
+ (void)is_continuation;
+#endif // defined(ASIO_HAS_THREADS)
+
+ work_started();
+ mutex::scoped_lock lock(mutex_);
+ op_queue_.push(op);
+ wake_one_thread_and_unlock(lock);
+}
+
+void scheduler::post_deferred_completion(scheduler::operation* op)
+{
+#if defined(ASIO_HAS_THREADS)
+ if (one_thread_)
+ {
+ if (thread_info_base* this_thread = thread_call_stack::contains(this))
+ {
+ static_cast<thread_info*>(this_thread)->private_op_queue.push(op);
+ return;
+ }
+ }
+#endif // defined(ASIO_HAS_THREADS)
+
+ mutex::scoped_lock lock(mutex_);
+ op_queue_.push(op);
+ wake_one_thread_and_unlock(lock);
+}
+
+void scheduler::post_deferred_completions(
+ op_queue<scheduler::operation>& ops)
+{
+ if (!ops.empty())
+ {
+#if defined(ASIO_HAS_THREADS)
+ if (one_thread_)
+ {
+ if (thread_info_base* this_thread = thread_call_stack::contains(this))
+ {
+ static_cast<thread_info*>(this_thread)->private_op_queue.push(ops);
+ return;
+ }
+ }
+#endif // defined(ASIO_HAS_THREADS)
+
+ mutex::scoped_lock lock(mutex_);
+ op_queue_.push(ops);
+ wake_one_thread_and_unlock(lock);
+ }
+}
+
+void scheduler::do_dispatch(
+ scheduler::operation* op)
+{
+ work_started();
+ mutex::scoped_lock lock(mutex_);
+ op_queue_.push(op);
+ wake_one_thread_and_unlock(lock);
+}
+
+void scheduler::abandon_operations(
+ op_queue<scheduler::operation>& ops)
+{
+ op_queue<scheduler::operation> ops2;
+ ops2.push(ops);
+}
+
+std::size_t scheduler::do_run_one(mutex::scoped_lock& lock,
+ scheduler::thread_info& this_thread,
+ const asio::error_code& ec)
+{
+ while (!stopped_)
+ {
+ if (!op_queue_.empty())
+ {
+ // Prepare to execute first handler from queue.
+ operation* o = op_queue_.front();
+ op_queue_.pop();
+ bool more_handlers = (!op_queue_.empty());
+
+ if (o == &task_operation_)
+ {
+ task_interrupted_ = more_handlers;
+
+ if (more_handlers && !one_thread_)
+ wakeup_event_.unlock_and_signal_one(lock);
+ else
+ lock.unlock();
+
+ task_cleanup on_exit = { this, &lock, &this_thread };
+ (void)on_exit;
+
+ // Run the task. May throw an exception. Only block if the operation
+ // queue is empty and we're not polling, otherwise we want to return
+ // as soon as possible.
+ task_->run(more_handlers ? 0 : -1, this_thread.private_op_queue);
+ }
+ else
+ {
+ std::size_t task_result = o->task_result_;
+
+ if (more_handlers && !one_thread_)
+ wake_one_thread_and_unlock(lock);
+ else
+ lock.unlock();
+
+ // Ensure the count of outstanding work is decremented on block exit.
+ work_cleanup on_exit = { this, &lock, &this_thread };
+ (void)on_exit;
+
+ // Complete the operation. May throw an exception. Deletes the object.
+ o->complete(this, ec, task_result);
+
+ return 1;
+ }
+ }
+ else
+ {
+ wakeup_event_.clear(lock);
+ wakeup_event_.wait(lock);
+ }
+ }
+
+ return 0;
+}
+
+std::size_t scheduler::do_wait_one(mutex::scoped_lock& lock,
+ scheduler::thread_info& this_thread, long usec,
+ const asio::error_code& ec)
+{
+ if (stopped_)
+ return 0;
+
+ operation* o = op_queue_.front();
+ if (o == 0)
+ {
+ wakeup_event_.clear(lock);
+ wakeup_event_.wait_for_usec(lock, usec);
+ usec = 0; // Wait at most once.
+ o = op_queue_.front();
+ }
+
+ if (o == &task_operation_)
+ {
+ op_queue_.pop();
+ bool more_handlers = (!op_queue_.empty());
+
+ task_interrupted_ = more_handlers;
+
+ if (more_handlers && !one_thread_)
+ wakeup_event_.unlock_and_signal_one(lock);
+ else
+ lock.unlock();
+
+ {
+ task_cleanup on_exit = { this, &lock, &this_thread };
+ (void)on_exit;
+
+ // Run the task. May throw an exception. Only block if the operation
+ // queue is empty and we're not polling, otherwise we want to return
+ // as soon as possible.
+ task_->run(more_handlers ? 0 : usec, this_thread.private_op_queue);
+ }
+
+ o = op_queue_.front();
+ if (o == &task_operation_)
+ {
+ if (!one_thread_)
+ wakeup_event_.maybe_unlock_and_signal_one(lock);
+ return 0;
+ }
+ }
+
+ if (o == 0)
+ return 0;
+
+ op_queue_.pop();
+ bool more_handlers = (!op_queue_.empty());
+
+ std::size_t task_result = o->task_result_;
+
+ if (more_handlers && !one_thread_)
+ wake_one_thread_and_unlock(lock);
+ else
+ lock.unlock();
+
+ // Ensure the count of outstanding work is decremented on block exit.
+ work_cleanup on_exit = { this, &lock, &this_thread };
+ (void)on_exit;
+
+ // Complete the operation. May throw an exception. Deletes the object.
+ o->complete(this, ec, task_result);
+
+ return 1;
+}
+
+std::size_t scheduler::do_poll_one(mutex::scoped_lock& lock,
+ scheduler::thread_info& this_thread,
+ const asio::error_code& ec)
+{
+ if (stopped_)
+ return 0;
+
+ operation* o = op_queue_.front();
+ if (o == &task_operation_)
+ {
+ op_queue_.pop();
+ lock.unlock();
+
+ {
+ task_cleanup c = { this, &lock, &this_thread };
+ (void)c;
+
+ // Run the task. May throw an exception. Only block if the operation
+ // queue is empty and we're not polling, otherwise we want to return
+ // as soon as possible.
+ task_->run(0, this_thread.private_op_queue);
+ }
+
+ o = op_queue_.front();
+ if (o == &task_operation_)
+ {
+ wakeup_event_.maybe_unlock_and_signal_one(lock);
+ return 0;
+ }
+ }
+
+ if (o == 0)
+ return 0;
+
+ op_queue_.pop();
+ bool more_handlers = (!op_queue_.empty());
+
+ std::size_t task_result = o->task_result_;
+
+ if (more_handlers && !one_thread_)
+ wake_one_thread_and_unlock(lock);
+ else
+ lock.unlock();
+
+ // Ensure the count of outstanding work is decremented on block exit.
+ work_cleanup on_exit = { this, &lock, &this_thread };
+ (void)on_exit;
+
+ // Complete the operation. May throw an exception. Deletes the object.
+ o->complete(this, ec, task_result);
+
+ return 1;
+}
+
+void scheduler::stop_all_threads(
+ mutex::scoped_lock& lock)
+{
+ stopped_ = true;
+ wakeup_event_.signal_all(lock);
+
+ if (!task_interrupted_ && task_)
+ {
+ task_interrupted_ = true;
+ task_->interrupt();
+ }
+}
+
+void scheduler::wake_one_thread_and_unlock(
+ mutex::scoped_lock& lock)
+{
+ if (!wakeup_event_.maybe_unlock_and_signal_one(lock))
+ {
+ if (!task_interrupted_ && task_)
+ {
+ task_interrupted_ = true;
+ task_->interrupt();
+ }
+ lock.unlock();
+ }
+}
+
+} // namespace detail
+} // namespace asio
+
+#include "asio/detail/pop_options.hpp"
+
+#endif // ASIO_DETAIL_IMPL_SCHEDULER_IPP
diff --git a/lib/asio/detail/impl/select_reactor.hpp b/lib/asio/detail/impl/select_reactor.hpp
new file mode 100644
index 0000000..04a04d4
--- /dev/null
+++ b/lib/asio/detail/impl/select_reactor.hpp
@@ -0,0 +1,100 @@
+//
+// detail/impl/select_reactor.hpp
+// ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+//
+// Copyright (c) 2003-2018 Christopher M. Kohlhoff (chris at kohlhoff dot com)
+//
+// 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 ASIO_DETAIL_IMPL_SELECT_REACTOR_HPP
+#define ASIO_DETAIL_IMPL_SELECT_REACTOR_HPP
+
+#if defined(_MSC_VER) && (_MSC_VER >= 1200)
+# pragma once
+#endif // defined(_MSC_VER) && (_MSC_VER >= 1200)
+
+#include "asio/detail/config.hpp"
+
+#if defined(ASIO_HAS_IOCP) \
+ || (!defined(ASIO_HAS_DEV_POLL) \
+ && !defined(ASIO_HAS_EPOLL) \
+ && !defined(ASIO_HAS_KQUEUE) \
+ && !defined(ASIO_WINDOWS_RUNTIME))
+
+#include "asio/detail/push_options.hpp"
+
+namespace asio {
+namespace detail {
+
+template <typename Time_Traits>
+void select_reactor::add_timer_queue(timer_queue<Time_Traits>& queue)
+{
+ do_add_timer_queue(queue);
+}
+
+// Remove a timer queue from the reactor.
+template <typename Time_Traits>
+void select_reactor::remove_timer_queue(timer_queue<Time_Traits>& queue)
+{
+ do_remove_timer_queue(queue);
+}
+
+template <typename Time_Traits>
+void select_reactor::schedule_timer(timer_queue<Time_Traits>& queue,
+ const typename Time_Traits::time_type& time,
+ typename timer_queue<Time_Traits>::per_timer_data& timer, wait_op* op)
+{
+ asio::detail::mutex::scoped_lock lock(mutex_);
+
+ if (shutdown_)
+ {
+ scheduler_.post_immediate_completion(op, false);
+ return;
+ }
+
+ bool earliest = queue.enqueue_timer(time, timer, op);
+ scheduler_.work_started();
+ if (earliest)
+ interrupter_.interrupt();
+}
+
+template <typename Time_Traits>
+std::size_t select_reactor::cancel_timer(timer_queue<Time_Traits>& queue,
+ typename timer_queue<Time_Traits>::per_timer_data& timer,
+ std::size_t max_cancelled)
+{
+ asio::detail::mutex::scoped_lock lock(mutex_);
+ op_queue<operation> ops;
+ std::size_t n = queue.cancel_timer(timer, ops, max_cancelled);
+ lock.unlock();
+ scheduler_.post_deferred_completions(ops);
+ return n;
+}
+
+template <typename Time_Traits>
+void select_reactor::move_timer(timer_queue<Time_Traits>& queue,
+ typename timer_queue<Time_Traits>::per_timer_data& target,
+ typename timer_queue<Time_Traits>::per_timer_data& source)
+{
+ asio::detail::mutex::scoped_lock lock(mutex_);
+ op_queue<operation> ops;
+ queue.cancel_timer(target, ops);
+ queue.move_timer(target, source);
+ lock.unlock();
+ scheduler_.post_deferred_completions(ops);
+}
+
+} // namespace detail
+} // namespace asio
+
+#include "asio/detail/pop_options.hpp"
+
+#endif // defined(ASIO_HAS_IOCP)
+ // || (!defined(ASIO_HAS_DEV_POLL)
+ // && !defined(ASIO_HAS_EPOLL)
+ // && !defined(ASIO_HAS_KQUEUE)
+ // && !defined(ASIO_WINDOWS_RUNTIME))
+
+#endif // ASIO_DETAIL_IMPL_SELECT_REACTOR_HPP
diff --git a/lib/asio/detail/impl/select_reactor.ipp b/lib/asio/detail/impl/select_reactor.ipp
new file mode 100644
index 0000000..262bc69
--- /dev/null
+++ b/lib/asio/detail/impl/select_reactor.ipp
@@ -0,0 +1,333 @@
+//
+// detail/impl/select_reactor.ipp
+// ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+//
+// Copyright (c) 2003-2018 Christopher M. Kohlhoff (chris at kohlhoff dot com)
+//
+// 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 ASIO_DETAIL_IMPL_SELECT_REACTOR_IPP
+#define ASIO_DETAIL_IMPL_SELECT_REACTOR_IPP
+
+#if defined(_MSC_VER) && (_MSC_VER >= 1200)
+# pragma once
+#endif // defined(_MSC_VER) && (_MSC_VER >= 1200)
+
+#include "asio/detail/config.hpp"
+
+#if defined(ASIO_HAS_IOCP) \
+ || (!defined(ASIO_HAS_DEV_POLL) \
+ && !defined(ASIO_HAS_EPOLL) \
+ && !defined(ASIO_HAS_KQUEUE) \
+ && !defined(ASIO_WINDOWS_RUNTIME))
+
+#include "asio/detail/fd_set_adapter.hpp"
+#include "asio/detail/select_reactor.hpp"
+#include "asio/detail/signal_blocker.hpp"
+#include "asio/detail/socket_ops.hpp"
+
+#include "asio/detail/push_options.hpp"
+
+namespace asio {
+namespace detail {
+
+#if defined(ASIO_HAS_IOCP)
+class select_reactor::thread_function
+{
+public:
+ explicit thread_function(select_reactor* r)
+ : this_(r)
+ {
+ }
+
+ void operator()()
+ {
+ this_->run_thread();
+ }
+
+private:
+ select_reactor* this_;
+};
+#endif // defined(ASIO_HAS_IOCP)
+
+select_reactor::select_reactor(asio::execution_context& ctx)
+ : execution_context_service_base<select_reactor>(ctx),
+ scheduler_(use_service<scheduler_type>(ctx)),
+ mutex_(),
+ interrupter_(),
+#if defined(ASIO_HAS_IOCP)
+ stop_thread_(false),
+ thread_(0),
+#endif // defined(ASIO_HAS_IOCP)
+ shutdown_(false)
+{
+#if defined(ASIO_HAS_IOCP)
+ asio::detail::signal_blocker sb;
+ thread_ = new asio::detail::thread(thread_function(this));
+#endif // defined(ASIO_HAS_IOCP)
+}
+
+select_reactor::~select_reactor()
+{
+ shutdown();
+}
+
+void select_reactor::shutdown()
+{
+ asio::detail::mutex::scoped_lock lock(mutex_);
+ shutdown_ = true;
+#if defined(ASIO_HAS_IOCP)
+ stop_thread_ = true;
+#endif // defined(ASIO_HAS_IOCP)
+ lock.unlock();
+
+#if defined(ASIO_HAS_IOCP)
+ if (thread_)
+ {
+ interrupter_.interrupt();
+ thread_->join();
+ delete thread_;
+ thread_ = 0;
+ }
+#endif // defined(ASIO_HAS_IOCP)
+
+ op_queue<operation> ops;
+
+ for (int i = 0; i < max_ops; ++i)
+ op_queue_[i].get_all_operations(ops);
+
+ timer_queues_.get_all_timers(ops);
+
+ scheduler_.abandon_operations(ops);
+}
+
+void select_reactor::notify_fork(
+ asio::execution_context::fork_event fork_ev)
+{
+ if (fork_ev == asio::execution_context::fork_child)
+ interrupter_.recreate();
+}
+
+void select_reactor::init_task()
+{
+ scheduler_.init_task();
+}
+
+int select_reactor::register_descriptor(socket_type,
+ select_reactor::per_descriptor_data&)
+{
+ return 0;
+}
+
+int select_reactor::register_internal_descriptor(
+ int op_type, socket_type descriptor,
+ select_reactor::per_descriptor_data&, reactor_op* op)
+{
+ asio::detail::mutex::scoped_lock lock(mutex_);
+
+ op_queue_[op_type].enqueue_operation(descriptor, op);
+ interrupter_.interrupt();
+
+ return 0;
+}
+
+void select_reactor::move_descriptor(socket_type,
+ select_reactor::per_descriptor_data&,
+ select_reactor::per_descriptor_data&)
+{
+}
+
+void select_reactor::start_op(int op_type, socket_type descriptor,
+ select_reactor::per_descriptor_data&, reactor_op* op,
+ bool is_continuation, bool)
+{
+ asio::detail::mutex::scoped_lock lock(mutex_);
+
+ if (shutdown_)
+ {
+ post_immediate_completion(op, is_continuation);
+ return;
+ }
+
+ bool first = op_queue_[op_type].enqueue_operation(descriptor, op);
+ scheduler_.work_started();
+ if (first)
+ interrupter_.interrupt();
+}
+
+void select_reactor::cancel_ops(socket_type descriptor,
+ select_reactor::per_descriptor_data&)
+{
+ asio::detail::mutex::scoped_lock lock(mutex_);
+ cancel_ops_unlocked(descriptor, asio::error::operation_aborted);
+}
+
+void select_reactor::deregister_descriptor(socket_type descriptor,
+ select_reactor::per_descriptor_data&, bool)
+{
+ asio::detail::mutex::scoped_lock lock(mutex_);
+ cancel_ops_unlocked(descriptor, asio::error::operation_aborted);
+}
+
+void select_reactor::deregister_internal_descriptor(
+ socket_type descriptor, select_reactor::per_descriptor_data&)
+{
+ asio::detail::mutex::scoped_lock lock(mutex_);
+ op_queue<operation> ops;
+ for (int i = 0; i < max_ops; ++i)
+ op_queue_[i].cancel_operations(descriptor, ops);
+}
+
+void select_reactor::cleanup_descriptor_data(
+ select_reactor::per_descriptor_data&)
+{
+}
+
+void select_reactor::run(long usec, op_queue<operation>& ops)
+{
+ asio::detail::mutex::scoped_lock lock(mutex_);
+
+#if defined(ASIO_HAS_IOCP)
+ // Check if the thread is supposed to stop.
+ if (stop_thread_)
+ return;
+#endif // defined(ASIO_HAS_IOCP)
+
+ // Set up the descriptor sets.
+ for (int i = 0; i < max_select_ops; ++i)
+ fd_sets_[i].reset();
+ fd_sets_[read_op].set(interrupter_.read_descriptor());
+ socket_type max_fd = 0;
+ bool have_work_to_do = !timer_queues_.all_empty();
+ for (int i = 0; i < max_select_ops; ++i)
+ {
+ have_work_to_do = have_work_to_do || !op_queue_[i].empty();
+ fd_sets_[i].set(op_queue_[i], ops);
+ if (fd_sets_[i].max_descriptor() > max_fd)
+ max_fd = fd_sets_[i].max_descriptor();
+ }
+
+#if defined(ASIO_WINDOWS) || defined(__CYGWIN__)
+ // Connection operations on Windows use both except and write fd_sets.
+ have_work_to_do = have_work_to_do || !op_queue_[connect_op].empty();
+ fd_sets_[write_op].set(op_queue_[connect_op], ops);
+ if (fd_sets_[write_op].max_descriptor() > max_fd)
+ max_fd = fd_sets_[write_op].max_descriptor();
+ fd_sets_[except_op].set(op_queue_[connect_op], ops);
+ if (fd_sets_[except_op].max_descriptor() > max_fd)
+ max_fd = fd_sets_[except_op].max_descriptor();
+#endif // defined(ASIO_WINDOWS) || defined(__CYGWIN__)
+
+ // We can return immediately if there's no work to do and the reactor is
+ // not supposed to block.
+ if (!usec && !have_work_to_do)
+ return;
+
+ // Determine how long to block while waiting for events.
+ timeval tv_buf = { 0, 0 };
+ timeval* tv = usec ? get_timeout(usec, tv_buf) : &tv_buf;
+
+ lock.unlock();
+
+ // Block on the select call until descriptors become ready.
+ asio::error_code ec;
+ int retval = socket_ops::select(static_cast<int>(max_fd + 1),
+ fd_sets_[read_op], fd_sets_[write_op], fd_sets_[except_op], tv, ec);
+
+ // Reset the interrupter.
+ if (retval > 0 && fd_sets_[read_op].is_set(interrupter_.read_descriptor()))
+ {
+ interrupter_.reset();
+ --retval;
+ }
+
+ lock.lock();
+
+ // Dispatch all ready operations.
+ if (retval > 0)
+ {
+#if defined(ASIO_WINDOWS) || defined(__CYGWIN__)
+ // Connection operations on Windows use both except and write fd_sets.
+ fd_sets_[except_op].perform(op_queue_[connect_op], ops);
+ fd_sets_[write_op].perform(op_queue_[connect_op], ops);
+#endif // defined(ASIO_WINDOWS) || defined(__CYGWIN__)
+
+ // Exception operations must be processed first to ensure that any
+ // out-of-band data is read before normal data.
+ for (int i = max_select_ops - 1; i >= 0; --i)
+ fd_sets_[i].perform(op_queue_[i], ops);
+ }
+ timer_queues_.get_ready_timers(ops);
+}
+
+void select_reactor::interrupt()
+{
+ interrupter_.interrupt();
+}
+
+#if defined(ASIO_HAS_IOCP)
+void select_reactor::run_thread()
+{
+ asio::detail::mutex::scoped_lock lock(mutex_);
+ while (!stop_thread_)
+ {
+ lock.unlock();
+ op_queue<operation> ops;
+ run(true, ops);
+ scheduler_.post_deferred_completions(ops);
+ lock.lock();
+ }
+}
+#endif // defined(ASIO_HAS_IOCP)
+
+void select_reactor::do_add_timer_queue(timer_queue_base& queue)
+{
+ mutex::scoped_lock lock(mutex_);
+ timer_queues_.insert(&queue);
+}
+
+void select_reactor::do_remove_timer_queue(timer_queue_base& queue)
+{
+ mutex::scoped_lock lock(mutex_);
+ timer_queues_.erase(&queue);
+}
+
+timeval* select_reactor::get_timeout(long usec, timeval& tv)
+{
+ // By default we will wait no longer than 5 minutes. This will ensure that
+ // any changes to the system clock are detected after no longer than this.
+ const long max_usec = 5 * 60 * 1000 * 1000;
+ usec = timer_queues_.wait_duration_usec(
+ (usec < 0 || max_usec < usec) ? max_usec : usec);
+ tv.tv_sec = usec / 1000000;
+ tv.tv_usec = usec % 1000000;
+ return &tv;
+}
+
+void select_reactor::cancel_ops_unlocked(socket_type descriptor,
+ const asio::error_code& ec)
+{
+ bool need_interrupt = false;
+ op_queue<operation> ops;
+ for (int i = 0; i < max_ops; ++i)
+ need_interrupt = op_queue_[i].cancel_operations(
+ descriptor, ops, ec) || need_interrupt;
+ scheduler_.post_deferred_completions(ops);
+ if (need_interrupt)
+ interrupter_.interrupt();
+}
+
+} // namespace detail
+} // namespace asio
+
+#include "asio/detail/pop_options.hpp"
+
+#endif // defined(ASIO_HAS_IOCP)
+ // || (!defined(ASIO_HAS_DEV_POLL)
+ // && !defined(ASIO_HAS_EPOLL)
+ // && !defined(ASIO_HAS_KQUEUE))
+ // && !defined(ASIO_WINDOWS_RUNTIME))
+
+#endif // ASIO_DETAIL_IMPL_SELECT_REACTOR_IPP
diff --git a/lib/asio/detail/impl/service_registry.hpp b/lib/asio/detail/impl/service_registry.hpp
new file mode 100644
index 0000000..d4db589
--- /dev/null
+++ b/lib/asio/detail/impl/service_registry.hpp
@@ -0,0 +1,94 @@
+//
+// detail/impl/service_registry.hpp
+// ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+//
+// Copyright (c) 2003-2018 Christopher M. Kohlhoff (chris at kohlhoff dot com)
+//
+// 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 ASIO_DETAIL_IMPL_SERVICE_REGISTRY_HPP
+#define ASIO_DETAIL_IMPL_SERVICE_REGISTRY_HPP
+
+#if defined(_MSC_VER) && (_MSC_VER >= 1200)
+# pragma once
+#endif // defined(_MSC_VER) && (_MSC_VER >= 1200)
+
+#include "asio/detail/push_options.hpp"
+
+namespace asio {
+namespace detail {
+
+template <typename Service>
+Service& service_registry::use_service()
+{
+ execution_context::service::key key;
+ init_key<Service>(key, 0);
+ factory_type factory = &service_registry::create<Service, execution_context>;
+ return *static_cast<Service*>(do_use_service(key, factory, &owner_));
+}
+
+template <typename Service>
+Service& service_registry::use_service(io_context& owner)
+{
+ execution_context::service::key key;
+ init_key<Service>(key, 0);
+ factory_type factory = &service_registry::create<Service, io_context>;
+ return *static_cast<Service*>(do_use_service(key, factory, &owner));
+}
+
+template <typename Service>
+void service_registry::add_service(Service* new_service)
+{
+ execution_context::service::key key;
+ init_key<Service>(key, 0);
+ return do_add_service(key, new_service);
+}
+
+template <typename Service>
+bool service_registry::has_service() const
+{
+ execution_context::service::key key;
+ init_key<Service>(key, 0);
+ return do_has_service(key);
+}
+
+template <typename Service>
+inline void service_registry::init_key(
+ execution_context::service::key& key, ...)
+{
+ init_key_from_id(key, Service::id);
+}
+
+#if !defined(ASIO_NO_TYPEID)
+template <typename Service>
+void service_registry::init_key(execution_context::service::key& key,
+ typename enable_if<
+ is_base_of<typename Service::key_type, Service>::value>::type*)
+{
+ key.type_info_ = &typeid(typeid_wrapper<Service>);
+ key.id_ = 0;
+}
+
+template <typename Service>
+void service_registry::init_key_from_id(execution_context::service::key& key,
+ const service_id<Service>& /*id*/)
+{
+ key.type_info_ = &typeid(typeid_wrapper<Service>);
+ key.id_ = 0;
+}
+#endif // !defined(ASIO_NO_TYPEID)
+
+template <typename Service, typename Owner>
+execution_context::service* service_registry::create(void* owner)
+{
+ return new Service(*static_cast<Owner*>(owner));
+}
+
+} // namespace detail
+} // namespace asio
+
+#include "asio/detail/pop_options.hpp"
+
+#endif // ASIO_DETAIL_IMPL_SERVICE_REGISTRY_HPP
diff --git a/lib/asio/detail/impl/service_registry.ipp b/lib/asio/detail/impl/service_registry.ipp
new file mode 100644
index 0000000..a465033
--- /dev/null
+++ b/lib/asio/detail/impl/service_registry.ipp
@@ -0,0 +1,197 @@
+//
+// detail/impl/service_registry.ipp
+// ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+//
+// Copyright (c) 2003-2018 Christopher M. Kohlhoff (chris at kohlhoff dot com)
+//
+// 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 ASIO_DETAIL_IMPL_SERVICE_REGISTRY_IPP
+#define ASIO_DETAIL_IMPL_SERVICE_REGISTRY_IPP
+
+#if defined(_MSC_VER) && (_MSC_VER >= 1200)
+# pragma once
+#endif // defined(_MSC_VER) && (_MSC_VER >= 1200)
+
+#include "asio/detail/config.hpp"
+#include <vector>
+#include "asio/detail/service_registry.hpp"
+#include "asio/detail/throw_exception.hpp"
+
+#include "asio/detail/push_options.hpp"
+
+namespace asio {
+namespace detail {
+
+service_registry::service_registry(execution_context& owner)
+ : owner_(owner),
+ first_service_(0)
+{
+}
+
+service_registry::~service_registry()
+{
+}
+
+void service_registry::shutdown_services()
+{
+ execution_context::service* service = first_service_;
+ while (service)
+ {
+ service->shutdown();
+ service = service->next_;
+ }
+}
+
+void service_registry::destroy_services()
+{
+ while (first_service_)
+ {
+ execution_context::service* next_service = first_service_->next_;
+ destroy(first_service_);
+ first_service_ = next_service;
+ }
+}
+
+void service_registry::notify_fork(execution_context::fork_event fork_ev)
+{
+ // Make a copy of all of the services while holding the lock. We don't want
+ // to hold the lock while calling into each service, as it may try to call
+ // back into this class.
+ std::vector<execution_context::service*> services;
+ {
+ asio::detail::mutex::scoped_lock lock(mutex_);
+ execution_context::service* service = first_service_;
+ while (service)
+ {
+ services.push_back(service);
+ service = service->next_;
+ }
+ }
+
+ // If processing the fork_prepare event, we want to go in reverse order of
+ // service registration, which happens to be the existing order of the
+ // services in the vector. For the other events we want to go in the other
+ // direction.
+ std::size_t num_services = services.size();
+ if (fork_ev == execution_context::fork_prepare)
+ for (std::size_t i = 0; i < num_services; ++i)
+ services[i]->notify_fork(fork_ev);
+ else
+ for (std::size_t i = num_services; i > 0; --i)
+ services[i - 1]->notify_fork(fork_ev);
+}
+
+void service_registry::init_key_from_id(execution_context::service::key& key,
+ const execution_context::id& id)
+{
+ key.type_info_ = 0;
+ key.id_ = &id;
+}
+
+bool service_registry::keys_match(
+ const execution_context::service::key& key1,
+ const execution_context::service::key& key2)
+{
+ if (key1.id_ && key2.id_)
+ if (key1.id_ == key2.id_)
+ return true;
+ if (key1.type_info_ && key2.type_info_)
+ if (*key1.type_info_ == *key2.type_info_)
+ return true;
+ return false;
+}
+
+void service_registry::destroy(execution_context::service* service)
+{
+ delete service;
+}
+
+execution_context::service* service_registry::do_use_service(
+ const execution_context::service::key& key,
+ factory_type factory, void* owner)
+{
+ asio::detail::mutex::scoped_lock lock(mutex_);
+
+ // First see if there is an existing service object with the given key.
+ execution_context::service* service = first_service_;
+ while (service)
+ {
+ if (keys_match(service->key_, key))
+ return service;
+ service = service->next_;
+ }
+
+ // Create a new service object. The service registry's mutex is not locked
+ // at this time to allow for nested calls into this function from the new
+ // service's constructor.
+ lock.unlock();
+ auto_service_ptr new_service = { factory(owner) };
+ new_service.ptr_->key_ = key;
+ lock.lock();
+
+ // Check that nobody else created another service object of the same type
+ // while the lock was released.
+ service = first_service_;
+ while (service)
+ {
+ if (keys_match(service->key_, key))
+ return service;
+ service = service->next_;
+ }
+
+ // Service was successfully initialised, pass ownership to registry.
+ new_service.ptr_->next_ = first_service_;
+ first_service_ = new_service.ptr_;
+ new_service.ptr_ = 0;
+ return first_service_;
+}
+
+void service_registry::do_add_service(
+ const execution_context::service::key& key,
+ execution_context::service* new_service)
+{
+ if (&owner_ != &new_service->context())
+ asio::detail::throw_exception(invalid_service_owner());
+
+ asio::detail::mutex::scoped_lock lock(mutex_);
+
+ // Check if there is an existing service object with the given key.
+ execution_context::service* service = first_service_;
+ while (service)
+ {
+ if (keys_match(service->key_, key))
+ asio::detail::throw_exception(service_already_exists());
+ service = service->next_;
+ }
+
+ // Take ownership of the service object.
+ new_service->key_ = key;
+ new_service->next_ = first_service_;
+ first_service_ = new_service;
+}
+
+bool service_registry::do_has_service(
+ const execution_context::service::key& key) const
+{
+ asio::detail::mutex::scoped_lock lock(mutex_);
+
+ execution_context::service* service = first_service_;
+ while (service)
+ {
+ if (keys_match(service->key_, key))
+ return true;
+ service = service->next_;
+ }
+
+ return false;
+}
+
+} // namespace detail
+} // namespace asio
+
+#include "asio/detail/pop_options.hpp"
+
+#endif // ASIO_DETAIL_IMPL_SERVICE_REGISTRY_IPP
diff --git a/lib/asio/detail/impl/signal_set_service.ipp b/lib/asio/detail/impl/signal_set_service.ipp
new file mode 100644
index 0000000..dd68fc1
--- /dev/null
+++ b/lib/asio/detail/impl/signal_set_service.ipp
@@ -0,0 +1,669 @@
+//
+// detail/impl/signal_set_service.ipp
+// ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+//
+// Copyright (c) 2003-2018 Christopher M. Kohlhoff (chris at kohlhoff dot com)
+//
+// 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 ASIO_DETAIL_IMPL_SIGNAL_SET_SERVICE_IPP
+#define ASIO_DETAIL_IMPL_SIGNAL_SET_SERVICE_IPP
+
+#if defined(_MSC_VER) && (_MSC_VER >= 1200)
+# pragma once
+#endif // defined(_MSC_VER) && (_MSC_VER >= 1200)
+
+#include "asio/detail/config.hpp"
+
+#include <cstring>
+#include <stdexcept>
+#include "asio/detail/reactor.hpp"
+#include "asio/detail/signal_blocker.hpp"
+#include "asio/detail/signal_set_service.hpp"
+#include "asio/detail/static_mutex.hpp"
+#include "asio/detail/throw_exception.hpp"
+
+#include "asio/detail/push_options.hpp"
+
+namespace asio {
+namespace detail {
+
+struct signal_state
+{
+ // Mutex used for protecting global state.
+ static_mutex mutex_;
+
+ // The read end of the pipe used for signal notifications.
+ int read_descriptor_;
+
+ // The write end of the pipe used for signal notifications.
+ int write_descriptor_;
+
+ // Whether the signal state has been prepared for a fork.
+ bool fork_prepared_;
+
+ // The head of a linked list of all signal_set_service instances.
+ class signal_set_service* service_list_;
+
+ // A count of the number of objects that are registered for each signal.
+ std::size_t registration_count_[max_signal_number];
+};
+
+signal_state* get_signal_state()
+{
+ static signal_state state = {
+ ASIO_STATIC_MUTEX_INIT, -1, -1, false, 0, { 0 } };
+ return &state;
+}
+
+void asio_signal_handler(int signal_number)
+{
+#if defined(ASIO_WINDOWS) \
+ || defined(ASIO_WINDOWS_RUNTIME) \
+ || defined(__CYGWIN__)
+ signal_set_service::deliver_signal(signal_number);
+#else // defined(ASIO_WINDOWS)
+ // || defined(ASIO_WINDOWS_RUNTIME)
+ // || defined(__CYGWIN__)
+ int saved_errno = errno;
+ signal_state* state = get_signal_state();
+ signed_size_type result = ::write(state->write_descriptor_,
+ &signal_number, sizeof(signal_number));
+ (void)result;
+ errno = saved_errno;
+#endif // defined(ASIO_WINDOWS)
+ // || defined(ASIO_WINDOWS_RUNTIME)
+ // || defined(__CYGWIN__)
+
+#if defined(ASIO_HAS_SIGNAL) && !defined(ASIO_HAS_SIGACTION)
+ ::signal(signal_number, asio_signal_handler);
+#endif // defined(ASIO_HAS_SIGNAL) && !defined(ASIO_HAS_SIGACTION)
+}
+
+#if !defined(ASIO_WINDOWS) \
+ && !defined(ASIO_WINDOWS_RUNTIME) \
+ && !defined(__CYGWIN__)
+class signal_set_service::pipe_read_op : public reactor_op
+{
+public:
+ pipe_read_op()
+ : reactor_op(&pipe_read_op::do_perform, pipe_read_op::do_complete)
+ {
+ }
+
+ static status do_perform(reactor_op*)
+ {
+ signal_state* state = get_signal_state();
+
+ int fd = state->read_descriptor_;
+ int signal_number = 0;
+ while (::read(fd, &signal_number, sizeof(int)) == sizeof(int))
+ if (signal_number >= 0 && signal_number < max_signal_number)
+ signal_set_service::deliver_signal(signal_number);
+
+ return not_done;
+ }
+
+ static void do_complete(void* /*owner*/, operation* base,
+ const asio::error_code& /*ec*/,
+ std::size_t /*bytes_transferred*/)
+ {
+ pipe_read_op* o(static_cast<pipe_read_op*>(base));
+ delete o;
+ }
+};
+#endif // !defined(ASIO_WINDOWS)
+ // && !defined(ASIO_WINDOWS_RUNTIME)
+ // && !defined(__CYGWIN__)
+
+signal_set_service::signal_set_service(
+ asio::io_context& io_context)
+ : service_base<signal_set_service>(io_context),
+ io_context_(asio::use_service<io_context_impl>(io_context)),
+#if !defined(ASIO_WINDOWS) \
+ && !defined(ASIO_WINDOWS_RUNTIME) \
+ && !defined(__CYGWIN__)
+ reactor_(asio::use_service<reactor>(io_context)),
+#endif // !defined(ASIO_WINDOWS)
+ // && !defined(ASIO_WINDOWS_RUNTIME)
+ // && !defined(__CYGWIN__)
+ next_(0),
+ prev_(0)
+{
+ get_signal_state()->mutex_.init();
+
+#if !defined(ASIO_WINDOWS) \
+ && !defined(ASIO_WINDOWS_RUNTIME) \
+ && !defined(__CYGWIN__)
+ reactor_.init_task();
+#endif // !defined(ASIO_WINDOWS)
+ // && !defined(ASIO_WINDOWS_RUNTIME)
+ // && !defined(__CYGWIN__)
+
+ for (int i = 0; i < max_signal_number; ++i)
+ registrations_[i] = 0;
+
+ add_service(this);
+}
+
+signal_set_service::~signal_set_service()
+{
+ remove_service(this);
+}
+
+void signal_set_service::shutdown()
+{
+ remove_service(this);
+
+ op_queue<operation> ops;
+
+ for (int i = 0; i < max_signal_number; ++i)
+ {
+ registration* reg = registrations_[i];
+ while (reg)
+ {
+ ops.push(*reg->queue_);
+ reg = reg->next_in_table_;
+ }
+ }
+
+ io_context_.abandon_operations(ops);
+}
+
+void signal_set_service::notify_fork(
+ asio::io_context::fork_event fork_ev)
+{
+#if !defined(ASIO_WINDOWS) \
+ && !defined(ASIO_WINDOWS_RUNTIME) \
+ && !defined(__CYGWIN__)
+ signal_state* state = get_signal_state();
+ static_mutex::scoped_lock lock(state->mutex_);
+
+ switch (fork_ev)
+ {
+ case asio::io_context::fork_prepare:
+ {
+ int read_descriptor = state->read_descriptor_;
+ state->fork_prepared_ = true;
+ lock.unlock();
+ reactor_.deregister_internal_descriptor(read_descriptor, reactor_data_);
+ reactor_.cleanup_descriptor_data(reactor_data_);
+ }
+ break;
+ case asio::io_context::fork_parent:
+ if (state->fork_prepared_)
+ {
+ int read_descriptor = state->read_descriptor_;
+ state->fork_prepared_ = false;
+ lock.unlock();
+ reactor_.register_internal_descriptor(reactor::read_op,
+ read_descriptor, reactor_data_, new pipe_read_op);
+ }
+ break;
+ case asio::io_context::fork_child:
+ if (state->fork_prepared_)
+ {
+ asio::detail::signal_blocker blocker;
+ close_descriptors();
+ open_descriptors();
+ int read_descriptor = state->read_descriptor_;
+ state->fork_prepared_ = false;
+ lock.unlock();
+ reactor_.register_internal_descriptor(reactor::read_op,
+ read_descriptor, reactor_data_, new pipe_read_op);
+ }
+ break;
+ default:
+ break;
+ }
+#else // !defined(ASIO_WINDOWS)
+ // && !defined(ASIO_WINDOWS_RUNTIME)
+ // && !defined(__CYGWIN__)
+ (void)fork_ev;
+#endif // !defined(ASIO_WINDOWS)
+ // && !defined(ASIO_WINDOWS_RUNTIME)
+ // && !defined(__CYGWIN__)
+}
+
+void signal_set_service::construct(
+ signal_set_service::implementation_type& impl)
+{
+ impl.signals_ = 0;
+}
+
+void signal_set_service::destroy(
+ signal_set_service::implementation_type& impl)
+{
+ asio::error_code ignored_ec;
+ clear(impl, ignored_ec);
+ cancel(impl, ignored_ec);
+}
+
+asio::error_code signal_set_service::add(
+ signal_set_service::implementation_type& impl,
+ int signal_number, asio::error_code& ec)
+{
+ // Check that the signal number is valid.
+ if (signal_number < 0 || signal_number >= max_signal_number)
+ {
+ ec = asio::error::invalid_argument;
+ return ec;
+ }
+
+ signal_state* state = get_signal_state();
+ static_mutex::scoped_lock lock(state->mutex_);
+
+ // Find the appropriate place to insert the registration.
+ registration** insertion_point = &impl.signals_;
+ registration* next = impl.signals_;
+ while (next && next->signal_number_ < signal_number)
+ {
+ insertion_point = &next->next_in_set_;
+ next = next->next_in_set_;
+ }
+
+ // Only do something if the signal is not already registered.
+ if (next == 0 || next->signal_number_ != signal_number)
+ {
+ registration* new_registration = new registration;
+
+#if defined(ASIO_HAS_SIGNAL) || defined(ASIO_HAS_SIGACTION)
+ // Register for the signal if we're the first.
+ if (state->registration_count_[signal_number] == 0)
+ {
+# if defined(ASIO_HAS_SIGACTION)
+ using namespace std; // For memset.
+ struct sigaction sa;
+ memset(&sa, 0, sizeof(sa));
+ sa.sa_handler = asio_signal_handler;
+ sigfillset(&sa.sa_mask);
+ if (::sigaction(signal_number, &sa, 0) == -1)
+# else // defined(ASIO_HAS_SIGACTION)
+ if (::signal(signal_number, asio_signal_handler) == SIG_ERR)
+# endif // defined(ASIO_HAS_SIGACTION)
+ {
+# if defined(ASIO_WINDOWS) || defined(__CYGWIN__)
+ ec = asio::error::invalid_argument;
+# else // defined(ASIO_WINDOWS) || defined(__CYGWIN__)
+ ec = asio::error_code(errno,
+ asio::error::get_system_category());
+# endif // defined(ASIO_WINDOWS) || defined(__CYGWIN__)
+ delete new_registration;
+ return ec;
+ }
+ }
+#endif // defined(ASIO_HAS_SIGNAL) || defined(ASIO_HAS_SIGACTION)
+
+ // Record the new registration in the set.
+ new_registration->signal_number_ = signal_number;
+ new_registration->queue_ = &impl.queue_;
+ new_registration->next_in_set_ = next;
+ *insertion_point = new_registration;
+
+ // Insert registration into the registration table.
+ new_registration->next_in_table_ = registrations_[signal_number];
+ if (registrations_[signal_number])
+ registrations_[signal_number]->prev_in_table_ = new_registration;
+ registrations_[signal_number] = new_registration;
+
+ ++state->registration_count_[signal_number];
+ }
+
+ ec = asio::error_code();
+ return ec;
+}
+
+asio::error_code signal_set_service::remove(
+ signal_set_service::implementation_type& impl,
+ int signal_number, asio::error_code& ec)
+{
+ // Check that the signal number is valid.
+ if (signal_number < 0 || signal_number >= max_signal_number)
+ {
+ ec = asio::error::invalid_argument;
+ return ec;
+ }
+
+ signal_state* state = get_signal_state();
+ static_mutex::scoped_lock lock(state->mutex_);
+
+ // Find the signal number in the list of registrations.
+ registration** deletion_point = &impl.signals_;
+ registration* reg = impl.signals_;
+ while (reg && reg->signal_number_ < signal_number)
+ {
+ deletion_point = &reg->next_in_set_;
+ reg = reg->next_in_set_;
+ }
+
+ if (reg != 0 && reg->signal_number_ == signal_number)
+ {
+#if defined(ASIO_HAS_SIGNAL) || defined(ASIO_HAS_SIGACTION)
+ // Set signal handler back to the default if we're the last.
+ if (state->registration_count_[signal_number] == 1)
+ {
+# if defined(ASIO_HAS_SIGACTION)
+ using namespace std; // For memset.
+ struct sigaction sa;
+ memset(&sa, 0, sizeof(sa));
+ sa.sa_handler = SIG_DFL;
+ if (::sigaction(signal_number, &sa, 0) == -1)
+# else // defined(ASIO_HAS_SIGACTION)
+ if (::signal(signal_number, SIG_DFL) == SIG_ERR)
+# endif // defined(ASIO_HAS_SIGACTION)
+ {
+# if defined(ASIO_WINDOWS) || defined(__CYGWIN__)
+ ec = asio::error::invalid_argument;
+# else // defined(ASIO_WINDOWS) || defined(__CYGWIN__)
+ ec = asio::error_code(errno,
+ asio::error::get_system_category());
+# endif // defined(ASIO_WINDOWS) || defined(__CYGWIN__)
+ return ec;
+ }
+ }
+#endif // defined(ASIO_HAS_SIGNAL) || defined(ASIO_HAS_SIGACTION)
+
+ // Remove the registration from the set.
+ *deletion_point = reg->next_in_set_;
+
+ // Remove the registration from the registration table.
+ if (registrations_[signal_number] == reg)
+ registrations_[signal_number] = reg->next_in_table_;
+ if (reg->prev_in_table_)
+ reg->prev_in_table_->next_in_table_ = reg->next_in_table_;
+ if (reg->next_in_table_)
+ reg->next_in_table_->prev_in_table_ = reg->prev_in_table_;
+
+ --state->registration_count_[signal_number];
+
+ delete reg;
+ }
+
+ ec = asio::error_code();
+ return ec;
+}
+
+asio::error_code signal_set_service::clear(
+ signal_set_service::implementation_type& impl,
+ asio::error_code& ec)
+{
+ signal_state* state = get_signal_state();
+ static_mutex::scoped_lock lock(state->mutex_);
+
+ while (registration* reg = impl.signals_)
+ {
+#if defined(ASIO_HAS_SIGNAL) || defined(ASIO_HAS_SIGACTION)
+ // Set signal handler back to the default if we're the last.
+ if (state->registration_count_[reg->signal_number_] == 1)
+ {
+# if defined(ASIO_HAS_SIGACTION)
+ using namespace std; // For memset.
+ struct sigaction sa;
+ memset(&sa, 0, sizeof(sa));
+ sa.sa_handler = SIG_DFL;
+ if (::sigaction(reg->signal_number_, &sa, 0) == -1)
+# else // defined(ASIO_HAS_SIGACTION)
+ if (::signal(reg->signal_number_, SIG_DFL) == SIG_ERR)
+# endif // defined(ASIO_HAS_SIGACTION)
+ {
+# if defined(ASIO_WINDOWS) || defined(__CYGWIN__)
+ ec = asio::error::invalid_argument;
+# else // defined(ASIO_WINDOWS) || defined(__CYGWIN__)
+ ec = asio::error_code(errno,
+ asio::error::get_system_category());
+# endif // defined(ASIO_WINDOWS) || defined(__CYGWIN__)
+ return ec;
+ }
+ }
+#endif // defined(ASIO_HAS_SIGNAL) || defined(ASIO_HAS_SIGACTION)
+
+ // Remove the registration from the registration table.
+ if (registrations_[reg->signal_number_] == reg)
+ registrations_[reg->signal_number_] = reg->next_in_table_;
+ if (reg->prev_in_table_)
+ reg->prev_in_table_->next_in_table_ = reg->next_in_table_;
+ if (reg->next_in_table_)
+ reg->next_in_table_->prev_in_table_ = reg->prev_in_table_;
+
+ --state->registration_count_[reg->signal_number_];
+
+ impl.signals_ = reg->next_in_set_;
+ delete reg;
+ }
+
+ ec = asio::error_code();
+ return ec;
+}
+
+asio::error_code signal_set_service::cancel(
+ signal_set_service::implementation_type& impl,
+ asio::error_code& ec)
+{
+ ASIO_HANDLER_OPERATION((io_context_.context(),
+ "signal_set", &impl, 0, "cancel"));
+
+ op_queue<operation> ops;
+ {
+ signal_state* state = get_signal_state();
+ static_mutex::scoped_lock lock(state->mutex_);
+
+ while (signal_op* op = impl.queue_.front())
+ {
+ op->ec_ = asio::error::operation_aborted;
+ impl.queue_.pop();
+ ops.push(op);
+ }
+ }
+
+ io_context_.post_deferred_completions(ops);
+
+ ec = asio::error_code();
+ return ec;
+}
+
+void signal_set_service::deliver_signal(int signal_number)
+{
+ signal_state* state = get_signal_state();
+ static_mutex::scoped_lock lock(state->mutex_);
+
+ signal_set_service* service = state->service_list_;
+ while (service)
+ {
+ op_queue<operation> ops;
+
+ registration* reg = service->registrations_[signal_number];
+ while (reg)
+ {
+ if (reg->queue_->empty())
+ {
+ ++reg->undelivered_;
+ }
+ else
+ {
+ while (signal_op* op = reg->queue_->front())
+ {
+ op->signal_number_ = signal_number;
+ reg->queue_->pop();
+ ops.push(op);
+ }
+ }
+
+ reg = reg->next_in_table_;
+ }
+
+ service->io_context_.post_deferred_completions(ops);
+
+ service = service->next_;
+ }
+}
+
+void signal_set_service::add_service(signal_set_service* service)
+{
+ signal_state* state = get_signal_state();
+ static_mutex::scoped_lock lock(state->mutex_);
+
+#if !defined(ASIO_WINDOWS) && !defined(__CYGWIN__)
+ // If this is the first service to be created, open a new pipe.
+ if (state->service_list_ == 0)
+ open_descriptors();
+#endif // !defined(ASIO_WINDOWS) && !defined(__CYGWIN__)
+
+ // If an io_context object is thread-unsafe then it must be the only
+ // io_context used to create signal_set objects.
+ if (state->service_list_ != 0)
+ {
+ if (!ASIO_CONCURRENCY_HINT_IS_LOCKING(SCHEDULER,
+ service->io_context_.concurrency_hint())
+ || !ASIO_CONCURRENCY_HINT_IS_LOCKING(SCHEDULER,
+ state->service_list_->io_context_.concurrency_hint()))
+ {
+ std::logic_error ex(
+ "Thread-unsafe io_context objects require "
+ "exclusive access to signal handling.");
+ asio::detail::throw_exception(ex);
+ }
+ }
+
+ // Insert service into linked list of all services.
+ service->next_ = state->service_list_;
+ service->prev_ = 0;
+ if (state->service_list_)
+ state->service_list_->prev_ = service;
+ state->service_list_ = service;
+
+#if !defined(ASIO_WINDOWS) \
+ && !defined(ASIO_WINDOWS_RUNTIME) \
+ && !defined(__CYGWIN__)
+ // Register for pipe readiness notifications.
+ int read_descriptor = state->read_descriptor_;
+ lock.unlock();
+ service->reactor_.register_internal_descriptor(reactor::read_op,
+ read_descriptor, service->reactor_data_, new pipe_read_op);
+#endif // !defined(ASIO_WINDOWS)
+ // && !defined(ASIO_WINDOWS_RUNTIME)
+ // && !defined(__CYGWIN__)
+}
+
+void signal_set_service::remove_service(signal_set_service* service)
+{
+ signal_state* state = get_signal_state();
+ static_mutex::scoped_lock lock(state->mutex_);
+
+ if (service->next_ || service->prev_ || state->service_list_ == service)
+ {
+#if !defined(ASIO_WINDOWS) \
+ && !defined(ASIO_WINDOWS_RUNTIME) \
+ && !defined(__CYGWIN__)
+ // Disable the pipe readiness notifications.
+ int read_descriptor = state->read_descriptor_;
+ lock.unlock();
+ service->reactor_.deregister_internal_descriptor(
+ read_descriptor, service->reactor_data_);
+ service->reactor_.cleanup_descriptor_data(service->reactor_data_);
+ lock.lock();
+#endif // !defined(ASIO_WINDOWS)
+ // && !defined(ASIO_WINDOWS_RUNTIME)
+ // && !defined(__CYGWIN__)
+
+ // Remove service from linked list of all services.
+ if (state->service_list_ == service)
+ state->service_list_ = service->next_;
+ if (service->prev_)
+ service->prev_->next_ = service->next_;
+ if (service->next_)
+ service->next_->prev_= service->prev_;
+ service->next_ = 0;
+ service->prev_ = 0;
+
+#if !defined(ASIO_WINDOWS) && !defined(__CYGWIN__)
+ // If this is the last service to be removed, close the pipe.
+ if (state->service_list_ == 0)
+ close_descriptors();
+#endif // !defined(ASIO_WINDOWS) && !defined(__CYGWIN__)
+ }
+}
+
+void signal_set_service::open_descriptors()
+{
+#if !defined(ASIO_WINDOWS) \
+ && !defined(ASIO_WINDOWS_RUNTIME) \
+ && !defined(__CYGWIN__)
+ signal_state* state = get_signal_state();
+
+ int pipe_fds[2];
+ if (::pipe(pipe_fds) == 0)
+ {
+ state->read_descriptor_ = pipe_fds[0];
+ ::fcntl(state->read_descriptor_, F_SETFL, O_NONBLOCK);
+
+ state->write_descriptor_ = pipe_fds[1];
+ ::fcntl(state->write_descriptor_, F_SETFL, O_NONBLOCK);
+
+#if defined(FD_CLOEXEC)
+ ::fcntl(state->read_descriptor_, F_SETFD, FD_CLOEXEC);
+ ::fcntl(state->write_descriptor_, F_SETFD, FD_CLOEXEC);
+#endif // defined(FD_CLOEXEC)
+ }
+ else
+ {
+ asio::error_code ec(errno,
+ asio::error::get_system_category());
+ asio::detail::throw_error(ec, "signal_set_service pipe");
+ }
+#endif // !defined(ASIO_WINDOWS)
+ // && !defined(ASIO_WINDOWS_RUNTIME)
+ // && !defined(__CYGWIN__)
+}
+
+void signal_set_service::close_descriptors()
+{
+#if !defined(ASIO_WINDOWS) \
+ && !defined(ASIO_WINDOWS_RUNTIME) \
+ && !defined(__CYGWIN__)
+ signal_state* state = get_signal_state();
+
+ if (state->read_descriptor_ != -1)
+ ::close(state->read_descriptor_);
+ state->read_descriptor_ = -1;
+
+ if (state->write_descriptor_ != -1)
+ ::close(state->write_descriptor_);
+ state->write_descriptor_ = -1;
+#endif // !defined(ASIO_WINDOWS)
+ // && !defined(ASIO_WINDOWS_RUNTIME)
+ // && !defined(__CYGWIN__)
+}
+
+void signal_set_service::start_wait_op(
+ signal_set_service::implementation_type& impl, signal_op* op)
+{
+ io_context_.work_started();
+
+ signal_state* state = get_signal_state();
+ static_mutex::scoped_lock lock(state->mutex_);
+
+ registration* reg = impl.signals_;
+ while (reg)
+ {
+ if (reg->undelivered_ > 0)
+ {
+ --reg->undelivered_;
+ op->signal_number_ = reg->signal_number_;
+ io_context_.post_deferred_completion(op);
+ return;
+ }
+
+ reg = reg->next_in_set_;
+ }
+
+ impl.queue_.push(op);
+}
+
+} // namespace detail
+} // namespace asio
+
+#include "asio/detail/pop_options.hpp"
+
+#endif // ASIO_DETAIL_IMPL_SIGNAL_SET_SERVICE_IPP
diff --git a/lib/asio/detail/impl/socket_ops.ipp b/lib/asio/detail/impl/socket_ops.ipp
new file mode 100644
index 0000000..5e74733
--- /dev/null
+++ b/lib/asio/detail/impl/socket_ops.ipp
@@ -0,0 +1,3571 @@
+//
+// detail/impl/socket_ops.ipp
+// ~~~~~~~~~~~~~~~~~~~~~~~~~~
+//
+// Copyright (c) 2003-2018 Christopher M. Kohlhoff (chris at kohlhoff dot com)
+//
+// 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 ASIO_DETAIL_SOCKET_OPS_IPP
+#define ASIO_DETAIL_SOCKET_OPS_IPP
+
+#if defined(_MSC_VER) && (_MSC_VER >= 1200)
+# pragma once
+#endif // defined(_MSC_VER) && (_MSC_VER >= 1200)
+
+#include "asio/detail/config.hpp"
+
+#include <cctype>
+#include <cstdio>
+#include <cstdlib>
+#include <cstring>
+#include <cerrno>
+#include <new>
+#include "asio/detail/assert.hpp"
+#include "asio/detail/socket_ops.hpp"
+#include "asio/error.hpp"
+
+#if defined(ASIO_WINDOWS_RUNTIME)
+# include <codecvt>
+# include <locale>
+# include <string>
+#endif // defined(ASIO_WINDOWS_RUNTIME)
+
+#if defined(ASIO_WINDOWS) || defined(__CYGWIN__) \
+ || defined(__MACH__) && defined(__APPLE__)
+# if defined(ASIO_HAS_PTHREADS)
+# include <pthread.h>
+# endif // defined(ASIO_HAS_PTHREADS)
+#endif // defined(ASIO_WINDOWS) || defined(__CYGWIN__)
+ // || defined(__MACH__) && defined(__APPLE__)
+
+#include "asio/detail/push_options.hpp"
+
+namespace asio {
+namespace detail {
+namespace socket_ops {
+
+#if !defined(ASIO_WINDOWS_RUNTIME)
+
+#if defined(ASIO_WINDOWS) || defined(__CYGWIN__)
+struct msghdr { int msg_namelen; };
+#endif // defined(ASIO_WINDOWS) || defined(__CYGWIN__)
+
+#if defined(__hpux)
+// HP-UX doesn't declare these functions extern "C", so they are declared again
+// here to avoid linker errors about undefined symbols.
+extern "C" char* if_indextoname(unsigned int, char*);
+extern "C" unsigned int if_nametoindex(const char*);
+#endif // defined(__hpux)
+
+#endif // !defined(ASIO_WINDOWS_RUNTIME)
+
+inline void clear_last_error()
+{
+#if defined(ASIO_WINDOWS) || defined(__CYGWIN__)
+ WSASetLastError(0);
+#else
+ errno = 0;
+#endif
+}
+
+#if !defined(ASIO_WINDOWS_RUNTIME)
+
+template <typename ReturnType>
+inline ReturnType error_wrapper(ReturnType return_value,
+ asio::error_code& ec)
+{
+#if defined(ASIO_WINDOWS) || defined(__CYGWIN__)
+ ec = asio::error_code(WSAGetLastError(),
+ asio::error::get_system_category());
+#else
+ ec = asio::error_code(errno,
+ asio::error::get_system_category());
+#endif
+ return return_value;
+}
+
+template <typename SockLenType>
+inline socket_type call_accept(SockLenType msghdr::*,
+ socket_type s, socket_addr_type* addr, std::size_t* addrlen)
+{
+ SockLenType tmp_addrlen = addrlen ? (SockLenType)*addrlen : 0;
+ socket_type result = ::accept(s, addr, addrlen ? &tmp_addrlen : 0);
+ if (addrlen)
+ *addrlen = (std::size_t)tmp_addrlen;
+ return result;
+}
+
+socket_type accept(socket_type s, socket_addr_type* addr,
+ std::size_t* addrlen, asio::error_code& ec)
+{
+ if (s == invalid_socket)
+ {
+ ec = asio::error::bad_descriptor;
+ return invalid_socket;
+ }
+
+ clear_last_error();
+
+ socket_type new_s = error_wrapper(call_accept(
+ &msghdr::msg_namelen, s, addr, addrlen), ec);
+ if (new_s == invalid_socket)
+ return new_s;
+
+#if defined(__MACH__) && defined(__APPLE__) || defined(__FreeBSD__)
+ int optval = 1;
+ int result = error_wrapper(::setsockopt(new_s,
+ SOL_SOCKET, SO_NOSIGPIPE, &optval, sizeof(optval)), ec);
+ if (result != 0)
+ {
+ ::close(new_s);
+ return invalid_socket;
+ }
+#endif
+
+ ec = asio::error_code();
+ return new_s;
+}
+
+socket_type sync_accept(socket_type s, state_type state,
+ socket_addr_type* addr, std::size_t* addrlen, asio::error_code& ec)
+{
+ // Accept a socket.
+ for (;;)
+ {
+ // Try to complete the operation without blocking.
+ socket_type new_socket = socket_ops::accept(s, addr, addrlen, ec);
+
+ // Check if operation succeeded.
+ if (new_socket != invalid_socket)
+ return new_socket;
+
+ // Operation failed.
+ if (ec == asio::error::would_block
+ || ec == asio::error::try_again)
+ {
+ if (state & user_set_non_blocking)
+ return invalid_socket;
+ // Fall through to retry operation.
+ }
+ else if (ec == asio::error::connection_aborted)
+ {
+ if (state & enable_connection_aborted)
+ return invalid_socket;
+ // Fall through to retry operation.
+ }
+#if defined(EPROTO)
+ else if (ec.value() == EPROTO)
+ {
+ if (state & enable_connection_aborted)
+ return invalid_socket;
+ // Fall through to retry operation.
+ }
+#endif // defined(EPROTO)
+ else
+ return invalid_socket;
+
+ // Wait for socket to become ready.
+ if (socket_ops::poll_read(s, 0, -1, ec) < 0)
+ return invalid_socket;
+ }
+}
+
+#if defined(ASIO_HAS_IOCP)
+
+void complete_iocp_accept(socket_type s,
+ void* output_buffer, DWORD address_length,
+ socket_addr_type* addr, std::size_t* addrlen,
+ socket_type new_socket, asio::error_code& ec)
+{
+ // Map non-portable errors to their portable counterparts.
+ if (ec.value() == ERROR_NETNAME_DELETED)
+ ec = asio::error::connection_aborted;
+
+ if (!ec)
+ {
+ // Get the address of the peer.
+ if (addr && addrlen)
+ {
+ LPSOCKADDR local_addr = 0;
+ int local_addr_length = 0;
+ LPSOCKADDR remote_addr = 0;
+ int remote_addr_length = 0;
+ GetAcceptExSockaddrs(output_buffer, 0, address_length,
+ address_length, &local_addr, &local_addr_length,
+ &remote_addr, &remote_addr_length);
+ if (static_cast<std::size_t>(remote_addr_length) > *addrlen)
+ {
+ ec = asio::error::invalid_argument;
+ }
+ else
+ {
+ using namespace std; // For memcpy.
+ memcpy(addr, remote_addr, remote_addr_length);
+ *addrlen = static_cast<std::size_t>(remote_addr_length);
+ }
+ }
+
+ // Need to set the SO_UPDATE_ACCEPT_CONTEXT option so that getsockname
+ // and getpeername will work on the accepted socket.
+ SOCKET update_ctx_param = s;
+ socket_ops::state_type state = 0;
+ socket_ops::setsockopt(new_socket, state,
+ SOL_SOCKET, SO_UPDATE_ACCEPT_CONTEXT,
+ &update_ctx_param, sizeof(SOCKET), ec);
+ }
+}
+
+#else // defined(ASIO_HAS_IOCP)
+
+bool non_blocking_accept(socket_type s,
+ state_type state, socket_addr_type* addr, std::size_t* addrlen,
+ asio::error_code& ec, socket_type& new_socket)
+{
+ for (;;)
+ {
+ // Accept the waiting connection.
+ new_socket = socket_ops::accept(s, addr, addrlen, ec);
+
+ // Check if operation succeeded.
+ if (new_socket != invalid_socket)
+ return true;
+
+ // Retry operation if interrupted by signal.
+ if (ec == asio::error::interrupted)
+ continue;
+
+ // Operation failed.
+ if (ec == asio::error::would_block
+ || ec == asio::error::try_again)
+ {
+ // Fall through to retry operation.
+ }
+ else if (ec == asio::error::connection_aborted)
+ {
+ if (state & enable_connection_aborted)
+ return true;
+ // Fall through to retry operation.
+ }
+#if defined(EPROTO)
+ else if (ec.value() == EPROTO)
+ {
+ if (state & enable_connection_aborted)
+ return true;
+ // Fall through to retry operation.
+ }
+#endif // defined(EPROTO)
+ else
+ return true;
+
+ return false;
+ }
+}
+
+#endif // defined(ASIO_HAS_IOCP)
+
+template <typename SockLenType>
+inline int call_bind(SockLenType msghdr::*,
+ socket_type s, const socket_addr_type* addr, std::size_t addrlen)
+{
+ return ::bind(s, addr, (SockLenType)addrlen);
+}
+
+int bind(socket_type s, const socket_addr_type* addr,
+ std::size_t addrlen, asio::error_code& ec)
+{
+ if (s == invalid_socket)
+ {
+ ec = asio::error::bad_descriptor;
+ return socket_error_retval;
+ }
+
+ clear_last_error();
+ int result = error_wrapper(call_bind(
+ &msghdr::msg_namelen, s, addr, addrlen), ec);
+ if (result == 0)
+ ec = asio::error_code();
+ return result;
+}
+
+int close(socket_type s, state_type& state,
+ bool destruction, asio::error_code& ec)
+{
+ int result = 0;
+ if (s != invalid_socket)
+ {
+ // We don't want the destructor to block, so set the socket to linger in
+ // the background. If the user doesn't like this behaviour then they need
+ // to explicitly close the socket.
+ if (destruction && (state & user_set_linger))
+ {
+ ::linger opt;
+ opt.l_onoff = 0;
+ opt.l_linger = 0;
+ asio::error_code ignored_ec;
+ socket_ops::setsockopt(s, state, SOL_SOCKET,
+ SO_LINGER, &opt, sizeof(opt), ignored_ec);
+ }
+
+ clear_last_error();
+#if defined(ASIO_WINDOWS) || defined(__CYGWIN__)
+ result = error_wrapper(::closesocket(s), ec);
+#else // defined(ASIO_WINDOWS) || defined(__CYGWIN__)
+ result = error_wrapper(::close(s), ec);
+#endif // defined(ASIO_WINDOWS) || defined(__CYGWIN__)
+
+ if (result != 0
+ && (ec == asio::error::would_block
+ || ec == asio::error::try_again))
+ {
+ // According to UNIX Network Programming Vol. 1, it is possible for
+ // close() to fail with EWOULDBLOCK under certain circumstances. What
+ // isn't clear is the state of the descriptor after this error. The one
+ // current OS where this behaviour is seen, Windows, says that the socket
+ // remains open. Therefore we'll put the descriptor back into blocking
+ // mode and have another attempt at closing it.
+#if defined(ASIO_WINDOWS) || defined(__CYGWIN__)
+ ioctl_arg_type arg = 0;
+ ::ioctlsocket(s, FIONBIO, &arg);
+#else // defined(ASIO_WINDOWS) || defined(__CYGWIN__)
+# if defined(__SYMBIAN32__)
+ int flags = ::fcntl(s, F_GETFL, 0);
+ if (flags >= 0)
+ ::fcntl(s, F_SETFL, flags & ~O_NONBLOCK);
+# else // defined(__SYMBIAN32__)
+ ioctl_arg_type arg = 0;
+ ::ioctl(s, FIONBIO, &arg);
+# endif // defined(__SYMBIAN32__)
+#endif // defined(ASIO_WINDOWS) || defined(__CYGWIN__)
+ state &= ~non_blocking;
+
+ clear_last_error();
+#if defined(ASIO_WINDOWS) || defined(__CYGWIN__)
+ result = error_wrapper(::closesocket(s), ec);
+#else // defined(ASIO_WINDOWS) || defined(__CYGWIN__)
+ result = error_wrapper(::close(s), ec);
+#endif // defined(ASIO_WINDOWS) || defined(__CYGWIN__)
+ }
+ }
+
+ if (result == 0)
+ ec = asio::error_code();
+ return result;
+}
+
+bool set_user_non_blocking(socket_type s,
+ state_type& state, bool value, asio::error_code& ec)
+{
+ if (s == invalid_socket)
+ {
+ ec = asio::error::bad_descriptor;
+ return false;
+ }
+
+ clear_last_error();
+#if defined(ASIO_WINDOWS) || defined(__CYGWIN__)
+ ioctl_arg_type arg = (value ? 1 : 0);
+ int result = error_wrapper(::ioctlsocket(s, FIONBIO, &arg), ec);
+#elif defined(__SYMBIAN32__)
+ int result = error_wrapper(::fcntl(s, F_GETFL, 0), ec);
+ if (result >= 0)
+ {
+ clear_last_error();
+ int flag = (value ? (result | O_NONBLOCK) : (result & ~O_NONBLOCK));
+ result = error_wrapper(::fcntl(s, F_SETFL, flag), ec);
+ }
+#else
+ ioctl_arg_type arg = (value ? 1 : 0);
+ int result = error_wrapper(::ioctl(s, FIONBIO, &arg), ec);
+#endif
+
+ if (result >= 0)
+ {
+ ec = asio::error_code();
+ if (value)
+ state |= user_set_non_blocking;
+ else
+ {
+ // Clearing the user-set non-blocking mode always overrides any
+ // internally-set non-blocking flag. Any subsequent asynchronous
+ // operations will need to re-enable non-blocking I/O.
+ state &= ~(user_set_non_blocking | internal_non_blocking);
+ }
+ return true;
+ }
+
+ return false;
+}
+
+bool set_internal_non_blocking(socket_type s,
+ state_type& state, bool value, asio::error_code& ec)
+{
+ if (s == invalid_socket)
+ {
+ ec = asio::error::bad_descriptor;
+ return false;
+ }
+
+ if (!value && (state & user_set_non_blocking))
+ {
+ // It does not make sense to clear the internal non-blocking flag if the
+ // user still wants non-blocking behaviour. Return an error and let the
+ // caller figure out whether to update the user-set non-blocking flag.
+ ec = asio::error::invalid_argument;
+ return false;
+ }
+
+ clear_last_error();
+#if defined(ASIO_WINDOWS) || defined(__CYGWIN__)
+ ioctl_arg_type arg = (value ? 1 : 0);
+ int result = error_wrapper(::ioctlsocket(s, FIONBIO, &arg), ec);
+#elif defined(__SYMBIAN32__)
+ int result = error_wrapper(::fcntl(s, F_GETFL, 0), ec);
+ if (result >= 0)
+ {
+ clear_last_error();
+ int flag = (value ? (result | O_NONBLOCK) : (result & ~O_NONBLOCK));
+ result = error_wrapper(::fcntl(s, F_SETFL, flag), ec);
+ }
+#else
+ ioctl_arg_type arg = (value ? 1 : 0);
+ int result = error_wrapper(::ioctl(s, FIONBIO, &arg), ec);
+#endif
+
+ if (result >= 0)
+ {
+ ec = asio::error_code();
+ if (value)
+ state |= internal_non_blocking;
+ else
+ state &= ~internal_non_blocking;
+ return true;
+ }
+
+ return false;
+}
+
+int shutdown(socket_type s, int what, asio::error_code& ec)
+{
+ if (s == invalid_socket)
+ {
+ ec = asio::error::bad_descriptor;
+ return socket_error_retval;
+ }
+
+ clear_last_error();
+ int result = error_wrapper(::shutdown(s, what), ec);
+ if (result == 0)
+ ec = asio::error_code();
+ return result;
+}
+
+template <typename SockLenType>
+inline int call_connect(SockLenType msghdr::*,
+ socket_type s, const socket_addr_type* addr, std::size_t addrlen)
+{
+ return ::connect(s, addr, (SockLenType)addrlen);
+}
+
+int connect(socket_type s, const socket_addr_type* addr,
+ std::size_t addrlen, asio::error_code& ec)
+{
+ if (s == invalid_socket)
+ {
+ ec = asio::error::bad_descriptor;
+ return socket_error_retval;
+ }
+
+ clear_last_error();
+ int result = error_wrapper(call_connect(
+ &msghdr::msg_namelen, s, addr, addrlen), ec);
+ if (result == 0)
+ ec = asio::error_code();
+#if defined(__linux__)
+ else if (ec == asio::error::try_again)
+ ec = asio::error::no_buffer_space;
+#endif // defined(__linux__)
+ return result;
+}
+
+void sync_connect(socket_type s, const socket_addr_type* addr,
+ std::size_t addrlen, asio::error_code& ec)
+{
+ // Perform the connect operation.
+ socket_ops::connect(s, addr, addrlen, ec);
+ if (ec != asio::error::in_progress
+ && ec != asio::error::would_block)
+ {
+ // The connect operation finished immediately.
+ return;
+ }
+
+ // Wait for socket to become ready.
+ if (socket_ops::poll_connect(s, -1, ec) < 0)
+ return;
+
+ // Get the error code from the connect operation.
+ int connect_error = 0;
+ size_t connect_error_len = sizeof(connect_error);
+ if (socket_ops::getsockopt(s, 0, SOL_SOCKET, SO_ERROR,
+ &connect_error, &connect_error_len, ec) == socket_error_retval)
+ return;
+
+ // Return the result of the connect operation.
+ ec = asio::error_code(connect_error,
+ asio::error::get_system_category());
+}
+
+#if defined(ASIO_HAS_IOCP)
+
+void complete_iocp_connect(socket_type s, asio::error_code& ec)
+{
+ // Map non-portable errors to their portable counterparts.
+ switch (ec.value())
+ {
+ case ERROR_CONNECTION_REFUSED:
+ ec = asio::error::connection_refused;
+ break;
+ case ERROR_NETWORK_UNREACHABLE:
+ ec = asio::error::network_unreachable;
+ break;
+ case ERROR_HOST_UNREACHABLE:
+ ec = asio::error::host_unreachable;
+ break;
+ case ERROR_SEM_TIMEOUT:
+ ec = asio::error::timed_out;
+ break;
+ default:
+ break;
+ }
+
+ if (!ec)
+ {
+ // Need to set the SO_UPDATE_CONNECT_CONTEXT option so that getsockname
+ // and getpeername will work on the connected socket.
+ socket_ops::state_type state = 0;
+ const int so_update_connect_context = 0x7010;
+ socket_ops::setsockopt(s, state, SOL_SOCKET,
+ so_update_connect_context, 0, 0, ec);
+ }
+}
+
+#endif // defined(ASIO_HAS_IOCP)
+
+bool non_blocking_connect(socket_type s, asio::error_code& ec)
+{
+ // Check if the connect operation has finished. This is required since we may
+ // get spurious readiness notifications from the reactor.
+#if defined(ASIO_WINDOWS) \
+ || defined(__CYGWIN__) \
+ || defined(__SYMBIAN32__)
+ fd_set write_fds;
+ FD_ZERO(&write_fds);
+ FD_SET(s, &write_fds);
+ fd_set except_fds;
+ FD_ZERO(&except_fds);
+ FD_SET(s, &except_fds);
+ timeval zero_timeout;
+ zero_timeout.tv_sec = 0;
+ zero_timeout.tv_usec = 0;
+ int ready = ::select(s + 1, 0, &write_fds, &except_fds, &zero_timeout);
+#else // defined(ASIO_WINDOWS)
+ // || defined(__CYGWIN__)
+ // || defined(__SYMBIAN32__)
+ pollfd fds;
+ fds.fd = s;
+ fds.events = POLLOUT;
+ fds.revents = 0;
+ int ready = ::poll(&fds, 1, 0);
+#endif // defined(ASIO_WINDOWS)
+ // || defined(__CYGWIN__)
+ // || defined(__SYMBIAN32__)
+ if (ready == 0)
+ {
+ // The asynchronous connect operation is still in progress.
+ return false;
+ }
+
+ // Get the error code from the connect operation.
+ int connect_error = 0;
+ size_t connect_error_len = sizeof(connect_error);
+ if (socket_ops::getsockopt(s, 0, SOL_SOCKET, SO_ERROR,
+ &connect_error, &connect_error_len, ec) == 0)
+ {
+ if (connect_error)
+ {
+ ec = asio::error_code(connect_error,
+ asio::error::get_system_category());
+ }
+ else
+ ec = asio::error_code();
+ }
+
+ return true;
+}
+
+int socketpair(int af, int type, int protocol,
+ socket_type sv[2], asio::error_code& ec)
+{
+#if defined(ASIO_WINDOWS) || defined(__CYGWIN__)
+ (void)(af);
+ (void)(type);
+ (void)(protocol);
+ (void)(sv);
+ ec = asio::error::operation_not_supported;
+ return socket_error_retval;
+#else
+ clear_last_error();
+ int result = error_wrapper(::socketpair(af, type, protocol, sv), ec);
+ if (result == 0)
+ ec = asio::error_code();
+ return result;
+#endif
+}
+
+bool sockatmark(socket_type s, asio::error_code& ec)
+{
+ if (s == invalid_socket)
+ {
+ ec = asio::error::bad_descriptor;
+ return false;
+ }
+
+#if defined(SIOCATMARK)
+ ioctl_arg_type value = 0;
+# if defined(ASIO_WINDOWS) || defined(__CYGWIN__)
+ int result = error_wrapper(::ioctlsocket(s, SIOCATMARK, &value), ec);
+# else // defined(ASIO_WINDOWS) || defined(__CYGWIN__)
+ int result = error_wrapper(::ioctl(s, SIOCATMARK, &value), ec);
+# endif // defined(ASIO_WINDOWS) || defined(__CYGWIN__)
+ if (result == 0)
+ ec = asio::error_code();
+# if defined(ENOTTY)
+ if (ec.value() == ENOTTY)
+ ec = asio::error::not_socket;
+# endif // defined(ENOTTY)
+#else // defined(SIOCATMARK)
+ int value = error_wrapper(::sockatmark(s), ec);
+ if (value != -1)
+ ec = asio::error_code();
+#endif // defined(SIOCATMARK)
+
+ return ec ? false : value != 0;
+}
+
+size_t available(socket_type s, asio::error_code& ec)
+{
+ if (s == invalid_socket)
+ {
+ ec = asio::error::bad_descriptor;
+ return 0;
+ }
+
+ ioctl_arg_type value = 0;
+#if defined(ASIO_WINDOWS) || defined(__CYGWIN__)
+ int result = error_wrapper(::ioctlsocket(s, FIONREAD, &value), ec);
+#else // defined(ASIO_WINDOWS) || defined(__CYGWIN__)
+ int result = error_wrapper(::ioctl(s, FIONREAD, &value), ec);
+#endif // defined(ASIO_WINDOWS) || defined(__CYGWIN__)
+ if (result == 0)
+ ec = asio::error_code();
+#if defined(ENOTTY)
+ if (ec.value() == ENOTTY)
+ ec = asio::error::not_socket;
+#endif // defined(ENOTTY)
+
+ return ec ? static_cast<size_t>(0) : static_cast<size_t>(value);
+}
+
+int listen(socket_type s, int backlog, asio::error_code& ec)
+{
+ if (s == invalid_socket)
+ {
+ ec = asio::error::bad_descriptor;
+ return socket_error_retval;
+ }
+
+ clear_last_error();
+ int result = error_wrapper(::listen(s, backlog), ec);
+ if (result == 0)
+ ec = asio::error_code();
+ return result;
+}
+
+inline void init_buf_iov_base(void*& base, void* addr)
+{
+ base = addr;
+}
+
+template <typename T>
+inline void init_buf_iov_base(T& base, void* addr)
+{
+ base = static_cast<T>(addr);
+}
+
+#if defined(ASIO_WINDOWS) || defined(__CYGWIN__)
+typedef WSABUF buf;
+#else // defined(ASIO_WINDOWS) || defined(__CYGWIN__)
+typedef iovec buf;
+#endif // defined(ASIO_WINDOWS) || defined(__CYGWIN__)
+
+void init_buf(buf& b, void* data, size_t size)
+{
+#if defined(ASIO_WINDOWS) || defined(__CYGWIN__)
+ b.buf = static_cast<char*>(data);
+ b.len = static_cast<u_long>(size);
+#else // defined(ASIO_WINDOWS) || defined(__CYGWIN__)
+ init_buf_iov_base(b.iov_base, data);
+ b.iov_len = size;
+#endif // defined(ASIO_WINDOWS) || defined(__CYGWIN__)
+}
+
+void init_buf(buf& b, const void* data, size_t size)
+{
+#if defined(ASIO_WINDOWS) || defined(__CYGWIN__)
+ b.buf = static_cast<char*>(const_cast<void*>(data));
+ b.len = static_cast<u_long>(size);
+#else // defined(ASIO_WINDOWS) || defined(__CYGWIN__)
+ init_buf_iov_base(b.iov_base, const_cast<void*>(data));
+ b.iov_len = size;
+#endif // defined(ASIO_WINDOWS) || defined(__CYGWIN__)
+}
+
+inline void init_msghdr_msg_name(void*& name, socket_addr_type* addr)
+{
+ name = addr;
+}
+
+inline void init_msghdr_msg_name(void*& name, const socket_addr_type* addr)
+{
+ name = const_cast<socket_addr_type*>(addr);
+}
+
+template <typename T>
+inline void init_msghdr_msg_name(T& name, socket_addr_type* addr)
+{
+ name = reinterpret_cast<T>(addr);
+}
+
+template <typename T>
+inline void init_msghdr_msg_name(T& name, const socket_addr_type* addr)
+{
+ name = reinterpret_cast<T>(const_cast<socket_addr_type*>(addr));
+}
+
+signed_size_type recv(socket_type s, buf* bufs, size_t count,
+ int flags, asio::error_code& ec)
+{
+ clear_last_error();
+#if defined(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 = error_wrapper(::WSARecv(s, bufs,
+ recv_buf_count, &bytes_transferred, &recv_flags, 0, 0), ec);
+ if (ec.value() == ERROR_NETNAME_DELETED)
+ ec = asio::error::connection_reset;
+ else if (ec.value() == ERROR_PORT_UNREACHABLE)
+ ec = asio::error::connection_refused;
+ else if (ec.value() == WSAEMSGSIZE || ec.value() == ERROR_MORE_DATA)
+ ec.assign(0, ec.category());
+ if (result != 0)
+ return socket_error_retval;
+ ec = asio::error_code();
+ return bytes_transferred;
+#else // defined(ASIO_WINDOWS) || defined(__CYGWIN__)
+ msghdr msg = msghdr();
+ msg.msg_iov = bufs;
+ msg.msg_iovlen = static_cast<int>(count);
+ signed_size_type result = error_wrapper(::recvmsg(s, &msg, flags), ec);
+ if (result >= 0)
+ ec = asio::error_code();
+ return result;
+#endif // defined(ASIO_WINDOWS) || defined(__CYGWIN__)
+}
+
+size_t sync_recv(socket_type s, state_type state, buf* bufs,
+ size_t count, int flags, bool all_empty, asio::error_code& ec)
+{
+ if (s == invalid_socket)
+ {
+ ec = asio::error::bad_descriptor;
+ return 0;
+ }
+
+ // A request to read 0 bytes on a stream is a no-op.
+ if (all_empty && (state & stream_oriented))
+ {
+ ec = asio::error_code();
+ return 0;
+ }
+
+ // Read some data.
+ for (;;)
+ {
+ // Try to complete the operation without blocking.
+ signed_size_type bytes = socket_ops::recv(s, bufs, count, flags, ec);
+
+ // Check if operation succeeded.
+ if (bytes > 0)
+ return bytes;
+
+ // Check for EOF.
+ if ((state & stream_oriented) && bytes == 0)
+ {
+ ec = asio::error::eof;
+ return 0;
+ }
+
+ // Operation failed.
+ if ((state & user_set_non_blocking)
+ || (ec != asio::error::would_block
+ && ec != 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(ASIO_HAS_IOCP)
+
+void complete_iocp_recv(state_type state,
+ const weak_cancel_token_type& cancel_token, bool all_empty,
+ asio::error_code& ec, size_t bytes_transferred)
+{
+ // Map non-portable errors to their portable counterparts.
+ if (ec.value() == ERROR_NETNAME_DELETED)
+ {
+ if (cancel_token.expired())
+ ec = asio::error::operation_aborted;
+ else
+ ec = asio::error::connection_reset;
+ }
+ else if (ec.value() == ERROR_PORT_UNREACHABLE)
+ {
+ ec = asio::error::connection_refused;
+ }
+ else if (ec.value() == WSAEMSGSIZE || ec.value() == ERROR_MORE_DATA)
+ {
+ ec.assign(0, ec.category());
+ }
+
+ // Check for connection closed.
+ else if (!ec && bytes_transferred == 0
+ && (state & stream_oriented) != 0
+ && !all_empty)
+ {
+ ec = asio::error::eof;
+ }
+}
+
+#else // defined(ASIO_HAS_IOCP)
+
+bool non_blocking_recv(socket_type s,
+ buf* bufs, size_t count, int flags, bool is_stream,
+ asio::error_code& ec, size_t& bytes_transferred)
+{
+ for (;;)
+ {
+ // Read some data.
+ signed_size_type bytes = socket_ops::recv(s, bufs, count, flags, ec);
+
+ // Check for end of stream.
+ if (is_stream && bytes == 0)
+ {
+ ec = asio::error::eof;
+ return true;
+ }
+
+ // Retry operation if interrupted by signal.
+ if (ec == asio::error::interrupted)
+ continue;
+
+ // Check if we need to run the operation again.
+ if (ec == asio::error::would_block
+ || ec == asio::error::try_again)
+ return false;
+
+ // Operation is complete.
+ if (bytes >= 0)
+ {
+ ec = asio::error_code();
+ bytes_transferred = bytes;
+ }
+ else
+ bytes_transferred = 0;
+
+ return true;
+ }
+}
+
+#endif // defined(ASIO_HAS_IOCP)
+
+signed_size_type recvfrom(socket_type s, buf* bufs, size_t count,
+ int flags, socket_addr_type* addr, std::size_t* addrlen,
+ asio::error_code& ec)
+{
+ clear_last_error();
+#if defined(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 = error_wrapper(::WSARecvFrom(s, bufs, recv_buf_count,
+ &bytes_transferred, &recv_flags, addr, &tmp_addrlen, 0, 0), ec);
+ *addrlen = (std::size_t)tmp_addrlen;
+ if (ec.value() == ERROR_NETNAME_DELETED)
+ ec = asio::error::connection_reset;
+ else if (ec.value() == ERROR_PORT_UNREACHABLE)
+ ec = asio::error::connection_refused;
+ else if (ec.value() == WSAEMSGSIZE || ec.value() == ERROR_MORE_DATA)
+ ec.assign(0, ec.category());
+ if (result != 0)
+ return socket_error_retval;
+ ec = asio::error_code();
+ return bytes_transferred;
+#else // defined(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);
+ signed_size_type result = error_wrapper(::recvmsg(s, &msg, flags), ec);
+ *addrlen = msg.msg_namelen;
+ if (result >= 0)
+ ec = asio::error_code();
+ return result;
+#endif // defined(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, asio::error_code& ec)
+{
+ if (s == invalid_socket)
+ {
+ ec = 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);
+
+ // Check if operation succeeded.
+ if (bytes >= 0)
+ return bytes;
+
+ // Operation failed.
+ if ((state & user_set_non_blocking)
+ || (ec != asio::error::would_block
+ && ec != 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(ASIO_HAS_IOCP)
+
+void complete_iocp_recvfrom(
+ const weak_cancel_token_type& cancel_token,
+ asio::error_code& ec)
+{
+ // Map non-portable errors to their portable counterparts.
+ if (ec.value() == ERROR_NETNAME_DELETED)
+ {
+ if (cancel_token.expired())
+ ec = asio::error::operation_aborted;
+ else
+ ec = asio::error::connection_reset;
+ }
+ else if (ec.value() == ERROR_PORT_UNREACHABLE)
+ {
+ ec = asio::error::connection_refused;
+ }
+ else if (ec.value() == WSAEMSGSIZE || ec.value() == ERROR_MORE_DATA)
+ {
+ ec.assign(0, ec.category());
+ }
+}
+
+#else // defined(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,
+ asio::error_code& ec, size_t& bytes_transferred)
+{
+ for (;;)
+ {
+ // Read some data.
+ signed_size_type bytes = socket_ops::recvfrom(
+ s, bufs, count, flags, addr, addrlen, ec);
+
+ // Retry operation if interrupted by signal.
+ if (ec == asio::error::interrupted)
+ continue;
+
+ // Check if we need to run the operation again.
+ if (ec == asio::error::would_block
+ || ec == asio::error::try_again)
+ return false;
+
+ // Operation is complete.
+ if (bytes >= 0)
+ {
+ ec = asio::error_code();
+ bytes_transferred = bytes;
+ }
+ else
+ bytes_transferred = 0;
+
+ return true;
+ }
+}
+
+#endif // defined(ASIO_HAS_IOCP)
+
+signed_size_type recvmsg(socket_type s, buf* bufs, size_t count,
+ int in_flags, int& out_flags, asio::error_code& ec)
+{
+ clear_last_error();
+#if defined(ASIO_WINDOWS) || defined(__CYGWIN__)
+ out_flags = 0;
+ return socket_ops::recv(s, bufs, count, in_flags, ec);
+#else // defined(ASIO_WINDOWS) || defined(__CYGWIN__)
+ msghdr msg = msghdr();
+ msg.msg_iov = bufs;
+ msg.msg_iovlen = static_cast<int>(count);
+ signed_size_type result = error_wrapper(::recvmsg(s, &msg, in_flags), ec);
+ if (result >= 0)
+ {
+ ec = asio::error_code();
+ out_flags = msg.msg_flags;
+ }
+ else
+ out_flags = 0;
+ return result;
+#endif // defined(ASIO_WINDOWS) || defined(__CYGWIN__)
+}
+
+size_t sync_recvmsg(socket_type s, state_type state,
+ buf* bufs, size_t count, int in_flags, int& out_flags,
+ asio::error_code& ec)
+{
+ if (s == invalid_socket)
+ {
+ ec = asio::error::bad_descriptor;
+ return 0;
+ }
+
+ // Read some data.
+ for (;;)
+ {
+ // Try to complete the operation without blocking.
+ signed_size_type bytes = socket_ops::recvmsg(
+ s, bufs, count, in_flags, out_flags, ec);
+
+ // Check if operation succeeded.
+ if (bytes >= 0)
+ return bytes;
+
+ // Operation failed.
+ if ((state & user_set_non_blocking)
+ || (ec != asio::error::would_block
+ && ec != 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(ASIO_HAS_IOCP)
+
+void complete_iocp_recvmsg(
+ const weak_cancel_token_type& cancel_token,
+ asio::error_code& ec)
+{
+ // Map non-portable errors to their portable counterparts.
+ if (ec.value() == ERROR_NETNAME_DELETED)
+ {
+ if (cancel_token.expired())
+ ec = asio::error::operation_aborted;
+ else
+ ec = asio::error::connection_reset;
+ }
+ else if (ec.value() == ERROR_PORT_UNREACHABLE)
+ {
+ ec = asio::error::connection_refused;
+ }
+ else if (ec.value() == WSAEMSGSIZE || ec.value() == ERROR_MORE_DATA)
+ {
+ ec.assign(0, ec.category());
+ }
+}
+
+#else // defined(ASIO_HAS_IOCP)
+
+bool non_blocking_recvmsg(socket_type s,
+ buf* bufs, size_t count, int in_flags, int& out_flags,
+ asio::error_code& ec, size_t& bytes_transferred)
+{
+ for (;;)
+ {
+ // Read some data.
+ signed_size_type bytes = socket_ops::recvmsg(
+ s, bufs, count, in_flags, out_flags, ec);
+
+ // Retry operation if interrupted by signal.
+ if (ec == asio::error::interrupted)
+ continue;
+
+ // Check if we need to run the operation again.
+ if (ec == asio::error::would_block
+ || ec == asio::error::try_again)
+ return false;
+
+ // Operation is complete.
+ if (bytes >= 0)
+ {
+ ec = asio::error_code();
+ bytes_transferred = bytes;
+ }
+ else
+ bytes_transferred = 0;
+
+ return true;
+ }
+}
+
+#endif // defined(ASIO_HAS_IOCP)
+
+signed_size_type send(socket_type s, const buf* bufs, size_t count,
+ int flags, asio::error_code& ec)
+{
+ clear_last_error();
+#if defined(ASIO_WINDOWS) || defined(__CYGWIN__)
+ // Send the data.
+ DWORD send_buf_count = static_cast<DWORD>(count);
+ DWORD bytes_transferred = 0;
+ DWORD send_flags = flags;
+ int result = error_wrapper(::WSASend(s, const_cast<buf*>(bufs),
+ send_buf_count, &bytes_transferred, send_flags, 0, 0), ec);
+ if (ec.value() == ERROR_NETNAME_DELETED)
+ ec = asio::error::connection_reset;
+ else if (ec.value() == ERROR_PORT_UNREACHABLE)
+ ec = asio::error::connection_refused;
+ if (result != 0)
+ return socket_error_retval;
+ ec = asio::error_code();
+ return bytes_transferred;
+#else // defined(ASIO_WINDOWS) || defined(__CYGWIN__)
+ msghdr msg = msghdr();
+ msg.msg_iov = const_cast<buf*>(bufs);
+ msg.msg_iovlen = static_cast<int>(count);
+#if defined(__linux__)
+ flags |= MSG_NOSIGNAL;
+#endif // defined(__linux__)
+ signed_size_type result = error_wrapper(::sendmsg(s, &msg, flags), ec);
+ if (result >= 0)
+ ec = asio::error_code();
+ return result;
+#endif // defined(ASIO_WINDOWS) || defined(__CYGWIN__)
+}
+
+size_t sync_send(socket_type s, state_type state, const buf* bufs,
+ size_t count, int flags, bool all_empty, asio::error_code& ec)
+{
+ if (s == invalid_socket)
+ {
+ ec = asio::error::bad_descriptor;
+ return 0;
+ }
+
+ // A request to write 0 bytes to a stream is a no-op.
+ if (all_empty && (state & stream_oriented))
+ {
+ ec = asio::error_code();
+ return 0;
+ }
+
+ // Read some data.
+ for (;;)
+ {
+ // Try to complete the operation without blocking.
+ signed_size_type bytes = socket_ops::send(s, bufs, count, flags, ec);
+
+ // Check if operation succeeded.
+ if (bytes >= 0)
+ return bytes;
+
+ // Operation failed.
+ if ((state & user_set_non_blocking)
+ || (ec != asio::error::would_block
+ && ec != asio::error::try_again))
+ return 0;
+
+ // Wait for socket to become ready.
+ if (socket_ops::poll_write(s, 0, -1, ec) < 0)
+ return 0;
+ }
+}
+
+#if defined(ASIO_HAS_IOCP)
+
+void complete_iocp_send(
+ const weak_cancel_token_type& cancel_token,
+ asio::error_code& ec)
+{
+ // Map non-portable errors to their portable counterparts.
+ if (ec.value() == ERROR_NETNAME_DELETED)
+ {
+ if (cancel_token.expired())
+ ec = asio::error::operation_aborted;
+ else
+ ec = asio::error::connection_reset;
+ }
+ else if (ec.value() == ERROR_PORT_UNREACHABLE)
+ {
+ ec = asio::error::connection_refused;
+ }
+}
+
+#else // defined(ASIO_HAS_IOCP)
+
+bool non_blocking_send(socket_type s,
+ const buf* bufs, size_t count, int flags,
+ asio::error_code& ec, size_t& bytes_transferred)
+{
+ for (;;)
+ {
+ // Write some data.
+ signed_size_type bytes = socket_ops::send(s, bufs, count, flags, ec);
+
+ // Retry operation if interrupted by signal.
+ if (ec == asio::error::interrupted)
+ continue;
+
+ // Check if we need to run the operation again.
+ if (ec == asio::error::would_block
+ || ec == asio::error::try_again)
+ return false;
+
+ // Operation is complete.
+ if (bytes >= 0)
+ {
+ ec = asio::error_code();
+ bytes_transferred = bytes;
+ }
+ else
+ bytes_transferred = 0;
+
+ return true;
+ }
+}
+
+#endif // defined(ASIO_HAS_IOCP)
+
+signed_size_type sendto(socket_type s, const buf* bufs, size_t count,
+ int flags, const socket_addr_type* addr, std::size_t addrlen,
+ asio::error_code& ec)
+{
+ clear_last_error();
+#if defined(ASIO_WINDOWS) || defined(__CYGWIN__)
+ // Send the data.
+ DWORD send_buf_count = static_cast<DWORD>(count);
+ DWORD bytes_transferred = 0;
+ int result = error_wrapper(::WSASendTo(s, const_cast<buf*>(bufs),
+ send_buf_count, &bytes_transferred, flags, addr,
+ static_cast<int>(addrlen), 0, 0), ec);
+ if (ec.value() == ERROR_NETNAME_DELETED)
+ ec = asio::error::connection_reset;
+ else if (ec.value() == ERROR_PORT_UNREACHABLE)
+ ec = asio::error::connection_refused;
+ if (result != 0)
+ return socket_error_retval;
+ ec = asio::error_code();
+ return bytes_transferred;
+#else // defined(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 = const_cast<buf*>(bufs);
+ msg.msg_iovlen = static_cast<int>(count);
+#if defined(__linux__)
+ flags |= MSG_NOSIGNAL;
+#endif // defined(__linux__)
+ signed_size_type result = error_wrapper(::sendmsg(s, &msg, flags), ec);
+ if (result >= 0)
+ ec = asio::error_code();
+ return result;
+#endif // defined(ASIO_WINDOWS) || defined(__CYGWIN__)
+}
+
+size_t sync_sendto(socket_type s, state_type state, const buf* bufs,
+ size_t count, int flags, const socket_addr_type* addr,
+ std::size_t addrlen, asio::error_code& ec)
+{
+ if (s == invalid_socket)
+ {
+ ec = asio::error::bad_descriptor;
+ return 0;
+ }
+
+ // Write some data.
+ for (;;)
+ {
+ // Try to complete the operation without blocking.
+ signed_size_type bytes = socket_ops::sendto(
+ s, bufs, count, flags, addr, addrlen, ec);
+
+ // Check if operation succeeded.
+ if (bytes >= 0)
+ return bytes;
+
+ // Operation failed.
+ if ((state & user_set_non_blocking)
+ || (ec != asio::error::would_block
+ && ec != asio::error::try_again))
+ return 0;
+
+ // Wait for socket to become ready.
+ if (socket_ops::poll_write(s, 0, -1, ec) < 0)
+ return 0;
+ }
+}
+
+#if !defined(ASIO_HAS_IOCP)
+
+bool non_blocking_sendto(socket_type s,
+ const buf* bufs, size_t count, int flags,
+ const socket_addr_type* addr, std::size_t addrlen,
+ asio::error_code& ec, size_t& bytes_transferred)
+{
+ for (;;)
+ {
+ // Write some data.
+ signed_size_type bytes = socket_ops::sendto(
+ s, bufs, count, flags, addr, addrlen, ec);
+
+ // Retry operation if interrupted by signal.
+ if (ec == asio::error::interrupted)
+ continue;
+
+ // Check if we need to run the operation again.
+ if (ec == asio::error::would_block
+ || ec == asio::error::try_again)
+ return false;
+
+ // Operation is complete.
+ if (bytes >= 0)
+ {
+ ec = asio::error_code();
+ bytes_transferred = bytes;
+ }
+ else
+ bytes_transferred = 0;
+
+ return true;
+ }
+}
+
+#endif // !defined(ASIO_HAS_IOCP)
+
+socket_type socket(int af, int type, int protocol,
+ asio::error_code& ec)
+{
+ clear_last_error();
+#if defined(ASIO_WINDOWS) || defined(__CYGWIN__)
+ socket_type s = error_wrapper(::WSASocketW(af, type, protocol, 0, 0,
+ WSA_FLAG_OVERLAPPED), ec);
+ if (s == invalid_socket)
+ return s;
+
+ if (af == ASIO_OS_DEF(AF_INET6))
+ {
+ // Try to enable the POSIX default behaviour of having IPV6_V6ONLY set to
+ // false. This will only succeed on Windows Vista and later versions of
+ // Windows, where a dual-stack IPv4/v6 implementation is available.
+ DWORD optval = 0;
+ ::setsockopt(s, IPPROTO_IPV6, IPV6_V6ONLY,
+ reinterpret_cast<const char*>(&optval), sizeof(optval));
+ }
+
+ ec = asio::error_code();
+
+ return s;
+#elif defined(__MACH__) && defined(__APPLE__) || defined(__FreeBSD__)
+ socket_type s = error_wrapper(::socket(af, type, protocol), ec);
+ if (s == invalid_socket)
+ return s;
+
+ int optval = 1;
+ int result = error_wrapper(::setsockopt(s,
+ SOL_SOCKET, SO_NOSIGPIPE, &optval, sizeof(optval)), ec);
+ if (result != 0)
+ {
+ ::close(s);
+ return invalid_socket;
+ }
+
+ return s;
+#else
+ int s = error_wrapper(::socket(af, type, protocol), ec);
+ if (s >= 0)
+ ec = asio::error_code();
+ return s;
+#endif
+}
+
+template <typename SockLenType>
+inline int call_setsockopt(SockLenType msghdr::*,
+ socket_type s, int level, int optname,
+ const void* optval, std::size_t optlen)
+{
+ return ::setsockopt(s, level, optname,
+ (const char*)optval, (SockLenType)optlen);
+}
+
+int setsockopt(socket_type s, state_type& state, int level, int optname,
+ const void* optval, std::size_t optlen, asio::error_code& ec)
+{
+ if (s == invalid_socket)
+ {
+ ec = asio::error::bad_descriptor;
+ return socket_error_retval;
+ }
+
+ if (level == custom_socket_option_level && optname == always_fail_option)
+ {
+ ec = asio::error::invalid_argument;
+ return socket_error_retval;
+ }
+
+ if (level == custom_socket_option_level
+ && optname == enable_connection_aborted_option)
+ {
+ if (optlen != sizeof(int))
+ {
+ ec = asio::error::invalid_argument;
+ return socket_error_retval;
+ }
+
+ if (*static_cast<const int*>(optval))
+ state |= enable_connection_aborted;
+ else
+ state &= ~enable_connection_aborted;
+ ec = asio::error_code();
+ return 0;
+ }
+
+ if (level == SOL_SOCKET && optname == SO_LINGER)
+ state |= user_set_linger;
+
+#if defined(__BORLANDC__)
+ // Mysteriously, using the getsockopt and setsockopt functions directly with
+ // Borland C++ results in incorrect values being set and read. The bug can be
+ // worked around by using function addresses resolved with GetProcAddress.
+ if (HMODULE winsock_module = ::GetModuleHandleA("ws2_32"))
+ {
+ typedef int (WSAAPI *sso_t)(SOCKET, int, int, const char*, int);
+ if (sso_t sso = (sso_t)::GetProcAddress(winsock_module, "setsockopt"))
+ {
+ clear_last_error();
+ return error_wrapper(sso(s, level, optname,
+ reinterpret_cast<const char*>(optval),
+ static_cast<int>(optlen)), ec);
+ }
+ }
+ ec = asio::error::fault;
+ return socket_error_retval;
+#else // defined(__BORLANDC__)
+ clear_last_error();
+ int result = error_wrapper(call_setsockopt(&msghdr::msg_namelen,
+ s, level, optname, optval, optlen), ec);
+ if (result == 0)
+ {
+ ec = asio::error_code();
+
+#if defined(__MACH__) && defined(__APPLE__) \
+ || defined(__NetBSD__) || defined(__FreeBSD__) || defined(__OpenBSD__)
+ // To implement portable behaviour for SO_REUSEADDR with UDP sockets we
+ // need to also set SO_REUSEPORT on BSD-based platforms.
+ if ((state & datagram_oriented)
+ && level == SOL_SOCKET && optname == SO_REUSEADDR)
+ {
+ call_setsockopt(&msghdr::msg_namelen, s,
+ SOL_SOCKET, SO_REUSEPORT, optval, optlen);
+ }
+#endif
+ }
+
+ return result;
+#endif // defined(__BORLANDC__)
+}
+
+template <typename SockLenType>
+inline int call_getsockopt(SockLenType msghdr::*,
+ socket_type s, int level, int optname,
+ void* optval, std::size_t* optlen)
+{
+ SockLenType tmp_optlen = (SockLenType)*optlen;
+ int result = ::getsockopt(s, level, optname, (char*)optval, &tmp_optlen);
+ *optlen = (std::size_t)tmp_optlen;
+ return result;
+}
+
+int getsockopt(socket_type s, state_type state, int level, int optname,
+ void* optval, size_t* optlen, asio::error_code& ec)
+{
+ if (s == invalid_socket)
+ {
+ ec = asio::error::bad_descriptor;
+ return socket_error_retval;
+ }
+
+ if (level == custom_socket_option_level && optname == always_fail_option)
+ {
+ ec = asio::error::invalid_argument;
+ return socket_error_retval;
+ }
+
+ if (level == custom_socket_option_level
+ && optname == enable_connection_aborted_option)
+ {
+ if (*optlen != sizeof(int))
+ {
+ ec = asio::error::invalid_argument;
+ return socket_error_retval;
+ }
+
+ *static_cast<int*>(optval) = (state & enable_connection_aborted) ? 1 : 0;
+ ec = asio::error_code();
+ return 0;
+ }
+
+#if defined(__BORLANDC__)
+ // Mysteriously, using the getsockopt and setsockopt functions directly with
+ // Borland C++ results in incorrect values being set and read. The bug can be
+ // worked around by using function addresses resolved with GetProcAddress.
+ if (HMODULE winsock_module = ::GetModuleHandleA("ws2_32"))
+ {
+ typedef int (WSAAPI *gso_t)(SOCKET, int, int, char*, int*);
+ if (gso_t gso = (gso_t)::GetProcAddress(winsock_module, "getsockopt"))
+ {
+ clear_last_error();
+ int tmp_optlen = static_cast<int>(*optlen);
+ int result = error_wrapper(gso(s, level, optname,
+ reinterpret_cast<char*>(optval), &tmp_optlen), ec);
+ *optlen = static_cast<size_t>(tmp_optlen);
+ if (result != 0 && level == IPPROTO_IPV6 && optname == IPV6_V6ONLY
+ && ec.value() == WSAENOPROTOOPT && *optlen == sizeof(DWORD))
+ {
+ // Dual-stack IPv4/v6 sockets, and the IPV6_V6ONLY socket option, are
+ // only supported on Windows Vista and later. To simplify program logic
+ // we will fake success of getting this option and specify that the
+ // value is non-zero (i.e. true). This corresponds to the behavior of
+ // IPv6 sockets on Windows platforms pre-Vista.
+ *static_cast<DWORD*>(optval) = 1;
+ ec = asio::error_code();
+ }
+ return result;
+ }
+ }
+ ec = asio::error::fault;
+ return socket_error_retval;
+#elif defined(ASIO_WINDOWS) || defined(__CYGWIN__)
+ clear_last_error();
+ int result = error_wrapper(call_getsockopt(&msghdr::msg_namelen,
+ s, level, optname, optval, optlen), ec);
+ if (result != 0 && level == IPPROTO_IPV6 && optname == IPV6_V6ONLY
+ && ec.value() == WSAENOPROTOOPT && *optlen == sizeof(DWORD))
+ {
+ // Dual-stack IPv4/v6 sockets, and the IPV6_V6ONLY socket option, are only
+ // supported on Windows Vista and later. To simplify program logic we will
+ // fake success of getting this option and specify that the value is
+ // non-zero (i.e. true). This corresponds to the behavior of IPv6 sockets
+ // on Windows platforms pre-Vista.
+ *static_cast<DWORD*>(optval) = 1;
+ ec = asio::error_code();
+ }
+ if (result == 0)
+ ec = asio::error_code();
+ return result;
+#else // defined(ASIO_WINDOWS) || defined(__CYGWIN__)
+ clear_last_error();
+ int result = error_wrapper(call_getsockopt(&msghdr::msg_namelen,
+ s, level, optname, optval, optlen), ec);
+#if defined(__linux__)
+ if (result == 0 && level == SOL_SOCKET && *optlen == sizeof(int)
+ && (optname == SO_SNDBUF || optname == SO_RCVBUF))
+ {
+ // On Linux, setting SO_SNDBUF or SO_RCVBUF to N actually causes the kernel
+ // to set the buffer size to N*2. Linux puts additional stuff into the
+ // buffers so that only about half is actually available to the application.
+ // The retrieved value is divided by 2 here to make it appear as though the
+ // correct value has been set.
+ *static_cast<int*>(optval) /= 2;
+ }
+#endif // defined(__linux__)
+ if (result == 0)
+ ec = asio::error_code();
+ return result;
+#endif // defined(ASIO_WINDOWS) || defined(__CYGWIN__)
+}
+
+template <typename SockLenType>
+inline int call_getpeername(SockLenType msghdr::*,
+ socket_type s, socket_addr_type* addr, std::size_t* addrlen)
+{
+ SockLenType tmp_addrlen = (SockLenType)*addrlen;
+ int result = ::getpeername(s, addr, &tmp_addrlen);
+ *addrlen = (std::size_t)tmp_addrlen;
+ return result;
+}
+
+int getpeername(socket_type s, socket_addr_type* addr,
+ std::size_t* addrlen, bool cached, asio::error_code& ec)
+{
+ if (s == invalid_socket)
+ {
+ ec = asio::error::bad_descriptor;
+ return socket_error_retval;
+ }
+
+#if defined(ASIO_WINDOWS) && !defined(ASIO_WINDOWS_APP) \
+ || defined(__CYGWIN__)
+ if (cached)
+ {
+ // Check if socket is still connected.
+ DWORD connect_time = 0;
+ size_t connect_time_len = sizeof(connect_time);
+ if (socket_ops::getsockopt(s, 0, SOL_SOCKET, SO_CONNECT_TIME,
+ &connect_time, &connect_time_len, ec) == socket_error_retval)
+ {
+ return socket_error_retval;
+ }
+ if (connect_time == 0xFFFFFFFF)
+ {
+ ec = asio::error::not_connected;
+ return socket_error_retval;
+ }
+
+ // The cached value is still valid.
+ ec = asio::error_code();
+ return 0;
+ }
+#else // defined(ASIO_WINDOWS) && !defined(ASIO_WINDOWS_APP)
+ // || defined(__CYGWIN__)
+ (void)cached;
+#endif // defined(ASIO_WINDOWS) && !defined(ASIO_WINDOWS_APP)
+ // || defined(__CYGWIN__)
+
+ clear_last_error();
+ int result = error_wrapper(call_getpeername(
+ &msghdr::msg_namelen, s, addr, addrlen), ec);
+ if (result == 0)
+ ec = asio::error_code();
+ return result;
+}
+
+template <typename SockLenType>
+inline int call_getsockname(SockLenType msghdr::*,
+ socket_type s, socket_addr_type* addr, std::size_t* addrlen)
+{
+ SockLenType tmp_addrlen = (SockLenType)*addrlen;
+ int result = ::getsockname(s, addr, &tmp_addrlen);
+ *addrlen = (std::size_t)tmp_addrlen;
+ return result;
+}
+
+int getsockname(socket_type s, socket_addr_type* addr,
+ std::size_t* addrlen, asio::error_code& ec)
+{
+ if (s == invalid_socket)
+ {
+ ec = asio::error::bad_descriptor;
+ return socket_error_retval;
+ }
+
+ clear_last_error();
+ int result = error_wrapper(call_getsockname(
+ &msghdr::msg_namelen, s, addr, addrlen), ec);
+ if (result == 0)
+ ec = asio::error_code();
+ return result;
+}
+
+int ioctl(socket_type s, state_type& state, int cmd,
+ ioctl_arg_type* arg, asio::error_code& ec)
+{
+ if (s == invalid_socket)
+ {
+ ec = asio::error::bad_descriptor;
+ return socket_error_retval;
+ }
+
+ clear_last_error();
+#if defined(ASIO_WINDOWS) || defined(__CYGWIN__)
+ int result = error_wrapper(::ioctlsocket(s, cmd, arg), ec);
+#elif defined(__MACH__) && defined(__APPLE__) \
+ || defined(__NetBSD__) || defined(__FreeBSD__) || defined(__OpenBSD__)
+ int result = error_wrapper(::ioctl(s,
+ static_cast<unsigned int>(cmd), arg), ec);
+#else
+ int result = error_wrapper(::ioctl(s, cmd, arg), ec);
+#endif
+ if (result >= 0)
+ {
+ ec = asio::error_code();
+
+ // When updating the non-blocking mode we always perform the ioctl syscall,
+ // even if the flags would otherwise indicate that the socket is already in
+ // the correct state. This ensures that the underlying socket is put into
+ // the state that has been requested by the user. If the ioctl syscall was
+ // successful then we need to update the flags to match.
+ if (cmd == static_cast<int>(FIONBIO))
+ {
+ if (*arg)
+ {
+ state |= user_set_non_blocking;
+ }
+ else
+ {
+ // Clearing the non-blocking mode always overrides any internally-set
+ // non-blocking flag. Any subsequent asynchronous operations will need
+ // to re-enable non-blocking I/O.
+ state &= ~(user_set_non_blocking | internal_non_blocking);
+ }
+ }
+ }
+
+ return result;
+}
+
+int select(int nfds, fd_set* readfds, fd_set* writefds,
+ fd_set* exceptfds, timeval* timeout, asio::error_code& ec)
+{
+ clear_last_error();
+#if defined(ASIO_WINDOWS) || defined(__CYGWIN__)
+ if (!readfds && !writefds && !exceptfds && timeout)
+ {
+ DWORD milliseconds = timeout->tv_sec * 1000 + timeout->tv_usec / 1000;
+ if (milliseconds == 0)
+ milliseconds = 1; // Force context switch.
+ ::Sleep(milliseconds);
+ ec = asio::error_code();
+ return 0;
+ }
+
+ // The select() call allows timeout values measured in microseconds, but the
+ // system clock (as wrapped by boost::posix_time::microsec_clock) typically
+ // has a resolution of 10 milliseconds. This can lead to a spinning select
+ // reactor, meaning increased CPU usage, when waiting for the earliest
+ // scheduled timeout if it's less than 10 milliseconds away. To avoid a tight
+ // spin we'll use a minimum timeout of 1 millisecond.
+ if (timeout && timeout->tv_sec == 0
+ && timeout->tv_usec > 0 && timeout->tv_usec < 1000)
+ timeout->tv_usec = 1000;
+#endif // defined(ASIO_WINDOWS) || defined(__CYGWIN__)
+
+#if defined(__hpux) && defined(__SELECT)
+ timespec ts;
+ ts.tv_sec = timeout ? timeout->tv_sec : 0;
+ ts.tv_nsec = timeout ? timeout->tv_usec * 1000 : 0;
+ return error_wrapper(::pselect(nfds, readfds,
+ writefds, exceptfds, timeout ? &ts : 0, 0), ec);
+#else
+ int result = error_wrapper(::select(nfds, readfds,
+ writefds, exceptfds, timeout), ec);
+ if (result >= 0)
+ ec = asio::error_code();
+ return result;
+#endif
+}
+
+int poll_read(socket_type s, state_type state,
+ int msec, asio::error_code& ec)
+{
+ if (s == invalid_socket)
+ {
+ ec = asio::error::bad_descriptor;
+ return socket_error_retval;
+ }
+
+#if defined(ASIO_WINDOWS) \
+ || defined(__CYGWIN__) \
+ || defined(__SYMBIAN32__)
+ fd_set fds;
+ FD_ZERO(&fds);
+ FD_SET(s, &fds);
+ timeval timeout_obj;
+ timeval* timeout;
+ if (state & user_set_non_blocking)
+ {
+ timeout_obj.tv_sec = 0;
+ timeout_obj.tv_usec = 0;
+ timeout = &timeout_obj;
+ }
+ else if (msec >= 0)
+ {
+ timeout_obj.tv_sec = msec / 1000;
+ timeout_obj.tv_usec = (msec % 1000) * 1000;
+ timeout = &timeout_obj;
+ }
+ else
+ timeout = 0;
+ clear_last_error();
+ int result = error_wrapper(::select(s + 1, &fds, 0, 0, timeout), ec);
+#else // defined(ASIO_WINDOWS)
+ // || defined(__CYGWIN__)
+ // || defined(__SYMBIAN32__)
+ pollfd fds;
+ fds.fd = s;
+ fds.events = POLLIN;
+ fds.revents = 0;
+ int timeout = (state & user_set_non_blocking) ? 0 : msec;
+ clear_last_error();
+ int result = error_wrapper(::poll(&fds, 1, timeout), ec);
+#endif // defined(ASIO_WINDOWS)
+ // || defined(__CYGWIN__)
+ // || defined(__SYMBIAN32__)
+ if (result == 0)
+ ec = (state & user_set_non_blocking)
+ ? asio::error::would_block : asio::error_code();
+ else if (result > 0)
+ ec = asio::error_code();
+ return result;
+}
+
+int poll_write(socket_type s, state_type state,
+ int msec, asio::error_code& ec)
+{
+ if (s == invalid_socket)
+ {
+ ec = asio::error::bad_descriptor;
+ return socket_error_retval;
+ }
+
+#if defined(ASIO_WINDOWS) \
+ || defined(__CYGWIN__) \
+ || defined(__SYMBIAN32__)
+ fd_set fds;
+ FD_ZERO(&fds);
+ FD_SET(s, &fds);
+ timeval timeout_obj;
+ timeval* timeout;
+ if (state & user_set_non_blocking)
+ {
+ timeout_obj.tv_sec = 0;
+ timeout_obj.tv_usec = 0;
+ timeout = &timeout_obj;
+ }
+ else if (msec >= 0)
+ {
+ timeout_obj.tv_sec = msec / 1000;
+ timeout_obj.tv_usec = (msec % 1000) * 1000;
+ timeout = &timeout_obj;
+ }
+ else
+ timeout = 0;
+ clear_last_error();
+ int result = error_wrapper(::select(s + 1, 0, &fds, 0, timeout), ec);
+#else // defined(ASIO_WINDOWS)
+ // || defined(__CYGWIN__)
+ // || defined(__SYMBIAN32__)
+ pollfd fds;
+ fds.fd = s;
+ fds.events = POLLOUT;
+ fds.revents = 0;
+ int timeout = (state & user_set_non_blocking) ? 0 : msec;
+ clear_last_error();
+ int result = error_wrapper(::poll(&fds, 1, timeout), ec);
+#endif // defined(ASIO_WINDOWS)
+ // || defined(__CYGWIN__)
+ // || defined(__SYMBIAN32__)
+ if (result == 0)
+ ec = (state & user_set_non_blocking)
+ ? asio::error::would_block : asio::error_code();
+ else if (result > 0)
+ ec = asio::error_code();
+ return result;
+}
+
+int poll_error(socket_type s, state_type state,
+ int msec, asio::error_code& ec)
+{
+ if (s == invalid_socket)
+ {
+ ec = asio::error::bad_descriptor;
+ return socket_error_retval;
+ }
+
+#if defined(ASIO_WINDOWS) \
+ || defined(__CYGWIN__) \
+ || defined(__SYMBIAN32__)
+ fd_set fds;
+ FD_ZERO(&fds);
+ FD_SET(s, &fds);
+ timeval timeout_obj;
+ timeval* timeout;
+ if (state & user_set_non_blocking)
+ {
+ timeout_obj.tv_sec = 0;
+ timeout_obj.tv_usec = 0;
+ timeout = &timeout_obj;
+ }
+ else if (msec >= 0)
+ {
+ timeout_obj.tv_sec = msec / 1000;
+ timeout_obj.tv_usec = (msec % 1000) * 1000;
+ timeout = &timeout_obj;
+ }
+ else
+ timeout = 0;
+ clear_last_error();
+ int result = error_wrapper(::select(s + 1, 0, 0, &fds, timeout), ec);
+#else // defined(ASIO_WINDOWS)
+ // || defined(__CYGWIN__)
+ // || defined(__SYMBIAN32__)
+ pollfd fds;
+ fds.fd = s;
+ fds.events = POLLPRI | POLLERR | POLLHUP;
+ fds.revents = 0;
+ int timeout = (state & user_set_non_blocking) ? 0 : msec;
+ clear_last_error();
+ int result = error_wrapper(::poll(&fds, 1, timeout), ec);
+#endif // defined(ASIO_WINDOWS)
+ // || defined(__CYGWIN__)
+ // || defined(__SYMBIAN32__)
+ if (result == 0)
+ ec = (state & user_set_non_blocking)
+ ? asio::error::would_block : asio::error_code();
+ else if (result > 0)
+ ec = asio::error_code();
+ return result;
+}
+
+int poll_connect(socket_type s, int msec, asio::error_code& ec)
+{
+ if (s == invalid_socket)
+ {
+ ec = asio::error::bad_descriptor;
+ return socket_error_retval;
+ }
+
+#if defined(ASIO_WINDOWS) \
+ || defined(__CYGWIN__) \
+ || defined(__SYMBIAN32__)
+ fd_set write_fds;
+ FD_ZERO(&write_fds);
+ FD_SET(s, &write_fds);
+ fd_set except_fds;
+ FD_ZERO(&except_fds);
+ FD_SET(s, &except_fds);
+ timeval timeout_obj;
+ timeval* timeout;
+ if (msec >= 0)
+ {
+ timeout_obj.tv_sec = msec / 1000;
+ timeout_obj.tv_usec = (msec % 1000) * 1000;
+ timeout = &timeout_obj;
+ }
+ else
+ timeout = 0;
+ clear_last_error();
+ int result = error_wrapper(::select(
+ s + 1, 0, &write_fds, &except_fds, timeout), ec);
+ if (result >= 0)
+ ec = asio::error_code();
+ return result;
+#else // defined(ASIO_WINDOWS)
+ // || defined(__CYGWIN__)
+ // || defined(__SYMBIAN32__)
+ pollfd fds;
+ fds.fd = s;
+ fds.events = POLLOUT;
+ fds.revents = 0;
+ clear_last_error();
+ int result = error_wrapper(::poll(&fds, 1, msec), ec);
+ if (result >= 0)
+ ec = asio::error_code();
+ return result;
+#endif // defined(ASIO_WINDOWS)
+ // || defined(__CYGWIN__)
+ // || defined(__SYMBIAN32__)
+}
+
+#endif // !defined(ASIO_WINDOWS_RUNTIME)
+
+const char* inet_ntop(int af, const void* src, char* dest, size_t length,
+ unsigned long scope_id, asio::error_code& ec)
+{
+ clear_last_error();
+#if defined(ASIO_WINDOWS_RUNTIME)
+ using namespace std; // For sprintf.
+ const unsigned char* bytes = static_cast<const unsigned char*>(src);
+ if (af == ASIO_OS_DEF(AF_INET))
+ {
+ sprintf_s(dest, length, "%u.%u.%u.%u",
+ bytes[0], bytes[1], bytes[2], bytes[3]);
+ return dest;
+ }
+ else if (af == ASIO_OS_DEF(AF_INET6))
+ {
+ size_t n = 0, b = 0, z = 0;
+ while (n < length && b < 16)
+ {
+ if (bytes[b] == 0 && bytes[b + 1] == 0 && z == 0)
+ {
+ do b += 2; while (b < 16 && bytes[b] == 0 && bytes[b + 1] == 0);
+ n += sprintf_s(dest + n, length - n, ":%s", b < 16 ? "" : ":"), ++z;
+ }
+ else
+ {
+ n += sprintf_s(dest + n, length - n, "%s%x", b ? ":" : "",
+ (static_cast<u_long_type>(bytes[b]) << 8) | bytes[b + 1]);
+ b += 2;
+ }
+ }
+ if (scope_id)
+ n += sprintf_s(dest + n, length - n, "%%%lu", scope_id);
+ return dest;
+ }
+ else
+ {
+ ec = asio::error::address_family_not_supported;
+ return 0;
+ }
+#elif defined(ASIO_WINDOWS) || defined(__CYGWIN__)
+ using namespace std; // For memcpy.
+
+ if (af != ASIO_OS_DEF(AF_INET) && af != ASIO_OS_DEF(AF_INET6))
+ {
+ ec = asio::error::address_family_not_supported;
+ return 0;
+ }
+
+ union
+ {
+ socket_addr_type base;
+ sockaddr_storage_type storage;
+ sockaddr_in4_type v4;
+ sockaddr_in6_type v6;
+ } address;
+ DWORD address_length;
+ if (af == ASIO_OS_DEF(AF_INET))
+ {
+ address_length = sizeof(sockaddr_in4_type);
+ address.v4.sin_family = ASIO_OS_DEF(AF_INET);
+ address.v4.sin_port = 0;
+ memcpy(&address.v4.sin_addr, src, sizeof(in4_addr_type));
+ }
+ else // AF_INET6
+ {
+ address_length = sizeof(sockaddr_in6_type);
+ address.v6.sin6_family = ASIO_OS_DEF(AF_INET6);
+ address.v6.sin6_port = 0;
+ address.v6.sin6_flowinfo = 0;
+ address.v6.sin6_scope_id = scope_id;
+ memcpy(&address.v6.sin6_addr, src, sizeof(in6_addr_type));
+ }
+
+ DWORD string_length = static_cast<DWORD>(length);
+#if defined(BOOST_NO_ANSI_APIS) || (defined(_MSC_VER) && (_MSC_VER >= 1800))
+ LPWSTR string_buffer = (LPWSTR)_alloca(length * sizeof(WCHAR));
+ int result = error_wrapper(::WSAAddressToStringW(&address.base,
+ address_length, 0, string_buffer, &string_length), ec);
+ ::WideCharToMultiByte(CP_ACP, 0, string_buffer, -1,
+ dest, static_cast<int>(length), 0, 0);
+#else
+ int result = error_wrapper(::WSAAddressToStringA(
+ &address.base, address_length, 0, dest, &string_length), ec);
+#endif
+
+ // Windows may set error code on success.
+ if (result != socket_error_retval)
+ ec = asio::error_code();
+
+ // Windows may not set an error code on failure.
+ else if (result == socket_error_retval && !ec)
+ ec = asio::error::invalid_argument;
+
+ return result == socket_error_retval ? 0 : dest;
+#else // defined(ASIO_WINDOWS) || defined(__CYGWIN__)
+ const char* result = error_wrapper(::inet_ntop(
+ af, src, dest, static_cast<int>(length)), ec);
+ if (result == 0 && !ec)
+ ec = asio::error::invalid_argument;
+ if (result != 0 && af == ASIO_OS_DEF(AF_INET6) && scope_id != 0)
+ {
+ using namespace std; // For strcat and sprintf.
+ char if_name[IF_NAMESIZE + 1] = "%";
+ const in6_addr_type* ipv6_address = static_cast<const in6_addr_type*>(src);
+ bool is_link_local = ((ipv6_address->s6_addr[0] == 0xfe)
+ && ((ipv6_address->s6_addr[1] & 0xc0) == 0x80));
+ bool is_multicast_link_local = ((ipv6_address->s6_addr[0] == 0xff)
+ && ((ipv6_address->s6_addr[1] & 0x0f) == 0x02));
+ if ((!is_link_local && !is_multicast_link_local)
+ || if_indextoname(static_cast<unsigned>(scope_id), if_name + 1) == 0)
+ sprintf(if_name + 1, "%lu", scope_id);
+ strcat(dest, if_name);
+ }
+ return result;
+#endif // defined(ASIO_WINDOWS) || defined(__CYGWIN__)
+}
+
+int inet_pton(int af, const char* src, void* dest,
+ unsigned long* scope_id, asio::error_code& ec)
+{
+ clear_last_error();
+#if defined(ASIO_WINDOWS_RUNTIME)
+ using namespace std; // For sscanf.
+ unsigned char* bytes = static_cast<unsigned char*>(dest);
+ if (af == ASIO_OS_DEF(AF_INET))
+ {
+ unsigned int b0, b1, b2, b3;
+ if (sscanf_s(src, "%u.%u.%u.%u", &b0, &b1, &b2, &b3) != 4)
+ {
+ ec = asio::error::invalid_argument;
+ return -1;
+ }
+ if (b0 > 255 || b1 > 255 || b2 > 255 || b3 > 255)
+ {
+ ec = asio::error::invalid_argument;
+ return -1;
+ }
+ bytes[0] = static_cast<unsigned char>(b0);
+ bytes[1] = static_cast<unsigned char>(b1);
+ bytes[2] = static_cast<unsigned char>(b2);
+ bytes[3] = static_cast<unsigned char>(b3);
+ ec = asio::error_code();
+ return 1;
+ }
+ else if (af == ASIO_OS_DEF(AF_INET6))
+ {
+ unsigned char* bytes = static_cast<unsigned char*>(dest);
+ std::memset(bytes, 0, 16);
+ unsigned char back_bytes[16] = { 0 };
+ int num_front_bytes = 0, num_back_bytes = 0;
+ const char* p = src;
+
+ enum { fword, fcolon, bword, scope, done } state = fword;
+ unsigned long current_word = 0;
+ while (state != done)
+ {
+ if (current_word > 0xFFFF)
+ {
+ ec = asio::error::invalid_argument;
+ return -1;
+ }
+
+ switch (state)
+ {
+ case fword:
+ if (*p >= '0' && *p <= '9')
+ current_word = current_word * 16 + *p++ - '0';
+ else if (*p >= 'a' && *p <= 'f')
+ current_word = current_word * 16 + *p++ - 'a' + 10;
+ else if (*p >= 'A' && *p <= 'F')
+ current_word = current_word * 16 + *p++ - 'A' + 10;
+ else
+ {
+ if (num_front_bytes == 16)
+ {
+ ec = asio::error::invalid_argument;
+ return -1;
+ }
+
+ bytes[num_front_bytes++] = (current_word >> 8) & 0xFF;
+ bytes[num_front_bytes++] = current_word & 0xFF;
+ current_word = 0;
+
+ if (*p == ':')
+ state = fcolon, ++p;
+ else if (*p == '%')
+ state = scope, ++p;
+ else if (*p == 0)
+ state = done;
+ else
+ {
+ ec = asio::error::invalid_argument;
+ return -1;
+ }
+ }
+ break;
+
+ case fcolon:
+ if (*p == ':')
+ state = bword, ++p;
+ else
+ state = fword;
+ break;
+
+ case bword:
+ if (*p >= '0' && *p <= '9')
+ current_word = current_word * 16 + *p++ - '0';
+ else if (*p >= 'a' && *p <= 'f')
+ current_word = current_word * 16 + *p++ - 'a' + 10;
+ else if (*p >= 'A' && *p <= 'F')
+ current_word = current_word * 16 + *p++ - 'A' + 10;
+ else
+ {
+ if (num_front_bytes + num_back_bytes == 16)
+ {
+ ec = asio::error::invalid_argument;
+ return -1;
+ }
+
+ back_bytes[num_back_bytes++] = (current_word >> 8) & 0xFF;
+ back_bytes[num_back_bytes++] = current_word & 0xFF;
+ current_word = 0;
+
+ if (*p == ':')
+ state = bword, ++p;
+ else if (*p == '%')
+ state = scope, ++p;
+ else if (*p == 0)
+ state = done;
+ else
+ {
+ ec = asio::error::invalid_argument;
+ return -1;
+ }
+ }
+ break;
+
+ case scope:
+ if (*p >= '0' && *p <= '9')
+ current_word = current_word * 10 + *p++ - '0';
+ else if (*p == 0)
+ *scope_id = current_word, state = done;
+ else
+ {
+ ec = asio::error::invalid_argument;
+ return -1;
+ }
+ break;
+
+ default:
+ break;
+ }
+ }
+
+ for (int i = 0; i < num_back_bytes; ++i)
+ bytes[16 - num_back_bytes + i] = back_bytes[i];
+
+ ec = asio::error_code();
+ return 1;
+ }
+ else
+ {
+ ec = asio::error::address_family_not_supported;
+ return -1;
+ }
+#elif defined(ASIO_WINDOWS) || defined(__CYGWIN__)
+ using namespace std; // For memcpy and strcmp.
+
+ if (af != ASIO_OS_DEF(AF_INET) && af != ASIO_OS_DEF(AF_INET6))
+ {
+ ec = asio::error::address_family_not_supported;
+ return -1;
+ }
+
+ union
+ {
+ socket_addr_type base;
+ sockaddr_storage_type storage;
+ sockaddr_in4_type v4;
+ sockaddr_in6_type v6;
+ } address;
+ int address_length = sizeof(sockaddr_storage_type);
+#if defined(BOOST_NO_ANSI_APIS) || (defined(_MSC_VER) && (_MSC_VER >= 1800))
+ int num_wide_chars = static_cast<int>(strlen(src)) + 1;
+ LPWSTR wide_buffer = (LPWSTR)_alloca(num_wide_chars * sizeof(WCHAR));
+ ::MultiByteToWideChar(CP_ACP, 0, src, -1, wide_buffer, num_wide_chars);
+ int result = error_wrapper(::WSAStringToAddressW(
+ wide_buffer, af, 0, &address.base, &address_length), ec);
+#else
+ int result = error_wrapper(::WSAStringToAddressA(
+ const_cast<char*>(src), af, 0, &address.base, &address_length), ec);
+#endif
+
+ if (af == ASIO_OS_DEF(AF_INET))
+ {
+ if (result != socket_error_retval)
+ {
+ memcpy(dest, &address.v4.sin_addr, sizeof(in4_addr_type));
+ ec = asio::error_code();
+ }
+ else if (strcmp(src, "255.255.255.255") == 0)
+ {
+ static_cast<in4_addr_type*>(dest)->s_addr = INADDR_NONE;
+ ec = asio::error_code();
+ }
+ }
+ else // AF_INET6
+ {
+ if (result != socket_error_retval)
+ {
+ memcpy(dest, &address.v6.sin6_addr, sizeof(in6_addr_type));
+ if (scope_id)
+ *scope_id = address.v6.sin6_scope_id;
+ ec = asio::error_code();
+ }
+ }
+
+ // Windows may not set an error code on failure.
+ if (result == socket_error_retval && !ec)
+ ec = asio::error::invalid_argument;
+
+ if (result != socket_error_retval)
+ ec = asio::error_code();
+
+ return result == socket_error_retval ? -1 : 1;
+#else // defined(ASIO_WINDOWS) || defined(__CYGWIN__)
+ using namespace std; // For strchr, memcpy and atoi.
+
+ // On some platforms, inet_pton fails if an address string contains a scope
+ // id. Detect and remove the scope id before passing the string to inet_pton.
+ const bool is_v6 = (af == ASIO_OS_DEF(AF_INET6));
+ const char* if_name = is_v6 ? strchr(src, '%') : 0;
+ char src_buf[max_addr_v6_str_len + 1];
+ const char* src_ptr = src;
+ if (if_name != 0)
+ {
+ if (if_name - src > max_addr_v6_str_len)
+ {
+ ec = asio::error::invalid_argument;
+ return 0;
+ }
+ memcpy(src_buf, src, if_name - src);
+ src_buf[if_name - src] = 0;
+ src_ptr = src_buf;
+ }
+
+ int result = error_wrapper(::inet_pton(af, src_ptr, dest), ec);
+ if (result <= 0 && !ec)
+ ec = asio::error::invalid_argument;
+ if (result > 0 && is_v6 && scope_id)
+ {
+ using namespace std; // For strchr and atoi.
+ *scope_id = 0;
+ if (if_name != 0)
+ {
+ in6_addr_type* ipv6_address = static_cast<in6_addr_type*>(dest);
+ bool is_link_local = ((ipv6_address->s6_addr[0] == 0xfe)
+ && ((ipv6_address->s6_addr[1] & 0xc0) == 0x80));
+ bool is_multicast_link_local = ((ipv6_address->s6_addr[0] == 0xff)
+ && ((ipv6_address->s6_addr[1] & 0x0f) == 0x02));
+ if (is_link_local || is_multicast_link_local)
+ *scope_id = if_nametoindex(if_name + 1);
+ if (*scope_id == 0)
+ *scope_id = atoi(if_name + 1);
+ }
+ }
+ return result;
+#endif // defined(ASIO_WINDOWS) || defined(__CYGWIN__)
+}
+
+int gethostname(char* name, int namelen, asio::error_code& ec)
+{
+ clear_last_error();
+#if defined(ASIO_WINDOWS_RUNTIME)
+ try
+ {
+ using namespace Windows::Foundation::Collections;
+ using namespace Windows::Networking;
+ using namespace Windows::Networking::Connectivity;
+ IVectorView<HostName^>^ hostnames = NetworkInformation::GetHostNames();
+ for (unsigned i = 0; i < hostnames->Size; ++i)
+ {
+ HostName^ hostname = hostnames->GetAt(i);
+ if (hostname->Type == HostNameType::DomainName)
+ {
+ std::wstring_convert<std::codecvt_utf8<wchar_t>> converter;
+ std::string raw_name = converter.to_bytes(hostname->RawName->Data());
+ if (namelen > 0 && raw_name.size() < static_cast<std::size_t>(namelen))
+ {
+ strcpy_s(name, namelen, raw_name.c_str());
+ return 0;
+ }
+ }
+ }
+ return -1;
+ }
+ catch (Platform::Exception^ e)
+ {
+ ec = asio::error_code(e->HResult,
+ asio::system_category());
+ return -1;
+ }
+#else // defined(ASIO_WINDOWS_RUNTIME)
+ int result = error_wrapper(::gethostname(name, namelen), ec);
+# if defined(ASIO_WINDOWS)
+ if (result == 0)
+ ec = asio::error_code();
+# endif // defined(ASIO_WINDOWS)
+ return result;
+#endif // defined(ASIO_WINDOWS_RUNTIME)
+}
+
+#if !defined(ASIO_WINDOWS_RUNTIME)
+
+#if !defined(ASIO_HAS_GETADDRINFO)
+
+// The following functions are only needed for emulation of getaddrinfo and
+// getnameinfo.
+
+inline asio::error_code translate_netdb_error(int error)
+{
+ switch (error)
+ {
+ case 0:
+ return asio::error_code();
+ case HOST_NOT_FOUND:
+ return asio::error::host_not_found;
+ case TRY_AGAIN:
+ return asio::error::host_not_found_try_again;
+ case NO_RECOVERY:
+ return asio::error::no_recovery;
+ case NO_DATA:
+ return asio::error::no_data;
+ default:
+ ASIO_ASSERT(false);
+ return asio::error::invalid_argument;
+ }
+}
+
+inline hostent* gethostbyaddr(const char* addr, int length, int af,
+ hostent* result, char* buffer, int buflength, asio::error_code& ec)
+{
+ clear_last_error();
+#if defined(ASIO_WINDOWS) || defined(__CYGWIN__)
+ (void)(buffer);
+ (void)(buflength);
+ hostent* retval = error_wrapper(::gethostbyaddr(addr, length, af), ec);
+ if (!retval)
+ return 0;
+ ec = asio::error_code();
+ *result = *retval;
+ return retval;
+#elif defined(__sun) || defined(__QNX__)
+ int error = 0;
+ hostent* retval = error_wrapper(::gethostbyaddr_r(addr, length, af, result,
+ buffer, buflength, &error), ec);
+ if (error)
+ ec = translate_netdb_error(error);
+ return retval;
+#elif defined(__MACH__) && defined(__APPLE__)
+ (void)(buffer);
+ (void)(buflength);
+ int error = 0;
+ hostent* retval = error_wrapper(::getipnodebyaddr(
+ addr, length, af, &error), ec);
+ if (error)
+ ec = translate_netdb_error(error);
+ if (!retval)
+ return 0;
+ *result = *retval;
+ return retval;
+#else
+ hostent* retval = 0;
+ int error = 0;
+ error_wrapper(::gethostbyaddr_r(addr, length, af, result, buffer,
+ buflength, &retval, &error), ec);
+ if (error)
+ ec = translate_netdb_error(error);
+ return retval;
+#endif
+}
+
+inline hostent* gethostbyname(const char* name, int af, struct hostent* result,
+ char* buffer, int buflength, int ai_flags, asio::error_code& ec)
+{
+ clear_last_error();
+#if defined(ASIO_WINDOWS) || defined(__CYGWIN__)
+ (void)(buffer);
+ (void)(buflength);
+ (void)(ai_flags);
+ if (af != ASIO_OS_DEF(AF_INET))
+ {
+ ec = asio::error::address_family_not_supported;
+ return 0;
+ }
+ hostent* retval = error_wrapper(::gethostbyname(name), ec);
+ if (!retval)
+ return 0;
+ ec = asio::error_code();
+ *result = *retval;
+ return result;
+#elif defined(__sun) || defined(__QNX__)
+ (void)(ai_flags);
+ if (af != ASIO_OS_DEF(AF_INET))
+ {
+ ec = asio::error::address_family_not_supported;
+ return 0;
+ }
+ int error = 0;
+ hostent* retval = error_wrapper(::gethostbyname_r(name, result, buffer,
+ buflength, &error), ec);
+ if (error)
+ ec = translate_netdb_error(error);
+ return retval;
+#elif defined(__MACH__) && defined(__APPLE__)
+ (void)(buffer);
+ (void)(buflength);
+ int error = 0;
+ hostent* retval = error_wrapper(::getipnodebyname(
+ name, af, ai_flags, &error), ec);
+ if (error)
+ ec = translate_netdb_error(error);
+ if (!retval)
+ return 0;
+ *result = *retval;
+ return retval;
+#else
+ (void)(ai_flags);
+ if (af != ASIO_OS_DEF(AF_INET))
+ {
+ ec = asio::error::address_family_not_supported;
+ return 0;
+ }
+ hostent* retval = 0;
+ int error = 0;
+ error_wrapper(::gethostbyname_r(name, result,
+ buffer, buflength, &retval, &error), ec);
+ if (error)
+ ec = translate_netdb_error(error);
+ return retval;
+#endif
+}
+
+inline void freehostent(hostent* h)
+{
+#if defined(__MACH__) && defined(__APPLE__)
+ if (h)
+ ::freehostent(h);
+#else
+ (void)(h);
+#endif
+}
+
+// Emulation of getaddrinfo based on implementation in:
+// Stevens, W. R., UNIX Network Programming Vol. 1, 2nd Ed., Prentice-Hall 1998.
+
+struct gai_search
+{
+ const char* host;
+ int family;
+};
+
+inline int gai_nsearch(const char* host,
+ const addrinfo_type* hints, gai_search (&search)[2])
+{
+ int search_count = 0;
+ if (host == 0 || host[0] == '\0')
+ {
+ if (hints->ai_flags & AI_PASSIVE)
+ {
+ // No host and AI_PASSIVE implies wildcard bind.
+ switch (hints->ai_family)
+ {
+ case ASIO_OS_DEF(AF_INET):
+ search[search_count].host = "0.0.0.0";
+ search[search_count].family = ASIO_OS_DEF(AF_INET);
+ ++search_count;
+ break;
+ case ASIO_OS_DEF(AF_INET6):
+ search[search_count].host = "0::0";
+ search[search_count].family = ASIO_OS_DEF(AF_INET6);
+ ++search_count;
+ break;
+ case ASIO_OS_DEF(AF_UNSPEC):
+ search[search_count].host = "0::0";
+ search[search_count].family = ASIO_OS_DEF(AF_INET6);
+ ++search_count;
+ search[search_count].host = "0.0.0.0";
+ search[search_count].family = ASIO_OS_DEF(AF_INET);
+ ++search_count;
+ break;
+ default:
+ break;
+ }
+ }
+ else
+ {
+ // No host and not AI_PASSIVE means connect to local host.
+ switch (hints->ai_family)
+ {
+ case ASIO_OS_DEF(AF_INET):
+ search[search_count].host = "localhost";
+ search[search_count].family = ASIO_OS_DEF(AF_INET);
+ ++search_count;
+ break;
+ case ASIO_OS_DEF(AF_INET6):
+ search[search_count].host = "localhost";
+ search[search_count].family = ASIO_OS_DEF(AF_INET6);
+ ++search_count;
+ break;
+ case ASIO_OS_DEF(AF_UNSPEC):
+ search[search_count].host = "localhost";
+ search[search_count].family = ASIO_OS_DEF(AF_INET6);
+ ++search_count;
+ search[search_count].host = "localhost";
+ search[search_count].family = ASIO_OS_DEF(AF_INET);
+ ++search_count;
+ break;
+ default:
+ break;
+ }
+ }
+ }
+ else
+ {
+ // Host is specified.
+ switch (hints->ai_family)
+ {
+ case ASIO_OS_DEF(AF_INET):
+ search[search_count].host = host;
+ search[search_count].family = ASIO_OS_DEF(AF_INET);
+ ++search_count;
+ break;
+ case ASIO_OS_DEF(AF_INET6):
+ search[search_count].host = host;
+ search[search_count].family = ASIO_OS_DEF(AF_INET6);
+ ++search_count;
+ break;
+ case ASIO_OS_DEF(AF_UNSPEC):
+ search[search_count].host = host;
+ search[search_count].family = ASIO_OS_DEF(AF_INET6);
+ ++search_count;
+ search[search_count].host = host;
+ search[search_count].family = ASIO_OS_DEF(AF_INET);
+ ++search_count;
+ break;
+ default:
+ break;
+ }
+ }
+ return search_count;
+}
+
+template <typename T>
+inline T* gai_alloc(std::size_t size = sizeof(T))
+{
+ using namespace std;
+ T* p = static_cast<T*>(::operator new(size, std::nothrow));
+ if (p)
+ memset(p, 0, size);
+ return p;
+}
+
+inline void gai_free(void* p)
+{
+ ::operator delete(p);
+}
+
+inline void gai_strcpy(char* target, const char* source, std::size_t max_size)
+{
+ using namespace std;
+#if defined(ASIO_HAS_SECURE_RTL)
+ strcpy_s(target, max_size, source);
+#else // defined(ASIO_HAS_SECURE_RTL)
+ *target = 0;
+ if (max_size > 0)
+ strncat(target, source, max_size - 1);
+#endif // defined(ASIO_HAS_SECURE_RTL)
+}
+
+enum { gai_clone_flag = 1 << 30 };
+
+inline int gai_aistruct(addrinfo_type*** next, const addrinfo_type* hints,
+ const void* addr, int family)
+{
+ using namespace std;
+
+ addrinfo_type* ai = gai_alloc<addrinfo_type>();
+ if (ai == 0)
+ return EAI_MEMORY;
+
+ ai->ai_next = 0;
+ **next = ai;
+ *next = &ai->ai_next;
+
+ ai->ai_canonname = 0;
+ ai->ai_socktype = hints->ai_socktype;
+ if (ai->ai_socktype == 0)
+ ai->ai_flags |= gai_clone_flag;
+ ai->ai_protocol = hints->ai_protocol;
+ ai->ai_family = family;
+
+ switch (ai->ai_family)
+ {
+ case ASIO_OS_DEF(AF_INET):
+ {
+ sockaddr_in4_type* sinptr = gai_alloc<sockaddr_in4_type>();
+ if (sinptr == 0)
+ return EAI_MEMORY;
+ sinptr->sin_family = ASIO_OS_DEF(AF_INET);
+ memcpy(&sinptr->sin_addr, addr, sizeof(in4_addr_type));
+ ai->ai_addr = reinterpret_cast<sockaddr*>(sinptr);
+ ai->ai_addrlen = sizeof(sockaddr_in4_type);
+ break;
+ }
+ case ASIO_OS_DEF(AF_INET6):
+ {
+ sockaddr_in6_type* sin6ptr = gai_alloc<sockaddr_in6_type>();
+ if (sin6ptr == 0)
+ return EAI_MEMORY;
+ sin6ptr->sin6_family = ASIO_OS_DEF(AF_INET6);
+ memcpy(&sin6ptr->sin6_addr, addr, sizeof(in6_addr_type));
+ ai->ai_addr = reinterpret_cast<sockaddr*>(sin6ptr);
+ ai->ai_addrlen = sizeof(sockaddr_in6_type);
+ break;
+ }
+ default:
+ break;
+ }
+
+ return 0;
+}
+
+inline addrinfo_type* gai_clone(addrinfo_type* ai)
+{
+ using namespace std;
+
+ addrinfo_type* new_ai = gai_alloc<addrinfo_type>();
+ if (new_ai == 0)
+ return new_ai;
+
+ new_ai->ai_next = ai->ai_next;
+ ai->ai_next = new_ai;
+
+ new_ai->ai_flags = 0;
+ new_ai->ai_family = ai->ai_family;
+ new_ai->ai_socktype = ai->ai_socktype;
+ new_ai->ai_protocol = ai->ai_protocol;
+ new_ai->ai_canonname = 0;
+ new_ai->ai_addrlen = ai->ai_addrlen;
+ new_ai->ai_addr = gai_alloc<sockaddr>(ai->ai_addrlen);
+ memcpy(new_ai->ai_addr, ai->ai_addr, ai->ai_addrlen);
+
+ return new_ai;
+}
+
+inline int gai_port(addrinfo_type* aihead, int port, int socktype)
+{
+ int num_found = 0;
+
+ for (addrinfo_type* ai = aihead; ai; ai = ai->ai_next)
+ {
+ if (ai->ai_flags & gai_clone_flag)
+ {
+ if (ai->ai_socktype != 0)
+ {
+ ai = gai_clone(ai);
+ if (ai == 0)
+ return -1;
+ // ai now points to newly cloned entry.
+ }
+ }
+ else if (ai->ai_socktype != socktype)
+ {
+ // Ignore if mismatch on socket type.
+ continue;
+ }
+
+ ai->ai_socktype = socktype;
+
+ switch (ai->ai_family)
+ {
+ case ASIO_OS_DEF(AF_INET):
+ {
+ sockaddr_in4_type* sinptr =
+ reinterpret_cast<sockaddr_in4_type*>(ai->ai_addr);
+ sinptr->sin_port = port;
+ ++num_found;
+ break;
+ }
+ case ASIO_OS_DEF(AF_INET6):
+ {
+ sockaddr_in6_type* sin6ptr =
+ reinterpret_cast<sockaddr_in6_type*>(ai->ai_addr);
+ sin6ptr->sin6_port = port;
+ ++num_found;
+ break;
+ }
+ default:
+ break;
+ }
+ }
+
+ return num_found;
+}
+
+inline int gai_serv(addrinfo_type* aihead,
+ const addrinfo_type* hints, const char* serv)
+{
+ using namespace std;
+
+ int num_found = 0;
+
+ if (
+#if defined(AI_NUMERICSERV)
+ (hints->ai_flags & AI_NUMERICSERV) ||
+#endif
+ isdigit(static_cast<unsigned char>(serv[0])))
+ {
+ int port = htons(atoi(serv));
+ if (hints->ai_socktype)
+ {
+ // Caller specifies socket type.
+ int rc = gai_port(aihead, port, hints->ai_socktype);
+ if (rc < 0)
+ return EAI_MEMORY;
+ num_found += rc;
+ }
+ else
+ {
+ // Caller does not specify socket type.
+ int rc = gai_port(aihead, port, SOCK_STREAM);
+ if (rc < 0)
+ return EAI_MEMORY;
+ num_found += rc;
+ rc = gai_port(aihead, port, SOCK_DGRAM);
+ if (rc < 0)
+ return EAI_MEMORY;
+ num_found += rc;
+ }
+ }
+ else
+ {
+ // Try service name with TCP first, then UDP.
+ if (hints->ai_socktype == 0 || hints->ai_socktype == SOCK_STREAM)
+ {
+ servent* sptr = getservbyname(serv, "tcp");
+ if (sptr != 0)
+ {
+ int rc = gai_port(aihead, sptr->s_port, SOCK_STREAM);
+ if (rc < 0)
+ return EAI_MEMORY;
+ num_found += rc;
+ }
+ }
+ if (hints->ai_socktype == 0 || hints->ai_socktype == SOCK_DGRAM)
+ {
+ servent* sptr = getservbyname(serv, "udp");
+ if (sptr != 0)
+ {
+ int rc = gai_port(aihead, sptr->s_port, SOCK_DGRAM);
+ if (rc < 0)
+ return EAI_MEMORY;
+ num_found += rc;
+ }
+ }
+ }
+
+ if (num_found == 0)
+ {
+ if (hints->ai_socktype == 0)
+ {
+ // All calls to getservbyname() failed.
+ return EAI_NONAME;
+ }
+ else
+ {
+ // Service not supported for socket type.
+ return EAI_SERVICE;
+ }
+ }
+
+ return 0;
+}
+
+inline int gai_echeck(const char* host, const char* service,
+ int flags, int family, int socktype, int protocol)
+{
+ (void)(flags);
+ (void)(protocol);
+
+ // Host or service must be specified.
+ if (host == 0 || host[0] == '\0')
+ if (service == 0 || service[0] == '\0')
+ return EAI_NONAME;
+
+ // Check combination of family and socket type.
+ switch (family)
+ {
+ case ASIO_OS_DEF(AF_UNSPEC):
+ break;
+ case ASIO_OS_DEF(AF_INET):
+ case ASIO_OS_DEF(AF_INET6):
+ if (service != 0 && service[0] != '\0')
+ if (socktype != 0 && socktype != SOCK_STREAM && socktype != SOCK_DGRAM)
+ return EAI_SOCKTYPE;
+ break;
+ default:
+ return EAI_FAMILY;
+ }
+
+ return 0;
+}
+
+inline void freeaddrinfo_emulation(addrinfo_type* aihead)
+{
+ addrinfo_type* ai = aihead;
+ while (ai)
+ {
+ gai_free(ai->ai_addr);
+ gai_free(ai->ai_canonname);
+ addrinfo_type* ainext = ai->ai_next;
+ gai_free(ai);
+ ai = ainext;
+ }
+}
+
+inline int getaddrinfo_emulation(const char* host, const char* service,
+ const addrinfo_type* hintsp, addrinfo_type** result)
+{
+ // Set up linked list of addrinfo structures.
+ addrinfo_type* aihead = 0;
+ addrinfo_type** ainext = &aihead;
+ char* canon = 0;
+
+ // Supply default hints if not specified by caller.
+ addrinfo_type hints = addrinfo_type();
+ hints.ai_family = ASIO_OS_DEF(AF_UNSPEC);
+ if (hintsp)
+ hints = *hintsp;
+
+ // If the resolution is not specifically for AF_INET6, remove the AI_V4MAPPED
+ // and AI_ALL flags.
+#if defined(AI_V4MAPPED)
+ if (hints.ai_family != ASIO_OS_DEF(AF_INET6))
+ hints.ai_flags &= ~AI_V4MAPPED;
+#endif
+#if defined(AI_ALL)
+ if (hints.ai_family != ASIO_OS_DEF(AF_INET6))
+ hints.ai_flags &= ~AI_ALL;
+#endif
+
+ // Basic error checking.
+ int rc = gai_echeck(host, service, hints.ai_flags, hints.ai_family,
+ hints.ai_socktype, hints.ai_protocol);
+ if (rc != 0)
+ {
+ freeaddrinfo_emulation(aihead);
+ return rc;
+ }
+
+ gai_search search[2];
+ int search_count = gai_nsearch(host, &hints, search);
+ for (gai_search* sptr = search; sptr < search + search_count; ++sptr)
+ {
+ // Check for IPv4 dotted decimal string.
+ in4_addr_type inaddr;
+ asio::error_code ec;
+ if (socket_ops::inet_pton(ASIO_OS_DEF(AF_INET),
+ sptr->host, &inaddr, 0, ec) == 1)
+ {
+ if (hints.ai_family != ASIO_OS_DEF(AF_UNSPEC)
+ && hints.ai_family != ASIO_OS_DEF(AF_INET))
+ {
+ freeaddrinfo_emulation(aihead);
+ gai_free(canon);
+ return EAI_FAMILY;
+ }
+ if (sptr->family == ASIO_OS_DEF(AF_INET))
+ {
+ rc = gai_aistruct(&ainext, &hints, &inaddr, ASIO_OS_DEF(AF_INET));
+ if (rc != 0)
+ {
+ freeaddrinfo_emulation(aihead);
+ gai_free(canon);
+ return rc;
+ }
+ }
+ continue;
+ }
+
+ // Check for IPv6 hex string.
+ in6_addr_type in6addr;
+ if (socket_ops::inet_pton(ASIO_OS_DEF(AF_INET6),
+ sptr->host, &in6addr, 0, ec) == 1)
+ {
+ if (hints.ai_family != ASIO_OS_DEF(AF_UNSPEC)
+ && hints.ai_family != ASIO_OS_DEF(AF_INET6))
+ {
+ freeaddrinfo_emulation(aihead);
+ gai_free(canon);
+ return EAI_FAMILY;
+ }
+ if (sptr->family == ASIO_OS_DEF(AF_INET6))
+ {
+ rc = gai_aistruct(&ainext, &hints, &in6addr,
+ ASIO_OS_DEF(AF_INET6));
+ if (rc != 0)
+ {
+ freeaddrinfo_emulation(aihead);
+ gai_free(canon);
+ return rc;
+ }
+ }
+ continue;
+ }
+
+ // Look up hostname.
+ hostent hent;
+ char hbuf[8192] = "";
+ hostent* hptr = socket_ops::gethostbyname(sptr->host,
+ sptr->family, &hent, hbuf, sizeof(hbuf), hints.ai_flags, ec);
+ if (hptr == 0)
+ {
+ if (search_count == 2)
+ {
+ // Failure is OK if there are multiple searches.
+ continue;
+ }
+ freeaddrinfo_emulation(aihead);
+ gai_free(canon);
+ if (ec == asio::error::host_not_found)
+ return EAI_NONAME;
+ if (ec == asio::error::host_not_found_try_again)
+ return EAI_AGAIN;
+ if (ec == asio::error::no_recovery)
+ return EAI_FAIL;
+ if (ec == asio::error::no_data)
+ return EAI_NONAME;
+ return EAI_NONAME;
+ }
+
+ // Check for address family mismatch if one was specified.
+ if (hints.ai_family != ASIO_OS_DEF(AF_UNSPEC)
+ && hints.ai_family != hptr->h_addrtype)
+ {
+ freeaddrinfo_emulation(aihead);
+ gai_free(canon);
+ socket_ops::freehostent(hptr);
+ return EAI_FAMILY;
+ }
+
+ // Save canonical name first time.
+ if (host != 0 && host[0] != '\0' && hptr->h_name && hptr->h_name[0]
+ && (hints.ai_flags & AI_CANONNAME) && canon == 0)
+ {
+ std::size_t canon_len = strlen(hptr->h_name) + 1;
+ canon = gai_alloc<char>(canon_len);
+ if (canon == 0)
+ {
+ freeaddrinfo_emulation(aihead);
+ socket_ops::freehostent(hptr);
+ return EAI_MEMORY;
+ }
+ gai_strcpy(canon, hptr->h_name, canon_len);
+ }
+
+ // Create an addrinfo structure for each returned address.
+ for (char** ap = hptr->h_addr_list; *ap; ++ap)
+ {
+ rc = gai_aistruct(&ainext, &hints, *ap, hptr->h_addrtype);
+ if (rc != 0)
+ {
+ freeaddrinfo_emulation(aihead);
+ gai_free(canon);
+ socket_ops::freehostent(hptr);
+ return EAI_FAMILY;
+ }
+ }
+
+ socket_ops::freehostent(hptr);
+ }
+
+ // Check if we found anything.
+ if (aihead == 0)
+ {
+ gai_free(canon);
+ return EAI_NONAME;
+ }
+
+ // Return canonical name in first entry.
+ if (host != 0 && host[0] != '\0' && (hints.ai_flags & AI_CANONNAME))
+ {
+ if (canon)
+ {
+ aihead->ai_canonname = canon;
+ canon = 0;
+ }
+ else
+ {
+ std::size_t canonname_len = strlen(search[0].host) + 1;
+ aihead->ai_canonname = gai_alloc<char>(canonname_len);
+ if (aihead->ai_canonname == 0)
+ {
+ freeaddrinfo_emulation(aihead);
+ return EAI_MEMORY;
+ }
+ gai_strcpy(aihead->ai_canonname, search[0].host, canonname_len);
+ }
+ }
+ gai_free(canon);
+
+ // Process the service name.
+ if (service != 0 && service[0] != '\0')
+ {
+ rc = gai_serv(aihead, &hints, service);
+ if (rc != 0)
+ {
+ freeaddrinfo_emulation(aihead);
+ return rc;
+ }
+ }
+
+ // Return result to caller.
+ *result = aihead;
+ return 0;
+}
+
+inline asio::error_code getnameinfo_emulation(
+ const socket_addr_type* sa, std::size_t salen, char* host,
+ std::size_t hostlen, char* serv, std::size_t servlen, int flags,
+ asio::error_code& ec)
+{
+ using namespace std;
+
+ const char* addr;
+ size_t addr_len;
+ unsigned short port;
+ switch (sa->sa_family)
+ {
+ case ASIO_OS_DEF(AF_INET):
+ if (salen != sizeof(sockaddr_in4_type))
+ {
+ return ec = asio::error::invalid_argument;
+ }
+ addr = reinterpret_cast<const char*>(
+ &reinterpret_cast<const sockaddr_in4_type*>(sa)->sin_addr);
+ addr_len = sizeof(in4_addr_type);
+ port = reinterpret_cast<const sockaddr_in4_type*>(sa)->sin_port;
+ break;
+ case ASIO_OS_DEF(AF_INET6):
+ if (salen != sizeof(sockaddr_in6_type))
+ {
+ return ec = asio::error::invalid_argument;
+ }
+ addr = reinterpret_cast<const char*>(
+ &reinterpret_cast<const sockaddr_in6_type*>(sa)->sin6_addr);
+ addr_len = sizeof(in6_addr_type);
+ port = reinterpret_cast<const sockaddr_in6_type*>(sa)->sin6_port;
+ break;
+ default:
+ return ec = asio::error::address_family_not_supported;
+ }
+
+ if (host && hostlen > 0)
+ {
+ if (flags & NI_NUMERICHOST)
+ {
+ if (socket_ops::inet_ntop(sa->sa_family, addr, host, hostlen, 0, ec) == 0)
+ {
+ return ec;
+ }
+ }
+ else
+ {
+ hostent hent;
+ char hbuf[8192] = "";
+ hostent* hptr = socket_ops::gethostbyaddr(addr,
+ static_cast<int>(addr_len), sa->sa_family,
+ &hent, hbuf, sizeof(hbuf), ec);
+ if (hptr && hptr->h_name && hptr->h_name[0] != '\0')
+ {
+ if (flags & NI_NOFQDN)
+ {
+ char* dot = strchr(hptr->h_name, '.');
+ if (dot)
+ {
+ *dot = 0;
+ }
+ }
+ gai_strcpy(host, hptr->h_name, hostlen);
+ socket_ops::freehostent(hptr);
+ }
+ else
+ {
+ socket_ops::freehostent(hptr);
+ if (flags & NI_NAMEREQD)
+ {
+ return ec = asio::error::host_not_found;
+ }
+ if (socket_ops::inet_ntop(sa->sa_family,
+ addr, host, hostlen, 0, ec) == 0)
+ {
+ return ec;
+ }
+ }
+ }
+ }
+
+ if (serv && servlen > 0)
+ {
+ if (flags & NI_NUMERICSERV)
+ {
+ if (servlen < 6)
+ {
+ return ec = asio::error::no_buffer_space;
+ }
+#if defined(ASIO_HAS_SECURE_RTL)
+ sprintf_s(serv, servlen, "%u", ntohs(port));
+#else // defined(ASIO_HAS_SECURE_RTL)
+ sprintf(serv, "%u", ntohs(port));
+#endif // defined(ASIO_HAS_SECURE_RTL)
+ }
+ else
+ {
+#if defined(ASIO_HAS_PTHREADS)
+ static ::pthread_mutex_t mutex = PTHREAD_MUTEX_INITIALIZER;
+ ::pthread_mutex_lock(&mutex);
+#endif // defined(ASIO_HAS_PTHREADS)
+ servent* sptr = ::getservbyport(port, (flags & NI_DGRAM) ? "udp" : 0);
+ if (sptr && sptr->s_name && sptr->s_name[0] != '\0')
+ {
+ gai_strcpy(serv, sptr->s_name, servlen);
+ }
+ else
+ {
+ if (servlen < 6)
+ {
+ return ec = asio::error::no_buffer_space;
+ }
+#if defined(ASIO_HAS_SECURE_RTL)
+ sprintf_s(serv, servlen, "%u", ntohs(port));
+#else // defined(ASIO_HAS_SECURE_RTL)
+ sprintf(serv, "%u", ntohs(port));
+#endif // defined(ASIO_HAS_SECURE_RTL)
+ }
+#if defined(ASIO_HAS_PTHREADS)
+ ::pthread_mutex_unlock(&mutex);
+#endif // defined(ASIO_HAS_PTHREADS)
+ }
+ }
+
+ ec = asio::error_code();
+ return ec;
+}
+
+#endif // !defined(ASIO_HAS_GETADDRINFO)
+
+inline asio::error_code translate_addrinfo_error(int error)
+{
+ switch (error)
+ {
+ case 0:
+ return asio::error_code();
+ case EAI_AGAIN:
+ return asio::error::host_not_found_try_again;
+ case EAI_BADFLAGS:
+ return asio::error::invalid_argument;
+ case EAI_FAIL:
+ return asio::error::no_recovery;
+ case EAI_FAMILY:
+ return asio::error::address_family_not_supported;
+ case EAI_MEMORY:
+ return asio::error::no_memory;
+ case EAI_NONAME:
+#if defined(EAI_ADDRFAMILY)
+ case EAI_ADDRFAMILY:
+#endif
+#if defined(EAI_NODATA) && (EAI_NODATA != EAI_NONAME)
+ case EAI_NODATA:
+#endif
+ return asio::error::host_not_found;
+ case EAI_SERVICE:
+ return asio::error::service_not_found;
+ case EAI_SOCKTYPE:
+ return asio::error::socket_type_not_supported;
+ default: // Possibly the non-portable EAI_SYSTEM.
+#if defined(ASIO_WINDOWS) || defined(__CYGWIN__)
+ return asio::error_code(
+ WSAGetLastError(), asio::error::get_system_category());
+#else
+ return asio::error_code(
+ errno, asio::error::get_system_category());
+#endif
+ }
+}
+
+asio::error_code getaddrinfo(const char* host,
+ const char* service, const addrinfo_type& hints,
+ addrinfo_type** result, asio::error_code& ec)
+{
+ host = (host && *host) ? host : 0;
+ service = (service && *service) ? service : 0;
+ clear_last_error();
+#if defined(ASIO_WINDOWS) || defined(__CYGWIN__)
+# if defined(ASIO_HAS_GETADDRINFO)
+ // Building for Windows XP, Windows Server 2003, or later.
+ int error = ::getaddrinfo(host, service, &hints, result);
+ return ec = translate_addrinfo_error(error);
+# else
+ // Building for Windows 2000 or earlier.
+ typedef int (WSAAPI *gai_t)(const char*,
+ const char*, const addrinfo_type*, addrinfo_type**);
+ if (HMODULE winsock_module = ::GetModuleHandleA("ws2_32"))
+ {
+ if (gai_t gai = (gai_t)::GetProcAddress(winsock_module, "getaddrinfo"))
+ {
+ int error = gai(host, service, &hints, result);
+ return ec = translate_addrinfo_error(error);
+ }
+ }
+ int error = getaddrinfo_emulation(host, service, &hints, result);
+ return ec = translate_addrinfo_error(error);
+# endif
+#elif !defined(ASIO_HAS_GETADDRINFO)
+ int error = getaddrinfo_emulation(host, service, &hints, result);
+ return ec = translate_addrinfo_error(error);
+#else
+ int error = ::getaddrinfo(host, service, &hints, result);
+#if defined(__MACH__) && defined(__APPLE__)
+ using namespace std; // For isdigit and atoi.
+ if (error == 0 && service && isdigit(static_cast<unsigned char>(service[0])))
+ {
+ u_short_type port = host_to_network_short(atoi(service));
+ for (addrinfo_type* ai = *result; ai; ai = ai->ai_next)
+ {
+ switch (ai->ai_family)
+ {
+ case ASIO_OS_DEF(AF_INET):
+ {
+ sockaddr_in4_type* sinptr =
+ reinterpret_cast<sockaddr_in4_type*>(ai->ai_addr);
+ if (sinptr->sin_port == 0)
+ sinptr->sin_port = port;
+ break;
+ }
+ case ASIO_OS_DEF(AF_INET6):
+ {
+ sockaddr_in6_type* sin6ptr =
+ reinterpret_cast<sockaddr_in6_type*>(ai->ai_addr);
+ if (sin6ptr->sin6_port == 0)
+ sin6ptr->sin6_port = port;
+ break;
+ }
+ default:
+ break;
+ }
+ }
+ }
+#endif
+ return ec = translate_addrinfo_error(error);
+#endif
+}
+
+asio::error_code background_getaddrinfo(
+ const weak_cancel_token_type& cancel_token, const char* host,
+ const char* service, const addrinfo_type& hints,
+ addrinfo_type** result, asio::error_code& ec)
+{
+ if (cancel_token.expired())
+ ec = asio::error::operation_aborted;
+ else
+ socket_ops::getaddrinfo(host, service, hints, result, ec);
+ return ec;
+}
+
+void freeaddrinfo(addrinfo_type* ai)
+{
+#if defined(ASIO_WINDOWS) || defined(__CYGWIN__)
+# if defined(ASIO_HAS_GETADDRINFO)
+ // Building for Windows XP, Windows Server 2003, or later.
+ ::freeaddrinfo(ai);
+# else
+ // Building for Windows 2000 or earlier.
+ typedef int (WSAAPI *fai_t)(addrinfo_type*);
+ if (HMODULE winsock_module = ::GetModuleHandleA("ws2_32"))
+ {
+ if (fai_t fai = (fai_t)::GetProcAddress(winsock_module, "freeaddrinfo"))
+ {
+ fai(ai);
+ return;
+ }
+ }
+ freeaddrinfo_emulation(ai);
+# endif
+#elif !defined(ASIO_HAS_GETADDRINFO)
+ freeaddrinfo_emulation(ai);
+#else
+ ::freeaddrinfo(ai);
+#endif
+}
+
+asio::error_code getnameinfo(const socket_addr_type* addr,
+ std::size_t addrlen, char* host, std::size_t hostlen,
+ char* serv, std::size_t servlen, int flags, asio::error_code& ec)
+{
+#if defined(ASIO_WINDOWS) || defined(__CYGWIN__)
+# if defined(ASIO_HAS_GETADDRINFO)
+ // Building for Windows XP, Windows Server 2003, or later.
+ clear_last_error();
+ int error = ::getnameinfo(addr, static_cast<socklen_t>(addrlen),
+ host, static_cast<DWORD>(hostlen),
+ serv, static_cast<DWORD>(servlen), flags);
+ return ec = translate_addrinfo_error(error);
+# else
+ // Building for Windows 2000 or earlier.
+ typedef int (WSAAPI *gni_t)(const socket_addr_type*,
+ int, char*, DWORD, char*, DWORD, int);
+ if (HMODULE winsock_module = ::GetModuleHandleA("ws2_32"))
+ {
+ if (gni_t gni = (gni_t)::GetProcAddress(winsock_module, "getnameinfo"))
+ {
+ clear_last_error();
+ int error = gni(addr, static_cast<int>(addrlen),
+ host, static_cast<DWORD>(hostlen),
+ serv, static_cast<DWORD>(servlen), flags);
+ return ec = translate_addrinfo_error(error);
+ }
+ }
+ clear_last_error();
+ return getnameinfo_emulation(addr, addrlen,
+ host, hostlen, serv, servlen, flags, ec);
+# endif
+#elif !defined(ASIO_HAS_GETADDRINFO)
+ using namespace std; // For memcpy.
+ sockaddr_storage_type tmp_addr;
+ memcpy(&tmp_addr, addr, addrlen);
+ addr = reinterpret_cast<socket_addr_type*>(&tmp_addr);
+ clear_last_error();
+ return getnameinfo_emulation(addr, addrlen,
+ host, hostlen, serv, servlen, flags, ec);
+#else
+ clear_last_error();
+ int error = ::getnameinfo(addr, addrlen, host, hostlen, serv, servlen, flags);
+ return ec = translate_addrinfo_error(error);
+#endif
+}
+
+asio::error_code sync_getnameinfo(
+ const socket_addr_type* addr, std::size_t addrlen,
+ char* host, std::size_t hostlen, char* serv,
+ std::size_t servlen, int sock_type, asio::error_code& ec)
+{
+ // First try resolving with the service name. If that fails try resolving
+ // but allow the service to be returned as a number.
+ int flags = (sock_type == SOCK_DGRAM) ? NI_DGRAM : 0;
+ socket_ops::getnameinfo(addr, addrlen, host,
+ hostlen, serv, servlen, flags, ec);
+ if (ec)
+ {
+ socket_ops::getnameinfo(addr, addrlen, host, hostlen,
+ serv, servlen, flags | NI_NUMERICSERV, ec);
+ }
+
+ return ec;
+}
+
+asio::error_code background_getnameinfo(
+ const weak_cancel_token_type& cancel_token,
+ const socket_addr_type* addr, std::size_t addrlen,
+ char* host, std::size_t hostlen, char* serv,
+ std::size_t servlen, int sock_type, asio::error_code& ec)
+{
+ if (cancel_token.expired())
+ {
+ ec = asio::error::operation_aborted;
+ }
+ else
+ {
+ // First try resolving with the service name. If that fails try resolving
+ // but allow the service to be returned as a number.
+ int flags = (sock_type == SOCK_DGRAM) ? NI_DGRAM : 0;
+ socket_ops::getnameinfo(addr, addrlen, host,
+ hostlen, serv, servlen, flags, ec);
+ if (ec)
+ {
+ socket_ops::getnameinfo(addr, addrlen, host, hostlen,
+ serv, servlen, flags | NI_NUMERICSERV, ec);
+ }
+ }
+
+ return ec;
+}
+
+#endif // !defined(ASIO_WINDOWS_RUNTIME)
+
+u_long_type network_to_host_long(u_long_type value)
+{
+#if defined(ASIO_WINDOWS_RUNTIME)
+ unsigned char* value_p = reinterpret_cast<unsigned char*>(&value);
+ u_long_type result = (static_cast<u_long_type>(value_p[0]) << 24)
+ | (static_cast<u_long_type>(value_p[1]) << 16)
+ | (static_cast<u_long_type>(value_p[2]) << 8)
+ | static_cast<u_long_type>(value_p[3]);
+ return result;
+#else // defined(ASIO_WINDOWS_RUNTIME)
+ return ntohl(value);
+#endif // defined(ASIO_WINDOWS_RUNTIME)
+}
+
+u_long_type host_to_network_long(u_long_type value)
+{
+#if defined(ASIO_WINDOWS_RUNTIME)
+ u_long_type result;
+ unsigned char* result_p = reinterpret_cast<unsigned char*>(&result);
+ result_p[0] = static_cast<unsigned char>((value >> 24) & 0xFF);
+ result_p[1] = static_cast<unsigned char>((value >> 16) & 0xFF);
+ result_p[2] = static_cast<unsigned char>((value >> 8) & 0xFF);
+ result_p[3] = static_cast<unsigned char>(value & 0xFF);
+ return result;
+#else // defined(ASIO_WINDOWS_RUNTIME)
+ return htonl(value);
+#endif // defined(ASIO_WINDOWS_RUNTIME)
+}
+
+u_short_type network_to_host_short(u_short_type value)
+{
+#if defined(ASIO_WINDOWS_RUNTIME)
+ unsigned char* value_p = reinterpret_cast<unsigned char*>(&value);
+ u_short_type result = (static_cast<u_short_type>(value_p[0]) << 8)
+ | static_cast<u_short_type>(value_p[1]);
+ return result;
+#else // defined(ASIO_WINDOWS_RUNTIME)
+ return ntohs(value);
+#endif // defined(ASIO_WINDOWS_RUNTIME)
+}
+
+u_short_type host_to_network_short(u_short_type value)
+{
+#if defined(ASIO_WINDOWS_RUNTIME)
+ u_short_type result;
+ unsigned char* result_p = reinterpret_cast<unsigned char*>(&result);
+ result_p[0] = static_cast<unsigned char>((value >> 8) & 0xFF);
+ result_p[1] = static_cast<unsigned char>(value & 0xFF);
+ return result;
+#else // defined(ASIO_WINDOWS_RUNTIME)
+ return htons(value);
+#endif // defined(ASIO_WINDOWS_RUNTIME)
+}
+
+} // namespace socket_ops
+} // namespace detail
+} // namespace asio
+
+#include "asio/detail/pop_options.hpp"
+
+#endif // ASIO_DETAIL_SOCKET_OPS_IPP
diff --git a/lib/asio/detail/impl/socket_select_interrupter.ipp b/lib/asio/detail/impl/socket_select_interrupter.ipp
new file mode 100644
index 0000000..052f2a7
--- /dev/null
+++ b/lib/asio/detail/impl/socket_select_interrupter.ipp
@@ -0,0 +1,176 @@
+//
+// detail/impl/socket_select_interrupter.ipp
+// ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+//
+// Copyright (c) 2003-2018 Christopher M. Kohlhoff (chris at kohlhoff dot com)
+//
+// 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 ASIO_DETAIL_IMPL_SOCKET_SELECT_INTERRUPTER_IPP
+#define ASIO_DETAIL_IMPL_SOCKET_SELECT_INTERRUPTER_IPP
+
+#if defined(_MSC_VER) && (_MSC_VER >= 1200)
+# pragma once
+#endif // defined(_MSC_VER) && (_MSC_VER >= 1200)
+
+#include "asio/detail/config.hpp"
+
+#if !defined(ASIO_WINDOWS_RUNTIME)
+
+#if defined(ASIO_WINDOWS) \
+ || defined(__CYGWIN__) \
+ || defined(__SYMBIAN32__)
+
+#include <cstdlib>
+#include "asio/detail/socket_holder.hpp"
+#include "asio/detail/socket_ops.hpp"
+#include "asio/detail/socket_select_interrupter.hpp"
+#include "asio/detail/throw_error.hpp"
+#include "asio/error.hpp"
+
+#include "asio/detail/push_options.hpp"
+
+namespace asio {
+namespace detail {
+
+socket_select_interrupter::socket_select_interrupter()
+{
+ open_descriptors();
+}
+
+void socket_select_interrupter::open_descriptors()
+{
+ asio::error_code ec;
+ socket_holder acceptor(socket_ops::socket(
+ AF_INET, SOCK_STREAM, IPPROTO_TCP, ec));
+ if (acceptor.get() == invalid_socket)
+ asio::detail::throw_error(ec, "socket_select_interrupter");
+
+ int opt = 1;
+ socket_ops::state_type acceptor_state = 0;
+ socket_ops::setsockopt(acceptor.get(), acceptor_state,
+ SOL_SOCKET, SO_REUSEADDR, &opt, sizeof(opt), ec);
+
+ using namespace std; // For memset.
+ sockaddr_in4_type addr;
+ std::size_t addr_len = sizeof(addr);
+ memset(&addr, 0, sizeof(addr));
+ addr.sin_family = AF_INET;
+ addr.sin_addr.s_addr = socket_ops::host_to_network_long(INADDR_LOOPBACK);
+ addr.sin_port = 0;
+ if (socket_ops::bind(acceptor.get(), (const socket_addr_type*)&addr,
+ addr_len, ec) == socket_error_retval)
+ asio::detail::throw_error(ec, "socket_select_interrupter");
+
+ if (socket_ops::getsockname(acceptor.get(), (socket_addr_type*)&addr,
+ &addr_len, ec) == socket_error_retval)
+ asio::detail::throw_error(ec, "socket_select_interrupter");
+
+ // Some broken firewalls on Windows will intermittently cause getsockname to
+ // return 0.0.0.0 when the socket is actually bound to 127.0.0.1. We
+ // explicitly specify the target address here to work around this problem.
+ if (addr.sin_addr.s_addr == socket_ops::host_to_network_long(INADDR_ANY))
+ addr.sin_addr.s_addr = socket_ops::host_to_network_long(INADDR_LOOPBACK);
+
+ if (socket_ops::listen(acceptor.get(),
+ SOMAXCONN, ec) == socket_error_retval)
+ asio::detail::throw_error(ec, "socket_select_interrupter");
+
+ socket_holder client(socket_ops::socket(
+ AF_INET, SOCK_STREAM, IPPROTO_TCP, ec));
+ if (client.get() == invalid_socket)
+ asio::detail::throw_error(ec, "socket_select_interrupter");
+
+ if (socket_ops::connect(client.get(), (const socket_addr_type*)&addr,
+ addr_len, ec) == socket_error_retval)
+ asio::detail::throw_error(ec, "socket_select_interrupter");
+
+ socket_holder server(socket_ops::accept(acceptor.get(), 0, 0, ec));
+ if (server.get() == invalid_socket)
+ asio::detail::throw_error(ec, "socket_select_interrupter");
+
+ ioctl_arg_type non_blocking = 1;
+ socket_ops::state_type client_state = 0;
+ if (socket_ops::ioctl(client.get(), client_state,
+ FIONBIO, &non_blocking, ec))
+ asio::detail::throw_error(ec, "socket_select_interrupter");
+
+ opt = 1;
+ socket_ops::setsockopt(client.get(), client_state,
+ IPPROTO_TCP, TCP_NODELAY, &opt, sizeof(opt), ec);
+
+ non_blocking = 1;
+ socket_ops::state_type server_state = 0;
+ if (socket_ops::ioctl(server.get(), server_state,
+ FIONBIO, &non_blocking, ec))
+ asio::detail::throw_error(ec, "socket_select_interrupter");
+
+ opt = 1;
+ socket_ops::setsockopt(server.get(), server_state,
+ IPPROTO_TCP, TCP_NODELAY, &opt, sizeof(opt), ec);
+
+ read_descriptor_ = server.release();
+ write_descriptor_ = client.release();
+}
+
+socket_select_interrupter::~socket_select_interrupter()
+{
+ close_descriptors();
+}
+
+void socket_select_interrupter::close_descriptors()
+{
+ asio::error_code ec;
+ socket_ops::state_type state = socket_ops::internal_non_blocking;
+ if (read_descriptor_ != invalid_socket)
+ socket_ops::close(read_descriptor_, state, true, ec);
+ if (write_descriptor_ != invalid_socket)
+ socket_ops::close(write_descriptor_, state, true, ec);
+}
+
+void socket_select_interrupter::recreate()
+{
+ close_descriptors();
+
+ write_descriptor_ = invalid_socket;
+ read_descriptor_ = invalid_socket;
+
+ open_descriptors();
+}
+
+void socket_select_interrupter::interrupt()
+{
+ char byte = 0;
+ socket_ops::buf b;
+ socket_ops::init_buf(b, &byte, 1);
+ asio::error_code ec;
+ socket_ops::send(write_descriptor_, &b, 1, 0, ec);
+}
+
+bool socket_select_interrupter::reset()
+{
+ char data[1024];
+ socket_ops::buf b;
+ socket_ops::init_buf(b, data, sizeof(data));
+ asio::error_code ec;
+ int bytes_read = socket_ops::recv(read_descriptor_, &b, 1, 0, ec);
+ bool was_interrupted = (bytes_read > 0);
+ while (bytes_read == sizeof(data))
+ bytes_read = socket_ops::recv(read_descriptor_, &b, 1, 0, ec);
+ return was_interrupted;
+}
+
+} // namespace detail
+} // namespace asio
+
+#include "asio/detail/pop_options.hpp"
+
+#endif // defined(ASIO_WINDOWS)
+ // || defined(__CYGWIN__)
+ // || defined(__SYMBIAN32__)
+
+#endif // !defined(ASIO_WINDOWS_RUNTIME)
+
+#endif // ASIO_DETAIL_IMPL_SOCKET_SELECT_INTERRUPTER_IPP
diff --git a/lib/asio/detail/impl/strand_executor_service.hpp b/lib/asio/detail/impl/strand_executor_service.hpp
new file mode 100644
index 0000000..0e18ca0
--- /dev/null
+++ b/lib/asio/detail/impl/strand_executor_service.hpp
@@ -0,0 +1,179 @@
+//
+// detail/impl/strand_executor_service.hpp
+// ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+//
+// Copyright (c) 2003-2018 Christopher M. Kohlhoff (chris at kohlhoff dot com)
+//
+// 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 ASIO_DETAIL_IMPL_STRAND_EXECUTOR_SERVICE_HPP
+#define ASIO_DETAIL_IMPL_STRAND_EXECUTOR_SERVICE_HPP
+
+#if defined(_MSC_VER) && (_MSC_VER >= 1200)
+# pragma once
+#endif // defined(_MSC_VER) && (_MSC_VER >= 1200)
+
+#include "asio/detail/call_stack.hpp"
+#include "asio/detail/fenced_block.hpp"
+#include "asio/detail/handler_invoke_helpers.hpp"
+#include "asio/detail/recycling_allocator.hpp"
+#include "asio/executor_work_guard.hpp"
+
+#include "asio/detail/push_options.hpp"
+
+namespace asio {
+namespace detail {
+
+template <typename Executor>
+class strand_executor_service::invoker
+{
+public:
+ invoker(const implementation_type& impl, Executor& ex)
+ : impl_(impl),
+ work_(ex)
+ {
+ }
+
+ invoker(const invoker& other)
+ : impl_(other.impl_),
+ work_(other.work_)
+ {
+ }
+
+#if defined(ASIO_HAS_MOVE)
+ invoker(invoker&& other)
+ : impl_(ASIO_MOVE_CAST(implementation_type)(other.impl_)),
+ work_(ASIO_MOVE_CAST(executor_work_guard<Executor>)(other.work_))
+ {
+ }
+#endif // defined(ASIO_HAS_MOVE)
+
+ struct on_invoker_exit
+ {
+ invoker* this_;
+
+ ~on_invoker_exit()
+ {
+ this_->impl_->mutex_->lock();
+ this_->impl_->ready_queue_.push(this_->impl_->waiting_queue_);
+ bool more_handlers = this_->impl_->locked_ =
+ !this_->impl_->ready_queue_.empty();
+ this_->impl_->mutex_->unlock();
+
+ if (more_handlers)
+ {
+ Executor ex(this_->work_.get_executor());
+ recycling_allocator<void> allocator;
+ ex.post(ASIO_MOVE_CAST(invoker)(*this_), allocator);
+ }
+ }
+ };
+
+ void operator()()
+ {
+ // Indicate that this strand is executing on the current thread.
+ call_stack<strand_impl>::context ctx(impl_.get());
+
+ // Ensure the next handler, if any, is scheduled on block exit.
+ on_invoker_exit on_exit = { this };
+ (void)on_exit;
+
+ // Run all ready handlers. No lock is required since the ready queue is
+ // accessed only within the strand.
+ asio::error_code ec;
+ while (scheduler_operation* o = impl_->ready_queue_.front())
+ {
+ impl_->ready_queue_.pop();
+ o->complete(impl_.get(), ec, 0);
+ }
+ }
+
+private:
+ implementation_type impl_;
+ executor_work_guard<Executor> work_;
+};
+
+template <typename Executor, typename Function, typename Allocator>
+void strand_executor_service::dispatch(const implementation_type& impl,
+ Executor& ex, ASIO_MOVE_ARG(Function) function, const Allocator& a)
+{
+ typedef typename decay<Function>::type function_type;
+
+ // If we are already in the strand then the function can run immediately.
+ if (call_stack<strand_impl>::contains(impl.get()))
+ {
+ // Make a local, non-const copy of the function.
+ function_type tmp(ASIO_MOVE_CAST(Function)(function));
+
+ fenced_block b(fenced_block::full);
+ asio_handler_invoke_helpers::invoke(tmp, tmp);
+ return;
+ }
+
+ // Allocate and construct an operation to wrap the function.
+ typedef executor_op<function_type, Allocator> op;
+ typename op::ptr p = { detail::addressof(a), op::ptr::allocate(a), 0 };
+ p.p = new (p.v) op(ASIO_MOVE_CAST(Function)(function), a);
+
+ ASIO_HANDLER_CREATION((impl->service_->context(), *p.p,
+ "strand_executor", impl.get(), 0, "dispatch"));
+
+ // Add the function to the strand and schedule the strand if required.
+ bool first = enqueue(impl, p.p);
+ p.v = p.p = 0;
+ if (first)
+ ex.dispatch(invoker<Executor>(impl, ex), a);
+}
+
+// Request invocation of the given function and return immediately.
+template <typename Executor, typename Function, typename Allocator>
+void strand_executor_service::post(const implementation_type& impl,
+ Executor& ex, ASIO_MOVE_ARG(Function) function, const Allocator& a)
+{
+ typedef typename decay<Function>::type function_type;
+
+ // Allocate and construct an operation to wrap the function.
+ typedef executor_op<function_type, Allocator> op;
+ typename op::ptr p = { detail::addressof(a), op::ptr::allocate(a), 0 };
+ p.p = new (p.v) op(ASIO_MOVE_CAST(Function)(function), a);
+
+ ASIO_HANDLER_CREATION((impl->service_->context(), *p.p,
+ "strand_executor", impl.get(), 0, "post"));
+
+ // Add the function to the strand and schedule the strand if required.
+ bool first = enqueue(impl, p.p);
+ p.v = p.p = 0;
+ if (first)
+ ex.post(invoker<Executor>(impl, ex), a);
+}
+
+// Request invocation of the given function and return immediately.
+template <typename Executor, typename Function, typename Allocator>
+void strand_executor_service::defer(const implementation_type& impl,
+ Executor& ex, ASIO_MOVE_ARG(Function) function, const Allocator& a)
+{
+ typedef typename decay<Function>::type function_type;
+
+ // Allocate and construct an operation to wrap the function.
+ typedef executor_op<function_type, Allocator> op;
+ typename op::ptr p = { detail::addressof(a), op::ptr::allocate(a), 0 };
+ p.p = new (p.v) op(ASIO_MOVE_CAST(Function)(function), a);
+
+ ASIO_HANDLER_CREATION((impl->service_->context(), *p.p,
+ "strand_executor", impl.get(), 0, "defer"));
+
+ // Add the function to the strand and schedule the strand if required.
+ bool first = enqueue(impl, p.p);
+ p.v = p.p = 0;
+ if (first)
+ ex.defer(invoker<Executor>(impl, ex), a);
+}
+
+} // namespace detail
+} // namespace asio
+
+#include "asio/detail/pop_options.hpp"
+
+#endif // ASIO_DETAIL_IMPL_STRAND_EXECUTOR_SERVICE_HPP
diff --git a/lib/asio/detail/impl/strand_executor_service.ipp b/lib/asio/detail/impl/strand_executor_service.ipp
new file mode 100644
index 0000000..365652e
--- /dev/null
+++ b/lib/asio/detail/impl/strand_executor_service.ipp
@@ -0,0 +1,134 @@
+//
+// detail/impl/strand_executor_service.ipp
+// ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+//
+// Copyright (c) 2003-2018 Christopher M. Kohlhoff (chris at kohlhoff dot com)
+//
+// 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 ASIO_DETAIL_IMPL_STRAND_EXECUTOR_SERVICE_IPP
+#define ASIO_DETAIL_IMPL_STRAND_EXECUTOR_SERVICE_IPP
+
+#if defined(_MSC_VER) && (_MSC_VER >= 1200)
+# pragma once
+#endif // defined(_MSC_VER) && (_MSC_VER >= 1200)
+
+#include "asio/detail/config.hpp"
+#include "asio/detail/strand_executor_service.hpp"
+
+#include "asio/detail/push_options.hpp"
+
+namespace asio {
+namespace detail {
+
+strand_executor_service::strand_executor_service(execution_context& ctx)
+ : execution_context_service_base<strand_executor_service>(ctx),
+ mutex_(),
+ salt_(0),
+ impl_list_(0)
+{
+}
+
+void strand_executor_service::shutdown()
+{
+ op_queue<scheduler_operation> ops;
+
+ asio::detail::mutex::scoped_lock lock(mutex_);
+
+ strand_impl* impl = impl_list_;
+ while (impl)
+ {
+ impl->mutex_->lock();
+ impl->shutdown_ = true;
+ ops.push(impl->waiting_queue_);
+ ops.push(impl->ready_queue_);
+ impl->mutex_->unlock();
+ impl = impl->next_;
+ }
+}
+
+strand_executor_service::implementation_type
+strand_executor_service::create_implementation()
+{
+ implementation_type new_impl(new strand_impl);
+ new_impl->locked_ = false;
+ new_impl->shutdown_ = false;
+
+ asio::detail::mutex::scoped_lock lock(mutex_);
+
+ // Select a mutex from the pool of shared mutexes.
+ std::size_t salt = salt_++;
+ std::size_t mutex_index = reinterpret_cast<std::size_t>(new_impl.get());
+ mutex_index += (reinterpret_cast<std::size_t>(new_impl.get()) >> 3);
+ mutex_index ^= salt + 0x9e3779b9 + (mutex_index << 6) + (mutex_index >> 2);
+ mutex_index = mutex_index % num_mutexes;
+ if (!mutexes_[mutex_index].get())
+ mutexes_[mutex_index].reset(new mutex);
+ new_impl->mutex_ = mutexes_[mutex_index].get();
+
+ // Insert implementation into linked list of all implementations.
+ new_impl->next_ = impl_list_;
+ new_impl->prev_ = 0;
+ if (impl_list_)
+ impl_list_->prev_ = new_impl.get();
+ impl_list_ = new_impl.get();
+ new_impl->service_ = this;
+
+ return new_impl;
+}
+
+strand_executor_service::strand_impl::~strand_impl()
+{
+ asio::detail::mutex::scoped_lock lock(service_->mutex_);
+
+ // Remove implementation from linked list of all implementations.
+ if (service_->impl_list_ == this)
+ service_->impl_list_ = next_;
+ if (prev_)
+ prev_->next_ = next_;
+ if (next_)
+ next_->prev_= prev_;
+}
+
+bool strand_executor_service::enqueue(const implementation_type& impl,
+ scheduler_operation* op)
+{
+ impl->mutex_->lock();
+ if (impl->shutdown_)
+ {
+ impl->mutex_->unlock();
+ op->destroy();
+ return false;
+ }
+ else if (impl->locked_)
+ {
+ // Some other function already holds the strand lock. Enqueue for later.
+ impl->waiting_queue_.push(op);
+ impl->mutex_->unlock();
+ return false;
+ }
+ else
+ {
+ // The function is acquiring the strand lock and so is responsible for
+ // scheduling the strand.
+ impl->locked_ = true;
+ impl->mutex_->unlock();
+ impl->ready_queue_.push(op);
+ return true;
+ }
+}
+
+bool strand_executor_service::running_in_this_thread(
+ const implementation_type& impl)
+{
+ return !!call_stack<strand_impl>::contains(impl.get());
+}
+
+} // namespace detail
+} // namespace asio
+
+#include "asio/detail/pop_options.hpp"
+
+#endif // ASIO_DETAIL_IMPL_STRAND_EXECUTOR_SERVICE_IPP
diff --git a/lib/asio/detail/impl/strand_service.hpp b/lib/asio/detail/impl/strand_service.hpp
new file mode 100644
index 0000000..da5b716
--- /dev/null
+++ b/lib/asio/detail/impl/strand_service.hpp
@@ -0,0 +1,118 @@
+//
+// detail/impl/strand_service.hpp
+// ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+//
+// Copyright (c) 2003-2018 Christopher M. Kohlhoff (chris at kohlhoff dot com)
+//
+// 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 ASIO_DETAIL_IMPL_STRAND_SERVICE_HPP
+#define ASIO_DETAIL_IMPL_STRAND_SERVICE_HPP
+
+#if defined(_MSC_VER) && (_MSC_VER >= 1200)
+# pragma once
+#endif // defined(_MSC_VER) && (_MSC_VER >= 1200)
+
+#include "asio/detail/call_stack.hpp"
+#include "asio/detail/completion_handler.hpp"
+#include "asio/detail/fenced_block.hpp"
+#include "asio/detail/handler_alloc_helpers.hpp"
+#include "asio/detail/handler_invoke_helpers.hpp"
+#include "asio/detail/memory.hpp"
+
+#include "asio/detail/push_options.hpp"
+
+namespace asio {
+namespace detail {
+
+inline strand_service::strand_impl::strand_impl()
+ : operation(&strand_service::do_complete),
+ locked_(false)
+{
+}
+
+struct strand_service::on_dispatch_exit
+{
+ io_context_impl* io_context_;
+ strand_impl* impl_;
+
+ ~on_dispatch_exit()
+ {
+ impl_->mutex_.lock();
+ impl_->ready_queue_.push(impl_->waiting_queue_);
+ bool more_handlers = impl_->locked_ = !impl_->ready_queue_.empty();
+ impl_->mutex_.unlock();
+
+ if (more_handlers)
+ io_context_->post_immediate_completion(impl_, false);
+ }
+};
+
+template <typename Handler>
+void strand_service::dispatch(strand_service::implementation_type& impl,
+ Handler& handler)
+{
+ // If we are already in the strand then the handler can run immediately.
+ if (call_stack<strand_impl>::contains(impl))
+ {
+ fenced_block b(fenced_block::full);
+ asio_handler_invoke_helpers::invoke(handler, handler);
+ return;
+ }
+
+ // Allocate and construct an operation to wrap the handler.
+ typedef completion_handler<Handler> op;
+ typename op::ptr p = { asio::detail::addressof(handler),
+ op::ptr::allocate(handler), 0 };
+ p.p = new (p.v) op(handler);
+
+ ASIO_HANDLER_CREATION((this->context(),
+ *p.p, "strand", impl, 0, "dispatch"));
+
+ bool dispatch_immediately = do_dispatch(impl, p.p);
+ operation* o = p.p;
+ p.v = p.p = 0;
+
+ if (dispatch_immediately)
+ {
+ // Indicate that this strand is executing on the current thread.
+ call_stack<strand_impl>::context ctx(impl);
+
+ // Ensure the next handler, if any, is scheduled on block exit.
+ on_dispatch_exit on_exit = { &io_context_, impl };
+ (void)on_exit;
+
+ completion_handler<Handler>::do_complete(
+ &io_context_, o, asio::error_code(), 0);
+ }
+}
+
+// Request the io_context to invoke the given handler and return immediately.
+template <typename Handler>
+void strand_service::post(strand_service::implementation_type& impl,
+ Handler& handler)
+{
+ bool is_continuation =
+ asio_handler_cont_helpers::is_continuation(handler);
+
+ // Allocate and construct an operation to wrap the handler.
+ typedef completion_handler<Handler> op;
+ typename op::ptr p = { asio::detail::addressof(handler),
+ op::ptr::allocate(handler), 0 };
+ p.p = new (p.v) op(handler);
+
+ ASIO_HANDLER_CREATION((this->context(),
+ *p.p, "strand", impl, 0, "post"));
+
+ do_post(impl, p.p, is_continuation);
+ p.v = p.p = 0;
+}
+
+} // namespace detail
+} // namespace asio
+
+#include "asio/detail/pop_options.hpp"
+
+#endif // ASIO_DETAIL_IMPL_STRAND_SERVICE_HPP
diff --git a/lib/asio/detail/impl/strand_service.ipp b/lib/asio/detail/impl/strand_service.ipp
new file mode 100644
index 0000000..cbaf25b
--- /dev/null
+++ b/lib/asio/detail/impl/strand_service.ipp
@@ -0,0 +1,177 @@
+//
+// detail/impl/strand_service.ipp
+// ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+//
+// Copyright (c) 2003-2018 Christopher M. Kohlhoff (chris at kohlhoff dot com)
+//
+// 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 ASIO_DETAIL_IMPL_STRAND_SERVICE_IPP
+#define ASIO_DETAIL_IMPL_STRAND_SERVICE_IPP
+
+#if defined(_MSC_VER) && (_MSC_VER >= 1200)
+# pragma once
+#endif // defined(_MSC_VER) && (_MSC_VER >= 1200)
+
+#include "asio/detail/config.hpp"
+#include "asio/detail/call_stack.hpp"
+#include "asio/detail/strand_service.hpp"
+
+#include "asio/detail/push_options.hpp"
+
+namespace asio {
+namespace detail {
+
+struct strand_service::on_do_complete_exit
+{
+ io_context_impl* owner_;
+ strand_impl* impl_;
+
+ ~on_do_complete_exit()
+ {
+ impl_->mutex_.lock();
+ impl_->ready_queue_.push(impl_->waiting_queue_);
+ bool more_handlers = impl_->locked_ = !impl_->ready_queue_.empty();
+ impl_->mutex_.unlock();
+
+ if (more_handlers)
+ owner_->post_immediate_completion(impl_, true);
+ }
+};
+
+strand_service::strand_service(asio::io_context& io_context)
+ : asio::detail::service_base<strand_service>(io_context),
+ io_context_(asio::use_service<io_context_impl>(io_context)),
+ mutex_(),
+ salt_(0)
+{
+}
+
+void strand_service::shutdown()
+{
+ op_queue<operation> ops;
+
+ asio::detail::mutex::scoped_lock lock(mutex_);
+
+ for (std::size_t i = 0; i < num_implementations; ++i)
+ {
+ if (strand_impl* impl = implementations_[i].get())
+ {
+ ops.push(impl->waiting_queue_);
+ ops.push(impl->ready_queue_);
+ }
+ }
+}
+
+void strand_service::construct(strand_service::implementation_type& impl)
+{
+ asio::detail::mutex::scoped_lock lock(mutex_);
+
+ std::size_t salt = salt_++;
+#if defined(ASIO_ENABLE_SEQUENTIAL_STRAND_ALLOCATION)
+ std::size_t index = salt;
+#else // defined(ASIO_ENABLE_SEQUENTIAL_STRAND_ALLOCATION)
+ std::size_t index = reinterpret_cast<std::size_t>(&impl);
+ index += (reinterpret_cast<std::size_t>(&impl) >> 3);
+ index ^= salt + 0x9e3779b9 + (index << 6) + (index >> 2);
+#endif // defined(ASIO_ENABLE_SEQUENTIAL_STRAND_ALLOCATION)
+ index = index % num_implementations;
+
+ if (!implementations_[index].get())
+ implementations_[index].reset(new strand_impl);
+ impl = implementations_[index].get();
+}
+
+bool strand_service::running_in_this_thread(
+ const implementation_type& impl) const
+{
+ return call_stack<strand_impl>::contains(impl) != 0;
+}
+
+bool strand_service::do_dispatch(implementation_type& impl, operation* op)
+{
+ // If we are running inside the io_context, and no other handler already
+ // holds the strand lock, then the handler can run immediately.
+ bool can_dispatch = io_context_.can_dispatch();
+ impl->mutex_.lock();
+ if (can_dispatch && !impl->locked_)
+ {
+ // Immediate invocation is allowed.
+ impl->locked_ = true;
+ impl->mutex_.unlock();
+ return true;
+ }
+
+ if (impl->locked_)
+ {
+ // Some other handler already holds the strand lock. Enqueue for later.
+ impl->waiting_queue_.push(op);
+ impl->mutex_.unlock();
+ }
+ else
+ {
+ // The handler is acquiring the strand lock and so is responsible for
+ // scheduling the strand.
+ impl->locked_ = true;
+ impl->mutex_.unlock();
+ impl->ready_queue_.push(op);
+ io_context_.post_immediate_completion(impl, false);
+ }
+
+ return false;
+}
+
+void strand_service::do_post(implementation_type& impl,
+ operation* op, bool is_continuation)
+{
+ impl->mutex_.lock();
+ if (impl->locked_)
+ {
+ // Some other handler already holds the strand lock. Enqueue for later.
+ impl->waiting_queue_.push(op);
+ impl->mutex_.unlock();
+ }
+ else
+ {
+ // The handler is acquiring the strand lock and so is responsible for
+ // scheduling the strand.
+ impl->locked_ = true;
+ impl->mutex_.unlock();
+ impl->ready_queue_.push(op);
+ io_context_.post_immediate_completion(impl, is_continuation);
+ }
+}
+
+void strand_service::do_complete(void* owner, operation* base,
+ const asio::error_code& ec, std::size_t /*bytes_transferred*/)
+{
+ if (owner)
+ {
+ strand_impl* impl = static_cast<strand_impl*>(base);
+
+ // Indicate that this strand is executing on the current thread.
+ call_stack<strand_impl>::context ctx(impl);
+
+ // Ensure the next handler, if any, is scheduled on block exit.
+ on_do_complete_exit on_exit;
+ on_exit.owner_ = static_cast<io_context_impl*>(owner);
+ on_exit.impl_ = impl;
+
+ // Run all ready handlers. No lock is required since the ready queue is
+ // accessed only within the strand.
+ while (operation* o = impl->ready_queue_.front())
+ {
+ impl->ready_queue_.pop();
+ o->complete(owner, ec, 0);
+ }
+ }
+}
+
+} // namespace detail
+} // namespace asio
+
+#include "asio/detail/pop_options.hpp"
+
+#endif // ASIO_DETAIL_IMPL_STRAND_SERVICE_IPP
diff --git a/lib/asio/detail/impl/throw_error.ipp b/lib/asio/detail/impl/throw_error.ipp
new file mode 100644
index 0000000..a540cd2
--- /dev/null
+++ b/lib/asio/detail/impl/throw_error.ipp
@@ -0,0 +1,60 @@
+//
+// detail/impl/throw_error.ipp
+// ~~~~~~~~~~~~~~~~~~~~~~~~~~~
+//
+// Copyright (c) 2003-2018 Christopher M. Kohlhoff (chris at kohlhoff dot com)
+//
+// 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 ASIO_DETAIL_IMPL_THROW_ERROR_IPP
+#define ASIO_DETAIL_IMPL_THROW_ERROR_IPP
+
+#if defined(_MSC_VER) && (_MSC_VER >= 1200)
+# pragma once
+#endif // defined(_MSC_VER) && (_MSC_VER >= 1200)
+
+#include "asio/detail/config.hpp"
+#include "asio/detail/throw_error.hpp"
+#include "asio/detail/throw_exception.hpp"
+#include "asio/system_error.hpp"
+
+#include "asio/detail/push_options.hpp"
+
+namespace asio {
+namespace detail {
+
+void do_throw_error(const asio::error_code& err)
+{
+ asio::system_error e(err);
+ asio::detail::throw_exception(e);
+}
+
+void do_throw_error(const asio::error_code& err, const char* location)
+{
+ // boostify: non-boost code starts here
+#if defined(ASIO_MSVC) && defined(ASIO_HAS_STD_SYSTEM_ERROR)
+ // Microsoft's implementation of std::system_error is non-conformant in that
+ // it ignores the error code's message when a "what" string is supplied. We'll
+ // work around this by explicitly formatting the "what" string.
+ std::string what_msg = location;
+ what_msg += ": ";
+ what_msg += err.message();
+ asio::system_error e(err, what_msg);
+ asio::detail::throw_exception(e);
+#else // defined(ASIO_MSVC) && defined(ASIO_HAS_STD_SYSTEM_ERROR)
+ // boostify: non-boost code ends here
+ asio::system_error e(err, location);
+ asio::detail::throw_exception(e);
+ // boostify: non-boost code starts here
+#endif // defined(ASIO_MSVC) && defined(ASIO_HAS_STD_SYSTEM_ERROR)
+ // boostify: non-boost code ends here
+}
+
+} // namespace detail
+} // namespace asio
+
+#include "asio/detail/pop_options.hpp"
+
+#endif // ASIO_DETAIL_IMPL_THROW_ERROR_IPP
diff --git a/lib/asio/detail/impl/timer_queue_ptime.ipp b/lib/asio/detail/impl/timer_queue_ptime.ipp
new file mode 100644
index 0000000..742837f
--- /dev/null
+++ b/lib/asio/detail/impl/timer_queue_ptime.ipp
@@ -0,0 +1,91 @@
+//
+// detail/impl/timer_queue_ptime.ipp
+// ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+//
+// Copyright (c) 2003-2018 Christopher M. Kohlhoff (chris at kohlhoff dot com)
+//
+// 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 ASIO_DETAIL_IMPL_TIMER_QUEUE_PTIME_IPP
+#define ASIO_DETAIL_IMPL_TIMER_QUEUE_PTIME_IPP
+
+#if defined(_MSC_VER) && (_MSC_VER >= 1200)
+# pragma once
+#endif // defined(_MSC_VER) && (_MSC_VER >= 1200)
+
+#include "asio/detail/config.hpp"
+
+#if defined(ASIO_HAS_BOOST_DATE_TIME)
+
+#include "asio/detail/timer_queue_ptime.hpp"
+
+#include "asio/detail/push_options.hpp"
+
+namespace asio {
+namespace detail {
+
+timer_queue<time_traits<boost::posix_time::ptime> >::timer_queue()
+{
+}
+
+timer_queue<time_traits<boost::posix_time::ptime> >::~timer_queue()
+{
+}
+
+bool timer_queue<time_traits<boost::posix_time::ptime> >::enqueue_timer(
+ const time_type& time, per_timer_data& timer, wait_op* op)
+{
+ return impl_.enqueue_timer(time, timer, op);
+}
+
+bool timer_queue<time_traits<boost::posix_time::ptime> >::empty() const
+{
+ return impl_.empty();
+}
+
+long timer_queue<time_traits<boost::posix_time::ptime> >::wait_duration_msec(
+ long max_duration) const
+{
+ return impl_.wait_duration_msec(max_duration);
+}
+
+long timer_queue<time_traits<boost::posix_time::ptime> >::wait_duration_usec(
+ long max_duration) const
+{
+ return impl_.wait_duration_usec(max_duration);
+}
+
+void timer_queue<time_traits<boost::posix_time::ptime> >::get_ready_timers(
+ op_queue<operation>& ops)
+{
+ impl_.get_ready_timers(ops);
+}
+
+void timer_queue<time_traits<boost::posix_time::ptime> >::get_all_timers(
+ op_queue<operation>& ops)
+{
+ impl_.get_all_timers(ops);
+}
+
+std::size_t timer_queue<time_traits<boost::posix_time::ptime> >::cancel_timer(
+ per_timer_data& timer, op_queue<operation>& ops, std::size_t max_cancelled)
+{
+ return impl_.cancel_timer(timer, ops, max_cancelled);
+}
+
+void timer_queue<time_traits<boost::posix_time::ptime> >::move_timer(
+ per_timer_data& target, per_timer_data& source)
+{
+ impl_.move_timer(target, source);
+}
+
+} // namespace detail
+} // namespace asio
+
+#include "asio/detail/pop_options.hpp"
+
+#endif // defined(ASIO_HAS_BOOST_DATE_TIME)
+
+#endif // ASIO_DETAIL_IMPL_TIMER_QUEUE_PTIME_IPP
diff --git a/lib/asio/detail/impl/timer_queue_set.ipp b/lib/asio/detail/impl/timer_queue_set.ipp
new file mode 100644
index 0000000..b516548
--- /dev/null
+++ b/lib/asio/detail/impl/timer_queue_set.ipp
@@ -0,0 +1,101 @@
+//
+// detail/impl/timer_queue_set.ipp
+// ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+//
+// Copyright (c) 2003-2018 Christopher M. Kohlhoff (chris at kohlhoff dot com)
+//
+// 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 ASIO_DETAIL_IMPL_TIMER_QUEUE_SET_IPP
+#define ASIO_DETAIL_IMPL_TIMER_QUEUE_SET_IPP
+
+#if defined(_MSC_VER) && (_MSC_VER >= 1200)
+# pragma once
+#endif // defined(_MSC_VER) && (_MSC_VER >= 1200)
+
+#include "asio/detail/config.hpp"
+#include "asio/detail/timer_queue_set.hpp"
+
+#include "asio/detail/push_options.hpp"
+
+namespace asio {
+namespace detail {
+
+timer_queue_set::timer_queue_set()
+ : first_(0)
+{
+}
+
+void timer_queue_set::insert(timer_queue_base* q)
+{
+ q->next_ = first_;
+ first_ = q;
+}
+
+void timer_queue_set::erase(timer_queue_base* q)
+{
+ if (first_)
+ {
+ if (q == first_)
+ {
+ first_ = q->next_;
+ q->next_ = 0;
+ return;
+ }
+
+ for (timer_queue_base* p = first_; p->next_; p = p->next_)
+ {
+ if (p->next_ == q)
+ {
+ p->next_ = q->next_;
+ q->next_ = 0;
+ return;
+ }
+ }
+ }
+}
+
+bool timer_queue_set::all_empty() const
+{
+ for (timer_queue_base* p = first_; p; p = p->next_)
+ if (!p->empty())
+ return false;
+ return true;
+}
+
+long timer_queue_set::wait_duration_msec(long max_duration) const
+{
+ long min_duration = max_duration;
+ for (timer_queue_base* p = first_; p; p = p->next_)
+ min_duration = p->wait_duration_msec(min_duration);
+ return min_duration;
+}
+
+long timer_queue_set::wait_duration_usec(long max_duration) const
+{
+ long min_duration = max_duration;
+ for (timer_queue_base* p = first_; p; p = p->next_)
+ min_duration = p->wait_duration_usec(min_duration);
+ return min_duration;
+}
+
+void timer_queue_set::get_ready_timers(op_queue<operation>& ops)
+{
+ for (timer_queue_base* p = first_; p; p = p->next_)
+ p->get_ready_timers(ops);
+}
+
+void timer_queue_set::get_all_timers(op_queue<operation>& ops)
+{
+ for (timer_queue_base* p = first_; p; p = p->next_)
+ p->get_all_timers(ops);
+}
+
+} // namespace detail
+} // namespace asio
+
+#include "asio/detail/pop_options.hpp"
+
+#endif // ASIO_DETAIL_IMPL_TIMER_QUEUE_SET_IPP
diff --git a/lib/asio/detail/impl/win_event.ipp b/lib/asio/detail/impl/win_event.ipp
new file mode 100644
index 0000000..6f74649
--- /dev/null
+++ b/lib/asio/detail/impl/win_event.ipp
@@ -0,0 +1,76 @@
+//
+// detail/win_event.ipp
+// ~~~~~~~~~~~~~~~~~~~~
+//
+// Copyright (c) 2003-2018 Christopher M. Kohlhoff (chris at kohlhoff dot com)
+//
+// 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 ASIO_DETAIL_IMPL_WIN_EVENT_IPP
+#define ASIO_DETAIL_IMPL_WIN_EVENT_IPP
+
+#if defined(_MSC_VER) && (_MSC_VER >= 1200)
+# pragma once
+#endif // defined(_MSC_VER) && (_MSC_VER >= 1200)
+
+#include "asio/detail/config.hpp"
+
+#if defined(ASIO_WINDOWS)
+
+#include "asio/detail/throw_error.hpp"
+#include "asio/detail/win_event.hpp"
+#include "asio/error.hpp"
+
+#include "asio/detail/push_options.hpp"
+
+namespace asio {
+namespace detail {
+
+win_event::win_event()
+ : state_(0)
+{
+#if defined(ASIO_WINDOWS_APP)
+ events_[0] = ::CreateEventExW(0, 0,
+ CREATE_EVENT_MANUAL_RESET, EVENT_ALL_ACCESS);
+#else // defined(ASIO_WINDOWS_APP)
+ events_[0] = ::CreateEventW(0, true, false, 0);
+#endif // defined(ASIO_WINDOWS_APP)
+ if (!events_[0])
+ {
+ DWORD last_error = ::GetLastError();
+ asio::error_code ec(last_error,
+ asio::error::get_system_category());
+ asio::detail::throw_error(ec, "event");
+ }
+
+#if defined(ASIO_WINDOWS_APP)
+ events_[1] = ::CreateEventExW(0, 0, 0, EVENT_ALL_ACCESS);
+#else // defined(ASIO_WINDOWS_APP)
+ events_[1] = ::CreateEventW(0, false, false, 0);
+#endif // defined(ASIO_WINDOWS_APP)
+ if (!events_[1])
+ {
+ DWORD last_error = ::GetLastError();
+ ::CloseHandle(events_[0]);
+ asio::error_code ec(last_error,
+ asio::error::get_system_category());
+ asio::detail::throw_error(ec, "event");
+ }
+}
+
+win_event::~win_event()
+{
+ ::CloseHandle(events_[0]);
+ ::CloseHandle(events_[1]);
+}
+
+} // namespace detail
+} // namespace asio
+
+#include "asio/detail/pop_options.hpp"
+
+#endif // defined(ASIO_WINDOWS)
+
+#endif // ASIO_DETAIL_IMPL_WIN_EVENT_IPP
diff --git a/lib/asio/detail/impl/win_iocp_handle_service.ipp b/lib/asio/detail/impl/win_iocp_handle_service.ipp
new file mode 100644
index 0000000..9cba2b0
--- /dev/null
+++ b/lib/asio/detail/impl/win_iocp_handle_service.ipp
@@ -0,0 +1,525 @@
+//
+// detail/impl/win_iocp_handle_service.ipp
+// ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+//
+// Copyright (c) 2003-2018 Christopher M. Kohlhoff (chris at kohlhoff dot com)
+// Copyright (c) 2008 Rep Invariant Systems, Inc. (info@repinvariant.com)
+//
+// 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 ASIO_DETAIL_IMPL_WIN_IOCP_HANDLE_SERVICE_IPP
+#define ASIO_DETAIL_IMPL_WIN_IOCP_HANDLE_SERVICE_IPP
+
+#if defined(_MSC_VER) && (_MSC_VER >= 1200)
+# pragma once
+#endif // defined(_MSC_VER) && (_MSC_VER >= 1200)
+
+#include "asio/detail/config.hpp"
+
+#if defined(ASIO_HAS_IOCP)
+
+#include "asio/detail/win_iocp_handle_service.hpp"
+
+#include "asio/detail/push_options.hpp"
+
+namespace asio {
+namespace detail {
+
+class win_iocp_handle_service::overlapped_wrapper
+ : public OVERLAPPED
+{
+public:
+ explicit overlapped_wrapper(asio::error_code& ec)
+ {
+ Internal = 0;
+ InternalHigh = 0;
+ Offset = 0;
+ OffsetHigh = 0;
+
+ // Create a non-signalled manual-reset event, for GetOverlappedResult.
+ hEvent = ::CreateEventW(0, TRUE, FALSE, 0);
+ if (hEvent)
+ {
+ // As documented in GetQueuedCompletionStatus, setting the low order
+ // bit of this event prevents our synchronous writes from being treated
+ // as completion port events.
+ DWORD_PTR tmp = reinterpret_cast<DWORD_PTR>(hEvent);
+ hEvent = reinterpret_cast<HANDLE>(tmp | 1);
+ }
+ else
+ {
+ DWORD last_error = ::GetLastError();
+ ec = asio::error_code(last_error,
+ asio::error::get_system_category());
+ }
+ }
+
+ ~overlapped_wrapper()
+ {
+ if (hEvent)
+ {
+ ::CloseHandle(hEvent);
+ }
+ }
+};
+
+win_iocp_handle_service::win_iocp_handle_service(
+ asio::io_context& io_context)
+ : service_base<win_iocp_handle_service>(io_context),
+ iocp_service_(asio::use_service<win_iocp_io_context>(io_context)),
+ mutex_(),
+ impl_list_(0)
+{
+}
+
+void win_iocp_handle_service::shutdown()
+{
+ // Close all implementations, causing all operations to complete.
+ asio::detail::mutex::scoped_lock lock(mutex_);
+ implementation_type* impl = impl_list_;
+ while (impl)
+ {
+ close_for_destruction(*impl);
+ impl = impl->next_;
+ }
+}
+
+void win_iocp_handle_service::construct(
+ win_iocp_handle_service::implementation_type& impl)
+{
+ impl.handle_ = INVALID_HANDLE_VALUE;
+ impl.safe_cancellation_thread_id_ = 0;
+
+ // Insert implementation into linked list of all implementations.
+ asio::detail::mutex::scoped_lock lock(mutex_);
+ impl.next_ = impl_list_;
+ impl.prev_ = 0;
+ if (impl_list_)
+ impl_list_->prev_ = &impl;
+ impl_list_ = &impl;
+}
+
+void win_iocp_handle_service::move_construct(
+ win_iocp_handle_service::implementation_type& impl,
+ win_iocp_handle_service::implementation_type& other_impl)
+{
+ impl.handle_ = other_impl.handle_;
+ other_impl.handle_ = INVALID_HANDLE_VALUE;
+
+ impl.safe_cancellation_thread_id_ = other_impl.safe_cancellation_thread_id_;
+ other_impl.safe_cancellation_thread_id_ = 0;
+
+ // Insert implementation into linked list of all implementations.
+ asio::detail::mutex::scoped_lock lock(mutex_);
+ impl.next_ = impl_list_;
+ impl.prev_ = 0;
+ if (impl_list_)
+ impl_list_->prev_ = &impl;
+ impl_list_ = &impl;
+}
+
+void win_iocp_handle_service::move_assign(
+ win_iocp_handle_service::implementation_type& impl,
+ win_iocp_handle_service& other_service,
+ win_iocp_handle_service::implementation_type& other_impl)
+{
+ close_for_destruction(impl);
+
+ if (this != &other_service)
+ {
+ // Remove implementation from linked list of all implementations.
+ asio::detail::mutex::scoped_lock lock(mutex_);
+ if (impl_list_ == &impl)
+ impl_list_ = impl.next_;
+ if (impl.prev_)
+ impl.prev_->next_ = impl.next_;
+ if (impl.next_)
+ impl.next_->prev_= impl.prev_;
+ impl.next_ = 0;
+ impl.prev_ = 0;
+ }
+
+ impl.handle_ = other_impl.handle_;
+ other_impl.handle_ = INVALID_HANDLE_VALUE;
+
+ impl.safe_cancellation_thread_id_ = other_impl.safe_cancellation_thread_id_;
+ other_impl.safe_cancellation_thread_id_ = 0;
+
+ if (this != &other_service)
+ {
+ // Insert implementation into linked list of all implementations.
+ asio::detail::mutex::scoped_lock lock(other_service.mutex_);
+ impl.next_ = other_service.impl_list_;
+ impl.prev_ = 0;
+ if (other_service.impl_list_)
+ other_service.impl_list_->prev_ = &impl;
+ other_service.impl_list_ = &impl;
+ }
+}
+
+void win_iocp_handle_service::destroy(
+ win_iocp_handle_service::implementation_type& impl)
+{
+ close_for_destruction(impl);
+
+ // Remove implementation from linked list of all implementations.
+ asio::detail::mutex::scoped_lock lock(mutex_);
+ if (impl_list_ == &impl)
+ impl_list_ = impl.next_;
+ if (impl.prev_)
+ impl.prev_->next_ = impl.next_;
+ if (impl.next_)
+ impl.next_->prev_= impl.prev_;
+ impl.next_ = 0;
+ impl.prev_ = 0;
+}
+
+asio::error_code win_iocp_handle_service::assign(
+ win_iocp_handle_service::implementation_type& impl,
+ const native_handle_type& handle, asio::error_code& ec)
+{
+ if (is_open(impl))
+ {
+ ec = asio::error::already_open;
+ return ec;
+ }
+
+ if (iocp_service_.register_handle(handle, ec))
+ return ec;
+
+ impl.handle_ = handle;
+ ec = asio::error_code();
+ return ec;
+}
+
+asio::error_code win_iocp_handle_service::close(
+ win_iocp_handle_service::implementation_type& impl,
+ asio::error_code& ec)
+{
+ if (is_open(impl))
+ {
+ ASIO_HANDLER_OPERATION((iocp_service_.context(), "handle",
+ &impl, reinterpret_cast<uintmax_t>(impl.handle_), "close"));
+
+ if (!::CloseHandle(impl.handle_))
+ {
+ DWORD last_error = ::GetLastError();
+ ec = asio::error_code(last_error,
+ asio::error::get_system_category());
+ }
+ else
+ {
+ ec = asio::error_code();
+ }
+
+ impl.handle_ = INVALID_HANDLE_VALUE;
+ impl.safe_cancellation_thread_id_ = 0;
+ }
+ else
+ {
+ ec = asio::error_code();
+ }
+
+ return ec;
+}
+
+asio::error_code win_iocp_handle_service::cancel(
+ win_iocp_handle_service::implementation_type& impl,
+ asio::error_code& ec)
+{
+ if (!is_open(impl))
+ {
+ ec = asio::error::bad_descriptor;
+ return ec;
+ }
+
+ ASIO_HANDLER_OPERATION((iocp_service_.context(), "handle",
+ &impl, reinterpret_cast<uintmax_t>(impl.handle_), "cancel"));
+
+ if (FARPROC cancel_io_ex_ptr = ::GetProcAddress(
+ ::GetModuleHandleA("KERNEL32"), "CancelIoEx"))
+ {
+ // The version of Windows supports cancellation from any thread.
+ typedef BOOL (WINAPI* cancel_io_ex_t)(HANDLE, LPOVERLAPPED);
+ cancel_io_ex_t cancel_io_ex = (cancel_io_ex_t)cancel_io_ex_ptr;
+ if (!cancel_io_ex(impl.handle_, 0))
+ {
+ DWORD last_error = ::GetLastError();
+ if (last_error == ERROR_NOT_FOUND)
+ {
+ // ERROR_NOT_FOUND means that there were no operations to be
+ // cancelled. We swallow this error to match the behaviour on other
+ // platforms.
+ ec = asio::error_code();
+ }
+ else
+ {
+ ec = asio::error_code(last_error,
+ asio::error::get_system_category());
+ }
+ }
+ else
+ {
+ ec = asio::error_code();
+ }
+ }
+ else if (impl.safe_cancellation_thread_id_ == 0)
+ {
+ // No operations have been started, so there's nothing to cancel.
+ ec = asio::error_code();
+ }
+ else if (impl.safe_cancellation_thread_id_ == ::GetCurrentThreadId())
+ {
+ // Asynchronous operations have been started from the current thread only,
+ // so it is safe to try to cancel them using CancelIo.
+ if (!::CancelIo(impl.handle_))
+ {
+ DWORD last_error = ::GetLastError();
+ ec = asio::error_code(last_error,
+ asio::error::get_system_category());
+ }
+ else
+ {
+ ec = asio::error_code();
+ }
+ }
+ else
+ {
+ // Asynchronous operations have been started from more than one thread,
+ // so cancellation is not safe.
+ ec = asio::error::operation_not_supported;
+ }
+
+ return ec;
+}
+
+size_t win_iocp_handle_service::do_write(
+ win_iocp_handle_service::implementation_type& impl, uint64_t offset,
+ const asio::const_buffer& buffer, asio::error_code& ec)
+{
+ if (!is_open(impl))
+ {
+ ec = asio::error::bad_descriptor;
+ return 0;
+ }
+
+ // A request to write 0 bytes on a handle is a no-op.
+ if (buffer.size() == 0)
+ {
+ ec = asio::error_code();
+ return 0;
+ }
+
+ overlapped_wrapper overlapped(ec);
+ if (ec)
+ {
+ return 0;
+ }
+
+ // Write the data.
+ overlapped.Offset = offset & 0xFFFFFFFF;
+ overlapped.OffsetHigh = (offset >> 32) & 0xFFFFFFFF;
+ BOOL ok = ::WriteFile(impl.handle_, buffer.data(),
+ static_cast<DWORD>(buffer.size()), 0, &overlapped);
+ if (!ok)
+ {
+ DWORD last_error = ::GetLastError();
+ if (last_error != ERROR_IO_PENDING)
+ {
+ ec = asio::error_code(last_error,
+ asio::error::get_system_category());
+ return 0;
+ }
+ }
+
+ // Wait for the operation to complete.
+ DWORD bytes_transferred = 0;
+ ok = ::GetOverlappedResult(impl.handle_,
+ &overlapped, &bytes_transferred, TRUE);
+ if (!ok)
+ {
+ DWORD last_error = ::GetLastError();
+ ec = asio::error_code(last_error,
+ asio::error::get_system_category());
+ return 0;
+ }
+
+ ec = asio::error_code();
+ return bytes_transferred;
+}
+
+void win_iocp_handle_service::start_write_op(
+ win_iocp_handle_service::implementation_type& impl, uint64_t offset,
+ const asio::const_buffer& buffer, operation* op)
+{
+ update_cancellation_thread_id(impl);
+ iocp_service_.work_started();
+
+ if (!is_open(impl))
+ {
+ iocp_service_.on_completion(op, asio::error::bad_descriptor);
+ }
+ else if (buffer.size() == 0)
+ {
+ // A request to write 0 bytes on a handle is a no-op.
+ iocp_service_.on_completion(op);
+ }
+ else
+ {
+ DWORD bytes_transferred = 0;
+ op->Offset = offset & 0xFFFFFFFF;
+ op->OffsetHigh = (offset >> 32) & 0xFFFFFFFF;
+ BOOL ok = ::WriteFile(impl.handle_, buffer.data(),
+ static_cast<DWORD>(buffer.size()),
+ &bytes_transferred, op);
+ DWORD last_error = ::GetLastError();
+ if (!ok && last_error != ERROR_IO_PENDING
+ && last_error != ERROR_MORE_DATA)
+ {
+ iocp_service_.on_completion(op, last_error, bytes_transferred);
+ }
+ else
+ {
+ iocp_service_.on_pending(op);
+ }
+ }
+}
+
+size_t win_iocp_handle_service::do_read(
+ win_iocp_handle_service::implementation_type& impl, uint64_t offset,
+ const asio::mutable_buffer& buffer, asio::error_code& ec)
+{
+ if (!is_open(impl))
+ {
+ ec = asio::error::bad_descriptor;
+ return 0;
+ }
+
+ // A request to read 0 bytes on a stream handle is a no-op.
+ if (buffer.size() == 0)
+ {
+ ec = asio::error_code();
+ return 0;
+ }
+
+ overlapped_wrapper overlapped(ec);
+ if (ec)
+ {
+ return 0;
+ }
+
+ // Read some data.
+ overlapped.Offset = offset & 0xFFFFFFFF;
+ overlapped.OffsetHigh = (offset >> 32) & 0xFFFFFFFF;
+ BOOL ok = ::ReadFile(impl.handle_, buffer.data(),
+ static_cast<DWORD>(buffer.size()), 0, &overlapped);
+ if (!ok)
+ {
+ DWORD last_error = ::GetLastError();
+ if (last_error != ERROR_IO_PENDING && last_error != ERROR_MORE_DATA)
+ {
+ if (last_error == ERROR_HANDLE_EOF)
+ {
+ ec = asio::error::eof;
+ }
+ else
+ {
+ ec = asio::error_code(last_error,
+ asio::error::get_system_category());
+ }
+ return 0;
+ }
+ }
+
+ // Wait for the operation to complete.
+ DWORD bytes_transferred = 0;
+ ok = ::GetOverlappedResult(impl.handle_,
+ &overlapped, &bytes_transferred, TRUE);
+ if (!ok)
+ {
+ DWORD last_error = ::GetLastError();
+ if (last_error == ERROR_HANDLE_EOF)
+ {
+ ec = asio::error::eof;
+ }
+ else
+ {
+ ec = asio::error_code(last_error,
+ asio::error::get_system_category());
+ }
+ return (last_error == ERROR_MORE_DATA) ? bytes_transferred : 0;
+ }
+
+ ec = asio::error_code();
+ return bytes_transferred;
+}
+
+void win_iocp_handle_service::start_read_op(
+ win_iocp_handle_service::implementation_type& impl, uint64_t offset,
+ const asio::mutable_buffer& buffer, operation* op)
+{
+ update_cancellation_thread_id(impl);
+ iocp_service_.work_started();
+
+ if (!is_open(impl))
+ {
+ iocp_service_.on_completion(op, asio::error::bad_descriptor);
+ }
+ else if (buffer.size() == 0)
+ {
+ // A request to read 0 bytes on a handle is a no-op.
+ iocp_service_.on_completion(op);
+ }
+ else
+ {
+ DWORD bytes_transferred = 0;
+ op->Offset = offset & 0xFFFFFFFF;
+ op->OffsetHigh = (offset >> 32) & 0xFFFFFFFF;
+ BOOL ok = ::ReadFile(impl.handle_, buffer.data(),
+ static_cast<DWORD>(buffer.size()),
+ &bytes_transferred, op);
+ DWORD last_error = ::GetLastError();
+ if (!ok && last_error != ERROR_IO_PENDING
+ && last_error != ERROR_MORE_DATA)
+ {
+ iocp_service_.on_completion(op, last_error, bytes_transferred);
+ }
+ else
+ {
+ iocp_service_.on_pending(op);
+ }
+ }
+}
+
+void win_iocp_handle_service::update_cancellation_thread_id(
+ win_iocp_handle_service::implementation_type& impl)
+{
+ if (impl.safe_cancellation_thread_id_ == 0)
+ impl.safe_cancellation_thread_id_ = ::GetCurrentThreadId();
+ else if (impl.safe_cancellation_thread_id_ != ::GetCurrentThreadId())
+ impl.safe_cancellation_thread_id_ = ~DWORD(0);
+}
+
+void win_iocp_handle_service::close_for_destruction(implementation_type& impl)
+{
+ if (is_open(impl))
+ {
+ ASIO_HANDLER_OPERATION((iocp_service_.context(), "handle",
+ &impl, reinterpret_cast<uintmax_t>(impl.handle_), "close"));
+
+ ::CloseHandle(impl.handle_);
+ impl.handle_ = INVALID_HANDLE_VALUE;
+ impl.safe_cancellation_thread_id_ = 0;
+ }
+}
+
+} // namespace detail
+} // namespace asio
+
+#include "asio/detail/pop_options.hpp"
+
+#endif // defined(ASIO_HAS_IOCP)
+
+#endif // ASIO_DETAIL_IMPL_WIN_IOCP_HANDLE_SERVICE_IPP
diff --git a/lib/asio/detail/impl/win_iocp_io_context.hpp b/lib/asio/detail/impl/win_iocp_io_context.hpp
new file mode 100644
index 0000000..44887d7
--- /dev/null
+++ b/lib/asio/detail/impl/win_iocp_io_context.hpp
@@ -0,0 +1,103 @@
+//
+// detail/impl/win_iocp_io_context.hpp
+// ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+//
+// Copyright (c) 2003-2018 Christopher M. Kohlhoff (chris at kohlhoff dot com)
+//
+// 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 ASIO_DETAIL_IMPL_WIN_IOCP_IO_CONTEXT_HPP
+#define ASIO_DETAIL_IMPL_WIN_IOCP_IO_CONTEXT_HPP
+
+#if defined(_MSC_VER) && (_MSC_VER >= 1200)
+# pragma once
+#endif // defined(_MSC_VER) && (_MSC_VER >= 1200)
+
+#include "asio/detail/config.hpp"
+
+#if defined(ASIO_HAS_IOCP)
+
+#include "asio/detail/completion_handler.hpp"
+#include "asio/detail/fenced_block.hpp"
+#include "asio/detail/handler_alloc_helpers.hpp"
+#include "asio/detail/handler_invoke_helpers.hpp"
+#include "asio/detail/memory.hpp"
+
+#include "asio/detail/push_options.hpp"
+
+namespace asio {
+namespace detail {
+
+template <typename Time_Traits>
+void win_iocp_io_context::add_timer_queue(
+ timer_queue<Time_Traits>& queue)
+{
+ do_add_timer_queue(queue);
+}
+
+template <typename Time_Traits>
+void win_iocp_io_context::remove_timer_queue(
+ timer_queue<Time_Traits>& queue)
+{
+ do_remove_timer_queue(queue);
+}
+
+template <typename Time_Traits>
+void win_iocp_io_context::schedule_timer(timer_queue<Time_Traits>& queue,
+ const typename Time_Traits::time_type& time,
+ typename timer_queue<Time_Traits>::per_timer_data& timer, wait_op* op)
+{
+ // If the service has been shut down we silently discard the timer.
+ if (::InterlockedExchangeAdd(&shutdown_, 0) != 0)
+ {
+ post_immediate_completion(op, false);
+ return;
+ }
+
+ mutex::scoped_lock lock(dispatch_mutex_);
+
+ bool earliest = queue.enqueue_timer(time, timer, op);
+ work_started();
+ if (earliest)
+ update_timeout();
+}
+
+template <typename Time_Traits>
+std::size_t win_iocp_io_context::cancel_timer(timer_queue<Time_Traits>& queue,
+ typename timer_queue<Time_Traits>::per_timer_data& timer,
+ std::size_t max_cancelled)
+{
+ // If the service has been shut down we silently ignore the cancellation.
+ if (::InterlockedExchangeAdd(&shutdown_, 0) != 0)
+ return 0;
+
+ mutex::scoped_lock lock(dispatch_mutex_);
+ op_queue<win_iocp_operation> ops;
+ std::size_t n = queue.cancel_timer(timer, ops, max_cancelled);
+ post_deferred_completions(ops);
+ return n;
+}
+
+template <typename Time_Traits>
+void win_iocp_io_context::move_timer(timer_queue<Time_Traits>& queue,
+ typename timer_queue<Time_Traits>::per_timer_data& to,
+ typename timer_queue<Time_Traits>::per_timer_data& from)
+{
+ asio::detail::mutex::scoped_lock lock(dispatch_mutex_);
+ op_queue<operation> ops;
+ queue.cancel_timer(to, ops);
+ queue.move_timer(to, from);
+ lock.unlock();
+ post_deferred_completions(ops);
+}
+
+} // namespace detail
+} // namespace asio
+
+#include "asio/detail/pop_options.hpp"
+
+#endif // defined(ASIO_HAS_IOCP)
+
+#endif // ASIO_DETAIL_IMPL_WIN_IOCP_IO_CONTEXT_HPP
diff --git a/lib/asio/detail/impl/win_iocp_io_context.ipp b/lib/asio/detail/impl/win_iocp_io_context.ipp
new file mode 100644
index 0000000..c371b86
--- /dev/null
+++ b/lib/asio/detail/impl/win_iocp_io_context.ipp
@@ -0,0 +1,554 @@
+//
+// detail/impl/win_iocp_io_context.ipp
+// ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+//
+// Copyright (c) 2003-2018 Christopher M. Kohlhoff (chris at kohlhoff dot com)
+//
+// 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 ASIO_DETAIL_IMPL_WIN_IOCP_IO_CONTEXT_IPP
+#define ASIO_DETAIL_IMPL_WIN_IOCP_IO_CONTEXT_IPP
+
+#if defined(_MSC_VER) && (_MSC_VER >= 1200)
+# pragma once
+#endif // defined(_MSC_VER) && (_MSC_VER >= 1200)
+
+#include "asio/detail/config.hpp"
+
+#if defined(ASIO_HAS_IOCP)
+
+#include "asio/error.hpp"
+#include "asio/detail/cstdint.hpp"
+#include "asio/detail/handler_alloc_helpers.hpp"
+#include "asio/detail/handler_invoke_helpers.hpp"
+#include "asio/detail/limits.hpp"
+#include "asio/detail/throw_error.hpp"
+#include "asio/detail/win_iocp_io_context.hpp"
+
+#include "asio/detail/push_options.hpp"
+
+namespace asio {
+namespace detail {
+
+struct win_iocp_io_context::work_finished_on_block_exit
+{
+ ~work_finished_on_block_exit()
+ {
+ io_context_->work_finished();
+ }
+
+ win_iocp_io_context* io_context_;
+};
+
+struct win_iocp_io_context::timer_thread_function
+{
+ void operator()()
+ {
+ while (::InterlockedExchangeAdd(&io_context_->shutdown_, 0) == 0)
+ {
+ if (::WaitForSingleObject(io_context_->waitable_timer_.handle,
+ INFINITE) == WAIT_OBJECT_0)
+ {
+ ::InterlockedExchange(&io_context_->dispatch_required_, 1);
+ ::PostQueuedCompletionStatus(io_context_->iocp_.handle,
+ 0, wake_for_dispatch, 0);
+ }
+ }
+ }
+
+ win_iocp_io_context* io_context_;
+};
+
+win_iocp_io_context::win_iocp_io_context(
+ asio::execution_context& ctx, int concurrency_hint)
+ : execution_context_service_base<win_iocp_io_context>(ctx),
+ iocp_(),
+ outstanding_work_(0),
+ stopped_(0),
+ stop_event_posted_(0),
+ shutdown_(0),
+ gqcs_timeout_(get_gqcs_timeout()),
+ dispatch_required_(0),
+ concurrency_hint_(concurrency_hint)
+{
+ ASIO_HANDLER_TRACKING_INIT;
+
+ iocp_.handle = ::CreateIoCompletionPort(INVALID_HANDLE_VALUE, 0, 0,
+ static_cast<DWORD>(concurrency_hint >= 0 ? concurrency_hint : DWORD(~0)));
+ if (!iocp_.handle)
+ {
+ DWORD last_error = ::GetLastError();
+ asio::error_code ec(last_error,
+ asio::error::get_system_category());
+ asio::detail::throw_error(ec, "iocp");
+ }
+}
+
+void win_iocp_io_context::shutdown()
+{
+ ::InterlockedExchange(&shutdown_, 1);
+
+ if (timer_thread_.get())
+ {
+ LARGE_INTEGER timeout;
+ timeout.QuadPart = 1;
+ ::SetWaitableTimer(waitable_timer_.handle, &timeout, 1, 0, 0, FALSE);
+ }
+
+ while (::InterlockedExchangeAdd(&outstanding_work_, 0) > 0)
+ {
+ op_queue<win_iocp_operation> ops;
+ timer_queues_.get_all_timers(ops);
+ ops.push(completed_ops_);
+ if (!ops.empty())
+ {
+ while (win_iocp_operation* op = ops.front())
+ {
+ ops.pop();
+ ::InterlockedDecrement(&outstanding_work_);
+ op->destroy();
+ }
+ }
+ else
+ {
+ DWORD bytes_transferred = 0;
+ dword_ptr_t completion_key = 0;
+ LPOVERLAPPED overlapped = 0;
+ ::GetQueuedCompletionStatus(iocp_.handle, &bytes_transferred,
+ &completion_key, &overlapped, gqcs_timeout_);
+ if (overlapped)
+ {
+ ::InterlockedDecrement(&outstanding_work_);
+ static_cast<win_iocp_operation*>(overlapped)->destroy();
+ }
+ }
+ }
+
+ if (timer_thread_.get())
+ timer_thread_->join();
+}
+
+asio::error_code win_iocp_io_context::register_handle(
+ HANDLE handle, asio::error_code& ec)
+{
+ if (::CreateIoCompletionPort(handle, iocp_.handle, 0, 0) == 0)
+ {
+ DWORD last_error = ::GetLastError();
+ ec = asio::error_code(last_error,
+ asio::error::get_system_category());
+ }
+ else
+ {
+ ec = asio::error_code();
+ }
+ return ec;
+}
+
+size_t win_iocp_io_context::run(asio::error_code& ec)
+{
+ if (::InterlockedExchangeAdd(&outstanding_work_, 0) == 0)
+ {
+ stop();
+ ec = asio::error_code();
+ return 0;
+ }
+
+ win_iocp_thread_info this_thread;
+ thread_call_stack::context ctx(this, this_thread);
+
+ size_t n = 0;
+ while (do_one(INFINITE, ec))
+ if (n != (std::numeric_limits<size_t>::max)())
+ ++n;
+ return n;
+}
+
+size_t win_iocp_io_context::run_one(asio::error_code& ec)
+{
+ if (::InterlockedExchangeAdd(&outstanding_work_, 0) == 0)
+ {
+ stop();
+ ec = asio::error_code();
+ return 0;
+ }
+
+ win_iocp_thread_info this_thread;
+ thread_call_stack::context ctx(this, this_thread);
+
+ return do_one(INFINITE, ec);
+}
+
+size_t win_iocp_io_context::wait_one(long usec, asio::error_code& ec)
+{
+ if (::InterlockedExchangeAdd(&outstanding_work_, 0) == 0)
+ {
+ stop();
+ ec = asio::error_code();
+ return 0;
+ }
+
+ win_iocp_thread_info this_thread;
+ thread_call_stack::context ctx(this, this_thread);
+
+ return do_one(usec < 0 ? INFINITE : ((usec - 1) / 1000 + 1), ec);
+}
+
+size_t win_iocp_io_context::poll(asio::error_code& ec)
+{
+ if (::InterlockedExchangeAdd(&outstanding_work_, 0) == 0)
+ {
+ stop();
+ ec = asio::error_code();
+ return 0;
+ }
+
+ win_iocp_thread_info this_thread;
+ thread_call_stack::context ctx(this, this_thread);
+
+ size_t n = 0;
+ while (do_one(0, ec))
+ if (n != (std::numeric_limits<size_t>::max)())
+ ++n;
+ return n;
+}
+
+size_t win_iocp_io_context::poll_one(asio::error_code& ec)
+{
+ if (::InterlockedExchangeAdd(&outstanding_work_, 0) == 0)
+ {
+ stop();
+ ec = asio::error_code();
+ return 0;
+ }
+
+ win_iocp_thread_info this_thread;
+ thread_call_stack::context ctx(this, this_thread);
+
+ return do_one(0, ec);
+}
+
+void win_iocp_io_context::stop()
+{
+ if (::InterlockedExchange(&stopped_, 1) == 0)
+ {
+ if (::InterlockedExchange(&stop_event_posted_, 1) == 0)
+ {
+ if (!::PostQueuedCompletionStatus(iocp_.handle, 0, 0, 0))
+ {
+ DWORD last_error = ::GetLastError();
+ asio::error_code ec(last_error,
+ asio::error::get_system_category());
+ asio::detail::throw_error(ec, "pqcs");
+ }
+ }
+ }
+}
+
+void win_iocp_io_context::post_deferred_completion(win_iocp_operation* op)
+{
+ // Flag the operation as ready.
+ op->ready_ = 1;
+
+ // Enqueue the operation on the I/O completion port.
+ if (!::PostQueuedCompletionStatus(iocp_.handle, 0, 0, op))
+ {
+ // Out of resources. Put on completed queue instead.
+ mutex::scoped_lock lock(dispatch_mutex_);
+ completed_ops_.push(op);
+ ::InterlockedExchange(&dispatch_required_, 1);
+ }
+}
+
+void win_iocp_io_context::post_deferred_completions(
+ op_queue<win_iocp_operation>& ops)
+{
+ while (win_iocp_operation* op = ops.front())
+ {
+ ops.pop();
+
+ // Flag the operation as ready.
+ op->ready_ = 1;
+
+ // Enqueue the operation on the I/O completion port.
+ if (!::PostQueuedCompletionStatus(iocp_.handle, 0, 0, op))
+ {
+ // Out of resources. Put on completed queue instead.
+ mutex::scoped_lock lock(dispatch_mutex_);
+ completed_ops_.push(op);
+ completed_ops_.push(ops);
+ ::InterlockedExchange(&dispatch_required_, 1);
+ }
+ }
+}
+
+void win_iocp_io_context::abandon_operations(
+ op_queue<win_iocp_operation>& ops)
+{
+ while (win_iocp_operation* op = ops.front())
+ {
+ ops.pop();
+ ::InterlockedDecrement(&outstanding_work_);
+ op->destroy();
+ }
+}
+
+void win_iocp_io_context::on_pending(win_iocp_operation* op)
+{
+ if (::InterlockedCompareExchange(&op->ready_, 1, 0) == 1)
+ {
+ // Enqueue the operation on the I/O completion port.
+ if (!::PostQueuedCompletionStatus(iocp_.handle,
+ 0, overlapped_contains_result, op))
+ {
+ // Out of resources. Put on completed queue instead.
+ mutex::scoped_lock lock(dispatch_mutex_);
+ completed_ops_.push(op);
+ ::InterlockedExchange(&dispatch_required_, 1);
+ }
+ }
+}
+
+void win_iocp_io_context::on_completion(win_iocp_operation* op,
+ DWORD last_error, DWORD bytes_transferred)
+{
+ // Flag that the operation is ready for invocation.
+ op->ready_ = 1;
+
+ // Store results in the OVERLAPPED structure.
+ op->Internal = reinterpret_cast<ulong_ptr_t>(
+ &asio::error::get_system_category());
+ op->Offset = last_error;
+ op->OffsetHigh = bytes_transferred;
+
+ // Enqueue the operation on the I/O completion port.
+ if (!::PostQueuedCompletionStatus(iocp_.handle,
+ 0, overlapped_contains_result, op))
+ {
+ // Out of resources. Put on completed queue instead.
+ mutex::scoped_lock lock(dispatch_mutex_);
+ completed_ops_.push(op);
+ ::InterlockedExchange(&dispatch_required_, 1);
+ }
+}
+
+void win_iocp_io_context::on_completion(win_iocp_operation* op,
+ const asio::error_code& ec, DWORD bytes_transferred)
+{
+ // Flag that the operation is ready for invocation.
+ op->ready_ = 1;
+
+ // Store results in the OVERLAPPED structure.
+ op->Internal = reinterpret_cast<ulong_ptr_t>(&ec.category());
+ op->Offset = ec.value();
+ op->OffsetHigh = bytes_transferred;
+
+ // Enqueue the operation on the I/O completion port.
+ if (!::PostQueuedCompletionStatus(iocp_.handle,
+ 0, overlapped_contains_result, op))
+ {
+ // Out of resources. Put on completed queue instead.
+ mutex::scoped_lock lock(dispatch_mutex_);
+ completed_ops_.push(op);
+ ::InterlockedExchange(&dispatch_required_, 1);
+ }
+}
+
+size_t win_iocp_io_context::do_one(DWORD msec, asio::error_code& ec)
+{
+ for (;;)
+ {
+ // Try to acquire responsibility for dispatching timers and completed ops.
+ if (::InterlockedCompareExchange(&dispatch_required_, 0, 1) == 1)
+ {
+ mutex::scoped_lock lock(dispatch_mutex_);
+
+ // Dispatch pending timers and operations.
+ op_queue<win_iocp_operation> ops;
+ ops.push(completed_ops_);
+ timer_queues_.get_ready_timers(ops);
+ post_deferred_completions(ops);
+ update_timeout();
+ }
+
+ // Get the next operation from the queue.
+ DWORD bytes_transferred = 0;
+ dword_ptr_t completion_key = 0;
+ LPOVERLAPPED overlapped = 0;
+ ::SetLastError(0);
+ BOOL ok = ::GetQueuedCompletionStatus(iocp_.handle,
+ &bytes_transferred, &completion_key, &overlapped,
+ msec < gqcs_timeout_ ? msec : gqcs_timeout_);
+ DWORD last_error = ::GetLastError();
+
+ if (overlapped)
+ {
+ win_iocp_operation* op = static_cast<win_iocp_operation*>(overlapped);
+ asio::error_code result_ec(last_error,
+ asio::error::get_system_category());
+
+ // We may have been passed the last_error and bytes_transferred in the
+ // OVERLAPPED structure itself.
+ if (completion_key == overlapped_contains_result)
+ {
+ result_ec = asio::error_code(static_cast<int>(op->Offset),
+ *reinterpret_cast<asio::error_category*>(op->Internal));
+ bytes_transferred = op->OffsetHigh;
+ }
+
+ // Otherwise ensure any result has been saved into the OVERLAPPED
+ // structure.
+ else
+ {
+ op->Internal = reinterpret_cast<ulong_ptr_t>(&result_ec.category());
+ op->Offset = result_ec.value();
+ op->OffsetHigh = bytes_transferred;
+ }
+
+ // Dispatch the operation only if ready. The operation may not be ready
+ // if the initiating function (e.g. a call to WSARecv) has not yet
+ // returned. This is because the initiating function still wants access
+ // to the operation's OVERLAPPED structure.
+ if (::InterlockedCompareExchange(&op->ready_, 1, 0) == 1)
+ {
+ // Ensure the count of outstanding work is decremented on block exit.
+ work_finished_on_block_exit on_exit = { this };
+ (void)on_exit;
+
+ op->complete(this, result_ec, bytes_transferred);
+ ec = asio::error_code();
+ return 1;
+ }
+ }
+ else if (!ok)
+ {
+ if (last_error != WAIT_TIMEOUT)
+ {
+ ec = asio::error_code(last_error,
+ asio::error::get_system_category());
+ return 0;
+ }
+
+ // If we're waiting indefinitely we need to keep going until we get a
+ // real handler.
+ if (msec == INFINITE)
+ continue;
+
+ ec = asio::error_code();
+ return 0;
+ }
+ else if (completion_key == wake_for_dispatch)
+ {
+ // We have been woken up to try to acquire responsibility for dispatching
+ // timers and completed operations.
+ }
+ else
+ {
+ // Indicate that there is no longer an in-flight stop event.
+ ::InterlockedExchange(&stop_event_posted_, 0);
+
+ // The stopped_ flag is always checked to ensure that any leftover
+ // stop events from a previous run invocation are ignored.
+ if (::InterlockedExchangeAdd(&stopped_, 0) != 0)
+ {
+ // Wake up next thread that is blocked on GetQueuedCompletionStatus.
+ if (::InterlockedExchange(&stop_event_posted_, 1) == 0)
+ {
+ if (!::PostQueuedCompletionStatus(iocp_.handle, 0, 0, 0))
+ {
+ last_error = ::GetLastError();
+ ec = asio::error_code(last_error,
+ asio::error::get_system_category());
+ return 0;
+ }
+ }
+
+ ec = asio::error_code();
+ return 0;
+ }
+ }
+ }
+}
+
+DWORD win_iocp_io_context::get_gqcs_timeout()
+{
+ OSVERSIONINFOEX osvi;
+ ZeroMemory(&osvi, sizeof(osvi));
+ osvi.dwOSVersionInfoSize = sizeof(osvi);
+ osvi.dwMajorVersion = 6ul;
+
+ const uint64_t condition_mask = ::VerSetConditionMask(
+ 0, VER_MAJORVERSION, VER_GREATER_EQUAL);
+
+ if (!!::VerifyVersionInfo(&osvi, VER_MAJORVERSION, condition_mask))
+ return INFINITE;
+
+ return default_gqcs_timeout;
+}
+
+void win_iocp_io_context::do_add_timer_queue(timer_queue_base& queue)
+{
+ mutex::scoped_lock lock(dispatch_mutex_);
+
+ timer_queues_.insert(&queue);
+
+ if (!waitable_timer_.handle)
+ {
+ waitable_timer_.handle = ::CreateWaitableTimer(0, FALSE, 0);
+ if (waitable_timer_.handle == 0)
+ {
+ DWORD last_error = ::GetLastError();
+ asio::error_code ec(last_error,
+ asio::error::get_system_category());
+ asio::detail::throw_error(ec, "timer");
+ }
+
+ LARGE_INTEGER timeout;
+ timeout.QuadPart = -max_timeout_usec;
+ timeout.QuadPart *= 10;
+ ::SetWaitableTimer(waitable_timer_.handle,
+ &timeout, max_timeout_msec, 0, 0, FALSE);
+ }
+
+ if (!timer_thread_.get())
+ {
+ timer_thread_function thread_function = { this };
+ timer_thread_.reset(new thread(thread_function, 65536));
+ }
+}
+
+void win_iocp_io_context::do_remove_timer_queue(timer_queue_base& queue)
+{
+ mutex::scoped_lock lock(dispatch_mutex_);
+
+ timer_queues_.erase(&queue);
+}
+
+void win_iocp_io_context::update_timeout()
+{
+ if (timer_thread_.get())
+ {
+ // There's no point updating the waitable timer if the new timeout period
+ // exceeds the maximum timeout. In that case, we might as well wait for the
+ // existing period of the timer to expire.
+ long timeout_usec = timer_queues_.wait_duration_usec(max_timeout_usec);
+ if (timeout_usec < max_timeout_usec)
+ {
+ LARGE_INTEGER timeout;
+ timeout.QuadPart = -timeout_usec;
+ timeout.QuadPart *= 10;
+ ::SetWaitableTimer(waitable_timer_.handle,
+ &timeout, max_timeout_msec, 0, 0, FALSE);
+ }
+ }
+}
+
+} // namespace detail
+} // namespace asio
+
+#include "asio/detail/pop_options.hpp"
+
+#endif // defined(ASIO_HAS_IOCP)
+
+#endif // ASIO_DETAIL_IMPL_WIN_IOCP_IO_CONTEXT_IPP
diff --git a/lib/asio/detail/impl/win_iocp_serial_port_service.ipp b/lib/asio/detail/impl/win_iocp_serial_port_service.ipp
new file mode 100644
index 0000000..4a9b8cd
--- /dev/null
+++ b/lib/asio/detail/impl/win_iocp_serial_port_service.ipp
@@ -0,0 +1,181 @@
+//
+// detail/impl/win_iocp_serial_port_service.ipp
+// ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+//
+// Copyright (c) 2003-2018 Christopher M. Kohlhoff (chris at kohlhoff dot com)
+// Copyright (c) 2008 Rep Invariant Systems, Inc. (info@repinvariant.com)
+//
+// 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 ASIO_DETAIL_IMPL_WIN_IOCP_SERIAL_PORT_SERVICE_IPP
+#define ASIO_DETAIL_IMPL_WIN_IOCP_SERIAL_PORT_SERVICE_IPP
+
+#if defined(_MSC_VER) && (_MSC_VER >= 1200)
+# pragma once
+#endif // defined(_MSC_VER) && (_MSC_VER >= 1200)
+
+#include "asio/detail/config.hpp"
+
+#if defined(ASIO_HAS_IOCP) && defined(ASIO_HAS_SERIAL_PORT)
+
+#include <cstring>
+#include "asio/detail/win_iocp_serial_port_service.hpp"
+
+#include "asio/detail/push_options.hpp"
+
+namespace asio {
+namespace detail {
+
+win_iocp_serial_port_service::win_iocp_serial_port_service(
+ asio::io_context& io_context)
+ : service_base<win_iocp_serial_port_service>(io_context),
+ handle_service_(io_context)
+{
+}
+
+void win_iocp_serial_port_service::shutdown()
+{
+}
+
+asio::error_code win_iocp_serial_port_service::open(
+ win_iocp_serial_port_service::implementation_type& impl,
+ const std::string& device, asio::error_code& ec)
+{
+ if (is_open(impl))
+ {
+ ec = asio::error::already_open;
+ return ec;
+ }
+
+ // For convenience, add a leading \\.\ sequence if not already present.
+ std::string name = (device[0] == '\\') ? device : "\\\\.\\" + device;
+
+ // Open a handle to the serial port.
+ ::HANDLE handle = ::CreateFileA(name.c_str(),
+ GENERIC_READ | GENERIC_WRITE, 0, 0,
+ OPEN_EXISTING, FILE_FLAG_OVERLAPPED, 0);
+ if (handle == INVALID_HANDLE_VALUE)
+ {
+ DWORD last_error = ::GetLastError();
+ ec = asio::error_code(last_error,
+ asio::error::get_system_category());
+ return ec;
+ }
+
+ // Determine the initial serial port parameters.
+ using namespace std; // For memset.
+ ::DCB dcb;
+ memset(&dcb, 0, sizeof(DCB));
+ dcb.DCBlength = sizeof(DCB);
+ if (!::GetCommState(handle, &dcb))
+ {
+ DWORD last_error = ::GetLastError();
+ ::CloseHandle(handle);
+ ec = asio::error_code(last_error,
+ asio::error::get_system_category());
+ return ec;
+ }
+
+ // Set some default serial port parameters. This implementation does not
+ // support changing these, so they might as well be in a known state.
+ dcb.fBinary = TRUE; // Win32 only supports binary mode.
+ dcb.fDsrSensitivity = FALSE;
+ dcb.fNull = FALSE; // Do not ignore NULL characters.
+ dcb.fAbortOnError = FALSE; // Ignore serial framing errors.
+ if (!::SetCommState(handle, &dcb))
+ {
+ DWORD last_error = ::GetLastError();
+ ::CloseHandle(handle);
+ ec = asio::error_code(last_error,
+ asio::error::get_system_category());
+ return ec;
+ }
+
+ // Set up timeouts so that the serial port will behave similarly to a
+ // network socket. Reads wait for at least one byte, then return with
+ // whatever they have. Writes return once everything is out the door.
+ ::COMMTIMEOUTS timeouts;
+ timeouts.ReadIntervalTimeout = 1;
+ timeouts.ReadTotalTimeoutMultiplier = 0;
+ timeouts.ReadTotalTimeoutConstant = 0;
+ timeouts.WriteTotalTimeoutMultiplier = 0;
+ timeouts.WriteTotalTimeoutConstant = 0;
+ if (!::SetCommTimeouts(handle, &timeouts))
+ {
+ DWORD last_error = ::GetLastError();
+ ::CloseHandle(handle);
+ ec = asio::error_code(last_error,
+ asio::error::get_system_category());
+ return ec;
+ }
+
+ // We're done. Take ownership of the serial port handle.
+ if (handle_service_.assign(impl, handle, ec))
+ ::CloseHandle(handle);
+ return ec;
+}
+
+asio::error_code win_iocp_serial_port_service::do_set_option(
+ win_iocp_serial_port_service::implementation_type& impl,
+ win_iocp_serial_port_service::store_function_type store,
+ const void* option, asio::error_code& ec)
+{
+ using namespace std; // For memcpy.
+
+ ::DCB dcb;
+ memset(&dcb, 0, sizeof(DCB));
+ dcb.DCBlength = sizeof(DCB);
+ if (!::GetCommState(handle_service_.native_handle(impl), &dcb))
+ {
+ DWORD last_error = ::GetLastError();
+ ec = asio::error_code(last_error,
+ asio::error::get_system_category());
+ return ec;
+ }
+
+ if (store(option, dcb, ec))
+ return ec;
+
+ if (!::SetCommState(handle_service_.native_handle(impl), &dcb))
+ {
+ DWORD last_error = ::GetLastError();
+ ec = asio::error_code(last_error,
+ asio::error::get_system_category());
+ return ec;
+ }
+
+ ec = asio::error_code();
+ return ec;
+}
+
+asio::error_code win_iocp_serial_port_service::do_get_option(
+ const win_iocp_serial_port_service::implementation_type& impl,
+ win_iocp_serial_port_service::load_function_type load,
+ void* option, asio::error_code& ec) const
+{
+ using namespace std; // For memset.
+
+ ::DCB dcb;
+ memset(&dcb, 0, sizeof(DCB));
+ dcb.DCBlength = sizeof(DCB);
+ if (!::GetCommState(handle_service_.native_handle(impl), &dcb))
+ {
+ DWORD last_error = ::GetLastError();
+ ec = asio::error_code(last_error,
+ asio::error::get_system_category());
+ return ec;
+ }
+
+ return load(option, dcb, ec);
+}
+
+} // namespace detail
+} // namespace asio
+
+#include "asio/detail/pop_options.hpp"
+
+#endif // defined(ASIO_HAS_IOCP) && defined(ASIO_HAS_SERIAL_PORT)
+
+#endif // ASIO_DETAIL_IMPL_WIN_IOCP_SERIAL_PORT_SERVICE_IPP
diff --git a/lib/asio/detail/impl/win_iocp_socket_service_base.ipp b/lib/asio/detail/impl/win_iocp_socket_service_base.ipp
new file mode 100644
index 0000000..6c478cd
--- /dev/null
+++ b/lib/asio/detail/impl/win_iocp_socket_service_base.ipp
@@ -0,0 +1,799 @@
+//
+// detail/impl/win_iocp_socket_service_base.ipp
+// ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+//
+// Copyright (c) 2003-2018 Christopher M. Kohlhoff (chris at kohlhoff dot com)
+//
+// 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 ASIO_DETAIL_IMPL_WIN_IOCP_SOCKET_SERVICE_BASE_IPP
+#define ASIO_DETAIL_IMPL_WIN_IOCP_SOCKET_SERVICE_BASE_IPP
+
+#if defined(_MSC_VER) && (_MSC_VER >= 1200)
+# pragma once
+#endif // defined(_MSC_VER) && (_MSC_VER >= 1200)
+
+#include "asio/detail/config.hpp"
+
+#if defined(ASIO_HAS_IOCP)
+
+#include "asio/detail/win_iocp_socket_service_base.hpp"
+
+#include "asio/detail/push_options.hpp"
+
+namespace asio {
+namespace detail {
+
+win_iocp_socket_service_base::win_iocp_socket_service_base(
+ asio::io_context& io_context)
+ : io_context_(io_context),
+ iocp_service_(use_service<win_iocp_io_context>(io_context)),
+ reactor_(0),
+ connect_ex_(0),
+ nt_set_info_(0),
+ mutex_(),
+ impl_list_(0)
+{
+}
+
+void win_iocp_socket_service_base::base_shutdown()
+{
+ // Close all implementations, causing all operations to complete.
+ asio::detail::mutex::scoped_lock lock(mutex_);
+ base_implementation_type* impl = impl_list_;
+ while (impl)
+ {
+ close_for_destruction(*impl);
+ impl = impl->next_;
+ }
+}
+
+void win_iocp_socket_service_base::construct(
+ win_iocp_socket_service_base::base_implementation_type& impl)
+{
+ impl.socket_ = invalid_socket;
+ impl.state_ = 0;
+ impl.cancel_token_.reset();
+#if defined(ASIO_ENABLE_CANCELIO)
+ impl.safe_cancellation_thread_id_ = 0;
+#endif // defined(ASIO_ENABLE_CANCELIO)
+
+ // Insert implementation into linked list of all implementations.
+ asio::detail::mutex::scoped_lock lock(mutex_);
+ impl.next_ = impl_list_;
+ impl.prev_ = 0;
+ if (impl_list_)
+ impl_list_->prev_ = &impl;
+ impl_list_ = &impl;
+}
+
+void win_iocp_socket_service_base::base_move_construct(
+ win_iocp_socket_service_base::base_implementation_type& impl,
+ win_iocp_socket_service_base::base_implementation_type& other_impl)
+{
+ impl.socket_ = other_impl.socket_;
+ other_impl.socket_ = invalid_socket;
+
+ impl.state_ = other_impl.state_;
+ other_impl.state_ = 0;
+
+ impl.cancel_token_ = other_impl.cancel_token_;
+ other_impl.cancel_token_.reset();
+
+#if defined(ASIO_ENABLE_CANCELIO)
+ impl.safe_cancellation_thread_id_ = other_impl.safe_cancellation_thread_id_;
+ other_impl.safe_cancellation_thread_id_ = 0;
+#endif // defined(ASIO_ENABLE_CANCELIO)
+
+ // Insert implementation into linked list of all implementations.
+ asio::detail::mutex::scoped_lock lock(mutex_);
+ impl.next_ = impl_list_;
+ impl.prev_ = 0;
+ if (impl_list_)
+ impl_list_->prev_ = &impl;
+ impl_list_ = &impl;
+}
+
+void win_iocp_socket_service_base::base_move_assign(
+ win_iocp_socket_service_base::base_implementation_type& impl,
+ win_iocp_socket_service_base& other_service,
+ win_iocp_socket_service_base::base_implementation_type& other_impl)
+{
+ close_for_destruction(impl);
+
+ if (this != &other_service)
+ {
+ // Remove implementation from linked list of all implementations.
+ asio::detail::mutex::scoped_lock lock(mutex_);
+ if (impl_list_ == &impl)
+ impl_list_ = impl.next_;
+ if (impl.prev_)
+ impl.prev_->next_ = impl.next_;
+ if (impl.next_)
+ impl.next_->prev_= impl.prev_;
+ impl.next_ = 0;
+ impl.prev_ = 0;
+ }
+
+ impl.socket_ = other_impl.socket_;
+ other_impl.socket_ = invalid_socket;
+
+ impl.state_ = other_impl.state_;
+ other_impl.state_ = 0;
+
+ impl.cancel_token_ = other_impl.cancel_token_;
+ other_impl.cancel_token_.reset();
+
+#if defined(ASIO_ENABLE_CANCELIO)
+ impl.safe_cancellation_thread_id_ = other_impl.safe_cancellation_thread_id_;
+ other_impl.safe_cancellation_thread_id_ = 0;
+#endif // defined(ASIO_ENABLE_CANCELIO)
+
+ if (this != &other_service)
+ {
+ // Insert implementation into linked list of all implementations.
+ asio::detail::mutex::scoped_lock lock(other_service.mutex_);
+ impl.next_ = other_service.impl_list_;
+ impl.prev_ = 0;
+ if (other_service.impl_list_)
+ other_service.impl_list_->prev_ = &impl;
+ other_service.impl_list_ = &impl;
+ }
+}
+
+void win_iocp_socket_service_base::destroy(
+ win_iocp_socket_service_base::base_implementation_type& impl)
+{
+ close_for_destruction(impl);
+
+ // Remove implementation from linked list of all implementations.
+ asio::detail::mutex::scoped_lock lock(mutex_);
+ if (impl_list_ == &impl)
+ impl_list_ = impl.next_;
+ if (impl.prev_)
+ impl.prev_->next_ = impl.next_;
+ if (impl.next_)
+ impl.next_->prev_= impl.prev_;
+ impl.next_ = 0;
+ impl.prev_ = 0;
+}
+
+asio::error_code win_iocp_socket_service_base::close(
+ win_iocp_socket_service_base::base_implementation_type& impl,
+ asio::error_code& ec)
+{
+ if (is_open(impl))
+ {
+ ASIO_HANDLER_OPERATION((iocp_service_.context(),
+ "socket", &impl, impl.socket_, "close"));
+
+ // Check if the reactor was created, in which case we need to close the
+ // socket on the reactor as well to cancel any operations that might be
+ // running there.
+ select_reactor* r = static_cast<select_reactor*>(
+ interlocked_compare_exchange_pointer(
+ reinterpret_cast<void**>(&reactor_), 0, 0));
+ if (r)
+ r->deregister_descriptor(impl.socket_, impl.reactor_data_, true);
+
+ socket_ops::close(impl.socket_, impl.state_, false, ec);
+
+ if (r)
+ r->cleanup_descriptor_data(impl.reactor_data_);
+ }
+ else
+ {
+ ec = asio::error_code();
+ }
+
+ impl.socket_ = invalid_socket;
+ impl.state_ = 0;
+ impl.cancel_token_.reset();
+#if defined(ASIO_ENABLE_CANCELIO)
+ impl.safe_cancellation_thread_id_ = 0;
+#endif // defined(ASIO_ENABLE_CANCELIO)
+
+ return ec;
+}
+
+socket_type win_iocp_socket_service_base::release(
+ win_iocp_socket_service_base::base_implementation_type& impl,
+ asio::error_code& ec)
+{
+ if (!is_open(impl))
+ return invalid_socket;
+
+ cancel(impl, ec);
+ if (ec)
+ return invalid_socket;
+
+ nt_set_info_fn fn = get_nt_set_info();
+ if (fn == 0)
+ {
+ ec = asio::error::operation_not_supported;
+ return invalid_socket;
+ }
+
+ HANDLE sock_as_handle = reinterpret_cast<HANDLE>(impl.socket_);
+ ULONG_PTR iosb[2] = { 0, 0 };
+ void* info[2] = { 0, 0 };
+ if (fn(sock_as_handle, iosb, &info, sizeof(info),
+ 61 /* FileReplaceCompletionInformation */))
+ {
+ ec = asio::error::operation_not_supported;
+ return invalid_socket;
+ }
+
+ socket_type tmp = impl.socket_;
+ impl.socket_ = invalid_socket;
+ return tmp;
+}
+
+asio::error_code win_iocp_socket_service_base::cancel(
+ win_iocp_socket_service_base::base_implementation_type& impl,
+ asio::error_code& ec)
+{
+ if (!is_open(impl))
+ {
+ ec = asio::error::bad_descriptor;
+ return ec;
+ }
+
+ ASIO_HANDLER_OPERATION((iocp_service_.context(),
+ "socket", &impl, impl.socket_, "cancel"));
+
+ if (FARPROC cancel_io_ex_ptr = ::GetProcAddress(
+ ::GetModuleHandleA("KERNEL32"), "CancelIoEx"))
+ {
+ // The version of Windows supports cancellation from any thread.
+ typedef BOOL (WINAPI* cancel_io_ex_t)(HANDLE, LPOVERLAPPED);
+ cancel_io_ex_t cancel_io_ex = (cancel_io_ex_t)cancel_io_ex_ptr;
+ socket_type sock = impl.socket_;
+ HANDLE sock_as_handle = reinterpret_cast<HANDLE>(sock);
+ if (!cancel_io_ex(sock_as_handle, 0))
+ {
+ DWORD last_error = ::GetLastError();
+ if (last_error == ERROR_NOT_FOUND)
+ {
+ // ERROR_NOT_FOUND means that there were no operations to be
+ // cancelled. We swallow this error to match the behaviour on other
+ // platforms.
+ ec = asio::error_code();
+ }
+ else
+ {
+ ec = asio::error_code(last_error,
+ asio::error::get_system_category());
+ }
+ }
+ else
+ {
+ ec = asio::error_code();
+ }
+ }
+#if defined(ASIO_ENABLE_CANCELIO)
+ else if (impl.safe_cancellation_thread_id_ == 0)
+ {
+ // No operations have been started, so there's nothing to cancel.
+ ec = asio::error_code();
+ }
+ else if (impl.safe_cancellation_thread_id_ == ::GetCurrentThreadId())
+ {
+ // Asynchronous operations have been started from the current thread only,
+ // so it is safe to try to cancel them using CancelIo.
+ socket_type sock = impl.socket_;
+ HANDLE sock_as_handle = reinterpret_cast<HANDLE>(sock);
+ if (!::CancelIo(sock_as_handle))
+ {
+ DWORD last_error = ::GetLastError();
+ ec = asio::error_code(last_error,
+ asio::error::get_system_category());
+ }
+ else
+ {
+ ec = asio::error_code();
+ }
+ }
+ else
+ {
+ // Asynchronous operations have been started from more than one thread,
+ // so cancellation is not safe.
+ ec = asio::error::operation_not_supported;
+ }
+#else // defined(ASIO_ENABLE_CANCELIO)
+ else
+ {
+ // Cancellation is not supported as CancelIo may not be used.
+ ec = asio::error::operation_not_supported;
+ }
+#endif // defined(ASIO_ENABLE_CANCELIO)
+
+ // Cancel any operations started via the reactor.
+ if (!ec)
+ {
+ select_reactor* r = static_cast<select_reactor*>(
+ interlocked_compare_exchange_pointer(
+ reinterpret_cast<void**>(&reactor_), 0, 0));
+ if (r)
+ r->cancel_ops(impl.socket_, impl.reactor_data_);
+ }
+
+ return ec;
+}
+
+asio::error_code win_iocp_socket_service_base::do_open(
+ win_iocp_socket_service_base::base_implementation_type& impl,
+ int family, int type, int protocol, asio::error_code& ec)
+{
+ if (is_open(impl))
+ {
+ ec = asio::error::already_open;
+ return ec;
+ }
+
+ socket_holder sock(socket_ops::socket(family, type, protocol, ec));
+ if (sock.get() == invalid_socket)
+ return ec;
+
+ HANDLE sock_as_handle = reinterpret_cast<HANDLE>(sock.get());
+ if (iocp_service_.register_handle(sock_as_handle, ec))
+ 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;
+ }
+ impl.cancel_token_.reset(static_cast<void*>(0), socket_ops::noop_deleter());
+ ec = asio::error_code();
+ return ec;
+}
+
+asio::error_code win_iocp_socket_service_base::do_assign(
+ win_iocp_socket_service_base::base_implementation_type& impl,
+ int type, socket_type native_socket, asio::error_code& ec)
+{
+ if (is_open(impl))
+ {
+ ec = asio::error::already_open;
+ return ec;
+ }
+
+ HANDLE sock_as_handle = reinterpret_cast<HANDLE>(native_socket);
+ if (iocp_service_.register_handle(sock_as_handle, ec))
+ 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.cancel_token_.reset(static_cast<void*>(0), socket_ops::noop_deleter());
+ ec = asio::error_code();
+ return ec;
+}
+
+void win_iocp_socket_service_base::start_send_op(
+ win_iocp_socket_service_base::base_implementation_type& impl,
+ WSABUF* buffers, std::size_t buffer_count,
+ socket_base::message_flags flags, bool noop, operation* op)
+{
+ update_cancellation_thread_id(impl);
+ iocp_service_.work_started();
+
+ if (noop)
+ iocp_service_.on_completion(op);
+ else if (!is_open(impl))
+ iocp_service_.on_completion(op, asio::error::bad_descriptor);
+ else
+ {
+ DWORD bytes_transferred = 0;
+ int result = ::WSASend(impl.socket_, buffers,
+ static_cast<DWORD>(buffer_count), &bytes_transferred, flags, op, 0);
+ DWORD last_error = ::WSAGetLastError();
+ if (last_error == ERROR_PORT_UNREACHABLE)
+ last_error = WSAECONNREFUSED;
+ if (result != 0 && last_error != WSA_IO_PENDING)
+ iocp_service_.on_completion(op, last_error, bytes_transferred);
+ else
+ iocp_service_.on_pending(op);
+ }
+}
+
+void win_iocp_socket_service_base::start_send_to_op(
+ win_iocp_socket_service_base::base_implementation_type& impl,
+ WSABUF* buffers, std::size_t buffer_count,
+ const socket_addr_type* addr, int addrlen,
+ socket_base::message_flags flags, operation* op)
+{
+ update_cancellation_thread_id(impl);
+ iocp_service_.work_started();
+
+ if (!is_open(impl))
+ iocp_service_.on_completion(op, asio::error::bad_descriptor);
+ else
+ {
+ DWORD bytes_transferred = 0;
+ int result = ::WSASendTo(impl.socket_, buffers,
+ static_cast<DWORD>(buffer_count),
+ &bytes_transferred, flags, addr, addrlen, op, 0);
+ DWORD last_error = ::WSAGetLastError();
+ if (last_error == ERROR_PORT_UNREACHABLE)
+ last_error = WSAECONNREFUSED;
+ if (result != 0 && last_error != WSA_IO_PENDING)
+ iocp_service_.on_completion(op, last_error, bytes_transferred);
+ else
+ iocp_service_.on_pending(op);
+ }
+}
+
+void win_iocp_socket_service_base::start_receive_op(
+ win_iocp_socket_service_base::base_implementation_type& impl,
+ WSABUF* buffers, std::size_t buffer_count,
+ socket_base::message_flags flags, bool noop, operation* op)
+{
+ update_cancellation_thread_id(impl);
+ iocp_service_.work_started();
+
+ if (noop)
+ iocp_service_.on_completion(op);
+ else if (!is_open(impl))
+ iocp_service_.on_completion(op, asio::error::bad_descriptor);
+ else
+ {
+ DWORD bytes_transferred = 0;
+ DWORD recv_flags = flags;
+ int result = ::WSARecv(impl.socket_, buffers,
+ static_cast<DWORD>(buffer_count),
+ &bytes_transferred, &recv_flags, op, 0);
+ DWORD last_error = ::WSAGetLastError();
+ if (last_error == ERROR_NETNAME_DELETED)
+ last_error = WSAECONNRESET;
+ else if (last_error == ERROR_PORT_UNREACHABLE)
+ last_error = WSAECONNREFUSED;
+ if (result != 0 && last_error != WSA_IO_PENDING)
+ iocp_service_.on_completion(op, last_error, bytes_transferred);
+ else
+ iocp_service_.on_pending(op);
+ }
+}
+
+void win_iocp_socket_service_base::start_null_buffers_receive_op(
+ win_iocp_socket_service_base::base_implementation_type& impl,
+ socket_base::message_flags flags, reactor_op* op)
+{
+ if ((impl.state_ & socket_ops::stream_oriented) != 0)
+ {
+ // For stream sockets on Windows, we may issue a 0-byte overlapped
+ // WSARecv to wait until there is data available on the socket.
+ ::WSABUF buf = { 0, 0 };
+ start_receive_op(impl, &buf, 1, flags, false, op);
+ }
+ else
+ {
+ start_reactor_op(impl,
+ (flags & socket_base::message_out_of_band)
+ ? select_reactor::except_op : select_reactor::read_op,
+ op);
+ }
+}
+
+void win_iocp_socket_service_base::start_receive_from_op(
+ win_iocp_socket_service_base::base_implementation_type& impl,
+ WSABUF* buffers, std::size_t buffer_count, socket_addr_type* addr,
+ socket_base::message_flags flags, int* addrlen, operation* op)
+{
+ update_cancellation_thread_id(impl);
+ iocp_service_.work_started();
+
+ if (!is_open(impl))
+ iocp_service_.on_completion(op, asio::error::bad_descriptor);
+ else
+ {
+ DWORD bytes_transferred = 0;
+ DWORD recv_flags = flags;
+ int result = ::WSARecvFrom(impl.socket_, buffers,
+ static_cast<DWORD>(buffer_count),
+ &bytes_transferred, &recv_flags, addr, addrlen, op, 0);
+ DWORD last_error = ::WSAGetLastError();
+ if (last_error == ERROR_PORT_UNREACHABLE)
+ last_error = WSAECONNREFUSED;
+ if (result != 0 && last_error != WSA_IO_PENDING)
+ iocp_service_.on_completion(op, last_error, bytes_transferred);
+ else
+ iocp_service_.on_pending(op);
+ }
+}
+
+void win_iocp_socket_service_base::start_accept_op(
+ win_iocp_socket_service_base::base_implementation_type& impl,
+ bool peer_is_open, socket_holder& new_socket, int family, int type,
+ int protocol, void* output_buffer, DWORD address_length, operation* op)
+{
+ update_cancellation_thread_id(impl);
+ iocp_service_.work_started();
+
+ if (!is_open(impl))
+ iocp_service_.on_completion(op, asio::error::bad_descriptor);
+ else if (peer_is_open)
+ iocp_service_.on_completion(op, asio::error::already_open);
+ else
+ {
+ asio::error_code ec;
+ new_socket.reset(socket_ops::socket(family, type, protocol, ec));
+ if (new_socket.get() == invalid_socket)
+ iocp_service_.on_completion(op, ec);
+ else
+ {
+ DWORD bytes_read = 0;
+ BOOL result = ::AcceptEx(impl.socket_, new_socket.get(), output_buffer,
+ 0, address_length, address_length, &bytes_read, op);
+ DWORD last_error = ::WSAGetLastError();
+ if (!result && last_error != WSA_IO_PENDING)
+ iocp_service_.on_completion(op, last_error);
+ else
+ iocp_service_.on_pending(op);
+ }
+ }
+}
+
+void win_iocp_socket_service_base::restart_accept_op(
+ socket_type s, socket_holder& new_socket, int family, int type,
+ int protocol, void* output_buffer, DWORD address_length, operation* op)
+{
+ new_socket.reset();
+ iocp_service_.work_started();
+
+ asio::error_code ec;
+ new_socket.reset(socket_ops::socket(family, type, protocol, ec));
+ if (new_socket.get() == invalid_socket)
+ iocp_service_.on_completion(op, ec);
+ else
+ {
+ DWORD bytes_read = 0;
+ BOOL result = ::AcceptEx(s, new_socket.get(), output_buffer,
+ 0, address_length, address_length, &bytes_read, op);
+ DWORD last_error = ::WSAGetLastError();
+ if (!result && last_error != WSA_IO_PENDING)
+ iocp_service_.on_completion(op, last_error);
+ else
+ iocp_service_.on_pending(op);
+ }
+}
+
+void win_iocp_socket_service_base::start_reactor_op(
+ win_iocp_socket_service_base::base_implementation_type& impl,
+ int op_type, reactor_op* op)
+{
+ select_reactor& r = get_reactor();
+ update_cancellation_thread_id(impl);
+
+ if (is_open(impl))
+ {
+ r.start_op(op_type, impl.socket_, impl.reactor_data_, op, false, false);
+ return;
+ }
+ else
+ op->ec_ = asio::error::bad_descriptor;
+
+ iocp_service_.post_immediate_completion(op, false);
+}
+
+void win_iocp_socket_service_base::start_connect_op(
+ win_iocp_socket_service_base::base_implementation_type& impl,
+ int family, int type, const socket_addr_type* addr,
+ std::size_t addrlen, win_iocp_socket_connect_op_base* op)
+{
+ // If ConnectEx is available, use that.
+ if (family == ASIO_OS_DEF(AF_INET)
+ || family == ASIO_OS_DEF(AF_INET6))
+ {
+ if (connect_ex_fn connect_ex = get_connect_ex(impl, type))
+ {
+ union address_union
+ {
+ socket_addr_type base;
+ sockaddr_in4_type v4;
+ sockaddr_in6_type v6;
+ } a;
+
+ using namespace std; // For memset.
+ memset(&a, 0, sizeof(a));
+ a.base.sa_family = family;
+
+ socket_ops::bind(impl.socket_, &a.base,
+ family == ASIO_OS_DEF(AF_INET)
+ ? sizeof(a.v4) : sizeof(a.v6), op->ec_);
+ if (op->ec_ && op->ec_ != asio::error::invalid_argument)
+ {
+ iocp_service_.post_immediate_completion(op, false);
+ return;
+ }
+
+ op->connect_ex_ = true;
+ update_cancellation_thread_id(impl);
+ iocp_service_.work_started();
+
+ BOOL result = connect_ex(impl.socket_,
+ addr, static_cast<int>(addrlen), 0, 0, 0, op);
+ DWORD last_error = ::WSAGetLastError();
+ if (!result && last_error != WSA_IO_PENDING)
+ iocp_service_.on_completion(op, last_error);
+ else
+ iocp_service_.on_pending(op);
+ return;
+ }
+ }
+
+ // Otherwise, fall back to a reactor-based implementation.
+ select_reactor& r = get_reactor();
+ update_cancellation_thread_id(impl);
+
+ if ((impl.state_ & socket_ops::non_blocking) != 0
+ || 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_ == asio::error::in_progress
+ || op->ec_ == asio::error::would_block)
+ {
+ op->ec_ = asio::error_code();
+ r.start_op(select_reactor::connect_op, impl.socket_,
+ impl.reactor_data_, op, false, false);
+ return;
+ }
+ }
+ }
+
+ r.post_immediate_completion(op, false);
+}
+
+void win_iocp_socket_service_base::close_for_destruction(
+ win_iocp_socket_service_base::base_implementation_type& impl)
+{
+ if (is_open(impl))
+ {
+ ASIO_HANDLER_OPERATION((iocp_service_.context(),
+ "socket", &impl, impl.socket_, "close"));
+
+ // Check if the reactor was created, in which case we need to close the
+ // socket on the reactor as well to cancel any operations that might be
+ // running there.
+ select_reactor* r = static_cast<select_reactor*>(
+ interlocked_compare_exchange_pointer(
+ reinterpret_cast<void**>(&reactor_), 0, 0));
+ if (r)
+ r->deregister_descriptor(impl.socket_, impl.reactor_data_, true);
+
+ asio::error_code ignored_ec;
+ socket_ops::close(impl.socket_, impl.state_, true, ignored_ec);
+
+ if (r)
+ r->cleanup_descriptor_data(impl.reactor_data_);
+ }
+
+ impl.socket_ = invalid_socket;
+ impl.state_ = 0;
+ impl.cancel_token_.reset();
+#if defined(ASIO_ENABLE_CANCELIO)
+ impl.safe_cancellation_thread_id_ = 0;
+#endif // defined(ASIO_ENABLE_CANCELIO)
+}
+
+void win_iocp_socket_service_base::update_cancellation_thread_id(
+ win_iocp_socket_service_base::base_implementation_type& impl)
+{
+#if defined(ASIO_ENABLE_CANCELIO)
+ if (impl.safe_cancellation_thread_id_ == 0)
+ impl.safe_cancellation_thread_id_ = ::GetCurrentThreadId();
+ else if (impl.safe_cancellation_thread_id_ != ::GetCurrentThreadId())
+ impl.safe_cancellation_thread_id_ = ~DWORD(0);
+#else // defined(ASIO_ENABLE_CANCELIO)
+ (void)impl;
+#endif // defined(ASIO_ENABLE_CANCELIO)
+}
+
+select_reactor& win_iocp_socket_service_base::get_reactor()
+{
+ select_reactor* r = static_cast<select_reactor*>(
+ interlocked_compare_exchange_pointer(
+ reinterpret_cast<void**>(&reactor_), 0, 0));
+ if (!r)
+ {
+ r = &(use_service<select_reactor>(io_context_));
+ interlocked_exchange_pointer(reinterpret_cast<void**>(&reactor_), r);
+ }
+ return *r;
+}
+
+win_iocp_socket_service_base::connect_ex_fn
+win_iocp_socket_service_base::get_connect_ex(
+ win_iocp_socket_service_base::base_implementation_type& impl, int type)
+{
+#if defined(ASIO_DISABLE_CONNECTEX)
+ (void)impl;
+ (void)type;
+ return 0;
+#else // defined(ASIO_DISABLE_CONNECTEX)
+ if (type != ASIO_OS_DEF(SOCK_STREAM)
+ && type != ASIO_OS_DEF(SOCK_SEQPACKET))
+ return 0;
+
+ void* ptr = interlocked_compare_exchange_pointer(&connect_ex_, 0, 0);
+ if (!ptr)
+ {
+ GUID guid = { 0x25a207b9, 0xddf3, 0x4660,
+ { 0x8e, 0xe9, 0x76, 0xe5, 0x8c, 0x74, 0x06, 0x3e } };
+
+ DWORD bytes = 0;
+ if (::WSAIoctl(impl.socket_, SIO_GET_EXTENSION_FUNCTION_POINTER,
+ &guid, sizeof(guid), &ptr, sizeof(ptr), &bytes, 0, 0) != 0)
+ {
+ // Set connect_ex_ to a special value to indicate that ConnectEx is
+ // unavailable. That way we won't bother trying to look it up again.
+ ptr = this;
+ }
+
+ interlocked_exchange_pointer(&connect_ex_, ptr);
+ }
+
+ return reinterpret_cast<connect_ex_fn>(ptr == this ? 0 : ptr);
+#endif // defined(ASIO_DISABLE_CONNECTEX)
+}
+
+win_iocp_socket_service_base::nt_set_info_fn
+win_iocp_socket_service_base::get_nt_set_info()
+{
+ void* ptr = interlocked_compare_exchange_pointer(&nt_set_info_, 0, 0);
+ if (!ptr)
+ {
+ if (HMODULE h = ::GetModuleHandleA("NTDLL.DLL"))
+ ptr = reinterpret_cast<void*>(GetProcAddress(h, "NtSetInformationFile"));
+
+ // On failure, set nt_set_info_ to a special value to indicate that the
+ // NtSetInformationFile function is unavailable. That way we won't bother
+ // trying to look it up again.
+ interlocked_exchange_pointer(&nt_set_info_, ptr ? ptr : this);
+ }
+
+ return reinterpret_cast<nt_set_info_fn>(ptr == this ? 0 : ptr);
+}
+
+void* win_iocp_socket_service_base::interlocked_compare_exchange_pointer(
+ void** dest, void* exch, void* cmp)
+{
+#if defined(_M_IX86)
+ return reinterpret_cast<void*>(InterlockedCompareExchange(
+ reinterpret_cast<PLONG>(dest), reinterpret_cast<LONG>(exch),
+ reinterpret_cast<LONG>(cmp)));
+#else
+ return InterlockedCompareExchangePointer(dest, exch, cmp);
+#endif
+}
+
+void* win_iocp_socket_service_base::interlocked_exchange_pointer(
+ void** dest, void* val)
+{
+#if defined(_M_IX86)
+ return reinterpret_cast<void*>(InterlockedExchange(
+ reinterpret_cast<PLONG>(dest), reinterpret_cast<LONG>(val)));
+#else
+ return InterlockedExchangePointer(dest, val);
+#endif
+}
+
+} // namespace detail
+} // namespace asio
+
+#include "asio/detail/pop_options.hpp"
+
+#endif // defined(ASIO_HAS_IOCP)
+
+#endif // ASIO_DETAIL_IMPL_WIN_IOCP_SOCKET_SERVICE_BASE_IPP
diff --git a/lib/asio/detail/impl/win_mutex.ipp b/lib/asio/detail/impl/win_mutex.ipp
new file mode 100644
index 0000000..dc58a12
--- /dev/null
+++ b/lib/asio/detail/impl/win_mutex.ipp
@@ -0,0 +1,84 @@
+//
+// detail/impl/win_mutex.ipp
+// ~~~~~~~~~~~~~~~~~~~~~~~~~
+//
+// Copyright (c) 2003-2018 Christopher M. Kohlhoff (chris at kohlhoff dot com)
+//
+// 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 ASIO_DETAIL_IMPL_WIN_MUTEX_IPP
+#define ASIO_DETAIL_IMPL_WIN_MUTEX_IPP
+
+#if defined(_MSC_VER) && (_MSC_VER >= 1200)
+# pragma once
+#endif // defined(_MSC_VER) && (_MSC_VER >= 1200)
+
+#include "asio/detail/config.hpp"
+
+#if defined(ASIO_WINDOWS)
+
+#include "asio/detail/throw_error.hpp"
+#include "asio/detail/win_mutex.hpp"
+#include "asio/error.hpp"
+
+#include "asio/detail/push_options.hpp"
+
+namespace asio {
+namespace detail {
+
+win_mutex::win_mutex()
+{
+ int error = do_init();
+ asio::error_code ec(error,
+ asio::error::get_system_category());
+ asio::detail::throw_error(ec, "mutex");
+}
+
+int win_mutex::do_init()
+{
+#if defined(__MINGW32__)
+ // Not sure if MinGW supports structured exception handling, so for now
+ // we'll just call the Windows API and hope.
+# if defined(UNDER_CE)
+ ::InitializeCriticalSection(&crit_section_);
+# elif defined(ASIO_WINDOWS_APP)
+ if (!::InitializeCriticalSectionEx(&crit_section_, 0, 0))
+ return ::GetLastError();
+# else
+ if (!::InitializeCriticalSectionAndSpinCount(&crit_section_, 0x80000000))
+ return ::GetLastError();
+# endif
+ return 0;
+#else
+ __try
+ {
+# if defined(UNDER_CE)
+ ::InitializeCriticalSection(&crit_section_);
+# elif defined(ASIO_WINDOWS_APP)
+ if (!::InitializeCriticalSectionEx(&crit_section_, 0, 0))
+ return ::GetLastError();
+# else
+ if (!::InitializeCriticalSectionAndSpinCount(&crit_section_, 0x80000000))
+ return ::GetLastError();
+# endif
+ }
+ __except(GetExceptionCode() == STATUS_NO_MEMORY
+ ? EXCEPTION_EXECUTE_HANDLER : EXCEPTION_CONTINUE_SEARCH)
+ {
+ return ERROR_OUTOFMEMORY;
+ }
+
+ return 0;
+#endif
+}
+
+} // namespace detail
+} // namespace asio
+
+#include "asio/detail/pop_options.hpp"
+
+#endif // defined(ASIO_WINDOWS)
+
+#endif // ASIO_DETAIL_IMPL_WIN_MUTEX_IPP
diff --git a/lib/asio/detail/impl/win_object_handle_service.ipp b/lib/asio/detail/impl/win_object_handle_service.ipp
new file mode 100644
index 0000000..c5e59d1
--- /dev/null
+++ b/lib/asio/detail/impl/win_object_handle_service.ipp
@@ -0,0 +1,449 @@
+//
+// detail/impl/win_object_handle_service.ipp
+// ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+//
+// Copyright (c) 2003-2018 Christopher M. Kohlhoff (chris at kohlhoff dot com)
+// Copyright (c) 2011 Boris Schaeling (boris@highscore.de)
+//
+// 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 ASIO_DETAIL_IMPL_WIN_OBJECT_HANDLE_SERVICE_IPP
+#define ASIO_DETAIL_IMPL_WIN_OBJECT_HANDLE_SERVICE_IPP
+
+#if defined(_MSC_VER) && (_MSC_VER >= 1200)
+# pragma once
+#endif // defined(_MSC_VER) && (_MSC_VER >= 1200)
+
+#include "asio/detail/config.hpp"
+
+#if defined(ASIO_HAS_WINDOWS_OBJECT_HANDLE)
+
+#include "asio/detail/win_object_handle_service.hpp"
+
+#include "asio/detail/push_options.hpp"
+
+namespace asio {
+namespace detail {
+
+win_object_handle_service::win_object_handle_service(
+ asio::io_context& io_context)
+ : service_base<win_object_handle_service>(io_context),
+ io_context_(asio::use_service<io_context_impl>(io_context)),
+ mutex_(),
+ impl_list_(0),
+ shutdown_(false)
+{
+}
+
+void win_object_handle_service::shutdown()
+{
+ mutex::scoped_lock lock(mutex_);
+
+ // Setting this flag to true prevents new objects from being registered, and
+ // new asynchronous wait operations from being started. We only need to worry
+ // about cleaning up the operations that are currently in progress.
+ shutdown_ = true;
+
+ op_queue<operation> ops;
+ for (implementation_type* impl = impl_list_; impl; impl = impl->next_)
+ ops.push(impl->op_queue_);
+
+ lock.unlock();
+
+ io_context_.abandon_operations(ops);
+}
+
+void win_object_handle_service::construct(
+ win_object_handle_service::implementation_type& impl)
+{
+ impl.handle_ = INVALID_HANDLE_VALUE;
+ impl.wait_handle_ = INVALID_HANDLE_VALUE;
+ impl.owner_ = this;
+
+ // Insert implementation into linked list of all implementations.
+ mutex::scoped_lock lock(mutex_);
+ if (!shutdown_)
+ {
+ impl.next_ = impl_list_;
+ impl.prev_ = 0;
+ if (impl_list_)
+ impl_list_->prev_ = &impl;
+ impl_list_ = &impl;
+ }
+}
+
+void win_object_handle_service::move_construct(
+ win_object_handle_service::implementation_type& impl,
+ win_object_handle_service::implementation_type& other_impl)
+{
+ mutex::scoped_lock lock(mutex_);
+
+ // Insert implementation into linked list of all implementations.
+ if (!shutdown_)
+ {
+ impl.next_ = impl_list_;
+ impl.prev_ = 0;
+ if (impl_list_)
+ impl_list_->prev_ = &impl;
+ impl_list_ = &impl;
+ }
+
+ impl.handle_ = other_impl.handle_;
+ other_impl.handle_ = INVALID_HANDLE_VALUE;
+ impl.wait_handle_ = other_impl.wait_handle_;
+ other_impl.wait_handle_ = INVALID_HANDLE_VALUE;
+ impl.op_queue_.push(other_impl.op_queue_);
+ impl.owner_ = this;
+
+ // We must not hold the lock while calling UnregisterWaitEx. This is because
+ // the registered callback function might be invoked while we are waiting for
+ // UnregisterWaitEx to complete.
+ lock.unlock();
+
+ if (impl.wait_handle_ != INVALID_HANDLE_VALUE)
+ ::UnregisterWaitEx(impl.wait_handle_, INVALID_HANDLE_VALUE);
+
+ if (!impl.op_queue_.empty())
+ register_wait_callback(impl, lock);
+}
+
+void win_object_handle_service::move_assign(
+ win_object_handle_service::implementation_type& impl,
+ win_object_handle_service& other_service,
+ win_object_handle_service::implementation_type& other_impl)
+{
+ asio::error_code ignored_ec;
+ close(impl, ignored_ec);
+
+ mutex::scoped_lock lock(mutex_);
+
+ if (this != &other_service)
+ {
+ // Remove implementation from linked list of all implementations.
+ if (impl_list_ == &impl)
+ impl_list_ = impl.next_;
+ if (impl.prev_)
+ impl.prev_->next_ = impl.next_;
+ if (impl.next_)
+ impl.next_->prev_= impl.prev_;
+ impl.next_ = 0;
+ impl.prev_ = 0;
+ }
+
+ impl.handle_ = other_impl.handle_;
+ other_impl.handle_ = INVALID_HANDLE_VALUE;
+ impl.wait_handle_ = other_impl.wait_handle_;
+ other_impl.wait_handle_ = INVALID_HANDLE_VALUE;
+ impl.op_queue_.push(other_impl.op_queue_);
+ impl.owner_ = this;
+
+ if (this != &other_service)
+ {
+ // Insert implementation into linked list of all implementations.
+ impl.next_ = other_service.impl_list_;
+ impl.prev_ = 0;
+ if (other_service.impl_list_)
+ other_service.impl_list_->prev_ = &impl;
+ other_service.impl_list_ = &impl;
+ }
+
+ // We must not hold the lock while calling UnregisterWaitEx. This is because
+ // the registered callback function might be invoked while we are waiting for
+ // UnregisterWaitEx to complete.
+ lock.unlock();
+
+ if (impl.wait_handle_ != INVALID_HANDLE_VALUE)
+ ::UnregisterWaitEx(impl.wait_handle_, INVALID_HANDLE_VALUE);
+
+ if (!impl.op_queue_.empty())
+ register_wait_callback(impl, lock);
+}
+
+void win_object_handle_service::destroy(
+ win_object_handle_service::implementation_type& impl)
+{
+ mutex::scoped_lock lock(mutex_);
+
+ // Remove implementation from linked list of all implementations.
+ if (impl_list_ == &impl)
+ impl_list_ = impl.next_;
+ if (impl.prev_)
+ impl.prev_->next_ = impl.next_;
+ if (impl.next_)
+ impl.next_->prev_= impl.prev_;
+ impl.next_ = 0;
+ impl.prev_ = 0;
+
+ if (is_open(impl))
+ {
+ ASIO_HANDLER_OPERATION((io_context_.context(), "object_handle",
+ &impl, reinterpret_cast<uintmax_t>(impl.wait_handle_), "close"));
+
+ HANDLE wait_handle = impl.wait_handle_;
+ impl.wait_handle_ = INVALID_HANDLE_VALUE;
+
+ op_queue<operation> ops;
+ while (wait_op* op = impl.op_queue_.front())
+ {
+ op->ec_ = asio::error::operation_aborted;
+ impl.op_queue_.pop();
+ ops.push(op);
+ }
+
+ // We must not hold the lock while calling UnregisterWaitEx. This is
+ // because the registered callback function might be invoked while we are
+ // waiting for UnregisterWaitEx to complete.
+ lock.unlock();
+
+ if (wait_handle != INVALID_HANDLE_VALUE)
+ ::UnregisterWaitEx(wait_handle, INVALID_HANDLE_VALUE);
+
+ ::CloseHandle(impl.handle_);
+ impl.handle_ = INVALID_HANDLE_VALUE;
+
+ io_context_.post_deferred_completions(ops);
+ }
+}
+
+asio::error_code win_object_handle_service::assign(
+ win_object_handle_service::implementation_type& impl,
+ const native_handle_type& handle, asio::error_code& ec)
+{
+ if (is_open(impl))
+ {
+ ec = asio::error::already_open;
+ return ec;
+ }
+
+ impl.handle_ = handle;
+ ec = asio::error_code();
+ return ec;
+}
+
+asio::error_code win_object_handle_service::close(
+ win_object_handle_service::implementation_type& impl,
+ asio::error_code& ec)
+{
+ if (is_open(impl))
+ {
+ ASIO_HANDLER_OPERATION((io_context_.context(), "object_handle",
+ &impl, reinterpret_cast<uintmax_t>(impl.wait_handle_), "close"));
+
+ mutex::scoped_lock lock(mutex_);
+
+ HANDLE wait_handle = impl.wait_handle_;
+ impl.wait_handle_ = INVALID_HANDLE_VALUE;
+
+ op_queue<operation> completed_ops;
+ while (wait_op* op = impl.op_queue_.front())
+ {
+ impl.op_queue_.pop();
+ op->ec_ = asio::error::operation_aborted;
+ completed_ops.push(op);
+ }
+
+ // We must not hold the lock while calling UnregisterWaitEx. This is
+ // because the registered callback function might be invoked while we are
+ // waiting for UnregisterWaitEx to complete.
+ lock.unlock();
+
+ if (wait_handle != INVALID_HANDLE_VALUE)
+ ::UnregisterWaitEx(wait_handle, INVALID_HANDLE_VALUE);
+
+ if (::CloseHandle(impl.handle_))
+ {
+ impl.handle_ = INVALID_HANDLE_VALUE;
+ ec = asio::error_code();
+ }
+ else
+ {
+ DWORD last_error = ::GetLastError();
+ ec = asio::error_code(last_error,
+ asio::error::get_system_category());
+ }
+
+ io_context_.post_deferred_completions(completed_ops);
+ }
+ else
+ {
+ ec = asio::error_code();
+ }
+
+ return ec;
+}
+
+asio::error_code win_object_handle_service::cancel(
+ win_object_handle_service::implementation_type& impl,
+ asio::error_code& ec)
+{
+ if (is_open(impl))
+ {
+ ASIO_HANDLER_OPERATION((io_context_.context(), "object_handle",
+ &impl, reinterpret_cast<uintmax_t>(impl.wait_handle_), "cancel"));
+
+ mutex::scoped_lock lock(mutex_);
+
+ HANDLE wait_handle = impl.wait_handle_;
+ impl.wait_handle_ = INVALID_HANDLE_VALUE;
+
+ op_queue<operation> completed_ops;
+ while (wait_op* op = impl.op_queue_.front())
+ {
+ op->ec_ = asio::error::operation_aborted;
+ impl.op_queue_.pop();
+ completed_ops.push(op);
+ }
+
+ // We must not hold the lock while calling UnregisterWaitEx. This is
+ // because the registered callback function might be invoked while we are
+ // waiting for UnregisterWaitEx to complete.
+ lock.unlock();
+
+ if (wait_handle != INVALID_HANDLE_VALUE)
+ ::UnregisterWaitEx(wait_handle, INVALID_HANDLE_VALUE);
+
+ ec = asio::error_code();
+
+ io_context_.post_deferred_completions(completed_ops);
+ }
+ else
+ {
+ ec = asio::error::bad_descriptor;
+ }
+
+ return ec;
+}
+
+void win_object_handle_service::wait(
+ win_object_handle_service::implementation_type& impl,
+ asio::error_code& ec)
+{
+ switch (::WaitForSingleObject(impl.handle_, INFINITE))
+ {
+ case WAIT_FAILED:
+ {
+ DWORD last_error = ::GetLastError();
+ ec = asio::error_code(last_error,
+ asio::error::get_system_category());
+ break;
+ }
+ case WAIT_OBJECT_0:
+ case WAIT_ABANDONED:
+ default:
+ ec = asio::error_code();
+ break;
+ }
+}
+
+void win_object_handle_service::start_wait_op(
+ win_object_handle_service::implementation_type& impl, wait_op* op)
+{
+ io_context_.work_started();
+
+ if (is_open(impl))
+ {
+ mutex::scoped_lock lock(mutex_);
+
+ if (!shutdown_)
+ {
+ impl.op_queue_.push(op);
+
+ // Only the first operation to be queued gets to register a wait callback.
+ // Subsequent operations have to wait for the first to finish.
+ if (impl.op_queue_.front() == op)
+ register_wait_callback(impl, lock);
+ }
+ else
+ {
+ lock.unlock();
+ io_context_.post_deferred_completion(op);
+ }
+ }
+ else
+ {
+ op->ec_ = asio::error::bad_descriptor;
+ io_context_.post_deferred_completion(op);
+ }
+}
+
+void win_object_handle_service::register_wait_callback(
+ win_object_handle_service::implementation_type& impl,
+ mutex::scoped_lock& lock)
+{
+ lock.lock();
+
+ if (!RegisterWaitForSingleObject(&impl.wait_handle_,
+ impl.handle_, &win_object_handle_service::wait_callback,
+ &impl, INFINITE, WT_EXECUTEONLYONCE))
+ {
+ DWORD last_error = ::GetLastError();
+ asio::error_code ec(last_error,
+ asio::error::get_system_category());
+
+ op_queue<operation> completed_ops;
+ while (wait_op* op = impl.op_queue_.front())
+ {
+ op->ec_ = ec;
+ impl.op_queue_.pop();
+ completed_ops.push(op);
+ }
+
+ lock.unlock();
+ io_context_.post_deferred_completions(completed_ops);
+ }
+}
+
+void win_object_handle_service::wait_callback(PVOID param, BOOLEAN)
+{
+ implementation_type* impl = static_cast<implementation_type*>(param);
+ mutex::scoped_lock lock(impl->owner_->mutex_);
+
+ if (impl->wait_handle_ != INVALID_HANDLE_VALUE)
+ {
+ ::UnregisterWaitEx(impl->wait_handle_, NULL);
+ impl->wait_handle_ = INVALID_HANDLE_VALUE;
+ }
+
+ if (wait_op* op = impl->op_queue_.front())
+ {
+ op_queue<operation> completed_ops;
+
+ op->ec_ = asio::error_code();
+ impl->op_queue_.pop();
+ completed_ops.push(op);
+
+ if (!impl->op_queue_.empty())
+ {
+ if (!RegisterWaitForSingleObject(&impl->wait_handle_,
+ impl->handle_, &win_object_handle_service::wait_callback,
+ param, INFINITE, WT_EXECUTEONLYONCE))
+ {
+ DWORD last_error = ::GetLastError();
+ asio::error_code ec(last_error,
+ asio::error::get_system_category());
+
+ while ((op = impl->op_queue_.front()) != 0)
+ {
+ op->ec_ = ec;
+ impl->op_queue_.pop();
+ completed_ops.push(op);
+ }
+ }
+ }
+
+ io_context_impl& ioc = impl->owner_->io_context_;
+ lock.unlock();
+ ioc.post_deferred_completions(completed_ops);
+ }
+}
+
+} // namespace detail
+} // namespace asio
+
+#include "asio/detail/pop_options.hpp"
+
+#endif // defined(ASIO_HAS_WINDOWS_OBJECT_HANDLE)
+
+#endif // ASIO_DETAIL_IMPL_WIN_OBJECT_HANDLE_SERVICE_IPP
diff --git a/lib/asio/detail/impl/win_static_mutex.ipp b/lib/asio/detail/impl/win_static_mutex.ipp
new file mode 100644
index 0000000..42089bd
--- /dev/null
+++ b/lib/asio/detail/impl/win_static_mutex.ipp
@@ -0,0 +1,136 @@
+//
+// detail/impl/win_static_mutex.ipp
+// ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+//
+// Copyright (c) 2003-2018 Christopher M. Kohlhoff (chris at kohlhoff dot com)
+//
+// 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 ASIO_DETAIL_IMPL_WIN_STATIC_MUTEX_IPP
+#define ASIO_DETAIL_IMPL_WIN_STATIC_MUTEX_IPP
+
+#if defined(_MSC_VER) && (_MSC_VER >= 1200)
+# pragma once
+#endif // defined(_MSC_VER) && (_MSC_VER >= 1200)
+
+#include "asio/detail/config.hpp"
+
+#if defined(ASIO_WINDOWS)
+
+#include <cstdio>
+#include "asio/detail/throw_error.hpp"
+#include "asio/detail/win_static_mutex.hpp"
+#include "asio/error.hpp"
+
+#include "asio/detail/push_options.hpp"
+
+namespace asio {
+namespace detail {
+
+void win_static_mutex::init()
+{
+ int error = do_init();
+ asio::error_code ec(error,
+ asio::error::get_system_category());
+ asio::detail::throw_error(ec, "static_mutex");
+}
+
+int win_static_mutex::do_init()
+{
+ using namespace std; // For sprintf.
+ wchar_t mutex_name[128];
+#if defined(ASIO_HAS_SECURE_RTL)
+ swprintf_s(
+#else // defined(ASIO_HAS_SECURE_RTL)
+ _snwprintf(
+#endif // defined(ASIO_HAS_SECURE_RTL)
+ mutex_name, 128, L"asio-58CCDC44-6264-4842-90C2-F3C545CB8AA7-%u-%p",
+ static_cast<unsigned int>(::GetCurrentProcessId()), this);
+
+#if defined(ASIO_WINDOWS_APP)
+ HANDLE mutex = ::CreateMutexExW(0, mutex_name, CREATE_MUTEX_INITIAL_OWNER, 0);
+#else // defined(ASIO_WINDOWS_APP)
+ HANDLE mutex = ::CreateMutexW(0, TRUE, mutex_name);
+#endif // defined(ASIO_WINDOWS_APP)
+ DWORD last_error = ::GetLastError();
+ if (mutex == 0)
+ return ::GetLastError();
+
+ if (last_error == ERROR_ALREADY_EXISTS)
+ {
+#if defined(ASIO_WINDOWS_APP)
+ ::WaitForSingleObjectEx(mutex, INFINITE, false);
+#else // defined(ASIO_WINDOWS_APP)
+ ::WaitForSingleObject(mutex, INFINITE);
+#endif // defined(ASIO_WINDOWS_APP)
+ }
+
+ if (initialised_)
+ {
+ ::ReleaseMutex(mutex);
+ ::CloseHandle(mutex);
+ return 0;
+ }
+
+#if defined(__MINGW32__)
+ // Not sure if MinGW supports structured exception handling, so for now
+ // we'll just call the Windows API and hope.
+# if defined(UNDER_CE)
+ ::InitializeCriticalSection(&crit_section_);
+# else
+ if (!::InitializeCriticalSectionAndSpinCount(&crit_section_, 0x80000000))
+ {
+ last_error = ::GetLastError();
+ ::ReleaseMutex(mutex);
+ ::CloseHandle(mutex);
+ return last_error;
+ }
+# endif
+#else
+ __try
+ {
+# if defined(UNDER_CE)
+ ::InitializeCriticalSection(&crit_section_);
+# elif defined(ASIO_WINDOWS_APP)
+ if (!::InitializeCriticalSectionEx(&crit_section_, 0, 0))
+ {
+ last_error = ::GetLastError();
+ ::ReleaseMutex(mutex);
+ ::CloseHandle(mutex);
+ return last_error;
+ }
+# else
+ if (!::InitializeCriticalSectionAndSpinCount(&crit_section_, 0x80000000))
+ {
+ last_error = ::GetLastError();
+ ::ReleaseMutex(mutex);
+ ::CloseHandle(mutex);
+ return last_error;
+ }
+# endif
+ }
+ __except(GetExceptionCode() == STATUS_NO_MEMORY
+ ? EXCEPTION_EXECUTE_HANDLER : EXCEPTION_CONTINUE_SEARCH)
+ {
+ ::ReleaseMutex(mutex);
+ ::CloseHandle(mutex);
+ return ERROR_OUTOFMEMORY;
+ }
+#endif
+
+ initialised_ = true;
+ ::ReleaseMutex(mutex);
+ ::CloseHandle(mutex);
+ return 0;
+}
+
+} // namespace detail
+} // namespace asio
+
+#include "asio/detail/pop_options.hpp"
+
+#endif // defined(ASIO_WINDOWS)
+
+#endif // ASIO_DETAIL_IMPL_WIN_STATIC_MUTEX_IPP
diff --git a/lib/asio/detail/impl/win_thread.ipp b/lib/asio/detail/impl/win_thread.ipp
new file mode 100644
index 0000000..ed6dbaf
--- /dev/null
+++ b/lib/asio/detail/impl/win_thread.ipp
@@ -0,0 +1,150 @@
+//
+// detail/impl/win_thread.ipp
+// ~~~~~~~~~~~~~~~~~~~~~~~~~~
+//
+// Copyright (c) 2003-2018 Christopher M. Kohlhoff (chris at kohlhoff dot com)
+//
+// 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 ASIO_DETAIL_IMPL_WIN_THREAD_IPP
+#define ASIO_DETAIL_IMPL_WIN_THREAD_IPP
+
+#if defined(_MSC_VER) && (_MSC_VER >= 1200)
+# pragma once
+#endif // defined(_MSC_VER) && (_MSC_VER >= 1200)
+
+#include "asio/detail/config.hpp"
+
+#if defined(ASIO_WINDOWS) \
+ && !defined(ASIO_WINDOWS_APP) \
+ && !defined(UNDER_CE)
+
+#include <process.h>
+#include "asio/detail/throw_error.hpp"
+#include "asio/detail/win_thread.hpp"
+#include "asio/error.hpp"
+
+#include "asio/detail/push_options.hpp"
+
+namespace asio {
+namespace detail {
+
+win_thread::~win_thread()
+{
+ ::CloseHandle(thread_);
+
+ // The exit_event_ handle is deliberately allowed to leak here since it
+ // is an error for the owner of an internal thread not to join() it.
+}
+
+void win_thread::join()
+{
+ HANDLE handles[2] = { exit_event_, thread_ };
+ ::WaitForMultipleObjects(2, handles, FALSE, INFINITE);
+ ::CloseHandle(exit_event_);
+ if (terminate_threads())
+ {
+ ::TerminateThread(thread_, 0);
+ }
+ else
+ {
+ ::QueueUserAPC(apc_function, thread_, 0);
+ ::WaitForSingleObject(thread_, INFINITE);
+ }
+}
+
+std::size_t win_thread::hardware_concurrency()
+{
+ SYSTEM_INFO system_info;
+ ::GetSystemInfo(&system_info);
+ return system_info.dwNumberOfProcessors;
+}
+
+void win_thread::start_thread(func_base* arg, unsigned int stack_size)
+{
+ ::HANDLE entry_event = 0;
+ arg->entry_event_ = entry_event = ::CreateEventW(0, true, false, 0);
+ if (!entry_event)
+ {
+ DWORD last_error = ::GetLastError();
+ delete arg;
+ asio::error_code ec(last_error,
+ asio::error::get_system_category());
+ asio::detail::throw_error(ec, "thread.entry_event");
+ }
+
+ arg->exit_event_ = exit_event_ = ::CreateEventW(0, true, false, 0);
+ if (!exit_event_)
+ {
+ DWORD last_error = ::GetLastError();
+ delete arg;
+ asio::error_code ec(last_error,
+ asio::error::get_system_category());
+ asio::detail::throw_error(ec, "thread.exit_event");
+ }
+
+ unsigned int thread_id = 0;
+ thread_ = reinterpret_cast<HANDLE>(::_beginthreadex(0,
+ stack_size, win_thread_function, arg, 0, &thread_id));
+ if (!thread_)
+ {
+ DWORD last_error = ::GetLastError();
+ delete arg;
+ if (entry_event)
+ ::CloseHandle(entry_event);
+ if (exit_event_)
+ ::CloseHandle(exit_event_);
+ asio::error_code ec(last_error,
+ asio::error::get_system_category());
+ asio::detail::throw_error(ec, "thread");
+ }
+
+ if (entry_event)
+ {
+ ::WaitForSingleObject(entry_event, INFINITE);
+ ::CloseHandle(entry_event);
+ }
+}
+
+unsigned int __stdcall win_thread_function(void* arg)
+{
+ win_thread::auto_func_base_ptr func = {
+ static_cast<win_thread::func_base*>(arg) };
+
+ ::SetEvent(func.ptr->entry_event_);
+
+ func.ptr->run();
+
+ // Signal that the thread has finished its work, but rather than returning go
+ // to sleep to put the thread into a well known state. If the thread is being
+ // joined during global object destruction then it may be killed using
+ // TerminateThread (to avoid a deadlock in DllMain). Otherwise, the SleepEx
+ // call will be interrupted using QueueUserAPC and the thread will shut down
+ // cleanly.
+ HANDLE exit_event = func.ptr->exit_event_;
+ delete func.ptr;
+ func.ptr = 0;
+ ::SetEvent(exit_event);
+ ::SleepEx(INFINITE, TRUE);
+
+ return 0;
+}
+
+#if defined(WINVER) && (WINVER < 0x0500)
+void __stdcall apc_function(ULONG) {}
+#else
+void __stdcall apc_function(ULONG_PTR) {}
+#endif
+
+} // namespace detail
+} // namespace asio
+
+#include "asio/detail/pop_options.hpp"
+
+#endif // defined(ASIO_WINDOWS)
+ // && !defined(ASIO_WINDOWS_APP)
+ // && !defined(UNDER_CE)
+
+#endif // ASIO_DETAIL_IMPL_WIN_THREAD_IPP
diff --git a/lib/asio/detail/impl/win_tss_ptr.ipp b/lib/asio/detail/impl/win_tss_ptr.ipp
new file mode 100644
index 0000000..61df0ce
--- /dev/null
+++ b/lib/asio/detail/impl/win_tss_ptr.ipp
@@ -0,0 +1,57 @@
+//
+// detail/impl/win_tss_ptr.ipp
+// ~~~~~~~~~~~~~~~~~~~~~~~~~~~
+//
+// Copyright (c) 2003-2018 Christopher M. Kohlhoff (chris at kohlhoff dot com)
+//
+// 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 ASIO_DETAIL_IMPL_WIN_TSS_PTR_IPP
+#define ASIO_DETAIL_IMPL_WIN_TSS_PTR_IPP
+
+#if defined(_MSC_VER) && (_MSC_VER >= 1200)
+# pragma once
+#endif // defined(_MSC_VER) && (_MSC_VER >= 1200)
+
+#include "asio/detail/config.hpp"
+
+#if defined(ASIO_WINDOWS)
+
+#include "asio/detail/throw_error.hpp"
+#include "asio/detail/win_tss_ptr.hpp"
+#include "asio/error.hpp"
+
+#include "asio/detail/push_options.hpp"
+
+namespace asio {
+namespace detail {
+
+DWORD win_tss_ptr_create()
+{
+#if defined(UNDER_CE)
+ const DWORD out_of_indexes = 0xFFFFFFFF;
+#else
+ const DWORD out_of_indexes = TLS_OUT_OF_INDEXES;
+#endif
+
+ DWORD tss_key = ::TlsAlloc();
+ if (tss_key == out_of_indexes)
+ {
+ DWORD last_error = ::GetLastError();
+ asio::error_code ec(last_error,
+ asio::error::get_system_category());
+ asio::detail::throw_error(ec, "tss");
+ }
+ return tss_key;
+}
+
+} // namespace detail
+} // namespace asio
+
+#include "asio/detail/pop_options.hpp"
+
+#endif // defined(ASIO_WINDOWS)
+
+#endif // ASIO_DETAIL_IMPL_WIN_TSS_PTR_IPP
diff --git a/lib/asio/detail/impl/winrt_ssocket_service_base.ipp b/lib/asio/detail/impl/winrt_ssocket_service_base.ipp
new file mode 100644
index 0000000..288ca8b
--- /dev/null
+++ b/lib/asio/detail/impl/winrt_ssocket_service_base.ipp
@@ -0,0 +1,629 @@
+//
+// detail/impl/winrt_ssocket_service_base.ipp
+// ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+//
+// Copyright (c) 2003-2018 Christopher M. Kohlhoff (chris at kohlhoff dot com)
+//
+// 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 ASIO_DETAIL_IMPL_WINRT_SSOCKET_SERVICE_BASE_IPP
+#define ASIO_DETAIL_IMPL_WINRT_SSOCKET_SERVICE_BASE_IPP
+
+#if defined(_MSC_VER) && (_MSC_VER >= 1200)
+# pragma once
+#endif // defined(_MSC_VER) && (_MSC_VER >= 1200)
+
+#include "asio/detail/config.hpp"
+
+#if defined(ASIO_WINDOWS_RUNTIME)
+
+#include <cstring>
+#include "asio/detail/winrt_ssocket_service_base.hpp"
+#include "asio/detail/winrt_async_op.hpp"
+#include "asio/detail/winrt_utils.hpp"
+
+#include "asio/detail/push_options.hpp"
+
+namespace asio {
+namespace detail {
+
+winrt_ssocket_service_base::winrt_ssocket_service_base(
+ asio::io_context& io_context)
+ : io_context_(use_service<io_context_impl>(io_context)),
+ async_manager_(use_service<winrt_async_manager>(io_context)),
+ mutex_(),
+ impl_list_(0)
+{
+}
+
+void winrt_ssocket_service_base::base_shutdown()
+{
+ // Close all implementations, causing all operations to complete.
+ asio::detail::mutex::scoped_lock lock(mutex_);
+ base_implementation_type* impl = impl_list_;
+ while (impl)
+ {
+ asio::error_code ignored_ec;
+ close(*impl, ignored_ec);
+ impl = impl->next_;
+ }
+}
+
+void winrt_ssocket_service_base::construct(
+ winrt_ssocket_service_base::base_implementation_type& impl)
+{
+ // Insert implementation into linked list of all implementations.
+ asio::detail::mutex::scoped_lock lock(mutex_);
+ impl.next_ = impl_list_;
+ impl.prev_ = 0;
+ if (impl_list_)
+ impl_list_->prev_ = &impl;
+ impl_list_ = &impl;
+}
+
+void winrt_ssocket_service_base::base_move_construct(
+ winrt_ssocket_service_base::base_implementation_type& impl,
+ winrt_ssocket_service_base::base_implementation_type& other_impl)
+{
+ impl.socket_ = other_impl.socket_;
+ other_impl.socket_ = nullptr;
+
+ // Insert implementation into linked list of all implementations.
+ asio::detail::mutex::scoped_lock lock(mutex_);
+ impl.next_ = impl_list_;
+ impl.prev_ = 0;
+ if (impl_list_)
+ impl_list_->prev_ = &impl;
+ impl_list_ = &impl;
+}
+
+void winrt_ssocket_service_base::base_move_assign(
+ winrt_ssocket_service_base::base_implementation_type& impl,
+ winrt_ssocket_service_base& other_service,
+ winrt_ssocket_service_base::base_implementation_type& other_impl)
+{
+ asio::error_code ignored_ec;
+ close(impl, ignored_ec);
+
+ if (this != &other_service)
+ {
+ // Remove implementation from linked list of all implementations.
+ asio::detail::mutex::scoped_lock lock(mutex_);
+ if (impl_list_ == &impl)
+ impl_list_ = impl.next_;
+ if (impl.prev_)
+ impl.prev_->next_ = impl.next_;
+ if (impl.next_)
+ impl.next_->prev_= impl.prev_;
+ impl.next_ = 0;
+ impl.prev_ = 0;
+ }
+
+ impl.socket_ = other_impl.socket_;
+ other_impl.socket_ = nullptr;
+
+ if (this != &other_service)
+ {
+ // Insert implementation into linked list of all implementations.
+ asio::detail::mutex::scoped_lock lock(other_service.mutex_);
+ impl.next_ = other_service.impl_list_;
+ impl.prev_ = 0;
+ if (other_service.impl_list_)
+ other_service.impl_list_->prev_ = &impl;
+ other_service.impl_list_ = &impl;
+ }
+}
+
+void winrt_ssocket_service_base::destroy(
+ winrt_ssocket_service_base::base_implementation_type& impl)
+{
+ asio::error_code ignored_ec;
+ close(impl, ignored_ec);
+
+ // Remove implementation from linked list of all implementations.
+ asio::detail::mutex::scoped_lock lock(mutex_);
+ if (impl_list_ == &impl)
+ impl_list_ = impl.next_;
+ if (impl.prev_)
+ impl.prev_->next_ = impl.next_;
+ if (impl.next_)
+ impl.next_->prev_= impl.prev_;
+ impl.next_ = 0;
+ impl.prev_ = 0;
+}
+
+asio::error_code winrt_ssocket_service_base::close(
+ winrt_ssocket_service_base::base_implementation_type& impl,
+ asio::error_code& ec)
+{
+ if (impl.socket_)
+ {
+ delete impl.socket_;
+ impl.socket_ = nullptr;
+ }
+
+ ec = asio::error_code();
+ return ec;
+}
+
+winrt_ssocket_service_base::native_handle_type
+winrt_ssocket_service_base::release(
+ winrt_ssocket_service_base::base_implementation_type& impl,
+ asio::error_code& ec)
+{
+ if (!is_open(impl))
+ return nullptr;
+
+ cancel(impl, ec);
+ if (ec)
+ return nullptr;
+
+ native_handle_type tmp = impl.socket_;
+ impl.socket_ = nullptr;
+ return tmp;
+}
+
+std::size_t winrt_ssocket_service_base::do_get_endpoint(
+ const base_implementation_type& impl, bool local,
+ void* addr, std::size_t addr_len, asio::error_code& ec) const
+{
+ if (!is_open(impl))
+ {
+ ec = asio::error::bad_descriptor;
+ return addr_len;
+ }
+
+ try
+ {
+ std::string addr_string = winrt_utils::string(local
+ ? impl.socket_->Information->LocalAddress->CanonicalName
+ : impl.socket_->Information->RemoteAddress->CanonicalName);
+ unsigned short port = winrt_utils::integer(local
+ ? impl.socket_->Information->LocalPort
+ : impl.socket_->Information->RemotePort);
+ unsigned long scope = 0;
+
+ switch (reinterpret_cast<const socket_addr_type*>(addr)->sa_family)
+ {
+ case ASIO_OS_DEF(AF_INET):
+ if (addr_len < sizeof(sockaddr_in4_type))
+ {
+ ec = asio::error::invalid_argument;
+ return addr_len;
+ }
+ else
+ {
+ socket_ops::inet_pton(ASIO_OS_DEF(AF_INET), addr_string.c_str(),
+ &reinterpret_cast<sockaddr_in4_type*>(addr)->sin_addr, &scope, ec);
+ reinterpret_cast<sockaddr_in4_type*>(addr)->sin_port
+ = socket_ops::host_to_network_short(port);
+ ec = asio::error_code();
+ return sizeof(sockaddr_in4_type);
+ }
+ case ASIO_OS_DEF(AF_INET6):
+ if (addr_len < sizeof(sockaddr_in6_type))
+ {
+ ec = asio::error::invalid_argument;
+ return addr_len;
+ }
+ else
+ {
+ socket_ops::inet_pton(ASIO_OS_DEF(AF_INET6), addr_string.c_str(),
+ &reinterpret_cast<sockaddr_in6_type*>(addr)->sin6_addr, &scope, ec);
+ reinterpret_cast<sockaddr_in6_type*>(addr)->sin6_port
+ = socket_ops::host_to_network_short(port);
+ ec = asio::error_code();
+ return sizeof(sockaddr_in6_type);
+ }
+ default:
+ ec = asio::error::address_family_not_supported;
+ return addr_len;
+ }
+ }
+ catch (Platform::Exception^ e)
+ {
+ ec = asio::error_code(e->HResult,
+ asio::system_category());
+ return addr_len;
+ }
+}
+
+asio::error_code winrt_ssocket_service_base::do_set_option(
+ winrt_ssocket_service_base::base_implementation_type& impl,
+ int level, int optname, const void* optval,
+ std::size_t optlen, asio::error_code& ec)
+{
+ if (!is_open(impl))
+ {
+ ec = asio::error::bad_descriptor;
+ return ec;
+ }
+
+ try
+ {
+ if (level == ASIO_OS_DEF(SOL_SOCKET)
+ && optname == ASIO_OS_DEF(SO_KEEPALIVE))
+ {
+ if (optlen == sizeof(int))
+ {
+ int value = 0;
+ std::memcpy(&value, optval, optlen);
+ impl.socket_->Control->KeepAlive = !!value;
+ ec = asio::error_code();
+ }
+ else
+ {
+ ec = asio::error::invalid_argument;
+ }
+ }
+ else if (level == ASIO_OS_DEF(IPPROTO_TCP)
+ && optname == ASIO_OS_DEF(TCP_NODELAY))
+ {
+ if (optlen == sizeof(int))
+ {
+ int value = 0;
+ std::memcpy(&value, optval, optlen);
+ impl.socket_->Control->NoDelay = !!value;
+ ec = asio::error_code();
+ }
+ else
+ {
+ ec = asio::error::invalid_argument;
+ }
+ }
+ else
+ {
+ ec = asio::error::invalid_argument;
+ }
+ }
+ catch (Platform::Exception^ e)
+ {
+ ec = asio::error_code(e->HResult,
+ asio::system_category());
+ }
+
+ return ec;
+}
+
+void winrt_ssocket_service_base::do_get_option(
+ const winrt_ssocket_service_base::base_implementation_type& impl,
+ int level, int optname, void* optval,
+ std::size_t* optlen, asio::error_code& ec) const
+{
+ if (!is_open(impl))
+ {
+ ec = asio::error::bad_descriptor;
+ return;
+ }
+
+ try
+ {
+ if (level == ASIO_OS_DEF(SOL_SOCKET)
+ && optname == ASIO_OS_DEF(SO_KEEPALIVE))
+ {
+ if (*optlen >= sizeof(int))
+ {
+ int value = impl.socket_->Control->KeepAlive ? 1 : 0;
+ std::memcpy(optval, &value, sizeof(int));
+ *optlen = sizeof(int);
+ ec = asio::error_code();
+ }
+ else
+ {
+ ec = asio::error::invalid_argument;
+ }
+ }
+ else if (level == ASIO_OS_DEF(IPPROTO_TCP)
+ && optname == ASIO_OS_DEF(TCP_NODELAY))
+ {
+ if (*optlen >= sizeof(int))
+ {
+ int value = impl.socket_->Control->NoDelay ? 1 : 0;
+ std::memcpy(optval, &value, sizeof(int));
+ *optlen = sizeof(int);
+ ec = asio::error_code();
+ }
+ else
+ {
+ ec = asio::error::invalid_argument;
+ }
+ }
+ else
+ {
+ ec = asio::error::invalid_argument;
+ }
+ }
+ catch (Platform::Exception^ e)
+ {
+ ec = asio::error_code(e->HResult,
+ asio::system_category());
+ }
+}
+
+asio::error_code winrt_ssocket_service_base::do_connect(
+ winrt_ssocket_service_base::base_implementation_type& impl,
+ const void* addr, asio::error_code& ec)
+{
+ if (!is_open(impl))
+ {
+ ec = asio::error::bad_descriptor;
+ return ec;
+ }
+
+ char addr_string[max_addr_v6_str_len];
+ unsigned short port;
+ switch (reinterpret_cast<const socket_addr_type*>(addr)->sa_family)
+ {
+ case ASIO_OS_DEF(AF_INET):
+ socket_ops::inet_ntop(ASIO_OS_DEF(AF_INET),
+ &reinterpret_cast<const sockaddr_in4_type*>(addr)->sin_addr,
+ addr_string, sizeof(addr_string), 0, ec);
+ port = socket_ops::network_to_host_short(
+ reinterpret_cast<const sockaddr_in4_type*>(addr)->sin_port);
+ break;
+ case ASIO_OS_DEF(AF_INET6):
+ socket_ops::inet_ntop(ASIO_OS_DEF(AF_INET6),
+ &reinterpret_cast<const sockaddr_in6_type*>(addr)->sin6_addr,
+ addr_string, sizeof(addr_string), 0, ec);
+ port = socket_ops::network_to_host_short(
+ reinterpret_cast<const sockaddr_in6_type*>(addr)->sin6_port);
+ break;
+ default:
+ ec = asio::error::address_family_not_supported;
+ return ec;
+ }
+
+ if (!ec) try
+ {
+ async_manager_.sync(impl.socket_->ConnectAsync(
+ ref new Windows::Networking::HostName(
+ winrt_utils::string(addr_string)),
+ winrt_utils::string(port)), ec);
+ }
+ catch (Platform::Exception^ e)
+ {
+ ec = asio::error_code(e->HResult,
+ asio::system_category());
+ }
+
+ return ec;
+}
+
+void winrt_ssocket_service_base::start_connect_op(
+ winrt_ssocket_service_base::base_implementation_type& impl,
+ const void* addr, winrt_async_op<void>* op, bool is_continuation)
+{
+ if (!is_open(impl))
+ {
+ op->ec_ = asio::error::bad_descriptor;
+ io_context_.post_immediate_completion(op, is_continuation);
+ return;
+ }
+
+ char addr_string[max_addr_v6_str_len];
+ unsigned short port = 0;
+ switch (reinterpret_cast<const socket_addr_type*>(addr)->sa_family)
+ {
+ case ASIO_OS_DEF(AF_INET):
+ socket_ops::inet_ntop(ASIO_OS_DEF(AF_INET),
+ &reinterpret_cast<const sockaddr_in4_type*>(addr)->sin_addr,
+ addr_string, sizeof(addr_string), 0, op->ec_);
+ port = socket_ops::network_to_host_short(
+ reinterpret_cast<const sockaddr_in4_type*>(addr)->sin_port);
+ break;
+ case ASIO_OS_DEF(AF_INET6):
+ socket_ops::inet_ntop(ASIO_OS_DEF(AF_INET6),
+ &reinterpret_cast<const sockaddr_in6_type*>(addr)->sin6_addr,
+ addr_string, sizeof(addr_string), 0, op->ec_);
+ port = socket_ops::network_to_host_short(
+ reinterpret_cast<const sockaddr_in6_type*>(addr)->sin6_port);
+ break;
+ default:
+ op->ec_ = asio::error::address_family_not_supported;
+ break;
+ }
+
+ if (op->ec_)
+ {
+ io_context_.post_immediate_completion(op, is_continuation);
+ return;
+ }
+
+ try
+ {
+ async_manager_.async(impl.socket_->ConnectAsync(
+ ref new Windows::Networking::HostName(
+ winrt_utils::string(addr_string)),
+ winrt_utils::string(port)), op);
+ }
+ catch (Platform::Exception^ e)
+ {
+ op->ec_ = asio::error_code(
+ e->HResult, asio::system_category());
+ io_context_.post_immediate_completion(op, is_continuation);
+ }
+}
+
+std::size_t winrt_ssocket_service_base::do_send(
+ winrt_ssocket_service_base::base_implementation_type& impl,
+ const asio::const_buffer& data,
+ socket_base::message_flags flags, asio::error_code& ec)
+{
+ if (flags)
+ {
+ ec = asio::error::operation_not_supported;
+ return 0;
+ }
+
+ if (!is_open(impl))
+ {
+ ec = asio::error::bad_descriptor;
+ return 0;
+ }
+
+ try
+ {
+ buffer_sequence_adapter<asio::const_buffer,
+ asio::const_buffer> bufs(asio::buffer(data));
+
+ if (bufs.all_empty())
+ {
+ ec = asio::error_code();
+ return 0;
+ }
+
+ return async_manager_.sync(
+ impl.socket_->OutputStream->WriteAsync(bufs.buffers()[0]), ec);
+ }
+ catch (Platform::Exception^ e)
+ {
+ ec = asio::error_code(e->HResult,
+ asio::system_category());
+ return 0;
+ }
+}
+
+void winrt_ssocket_service_base::start_send_op(
+ winrt_ssocket_service_base::base_implementation_type& impl,
+ const asio::const_buffer& data, socket_base::message_flags flags,
+ winrt_async_op<unsigned int>* op, bool is_continuation)
+{
+ if (flags)
+ {
+ op->ec_ = asio::error::operation_not_supported;
+ io_context_.post_immediate_completion(op, is_continuation);
+ return;
+ }
+
+ if (!is_open(impl))
+ {
+ op->ec_ = asio::error::bad_descriptor;
+ io_context_.post_immediate_completion(op, is_continuation);
+ return;
+ }
+
+ try
+ {
+ buffer_sequence_adapter<asio::const_buffer,
+ asio::const_buffer> bufs(asio::buffer(data));
+
+ if (bufs.all_empty())
+ {
+ io_context_.post_immediate_completion(op, is_continuation);
+ return;
+ }
+
+ async_manager_.async(
+ impl.socket_->OutputStream->WriteAsync(bufs.buffers()[0]), op);
+ }
+ catch (Platform::Exception^ e)
+ {
+ op->ec_ = asio::error_code(e->HResult,
+ asio::system_category());
+ io_context_.post_immediate_completion(op, is_continuation);
+ }
+}
+
+std::size_t winrt_ssocket_service_base::do_receive(
+ winrt_ssocket_service_base::base_implementation_type& impl,
+ const asio::mutable_buffer& data,
+ socket_base::message_flags flags, asio::error_code& ec)
+{
+ if (flags)
+ {
+ ec = asio::error::operation_not_supported;
+ return 0;
+ }
+
+ if (!is_open(impl))
+ {
+ ec = asio::error::bad_descriptor;
+ return 0;
+ }
+
+ try
+ {
+ buffer_sequence_adapter<asio::mutable_buffer,
+ asio::mutable_buffer> bufs(asio::buffer(data));
+
+ if (bufs.all_empty())
+ {
+ ec = asio::error_code();
+ return 0;
+ }
+
+ async_manager_.sync(
+ impl.socket_->InputStream->ReadAsync(
+ bufs.buffers()[0], bufs.buffers()[0]->Capacity,
+ Windows::Storage::Streams::InputStreamOptions::Partial), ec);
+
+ std::size_t bytes_transferred = bufs.buffers()[0]->Length;
+ if (bytes_transferred == 0 && !ec)
+ {
+ ec = asio::error::eof;
+ }
+
+ return bytes_transferred;
+ }
+ catch (Platform::Exception^ e)
+ {
+ ec = asio::error_code(e->HResult,
+ asio::system_category());
+ return 0;
+ }
+}
+
+void winrt_ssocket_service_base::start_receive_op(
+ winrt_ssocket_service_base::base_implementation_type& impl,
+ const asio::mutable_buffer& data, socket_base::message_flags flags,
+ winrt_async_op<Windows::Storage::Streams::IBuffer^>* op,
+ bool is_continuation)
+{
+ if (flags)
+ {
+ op->ec_ = asio::error::operation_not_supported;
+ io_context_.post_immediate_completion(op, is_continuation);
+ return;
+ }
+
+ if (!is_open(impl))
+ {
+ op->ec_ = asio::error::bad_descriptor;
+ io_context_.post_immediate_completion(op, is_continuation);
+ return;
+ }
+
+ try
+ {
+ buffer_sequence_adapter<asio::mutable_buffer,
+ asio::mutable_buffer> bufs(asio::buffer(data));
+
+ if (bufs.all_empty())
+ {
+ io_context_.post_immediate_completion(op, is_continuation);
+ return;
+ }
+
+ async_manager_.async(
+ impl.socket_->InputStream->ReadAsync(
+ bufs.buffers()[0], bufs.buffers()[0]->Capacity,
+ Windows::Storage::Streams::InputStreamOptions::Partial), op);
+ }
+ catch (Platform::Exception^ e)
+ {
+ op->ec_ = asio::error_code(e->HResult,
+ asio::system_category());
+ io_context_.post_immediate_completion(op, is_continuation);
+ }
+}
+
+} // namespace detail
+} // namespace asio
+
+#include "asio/detail/pop_options.hpp"
+
+#endif // defined(ASIO_WINDOWS_RUNTIME)
+
+#endif // ASIO_DETAIL_IMPL_WINRT_SSOCKET_SERVICE_BASE_IPP
diff --git a/lib/asio/detail/impl/winrt_timer_scheduler.hpp b/lib/asio/detail/impl/winrt_timer_scheduler.hpp
new file mode 100644
index 0000000..856378f
--- /dev/null
+++ b/lib/asio/detail/impl/winrt_timer_scheduler.hpp
@@ -0,0 +1,92 @@
+//
+// detail/impl/winrt_timer_scheduler.hpp
+// ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+//
+// Copyright (c) 2003-2018 Christopher M. Kohlhoff (chris at kohlhoff dot com)
+//
+// 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 ASIO_DETAIL_IMPL_WINRT_TIMER_SCHEDULER_HPP
+#define ASIO_DETAIL_IMPL_WINRT_TIMER_SCHEDULER_HPP
+
+#if defined(_MSC_VER) && (_MSC_VER >= 1200)
+# pragma once
+#endif // defined(_MSC_VER) && (_MSC_VER >= 1200)
+
+#include "asio/detail/config.hpp"
+
+#if defined(ASIO_WINDOWS_RUNTIME)
+
+#include "asio/detail/push_options.hpp"
+
+namespace asio {
+namespace detail {
+
+template <typename Time_Traits>
+void winrt_timer_scheduler::add_timer_queue(timer_queue<Time_Traits>& queue)
+{
+ do_add_timer_queue(queue);
+}
+
+// Remove a timer queue from the reactor.
+template <typename Time_Traits>
+void winrt_timer_scheduler::remove_timer_queue(timer_queue<Time_Traits>& queue)
+{
+ do_remove_timer_queue(queue);
+}
+
+template <typename Time_Traits>
+void winrt_timer_scheduler::schedule_timer(timer_queue<Time_Traits>& queue,
+ const typename Time_Traits::time_type& time,
+ typename timer_queue<Time_Traits>::per_timer_data& timer, wait_op* op)
+{
+ asio::detail::mutex::scoped_lock lock(mutex_);
+
+ if (shutdown_)
+ {
+ io_context_.post_immediate_completion(op, false);
+ return;
+ }
+
+ bool earliest = queue.enqueue_timer(time, timer, op);
+ io_context_.work_started();
+ if (earliest)
+ event_.signal(lock);
+}
+
+template <typename Time_Traits>
+std::size_t winrt_timer_scheduler::cancel_timer(timer_queue<Time_Traits>& queue,
+ typename timer_queue<Time_Traits>::per_timer_data& timer,
+ std::size_t max_cancelled)
+{
+ asio::detail::mutex::scoped_lock lock(mutex_);
+ op_queue<operation> ops;
+ std::size_t n = queue.cancel_timer(timer, ops, max_cancelled);
+ lock.unlock();
+ io_context_.post_deferred_completions(ops);
+ return n;
+}
+
+template <typename Time_Traits>
+void winrt_timer_scheduler::move_timer(timer_queue<Time_Traits>& queue,
+ typename timer_queue<Time_Traits>::per_timer_data& to,
+ typename timer_queue<Time_Traits>::per_timer_data& from)
+{
+ asio::detail::mutex::scoped_lock lock(mutex_);
+ op_queue<operation> ops;
+ queue.cancel_timer(to, ops);
+ queue.move_timer(to, from);
+ lock.unlock();
+ scheduler_.post_deferred_completions(ops);
+}
+
+} // namespace detail
+} // namespace asio
+
+#include "asio/detail/pop_options.hpp"
+
+#endif // defined(ASIO_WINDOWS_RUNTIME)
+
+#endif // ASIO_DETAIL_IMPL_WINRT_TIMER_SCHEDULER_HPP
diff --git a/lib/asio/detail/impl/winrt_timer_scheduler.ipp b/lib/asio/detail/impl/winrt_timer_scheduler.ipp
new file mode 100644
index 0000000..ef21399
--- /dev/null
+++ b/lib/asio/detail/impl/winrt_timer_scheduler.ipp
@@ -0,0 +1,122 @@
+//
+// detail/impl/winrt_timer_scheduler.ipp
+// ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+//
+// Copyright (c) 2003-2018 Christopher M. Kohlhoff (chris at kohlhoff dot com)
+//
+// 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 ASIO_DETAIL_IMPL_WINRT_TIMER_SCHEDULER_IPP
+#define ASIO_DETAIL_IMPL_WINRT_TIMER_SCHEDULER_IPP
+
+#if defined(_MSC_VER) && (_MSC_VER >= 1200)
+# pragma once
+#endif // defined(_MSC_VER) && (_MSC_VER >= 1200)
+
+#include "asio/detail/config.hpp"
+
+#if defined(ASIO_WINDOWS_RUNTIME)
+
+#include "asio/detail/bind_handler.hpp"
+#include "asio/detail/winrt_timer_scheduler.hpp"
+
+#include "asio/detail/push_options.hpp"
+
+namespace asio {
+namespace detail {
+
+winrt_timer_scheduler::winrt_timer_scheduler(
+ asio::io_context& io_context)
+ : asio::detail::service_base<winrt_timer_scheduler>(io_context),
+ io_context_(use_service<io_context_impl>(io_context)),
+ mutex_(),
+ event_(),
+ timer_queues_(),
+ thread_(0),
+ stop_thread_(false),
+ shutdown_(false)
+{
+ thread_ = new asio::detail::thread(
+ bind_handler(&winrt_timer_scheduler::call_run_thread, this));
+}
+
+winrt_timer_scheduler::~winrt_timer_scheduler()
+{
+ shutdown();
+}
+
+void winrt_timer_scheduler::shutdown()
+{
+ asio::detail::mutex::scoped_lock lock(mutex_);
+ shutdown_ = true;
+ stop_thread_ = true;
+ event_.signal(lock);
+ lock.unlock();
+
+ if (thread_)
+ {
+ thread_->join();
+ delete thread_;
+ thread_ = 0;
+ }
+
+ op_queue<operation> ops;
+ timer_queues_.get_all_timers(ops);
+ io_context_.abandon_operations(ops);
+}
+
+void winrt_timer_scheduler::notify_fork(asio::io_context::fork_event)
+{
+}
+
+void winrt_timer_scheduler::init_task()
+{
+}
+
+void winrt_timer_scheduler::run_thread()
+{
+ asio::detail::mutex::scoped_lock lock(mutex_);
+ while (!stop_thread_)
+ {
+ const long max_wait_duration = 5 * 60 * 1000000;
+ long wait_duration = timer_queues_.wait_duration_usec(max_wait_duration);
+ event_.wait_for_usec(lock, wait_duration);
+ event_.clear(lock);
+ op_queue<operation> ops;
+ timer_queues_.get_ready_timers(ops);
+ if (!ops.empty())
+ {
+ lock.unlock();
+ io_context_.post_deferred_completions(ops);
+ lock.lock();
+ }
+ }
+}
+
+void winrt_timer_scheduler::call_run_thread(winrt_timer_scheduler* scheduler)
+{
+ scheduler->run_thread();
+}
+
+void winrt_timer_scheduler::do_add_timer_queue(timer_queue_base& queue)
+{
+ mutex::scoped_lock lock(mutex_);
+ timer_queues_.insert(&queue);
+}
+
+void winrt_timer_scheduler::do_remove_timer_queue(timer_queue_base& queue)
+{
+ mutex::scoped_lock lock(mutex_);
+ timer_queues_.erase(&queue);
+}
+
+} // namespace detail
+} // namespace asio
+
+#include "asio/detail/pop_options.hpp"
+
+#endif // defined(ASIO_WINDOWS_RUNTIME)
+
+#endif // ASIO_DETAIL_IMPL_WINRT_TIMER_SCHEDULER_IPP
diff --git a/lib/asio/detail/impl/winsock_init.ipp b/lib/asio/detail/impl/winsock_init.ipp
new file mode 100644
index 0000000..da4b0c0
--- /dev/null
+++ b/lib/asio/detail/impl/winsock_init.ipp
@@ -0,0 +1,82 @@
+//
+// detail/impl/winsock_init.ipp
+// ~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+//
+// Copyright (c) 2003-2018 Christopher M. Kohlhoff (chris at kohlhoff dot com)
+//
+// 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 ASIO_DETAIL_IMPL_WINSOCK_INIT_IPP
+#define ASIO_DETAIL_IMPL_WINSOCK_INIT_IPP
+
+#if defined(_MSC_VER) && (_MSC_VER >= 1200)
+# pragma once
+#endif // defined(_MSC_VER) && (_MSC_VER >= 1200)
+
+#include "asio/detail/config.hpp"
+
+#if defined(ASIO_WINDOWS) || defined(__CYGWIN__)
+
+#include "asio/detail/socket_types.hpp"
+#include "asio/detail/winsock_init.hpp"
+#include "asio/detail/throw_error.hpp"
+#include "asio/error.hpp"
+
+#include "asio/detail/push_options.hpp"
+
+namespace asio {
+namespace detail {
+
+void winsock_init_base::startup(data& d,
+ unsigned char major, unsigned char minor)
+{
+ if (::InterlockedIncrement(&d.init_count_) == 1)
+ {
+ WSADATA wsa_data;
+ long result = ::WSAStartup(MAKEWORD(major, minor), &wsa_data);
+ ::InterlockedExchange(&d.result_, result);
+ }
+}
+
+void winsock_init_base::manual_startup(data& d)
+{
+ if (::InterlockedIncrement(&d.init_count_) == 1)
+ {
+ ::InterlockedExchange(&d.result_, 0);
+ }
+}
+
+void winsock_init_base::cleanup(data& d)
+{
+ if (::InterlockedDecrement(&d.init_count_) == 0)
+ {
+ ::WSACleanup();
+ }
+}
+
+void winsock_init_base::manual_cleanup(data& d)
+{
+ ::InterlockedDecrement(&d.init_count_);
+}
+
+void winsock_init_base::throw_on_error(data& d)
+{
+ long result = ::InterlockedExchangeAdd(&d.result_, 0);
+ if (result != 0)
+ {
+ asio::error_code ec(result,
+ asio::error::get_system_category());
+ asio::detail::throw_error(ec, "winsock");
+ }
+}
+
+} // namespace detail
+} // namespace asio
+
+#include "asio/detail/pop_options.hpp"
+
+#endif // defined(ASIO_WINDOWS) || defined(__CYGWIN__)
+
+#endif // ASIO_DETAIL_IMPL_WINSOCK_INIT_IPP
diff --git a/lib/asio/detail/io_control.hpp b/lib/asio/detail/io_control.hpp
new file mode 100644
index 0000000..12f35e0
--- /dev/null
+++ b/lib/asio/detail/io_control.hpp
@@ -0,0 +1,84 @@
+//
+// detail/io_control.hpp
+// ~~~~~~~~~~~~~~~~~~~~~
+//
+// Copyright (c) 2003-2018 Christopher M. Kohlhoff (chris at kohlhoff dot com)
+//
+// 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 ASIO_DETAIL_IO_CONTROL_HPP
+#define ASIO_DETAIL_IO_CONTROL_HPP
+
+#if defined(_MSC_VER) && (_MSC_VER >= 1200)
+# pragma once
+#endif // defined(_MSC_VER) && (_MSC_VER >= 1200)
+
+#include "asio/detail/config.hpp"
+#include <cstddef>
+#include "asio/detail/socket_types.hpp"
+
+#include "asio/detail/push_options.hpp"
+
+namespace asio {
+namespace detail {
+namespace io_control {
+
+// I/O control command for getting number of bytes available.
+class bytes_readable
+{
+public:
+ // Default constructor.
+ bytes_readable()
+ : value_(0)
+ {
+ }
+
+ // Construct with a specific command value.
+ bytes_readable(std::size_t value)
+ : value_(static_cast<detail::ioctl_arg_type>(value))
+ {
+ }
+
+ // Get the name of the IO control command.
+ int name() const
+ {
+ return static_cast<int>(ASIO_OS_DEF(FIONREAD));
+ }
+
+ // Set the value of the I/O control command.
+ void set(std::size_t value)
+ {
+ value_ = static_cast<detail::ioctl_arg_type>(value);
+ }
+
+ // Get the current value of the I/O control command.
+ std::size_t get() const
+ {
+ return static_cast<std::size_t>(value_);
+ }
+
+ // Get the address of the command data.
+ detail::ioctl_arg_type* data()
+ {
+ return &value_;
+ }
+
+ // Get the address of the command data.
+ const detail::ioctl_arg_type* data() const
+ {
+ return &value_;
+ }
+
+private:
+ detail::ioctl_arg_type value_;
+};
+
+} // namespace io_control
+} // namespace detail
+} // namespace asio
+
+#include "asio/detail/pop_options.hpp"
+
+#endif // ASIO_DETAIL_IO_CONTROL_HPP
diff --git a/lib/asio/detail/is_buffer_sequence.hpp b/lib/asio/detail/is_buffer_sequence.hpp
new file mode 100644
index 0000000..42ad0eb
--- /dev/null
+++ b/lib/asio/detail/is_buffer_sequence.hpp
@@ -0,0 +1,239 @@
+//
+// detail/is_buffer_sequence.hpp
+// ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+//
+// Copyright (c) 2003-2018 Christopher M. Kohlhoff (chris at kohlhoff dot com)
+//
+// 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 ASIO_DETAIL_IS_BUFFER_SEQUENCE_HPP
+#define ASIO_DETAIL_IS_BUFFER_SEQUENCE_HPP
+
+#if defined(_MSC_VER) && (_MSC_VER >= 1200)
+# pragma once
+#endif // defined(_MSC_VER) && (_MSC_VER >= 1200)
+
+#include "asio/detail/config.hpp"
+#include "asio/detail/type_traits.hpp"
+
+#include "asio/detail/push_options.hpp"
+
+namespace asio {
+
+class mutable_buffer;
+class const_buffer;
+
+namespace detail {
+
+struct buffer_sequence_memfns_base
+{
+ void begin();
+ void end();
+ void size();
+ void max_size();
+ void capacity();
+ void data();
+ void prepare();
+ void commit();
+ void consume();
+};
+
+template <typename T>
+struct buffer_sequence_memfns_derived
+ : T, buffer_sequence_memfns_base
+{
+};
+
+template <typename T, T>
+struct buffer_sequence_memfns_check
+{
+};
+
+template <typename>
+char (&begin_memfn_helper(...))[2];
+
+template <typename T>
+char begin_memfn_helper(
+ buffer_sequence_memfns_check<
+ void (buffer_sequence_memfns_base::*)(),
+ &buffer_sequence_memfns_derived<T>::begin>*);
+
+template <typename>
+char (&end_memfn_helper(...))[2];
+
+template <typename T>
+char end_memfn_helper(
+ buffer_sequence_memfns_check<
+ void (buffer_sequence_memfns_base::*)(),
+ &buffer_sequence_memfns_derived<T>::end>*);
+
+template <typename>
+char (&size_memfn_helper(...))[2];
+
+template <typename T>
+char size_memfn_helper(
+ buffer_sequence_memfns_check<
+ void (buffer_sequence_memfns_base::*)(),
+ &buffer_sequence_memfns_derived<T>::size>*);
+
+template <typename>
+char (&max_size_memfn_helper(...))[2];
+
+template <typename T>
+char max_size_memfn_helper(
+ buffer_sequence_memfns_check<
+ void (buffer_sequence_memfns_base::*)(),
+ &buffer_sequence_memfns_derived<T>::max_size>*);
+
+template <typename>
+char (&capacity_memfn_helper(...))[2];
+
+template <typename T>
+char capacity_memfn_helper(
+ buffer_sequence_memfns_check<
+ void (buffer_sequence_memfns_base::*)(),
+ &buffer_sequence_memfns_derived<T>::capacity>*);
+
+template <typename>
+char (&data_memfn_helper(...))[2];
+
+template <typename T>
+char data_memfn_helper(
+ buffer_sequence_memfns_check<
+ void (buffer_sequence_memfns_base::*)(),
+ &buffer_sequence_memfns_derived<T>::data>*);
+
+template <typename>
+char (&prepare_memfn_helper(...))[2];
+
+template <typename T>
+char prepare_memfn_helper(
+ buffer_sequence_memfns_check<
+ void (buffer_sequence_memfns_base::*)(),
+ &buffer_sequence_memfns_derived<T>::prepare>*);
+
+template <typename>
+char (&commit_memfn_helper(...))[2];
+
+template <typename T>
+char commit_memfn_helper(
+ buffer_sequence_memfns_check<
+ void (buffer_sequence_memfns_base::*)(),
+ &buffer_sequence_memfns_derived<T>::commit>*);
+
+template <typename>
+char (&consume_memfn_helper(...))[2];
+
+template <typename T>
+char consume_memfn_helper(
+ buffer_sequence_memfns_check<
+ void (buffer_sequence_memfns_base::*)(),
+ &buffer_sequence_memfns_derived<T>::consume>*);
+
+template <typename, typename>
+char (&buffer_element_type_helper(...))[2];
+
+#if defined(ASIO_HAS_DECL_TYPE)
+
+template <typename T, typename Buffer>
+char buffer_element_type_helper(T* t,
+ typename enable_if<is_convertible<
+ decltype(*buffer_sequence_begin(*t)),
+ Buffer>::value>::type*);
+
+#else // defined(ASIO_HAS_DECL_TYPE)
+
+template <typename T, typename Buffer>
+char buffer_element_type_helper(
+ typename T::const_iterator*,
+ typename enable_if<is_convertible<
+ typename T::value_type, Buffer>::value>::type*);
+
+#endif // defined(ASIO_HAS_DECL_TYPE)
+
+template <typename>
+char (&const_buffers_type_typedef_helper(...))[2];
+
+template <typename T>
+char const_buffers_type_typedef_helper(
+ typename T::const_buffers_type*);
+
+template <typename>
+char (&mutable_buffers_type_typedef_helper(...))[2];
+
+template <typename T>
+char mutable_buffers_type_typedef_helper(
+ typename T::mutable_buffers_type*);
+
+template <typename T, typename Buffer>
+struct is_buffer_sequence_class
+ : integral_constant<bool,
+ sizeof(begin_memfn_helper<T>(0)) != 1 &&
+ sizeof(end_memfn_helper<T>(0)) != 1 &&
+ sizeof(buffer_element_type_helper<T, Buffer>(0, 0)) == 1>
+{
+};
+
+template <typename T, typename Buffer>
+struct is_buffer_sequence
+ : conditional<is_class<T>::value,
+ is_buffer_sequence_class<T, Buffer>,
+ false_type>::type
+{
+};
+
+template <>
+struct is_buffer_sequence<mutable_buffer, mutable_buffer>
+ : true_type
+{
+};
+
+template <>
+struct is_buffer_sequence<mutable_buffer, const_buffer>
+ : true_type
+{
+};
+
+template <>
+struct is_buffer_sequence<const_buffer, const_buffer>
+ : true_type
+{
+};
+
+template <>
+struct is_buffer_sequence<const_buffer, mutable_buffer>
+ : false_type
+{
+};
+
+template <typename T>
+struct is_dynamic_buffer_class
+ : integral_constant<bool,
+ sizeof(size_memfn_helper<T>(0)) != 1 &&
+ sizeof(max_size_memfn_helper<T>(0)) != 1 &&
+ sizeof(capacity_memfn_helper<T>(0)) != 1 &&
+ sizeof(data_memfn_helper<T>(0)) != 1 &&
+ sizeof(consume_memfn_helper<T>(0)) != 1 &&
+ sizeof(prepare_memfn_helper<T>(0)) != 1 &&
+ sizeof(commit_memfn_helper<T>(0)) != 1 &&
+ sizeof(const_buffers_type_typedef_helper<T>(0)) == 1 &&
+ sizeof(mutable_buffers_type_typedef_helper<T>(0)) == 1>
+{
+};
+
+template <typename T>
+struct is_dynamic_buffer
+ : conditional<is_class<T>::value,
+ is_dynamic_buffer_class<T>,
+ false_type>::type
+{
+};
+
+} // namespace detail
+} // namespace asio
+
+#include "asio/detail/pop_options.hpp"
+
+#endif // ASIO_DETAIL_IS_BUFFER_SEQUENCE_HPP
diff --git a/lib/asio/detail/is_executor.hpp b/lib/asio/detail/is_executor.hpp
new file mode 100644
index 0000000..4584dd0
--- /dev/null
+++ b/lib/asio/detail/is_executor.hpp
@@ -0,0 +1,126 @@
+//
+// detail/is_executor.hpp
+// ~~~~~~~~~~~~~~~~~~~~~~
+//
+// Copyright (c) 2003-2018 Christopher M. Kohlhoff (chris at kohlhoff dot com)
+//
+// 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 ASIO_DETAIL_IS_EXECUTOR_HPP
+#define ASIO_DETAIL_IS_EXECUTOR_HPP
+
+#if defined(_MSC_VER) && (_MSC_VER >= 1200)
+# pragma once
+#endif // defined(_MSC_VER) && (_MSC_VER >= 1200)
+
+#include "asio/detail/config.hpp"
+#include "asio/detail/type_traits.hpp"
+
+#include "asio/detail/push_options.hpp"
+
+namespace asio {
+namespace detail {
+
+struct executor_memfns_base
+{
+ void context();
+ void on_work_started();
+ void on_work_finished();
+ void dispatch();
+ void post();
+ void defer();
+};
+
+template <typename T>
+struct executor_memfns_derived
+ : T, executor_memfns_base
+{
+};
+
+template <typename T, T>
+struct executor_memfns_check
+{
+};
+
+template <typename>
+char (&context_memfn_helper(...))[2];
+
+template <typename T>
+char context_memfn_helper(
+ executor_memfns_check<
+ void (executor_memfns_base::*)(),
+ &executor_memfns_derived<T>::context>*);
+
+template <typename>
+char (&on_work_started_memfn_helper(...))[2];
+
+template <typename T>
+char on_work_started_memfn_helper(
+ executor_memfns_check<
+ void (executor_memfns_base::*)(),
+ &executor_memfns_derived<T>::on_work_started>*);
+
+template <typename>
+char (&on_work_finished_memfn_helper(...))[2];
+
+template <typename T>
+char on_work_finished_memfn_helper(
+ executor_memfns_check<
+ void (executor_memfns_base::*)(),
+ &executor_memfns_derived<T>::on_work_finished>*);
+
+template <typename>
+char (&dispatch_memfn_helper(...))[2];
+
+template <typename T>
+char dispatch_memfn_helper(
+ executor_memfns_check<
+ void (executor_memfns_base::*)(),
+ &executor_memfns_derived<T>::dispatch>*);
+
+template <typename>
+char (&post_memfn_helper(...))[2];
+
+template <typename T>
+char post_memfn_helper(
+ executor_memfns_check<
+ void (executor_memfns_base::*)(),
+ &executor_memfns_derived<T>::post>*);
+
+template <typename>
+char (&defer_memfn_helper(...))[2];
+
+template <typename T>
+char defer_memfn_helper(
+ executor_memfns_check<
+ void (executor_memfns_base::*)(),
+ &executor_memfns_derived<T>::defer>*);
+
+template <typename T>
+struct is_executor_class
+ : integral_constant<bool,
+ sizeof(context_memfn_helper<T>(0)) != 1 &&
+ sizeof(on_work_started_memfn_helper<T>(0)) != 1 &&
+ sizeof(on_work_finished_memfn_helper<T>(0)) != 1 &&
+ sizeof(dispatch_memfn_helper<T>(0)) != 1 &&
+ sizeof(post_memfn_helper<T>(0)) != 1 &&
+ sizeof(defer_memfn_helper<T>(0)) != 1>
+{
+};
+
+template <typename T>
+struct is_executor
+ : conditional<is_class<T>::value,
+ is_executor_class<T>,
+ false_type>::type
+{
+};
+
+} // namespace detail
+} // namespace asio
+
+#include "asio/detail/pop_options.hpp"
+
+#endif // ASIO_DETAIL_IS_EXECUTOR_HPP
diff --git a/lib/asio/detail/keyword_tss_ptr.hpp b/lib/asio/detail/keyword_tss_ptr.hpp
new file mode 100644
index 0000000..2ae651a
--- /dev/null
+++ b/lib/asio/detail/keyword_tss_ptr.hpp
@@ -0,0 +1,70 @@
+//
+// detail/keyword_tss_ptr.hpp
+// ~~~~~~~~~~~~~~~~~~~~~~~~~~
+//
+// Copyright (c) 2003-2018 Christopher M. Kohlhoff (chris at kohlhoff dot com)
+//
+// 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 ASIO_DETAIL_KEYWORD_TSS_PTR_HPP
+#define ASIO_DETAIL_KEYWORD_TSS_PTR_HPP
+
+#if defined(_MSC_VER) && (_MSC_VER >= 1200)
+# pragma once
+#endif // defined(_MSC_VER) && (_MSC_VER >= 1200)
+
+#include "asio/detail/config.hpp"
+
+#if defined(ASIO_HAS_THREAD_KEYWORD_EXTENSION)
+
+#include "asio/detail/noncopyable.hpp"
+
+#include "asio/detail/push_options.hpp"
+
+namespace asio {
+namespace detail {
+
+template <typename T>
+class keyword_tss_ptr
+ : private noncopyable
+{
+public:
+ // Constructor.
+ keyword_tss_ptr()
+ {
+ }
+
+ // Destructor.
+ ~keyword_tss_ptr()
+ {
+ }
+
+ // Get the value.
+ operator T*() const
+ {
+ return value_;
+ }
+
+ // Set the value.
+ void operator=(T* value)
+ {
+ value_ = value;
+ }
+
+private:
+ static ASIO_THREAD_KEYWORD T* value_;
+};
+
+template <typename T>
+ASIO_THREAD_KEYWORD T* keyword_tss_ptr<T>::value_;
+
+} // namespace detail
+} // namespace asio
+
+#include "asio/detail/pop_options.hpp"
+
+#endif // defined(ASIO_HAS_THREAD_KEYWORD_EXTENSION)
+
+#endif // ASIO_DETAIL_KEYWORD_TSS_PTR_HPP
diff --git a/lib/asio/detail/kqueue_reactor.hpp b/lib/asio/detail/kqueue_reactor.hpp
new file mode 100644
index 0000000..43cb9f9
--- /dev/null
+++ b/lib/asio/detail/kqueue_reactor.hpp
@@ -0,0 +1,242 @@
+//
+// detail/kqueue_reactor.hpp
+// ~~~~~~~~~~~~~~~~~~~~~~~~~
+//
+// Copyright (c) 2003-2018 Christopher M. Kohlhoff (chris at kohlhoff dot com)
+// Copyright (c) 2005 Stefan Arentz (stefan at soze dot com)
+//
+// 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 ASIO_DETAIL_KQUEUE_REACTOR_HPP
+#define ASIO_DETAIL_KQUEUE_REACTOR_HPP
+
+#if defined(_MSC_VER) && (_MSC_VER >= 1200)
+# pragma once
+#endif // defined(_MSC_VER) && (_MSC_VER >= 1200)
+
+#include "asio/detail/config.hpp"
+
+#if defined(ASIO_HAS_KQUEUE)
+
+#include <cstddef>
+#include <sys/types.h>
+#include <sys/event.h>
+#include <sys/time.h>
+#include "asio/detail/limits.hpp"
+#include "asio/detail/mutex.hpp"
+#include "asio/detail/object_pool.hpp"
+#include "asio/detail/op_queue.hpp"
+#include "asio/detail/reactor_op.hpp"
+#include "asio/detail/select_interrupter.hpp"
+#include "asio/detail/socket_types.hpp"
+#include "asio/detail/timer_queue_base.hpp"
+#include "asio/detail/timer_queue_set.hpp"
+#include "asio/detail/wait_op.hpp"
+#include "asio/error.hpp"
+#include "asio/execution_context.hpp"
+
+// Older versions of Mac OS X may not define EV_OOBAND.
+#if !defined(EV_OOBAND)
+# define EV_OOBAND EV_FLAG1
+#endif // !defined(EV_OOBAND)
+
+#include "asio/detail/push_options.hpp"
+
+namespace asio {
+namespace detail {
+
+class scheduler;
+
+class kqueue_reactor
+ : public execution_context_service_base<kqueue_reactor>
+{
+private:
+ // The mutex type used by this reactor.
+ typedef conditionally_enabled_mutex mutex;
+
+public:
+ enum op_types { read_op = 0, write_op = 1,
+ connect_op = 1, except_op = 2, max_ops = 3 };
+
+ // Per-descriptor queues.
+ struct descriptor_state
+ {
+ descriptor_state(bool locking) : mutex_(locking) {}
+
+ friend class kqueue_reactor;
+ friend class object_pool_access;
+
+ descriptor_state* next_;
+ descriptor_state* prev_;
+
+ mutex mutex_;
+ int descriptor_;
+ int num_kevents_; // 1 == read only, 2 == read and write
+ op_queue<reactor_op> op_queue_[max_ops];
+ bool shutdown_;
+ };
+
+ // Per-descriptor data.
+ typedef descriptor_state* per_descriptor_data;
+
+ // Constructor.
+ ASIO_DECL kqueue_reactor(asio::execution_context& ctx);
+
+ // Destructor.
+ ASIO_DECL ~kqueue_reactor();
+
+ // Destroy all user-defined handler objects owned by the service.
+ ASIO_DECL void shutdown();
+
+ // Recreate internal descriptors following a fork.
+ ASIO_DECL void notify_fork(
+ asio::execution_context::fork_event fork_ev);
+
+ // Initialise the task.
+ ASIO_DECL void init_task();
+
+ // Register a socket with the reactor. Returns 0 on success, system error
+ // code on failure.
+ ASIO_DECL int register_descriptor(socket_type descriptor,
+ per_descriptor_data& descriptor_data);
+
+ // Register a descriptor with an associated single operation. Returns 0 on
+ // success, system error code on failure.
+ ASIO_DECL int register_internal_descriptor(
+ int op_type, socket_type descriptor,
+ per_descriptor_data& descriptor_data, reactor_op* op);
+
+ // Move descriptor registration from one descriptor_data object to another.
+ ASIO_DECL void move_descriptor(socket_type descriptor,
+ per_descriptor_data& target_descriptor_data,
+ per_descriptor_data& source_descriptor_data);
+
+ // Post a reactor operation for immediate completion.
+ void post_immediate_completion(reactor_op* op, bool is_continuation)
+ {
+ scheduler_.post_immediate_completion(op, is_continuation);
+ }
+
+ // Start a new operation. The reactor operation will be performed when the
+ // given descriptor is flagged as ready, or an error has occurred.
+ ASIO_DECL void start_op(int op_type, socket_type descriptor,
+ per_descriptor_data& descriptor_data, reactor_op* op,
+ bool is_continuation, bool allow_speculative);
+
+ // Cancel all operations associated with the given descriptor. The
+ // handlers associated with the descriptor will be invoked with the
+ // operation_aborted error.
+ ASIO_DECL void cancel_ops(socket_type descriptor,
+ per_descriptor_data& descriptor_data);
+
+ // Cancel any operations that are running against the descriptor and remove
+ // its registration from the reactor. The reactor resources associated with
+ // the descriptor must be released by calling cleanup_descriptor_data.
+ ASIO_DECL void deregister_descriptor(socket_type descriptor,
+ per_descriptor_data& descriptor_data, bool closing);
+
+ // Remove the descriptor's registration from the reactor. The reactor
+ // resources associated with the descriptor must be released by calling
+ // cleanup_descriptor_data.
+ ASIO_DECL void deregister_internal_descriptor(
+ socket_type descriptor, per_descriptor_data& descriptor_data);
+
+ // Perform any post-deregistration cleanup tasks associated with the
+ // descriptor data.
+ ASIO_DECL void cleanup_descriptor_data(
+ per_descriptor_data& descriptor_data);
+
+ // Add a new timer queue to the reactor.
+ template <typename Time_Traits>
+ void add_timer_queue(timer_queue<Time_Traits>& queue);
+
+ // Remove a timer queue from the reactor.
+ template <typename Time_Traits>
+ void remove_timer_queue(timer_queue<Time_Traits>& queue);
+
+ // Schedule a new operation in the given timer queue to expire at the
+ // specified absolute time.
+ template <typename Time_Traits>
+ void schedule_timer(timer_queue<Time_Traits>& queue,
+ const typename Time_Traits::time_type& time,
+ typename timer_queue<Time_Traits>::per_timer_data& timer, wait_op* op);
+
+ // Cancel the timer operations associated with the given token. Returns the
+ // number of operations that have been posted or dispatched.
+ template <typename Time_Traits>
+ std::size_t cancel_timer(timer_queue<Time_Traits>& queue,
+ typename timer_queue<Time_Traits>::per_timer_data& timer,
+ std::size_t max_cancelled = (std::numeric_limits<std::size_t>::max)());
+
+ // Move the timer operations associated with the given timer.
+ template <typename Time_Traits>
+ void move_timer(timer_queue<Time_Traits>& queue,
+ typename timer_queue<Time_Traits>::per_timer_data& target,
+ typename timer_queue<Time_Traits>::per_timer_data& source);
+
+ // Run the kqueue loop.
+ ASIO_DECL void run(long usec, op_queue<operation>& ops);
+
+ // Interrupt the kqueue loop.
+ ASIO_DECL void interrupt();
+
+private:
+ // Create the kqueue file descriptor. Throws an exception if the descriptor
+ // cannot be created.
+ ASIO_DECL static int do_kqueue_create();
+
+ // Allocate a new descriptor state object.
+ ASIO_DECL descriptor_state* allocate_descriptor_state();
+
+ // Free an existing descriptor state object.
+ ASIO_DECL void free_descriptor_state(descriptor_state* s);
+
+ // Helper function to add a new timer queue.
+ ASIO_DECL void do_add_timer_queue(timer_queue_base& queue);
+
+ // Helper function to remove a timer queue.
+ ASIO_DECL void do_remove_timer_queue(timer_queue_base& queue);
+
+ // Get the timeout value for the kevent call.
+ ASIO_DECL timespec* get_timeout(long usec, timespec& ts);
+
+ // The scheduler used to post completions.
+ scheduler& scheduler_;
+
+ // Mutex to protect access to internal data.
+ mutex mutex_;
+
+ // The kqueue file descriptor.
+ int kqueue_fd_;
+
+ // The interrupter is used to break a blocking kevent call.
+ select_interrupter interrupter_;
+
+ // The timer queues.
+ timer_queue_set timer_queues_;
+
+ // Whether the service has been shut down.
+ bool shutdown_;
+
+ // Mutex to protect access to the registered descriptors.
+ mutex registered_descriptors_mutex_;
+
+ // Keep track of all registered descriptors.
+ object_pool<descriptor_state> registered_descriptors_;
+};
+
+} // namespace detail
+} // namespace asio
+
+#include "asio/detail/pop_options.hpp"
+
+#include "asio/detail/impl/kqueue_reactor.hpp"
+#if defined(ASIO_HEADER_ONLY)
+# include "asio/detail/impl/kqueue_reactor.ipp"
+#endif // defined(ASIO_HEADER_ONLY)
+
+#endif // defined(ASIO_HAS_KQUEUE)
+
+#endif // ASIO_DETAIL_KQUEUE_REACTOR_HPP
diff --git a/lib/asio/detail/limits.hpp b/lib/asio/detail/limits.hpp
new file mode 100644
index 0000000..d32470d
--- /dev/null
+++ b/lib/asio/detail/limits.hpp
@@ -0,0 +1,26 @@
+//
+// detail/limits.hpp
+// ~~~~~~~~~~~~~~~~~
+//
+// Copyright (c) 2003-2011 Christopher M. Kohlhoff (chris at kohlhoff dot com)
+//
+// 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 ASIO_DETAIL_LIMITS_HPP
+#define ASIO_DETAIL_LIMITS_HPP
+
+#if defined(_MSC_VER) && (_MSC_VER >= 1200)
+# pragma once
+#endif // defined(_MSC_VER) && (_MSC_VER >= 1200)
+
+#include "asio/detail/config.hpp"
+
+#if defined(ASIO_HAS_BOOST_LIMITS)
+# include <boost/limits.hpp>
+#else // defined(ASIO_HAS_BOOST_LIMITS)
+# include <limits>
+#endif // defined(ASIO_HAS_BOOST_LIMITS)
+
+#endif // ASIO_DETAIL_LIMITS_HPP
diff --git a/lib/asio/detail/local_free_on_block_exit.hpp b/lib/asio/detail/local_free_on_block_exit.hpp
new file mode 100644
index 0000000..eba6b77
--- /dev/null
+++ b/lib/asio/detail/local_free_on_block_exit.hpp
@@ -0,0 +1,59 @@
+//
+// detail/local_free_on_block_exit.hpp
+// ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+//
+// Copyright (c) 2003-2018 Christopher M. Kohlhoff (chris at kohlhoff dot com)
+//
+// 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 ASIO_DETAIL_LOCAL_FREE_ON_BLOCK_EXIT_HPP
+#define ASIO_DETAIL_LOCAL_FREE_ON_BLOCK_EXIT_HPP
+
+#if defined(_MSC_VER) && (_MSC_VER >= 1200)
+# pragma once
+#endif // defined(_MSC_VER) && (_MSC_VER >= 1200)
+
+#include "asio/detail/config.hpp"
+
+#if defined(ASIO_WINDOWS) || defined(__CYGWIN__)
+#if !defined(ASIO_WINDOWS_APP)
+
+#include "asio/detail/noncopyable.hpp"
+#include "asio/detail/socket_types.hpp"
+
+#include "asio/detail/push_options.hpp"
+
+namespace asio {
+namespace detail {
+
+class local_free_on_block_exit
+ : private noncopyable
+{
+public:
+ // Constructor blocks all signals for the calling thread.
+ explicit local_free_on_block_exit(void* p)
+ : p_(p)
+ {
+ }
+
+ // Destructor restores the previous signal mask.
+ ~local_free_on_block_exit()
+ {
+ ::LocalFree(p_);
+ }
+
+private:
+ void* p_;
+};
+
+} // namespace detail
+} // namespace asio
+
+#include "asio/detail/pop_options.hpp"
+
+#endif // !defined(ASIO_WINDOWS_APP)
+#endif // defined(ASIO_WINDOWS) || defined(__CYGWIN__)
+
+#endif // ASIO_DETAIL_LOCAL_FREE_ON_BLOCK_EXIT_HPP
diff --git a/lib/asio/detail/macos_fenced_block.hpp b/lib/asio/detail/macos_fenced_block.hpp
new file mode 100644
index 0000000..bbac270
--- /dev/null
+++ b/lib/asio/detail/macos_fenced_block.hpp
@@ -0,0 +1,62 @@
+//
+// detail/macos_fenced_block.hpp
+// ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+//
+// Copyright (c) 2003-2018 Christopher M. Kohlhoff (chris at kohlhoff dot com)
+//
+// 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 ASIO_DETAIL_MACOS_FENCED_BLOCK_HPP
+#define ASIO_DETAIL_MACOS_FENCED_BLOCK_HPP
+
+#if defined(_MSC_VER) && (_MSC_VER >= 1200)
+# pragma once
+#endif // defined(_MSC_VER) && (_MSC_VER >= 1200)
+
+#include "asio/detail/config.hpp"
+
+#if defined(__MACH__) && defined(__APPLE__)
+
+#include <libkern/OSAtomic.h>
+#include "asio/detail/noncopyable.hpp"
+
+#include "asio/detail/push_options.hpp"
+
+namespace asio {
+namespace detail {
+
+class macos_fenced_block
+ : private noncopyable
+{
+public:
+ enum half_t { half };
+ enum full_t { full };
+
+ // Constructor for a half fenced block.
+ explicit macos_fenced_block(half_t)
+ {
+ }
+
+ // Constructor for a full fenced block.
+ explicit macos_fenced_block(full_t)
+ {
+ OSMemoryBarrier();
+ }
+
+ // Destructor.
+ ~macos_fenced_block()
+ {
+ OSMemoryBarrier();
+ }
+};
+
+} // namespace detail
+} // namespace asio
+
+#include "asio/detail/pop_options.hpp"
+
+#endif // defined(__MACH__) && defined(__APPLE__)
+
+#endif // ASIO_DETAIL_MACOS_FENCED_BLOCK_HPP
diff --git a/lib/asio/detail/memory.hpp b/lib/asio/detail/memory.hpp
new file mode 100644
index 0000000..b1ec497
--- /dev/null
+++ b/lib/asio/detail/memory.hpp
@@ -0,0 +1,70 @@
+//
+// detail/memory.hpp
+// ~~~~~~~~~~~~~~~~~
+//
+// Copyright (c) 2003-2018 Christopher M. Kohlhoff (chris at kohlhoff dot com)
+//
+// 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 ASIO_DETAIL_MEMORY_HPP
+#define ASIO_DETAIL_MEMORY_HPP
+
+#if defined(_MSC_VER) && (_MSC_VER >= 1200)
+# pragma once
+#endif // defined(_MSC_VER) && (_MSC_VER >= 1200)
+
+#include "asio/detail/config.hpp"
+#include <memory>
+
+#if !defined(ASIO_HAS_STD_SHARED_PTR)
+# include <boost/shared_ptr.hpp>
+# include <boost/weak_ptr.hpp>
+#endif // !defined(ASIO_HAS_STD_SHARED_PTR)
+
+#if !defined(ASIO_HAS_STD_ADDRESSOF)
+# include <boost/utility/addressof.hpp>
+#endif // !defined(ASIO_HAS_STD_ADDRESSOF)
+
+namespace asio {
+namespace detail {
+
+#if defined(ASIO_HAS_STD_SHARED_PTR)
+using std::shared_ptr;
+using std::weak_ptr;
+#else // defined(ASIO_HAS_STD_SHARED_PTR)
+using boost::shared_ptr;
+using boost::weak_ptr;
+#endif // defined(ASIO_HAS_STD_SHARED_PTR)
+
+#if defined(ASIO_HAS_STD_ADDRESSOF)
+using std::addressof;
+#else // defined(ASIO_HAS_STD_ADDRESSOF)
+using boost::addressof;
+#endif // defined(ASIO_HAS_STD_ADDRESSOF)
+
+} // namespace detail
+
+#if defined(ASIO_HAS_CXX11_ALLOCATORS)
+using std::allocator_arg_t;
+# define ASIO_USES_ALLOCATOR(t) \
+ namespace std { \
+ template <typename Allocator> \
+ struct uses_allocator<t, Allocator> : true_type {}; \
+ } \
+ /**/
+# define ASIO_REBIND_ALLOC(alloc, t) \
+ typename std::allocator_traits<alloc>::template rebind_alloc<t>
+ /**/
+#else // defined(ASIO_HAS_CXX11_ALLOCATORS)
+struct allocator_arg_t {};
+# define ASIO_USES_ALLOCATOR(t)
+# define ASIO_REBIND_ALLOC(alloc, t) \
+ typename alloc::template rebind<t>::other
+ /**/
+#endif // defined(ASIO_HAS_CXX11_ALLOCATORS)
+
+} // namespace asio
+
+#endif // ASIO_DETAIL_MEMORY_HPP
diff --git a/lib/asio/detail/mutex.hpp b/lib/asio/detail/mutex.hpp
new file mode 100644
index 0000000..2f8f0b1
--- /dev/null
+++ b/lib/asio/detail/mutex.hpp
@@ -0,0 +1,48 @@
+//
+// detail/mutex.hpp
+// ~~~~~~~~~~~~~~~~
+//
+// Copyright (c) 2003-2018 Christopher M. Kohlhoff (chris at kohlhoff dot com)
+//
+// 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 ASIO_DETAIL_MUTEX_HPP
+#define ASIO_DETAIL_MUTEX_HPP
+
+#if defined(_MSC_VER) && (_MSC_VER >= 1200)
+# pragma once
+#endif // defined(_MSC_VER) && (_MSC_VER >= 1200)
+
+#include "asio/detail/config.hpp"
+
+#if !defined(ASIO_HAS_THREADS)
+# include "asio/detail/null_mutex.hpp"
+#elif defined(ASIO_WINDOWS)
+# include "asio/detail/win_mutex.hpp"
+#elif defined(ASIO_HAS_PTHREADS)
+# include "asio/detail/posix_mutex.hpp"
+#elif defined(ASIO_HAS_STD_MUTEX_AND_CONDVAR)
+# include "asio/detail/std_mutex.hpp"
+#else
+# error Only Windows, POSIX and std::mutex are supported!
+#endif
+
+namespace asio {
+namespace detail {
+
+#if !defined(ASIO_HAS_THREADS)
+typedef null_mutex mutex;
+#elif defined(ASIO_WINDOWS)
+typedef win_mutex mutex;
+#elif defined(ASIO_HAS_PTHREADS)
+typedef posix_mutex mutex;
+#elif defined(ASIO_HAS_STD_MUTEX_AND_CONDVAR)
+typedef std_mutex mutex;
+#endif
+
+} // namespace detail
+} // namespace asio
+
+#endif // ASIO_DETAIL_MUTEX_HPP
diff --git a/lib/asio/detail/noncopyable.hpp b/lib/asio/detail/noncopyable.hpp
new file mode 100644
index 0000000..0c038e1
--- /dev/null
+++ b/lib/asio/detail/noncopyable.hpp
@@ -0,0 +1,43 @@
+//
+// detail/noncopyable.hpp
+// ~~~~~~~~~~~~~~~~~~~~~~
+//
+// Copyright (c) 2003-2018 Christopher M. Kohlhoff (chris at kohlhoff dot com)
+//
+// 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 ASIO_DETAIL_NONCOPYABLE_HPP
+#define ASIO_DETAIL_NONCOPYABLE_HPP
+
+#if defined(_MSC_VER) && (_MSC_VER >= 1200)
+# pragma once
+#endif // defined(_MSC_VER) && (_MSC_VER >= 1200)
+
+#include "asio/detail/config.hpp"
+
+#include "asio/detail/push_options.hpp"
+
+namespace asio {
+namespace detail {
+
+class noncopyable
+{
+protected:
+ noncopyable() {}
+ ~noncopyable() {}
+private:
+ noncopyable(const noncopyable&);
+ const noncopyable& operator=(const noncopyable&);
+};
+
+} // namespace detail
+
+using asio::detail::noncopyable;
+
+} // namespace asio
+
+#include "asio/detail/pop_options.hpp"
+
+#endif // ASIO_DETAIL_NONCOPYABLE_HPP
diff --git a/lib/asio/detail/null_event.hpp b/lib/asio/detail/null_event.hpp
new file mode 100644
index 0000000..5686a41
--- /dev/null
+++ b/lib/asio/detail/null_event.hpp
@@ -0,0 +1,100 @@
+//
+// detail/null_event.hpp
+// ~~~~~~~~~~~~~~~~~~~~~
+//
+// Copyright (c) 2003-2018 Christopher M. Kohlhoff (chris at kohlhoff dot com)
+//
+// 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 ASIO_DETAIL_NULL_EVENT_HPP
+#define ASIO_DETAIL_NULL_EVENT_HPP
+
+#if defined(_MSC_VER) && (_MSC_VER >= 1200)
+# pragma once
+#endif // defined(_MSC_VER) && (_MSC_VER >= 1200)
+
+#include "asio/detail/config.hpp"
+#include "asio/detail/noncopyable.hpp"
+
+#include "asio/detail/push_options.hpp"
+
+namespace asio {
+namespace detail {
+
+class null_event
+ : private noncopyable
+{
+public:
+ // Constructor.
+ null_event()
+ {
+ }
+
+ // Destructor.
+ ~null_event()
+ {
+ }
+
+ // Signal the event. (Retained for backward compatibility.)
+ template <typename Lock>
+ void signal(Lock&)
+ {
+ }
+
+ // Signal all waiters.
+ template <typename Lock>
+ void signal_all(Lock&)
+ {
+ }
+
+ // Unlock the mutex and signal one waiter.
+ template <typename Lock>
+ void unlock_and_signal_one(Lock&)
+ {
+ }
+
+ // If there's a waiter, unlock the mutex and signal it.
+ template <typename Lock>
+ bool maybe_unlock_and_signal_one(Lock&)
+ {
+ return false;
+ }
+
+ // Reset the event.
+ template <typename Lock>
+ void clear(Lock&)
+ {
+ }
+
+ // Wait for the event to become signalled.
+ template <typename Lock>
+ void wait(Lock&)
+ {
+ do_wait();
+ }
+
+ // Timed wait for the event to become signalled.
+ template <typename Lock>
+ bool wait_for_usec(Lock&, long usec)
+ {
+ do_wait_for_usec(usec);
+ return true;
+ }
+
+private:
+ ASIO_DECL static void do_wait();
+ ASIO_DECL static void do_wait_for_usec(long usec);
+};
+
+} // namespace detail
+} // namespace asio
+
+#include "asio/detail/pop_options.hpp"
+
+#if defined(ASIO_HEADER_ONLY)
+# include "asio/detail/impl/null_event.ipp"
+#endif // defined(ASIO_HEADER_ONLY)
+
+#endif // ASIO_DETAIL_NULL_EVENT_HPP
diff --git a/lib/asio/detail/null_fenced_block.hpp b/lib/asio/detail/null_fenced_block.hpp
new file mode 100644
index 0000000..0275326
--- /dev/null
+++ b/lib/asio/detail/null_fenced_block.hpp
@@ -0,0 +1,47 @@
+//
+// detail/null_fenced_block.hpp
+// ~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+//
+// Copyright (c) 2003-2018 Christopher M. Kohlhoff (chris at kohlhoff dot com)
+//
+// 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 ASIO_DETAIL_NULL_FENCED_BLOCK_HPP
+#define ASIO_DETAIL_NULL_FENCED_BLOCK_HPP
+
+#if defined(_MSC_VER) && (_MSC_VER >= 1200)
+# pragma once
+#endif // defined(_MSC_VER) && (_MSC_VER >= 1200)
+
+#include "asio/detail/noncopyable.hpp"
+
+#include "asio/detail/push_options.hpp"
+
+namespace asio {
+namespace detail {
+
+class null_fenced_block
+ : private noncopyable
+{
+public:
+ enum half_or_full_t { half, full };
+
+ // Constructor.
+ explicit null_fenced_block(half_or_full_t)
+ {
+ }
+
+ // Destructor.
+ ~null_fenced_block()
+ {
+ }
+};
+
+} // namespace detail
+} // namespace asio
+
+#include "asio/detail/pop_options.hpp"
+
+#endif // ASIO_DETAIL_NULL_FENCED_BLOCK_HPP
diff --git a/lib/asio/detail/null_global.hpp b/lib/asio/detail/null_global.hpp
new file mode 100644
index 0000000..727dd3f
--- /dev/null
+++ b/lib/asio/detail/null_global.hpp
@@ -0,0 +1,59 @@
+//
+// detail/null_global.hpp
+// ~~~~~~~~~~~~~~~~~~~~~~
+//
+// Copyright (c) 2003-2018 Christopher M. Kohlhoff (chris at kohlhoff dot com)
+//
+// 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 ASIO_DETAIL_NULL_GLOBAL_HPP
+#define ASIO_DETAIL_NULL_GLOBAL_HPP
+
+#if defined(_MSC_VER) && (_MSC_VER >= 1200)
+# pragma once
+#endif // defined(_MSC_VER) && (_MSC_VER >= 1200)
+
+#include "asio/detail/config.hpp"
+
+#include "asio/detail/push_options.hpp"
+
+namespace asio {
+namespace detail {
+
+template <typename T>
+struct null_global_impl
+{
+ null_global_impl()
+ : ptr_(0)
+ {
+ }
+
+ // Destructor automatically cleans up the global.
+ ~null_global_impl()
+ {
+ delete ptr_;
+ }
+
+ static null_global_impl instance_;
+ T* ptr_;
+};
+
+template <typename T>
+null_global_impl<T> null_global_impl<T>::instance_;
+
+template <typename T>
+T& null_global()
+{
+ if (null_global_impl<T>::instance_.ptr_ == 0)
+ null_global_impl<T>::instance_.ptr_ = new T;
+ return *null_global_impl<T>::instance_.ptr_;
+}
+
+} // namespace detail
+} // namespace asio
+
+#include "asio/detail/pop_options.hpp"
+
+#endif // ASIO_DETAIL_NULL_GLOBAL_HPP
diff --git a/lib/asio/detail/null_mutex.hpp b/lib/asio/detail/null_mutex.hpp
new file mode 100644
index 0000000..afe3fc0
--- /dev/null
+++ b/lib/asio/detail/null_mutex.hpp
@@ -0,0 +1,64 @@
+//
+// detail/null_mutex.hpp
+// ~~~~~~~~~~~~~~~~~~~~~
+//
+// Copyright (c) 2003-2018 Christopher M. Kohlhoff (chris at kohlhoff dot com)
+//
+// 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 ASIO_DETAIL_NULL_MUTEX_HPP
+#define ASIO_DETAIL_NULL_MUTEX_HPP
+
+#if defined(_MSC_VER) && (_MSC_VER >= 1200)
+# pragma once
+#endif // defined(_MSC_VER) && (_MSC_VER >= 1200)
+
+#include "asio/detail/config.hpp"
+
+#if !defined(ASIO_HAS_THREADS)
+
+#include "asio/detail/noncopyable.hpp"
+#include "asio/detail/scoped_lock.hpp"
+
+#include "asio/detail/push_options.hpp"
+
+namespace asio {
+namespace detail {
+
+class null_mutex
+ : private noncopyable
+{
+public:
+ typedef asio::detail::scoped_lock<null_mutex> scoped_lock;
+
+ // Constructor.
+ null_mutex()
+ {
+ }
+
+ // Destructor.
+ ~null_mutex()
+ {
+ }
+
+ // Lock the mutex.
+ void lock()
+ {
+ }
+
+ // Unlock the mutex.
+ void unlock()
+ {
+ }
+};
+
+} // namespace detail
+} // namespace asio
+
+#include "asio/detail/pop_options.hpp"
+
+#endif // !defined(ASIO_HAS_THREADS)
+
+#endif // ASIO_DETAIL_NULL_MUTEX_HPP
diff --git a/lib/asio/detail/null_reactor.hpp b/lib/asio/detail/null_reactor.hpp
new file mode 100644
index 0000000..ca3c5fd
--- /dev/null
+++ b/lib/asio/detail/null_reactor.hpp
@@ -0,0 +1,68 @@
+//
+// detail/null_reactor.hpp
+// ~~~~~~~~~~~~~~~~~~~~~~~
+//
+// Copyright (c) 2003-2018 Christopher M. Kohlhoff (chris at kohlhoff dot com)
+//
+// 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 ASIO_DETAIL_NULL_REACTOR_HPP
+#define ASIO_DETAIL_NULL_REACTOR_HPP
+
+#if defined(_MSC_VER) && (_MSC_VER >= 1200)
+# pragma once
+#endif // defined(_MSC_VER) && (_MSC_VER >= 1200)
+
+#include "asio/detail/config.hpp"
+
+#if defined(ASIO_HAS_IOCP) || defined(ASIO_WINDOWS_RUNTIME)
+
+#include "asio/detail/scheduler_operation.hpp"
+#include "asio/execution_context.hpp"
+
+#include "asio/detail/push_options.hpp"
+
+namespace asio {
+namespace detail {
+
+class null_reactor
+ : public execution_context_service_base<null_reactor>
+{
+public:
+ // Constructor.
+ null_reactor(asio::execution_context& ctx)
+ : execution_context_service_base<null_reactor>(ctx)
+ {
+ }
+
+ // Destructor.
+ ~null_reactor()
+ {
+ }
+
+ // Destroy all user-defined handler objects owned by the service.
+ void shutdown()
+ {
+ }
+
+ // No-op because should never be called.
+ void run(long /*usec*/, op_queue<scheduler_operation>& /*ops*/)
+ {
+ }
+
+ // No-op.
+ void interrupt()
+ {
+ }
+};
+
+} // namespace detail
+} // namespace asio
+
+#include "asio/detail/pop_options.hpp"
+
+#endif // defined(ASIO_HAS_IOCP) || defined(ASIO_WINDOWS_RUNTIME)
+
+#endif // ASIO_DETAIL_NULL_REACTOR_HPP
diff --git a/lib/asio/detail/null_signal_blocker.hpp b/lib/asio/detail/null_signal_blocker.hpp
new file mode 100644
index 0000000..edfe820
--- /dev/null
+++ b/lib/asio/detail/null_signal_blocker.hpp
@@ -0,0 +1,69 @@
+//
+// detail/null_signal_blocker.hpp
+// ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+//
+// Copyright (c) 2003-2018 Christopher M. Kohlhoff (chris at kohlhoff dot com)
+//
+// 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 ASIO_DETAIL_NULL_SIGNAL_BLOCKER_HPP
+#define ASIO_DETAIL_NULL_SIGNAL_BLOCKER_HPP
+
+#if defined(_MSC_VER) && (_MSC_VER >= 1200)
+# pragma once
+#endif // defined(_MSC_VER) && (_MSC_VER >= 1200)
+
+#include "asio/detail/config.hpp"
+
+#if !defined(ASIO_HAS_THREADS) \
+ || defined(ASIO_WINDOWS) \
+ || defined(ASIO_WINDOWS_RUNTIME) \
+ || defined(__CYGWIN__) \
+ || defined(__SYMBIAN32__)
+
+#include "asio/detail/noncopyable.hpp"
+
+#include "asio/detail/push_options.hpp"
+
+namespace asio {
+namespace detail {
+
+class null_signal_blocker
+ : private noncopyable
+{
+public:
+ // Constructor blocks all signals for the calling thread.
+ null_signal_blocker()
+ {
+ }
+
+ // Destructor restores the previous signal mask.
+ ~null_signal_blocker()
+ {
+ }
+
+ // Block all signals for the calling thread.
+ void block()
+ {
+ }
+
+ // Restore the previous signal mask.
+ void unblock()
+ {
+ }
+};
+
+} // namespace detail
+} // namespace asio
+
+#include "asio/detail/pop_options.hpp"
+
+#endif // !defined(ASIO_HAS_THREADS)
+ // || defined(ASIO_WINDOWS)
+ // || defined(ASIO_WINDOWS_RUNTIME)
+ // || defined(__CYGWIN__)
+ // || defined(__SYMBIAN32__)
+
+#endif // ASIO_DETAIL_NULL_SIGNAL_BLOCKER_HPP
diff --git a/lib/asio/detail/null_socket_service.hpp b/lib/asio/detail/null_socket_service.hpp
new file mode 100644
index 0000000..109c6c7
--- /dev/null
+++ b/lib/asio/detail/null_socket_service.hpp
@@ -0,0 +1,508 @@
+//
+// detail/null_socket_service.hpp
+// ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+//
+// Copyright (c) 2003-2018 Christopher M. Kohlhoff (chris at kohlhoff dot com)
+//
+// 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 ASIO_DETAIL_NULL_SOCKET_SERVICE_HPP
+#define ASIO_DETAIL_NULL_SOCKET_SERVICE_HPP
+
+#if defined(_MSC_VER) && (_MSC_VER >= 1200)
+# pragma once
+#endif // defined(_MSC_VER) && (_MSC_VER >= 1200)
+
+#include "asio/detail/config.hpp"
+
+#if defined(ASIO_WINDOWS_RUNTIME)
+
+#include "asio/buffer.hpp"
+#include "asio/error.hpp"
+#include "asio/io_context.hpp"
+#include "asio/socket_base.hpp"
+#include "asio/detail/bind_handler.hpp"
+
+#include "asio/detail/push_options.hpp"
+
+namespace asio {
+namespace detail {
+
+template <typename Protocol>
+class null_socket_service :
+ public service_base<null_socket_service<Protocol> >
+{
+public:
+ // The protocol type.
+ typedef Protocol protocol_type;
+
+ // The endpoint type.
+ typedef typename Protocol::endpoint endpoint_type;
+
+ // The native type of a socket.
+ typedef int native_handle_type;
+
+ // The implementation type of the socket.
+ struct implementation_type
+ {
+ };
+
+ // Constructor.
+ null_socket_service(asio::io_context& io_context)
+ : service_base<null_socket_service<Protocol> >(io_context),
+ io_context_(io_context)
+ {
+ }
+
+ // Destroy all user-defined handler objects owned by the service.
+ void shutdown()
+ {
+ }
+
+ // Construct a new socket implementation.
+ void construct(implementation_type&)
+ {
+ }
+
+ // Move-construct a new socket implementation.
+ void move_construct(implementation_type&, implementation_type&)
+ {
+ }
+
+ // Move-assign from another socket implementation.
+ void move_assign(implementation_type&,
+ null_socket_service&, implementation_type&)
+ {
+ }
+
+ // Move-construct a new socket implementation from another protocol type.
+ template <typename Protocol1>
+ void converting_move_construct(implementation_type&,
+ null_socket_service<Protocol1>&,
+ typename null_socket_service<Protocol1>::implementation_type&)
+ {
+ }
+
+ // Destroy a socket implementation.
+ void destroy(implementation_type&)
+ {
+ }
+
+ // Open a new socket implementation.
+ asio::error_code open(implementation_type&,
+ const protocol_type&, asio::error_code& ec)
+ {
+ ec = asio::error::operation_not_supported;
+ return ec;
+ }
+
+ // Assign a native socket to a socket implementation.
+ asio::error_code assign(implementation_type&, const protocol_type&,
+ const native_handle_type&, asio::error_code& ec)
+ {
+ ec = asio::error::operation_not_supported;
+ return ec;
+ }
+
+ // Determine whether the socket is open.
+ bool is_open(const implementation_type&) const
+ {
+ return false;
+ }
+
+ // Destroy a socket implementation.
+ asio::error_code close(implementation_type&,
+ asio::error_code& ec)
+ {
+ ec = asio::error::operation_not_supported;
+ return ec;
+ }
+
+ // Release ownership of the socket.
+ native_handle_type release(implementation_type&,
+ asio::error_code& ec)
+ {
+ ec = asio::error::operation_not_supported;
+ return 0;
+ }
+
+ // Get the native socket representation.
+ native_handle_type native_handle(implementation_type&)
+ {
+ return 0;
+ }
+
+ // Cancel all operations associated with the socket.
+ asio::error_code cancel(implementation_type&,
+ asio::error_code& ec)
+ {
+ ec = asio::error::operation_not_supported;
+ return ec;
+ }
+
+ // Determine whether the socket is at the out-of-band data mark.
+ bool at_mark(const implementation_type&,
+ asio::error_code& ec) const
+ {
+ ec = asio::error::operation_not_supported;
+ return false;
+ }
+
+ // Determine the number of bytes available for reading.
+ std::size_t available(const implementation_type&,
+ asio::error_code& ec) const
+ {
+ ec = asio::error::operation_not_supported;
+ return 0;
+ }
+
+ // Place the socket into the state where it will listen for new connections.
+ asio::error_code listen(implementation_type&,
+ int, asio::error_code& ec)
+ {
+ ec = asio::error::operation_not_supported;
+ return ec;
+ }
+
+ // Perform an IO control command on the socket.
+ template <typename IO_Control_Command>
+ asio::error_code io_control(implementation_type&,
+ IO_Control_Command&, asio::error_code& ec)
+ {
+ ec = asio::error::operation_not_supported;
+ return ec;
+ }
+
+ // Gets the non-blocking mode of the socket.
+ bool non_blocking(const implementation_type&) const
+ {
+ return false;
+ }
+
+ // Sets the non-blocking mode of the socket.
+ asio::error_code non_blocking(implementation_type&,
+ bool, asio::error_code& ec)
+ {
+ ec = asio::error::operation_not_supported;
+ return ec;
+ }
+
+ // Gets the non-blocking mode of the native socket implementation.
+ bool native_non_blocking(const implementation_type&) const
+ {
+ return false;
+ }
+
+ // Sets the non-blocking mode of the native socket implementation.
+ asio::error_code native_non_blocking(implementation_type&,
+ bool, asio::error_code& ec)
+ {
+ ec = asio::error::operation_not_supported;
+ return ec;
+ }
+
+ // Disable sends or receives on the socket.
+ asio::error_code shutdown(implementation_type&,
+ socket_base::shutdown_type, asio::error_code& ec)
+ {
+ ec = asio::error::operation_not_supported;
+ return ec;
+ }
+
+ // Bind the socket to the specified local endpoint.
+ asio::error_code bind(implementation_type&,
+ const endpoint_type&, asio::error_code& ec)
+ {
+ ec = asio::error::operation_not_supported;
+ return ec;
+ }
+
+ // Set a socket option.
+ template <typename Option>
+ asio::error_code set_option(implementation_type&,
+ const Option&, asio::error_code& ec)
+ {
+ ec = asio::error::operation_not_supported;
+ return ec;
+ }
+
+ // Set a socket option.
+ template <typename Option>
+ asio::error_code get_option(const implementation_type&,
+ Option&, asio::error_code& ec) const
+ {
+ ec = asio::error::operation_not_supported;
+ return ec;
+ }
+
+ // Get the local endpoint.
+ endpoint_type local_endpoint(const implementation_type&,
+ asio::error_code& ec) const
+ {
+ ec = asio::error::operation_not_supported;
+ return endpoint_type();
+ }
+
+ // Get the remote endpoint.
+ endpoint_type remote_endpoint(const implementation_type&,
+ asio::error_code& ec) const
+ {
+ ec = asio::error::operation_not_supported;
+ return endpoint_type();
+ }
+
+ // Send the given data to the peer.
+ template <typename ConstBufferSequence>
+ std::size_t send(implementation_type&, const ConstBufferSequence&,
+ socket_base::message_flags, asio::error_code& ec)
+ {
+ ec = asio::error::operation_not_supported;
+ return 0;
+ }
+
+ // Wait until data can be sent without blocking.
+ std::size_t send(implementation_type&, const null_buffers&,
+ socket_base::message_flags, asio::error_code& ec)
+ {
+ ec = asio::error::operation_not_supported;
+ 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>
+ void async_send(implementation_type&, const ConstBufferSequence&,
+ socket_base::message_flags, Handler& handler)
+ {
+ asio::error_code ec = asio::error::operation_not_supported;
+ const std::size_t bytes_transferred = 0;
+ io_context_.post(detail::bind_handler(handler, ec, bytes_transferred));
+ }
+
+ // Start an asynchronous wait until data can be sent without blocking.
+ template <typename Handler>
+ void async_send(implementation_type&, const null_buffers&,
+ socket_base::message_flags, Handler& handler)
+ {
+ asio::error_code ec = asio::error::operation_not_supported;
+ const std::size_t bytes_transferred = 0;
+ io_context_.post(detail::bind_handler(handler, ec, bytes_transferred));
+ }
+
+ // Receive some data from the peer. Returns the number of bytes received.
+ template <typename MutableBufferSequence>
+ std::size_t receive(implementation_type&, const MutableBufferSequence&,
+ socket_base::message_flags, asio::error_code& ec)
+ {
+ ec = asio::error::operation_not_supported;
+ return 0;
+ }
+
+ // Wait until data can be received without blocking.
+ std::size_t receive(implementation_type&, const null_buffers&,
+ socket_base::message_flags, asio::error_code& ec)
+ {
+ ec = asio::error::operation_not_supported;
+ 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>
+ void async_receive(implementation_type&, const MutableBufferSequence&,
+ socket_base::message_flags, Handler& handler)
+ {
+ asio::error_code ec = asio::error::operation_not_supported;
+ const std::size_t bytes_transferred = 0;
+ io_context_.post(detail::bind_handler(handler, ec, bytes_transferred));
+ }
+
+ // Wait until data can be received without blocking.
+ template <typename Handler>
+ void async_receive(implementation_type&, const null_buffers&,
+ socket_base::message_flags, Handler& handler)
+ {
+ asio::error_code ec = asio::error::operation_not_supported;
+ const std::size_t bytes_transferred = 0;
+ io_context_.post(detail::bind_handler(handler, ec, bytes_transferred));
+ }
+
+ // Receive some data with associated flags. Returns the number of bytes
+ // received.
+ template <typename MutableBufferSequence>
+ std::size_t receive_with_flags(implementation_type&,
+ const MutableBufferSequence&, socket_base::message_flags,
+ socket_base::message_flags&, asio::error_code& ec)
+ {
+ ec = asio::error::operation_not_supported;
+ return 0;
+ }
+
+ // Wait until data can be received without blocking.
+ std::size_t receive_with_flags(implementation_type&,
+ const null_buffers&, socket_base::message_flags,
+ socket_base::message_flags&, asio::error_code& ec)
+ {
+ ec = asio::error::operation_not_supported;
+ 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>
+ void async_receive_with_flags(implementation_type&,
+ const MutableBufferSequence&, socket_base::message_flags,
+ socket_base::message_flags&, Handler& handler)
+ {
+ asio::error_code ec = asio::error::operation_not_supported;
+ const std::size_t bytes_transferred = 0;
+ io_context_.post(detail::bind_handler(handler, ec, bytes_transferred));
+ }
+
+ // Wait until data can be received without blocking.
+ template <typename Handler>
+ void async_receive_with_flags(implementation_type&,
+ const null_buffers&, socket_base::message_flags,
+ socket_base::message_flags&, Handler& handler)
+ {
+ asio::error_code ec = asio::error::operation_not_supported;
+ const std::size_t bytes_transferred = 0;
+ io_context_.post(detail::bind_handler(handler, ec, bytes_transferred));
+ }
+
+ // Send a datagram to the specified endpoint. Returns the number of bytes
+ // sent.
+ template <typename ConstBufferSequence>
+ std::size_t send_to(implementation_type&, const ConstBufferSequence&,
+ const endpoint_type&, socket_base::message_flags,
+ asio::error_code& ec)
+ {
+ ec = asio::error::operation_not_supported;
+ return 0;
+ }
+
+ // Wait until data can be sent without blocking.
+ std::size_t send_to(implementation_type&, const null_buffers&,
+ const endpoint_type&, socket_base::message_flags,
+ asio::error_code& ec)
+ {
+ ec = asio::error::operation_not_supported;
+ 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>
+ void async_send_to(implementation_type&, const ConstBufferSequence&,
+ const endpoint_type&, socket_base::message_flags,
+ Handler& handler)
+ {
+ asio::error_code ec = asio::error::operation_not_supported;
+ const std::size_t bytes_transferred = 0;
+ io_context_.post(detail::bind_handler(handler, ec, bytes_transferred));
+ }
+
+ // Start an asynchronous wait until data can be sent without blocking.
+ template <typename Handler>
+ void async_send_to(implementation_type&, const null_buffers&,
+ const endpoint_type&, socket_base::message_flags, Handler& handler)
+ {
+ asio::error_code ec = asio::error::operation_not_supported;
+ const std::size_t bytes_transferred = 0;
+ io_context_.post(detail::bind_handler(handler, ec, bytes_transferred));
+ }
+
+ // Receive a datagram with the endpoint of the sender. Returns the number of
+ // bytes received.
+ template <typename MutableBufferSequence>
+ std::size_t receive_from(implementation_type&, const MutableBufferSequence&,
+ endpoint_type&, socket_base::message_flags,
+ asio::error_code& ec)
+ {
+ ec = asio::error::operation_not_supported;
+ return 0;
+ }
+
+ // Wait until data can be received without blocking.
+ std::size_t receive_from(implementation_type&, const null_buffers&,
+ endpoint_type&, socket_base::message_flags,
+ asio::error_code& ec)
+ {
+ ec = asio::error::operation_not_supported;
+ 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>
+ void async_receive_from(implementation_type&,
+ const MutableBufferSequence&, endpoint_type&,
+ socket_base::message_flags, Handler& handler)
+ {
+ asio::error_code ec = asio::error::operation_not_supported;
+ const std::size_t bytes_transferred = 0;
+ io_context_.post(detail::bind_handler(handler, ec, bytes_transferred));
+ }
+
+ // Wait until data can be received without blocking.
+ template <typename Handler>
+ void async_receive_from(implementation_type&,
+ const null_buffers&, endpoint_type&,
+ socket_base::message_flags, Handler& handler)
+ {
+ asio::error_code ec = asio::error::operation_not_supported;
+ const std::size_t bytes_transferred = 0;
+ io_context_.post(detail::bind_handler(handler, ec, bytes_transferred));
+ }
+
+ // Accept a new connection.
+ template <typename Socket>
+ asio::error_code accept(implementation_type&,
+ Socket&, endpoint_type*, asio::error_code& ec)
+ {
+ ec = asio::error::operation_not_supported;
+ 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>
+ void async_accept(implementation_type&, Socket&,
+ endpoint_type*, Handler& handler)
+ {
+ asio::error_code ec = asio::error::operation_not_supported;
+ io_context_.post(detail::bind_handler(handler, ec));
+ }
+
+ // Connect the socket to the specified endpoint.
+ asio::error_code connect(implementation_type&,
+ const endpoint_type&, asio::error_code& ec)
+ {
+ ec = asio::error::operation_not_supported;
+ return ec;
+ }
+
+ // Start an asynchronous connect.
+ template <typename Handler>
+ void async_connect(implementation_type&,
+ const endpoint_type&, Handler& handler)
+ {
+ asio::error_code ec = asio::error::operation_not_supported;
+ io_context_.post(detail::bind_handler(handler, ec));
+ }
+
+private:
+ asio::io_context& io_context_;
+};
+
+} // namespace detail
+} // namespace asio
+
+#include "asio/detail/pop_options.hpp"
+
+#endif // defined(ASIO_WINDOWS_RUNTIME)
+
+#endif // ASIO_DETAIL_NULL_SOCKET_SERVICE_HPP
diff --git a/lib/asio/detail/null_static_mutex.hpp b/lib/asio/detail/null_static_mutex.hpp
new file mode 100644
index 0000000..36ec04f
--- /dev/null
+++ b/lib/asio/detail/null_static_mutex.hpp
@@ -0,0 +1,60 @@
+//
+// detail/null_static_mutex.hpp
+// ~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+//
+// Copyright (c) 2003-2018 Christopher M. Kohlhoff (chris at kohlhoff dot com)
+//
+// 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 ASIO_DETAIL_NULL_STATIC_MUTEX_HPP
+#define ASIO_DETAIL_NULL_STATIC_MUTEX_HPP
+
+#if defined(_MSC_VER) && (_MSC_VER >= 1200)
+# pragma once
+#endif // defined(_MSC_VER) && (_MSC_VER >= 1200)
+
+#include "asio/detail/config.hpp"
+
+#if !defined(ASIO_HAS_THREADS)
+
+#include "asio/detail/scoped_lock.hpp"
+
+#include "asio/detail/push_options.hpp"
+
+namespace asio {
+namespace detail {
+
+struct null_static_mutex
+{
+ typedef asio::detail::scoped_lock<null_static_mutex> scoped_lock;
+
+ // Initialise the mutex.
+ void init()
+ {
+ }
+
+ // Lock the mutex.
+ void lock()
+ {
+ }
+
+ // Unlock the mutex.
+ void unlock()
+ {
+ }
+
+ int unused_;
+};
+
+#define ASIO_NULL_STATIC_MUTEX_INIT { 0 }
+
+} // namespace detail
+} // namespace asio
+
+#include "asio/detail/pop_options.hpp"
+
+#endif // !defined(ASIO_HAS_THREADS)
+
+#endif // ASIO_DETAIL_NULL_STATIC_MUTEX_HPP
diff --git a/lib/asio/detail/null_thread.hpp b/lib/asio/detail/null_thread.hpp
new file mode 100644
index 0000000..7291ba3
--- /dev/null
+++ b/lib/asio/detail/null_thread.hpp
@@ -0,0 +1,67 @@
+//
+// detail/null_thread.hpp
+// ~~~~~~~~~~~~~~~~~~~~~~
+//
+// Copyright (c) 2003-2018 Christopher M. Kohlhoff (chris at kohlhoff dot com)
+//
+// 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 ASIO_DETAIL_NULL_THREAD_HPP
+#define ASIO_DETAIL_NULL_THREAD_HPP
+
+#if defined(_MSC_VER) && (_MSC_VER >= 1200)
+# pragma once
+#endif // defined(_MSC_VER) && (_MSC_VER >= 1200)
+
+#include "asio/detail/config.hpp"
+
+#if !defined(ASIO_HAS_THREADS)
+
+#include "asio/detail/noncopyable.hpp"
+#include "asio/detail/throw_error.hpp"
+#include "asio/error.hpp"
+
+#include "asio/detail/push_options.hpp"
+
+namespace asio {
+namespace detail {
+
+class null_thread
+ : private noncopyable
+{
+public:
+ // Constructor.
+ template <typename Function>
+ null_thread(Function, unsigned int = 0)
+ {
+ asio::detail::throw_error(
+ asio::error::operation_not_supported, "thread");
+ }
+
+ // Destructor.
+ ~null_thread()
+ {
+ }
+
+ // Wait for the thread to exit.
+ void join()
+ {
+ }
+
+ // Get number of CPUs.
+ static std::size_t hardware_concurrency()
+ {
+ return 1;
+ }
+};
+
+} // namespace detail
+} // namespace asio
+
+#include "asio/detail/pop_options.hpp"
+
+#endif // !defined(ASIO_HAS_THREADS)
+
+#endif // ASIO_DETAIL_NULL_THREAD_HPP
diff --git a/lib/asio/detail/null_tss_ptr.hpp b/lib/asio/detail/null_tss_ptr.hpp
new file mode 100644
index 0000000..323967d
--- /dev/null
+++ b/lib/asio/detail/null_tss_ptr.hpp
@@ -0,0 +1,68 @@
+//
+// detail/null_tss_ptr.hpp
+// ~~~~~~~~~~~~~~~~~~~~~~~
+//
+// Copyright (c) 2003-2018 Christopher M. Kohlhoff (chris at kohlhoff dot com)
+//
+// 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 ASIO_DETAIL_NULL_TSS_PTR_HPP
+#define ASIO_DETAIL_NULL_TSS_PTR_HPP
+
+#if defined(_MSC_VER) && (_MSC_VER >= 1200)
+# pragma once
+#endif // defined(_MSC_VER) && (_MSC_VER >= 1200)
+
+#include "asio/detail/config.hpp"
+
+#if !defined(ASIO_HAS_THREADS)
+
+#include "asio/detail/noncopyable.hpp"
+
+#include "asio/detail/push_options.hpp"
+
+namespace asio {
+namespace detail {
+
+template <typename T>
+class null_tss_ptr
+ : private noncopyable
+{
+public:
+ // Constructor.
+ null_tss_ptr()
+ : value_(0)
+ {
+ }
+
+ // Destructor.
+ ~null_tss_ptr()
+ {
+ }
+
+ // Get the value.
+ operator T*() const
+ {
+ return value_;
+ }
+
+ // Set the value.
+ void operator=(T* value)
+ {
+ value_ = value;
+ }
+
+private:
+ T* value_;
+};
+
+} // namespace detail
+} // namespace asio
+
+#include "asio/detail/pop_options.hpp"
+
+#endif // !defined(ASIO_HAS_THREADS)
+
+#endif // ASIO_DETAIL_NULL_TSS_PTR_HPP
diff --git a/lib/asio/detail/object_pool.hpp b/lib/asio/detail/object_pool.hpp
new file mode 100644
index 0000000..e1a3c54
--- /dev/null
+++ b/lib/asio/detail/object_pool.hpp
@@ -0,0 +1,171 @@
+//
+// detail/object_pool.hpp
+// ~~~~~~~~~~~~~~~~~~~~~~
+//
+// Copyright (c) 2003-2018 Christopher M. Kohlhoff (chris at kohlhoff dot com)
+//
+// 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 ASIO_DETAIL_OBJECT_POOL_HPP
+#define ASIO_DETAIL_OBJECT_POOL_HPP
+
+#if defined(_MSC_VER) && (_MSC_VER >= 1200)
+# pragma once
+#endif // defined(_MSC_VER) && (_MSC_VER >= 1200)
+
+#include "asio/detail/noncopyable.hpp"
+
+#include "asio/detail/push_options.hpp"
+
+namespace asio {
+namespace detail {
+
+template <typename Object>
+class object_pool;
+
+class object_pool_access
+{
+public:
+ template <typename Object>
+ static Object* create()
+ {
+ return new Object;
+ }
+
+ template <typename Object, typename Arg>
+ static Object* create(Arg arg)
+ {
+ return new Object(arg);
+ }
+
+ template <typename Object>
+ static void destroy(Object* o)
+ {
+ delete o;
+ }
+
+ template <typename Object>
+ static Object*& next(Object* o)
+ {
+ return o->next_;
+ }
+
+ template <typename Object>
+ static Object*& prev(Object* o)
+ {
+ return o->prev_;
+ }
+};
+
+template <typename Object>
+class object_pool
+ : private noncopyable
+{
+public:
+ // Constructor.
+ object_pool()
+ : live_list_(0),
+ free_list_(0)
+ {
+ }
+
+ // Destructor destroys all objects.
+ ~object_pool()
+ {
+ destroy_list(live_list_);
+ destroy_list(free_list_);
+ }
+
+ // Get the object at the start of the live list.
+ Object* first()
+ {
+ return live_list_;
+ }
+
+ // Allocate a new object.
+ Object* alloc()
+ {
+ Object* o = free_list_;
+ if (o)
+ free_list_ = object_pool_access::next(free_list_);
+ else
+ o = object_pool_access::create<Object>();
+
+ object_pool_access::next(o) = live_list_;
+ object_pool_access::prev(o) = 0;
+ if (live_list_)
+ object_pool_access::prev(live_list_) = o;
+ live_list_ = o;
+
+ return o;
+ }
+
+ // Allocate a new object with an argument.
+ template <typename Arg>
+ Object* alloc(Arg arg)
+ {
+ Object* o = free_list_;
+ if (o)
+ free_list_ = object_pool_access::next(free_list_);
+ else
+ o = object_pool_access::create<Object>(arg);
+
+ object_pool_access::next(o) = live_list_;
+ object_pool_access::prev(o) = 0;
+ if (live_list_)
+ object_pool_access::prev(live_list_) = o;
+ live_list_ = o;
+
+ return o;
+ }
+
+ // Free an object. Moves it to the free list. No destructors are run.
+ void free(Object* o)
+ {
+ if (live_list_ == o)
+ live_list_ = object_pool_access::next(o);
+
+ if (object_pool_access::prev(o))
+ {
+ object_pool_access::next(object_pool_access::prev(o))
+ = object_pool_access::next(o);
+ }
+
+ if (object_pool_access::next(o))
+ {
+ object_pool_access::prev(object_pool_access::next(o))
+ = object_pool_access::prev(o);
+ }
+
+ object_pool_access::next(o) = free_list_;
+ object_pool_access::prev(o) = 0;
+ free_list_ = o;
+ }
+
+private:
+ // Helper function to destroy all elements in a list.
+ void destroy_list(Object* list)
+ {
+ while (list)
+ {
+ Object* o = list;
+ list = object_pool_access::next(o);
+ object_pool_access::destroy(o);
+ }
+ }
+
+ // The list of live objects.
+ Object* live_list_;
+
+ // The free list.
+ Object* free_list_;
+};
+
+} // namespace detail
+} // namespace asio
+
+#include "asio/detail/pop_options.hpp"
+
+#endif // ASIO_DETAIL_OBJECT_POOL_HPP
diff --git a/lib/asio/detail/old_win_sdk_compat.hpp b/lib/asio/detail/old_win_sdk_compat.hpp
new file mode 100644
index 0000000..bfb109e
--- /dev/null
+++ b/lib/asio/detail/old_win_sdk_compat.hpp
@@ -0,0 +1,214 @@
+//
+// detail/old_win_sdk_compat.hpp
+// ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+//
+// Copyright (c) 2003-2018 Christopher M. Kohlhoff (chris at kohlhoff dot com)
+//
+// 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 ASIO_DETAIL_OLD_WIN_SDK_COMPAT_HPP
+#define ASIO_DETAIL_OLD_WIN_SDK_COMPAT_HPP
+
+#if defined(_MSC_VER) && (_MSC_VER >= 1200)
+# pragma once
+#endif // defined(_MSC_VER) && (_MSC_VER >= 1200)
+
+#include "asio/detail/config.hpp"
+
+#if defined(ASIO_WINDOWS) || defined(__CYGWIN__)
+
+// Guess whether we are building against on old Platform SDK.
+#if !defined(IN6ADDR_ANY_INIT)
+#define ASIO_HAS_OLD_WIN_SDK 1
+#endif // !defined(IN6ADDR_ANY_INIT)
+
+#if defined(ASIO_HAS_OLD_WIN_SDK)
+
+// Emulation of types that are missing from old Platform SDKs.
+//
+// N.B. this emulation is also used if building for a Windows 2000 target with
+// a recent (i.e. Vista or later) SDK, as the SDK does not provide IPv6 support
+// in that case.
+
+#include "asio/detail/push_options.hpp"
+
+namespace asio {
+namespace detail {
+
+enum
+{
+ sockaddr_storage_maxsize = 128, // Maximum size.
+ sockaddr_storage_alignsize = (sizeof(__int64)), // Desired alignment.
+ sockaddr_storage_pad1size = (sockaddr_storage_alignsize - sizeof(short)),
+ sockaddr_storage_pad2size = (sockaddr_storage_maxsize -
+ (sizeof(short) + sockaddr_storage_pad1size + sockaddr_storage_alignsize))
+};
+
+struct sockaddr_storage_emulation
+{
+ short ss_family;
+ char __ss_pad1[sockaddr_storage_pad1size];
+ __int64 __ss_align;
+ char __ss_pad2[sockaddr_storage_pad2size];
+};
+
+struct in6_addr_emulation
+{
+ union
+ {
+ u_char Byte[16];
+ u_short Word[8];
+ } u;
+};
+
+#if !defined(s6_addr)
+# define _S6_un u
+# define _S6_u8 Byte
+# define s6_addr _S6_un._S6_u8
+#endif // !defined(s6_addr)
+
+struct sockaddr_in6_emulation
+{
+ short sin6_family;
+ u_short sin6_port;
+ u_long sin6_flowinfo;
+ in6_addr_emulation sin6_addr;
+ u_long sin6_scope_id;
+};
+
+struct ipv6_mreq_emulation
+{
+ in6_addr_emulation ipv6mr_multiaddr;
+ unsigned int ipv6mr_interface;
+};
+
+struct addrinfo_emulation
+{
+ int ai_flags;
+ int ai_family;
+ int ai_socktype;
+ int ai_protocol;
+ size_t ai_addrlen;
+ char* ai_canonname;
+ sockaddr* ai_addr;
+ addrinfo_emulation* ai_next;
+};
+
+#if !defined(AI_PASSIVE)
+# define AI_PASSIVE 0x1
+#endif
+
+#if !defined(AI_CANONNAME)
+# define AI_CANONNAME 0x2
+#endif
+
+#if !defined(AI_NUMERICHOST)
+# define AI_NUMERICHOST 0x4
+#endif
+
+#if !defined(EAI_AGAIN)
+# define EAI_AGAIN WSATRY_AGAIN
+#endif
+
+#if !defined(EAI_BADFLAGS)
+# define EAI_BADFLAGS WSAEINVAL
+#endif
+
+#if !defined(EAI_FAIL)
+# define EAI_FAIL WSANO_RECOVERY
+#endif
+
+#if !defined(EAI_FAMILY)
+# define EAI_FAMILY WSAEAFNOSUPPORT
+#endif
+
+#if !defined(EAI_MEMORY)
+# define EAI_MEMORY WSA_NOT_ENOUGH_MEMORY
+#endif
+
+#if !defined(EAI_NODATA)
+# define EAI_NODATA WSANO_DATA
+#endif
+
+#if !defined(EAI_NONAME)
+# define EAI_NONAME WSAHOST_NOT_FOUND
+#endif
+
+#if !defined(EAI_SERVICE)
+# define EAI_SERVICE WSATYPE_NOT_FOUND
+#endif
+
+#if !defined(EAI_SOCKTYPE)
+# define EAI_SOCKTYPE WSAESOCKTNOSUPPORT
+#endif
+
+#if !defined(NI_NOFQDN)
+# define NI_NOFQDN 0x01
+#endif
+
+#if !defined(NI_NUMERICHOST)
+# define NI_NUMERICHOST 0x02
+#endif
+
+#if !defined(NI_NAMEREQD)
+# define NI_NAMEREQD 0x04
+#endif
+
+#if !defined(NI_NUMERICSERV)
+# define NI_NUMERICSERV 0x08
+#endif
+
+#if !defined(NI_DGRAM)
+# define NI_DGRAM 0x10
+#endif
+
+#if !defined(IPPROTO_IPV6)
+# define IPPROTO_IPV6 41
+#endif
+
+#if !defined(IPV6_UNICAST_HOPS)
+# define IPV6_UNICAST_HOPS 4
+#endif
+
+#if !defined(IPV6_MULTICAST_IF)
+# define IPV6_MULTICAST_IF 9
+#endif
+
+#if !defined(IPV6_MULTICAST_HOPS)
+# define IPV6_MULTICAST_HOPS 10
+#endif
+
+#if !defined(IPV6_MULTICAST_LOOP)
+# define IPV6_MULTICAST_LOOP 11
+#endif
+
+#if !defined(IPV6_JOIN_GROUP)
+# define IPV6_JOIN_GROUP 12
+#endif
+
+#if !defined(IPV6_LEAVE_GROUP)
+# define IPV6_LEAVE_GROUP 13
+#endif
+
+} // namespace detail
+} // namespace asio
+
+#include "asio/detail/pop_options.hpp"
+
+#endif // defined(ASIO_HAS_OLD_WIN_SDK)
+
+// Even newer Platform SDKs that support IPv6 may not define IPV6_V6ONLY.
+#if !defined(IPV6_V6ONLY)
+# define IPV6_V6ONLY 27
+#endif
+
+// Some SDKs (e.g. Windows CE) don't define IPPROTO_ICMPV6.
+#if !defined(IPPROTO_ICMPV6)
+# define IPPROTO_ICMPV6 58
+#endif
+
+#endif // defined(ASIO_WINDOWS) || defined(__CYGWIN__)
+
+#endif // ASIO_DETAIL_OLD_WIN_SDK_COMPAT_HPP
diff --git a/lib/asio/detail/op_queue.hpp b/lib/asio/detail/op_queue.hpp
new file mode 100644
index 0000000..6219f79
--- /dev/null
+++ b/lib/asio/detail/op_queue.hpp
@@ -0,0 +1,162 @@
+//
+// detail/op_queue.hpp
+// ~~~~~~~~~~~~~~~~~~~
+//
+// Copyright (c) 2003-2018 Christopher M. Kohlhoff (chris at kohlhoff dot com)
+//
+// 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 ASIO_DETAIL_OP_QUEUE_HPP
+#define ASIO_DETAIL_OP_QUEUE_HPP
+
+#if defined(_MSC_VER) && (_MSC_VER >= 1200)
+# pragma once
+#endif // defined(_MSC_VER) && (_MSC_VER >= 1200)
+
+#include "asio/detail/noncopyable.hpp"
+
+#include "asio/detail/push_options.hpp"
+
+namespace asio {
+namespace detail {
+
+template <typename Operation>
+class op_queue;
+
+class op_queue_access
+{
+public:
+ template <typename Operation>
+ static Operation* next(Operation* o)
+ {
+ return static_cast<Operation*>(o->next_);
+ }
+
+ template <typename Operation1, typename Operation2>
+ static void next(Operation1*& o1, Operation2* o2)
+ {
+ o1->next_ = o2;
+ }
+
+ template <typename Operation>
+ static void destroy(Operation* o)
+ {
+ o->destroy();
+ }
+
+ template <typename Operation>
+ static Operation*& front(op_queue<Operation>& q)
+ {
+ return q.front_;
+ }
+
+ template <typename Operation>
+ static Operation*& back(op_queue<Operation>& q)
+ {
+ return q.back_;
+ }
+};
+
+template <typename Operation>
+class op_queue
+ : private noncopyable
+{
+public:
+ // Constructor.
+ op_queue()
+ : front_(0),
+ back_(0)
+ {
+ }
+
+ // Destructor destroys all operations.
+ ~op_queue()
+ {
+ while (Operation* op = front_)
+ {
+ pop();
+ op_queue_access::destroy(op);
+ }
+ }
+
+ // Get the operation at the front of the queue.
+ Operation* front()
+ {
+ return front_;
+ }
+
+ // Pop an operation from the front of the queue.
+ void pop()
+ {
+ if (front_)
+ {
+ Operation* tmp = front_;
+ front_ = op_queue_access::next(front_);
+ if (front_ == 0)
+ back_ = 0;
+ op_queue_access::next(tmp, static_cast<Operation*>(0));
+ }
+ }
+
+ // Push an operation on to the back of the queue.
+ void push(Operation* h)
+ {
+ op_queue_access::next(h, static_cast<Operation*>(0));
+ if (back_)
+ {
+ op_queue_access::next(back_, h);
+ back_ = h;
+ }
+ else
+ {
+ front_ = back_ = h;
+ }
+ }
+
+ // Push all operations from another queue on to the back of the queue. The
+ // source queue may contain operations of a derived type.
+ template <typename OtherOperation>
+ void push(op_queue<OtherOperation>& q)
+ {
+ if (Operation* other_front = op_queue_access::front(q))
+ {
+ if (back_)
+ op_queue_access::next(back_, other_front);
+ else
+ front_ = other_front;
+ back_ = op_queue_access::back(q);
+ op_queue_access::front(q) = 0;
+ op_queue_access::back(q) = 0;
+ }
+ }
+
+ // Whether the queue is empty.
+ bool empty() const
+ {
+ return front_ == 0;
+ }
+
+ // Test whether an operation is already enqueued.
+ bool is_enqueued(Operation* o) const
+ {
+ return op_queue_access::next(o) != 0 || back_ == o;
+ }
+
+private:
+ friend class op_queue_access;
+
+ // The front of the queue.
+ Operation* front_;
+
+ // The back of the queue.
+ Operation* back_;
+};
+
+} // namespace detail
+} // namespace asio
+
+#include "asio/detail/pop_options.hpp"
+
+#endif // ASIO_DETAIL_OP_QUEUE_HPP
diff --git a/lib/asio/detail/operation.hpp b/lib/asio/detail/operation.hpp
new file mode 100644
index 0000000..811e54d
--- /dev/null
+++ b/lib/asio/detail/operation.hpp
@@ -0,0 +1,38 @@
+//
+// detail/operation.hpp
+// ~~~~~~~~~~~~~~~~~~~~
+//
+// Copyright (c) 2003-2018 Christopher M. Kohlhoff (chris at kohlhoff dot com)
+//
+// 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 ASIO_DETAIL_OPERATION_HPP
+#define ASIO_DETAIL_OPERATION_HPP
+
+#if defined(_MSC_VER) && (_MSC_VER >= 1200)
+# pragma once
+#endif // defined(_MSC_VER) && (_MSC_VER >= 1200)
+
+#include "asio/detail/config.hpp"
+
+#if defined(ASIO_HAS_IOCP)
+# include "asio/detail/win_iocp_operation.hpp"
+#else
+# include "asio/detail/scheduler_operation.hpp"
+#endif
+
+namespace asio {
+namespace detail {
+
+#if defined(ASIO_HAS_IOCP)
+typedef win_iocp_operation operation;
+#else
+typedef scheduler_operation operation;
+#endif
+
+} // namespace detail
+} // namespace asio
+
+#endif // ASIO_DETAIL_OPERATION_HPP
diff --git a/lib/asio/detail/pipe_select_interrupter.hpp b/lib/asio/detail/pipe_select_interrupter.hpp
new file mode 100644
index 0000000..55d7db4
--- /dev/null
+++ b/lib/asio/detail/pipe_select_interrupter.hpp
@@ -0,0 +1,89 @@
+//
+// detail/pipe_select_interrupter.hpp
+// ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+//
+// Copyright (c) 2003-2018 Christopher M. Kohlhoff (chris at kohlhoff dot com)
+//
+// 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 ASIO_DETAIL_PIPE_SELECT_INTERRUPTER_HPP
+#define ASIO_DETAIL_PIPE_SELECT_INTERRUPTER_HPP
+
+#if defined(_MSC_VER) && (_MSC_VER >= 1200)
+# pragma once
+#endif // defined(_MSC_VER) && (_MSC_VER >= 1200)
+
+#include "asio/detail/config.hpp"
+
+#if !defined(ASIO_WINDOWS)
+#if !defined(ASIO_WINDOWS_RUNTIME)
+#if !defined(__CYGWIN__)
+#if !defined(__SYMBIAN32__)
+#if !defined(ASIO_HAS_EVENTFD)
+
+#include "asio/detail/push_options.hpp"
+
+namespace asio {
+namespace detail {
+
+class pipe_select_interrupter
+{
+public:
+ // Constructor.
+ ASIO_DECL pipe_select_interrupter();
+
+ // Destructor.
+ ASIO_DECL ~pipe_select_interrupter();
+
+ // Recreate the interrupter's descriptors. Used after a fork.
+ ASIO_DECL void recreate();
+
+ // Interrupt the select call.
+ ASIO_DECL void interrupt();
+
+ // Reset the select interrupt. Returns true if the call was interrupted.
+ ASIO_DECL bool reset();
+
+ // Get the read descriptor to be passed to select.
+ int read_descriptor() const
+ {
+ return read_descriptor_;
+ }
+
+private:
+ // Open the descriptors. Throws on error.
+ ASIO_DECL void open_descriptors();
+
+ // Close the descriptors.
+ ASIO_DECL void close_descriptors();
+
+ // The read end of a connection used to interrupt the select call. This file
+ // descriptor is passed to select such that when it is time to stop, a single
+ // byte will be written on the other end of the connection and this
+ // descriptor will become readable.
+ int read_descriptor_;
+
+ // The write end of a connection used to interrupt the select call. A single
+ // byte may be written to this to wake up the select which is waiting for the
+ // other end to become readable.
+ int write_descriptor_;
+};
+
+} // namespace detail
+} // namespace asio
+
+#include "asio/detail/pop_options.hpp"
+
+#if defined(ASIO_HEADER_ONLY)
+# include "asio/detail/impl/pipe_select_interrupter.ipp"
+#endif // defined(ASIO_HEADER_ONLY)
+
+#endif // !defined(ASIO_HAS_EVENTFD)
+#endif // !defined(__SYMBIAN32__)
+#endif // !defined(__CYGWIN__)
+#endif // !defined(ASIO_WINDOWS_RUNTIME)
+#endif // !defined(ASIO_WINDOWS)
+
+#endif // ASIO_DETAIL_PIPE_SELECT_INTERRUPTER_HPP
diff --git a/lib/asio/detail/pop_options.hpp b/lib/asio/detail/pop_options.hpp
new file mode 100644
index 0000000..1045612
--- /dev/null
+++ b/lib/asio/detail/pop_options.hpp
@@ -0,0 +1,135 @@
+//
+// detail/pop_options.hpp
+// ~~~~~~~~~~~~~~~~~~~~~~
+//
+// Copyright (c) 2003-2018 Christopher M. Kohlhoff (chris at kohlhoff dot com)
+//
+// 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)
+//
+
+// No header guard
+
+#if defined(__COMO__)
+
+// Comeau C++
+
+#elif defined(__DMC__)
+
+// Digital Mars C++
+
+#elif defined(__INTEL_COMPILER) || defined(__ICL) \
+ || defined(__ICC) || defined(__ECC)
+
+// Intel C++
+
+# if (__GNUC__ == 4 && __GNUC_MINOR__ >= 1) || (__GNUC__ > 4)
+# pragma GCC visibility pop
+# endif // (__GNUC__ == 4 && __GNUC_MINOR__ >= 1) || (__GNUC__ > 4)
+
+#elif defined(__clang__)
+
+// Clang
+
+# if defined(__OBJC__)
+# if !defined(__APPLE_CC__) || (__APPLE_CC__ <= 1)
+# if defined(ASIO_OBJC_WORKAROUND)
+# undef Protocol
+# undef id
+# undef ASIO_OBJC_WORKAROUND
+# endif
+# endif
+# endif
+
+# if !defined(_WIN32) && !defined(__WIN32__) && !defined(WIN32)
+# pragma GCC visibility pop
+# endif // !defined(_WIN32) && !defined(__WIN32__) && !defined(WIN32)
+
+#elif defined(__GNUC__)
+
+// GNU C++
+
+# if defined(__MINGW32__) || defined(__CYGWIN__)
+# pragma pack (pop)
+# endif
+
+# if defined(__OBJC__)
+# if !defined(__APPLE_CC__) || (__APPLE_CC__ <= 1)
+# if defined(ASIO_OBJC_WORKAROUND)
+# undef Protocol
+# undef id
+# undef ASIO_OBJC_WORKAROUND
+# endif
+# endif
+# endif
+
+# if (__GNUC__ == 4 && __GNUC_MINOR__ >= 1) || (__GNUC__ > 4)
+# pragma GCC visibility pop
+# endif // (__GNUC__ == 4 && __GNUC_MINOR__ >= 1) || (__GNUC__ > 4)
+
+# if (__GNUC__ >= 7)
+# pragma GCC diagnostic pop
+# endif // (__GNUC__ >= 7)
+
+#elif defined(__KCC)
+
+// Kai C++
+
+#elif defined(__sgi)
+
+// SGI MIPSpro C++
+
+#elif defined(__DECCXX)
+
+// Compaq Tru64 Unix cxx
+
+#elif defined(__ghs)
+
+// Greenhills C++
+
+#elif defined(__BORLANDC__)
+
+// Borland C++
+
+# pragma option pop
+# pragma nopushoptwarn
+# pragma nopackwarning
+
+#elif defined(__MWERKS__)
+
+// Metrowerks CodeWarrior
+
+#elif defined(__SUNPRO_CC)
+
+// Sun Workshop Compiler C++
+
+#elif defined(__HP_aCC)
+
+// HP aCC
+
+#elif defined(__MRC__) || defined(__SC__)
+
+// MPW MrCpp or SCpp
+
+#elif defined(__IBMCPP__)
+
+// IBM Visual Age
+
+#elif defined(_MSC_VER)
+
+// Microsoft Visual C++
+//
+// Must remain the last #elif since some other vendors (Metrowerks, for example)
+// also #define _MSC_VER
+
+# pragma warning (pop)
+# pragma pack (pop)
+
+# if defined(__cplusplus_cli) || defined(__cplusplus_winrt)
+# if defined(ASIO_CLR_WORKAROUND)
+# undef generic
+# undef ASIO_CLR_WORKAROUND
+# endif
+# endif
+
+#endif
diff --git a/lib/asio/detail/posix_event.hpp b/lib/asio/detail/posix_event.hpp
new file mode 100644
index 0000000..121065e
--- /dev/null
+++ b/lib/asio/detail/posix_event.hpp
@@ -0,0 +1,162 @@
+//
+// detail/posix_event.hpp
+// ~~~~~~~~~~~~~~~~~~~~~~
+//
+// Copyright (c) 2003-2018 Christopher M. Kohlhoff (chris at kohlhoff dot com)
+//
+// 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 ASIO_DETAIL_POSIX_EVENT_HPP
+#define ASIO_DETAIL_POSIX_EVENT_HPP
+
+#if defined(_MSC_VER) && (_MSC_VER >= 1200)
+# pragma once
+#endif // defined(_MSC_VER) && (_MSC_VER >= 1200)
+
+#include "asio/detail/config.hpp"
+
+#if defined(ASIO_HAS_PTHREADS)
+
+#include <pthread.h>
+#include "asio/detail/assert.hpp"
+#include "asio/detail/noncopyable.hpp"
+
+#include "asio/detail/push_options.hpp"
+
+namespace asio {
+namespace detail {
+
+class posix_event
+ : private noncopyable
+{
+public:
+ // Constructor.
+ ASIO_DECL posix_event();
+
+ // Destructor.
+ ~posix_event()
+ {
+ ::pthread_cond_destroy(&cond_);
+ }
+
+ // Signal the event. (Retained for backward compatibility.)
+ template <typename Lock>
+ void signal(Lock& lock)
+ {
+ this->signal_all(lock);
+ }
+
+ // Signal all waiters.
+ template <typename Lock>
+ void signal_all(Lock& lock)
+ {
+ ASIO_ASSERT(lock.locked());
+ (void)lock;
+ state_ |= 1;
+ ::pthread_cond_broadcast(&cond_); // Ignore EINVAL.
+ }
+
+ // Unlock the mutex and signal one waiter.
+ template <typename Lock>
+ void unlock_and_signal_one(Lock& lock)
+ {
+ ASIO_ASSERT(lock.locked());
+ state_ |= 1;
+ bool have_waiters = (state_ > 1);
+ lock.unlock();
+ if (have_waiters)
+ ::pthread_cond_signal(&cond_); // Ignore EINVAL.
+ }
+
+ // If there's a waiter, unlock the mutex and signal it.
+ template <typename Lock>
+ bool maybe_unlock_and_signal_one(Lock& lock)
+ {
+ ASIO_ASSERT(lock.locked());
+ state_ |= 1;
+ if (state_ > 1)
+ {
+ lock.unlock();
+ ::pthread_cond_signal(&cond_); // Ignore EINVAL.
+ return true;
+ }
+ return false;
+ }
+
+ // Reset the event.
+ template <typename Lock>
+ void clear(Lock& lock)
+ {
+ ASIO_ASSERT(lock.locked());
+ (void)lock;
+ state_ &= ~std::size_t(1);
+ }
+
+ // Wait for the event to become signalled.
+ template <typename Lock>
+ void wait(Lock& lock)
+ {
+ ASIO_ASSERT(lock.locked());
+ while ((state_ & 1) == 0)
+ {
+ state_ += 2;
+ ::pthread_cond_wait(&cond_, &lock.mutex().mutex_); // Ignore EINVAL.
+ state_ -= 2;
+ }
+ }
+
+ // Timed wait for the event to become signalled.
+ template <typename Lock>
+ bool wait_for_usec(Lock& lock, long usec)
+ {
+ ASIO_ASSERT(lock.locked());
+ if ((state_ & 1) == 0)
+ {
+ state_ += 2;
+ timespec ts;
+#if (defined(__MACH__) && defined(__APPLE__)) \
+ || (defined(__ANDROID__) && (__ANDROID_API__ < 21) \
+ && defined(HAVE_PTHREAD_COND_TIMEDWAIT_RELATIVE))
+ ts.tv_sec = usec / 1000000;
+ ts.tv_nsec = (usec % 1000000) * 1000;
+ ::pthread_cond_timedwait_relative_np(
+ &cond_, &lock.mutex().mutex_, &ts); // Ignore EINVAL.
+#else // (defined(__MACH__) && defined(__APPLE__))
+ // || (defined(__ANDROID__) && (__ANDROID_API__ < 21)
+ // && defined(HAVE_PTHREAD_COND_TIMEDWAIT_RELATIVE))
+ if (::clock_gettime(CLOCK_MONOTONIC, &ts) == 0)
+ {
+ ts.tv_sec += usec / 1000000;
+ ts.tv_nsec = (usec % 1000000) * 1000;
+ ts.tv_sec += ts.tv_nsec / 1000000000;
+ ts.tv_nsec = ts.tv_nsec % 1000000000;
+ ::pthread_cond_timedwait(&cond_,
+ &lock.mutex().mutex_, &ts); // Ignore EINVAL.
+ }
+#endif // (defined(__MACH__) && defined(__APPLE__))
+ // || (defined(__ANDROID__) && (__ANDROID_API__ < 21)
+ // && defined(HAVE_PTHREAD_COND_TIMEDWAIT_RELATIVE))
+ state_ -= 2;
+ }
+ return (state_ & 1) != 0;
+ }
+
+private:
+ ::pthread_cond_t cond_;
+ std::size_t state_;
+};
+
+} // namespace detail
+} // namespace asio
+
+#include "asio/detail/pop_options.hpp"
+
+#if defined(ASIO_HEADER_ONLY)
+# include "asio/detail/impl/posix_event.ipp"
+#endif // defined(ASIO_HEADER_ONLY)
+
+#endif // defined(ASIO_HAS_PTHREADS)
+
+#endif // ASIO_DETAIL_POSIX_EVENT_HPP
diff --git a/lib/asio/detail/posix_fd_set_adapter.hpp b/lib/asio/detail/posix_fd_set_adapter.hpp
new file mode 100644
index 0000000..95042d6
--- /dev/null
+++ b/lib/asio/detail/posix_fd_set_adapter.hpp
@@ -0,0 +1,118 @@
+//
+// detail/posix_fd_set_adapter.hpp
+// ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+//
+// Copyright (c) 2003-2018 Christopher M. Kohlhoff (chris at kohlhoff dot com)
+//
+// 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 ASIO_DETAIL_POSIX_FD_SET_ADAPTER_HPP
+#define ASIO_DETAIL_POSIX_FD_SET_ADAPTER_HPP
+
+#if defined(_MSC_VER) && (_MSC_VER >= 1200)
+# pragma once
+#endif // defined(_MSC_VER) && (_MSC_VER >= 1200)
+
+#include "asio/detail/config.hpp"
+
+#if !defined(ASIO_WINDOWS) \
+ && !defined(__CYGWIN__) \
+ && !defined(ASIO_WINDOWS_RUNTIME)
+
+#include <cstring>
+#include "asio/detail/noncopyable.hpp"
+#include "asio/detail/reactor_op_queue.hpp"
+#include "asio/detail/socket_types.hpp"
+
+#include "asio/detail/push_options.hpp"
+
+namespace asio {
+namespace detail {
+
+// Adapts the FD_SET type to meet the Descriptor_Set concept's requirements.
+class posix_fd_set_adapter : noncopyable
+{
+public:
+ posix_fd_set_adapter()
+ : max_descriptor_(invalid_socket)
+ {
+ using namespace std; // Needed for memset on Solaris.
+ FD_ZERO(&fd_set_);
+ }
+
+ void reset()
+ {
+ using namespace std; // Needed for memset on Solaris.
+ FD_ZERO(&fd_set_);
+ }
+
+ bool set(socket_type descriptor)
+ {
+ if (descriptor < (socket_type)FD_SETSIZE)
+ {
+ if (max_descriptor_ == invalid_socket || descriptor > max_descriptor_)
+ max_descriptor_ = descriptor;
+ FD_SET(descriptor, &fd_set_);
+ return true;
+ }
+ return false;
+ }
+
+ void set(reactor_op_queue<socket_type>& operations, op_queue<operation>& ops)
+ {
+ reactor_op_queue<socket_type>::iterator i = operations.begin();
+ while (i != operations.end())
+ {
+ reactor_op_queue<socket_type>::iterator op_iter = i++;
+ if (!set(op_iter->first))
+ {
+ asio::error_code ec(error::fd_set_failure);
+ operations.cancel_operations(op_iter, ops, ec);
+ }
+ }
+ }
+
+ bool is_set(socket_type descriptor) const
+ {
+ return FD_ISSET(descriptor, &fd_set_) != 0;
+ }
+
+ operator fd_set*()
+ {
+ return &fd_set_;
+ }
+
+ socket_type max_descriptor() const
+ {
+ return max_descriptor_;
+ }
+
+ void perform(reactor_op_queue<socket_type>& operations,
+ op_queue<operation>& ops) const
+ {
+ reactor_op_queue<socket_type>::iterator i = operations.begin();
+ while (i != operations.end())
+ {
+ reactor_op_queue<socket_type>::iterator op_iter = i++;
+ if (is_set(op_iter->first))
+ operations.perform_operations(op_iter, ops);
+ }
+ }
+
+private:
+ mutable fd_set fd_set_;
+ socket_type max_descriptor_;
+};
+
+} // namespace detail
+} // namespace asio
+
+#include "asio/detail/pop_options.hpp"
+
+#endif // !defined(ASIO_WINDOWS)
+ // && !defined(__CYGWIN__)
+ // && !defined(ASIO_WINDOWS_RUNTIME)
+
+#endif // ASIO_DETAIL_POSIX_FD_SET_ADAPTER_HPP
diff --git a/lib/asio/detail/posix_global.hpp b/lib/asio/detail/posix_global.hpp
new file mode 100644
index 0000000..7ee0a71
--- /dev/null
+++ b/lib/asio/detail/posix_global.hpp
@@ -0,0 +1,80 @@
+//
+// detail/posix_global.hpp
+// ~~~~~~~~~~~~~~~~~~~~~~~
+//
+// Copyright (c) 2003-2018 Christopher M. Kohlhoff (chris at kohlhoff dot com)
+//
+// 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 ASIO_DETAIL_POSIX_GLOBAL_HPP
+#define ASIO_DETAIL_POSIX_GLOBAL_HPP
+
+#if defined(_MSC_VER) && (_MSC_VER >= 1200)
+# pragma once
+#endif // defined(_MSC_VER) && (_MSC_VER >= 1200)
+
+#include "asio/detail/config.hpp"
+
+#if defined(ASIO_HAS_PTHREADS)
+
+#include <exception>
+#include <pthread.h>
+
+#include "asio/detail/push_options.hpp"
+
+namespace asio {
+namespace detail {
+
+template <typename T>
+struct posix_global_impl
+{
+ // Helper function to perform initialisation.
+ static void do_init()
+ {
+ instance_.static_ptr_ = instance_.ptr_ = new T;
+ }
+
+ // Destructor automatically cleans up the global.
+ ~posix_global_impl()
+ {
+ delete static_ptr_;
+ }
+
+ static ::pthread_once_t init_once_;
+ static T* static_ptr_;
+ static posix_global_impl instance_;
+ T* ptr_;
+};
+
+template <typename T>
+::pthread_once_t posix_global_impl<T>::init_once_ = PTHREAD_ONCE_INIT;
+
+template <typename T>
+T* posix_global_impl<T>::static_ptr_ = 0;
+
+template <typename T>
+posix_global_impl<T> posix_global_impl<T>::instance_;
+
+template <typename T>
+T& posix_global()
+{
+ int result = ::pthread_once(
+ &posix_global_impl<T>::init_once_,
+ &posix_global_impl<T>::do_init);
+
+ if (result != 0)
+ std::terminate();
+
+ return *posix_global_impl<T>::instance_.ptr_;
+}
+
+} // namespace detail
+} // namespace asio
+
+#include "asio/detail/pop_options.hpp"
+
+#endif // defined(ASIO_HAS_PTHREADS)
+
+#endif // ASIO_DETAIL_POSIX_GLOBAL_HPP
diff --git a/lib/asio/detail/posix_mutex.hpp b/lib/asio/detail/posix_mutex.hpp
new file mode 100644
index 0000000..c0d9fc9
--- /dev/null
+++ b/lib/asio/detail/posix_mutex.hpp
@@ -0,0 +1,76 @@
+//
+// detail/posix_mutex.hpp
+// ~~~~~~~~~~~~~~~~~~~~~~
+//
+// Copyright (c) 2003-2018 Christopher M. Kohlhoff (chris at kohlhoff dot com)
+//
+// 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 ASIO_DETAIL_POSIX_MUTEX_HPP
+#define ASIO_DETAIL_POSIX_MUTEX_HPP
+
+#if defined(_MSC_VER) && (_MSC_VER >= 1200)
+# pragma once
+#endif // defined(_MSC_VER) && (_MSC_VER >= 1200)
+
+#include "asio/detail/config.hpp"
+
+#if defined(ASIO_HAS_PTHREADS)
+
+#include <pthread.h>
+#include "asio/detail/noncopyable.hpp"
+#include "asio/detail/scoped_lock.hpp"
+
+#include "asio/detail/push_options.hpp"
+
+namespace asio {
+namespace detail {
+
+class posix_event;
+
+class posix_mutex
+ : private noncopyable
+{
+public:
+ typedef asio::detail::scoped_lock<posix_mutex> scoped_lock;
+
+ // Constructor.
+ ASIO_DECL posix_mutex();
+
+ // Destructor.
+ ~posix_mutex()
+ {
+ ::pthread_mutex_destroy(&mutex_); // Ignore EBUSY.
+ }
+
+ // Lock the mutex.
+ void lock()
+ {
+ (void)::pthread_mutex_lock(&mutex_); // Ignore EINVAL.
+ }
+
+ // Unlock the mutex.
+ void unlock()
+ {
+ (void)::pthread_mutex_unlock(&mutex_); // Ignore EINVAL.
+ }
+
+private:
+ friend class posix_event;
+ ::pthread_mutex_t mutex_;
+};
+
+} // namespace detail
+} // namespace asio
+
+#include "asio/detail/pop_options.hpp"
+
+#if defined(ASIO_HEADER_ONLY)
+# include "asio/detail/impl/posix_mutex.ipp"
+#endif // defined(ASIO_HEADER_ONLY)
+
+#endif // defined(ASIO_HAS_PTHREADS)
+
+#endif // ASIO_DETAIL_POSIX_MUTEX_HPP
diff --git a/lib/asio/detail/posix_signal_blocker.hpp b/lib/asio/detail/posix_signal_blocker.hpp
new file mode 100644
index 0000000..fab5eb1
--- /dev/null
+++ b/lib/asio/detail/posix_signal_blocker.hpp
@@ -0,0 +1,85 @@
+//
+// detail/posix_signal_blocker.hpp
+// ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+//
+// Copyright (c) 2003-2018 Christopher M. Kohlhoff (chris at kohlhoff dot com)
+//
+// 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 ASIO_DETAIL_POSIX_SIGNAL_BLOCKER_HPP
+#define ASIO_DETAIL_POSIX_SIGNAL_BLOCKER_HPP
+
+#if defined(_MSC_VER) && (_MSC_VER >= 1200)
+# pragma once
+#endif // defined(_MSC_VER) && (_MSC_VER >= 1200)
+
+#include "asio/detail/config.hpp"
+
+#if defined(ASIO_HAS_PTHREADS)
+
+#include <csignal>
+#include <pthread.h>
+#include <signal.h>
+#include "asio/detail/noncopyable.hpp"
+
+#include "asio/detail/push_options.hpp"
+
+namespace asio {
+namespace detail {
+
+class posix_signal_blocker
+ : private noncopyable
+{
+public:
+ // Constructor blocks all signals for the calling thread.
+ posix_signal_blocker()
+ : blocked_(false)
+ {
+ sigset_t new_mask;
+ sigfillset(&new_mask);
+ blocked_ = (pthread_sigmask(SIG_BLOCK, &new_mask, &old_mask_) == 0);
+ }
+
+ // Destructor restores the previous signal mask.
+ ~posix_signal_blocker()
+ {
+ if (blocked_)
+ pthread_sigmask(SIG_SETMASK, &old_mask_, 0);
+ }
+
+ // Block all signals for the calling thread.
+ void block()
+ {
+ if (!blocked_)
+ {
+ sigset_t new_mask;
+ sigfillset(&new_mask);
+ blocked_ = (pthread_sigmask(SIG_BLOCK, &new_mask, &old_mask_) == 0);
+ }
+ }
+
+ // Restore the previous signal mask.
+ void unblock()
+ {
+ if (blocked_)
+ blocked_ = (pthread_sigmask(SIG_SETMASK, &old_mask_, 0) != 0);
+ }
+
+private:
+ // Have signals been blocked.
+ bool blocked_;
+
+ // The previous signal mask.
+ sigset_t old_mask_;
+};
+
+} // namespace detail
+} // namespace asio
+
+#include "asio/detail/pop_options.hpp"
+
+#endif // defined(ASIO_HAS_PTHREADS)
+
+#endif // ASIO_DETAIL_POSIX_SIGNAL_BLOCKER_HPP
diff --git a/lib/asio/detail/posix_static_mutex.hpp b/lib/asio/detail/posix_static_mutex.hpp
new file mode 100644
index 0000000..59b86c1
--- /dev/null
+++ b/lib/asio/detail/posix_static_mutex.hpp
@@ -0,0 +1,64 @@
+//
+// detail/posix_static_mutex.hpp
+// ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+//
+// Copyright (c) 2003-2018 Christopher M. Kohlhoff (chris at kohlhoff dot com)
+//
+// 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 ASIO_DETAIL_POSIX_STATIC_MUTEX_HPP
+#define ASIO_DETAIL_POSIX_STATIC_MUTEX_HPP
+
+#if defined(_MSC_VER) && (_MSC_VER >= 1200)
+# pragma once
+#endif // defined(_MSC_VER) && (_MSC_VER >= 1200)
+
+#include "asio/detail/config.hpp"
+
+#if defined(ASIO_HAS_PTHREADS)
+
+#include <pthread.h>
+#include "asio/detail/scoped_lock.hpp"
+
+#include "asio/detail/push_options.hpp"
+
+namespace asio {
+namespace detail {
+
+struct posix_static_mutex
+{
+ typedef asio::detail::scoped_lock<posix_static_mutex> scoped_lock;
+
+ // Initialise the mutex.
+ void init()
+ {
+ // Nothing to do.
+ }
+
+ // Lock the mutex.
+ void lock()
+ {
+ (void)::pthread_mutex_lock(&mutex_); // Ignore EINVAL.
+ }
+
+ // Unlock the mutex.
+ void unlock()
+ {
+ (void)::pthread_mutex_unlock(&mutex_); // Ignore EINVAL.
+ }
+
+ ::pthread_mutex_t mutex_;
+};
+
+#define ASIO_POSIX_STATIC_MUTEX_INIT { PTHREAD_MUTEX_INITIALIZER }
+
+} // namespace detail
+} // namespace asio
+
+#include "asio/detail/pop_options.hpp"
+
+#endif // defined(ASIO_HAS_PTHREADS)
+
+#endif // ASIO_DETAIL_POSIX_STATIC_MUTEX_HPP
diff --git a/lib/asio/detail/posix_thread.hpp b/lib/asio/detail/posix_thread.hpp
new file mode 100644
index 0000000..1817af2
--- /dev/null
+++ b/lib/asio/detail/posix_thread.hpp
@@ -0,0 +1,109 @@
+//
+// detail/posix_thread.hpp
+// ~~~~~~~~~~~~~~~~~~~~~~~
+//
+// Copyright (c) 2003-2018 Christopher M. Kohlhoff (chris at kohlhoff dot com)
+//
+// 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 ASIO_DETAIL_POSIX_THREAD_HPP
+#define ASIO_DETAIL_POSIX_THREAD_HPP
+
+#if defined(_MSC_VER) && (_MSC_VER >= 1200)
+# pragma once
+#endif // defined(_MSC_VER) && (_MSC_VER >= 1200)
+
+#include "asio/detail/config.hpp"
+
+#if defined(ASIO_HAS_PTHREADS)
+
+#include <cstddef>
+#include <pthread.h>
+#include "asio/detail/noncopyable.hpp"
+
+#include "asio/detail/push_options.hpp"
+
+namespace asio {
+namespace detail {
+
+extern "C"
+{
+ ASIO_DECL void* asio_detail_posix_thread_function(void* arg);
+}
+
+class posix_thread
+ : private noncopyable
+{
+public:
+ // Constructor.
+ template <typename Function>
+ posix_thread(Function f, unsigned int = 0)
+ : joined_(false)
+ {
+ start_thread(new func<Function>(f));
+ }
+
+ // Destructor.
+ ASIO_DECL ~posix_thread();
+
+ // Wait for the thread to exit.
+ ASIO_DECL void join();
+
+ // Get number of CPUs.
+ ASIO_DECL static std::size_t hardware_concurrency();
+
+private:
+ friend void* asio_detail_posix_thread_function(void* arg);
+
+ class func_base
+ {
+ public:
+ virtual ~func_base() {}
+ virtual void run() = 0;
+ };
+
+ struct auto_func_base_ptr
+ {
+ func_base* ptr;
+ ~auto_func_base_ptr() { delete ptr; }
+ };
+
+ template <typename Function>
+ class func
+ : public func_base
+ {
+ public:
+ func(Function f)
+ : f_(f)
+ {
+ }
+
+ virtual void run()
+ {
+ f_();
+ }
+
+ private:
+ Function f_;
+ };
+
+ ASIO_DECL void start_thread(func_base* arg);
+
+ ::pthread_t thread_;
+ bool joined_;
+};
+
+} // namespace detail
+} // namespace asio
+
+#include "asio/detail/pop_options.hpp"
+
+#if defined(ASIO_HEADER_ONLY)
+# include "asio/detail/impl/posix_thread.ipp"
+#endif // defined(ASIO_HEADER_ONLY)
+
+#endif // defined(ASIO_HAS_PTHREADS)
+
+#endif // ASIO_DETAIL_POSIX_THREAD_HPP
diff --git a/lib/asio/detail/posix_tss_ptr.hpp b/lib/asio/detail/posix_tss_ptr.hpp
new file mode 100644
index 0000000..a3096b4
--- /dev/null
+++ b/lib/asio/detail/posix_tss_ptr.hpp
@@ -0,0 +1,79 @@
+//
+// detail/posix_tss_ptr.hpp
+// ~~~~~~~~~~~~~~~~~~~~~~~~
+//
+// Copyright (c) 2003-2018 Christopher M. Kohlhoff (chris at kohlhoff dot com)
+//
+// 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 ASIO_DETAIL_POSIX_TSS_PTR_HPP
+#define ASIO_DETAIL_POSIX_TSS_PTR_HPP
+
+#if defined(_MSC_VER) && (_MSC_VER >= 1200)
+# pragma once
+#endif // defined(_MSC_VER) && (_MSC_VER >= 1200)
+
+#include "asio/detail/config.hpp"
+
+#if defined(ASIO_HAS_PTHREADS)
+
+#include <pthread.h>
+#include "asio/detail/noncopyable.hpp"
+
+#include "asio/detail/push_options.hpp"
+
+namespace asio {
+namespace detail {
+
+// Helper function to create thread-specific storage.
+ASIO_DECL void posix_tss_ptr_create(pthread_key_t& key);
+
+template <typename T>
+class posix_tss_ptr
+ : private noncopyable
+{
+public:
+ // Constructor.
+ posix_tss_ptr()
+ {
+ posix_tss_ptr_create(tss_key_);
+ }
+
+ // Destructor.
+ ~posix_tss_ptr()
+ {
+ ::pthread_key_delete(tss_key_);
+ }
+
+ // Get the value.
+ operator T*() const
+ {
+ return static_cast<T*>(::pthread_getspecific(tss_key_));
+ }
+
+ // Set the value.
+ void operator=(T* value)
+ {
+ ::pthread_setspecific(tss_key_, value);
+ }
+
+private:
+ // Thread-specific storage to allow unlocked access to determine whether a
+ // thread is a member of the pool.
+ pthread_key_t tss_key_;
+};
+
+} // namespace detail
+} // namespace asio
+
+#include "asio/detail/pop_options.hpp"
+
+#if defined(ASIO_HEADER_ONLY)
+# include "asio/detail/impl/posix_tss_ptr.ipp"
+#endif // defined(ASIO_HEADER_ONLY)
+
+#endif // defined(ASIO_HAS_PTHREADS)
+
+#endif // ASIO_DETAIL_POSIX_TSS_PTR_HPP
diff --git a/lib/asio/detail/push_options.hpp b/lib/asio/detail/push_options.hpp
new file mode 100644
index 0000000..0a3e979
--- /dev/null
+++ b/lib/asio/detail/push_options.hpp
@@ -0,0 +1,175 @@
+//
+// detail/push_options.hpp
+// ~~~~~~~~~~~~~~~~~~~~~~~
+//
+// Copyright (c) 2003-2018 Christopher M. Kohlhoff (chris at kohlhoff dot com)
+//
+// 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)
+//
+
+// No header guard
+
+#if defined(__COMO__)
+
+// Comeau C++
+
+#elif defined(__DMC__)
+
+// Digital Mars C++
+
+#elif defined(__INTEL_COMPILER) || defined(__ICL) \
+ || defined(__ICC) || defined(__ECC)
+
+// Intel C++
+
+# if (__GNUC__ == 4 && __GNUC_MINOR__ >= 1) || (__GNUC__ > 4)
+# pragma GCC visibility push (default)
+# endif // (__GNUC__ == 4 && __GNUC_MINOR__ >= 1) || (__GNUC__ > 4)
+
+#elif defined(__clang__)
+
+// Clang
+
+# if defined(__OBJC__)
+# if !defined(__APPLE_CC__) || (__APPLE_CC__ <= 1)
+# if !defined(ASIO_DISABLE_OBJC_WORKAROUND)
+# if !defined(Protocol) && !defined(id)
+# define Protocol cpp_Protocol
+# define id cpp_id
+# define ASIO_OBJC_WORKAROUND
+# endif
+# endif
+# endif
+# endif
+
+# if !defined(_WIN32) && !defined(__WIN32__) && !defined(WIN32)
+# pragma GCC visibility push (default)
+# endif // !defined(_WIN32) && !defined(__WIN32__) && !defined(WIN32)
+
+#elif defined(__GNUC__)
+
+// GNU C++
+
+# if defined(__MINGW32__) || defined(__CYGWIN__)
+# pragma pack (push, 8)
+# endif
+
+# if defined(__OBJC__)
+# if !defined(__APPLE_CC__) || (__APPLE_CC__ <= 1)
+# if !defined(ASIO_DISABLE_OBJC_WORKAROUND)
+# if !defined(Protocol) && !defined(id)
+# define Protocol cpp_Protocol
+# define id cpp_id
+# define ASIO_OBJC_WORKAROUND
+# endif
+# endif
+# endif
+# endif
+
+# if (__GNUC__ == 4 && __GNUC_MINOR__ >= 1) || (__GNUC__ > 4)
+# pragma GCC visibility push (default)
+# endif // (__GNUC__ == 4 && __GNUC_MINOR__ >= 1) || (__GNUC__ > 4)
+
+# if (__GNUC__ >= 7)
+# pragma GCC diagnostic push
+# pragma GCC diagnostic ignored "-Wimplicit-fallthrough"
+# endif // (__GNUC__ >= 7)
+
+#elif defined(__KCC)
+
+// Kai C++
+
+#elif defined(__sgi)
+
+// SGI MIPSpro C++
+
+#elif defined(__DECCXX)
+
+// Compaq Tru64 Unix cxx
+
+#elif defined(__ghs)
+
+// Greenhills C++
+
+#elif defined(__BORLANDC__)
+
+// Borland C++
+
+# pragma option push -a8 -b -Ve- -Vx- -w-inl -vi-
+# pragma nopushoptwarn
+# pragma nopackwarning
+# if !defined(__MT__)
+# error Multithreaded RTL must be selected.
+# endif // !defined(__MT__)
+
+#elif defined(__MWERKS__)
+
+// Metrowerks CodeWarrior
+
+#elif defined(__SUNPRO_CC)
+
+// Sun Workshop Compiler C++
+
+#elif defined(__HP_aCC)
+
+// HP aCC
+
+#elif defined(__MRC__) || defined(__SC__)
+
+// MPW MrCpp or SCpp
+
+#elif defined(__IBMCPP__)
+
+// IBM Visual Age
+
+#elif defined(_MSC_VER)
+
+// Microsoft Visual C++
+//
+// Must remain the last #elif since some other vendors (Metrowerks, for example)
+// also #define _MSC_VER
+
+# pragma warning (disable:4103)
+# pragma warning (push)
+# pragma warning (disable:4127)
+# pragma warning (disable:4180)
+# pragma warning (disable:4244)
+# pragma warning (disable:4355)
+# pragma warning (disable:4510)
+# pragma warning (disable:4512)
+# pragma warning (disable:4610)
+# pragma warning (disable:4675)
+# if (_MSC_VER < 1600)
+// Visual Studio 2008 generates spurious warnings about unused parameters.
+# pragma warning (disable:4100)
+# endif // (_MSC_VER < 1600)
+# if defined(_M_IX86) && defined(_Wp64)
+// The /Wp64 option is broken. If you want to check 64 bit portability, use a
+// 64 bit compiler!
+# pragma warning (disable:4311)
+# pragma warning (disable:4312)
+# endif // defined(_M_IX86) && defined(_Wp64)
+# pragma pack (push, 8)
+// Note that if the /Og optimisation flag is enabled with MSVC6, the compiler
+// has a tendency to incorrectly optimise away some calls to member template
+// functions, even though those functions contain code that should not be
+// optimised away! Therefore we will always disable this optimisation option
+// for the MSVC6 compiler.
+# if (_MSC_VER < 1300)
+# pragma optimize ("g", off)
+# endif
+# if !defined(_MT)
+# error Multithreaded RTL must be selected.
+# endif // !defined(_MT)
+
+# if defined(__cplusplus_cli) || defined(__cplusplus_winrt)
+# if !defined(ASIO_DISABLE_CLR_WORKAROUND)
+# if !defined(generic)
+# define generic cpp_generic
+# define ASIO_CLR_WORKAROUND
+# endif
+# endif
+# endif
+
+#endif
diff --git a/lib/asio/detail/reactive_descriptor_service.hpp b/lib/asio/detail/reactive_descriptor_service.hpp
new file mode 100644
index 0000000..e866863
--- /dev/null
+++ b/lib/asio/detail/reactive_descriptor_service.hpp
@@ -0,0 +1,388 @@
+//
+// detail/reactive_descriptor_service.hpp
+// ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+//
+// Copyright (c) 2003-2018 Christopher M. Kohlhoff (chris at kohlhoff dot com)
+//
+// 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 ASIO_DETAIL_REACTIVE_DESCRIPTOR_SERVICE_HPP
+#define ASIO_DETAIL_REACTIVE_DESCRIPTOR_SERVICE_HPP
+
+#if defined(_MSC_VER) && (_MSC_VER >= 1200)
+# pragma once
+#endif // defined(_MSC_VER) && (_MSC_VER >= 1200)
+
+#include "asio/detail/config.hpp"
+
+#if !defined(ASIO_WINDOWS) \
+ && !defined(ASIO_WINDOWS_RUNTIME) \
+ && !defined(__CYGWIN__)
+
+#include "asio/buffer.hpp"
+#include "asio/io_context.hpp"
+#include "asio/detail/bind_handler.hpp"
+#include "asio/detail/buffer_sequence_adapter.hpp"
+#include "asio/detail/descriptor_ops.hpp"
+#include "asio/detail/descriptor_read_op.hpp"
+#include "asio/detail/descriptor_write_op.hpp"
+#include "asio/detail/fenced_block.hpp"
+#include "asio/detail/memory.hpp"
+#include "asio/detail/noncopyable.hpp"
+#include "asio/detail/reactive_null_buffers_op.hpp"
+#include "asio/detail/reactive_wait_op.hpp"
+#include "asio/detail/reactor.hpp"
+#include "asio/posix/descriptor_base.hpp"
+
+#include "asio/detail/push_options.hpp"
+
+namespace asio {
+namespace detail {
+
+class reactive_descriptor_service :
+ public service_base<reactive_descriptor_service>
+{
+public:
+ // The native type of a descriptor.
+ typedef int native_handle_type;
+
+ // The implementation type of the descriptor.
+ class implementation_type
+ : private asio::detail::noncopyable
+ {
+ public:
+ // Default constructor.
+ implementation_type()
+ : descriptor_(-1),
+ state_(0)
+ {
+ }
+
+ private:
+ // Only this service will have access to the internal values.
+ friend class reactive_descriptor_service;
+
+ // The native descriptor representation.
+ int descriptor_;
+
+ // The current state of the descriptor.
+ descriptor_ops::state_type state_;
+
+ // Per-descriptor data used by the reactor.
+ reactor::per_descriptor_data reactor_data_;
+ };
+
+ // Constructor.
+ ASIO_DECL reactive_descriptor_service(
+ asio::io_context& io_context);
+
+ // Destroy all user-defined handler objects owned by the service.
+ ASIO_DECL void shutdown();
+
+ // Construct a new descriptor implementation.
+ ASIO_DECL void construct(implementation_type& impl);
+
+ // Move-construct a new descriptor implementation.
+ ASIO_DECL void move_construct(implementation_type& impl,
+ implementation_type& other_impl);
+
+ // Move-assign from another descriptor implementation.
+ ASIO_DECL void move_assign(implementation_type& impl,
+ reactive_descriptor_service& other_service,
+ implementation_type& other_impl);
+
+ // Destroy a descriptor implementation.
+ ASIO_DECL void destroy(implementation_type& impl);
+
+ // Assign a native descriptor to a descriptor implementation.
+ ASIO_DECL asio::error_code assign(implementation_type& impl,
+ const native_handle_type& native_descriptor,
+ asio::error_code& ec);
+
+ // Determine whether the descriptor is open.
+ bool is_open(const implementation_type& impl) const
+ {
+ return impl.descriptor_ != -1;
+ }
+
+ // Destroy a descriptor implementation.
+ ASIO_DECL asio::error_code close(implementation_type& impl,
+ asio::error_code& ec);
+
+ // Get the native descriptor representation.
+ native_handle_type native_handle(const implementation_type& impl) const
+ {
+ return impl.descriptor_;
+ }
+
+ // Release ownership of the native descriptor representation.
+ ASIO_DECL native_handle_type release(implementation_type& impl);
+
+ // Cancel all operations associated with the descriptor.
+ ASIO_DECL asio::error_code cancel(implementation_type& impl,
+ asio::error_code& ec);
+
+ // Perform an IO control command on the descriptor.
+ template <typename IO_Control_Command>
+ asio::error_code io_control(implementation_type& impl,
+ IO_Control_Command& command, asio::error_code& ec)
+ {
+ descriptor_ops::ioctl(impl.descriptor_, impl.state_,
+ command.name(), static_cast<ioctl_arg_type*>(command.data()), ec);
+ return ec;
+ }
+
+ // Gets the non-blocking mode of the descriptor.
+ bool non_blocking(const implementation_type& impl) const
+ {
+ return (impl.state_ & descriptor_ops::user_set_non_blocking) != 0;
+ }
+
+ // Sets the non-blocking mode of the descriptor.
+ asio::error_code non_blocking(implementation_type& impl,
+ bool mode, asio::error_code& ec)
+ {
+ descriptor_ops::set_user_non_blocking(
+ impl.descriptor_, impl.state_, mode, ec);
+ return ec;
+ }
+
+ // Gets the non-blocking mode of the native descriptor implementation.
+ bool native_non_blocking(const implementation_type& impl) const
+ {
+ return (impl.state_ & descriptor_ops::internal_non_blocking) != 0;
+ }
+
+ // Sets the non-blocking mode of the native descriptor implementation.
+ asio::error_code native_non_blocking(implementation_type& impl,
+ bool mode, asio::error_code& ec)
+ {
+ descriptor_ops::set_internal_non_blocking(
+ impl.descriptor_, impl.state_, mode, ec);
+ return ec;
+ }
+
+ // Wait for the descriptor to become ready to read, ready to write, or to have
+ // pending error conditions.
+ asio::error_code wait(implementation_type& impl,
+ posix::descriptor_base::wait_type w, asio::error_code& ec)
+ {
+ switch (w)
+ {
+ case posix::descriptor_base::wait_read:
+ descriptor_ops::poll_read(impl.descriptor_, impl.state_, ec);
+ break;
+ case posix::descriptor_base::wait_write:
+ descriptor_ops::poll_write(impl.descriptor_, impl.state_, ec);
+ break;
+ case posix::descriptor_base::wait_error:
+ descriptor_ops::poll_error(impl.descriptor_, impl.state_, ec);
+ break;
+ default:
+ ec = asio::error::invalid_argument;
+ break;
+ }
+
+ return ec;
+ }
+
+ // Asynchronously wait for the descriptor to become ready to read, ready to
+ // write, or to have pending error conditions.
+ template <typename Handler>
+ void async_wait(implementation_type& impl,
+ posix::descriptor_base::wait_type w, Handler& handler)
+ {
+ bool is_continuation =
+ asio_handler_cont_helpers::is_continuation(handler);
+
+ // Allocate and construct an operation to wrap the handler.
+ typedef reactive_wait_op<Handler> op;
+ typename op::ptr p = { asio::detail::addressof(handler),
+ op::ptr::allocate(handler), 0 };
+ p.p = new (p.v) op(handler);
+
+ ASIO_HANDLER_CREATION((reactor_.context(), *p.p, "descriptor",
+ &impl, impl.descriptor_, "async_wait"));
+
+ int op_type;
+ switch (w)
+ {
+ case posix::descriptor_base::wait_read:
+ op_type = reactor::read_op;
+ break;
+ case posix::descriptor_base::wait_write:
+ op_type = reactor::write_op;
+ break;
+ case posix::descriptor_base::wait_error:
+ op_type = reactor::except_op;
+ break;
+ default:
+ p.p->ec_ = 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;
+ }
+
+ // Write some data to the descriptor.
+ template <typename ConstBufferSequence>
+ size_t write_some(implementation_type& impl,
+ const ConstBufferSequence& buffers, asio::error_code& ec)
+ {
+ buffer_sequence_adapter<asio::const_buffer,
+ ConstBufferSequence> bufs(buffers);
+
+ return descriptor_ops::sync_write(impl.descriptor_, impl.state_,
+ bufs.buffers(), bufs.count(), bufs.all_empty(), ec);
+ }
+
+ // Wait until data can be written without blocking.
+ size_t write_some(implementation_type& impl,
+ const null_buffers&, asio::error_code& ec)
+ {
+ // Wait for descriptor to become ready.
+ descriptor_ops::poll_write(impl.descriptor_, impl.state_, ec);
+
+ return 0;
+ }
+
+ // Start an asynchronous write. The data being sent must be valid for the
+ // lifetime of the asynchronous operation.
+ template <typename ConstBufferSequence, typename Handler>
+ void async_write_some(implementation_type& impl,
+ const ConstBufferSequence& buffers, Handler& handler)
+ {
+ bool is_continuation =
+ asio_handler_cont_helpers::is_continuation(handler);
+
+ // Allocate and construct an operation to wrap the handler.
+ typedef descriptor_write_op<ConstBufferSequence, Handler> op;
+ typename op::ptr p = { asio::detail::addressof(handler),
+ op::ptr::allocate(handler), 0 };
+ p.p = new (p.v) op(impl.descriptor_, buffers, handler);
+
+ ASIO_HANDLER_CREATION((reactor_.context(), *p.p, "descriptor",
+ &impl, impl.descriptor_, "async_write_some"));
+
+ start_op(impl, reactor::write_op, p.p, is_continuation, true,
+ buffer_sequence_adapter<asio::const_buffer,
+ ConstBufferSequence>::all_empty(buffers));
+ p.v = p.p = 0;
+ }
+
+ // Start an asynchronous wait until data can be written without blocking.
+ template <typename Handler>
+ void async_write_some(implementation_type& impl,
+ const null_buffers&, Handler& handler)
+ {
+ bool is_continuation =
+ asio_handler_cont_helpers::is_continuation(handler);
+
+ // Allocate and construct an operation to wrap the handler.
+ typedef reactive_null_buffers_op<Handler> op;
+ typename op::ptr p = { asio::detail::addressof(handler),
+ op::ptr::allocate(handler), 0 };
+ p.p = new (p.v) op(handler);
+
+ ASIO_HANDLER_CREATION((reactor_.context(), *p.p, "descriptor",
+ &impl, impl.descriptor_, "async_write_some(null_buffers)"));
+
+ start_op(impl, reactor::write_op, p.p, is_continuation, false, false);
+ p.v = p.p = 0;
+ }
+
+ // Read some data from the stream. Returns the number of bytes read.
+ template <typename MutableBufferSequence>
+ size_t read_some(implementation_type& impl,
+ const MutableBufferSequence& buffers, asio::error_code& ec)
+ {
+ buffer_sequence_adapter<asio::mutable_buffer,
+ MutableBufferSequence> bufs(buffers);
+
+ return descriptor_ops::sync_read(impl.descriptor_, impl.state_,
+ bufs.buffers(), bufs.count(), bufs.all_empty(), ec);
+ }
+
+ // Wait until data can be read without blocking.
+ size_t read_some(implementation_type& impl,
+ const null_buffers&, asio::error_code& ec)
+ {
+ // Wait for descriptor to become ready.
+ descriptor_ops::poll_read(impl.descriptor_, impl.state_, ec);
+
+ return 0;
+ }
+
+ // Start an asynchronous read. The buffer for the data being read must be
+ // valid for the lifetime of the asynchronous operation.
+ template <typename MutableBufferSequence, typename Handler>
+ void async_read_some(implementation_type& impl,
+ const MutableBufferSequence& buffers, Handler& handler)
+ {
+ bool is_continuation =
+ asio_handler_cont_helpers::is_continuation(handler);
+
+ // Allocate and construct an operation to wrap the handler.
+ typedef descriptor_read_op<MutableBufferSequence, Handler> op;
+ typename op::ptr p = { asio::detail::addressof(handler),
+ op::ptr::allocate(handler), 0 };
+ p.p = new (p.v) op(impl.descriptor_, buffers, handler);
+
+ ASIO_HANDLER_CREATION((reactor_.context(), *p.p, "descriptor",
+ &impl, impl.descriptor_, "async_read_some"));
+
+ start_op(impl, reactor::read_op, p.p, is_continuation, true,
+ buffer_sequence_adapter<asio::mutable_buffer,
+ MutableBufferSequence>::all_empty(buffers));
+ p.v = p.p = 0;
+ }
+
+ // Wait until data can be read without blocking.
+ template <typename Handler>
+ void async_read_some(implementation_type& impl,
+ const null_buffers&, Handler& handler)
+ {
+ bool is_continuation =
+ asio_handler_cont_helpers::is_continuation(handler);
+
+ // Allocate and construct an operation to wrap the handler.
+ typedef reactive_null_buffers_op<Handler> op;
+ typename op::ptr p = { asio::detail::addressof(handler),
+ op::ptr::allocate(handler), 0 };
+ p.p = new (p.v) op(handler);
+
+ ASIO_HANDLER_CREATION((reactor_.context(), *p.p, "descriptor",
+ &impl, impl.descriptor_, "async_read_some(null_buffers)"));
+
+ start_op(impl, reactor::read_op, p.p, is_continuation, false, false);
+ p.v = p.p = 0;
+ }
+
+private:
+ // Start the asynchronous operation.
+ ASIO_DECL void start_op(implementation_type& impl, int op_type,
+ reactor_op* op, bool is_continuation, bool is_non_blocking, bool noop);
+
+ // The selector that performs event demultiplexing for the service.
+ reactor& reactor_;
+};
+
+} // namespace detail
+} // namespace asio
+
+#include "asio/detail/pop_options.hpp"
+
+#if defined(ASIO_HEADER_ONLY)
+# include "asio/detail/impl/reactive_descriptor_service.ipp"
+#endif // defined(ASIO_HEADER_ONLY)
+
+#endif // !defined(ASIO_WINDOWS)
+ // && !defined(ASIO_WINDOWS_RUNTIME)
+ // && !defined(__CYGWIN__)
+
+#endif // ASIO_DETAIL_REACTIVE_DESCRIPTOR_SERVICE_HPP
diff --git a/lib/asio/detail/reactive_null_buffers_op.hpp b/lib/asio/detail/reactive_null_buffers_op.hpp
new file mode 100644
index 0000000..7408269
--- /dev/null
+++ b/lib/asio/detail/reactive_null_buffers_op.hpp
@@ -0,0 +1,90 @@
+//
+// detail/reactive_null_buffers_op.hpp
+// ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+//
+// Copyright (c) 2003-2018 Christopher M. Kohlhoff (chris at kohlhoff dot com)
+//
+// 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 ASIO_DETAIL_REACTIVE_NULL_BUFFERS_OP_HPP
+#define ASIO_DETAIL_REACTIVE_NULL_BUFFERS_OP_HPP
+
+#if defined(_MSC_VER) && (_MSC_VER >= 1200)
+# pragma once
+#endif // defined(_MSC_VER) && (_MSC_VER >= 1200)
+
+#include "asio/detail/config.hpp"
+#include "asio/detail/fenced_block.hpp"
+#include "asio/detail/handler_alloc_helpers.hpp"
+#include "asio/detail/handler_invoke_helpers.hpp"
+#include "asio/detail/memory.hpp"
+#include "asio/detail/reactor_op.hpp"
+
+#include "asio/detail/push_options.hpp"
+
+namespace asio {
+namespace detail {
+
+template <typename Handler>
+class reactive_null_buffers_op : public reactor_op
+{
+public:
+ ASIO_DEFINE_HANDLER_PTR(reactive_null_buffers_op);
+
+ reactive_null_buffers_op(Handler& handler)
+ : reactor_op(&reactive_null_buffers_op::do_perform,
+ &reactive_null_buffers_op::do_complete),
+ handler_(ASIO_MOVE_CAST(Handler)(handler))
+ {
+ handler_work<Handler>::start(handler_);
+ }
+
+ static status do_perform(reactor_op*)
+ {
+ return done;
+ }
+
+ static void do_complete(void* owner, operation* base,
+ const asio::error_code& /*ec*/,
+ std::size_t /*bytes_transferred*/)
+ {
+ // Take ownership of the handler object.
+ reactive_null_buffers_op* o(static_cast<reactive_null_buffers_op*>(base));
+ ptr p = { asio::detail::addressof(o->handler_), o, o };
+ handler_work<Handler> w(o->handler_);
+
+ ASIO_HANDLER_COMPLETION((*o));
+
+ // 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::binder2<Handler, asio::error_code, std::size_t>
+ handler(o->handler_, o->ec_, o->bytes_transferred_);
+ p.h = asio::detail::addressof(handler.handler_);
+ p.reset();
+
+ // Make the upcall if required.
+ if (owner)
+ {
+ fenced_block b(fenced_block::half);
+ ASIO_HANDLER_INVOCATION_BEGIN((handler.arg1_, handler.arg2_));
+ w.complete(handler, handler.handler_);
+ ASIO_HANDLER_INVOCATION_END;
+ }
+ }
+
+private:
+ Handler handler_;
+};
+
+} // namespace detail
+} // namespace asio
+
+#include "asio/detail/pop_options.hpp"
+
+#endif // ASIO_DETAIL_REACTIVE_NULL_BUFFERS_OP_HPP
diff --git a/lib/asio/detail/reactive_serial_port_service.hpp b/lib/asio/detail/reactive_serial_port_service.hpp
new file mode 100644
index 0000000..6fddd9f
--- /dev/null
+++ b/lib/asio/detail/reactive_serial_port_service.hpp
@@ -0,0 +1,236 @@
+//
+// detail/reactive_serial_port_service.hpp
+// ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+//
+// Copyright (c) 2003-2018 Christopher M. Kohlhoff (chris at kohlhoff dot com)
+// Copyright (c) 2008 Rep Invariant Systems, Inc. (info@repinvariant.com)
+//
+// 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 ASIO_DETAIL_REACTIVE_SERIAL_PORT_SERVICE_HPP
+#define ASIO_DETAIL_REACTIVE_SERIAL_PORT_SERVICE_HPP
+
+#if defined(_MSC_VER) && (_MSC_VER >= 1200)
+# pragma once
+#endif // defined(_MSC_VER) && (_MSC_VER >= 1200)
+
+#include "asio/detail/config.hpp"
+
+#if defined(ASIO_HAS_SERIAL_PORT)
+#if !defined(ASIO_WINDOWS) && !defined(__CYGWIN__)
+
+#include <string>
+#include "asio/error.hpp"
+#include "asio/io_context.hpp"
+#include "asio/serial_port_base.hpp"
+#include "asio/detail/descriptor_ops.hpp"
+#include "asio/detail/reactive_descriptor_service.hpp"
+
+#include "asio/detail/push_options.hpp"
+
+namespace asio {
+namespace detail {
+
+// Extend reactive_descriptor_service to provide serial port support.
+class reactive_serial_port_service :
+ public service_base<reactive_serial_port_service>
+{
+public:
+ // The native type of a serial port.
+ typedef reactive_descriptor_service::native_handle_type native_handle_type;
+
+ // The implementation type of the serial port.
+ typedef reactive_descriptor_service::implementation_type implementation_type;
+
+ ASIO_DECL reactive_serial_port_service(
+ asio::io_context& io_context);
+
+ // Destroy all user-defined handler objects owned by the service.
+ ASIO_DECL void shutdown();
+
+ // Construct a new serial port implementation.
+ void construct(implementation_type& impl)
+ {
+ descriptor_service_.construct(impl);
+ }
+
+ // Move-construct a new serial port implementation.
+ void move_construct(implementation_type& impl,
+ implementation_type& other_impl)
+ {
+ descriptor_service_.move_construct(impl, other_impl);
+ }
+
+ // Move-assign from another serial port implementation.
+ void move_assign(implementation_type& impl,
+ reactive_serial_port_service& other_service,
+ implementation_type& other_impl)
+ {
+ descriptor_service_.move_assign(impl,
+ other_service.descriptor_service_, other_impl);
+ }
+
+ // Destroy a serial port implementation.
+ void destroy(implementation_type& impl)
+ {
+ descriptor_service_.destroy(impl);
+ }
+
+ // Open the serial port using the specified device name.
+ ASIO_DECL asio::error_code open(implementation_type& impl,
+ const std::string& device, asio::error_code& ec);
+
+ // Assign a native descriptor to a serial port implementation.
+ asio::error_code assign(implementation_type& impl,
+ const native_handle_type& native_descriptor,
+ asio::error_code& ec)
+ {
+ return descriptor_service_.assign(impl, native_descriptor, ec);
+ }
+
+ // Determine whether the serial port is open.
+ bool is_open(const implementation_type& impl) const
+ {
+ return descriptor_service_.is_open(impl);
+ }
+
+ // Destroy a serial port implementation.
+ asio::error_code close(implementation_type& impl,
+ asio::error_code& ec)
+ {
+ return descriptor_service_.close(impl, ec);
+ }
+
+ // Get the native serial port representation.
+ native_handle_type native_handle(implementation_type& impl)
+ {
+ return descriptor_service_.native_handle(impl);
+ }
+
+ // Cancel all operations associated with the serial port.
+ asio::error_code cancel(implementation_type& impl,
+ asio::error_code& ec)
+ {
+ return descriptor_service_.cancel(impl, ec);
+ }
+
+ // Set an option on the serial port.
+ template <typename SettableSerialPortOption>
+ asio::error_code set_option(implementation_type& impl,
+ const SettableSerialPortOption& option, asio::error_code& ec)
+ {
+ return do_set_option(impl,
+ &reactive_serial_port_service::store_option<SettableSerialPortOption>,
+ &option, ec);
+ }
+
+ // Get an option from the serial port.
+ template <typename GettableSerialPortOption>
+ asio::error_code get_option(const implementation_type& impl,
+ GettableSerialPortOption& option, asio::error_code& ec) const
+ {
+ return do_get_option(impl,
+ &reactive_serial_port_service::load_option<GettableSerialPortOption>,
+ &option, ec);
+ }
+
+ // Send a break sequence to the serial port.
+ asio::error_code send_break(implementation_type& impl,
+ asio::error_code& ec)
+ {
+ errno = 0;
+ descriptor_ops::error_wrapper(::tcsendbreak(
+ descriptor_service_.native_handle(impl), 0), ec);
+ return ec;
+ }
+
+ // Write the given data. Returns the number of bytes sent.
+ template <typename ConstBufferSequence>
+ size_t write_some(implementation_type& impl,
+ const ConstBufferSequence& buffers, asio::error_code& ec)
+ {
+ return descriptor_service_.write_some(impl, buffers, ec);
+ }
+
+ // Start an asynchronous write. The data being written must be valid for the
+ // lifetime of the asynchronous operation.
+ template <typename ConstBufferSequence, typename Handler>
+ void async_write_some(implementation_type& impl,
+ const ConstBufferSequence& buffers, Handler& handler)
+ {
+ descriptor_service_.async_write_some(impl, buffers, handler);
+ }
+
+ // Read some data. Returns the number of bytes received.
+ template <typename MutableBufferSequence>
+ size_t read_some(implementation_type& impl,
+ const MutableBufferSequence& buffers, asio::error_code& ec)
+ {
+ return descriptor_service_.read_some(impl, buffers, ec);
+ }
+
+ // Start an asynchronous read. The buffer for the data being received must be
+ // valid for the lifetime of the asynchronous operation.
+ template <typename MutableBufferSequence, typename Handler>
+ void async_read_some(implementation_type& impl,
+ const MutableBufferSequence& buffers, Handler& handler)
+ {
+ descriptor_service_.async_read_some(impl, buffers, handler);
+ }
+
+private:
+ // Function pointer type for storing a serial port option.
+ typedef asio::error_code (*store_function_type)(
+ const void*, termios&, asio::error_code&);
+
+ // Helper function template to store a serial port option.
+ template <typename SettableSerialPortOption>
+ static asio::error_code store_option(const void* option,
+ termios& storage, asio::error_code& ec)
+ {
+ static_cast<const SettableSerialPortOption*>(option)->store(storage, ec);
+ return ec;
+ }
+
+ // Helper function to set a serial port option.
+ ASIO_DECL asio::error_code do_set_option(
+ implementation_type& impl, store_function_type store,
+ const void* option, asio::error_code& ec);
+
+ // Function pointer type for loading a serial port option.
+ typedef asio::error_code (*load_function_type)(
+ void*, const termios&, asio::error_code&);
+
+ // Helper function template to load a serial port option.
+ template <typename GettableSerialPortOption>
+ static asio::error_code load_option(void* option,
+ const termios& storage, asio::error_code& ec)
+ {
+ static_cast<GettableSerialPortOption*>(option)->load(storage, ec);
+ return ec;
+ }
+
+ // Helper function to get a serial port option.
+ ASIO_DECL asio::error_code do_get_option(
+ const implementation_type& impl, load_function_type load,
+ void* option, asio::error_code& ec) const;
+
+ // The implementation used for initiating asynchronous operations.
+ reactive_descriptor_service descriptor_service_;
+};
+
+} // namespace detail
+} // namespace asio
+
+#include "asio/detail/pop_options.hpp"
+
+#if defined(ASIO_HEADER_ONLY)
+# include "asio/detail/impl/reactive_serial_port_service.ipp"
+#endif // defined(ASIO_HEADER_ONLY)
+
+#endif // !defined(ASIO_WINDOWS) && !defined(__CYGWIN__)
+#endif // defined(ASIO_HAS_SERIAL_PORT)
+
+#endif // ASIO_DETAIL_REACTIVE_SERIAL_PORT_SERVICE_HPP
diff --git a/lib/asio/detail/reactive_socket_accept_op.hpp b/lib/asio/detail/reactive_socket_accept_op.hpp
new file mode 100644
index 0000000..4a98f04
--- /dev/null
+++ b/lib/asio/detail/reactive_socket_accept_op.hpp
@@ -0,0 +1,217 @@
+//
+// detail/reactive_socket_accept_op.hpp
+// ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+//
+// Copyright (c) 2003-2018 Christopher M. Kohlhoff (chris at kohlhoff dot com)
+//
+// 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 ASIO_DETAIL_REACTIVE_SOCKET_ACCEPT_OP_HPP
+#define ASIO_DETAIL_REACTIVE_SOCKET_ACCEPT_OP_HPP
+
+#if defined(_MSC_VER) && (_MSC_VER >= 1200)
+# pragma once
+#endif // defined(_MSC_VER) && (_MSC_VER >= 1200)
+
+#include "asio/detail/config.hpp"
+#include "asio/detail/bind_handler.hpp"
+#include "asio/detail/buffer_sequence_adapter.hpp"
+#include "asio/detail/fenced_block.hpp"
+#include "asio/detail/memory.hpp"
+#include "asio/detail/reactor_op.hpp"
+#include "asio/detail/socket_holder.hpp"
+#include "asio/detail/socket_ops.hpp"
+
+#include "asio/detail/push_options.hpp"
+
+namespace asio {
+namespace detail {
+
+template <typename Socket, typename Protocol>
+class reactive_socket_accept_op_base : public reactor_op
+{
+public:
+ reactive_socket_accept_op_base(socket_type socket,
+ socket_ops::state_type state, Socket& peer, const Protocol& protocol,
+ typename Protocol::endpoint* peer_endpoint, func_type complete_func)
+ : reactor_op(&reactive_socket_accept_op_base::do_perform, complete_func),
+ socket_(socket),
+ state_(state),
+ peer_(peer),
+ protocol_(protocol),
+ peer_endpoint_(peer_endpoint),
+ addrlen_(peer_endpoint ? peer_endpoint->capacity() : 0)
+ {
+ }
+
+ static status do_perform(reactor_op* base)
+ {
+ reactive_socket_accept_op_base* o(
+ static_cast<reactive_socket_accept_op_base*>(base));
+
+ socket_type new_socket = invalid_socket;
+ status result = socket_ops::non_blocking_accept(o->socket_,
+ o->state_, o->peer_endpoint_ ? o->peer_endpoint_->data() : 0,
+ o->peer_endpoint_ ? &o->addrlen_ : 0, o->ec_, new_socket)
+ ? done : not_done;
+ o->new_socket_.reset(new_socket);
+
+ ASIO_HANDLER_REACTOR_OPERATION((*o, "non_blocking_accept", o->ec_));
+
+ return result;
+ }
+
+ void do_assign()
+ {
+ if (new_socket_.get() != invalid_socket)
+ {
+ if (peer_endpoint_)
+ peer_endpoint_->resize(addrlen_);
+ peer_.assign(protocol_, new_socket_.get(), ec_);
+ if (!ec_)
+ new_socket_.release();
+ }
+ }
+
+private:
+ socket_type socket_;
+ socket_ops::state_type state_;
+ socket_holder new_socket_;
+ Socket& peer_;
+ Protocol protocol_;
+ typename Protocol::endpoint* peer_endpoint_;
+ std::size_t addrlen_;
+};
+
+template <typename Socket, typename Protocol, typename Handler>
+class reactive_socket_accept_op :
+ public reactive_socket_accept_op_base<Socket, Protocol>
+{
+public:
+ ASIO_DEFINE_HANDLER_PTR(reactive_socket_accept_op);
+
+ reactive_socket_accept_op(socket_type socket,
+ socket_ops::state_type state, Socket& peer, const Protocol& protocol,
+ typename Protocol::endpoint* peer_endpoint, Handler& handler)
+ : reactive_socket_accept_op_base<Socket, Protocol>(socket, state, peer,
+ protocol, peer_endpoint, &reactive_socket_accept_op::do_complete),
+ handler_(ASIO_MOVE_CAST(Handler)(handler))
+ {
+ handler_work<Handler>::start(handler_);
+ }
+
+ static void do_complete(void* owner, operation* base,
+ const asio::error_code& /*ec*/,
+ std::size_t /*bytes_transferred*/)
+ {
+ // Take ownership of the handler object.
+ reactive_socket_accept_op* o(static_cast<reactive_socket_accept_op*>(base));
+ ptr p = { asio::detail::addressof(o->handler_), o, o };
+ handler_work<Handler> w(o->handler_);
+
+ // On success, assign new connection to peer socket object.
+ if (owner)
+ o->do_assign();
+
+ ASIO_HANDLER_COMPLETION((*o));
+
+ // 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::binder1<Handler, asio::error_code>
+ handler(o->handler_, o->ec_);
+ p.h = asio::detail::addressof(handler.handler_);
+ p.reset();
+
+ // Make the upcall if required.
+ if (owner)
+ {
+ fenced_block b(fenced_block::half);
+ ASIO_HANDLER_INVOCATION_BEGIN((handler.arg1_));
+ w.complete(handler, handler.handler_);
+ ASIO_HANDLER_INVOCATION_END;
+ }
+ }
+
+private:
+ Handler handler_;
+};
+
+#if defined(ASIO_HAS_MOVE)
+
+template <typename Protocol, typename Handler>
+class reactive_socket_move_accept_op :
+ private Protocol::socket,
+ public reactive_socket_accept_op_base<typename Protocol::socket, Protocol>
+{
+public:
+ ASIO_DEFINE_HANDLER_PTR(reactive_socket_move_accept_op);
+
+ reactive_socket_move_accept_op(io_context& ioc, socket_type socket,
+ socket_ops::state_type state, const Protocol& protocol,
+ typename Protocol::endpoint* peer_endpoint, Handler& handler)
+ : Protocol::socket(ioc),
+ reactive_socket_accept_op_base<typename Protocol::socket, Protocol>(
+ socket, state, *this, protocol, peer_endpoint,
+ &reactive_socket_move_accept_op::do_complete),
+ handler_(ASIO_MOVE_CAST(Handler)(handler))
+ {
+ handler_work<Handler>::start(handler_);
+ }
+
+ static void do_complete(void* owner, operation* base,
+ const asio::error_code& /*ec*/,
+ std::size_t /*bytes_transferred*/)
+ {
+ // Take ownership of the handler object.
+ reactive_socket_move_accept_op* o(
+ static_cast<reactive_socket_move_accept_op*>(base));
+ ptr p = { asio::detail::addressof(o->handler_), o, o };
+ handler_work<Handler> w(o->handler_);
+
+ // On success, assign new connection to peer socket object.
+ if (owner)
+ o->do_assign();
+
+ ASIO_HANDLER_COMPLETION((*o));
+
+ // 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::move_binder2<Handler,
+ asio::error_code, typename Protocol::socket>
+ handler(0, ASIO_MOVE_CAST(Handler)(o->handler_), o->ec_,
+ ASIO_MOVE_CAST(typename Protocol::socket)(*o));
+ p.h = asio::detail::addressof(handler.handler_);
+ p.reset();
+
+ // Make the upcall if required.
+ if (owner)
+ {
+ fenced_block b(fenced_block::half);
+ ASIO_HANDLER_INVOCATION_BEGIN((handler.arg1_, "..."));
+ w.complete(handler, handler.handler_);
+ ASIO_HANDLER_INVOCATION_END;
+ }
+ }
+
+private:
+ Handler handler_;
+};
+
+#endif // defined(ASIO_HAS_MOVE)
+
+} // namespace detail
+} // namespace asio
+
+#include "asio/detail/pop_options.hpp"
+
+#endif // ASIO_DETAIL_REACTIVE_SOCKET_ACCEPT_OP_HPP
diff --git a/lib/asio/detail/reactive_socket_connect_op.hpp b/lib/asio/detail/reactive_socket_connect_op.hpp
new file mode 100644
index 0000000..76164b2
--- /dev/null
+++ b/lib/asio/detail/reactive_socket_connect_op.hpp
@@ -0,0 +1,113 @@
+//
+// detail/reactive_socket_connect_op.hpp
+// ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+//
+// Copyright (c) 2003-2018 Christopher M. Kohlhoff (chris at kohlhoff dot com)
+//
+// 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 ASIO_DETAIL_REACTIVE_SOCKET_CONNECT_OP_HPP
+#define ASIO_DETAIL_REACTIVE_SOCKET_CONNECT_OP_HPP
+
+#if defined(_MSC_VER) && (_MSC_VER >= 1200)
+# pragma once
+#endif // defined(_MSC_VER) && (_MSC_VER >= 1200)
+
+#include "asio/detail/config.hpp"
+#include "asio/detail/bind_handler.hpp"
+#include "asio/detail/buffer_sequence_adapter.hpp"
+#include "asio/detail/fenced_block.hpp"
+#include "asio/detail/memory.hpp"
+#include "asio/detail/reactor_op.hpp"
+#include "asio/detail/socket_ops.hpp"
+
+#include "asio/detail/push_options.hpp"
+
+namespace asio {
+namespace detail {
+
+class reactive_socket_connect_op_base : public reactor_op
+{
+public:
+ reactive_socket_connect_op_base(socket_type socket, func_type complete_func)
+ : reactor_op(&reactive_socket_connect_op_base::do_perform, complete_func),
+ socket_(socket)
+ {
+ }
+
+ static status do_perform(reactor_op* base)
+ {
+ reactive_socket_connect_op_base* o(
+ static_cast<reactive_socket_connect_op_base*>(base));
+
+ status result = socket_ops::non_blocking_connect(
+ o->socket_, o->ec_) ? done : not_done;
+
+ ASIO_HANDLER_REACTOR_OPERATION((*o, "non_blocking_connect", o->ec_));
+
+ return result;
+ }
+
+private:
+ socket_type socket_;
+};
+
+template <typename Handler>
+class reactive_socket_connect_op : public reactive_socket_connect_op_base
+{
+public:
+ ASIO_DEFINE_HANDLER_PTR(reactive_socket_connect_op);
+
+ reactive_socket_connect_op(socket_type socket, Handler& handler)
+ : reactive_socket_connect_op_base(socket,
+ &reactive_socket_connect_op::do_complete),
+ handler_(ASIO_MOVE_CAST(Handler)(handler))
+ {
+ handler_work<Handler>::start(handler_);
+ }
+
+ static void do_complete(void* owner, operation* base,
+ const asio::error_code& /*ec*/,
+ std::size_t /*bytes_transferred*/)
+ {
+ // Take ownership of the handler object.
+ reactive_socket_connect_op* o
+ (static_cast<reactive_socket_connect_op*>(base));
+ ptr p = { asio::detail::addressof(o->handler_), o, o };
+ handler_work<Handler> w(o->handler_);
+
+ ASIO_HANDLER_COMPLETION((*o));
+
+ // 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::binder1<Handler, asio::error_code>
+ handler(o->handler_, o->ec_);
+ p.h = asio::detail::addressof(handler.handler_);
+ p.reset();
+
+ // Make the upcall if required.
+ if (owner)
+ {
+ fenced_block b(fenced_block::half);
+ ASIO_HANDLER_INVOCATION_BEGIN((handler.arg1_));
+ w.complete(handler, handler.handler_);
+ ASIO_HANDLER_INVOCATION_END;
+ }
+ }
+
+private:
+ Handler handler_;
+};
+
+} // namespace detail
+} // namespace asio
+
+#include "asio/detail/pop_options.hpp"
+
+#endif // ASIO_DETAIL_REACTIVE_SOCKET_CONNECT_OP_HPP
diff --git a/lib/asio/detail/reactive_socket_recv_op.hpp b/lib/asio/detail/reactive_socket_recv_op.hpp
new file mode 100644
index 0000000..04bd266
--- /dev/null
+++ b/lib/asio/detail/reactive_socket_recv_op.hpp
@@ -0,0 +1,135 @@
+//
+// detail/reactive_socket_recv_op.hpp
+// ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+//
+// Copyright (c) 2003-2018 Christopher M. Kohlhoff (chris at kohlhoff dot com)
+//
+// 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 ASIO_DETAIL_REACTIVE_SOCKET_RECV_OP_HPP
+#define ASIO_DETAIL_REACTIVE_SOCKET_RECV_OP_HPP
+
+#if defined(_MSC_VER) && (_MSC_VER >= 1200)
+# pragma once
+#endif // defined(_MSC_VER) && (_MSC_VER >= 1200)
+
+#include "asio/detail/config.hpp"
+#include "asio/detail/bind_handler.hpp"
+#include "asio/detail/buffer_sequence_adapter.hpp"
+#include "asio/detail/fenced_block.hpp"
+#include "asio/detail/memory.hpp"
+#include "asio/detail/reactor_op.hpp"
+#include "asio/detail/socket_ops.hpp"
+
+#include "asio/detail/push_options.hpp"
+
+namespace asio {
+namespace detail {
+
+template <typename MutableBufferSequence>
+class reactive_socket_recv_op_base : public reactor_op
+{
+public:
+ reactive_socket_recv_op_base(socket_type socket,
+ socket_ops::state_type state, const MutableBufferSequence& buffers,
+ socket_base::message_flags flags, func_type complete_func)
+ : reactor_op(&reactive_socket_recv_op_base::do_perform, complete_func),
+ socket_(socket),
+ state_(state),
+ buffers_(buffers),
+ flags_(flags)
+ {
+ }
+
+ static status do_perform(reactor_op* base)
+ {
+ reactive_socket_recv_op_base* o(
+ static_cast<reactive_socket_recv_op_base*>(base));
+
+ buffer_sequence_adapter<asio::mutable_buffer,
+ MutableBufferSequence> bufs(o->buffers_);
+
+ status 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;
+
+ 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>
+class reactive_socket_recv_op :
+ public reactive_socket_recv_op_base<MutableBufferSequence>
+{
+public:
+ ASIO_DEFINE_HANDLER_PTR(reactive_socket_recv_op);
+
+ reactive_socket_recv_op(socket_type socket,
+ socket_ops::state_type state, const MutableBufferSequence& buffers,
+ socket_base::message_flags flags, Handler& handler)
+ : reactive_socket_recv_op_base<MutableBufferSequence>(socket, state,
+ buffers, flags, &reactive_socket_recv_op::do_complete),
+ handler_(ASIO_MOVE_CAST(Handler)(handler))
+ {
+ handler_work<Handler>::start(handler_);
+ }
+
+ static void do_complete(void* owner, operation* base,
+ const asio::error_code& /*ec*/,
+ std::size_t /*bytes_transferred*/)
+ {
+ // Take ownership of the handler object.
+ reactive_socket_recv_op* o(static_cast<reactive_socket_recv_op*>(base));
+ ptr p = { asio::detail::addressof(o->handler_), o, o };
+ handler_work<Handler> w(o->handler_);
+
+ ASIO_HANDLER_COMPLETION((*o));
+
+ // 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::binder2<Handler, asio::error_code, std::size_t>
+ handler(o->handler_, o->ec_, o->bytes_transferred_);
+ p.h = asio::detail::addressof(handler.handler_);
+ p.reset();
+
+ // Make the upcall if required.
+ if (owner)
+ {
+ fenced_block b(fenced_block::half);
+ ASIO_HANDLER_INVOCATION_BEGIN((handler.arg1_, handler.arg2_));
+ w.complete(handler, handler.handler_);
+ ASIO_HANDLER_INVOCATION_END;
+ }
+ }
+
+private:
+ Handler handler_;
+};
+
+} // namespace detail
+} // namespace asio
+
+#include "asio/detail/pop_options.hpp"
+
+#endif // ASIO_DETAIL_REACTIVE_SOCKET_RECV_OP_HPP
diff --git a/lib/asio/detail/reactive_socket_recvfrom_op.hpp b/lib/asio/detail/reactive_socket_recvfrom_op.hpp
new file mode 100644
index 0000000..3d4fa4c
--- /dev/null
+++ b/lib/asio/detail/reactive_socket_recvfrom_op.hpp
@@ -0,0 +1,138 @@
+//
+// detail/reactive_socket_recvfrom_op.hpp
+// ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+//
+// Copyright (c) 2003-2018 Christopher M. Kohlhoff (chris at kohlhoff dot com)
+//
+// 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 ASIO_DETAIL_REACTIVE_SOCKET_RECVFROM_OP_HPP
+#define ASIO_DETAIL_REACTIVE_SOCKET_RECVFROM_OP_HPP
+
+#if defined(_MSC_VER) && (_MSC_VER >= 1200)
+# pragma once
+#endif // defined(_MSC_VER) && (_MSC_VER >= 1200)
+
+#include "asio/detail/config.hpp"
+#include "asio/detail/bind_handler.hpp"
+#include "asio/detail/buffer_sequence_adapter.hpp"
+#include "asio/detail/fenced_block.hpp"
+#include "asio/detail/memory.hpp"
+#include "asio/detail/reactor_op.hpp"
+#include "asio/detail/socket_ops.hpp"
+
+#include "asio/detail/push_options.hpp"
+
+namespace asio {
+namespace detail {
+
+template <typename MutableBufferSequence, typename Endpoint>
+class reactive_socket_recvfrom_op_base : public reactor_op
+{
+public:
+ reactive_socket_recvfrom_op_base(socket_type socket, int protocol_type,
+ const MutableBufferSequence& buffers, Endpoint& endpoint,
+ socket_base::message_flags flags, func_type complete_func)
+ : reactor_op(&reactive_socket_recvfrom_op_base::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* o(
+ static_cast<reactive_socket_recvfrom_op_base*>(base));
+
+ buffer_sequence_adapter<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_) ? done : not_done;
+
+ if (result && !o->ec_)
+ o->sender_endpoint_.resize(addr_len);
+
+ 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>
+class reactive_socket_recvfrom_op :
+ public reactive_socket_recvfrom_op_base<MutableBufferSequence, Endpoint>
+{
+public:
+ ASIO_DEFINE_HANDLER_PTR(reactive_socket_recvfrom_op);
+
+ reactive_socket_recvfrom_op(socket_type socket, int protocol_type,
+ const MutableBufferSequence& buffers, Endpoint& endpoint,
+ socket_base::message_flags flags, Handler& handler)
+ : reactive_socket_recvfrom_op_base<MutableBufferSequence, Endpoint>(
+ socket, protocol_type, buffers, endpoint, flags,
+ &reactive_socket_recvfrom_op::do_complete),
+ handler_(ASIO_MOVE_CAST(Handler)(handler))
+ {
+ handler_work<Handler>::start(handler_);
+ }
+
+ static void do_complete(void* owner, operation* base,
+ const asio::error_code& /*ec*/,
+ std::size_t /*bytes_transferred*/)
+ {
+ // Take ownership of the handler object.
+ reactive_socket_recvfrom_op* o(
+ static_cast<reactive_socket_recvfrom_op*>(base));
+ ptr p = { asio::detail::addressof(o->handler_), o, o };
+ handler_work<Handler> w(o->handler_);
+
+ ASIO_HANDLER_COMPLETION((*o));
+
+ // 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::binder2<Handler, asio::error_code, std::size_t>
+ handler(o->handler_, o->ec_, o->bytes_transferred_);
+ p.h = asio::detail::addressof(handler.handler_);
+ p.reset();
+
+ // Make the upcall if required.
+ if (owner)
+ {
+ fenced_block b(fenced_block::half);
+ ASIO_HANDLER_INVOCATION_BEGIN((handler.arg1_, handler.arg2_));
+ w.complete(handler, handler.handler_);
+ ASIO_HANDLER_INVOCATION_END;
+ }
+ }
+
+private:
+ Handler handler_;
+};
+
+} // namespace detail
+} // namespace asio
+
+#include "asio/detail/pop_options.hpp"
+
+#endif // ASIO_DETAIL_REACTIVE_SOCKET_RECVFROM_OP_HPP
diff --git a/lib/asio/detail/reactive_socket_recvmsg_op.hpp b/lib/asio/detail/reactive_socket_recvmsg_op.hpp
new file mode 100644
index 0000000..f473274
--- /dev/null
+++ b/lib/asio/detail/reactive_socket_recvmsg_op.hpp
@@ -0,0 +1,132 @@
+//
+// detail/reactive_socket_recvmsg_op.hpp
+// ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+//
+// Copyright (c) 2003-2018 Christopher M. Kohlhoff (chris at kohlhoff dot com)
+//
+// 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 ASIO_DETAIL_REACTIVE_SOCKET_RECVMSG_OP_HPP
+#define ASIO_DETAIL_REACTIVE_SOCKET_RECVMSG_OP_HPP
+
+#if defined(_MSC_VER) && (_MSC_VER >= 1200)
+# pragma once
+#endif // defined(_MSC_VER) && (_MSC_VER >= 1200)
+
+#include "asio/detail/config.hpp"
+#include "asio/detail/bind_handler.hpp"
+#include "asio/detail/buffer_sequence_adapter.hpp"
+#include "asio/detail/fenced_block.hpp"
+#include "asio/detail/memory.hpp"
+#include "asio/detail/reactor_op.hpp"
+#include "asio/detail/socket_ops.hpp"
+#include "asio/socket_base.hpp"
+
+#include "asio/detail/push_options.hpp"
+
+namespace asio {
+namespace detail {
+
+template <typename MutableBufferSequence>
+class reactive_socket_recvmsg_op_base : public reactor_op
+{
+public:
+ reactive_socket_recvmsg_op_base(socket_type socket,
+ const MutableBufferSequence& buffers, socket_base::message_flags in_flags,
+ socket_base::message_flags& out_flags, func_type complete_func)
+ : reactor_op(&reactive_socket_recvmsg_op_base::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* o(
+ static_cast<reactive_socket_recvmsg_op_base*>(base));
+
+ buffer_sequence_adapter<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;
+
+ 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>
+class reactive_socket_recvmsg_op :
+ public reactive_socket_recvmsg_op_base<MutableBufferSequence>
+{
+public:
+ ASIO_DEFINE_HANDLER_PTR(reactive_socket_recvmsg_op);
+
+ reactive_socket_recvmsg_op(socket_type socket,
+ const MutableBufferSequence& buffers, socket_base::message_flags in_flags,
+ socket_base::message_flags& out_flags, Handler& handler)
+ : reactive_socket_recvmsg_op_base<MutableBufferSequence>(socket, buffers,
+ in_flags, out_flags, &reactive_socket_recvmsg_op::do_complete),
+ handler_(ASIO_MOVE_CAST(Handler)(handler))
+ {
+ handler_work<Handler>::start(handler_);
+ }
+
+ static void do_complete(void* owner, operation* base,
+ const asio::error_code& /*ec*/,
+ std::size_t /*bytes_transferred*/)
+ {
+ // Take ownership of the handler object.
+ reactive_socket_recvmsg_op* o(
+ static_cast<reactive_socket_recvmsg_op*>(base));
+ ptr p = { asio::detail::addressof(o->handler_), o, o };
+ handler_work<Handler> w(o->handler_);
+
+ ASIO_HANDLER_COMPLETION((*o));
+
+ // 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::binder2<Handler, asio::error_code, std::size_t>
+ handler(o->handler_, o->ec_, o->bytes_transferred_);
+ p.h = asio::detail::addressof(handler.handler_);
+ p.reset();
+
+ // Make the upcall if required.
+ if (owner)
+ {
+ fenced_block b(fenced_block::half);
+ ASIO_HANDLER_INVOCATION_BEGIN((handler.arg1_, handler.arg2_));
+ w.complete(handler, handler.handler_);
+ ASIO_HANDLER_INVOCATION_END;
+ }
+ }
+
+private:
+ Handler handler_;
+};
+
+} // namespace detail
+} // namespace asio
+
+#include "asio/detail/pop_options.hpp"
+
+#endif // ASIO_DETAIL_REACTIVE_SOCKET_RECVMSG_OP_HPP
diff --git a/lib/asio/detail/reactive_socket_send_op.hpp b/lib/asio/detail/reactive_socket_send_op.hpp
new file mode 100644
index 0000000..bd550d9
--- /dev/null
+++ b/lib/asio/detail/reactive_socket_send_op.hpp
@@ -0,0 +1,134 @@
+//
+// detail/reactive_socket_send_op.hpp
+// ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+//
+// Copyright (c) 2003-2018 Christopher M. Kohlhoff (chris at kohlhoff dot com)
+//
+// 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 ASIO_DETAIL_REACTIVE_SOCKET_SEND_OP_HPP
+#define ASIO_DETAIL_REACTIVE_SOCKET_SEND_OP_HPP
+
+#if defined(_MSC_VER) && (_MSC_VER >= 1200)
+# pragma once
+#endif // defined(_MSC_VER) && (_MSC_VER >= 1200)
+
+#include "asio/detail/config.hpp"
+#include "asio/detail/bind_handler.hpp"
+#include "asio/detail/buffer_sequence_adapter.hpp"
+#include "asio/detail/fenced_block.hpp"
+#include "asio/detail/memory.hpp"
+#include "asio/detail/reactor_op.hpp"
+#include "asio/detail/socket_ops.hpp"
+
+#include "asio/detail/push_options.hpp"
+
+namespace asio {
+namespace detail {
+
+template <typename ConstBufferSequence>
+class reactive_socket_send_op_base : public reactor_op
+{
+public:
+ reactive_socket_send_op_base(socket_type socket,
+ socket_ops::state_type state, const ConstBufferSequence& buffers,
+ socket_base::message_flags flags, func_type complete_func)
+ : reactor_op(&reactive_socket_send_op_base::do_perform, complete_func),
+ socket_(socket),
+ state_(state),
+ buffers_(buffers),
+ flags_(flags)
+ {
+ }
+
+ static status do_perform(reactor_op* base)
+ {
+ reactive_socket_send_op_base* o(
+ static_cast<reactive_socket_send_op_base*>(base));
+
+ buffer_sequence_adapter<asio::const_buffer,
+ ConstBufferSequence> bufs(o->buffers_);
+
+ status result = socket_ops::non_blocking_send(o->socket_,
+ bufs.buffers(), bufs.count(), o->flags_,
+ o->ec_, o->bytes_transferred_) ? done : not_done;
+
+ if (result == done)
+ if ((o->state_ & socket_ops::stream_oriented) != 0)
+ if (o->bytes_transferred_ < bufs.total_size())
+ result = done_and_exhausted;
+
+ ASIO_HANDLER_REACTOR_OPERATION((*o, "non_blocking_send",
+ o->ec_, o->bytes_transferred_));
+
+ return result;
+ }
+
+private:
+ socket_type socket_;
+ socket_ops::state_type state_;
+ ConstBufferSequence buffers_;
+ socket_base::message_flags flags_;
+};
+
+template <typename ConstBufferSequence, typename Handler>
+class reactive_socket_send_op :
+ public reactive_socket_send_op_base<ConstBufferSequence>
+{
+public:
+ ASIO_DEFINE_HANDLER_PTR(reactive_socket_send_op);
+
+ reactive_socket_send_op(socket_type socket,
+ socket_ops::state_type state, const ConstBufferSequence& buffers,
+ socket_base::message_flags flags, Handler& handler)
+ : reactive_socket_send_op_base<ConstBufferSequence>(socket,
+ state, buffers, flags, &reactive_socket_send_op::do_complete),
+ handler_(ASIO_MOVE_CAST(Handler)(handler))
+ {
+ handler_work<Handler>::start(handler_);
+ }
+
+ static void do_complete(void* owner, operation* base,
+ const asio::error_code& /*ec*/,
+ std::size_t /*bytes_transferred*/)
+ {
+ // Take ownership of the handler object.
+ reactive_socket_send_op* o(static_cast<reactive_socket_send_op*>(base));
+ ptr p = { asio::detail::addressof(o->handler_), o, o };
+ handler_work<Handler> w(o->handler_);
+
+ ASIO_HANDLER_COMPLETION((*o));
+
+ // 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::binder2<Handler, asio::error_code, std::size_t>
+ handler(o->handler_, o->ec_, o->bytes_transferred_);
+ p.h = asio::detail::addressof(handler.handler_);
+ p.reset();
+
+ // Make the upcall if required.
+ if (owner)
+ {
+ fenced_block b(fenced_block::half);
+ ASIO_HANDLER_INVOCATION_BEGIN((handler.arg1_, handler.arg2_));
+ w.complete(handler, handler.handler_);
+ ASIO_HANDLER_INVOCATION_END;
+ }
+ }
+
+private:
+ Handler handler_;
+};
+
+} // namespace detail
+} // namespace asio
+
+#include "asio/detail/pop_options.hpp"
+
+#endif // ASIO_DETAIL_REACTIVE_SOCKET_SEND_OP_HPP
diff --git a/lib/asio/detail/reactive_socket_sendto_op.hpp b/lib/asio/detail/reactive_socket_sendto_op.hpp
new file mode 100644
index 0000000..c97554d
--- /dev/null
+++ b/lib/asio/detail/reactive_socket_sendto_op.hpp
@@ -0,0 +1,130 @@
+//
+// detail/reactive_socket_sendto_op.hpp
+// ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+//
+// Copyright (c) 2003-2018 Christopher M. Kohlhoff (chris at kohlhoff dot com)
+//
+// 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 ASIO_DETAIL_REACTIVE_SOCKET_SENDTO_OP_HPP
+#define ASIO_DETAIL_REACTIVE_SOCKET_SENDTO_OP_HPP
+
+#if defined(_MSC_VER) && (_MSC_VER >= 1200)
+# pragma once
+#endif // defined(_MSC_VER) && (_MSC_VER >= 1200)
+
+#include "asio/detail/config.hpp"
+#include "asio/detail/bind_handler.hpp"
+#include "asio/detail/buffer_sequence_adapter.hpp"
+#include "asio/detail/fenced_block.hpp"
+#include "asio/detail/memory.hpp"
+#include "asio/detail/reactor_op.hpp"
+#include "asio/detail/socket_ops.hpp"
+
+#include "asio/detail/push_options.hpp"
+
+namespace asio {
+namespace detail {
+
+template <typename ConstBufferSequence, typename Endpoint>
+class reactive_socket_sendto_op_base : public reactor_op
+{
+public:
+ reactive_socket_sendto_op_base(socket_type socket,
+ const ConstBufferSequence& buffers, const Endpoint& endpoint,
+ socket_base::message_flags flags, func_type complete_func)
+ : reactor_op(&reactive_socket_sendto_op_base::do_perform, complete_func),
+ socket_(socket),
+ buffers_(buffers),
+ destination_(endpoint),
+ flags_(flags)
+ {
+ }
+
+ static status do_perform(reactor_op* base)
+ {
+ reactive_socket_sendto_op_base* o(
+ static_cast<reactive_socket_sendto_op_base*>(base));
+
+ buffer_sequence_adapter<asio::const_buffer,
+ ConstBufferSequence> bufs(o->buffers_);
+
+ status result = socket_ops::non_blocking_sendto(o->socket_,
+ bufs.buffers(), bufs.count(), o->flags_,
+ o->destination_.data(), o->destination_.size(),
+ o->ec_, o->bytes_transferred_) ? done : not_done;
+
+ ASIO_HANDLER_REACTOR_OPERATION((*o, "non_blocking_sendto",
+ o->ec_, o->bytes_transferred_));
+
+ return result;
+ }
+
+private:
+ socket_type socket_;
+ ConstBufferSequence buffers_;
+ Endpoint destination_;
+ socket_base::message_flags flags_;
+};
+
+template <typename ConstBufferSequence, typename Endpoint, typename Handler>
+class reactive_socket_sendto_op :
+ public reactive_socket_sendto_op_base<ConstBufferSequence, Endpoint>
+{
+public:
+ ASIO_DEFINE_HANDLER_PTR(reactive_socket_sendto_op);
+
+ reactive_socket_sendto_op(socket_type socket,
+ const ConstBufferSequence& buffers, const Endpoint& endpoint,
+ socket_base::message_flags flags, Handler& handler)
+ : reactive_socket_sendto_op_base<ConstBufferSequence, Endpoint>(socket,
+ buffers, endpoint, flags, &reactive_socket_sendto_op::do_complete),
+ handler_(ASIO_MOVE_CAST(Handler)(handler))
+ {
+ handler_work<Handler>::start(handler_);
+ }
+
+ static void do_complete(void* owner, operation* base,
+ const asio::error_code& /*ec*/,
+ std::size_t /*bytes_transferred*/)
+ {
+ // Take ownership of the handler object.
+ reactive_socket_sendto_op* o(static_cast<reactive_socket_sendto_op*>(base));
+ ptr p = { asio::detail::addressof(o->handler_), o, o };
+ handler_work<Handler> w(o->handler_);
+
+ ASIO_HANDLER_COMPLETION((*o));
+
+ // 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::binder2<Handler, asio::error_code, std::size_t>
+ handler(o->handler_, o->ec_, o->bytes_transferred_);
+ p.h = asio::detail::addressof(handler.handler_);
+ p.reset();
+
+ // Make the upcall if required.
+ if (owner)
+ {
+ fenced_block b(fenced_block::half);
+ ASIO_HANDLER_INVOCATION_BEGIN((handler.arg1_, handler.arg2_));
+ w.complete(handler, handler.handler_);
+ ASIO_HANDLER_INVOCATION_END;
+ }
+ }
+
+private:
+ Handler handler_;
+};
+
+} // namespace detail
+} // namespace asio
+
+#include "asio/detail/pop_options.hpp"
+
+#endif // ASIO_DETAIL_REACTIVE_SOCKET_SENDTO_OP_HPP
diff --git a/lib/asio/detail/reactive_socket_service.hpp b/lib/asio/detail/reactive_socket_service.hpp
new file mode 100644
index 0000000..15a4fdb
--- /dev/null
+++ b/lib/asio/detail/reactive_socket_service.hpp
@@ -0,0 +1,526 @@
+//
+// detail/reactive_socket_service.hpp
+// ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+//
+// Copyright (c) 2003-2018 Christopher M. Kohlhoff (chris at kohlhoff dot com)
+//
+// 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 ASIO_DETAIL_REACTIVE_SOCKET_SERVICE_HPP
+#define ASIO_DETAIL_REACTIVE_SOCKET_SERVICE_HPP
+
+#if defined(_MSC_VER) && (_MSC_VER >= 1200)
+# pragma once
+#endif // defined(_MSC_VER) && (_MSC_VER >= 1200)
+
+#include "asio/detail/config.hpp"
+
+#if !defined(ASIO_HAS_IOCP)
+
+#include "asio/buffer.hpp"
+#include "asio/error.hpp"
+#include "asio/io_context.hpp"
+#include "asio/socket_base.hpp"
+#include "asio/detail/buffer_sequence_adapter.hpp"
+#include "asio/detail/memory.hpp"
+#include "asio/detail/noncopyable.hpp"
+#include "asio/detail/reactive_null_buffers_op.hpp"
+#include "asio/detail/reactive_socket_accept_op.hpp"
+#include "asio/detail/reactive_socket_connect_op.hpp"
+#include "asio/detail/reactive_socket_recvfrom_op.hpp"
+#include "asio/detail/reactive_socket_sendto_op.hpp"
+#include "asio/detail/reactive_socket_service_base.hpp"
+#include "asio/detail/reactor.hpp"
+#include "asio/detail/reactor_op.hpp"
+#include "asio/detail/socket_holder.hpp"
+#include "asio/detail/socket_ops.hpp"
+#include "asio/detail/socket_types.hpp"
+
+#include "asio/detail/push_options.hpp"
+
+namespace asio {
+namespace detail {
+
+template <typename Protocol>
+class reactive_socket_service :
+ public service_base<reactive_socket_service<Protocol> >,
+ public reactive_socket_service_base
+{
+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::base_implementation_type
+ {
+ // Default constructor.
+ implementation_type()
+ : protocol_(endpoint_type().protocol())
+ {
+ }
+
+ // The protocol associated with the socket.
+ protocol_type protocol_;
+ };
+
+ // Constructor.
+ reactive_socket_service(asio::io_context& io_context)
+ : service_base<reactive_socket_service<Protocol> >(io_context),
+ reactive_socket_service_base(io_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& 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<Protocol1>&,
+ typename reactive_socket_service<
+ 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.
+ asio::error_code open(implementation_type& impl,
+ const protocol_type& protocol, asio::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.
+ asio::error_code assign(implementation_type& impl,
+ const protocol_type& protocol, const native_handle_type& native_socket,
+ asio::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.
+ asio::error_code bind(implementation_type& impl,
+ const endpoint_type& endpoint, asio::error_code& ec)
+ {
+ socket_ops::bind(impl.socket_, endpoint.data(), endpoint.size(), ec);
+ return ec;
+ }
+
+ // Set a socket option.
+ template <typename Option>
+ asio::error_code set_option(implementation_type& impl,
+ const Option& option, asio::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>
+ asio::error_code get_option(const implementation_type& impl,
+ Option& option, asio::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,
+ asio::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,
+ asio::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.
+ asio::error_code shutdown(base_implementation_type& impl,
+ socket_base::shutdown_type what, asio::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,
+ asio::error_code& ec)
+ {
+ buffer_sequence_adapter<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,
+ asio::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>
+ void async_send_to(implementation_type& impl,
+ const ConstBufferSequence& buffers,
+ const endpoint_type& destination, socket_base::message_flags flags,
+ Handler& handler)
+ {
+ bool is_continuation =
+ 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> op;
+ typename op::ptr p = { asio::detail::addressof(handler),
+ op::ptr::allocate(handler), 0 };
+ p.p = new (p.v) op(impl.socket_, buffers, destination, flags, handler);
+
+ 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>
+ void async_send_to(implementation_type& impl, const null_buffers&,
+ const endpoint_type&, socket_base::message_flags, Handler& handler)
+ {
+ bool is_continuation =
+ asio_handler_cont_helpers::is_continuation(handler);
+
+ // Allocate and construct an operation to wrap the handler.
+ typedef reactive_null_buffers_op<Handler> op;
+ typename op::ptr p = { asio::detail::addressof(handler),
+ op::ptr::allocate(handler), 0 };
+ p.p = new (p.v) op(handler);
+
+ 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,
+ asio::error_code& ec)
+ {
+ buffer_sequence_adapter<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,
+ asio::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>
+ void async_receive_from(implementation_type& impl,
+ const MutableBufferSequence& buffers, endpoint_type& sender_endpoint,
+ socket_base::message_flags flags, Handler& handler)
+ {
+ bool is_continuation =
+ asio_handler_cont_helpers::is_continuation(handler);
+
+ // Allocate and construct an operation to wrap the handler.
+ typedef reactive_socket_recvfrom_op<MutableBufferSequence,
+ endpoint_type, Handler> op;
+ typename op::ptr p = { asio::detail::addressof(handler),
+ op::ptr::allocate(handler), 0 };
+ int protocol = impl.protocol_.type();
+ p.p = new (p.v) op(impl.socket_, protocol,
+ buffers, sender_endpoint, flags, handler);
+
+ 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>
+ void async_receive_from(implementation_type& impl,
+ const null_buffers&, endpoint_type& sender_endpoint,
+ socket_base::message_flags flags, Handler& handler)
+ {
+ bool is_continuation =
+ asio_handler_cont_helpers::is_continuation(handler);
+
+ // Allocate and construct an operation to wrap the handler.
+ typedef reactive_null_buffers_op<Handler> op;
+ typename op::ptr p = { asio::detail::addressof(handler),
+ op::ptr::allocate(handler), 0 };
+ p.p = new (p.v) op(handler);
+
+ 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>
+ asio::error_code accept(implementation_type& impl,
+ Socket& peer, endpoint_type* peer_endpoint, asio::error_code& ec)
+ {
+ // We cannot accept a socket that is already open.
+ if (peer.is_open())
+ {
+ ec = 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;
+ }
+
+#if defined(ASIO_HAS_MOVE)
+ // Accept a new connection.
+ typename Protocol::socket accept(implementation_type& impl,
+ io_context* peer_io_context, endpoint_type* peer_endpoint,
+ asio::error_code& ec)
+ {
+ typename Protocol::socket peer(
+ peer_io_context ? *peer_io_context : io_context_);
+
+ 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 peer;
+ }
+#endif // defined(ASIO_HAS_MOVE)
+
+ // 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>
+ void async_accept(implementation_type& impl, Socket& peer,
+ endpoint_type* peer_endpoint, Handler& handler)
+ {
+ bool is_continuation =
+ asio_handler_cont_helpers::is_continuation(handler);
+
+ // Allocate and construct an operation to wrap the handler.
+ typedef reactive_socket_accept_op<Socket, Protocol, Handler> op;
+ typename op::ptr p = { asio::detail::addressof(handler),
+ op::ptr::allocate(handler), 0 };
+ p.p = new (p.v) op(impl.socket_, impl.state_, peer,
+ impl.protocol_, peer_endpoint, handler);
+
+ 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(ASIO_HAS_MOVE)
+ // Start an asynchronous accept. The peer_endpoint object must be valid until
+ // the accept's handler is invoked.
+ template <typename Handler>
+ void async_accept(implementation_type& impl,
+ asio::io_context* peer_io_context,
+ endpoint_type* peer_endpoint, Handler& handler)
+ {
+ bool is_continuation =
+ asio_handler_cont_helpers::is_continuation(handler);
+
+ // Allocate and construct an operation to wrap the handler.
+ typedef reactive_socket_move_accept_op<Protocol, Handler> op;
+ typename op::ptr p = { asio::detail::addressof(handler),
+ op::ptr::allocate(handler), 0 };
+ p.p = new (p.v) op(peer_io_context ? *peer_io_context : io_context_,
+ impl.socket_, impl.state_, impl.protocol_, peer_endpoint, handler);
+
+ 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(ASIO_HAS_MOVE)
+
+ // Connect the socket to the specified endpoint.
+ asio::error_code connect(implementation_type& impl,
+ const endpoint_type& peer_endpoint, asio::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>
+ void async_connect(implementation_type& impl,
+ const endpoint_type& peer_endpoint, Handler& handler)
+ {
+ bool is_continuation =
+ asio_handler_cont_helpers::is_continuation(handler);
+
+ // Allocate and construct an operation to wrap the handler.
+ typedef reactive_socket_connect_op<Handler> op;
+ typename op::ptr p = { asio::detail::addressof(handler),
+ op::ptr::allocate(handler), 0 };
+ p.p = new (p.v) op(impl.socket_, handler);
+
+ 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
+
+#include "asio/detail/pop_options.hpp"
+
+#endif // !defined(ASIO_HAS_IOCP)
+
+#endif // ASIO_DETAIL_REACTIVE_SOCKET_SERVICE_HPP
diff --git a/lib/asio/detail/reactive_socket_service_base.hpp b/lib/asio/detail/reactive_socket_service_base.hpp
new file mode 100644
index 0000000..ccd497e
--- /dev/null
+++ b/lib/asio/detail/reactive_socket_service_base.hpp
@@ -0,0 +1,511 @@
+//
+// detail/reactive_socket_service_base.hpp
+// ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+//
+// Copyright (c) 2003-2018 Christopher M. Kohlhoff (chris at kohlhoff dot com)
+//
+// 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 ASIO_DETAIL_REACTIVE_SOCKET_SERVICE_BASE_HPP
+#define ASIO_DETAIL_REACTIVE_SOCKET_SERVICE_BASE_HPP
+
+#if defined(_MSC_VER) && (_MSC_VER >= 1200)
+# pragma once
+#endif // defined(_MSC_VER) && (_MSC_VER >= 1200)
+
+#include "asio/detail/config.hpp"
+
+#if !defined(ASIO_HAS_IOCP) \
+ && !defined(ASIO_WINDOWS_RUNTIME)
+
+#include "asio/buffer.hpp"
+#include "asio/error.hpp"
+#include "asio/io_context.hpp"
+#include "asio/socket_base.hpp"
+#include "asio/detail/buffer_sequence_adapter.hpp"
+#include "asio/detail/memory.hpp"
+#include "asio/detail/reactive_null_buffers_op.hpp"
+#include "asio/detail/reactive_socket_recv_op.hpp"
+#include "asio/detail/reactive_socket_recvmsg_op.hpp"
+#include "asio/detail/reactive_socket_send_op.hpp"
+#include "asio/detail/reactive_wait_op.hpp"
+#include "asio/detail/reactor.hpp"
+#include "asio/detail/reactor_op.hpp"
+#include "asio/detail/socket_holder.hpp"
+#include "asio/detail/socket_ops.hpp"
+#include "asio/detail/socket_types.hpp"
+
+#include "asio/detail/push_options.hpp"
+
+namespace asio {
+namespace detail {
+
+class reactive_socket_service_base
+{
+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.
+ ASIO_DECL reactive_socket_service_base(
+ asio::io_context& io_context);
+
+ // Destroy all user-defined handler objects owned by the service.
+ ASIO_DECL void base_shutdown();
+
+ // Construct a new socket implementation.
+ ASIO_DECL void construct(base_implementation_type& impl);
+
+ // Move-construct a new socket implementation.
+ ASIO_DECL void base_move_construct(base_implementation_type& impl,
+ base_implementation_type& other_impl);
+
+ // Move-assign from another socket implementation.
+ ASIO_DECL void base_move_assign(base_implementation_type& impl,
+ reactive_socket_service_base& other_service,
+ base_implementation_type& other_impl);
+
+ // Destroy a socket implementation.
+ 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.
+ ASIO_DECL asio::error_code close(
+ base_implementation_type& impl, asio::error_code& ec);
+
+ // Release ownership of the socket.
+ ASIO_DECL socket_type release(
+ base_implementation_type& impl, asio::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.
+ ASIO_DECL asio::error_code cancel(
+ base_implementation_type& impl, asio::error_code& ec);
+
+ // Determine whether the socket is at the out-of-band data mark.
+ bool at_mark(const base_implementation_type& impl,
+ asio::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,
+ asio::error_code& ec) const
+ {
+ return socket_ops::available(impl.socket_, ec);
+ }
+
+ // Place the socket into the state where it will listen for new connections.
+ asio::error_code listen(base_implementation_type& impl,
+ int backlog, asio::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>
+ asio::error_code io_control(base_implementation_type& impl,
+ IO_Control_Command& command, asio::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.
+ asio::error_code non_blocking(base_implementation_type& impl,
+ bool mode, asio::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.
+ asio::error_code native_non_blocking(base_implementation_type& impl,
+ bool mode, asio::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.
+ asio::error_code wait(base_implementation_type& impl,
+ socket_base::wait_type w, asio::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 = 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>
+ void async_wait(base_implementation_type& impl,
+ socket_base::wait_type w, Handler& handler)
+ {
+ bool is_continuation =
+ asio_handler_cont_helpers::is_continuation(handler);
+
+ // Allocate and construct an operation to wrap the handler.
+ typedef reactive_wait_op<Handler> op;
+ typename op::ptr p = { asio::detail::addressof(handler),
+ op::ptr::allocate(handler), 0 };
+ p.p = new (p.v) op(handler);
+
+ 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_ = 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, asio::error_code& ec)
+ {
+ buffer_sequence_adapter<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, asio::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>
+ void async_send(base_implementation_type& impl,
+ const ConstBufferSequence& buffers,
+ socket_base::message_flags flags, Handler& handler)
+ {
+ bool is_continuation =
+ asio_handler_cont_helpers::is_continuation(handler);
+
+ // Allocate and construct an operation to wrap the handler.
+ typedef reactive_socket_send_op<ConstBufferSequence, Handler> op;
+ typename op::ptr p = { asio::detail::addressof(handler),
+ op::ptr::allocate(handler), 0 };
+ p.p = new (p.v) op(impl.socket_, impl.state_, buffers, flags, handler);
+
+ 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<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>
+ void async_send(base_implementation_type& impl, const null_buffers&,
+ socket_base::message_flags, Handler& handler)
+ {
+ bool is_continuation =
+ asio_handler_cont_helpers::is_continuation(handler);
+
+ // Allocate and construct an operation to wrap the handler.
+ typedef reactive_null_buffers_op<Handler> op;
+ typename op::ptr p = { asio::detail::addressof(handler),
+ op::ptr::allocate(handler), 0 };
+ p.p = new (p.v) op(handler);
+
+ 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, asio::error_code& ec)
+ {
+ buffer_sequence_adapter<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, asio::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>
+ void async_receive(base_implementation_type& impl,
+ const MutableBufferSequence& buffers,
+ socket_base::message_flags flags, Handler& handler)
+ {
+ bool is_continuation =
+ asio_handler_cont_helpers::is_continuation(handler);
+
+ // Allocate and construct an operation to wrap the handler.
+ typedef reactive_socket_recv_op<MutableBufferSequence, Handler> op;
+ typename op::ptr p = { asio::detail::addressof(handler),
+ op::ptr::allocate(handler), 0 };
+ p.p = new (p.v) op(impl.socket_, impl.state_, buffers, flags, handler);
+
+ 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<asio::mutable_buffer,
+ MutableBufferSequence>::all_empty(buffers)));
+ p.v = p.p = 0;
+ }
+
+ // Wait until data can be received without blocking.
+ template <typename Handler>
+ void async_receive(base_implementation_type& impl, const null_buffers&,
+ socket_base::message_flags flags, Handler& handler)
+ {
+ bool is_continuation =
+ asio_handler_cont_helpers::is_continuation(handler);
+
+ // Allocate and construct an operation to wrap the handler.
+ typedef reactive_null_buffers_op<Handler> op;
+ typename op::ptr p = { asio::detail::addressof(handler),
+ op::ptr::allocate(handler), 0 };
+ p.p = new (p.v) op(handler);
+
+ 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, asio::error_code& ec)
+ {
+ buffer_sequence_adapter<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, asio::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>
+ 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)
+ {
+ bool is_continuation =
+ asio_handler_cont_helpers::is_continuation(handler);
+
+ // Allocate and construct an operation to wrap the handler.
+ typedef reactive_socket_recvmsg_op<MutableBufferSequence, Handler> op;
+ typename op::ptr p = { asio::detail::addressof(handler),
+ op::ptr::allocate(handler), 0 };
+ p.p = new (p.v) op(impl.socket_, buffers, in_flags, out_flags, handler);
+
+ 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>
+ 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)
+ {
+ bool is_continuation =
+ asio_handler_cont_helpers::is_continuation(handler);
+
+ // Allocate and construct an operation to wrap the handler.
+ typedef reactive_null_buffers_op<Handler> op;
+ typename op::ptr p = { asio::detail::addressof(handler),
+ op::ptr::allocate(handler), 0 };
+ p.p = new (p.v) op(handler);
+
+ 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.
+ ASIO_DECL asio::error_code do_open(
+ base_implementation_type& impl, int af,
+ int type, int protocol, asio::error_code& ec);
+
+ // Assign a native socket to a socket implementation.
+ ASIO_DECL asio::error_code do_assign(
+ base_implementation_type& impl, int type,
+ const native_handle_type& native_socket, asio::error_code& ec);
+
+ // Start the asynchronous read or write operation.
+ 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.
+ 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.
+ 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 io_context that owns this socket service.
+ io_context& io_context_;
+
+ // The selector that performs event demultiplexing for the service.
+ reactor& reactor_;
+};
+
+} // namespace detail
+} // namespace asio
+
+#include "asio/detail/pop_options.hpp"
+
+#if defined(ASIO_HEADER_ONLY)
+# include "asio/detail/impl/reactive_socket_service_base.ipp"
+#endif // defined(ASIO_HEADER_ONLY)
+
+#endif // !defined(ASIO_HAS_IOCP)
+ // && !defined(ASIO_WINDOWS_RUNTIME)
+
+#endif // ASIO_DETAIL_REACTIVE_SOCKET_SERVICE_BASE_HPP
diff --git a/lib/asio/detail/reactive_wait_op.hpp b/lib/asio/detail/reactive_wait_op.hpp
new file mode 100644
index 0000000..616d8b1
--- /dev/null
+++ b/lib/asio/detail/reactive_wait_op.hpp
@@ -0,0 +1,90 @@
+//
+// detail/reactive_wait_op.hpp
+// ~~~~~~~~~~~~~~~~~~~~~~~~~~~
+//
+// Copyright (c) 2003-2018 Christopher M. Kohlhoff (chris at kohlhoff dot com)
+//
+// 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 ASIO_DETAIL_REACTIVE_WAIT_OP_HPP
+#define ASIO_DETAIL_REACTIVE_WAIT_OP_HPP
+
+#if defined(_MSC_VER) && (_MSC_VER >= 1200)
+# pragma once
+#endif // defined(_MSC_VER) && (_MSC_VER >= 1200)
+
+#include "asio/detail/config.hpp"
+#include "asio/detail/fenced_block.hpp"
+#include "asio/detail/handler_alloc_helpers.hpp"
+#include "asio/detail/handler_invoke_helpers.hpp"
+#include "asio/detail/memory.hpp"
+#include "asio/detail/reactor_op.hpp"
+
+#include "asio/detail/push_options.hpp"
+
+namespace asio {
+namespace detail {
+
+template <typename Handler>
+class reactive_wait_op : public reactor_op
+{
+public:
+ ASIO_DEFINE_HANDLER_PTR(reactive_wait_op);
+
+ reactive_wait_op(Handler& handler)
+ : reactor_op(&reactive_wait_op::do_perform,
+ &reactive_wait_op::do_complete),
+ handler_(ASIO_MOVE_CAST(Handler)(handler))
+ {
+ handler_work<Handler>::start(handler_);
+ }
+
+ static status do_perform(reactor_op*)
+ {
+ return done;
+ }
+
+ static void do_complete(void* owner, operation* base,
+ const asio::error_code& /*ec*/,
+ std::size_t /*bytes_transferred*/)
+ {
+ // Take ownership of the handler object.
+ reactive_wait_op* o(static_cast<reactive_wait_op*>(base));
+ ptr p = { asio::detail::addressof(o->handler_), o, o };
+ handler_work<Handler> w(o->handler_);
+
+ ASIO_HANDLER_COMPLETION((*o));
+
+ // 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::binder1<Handler, asio::error_code>
+ handler(o->handler_, o->ec_);
+ p.h = asio::detail::addressof(handler.handler_);
+ p.reset();
+
+ // Make the upcall if required.
+ if (owner)
+ {
+ fenced_block b(fenced_block::half);
+ ASIO_HANDLER_INVOCATION_BEGIN((handler.arg1_));
+ w.complete(handler, handler.handler_);
+ ASIO_HANDLER_INVOCATION_END;
+ }
+ }
+
+private:
+ Handler handler_;
+};
+
+} // namespace detail
+} // namespace asio
+
+#include "asio/detail/pop_options.hpp"
+
+#endif // ASIO_DETAIL_REACTIVE_WAIT_OP_HPP
diff --git a/lib/asio/detail/reactor.hpp b/lib/asio/detail/reactor.hpp
new file mode 100644
index 0000000..4750276
--- /dev/null
+++ b/lib/asio/detail/reactor.hpp
@@ -0,0 +1,32 @@
+//
+// detail/reactor.hpp
+// ~~~~~~~~~~~~~~~~~~
+//
+// Copyright (c) 2003-2018 Christopher M. Kohlhoff (chris at kohlhoff dot com)
+//
+// 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 ASIO_DETAIL_REACTOR_HPP
+#define ASIO_DETAIL_REACTOR_HPP
+
+#if defined(_MSC_VER) && (_MSC_VER >= 1200)
+# pragma once
+#endif // defined(_MSC_VER) && (_MSC_VER >= 1200)
+
+#include "asio/detail/reactor_fwd.hpp"
+
+#if defined(ASIO_HAS_EPOLL)
+# include "asio/detail/epoll_reactor.hpp"
+#elif defined(ASIO_HAS_KQUEUE)
+# include "asio/detail/kqueue_reactor.hpp"
+#elif defined(ASIO_HAS_DEV_POLL)
+# include "asio/detail/dev_poll_reactor.hpp"
+#elif defined(ASIO_HAS_IOCP) || defined(ASIO_WINDOWS_RUNTIME)
+# include "asio/detail/null_reactor.hpp"
+#else
+# include "asio/detail/select_reactor.hpp"
+#endif
+
+#endif // ASIO_DETAIL_REACTOR_HPP
diff --git a/lib/asio/detail/reactor_fwd.hpp b/lib/asio/detail/reactor_fwd.hpp
new file mode 100644
index 0000000..a4555c3
--- /dev/null
+++ b/lib/asio/detail/reactor_fwd.hpp
@@ -0,0 +1,40 @@
+//
+// detail/reactor_fwd.hpp
+// ~~~~~~~~~~~~~~~~~~~~~~
+//
+// Copyright (c) 2003-2018 Christopher M. Kohlhoff (chris at kohlhoff dot com)
+//
+// 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 ASIO_DETAIL_REACTOR_FWD_HPP
+#define ASIO_DETAIL_REACTOR_FWD_HPP
+
+#if defined(_MSC_VER) && (_MSC_VER >= 1200)
+# pragma once
+#endif // defined(_MSC_VER) && (_MSC_VER >= 1200)
+
+#include "asio/detail/config.hpp"
+
+namespace asio {
+namespace detail {
+
+#if defined(ASIO_HAS_IOCP) || defined(ASIO_WINDOWS_RUNTIME)
+typedef class null_reactor reactor;
+#elif defined(ASIO_HAS_IOCP)
+typedef class select_reactor reactor;
+#elif defined(ASIO_HAS_EPOLL)
+typedef class epoll_reactor reactor;
+#elif defined(ASIO_HAS_KQUEUE)
+typedef class kqueue_reactor reactor;
+#elif defined(ASIO_HAS_DEV_POLL)
+typedef class dev_poll_reactor reactor;
+#else
+typedef class select_reactor reactor;
+#endif
+
+} // namespace detail
+} // namespace asio
+
+#endif // ASIO_DETAIL_REACTOR_FWD_HPP
diff --git a/lib/asio/detail/reactor_op.hpp b/lib/asio/detail/reactor_op.hpp
new file mode 100644
index 0000000..faad1a7
--- /dev/null
+++ b/lib/asio/detail/reactor_op.hpp
@@ -0,0 +1,65 @@
+//
+// detail/reactor_op.hpp
+// ~~~~~~~~~~~~~~~~~~~~~
+//
+// Copyright (c) 2003-2018 Christopher M. Kohlhoff (chris at kohlhoff dot com)
+//
+// 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 ASIO_DETAIL_REACTOR_OP_HPP
+#define ASIO_DETAIL_REACTOR_OP_HPP
+
+#if defined(_MSC_VER) && (_MSC_VER >= 1200)
+# pragma once
+#endif // defined(_MSC_VER) && (_MSC_VER >= 1200)
+
+#include "asio/detail/config.hpp"
+#include "asio/detail/operation.hpp"
+
+#include "asio/detail/push_options.hpp"
+
+namespace asio {
+namespace detail {
+
+class reactor_op
+ : public operation
+{
+public:
+ // The error code to be passed to the completion handler.
+ asio::error_code ec_;
+
+ // The number of bytes transferred, to be passed to the completion handler.
+ std::size_t bytes_transferred_;
+
+ // Status returned by perform function. May be used to decide whether it is
+ // worth performing more operations on the descriptor immediately.
+ enum status { not_done, done, done_and_exhausted };
+
+ // Perform the operation. Returns true if it is finished.
+ status perform()
+ {
+ return perform_func_(this);
+ }
+
+protected:
+ typedef status (*perform_func_type)(reactor_op*);
+
+ reactor_op(perform_func_type perform_func, func_type complete_func)
+ : operation(complete_func),
+ bytes_transferred_(0),
+ perform_func_(perform_func)
+ {
+ }
+
+private:
+ perform_func_type perform_func_;
+};
+
+} // namespace detail
+} // namespace asio
+
+#include "asio/detail/pop_options.hpp"
+
+#endif // ASIO_DETAIL_REACTOR_OP_HPP
diff --git a/lib/asio/detail/reactor_op_queue.hpp b/lib/asio/detail/reactor_op_queue.hpp
new file mode 100644
index 0000000..898f31d
--- /dev/null
+++ b/lib/asio/detail/reactor_op_queue.hpp
@@ -0,0 +1,168 @@
+//
+// detail/reactor_op_queue.hpp
+// ~~~~~~~~~~~~~~~~~~~~~~~~~~~
+//
+// Copyright (c) 2003-2018 Christopher M. Kohlhoff (chris at kohlhoff dot com)
+//
+// 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 ASIO_DETAIL_REACTOR_OP_QUEUE_HPP
+#define ASIO_DETAIL_REACTOR_OP_QUEUE_HPP
+
+#if defined(_MSC_VER) && (_MSC_VER >= 1200)
+# pragma once
+#endif // defined(_MSC_VER) && (_MSC_VER >= 1200)
+
+#include "asio/detail/config.hpp"
+#include "asio/detail/hash_map.hpp"
+#include "asio/detail/noncopyable.hpp"
+#include "asio/detail/op_queue.hpp"
+#include "asio/detail/reactor_op.hpp"
+#include "asio/error.hpp"
+
+#include "asio/detail/push_options.hpp"
+
+namespace asio {
+namespace detail {
+
+template <typename Descriptor>
+class reactor_op_queue
+ : private noncopyable
+{
+public:
+ typedef Descriptor key_type;
+
+ struct mapped_type : op_queue<reactor_op>
+ {
+ mapped_type() {}
+ mapped_type(const mapped_type&) {}
+ void operator=(const mapped_type&) {}
+ };
+
+ typedef typename hash_map<key_type, mapped_type>::value_type value_type;
+ typedef typename hash_map<key_type, mapped_type>::iterator iterator;
+
+ // Constructor.
+ reactor_op_queue()
+ : operations_()
+ {
+ }
+
+ // Obtain iterators to all registered descriptors.
+ iterator begin() { return operations_.begin(); }
+ iterator end() { return operations_.end(); }
+
+ // Add a new operation to the queue. Returns true if this is the only
+ // operation for the given descriptor, in which case the reactor's event
+ // demultiplexing function call may need to be interrupted and restarted.
+ bool enqueue_operation(Descriptor descriptor, reactor_op* op)
+ {
+ std::pair<iterator, bool> entry =
+ operations_.insert(value_type(descriptor, mapped_type()));
+ entry.first->second.push(op);
+ return entry.second;
+ }
+
+ // Cancel all operations associated with the descriptor identified by the
+ // supplied iterator. Any operations pending for the descriptor will be
+ // cancelled. Returns true if any operations were cancelled, in which case
+ // the reactor's event demultiplexing function may need to be interrupted and
+ // restarted.
+ bool cancel_operations(iterator i, op_queue<operation>& ops,
+ const asio::error_code& ec =
+ asio::error::operation_aborted)
+ {
+ if (i != operations_.end())
+ {
+ while (reactor_op* op = i->second.front())
+ {
+ op->ec_ = ec;
+ i->second.pop();
+ ops.push(op);
+ }
+ operations_.erase(i);
+ return true;
+ }
+
+ return false;
+ }
+
+ // Cancel all operations associated with the descriptor. Any operations
+ // pending for the descriptor will be cancelled. Returns true if any
+ // operations were cancelled, in which case the reactor's event
+ // demultiplexing function may need to be interrupted and restarted.
+ bool cancel_operations(Descriptor descriptor, op_queue<operation>& ops,
+ const asio::error_code& ec =
+ asio::error::operation_aborted)
+ {
+ return this->cancel_operations(operations_.find(descriptor), ops, ec);
+ }
+
+ // Whether there are no operations in the queue.
+ bool empty() const
+ {
+ return operations_.empty();
+ }
+
+ // Determine whether there are any operations associated with the descriptor.
+ bool has_operation(Descriptor descriptor) const
+ {
+ return operations_.find(descriptor) != operations_.end();
+ }
+
+ // Perform the operations corresponding to the descriptor identified by the
+ // supplied iterator. Returns true if there are still unfinished operations
+ // queued for the descriptor.
+ bool perform_operations(iterator i, op_queue<operation>& ops)
+ {
+ if (i != operations_.end())
+ {
+ while (reactor_op* op = i->second.front())
+ {
+ if (op->perform())
+ {
+ i->second.pop();
+ ops.push(op);
+ }
+ else
+ {
+ return true;
+ }
+ }
+ operations_.erase(i);
+ }
+ return false;
+ }
+
+ // Perform the operations corresponding to the descriptor. Returns true if
+ // there are still unfinished operations queued for the descriptor.
+ bool perform_operations(Descriptor descriptor, op_queue<operation>& ops)
+ {
+ return this->perform_operations(operations_.find(descriptor), ops);
+ }
+
+ // Get all operations owned by the queue.
+ void get_all_operations(op_queue<operation>& ops)
+ {
+ iterator i = operations_.begin();
+ while (i != operations_.end())
+ {
+ iterator op_iter = i++;
+ ops.push(op_iter->second);
+ operations_.erase(op_iter);
+ }
+ }
+
+private:
+ // The operations that are currently executing asynchronously.
+ hash_map<key_type, mapped_type> operations_;
+};
+
+} // namespace detail
+} // namespace asio
+
+#include "asio/detail/pop_options.hpp"
+
+#endif // ASIO_DETAIL_REACTOR_OP_QUEUE_HPP
diff --git a/lib/asio/detail/recycling_allocator.hpp b/lib/asio/detail/recycling_allocator.hpp
new file mode 100644
index 0000000..964af1d
--- /dev/null
+++ b/lib/asio/detail/recycling_allocator.hpp
@@ -0,0 +1,104 @@
+//
+// detail/recycling_allocator.hpp
+// ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+//
+// Copyright (c) 2003-2018 Christopher M. Kohlhoff (chris at kohlhoff dot com)
+//
+// 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 ASIO_DETAIL_RECYCLING_ALLOCATOR_HPP
+#define ASIO_DETAIL_RECYCLING_ALLOCATOR_HPP
+
+#if defined(_MSC_VER) && (_MSC_VER >= 1200)
+# pragma once
+#endif // defined(_MSC_VER) && (_MSC_VER >= 1200)
+
+#include "asio/detail/config.hpp"
+#include "asio/detail/memory.hpp"
+#include "asio/detail/thread_context.hpp"
+#include "asio/detail/thread_info_base.hpp"
+
+#include "asio/detail/push_options.hpp"
+
+namespace asio {
+namespace detail {
+
+template <typename T>
+class recycling_allocator
+{
+public:
+ typedef T value_type;
+
+ template <typename U>
+ struct rebind
+ {
+ typedef recycling_allocator<U> other;
+ };
+
+ recycling_allocator()
+ {
+ }
+
+ template <typename U>
+ recycling_allocator(const recycling_allocator<U>&)
+ {
+ }
+
+ T* allocate(std::size_t n)
+ {
+ typedef thread_context::thread_call_stack call_stack;
+ void* p = thread_info_base::allocate(call_stack::top(), sizeof(T) * n);
+ return static_cast<T*>(p);
+ }
+
+ void deallocate(T* p, std::size_t n)
+ {
+ typedef thread_context::thread_call_stack call_stack;
+ thread_info_base::deallocate(call_stack::top(), p, sizeof(T) * n);
+ }
+};
+
+template <>
+class recycling_allocator<void>
+{
+public:
+ typedef void value_type;
+
+ template <typename U>
+ struct rebind
+ {
+ typedef recycling_allocator<U> other;
+ };
+
+ recycling_allocator()
+ {
+ }
+
+ template <typename U>
+ recycling_allocator(const recycling_allocator<U>&)
+ {
+ }
+};
+
+template <typename Allocator>
+struct get_recycling_allocator
+{
+ typedef Allocator type;
+ static type get(const Allocator& a) { return a; }
+};
+
+template <typename T>
+struct get_recycling_allocator<std::allocator<T> >
+{
+ typedef recycling_allocator<T> type;
+ static type get(const std::allocator<T>&) { return type(); }
+};
+
+} // namespace detail
+} // namespace asio
+
+#include "asio/detail/pop_options.hpp"
+
+#endif // ASIO_DETAIL_RECYCLING_ALLOCATOR_HPP
diff --git a/lib/asio/detail/regex_fwd.hpp b/lib/asio/detail/regex_fwd.hpp
new file mode 100644
index 0000000..dcf7d06
--- /dev/null
+++ b/lib/asio/detail/regex_fwd.hpp
@@ -0,0 +1,35 @@
+//
+// detail/regex_fwd.hpp
+// ~~~~~~~~~~~~~~~~~~~~
+//
+// Copyright (c) 2003-2018 Christopher M. Kohlhoff (chris at kohlhoff dot com)
+//
+// 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 ASIO_DETAIL_REGEX_FWD_HPP
+#define ASIO_DETAIL_REGEX_FWD_HPP
+
+#if defined(_MSC_VER) && (_MSC_VER >= 1200)
+# pragma once
+#endif // defined(_MSC_VER) && (_MSC_VER >= 1200)
+
+#if defined(ASIO_HAS_BOOST_REGEX)
+
+#include <boost/regex_fwd.hpp>
+#include <boost/regex/v4/match_flags.hpp>
+
+namespace boost {
+
+template <class BidiIterator>
+struct sub_match;
+
+template <class BidiIterator, class Allocator>
+class match_results;
+
+} // namespace boost
+
+#endif // defined(ASIO_HAS_BOOST_REGEX)
+
+#endif // ASIO_DETAIL_REGEX_FWD_HPP
diff --git a/lib/asio/detail/resolve_endpoint_op.hpp b/lib/asio/detail/resolve_endpoint_op.hpp
new file mode 100644
index 0000000..8eee2f9
--- /dev/null
+++ b/lib/asio/detail/resolve_endpoint_op.hpp
@@ -0,0 +1,122 @@
+//
+// detail/resolve_endpoint_op.hpp
+// ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+//
+// Copyright (c) 2003-2018 Christopher M. Kohlhoff (chris at kohlhoff dot com)
+//
+// 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 ASIO_DETAIL_RESOLVER_ENDPOINT_OP_HPP
+#define ASIO_DETAIL_RESOLVER_ENDPOINT_OP_HPP
+
+#if defined(_MSC_VER) && (_MSC_VER >= 1200)
+# pragma once
+#endif // defined(_MSC_VER) && (_MSC_VER >= 1200)
+
+#include "asio/detail/config.hpp"
+#include "asio/error.hpp"
+#include "asio/io_context.hpp"
+#include "asio/ip/basic_resolver_results.hpp"
+#include "asio/detail/bind_handler.hpp"
+#include "asio/detail/fenced_block.hpp"
+#include "asio/detail/handler_alloc_helpers.hpp"
+#include "asio/detail/handler_invoke_helpers.hpp"
+#include "asio/detail/memory.hpp"
+#include "asio/detail/resolve_op.hpp"
+#include "asio/detail/socket_ops.hpp"
+
+#include "asio/detail/push_options.hpp"
+
+namespace asio {
+namespace detail {
+
+template <typename Protocol, typename Handler>
+class resolve_endpoint_op : public resolve_op
+{
+public:
+ ASIO_DEFINE_HANDLER_PTR(resolve_endpoint_op);
+
+ typedef typename Protocol::endpoint endpoint_type;
+ typedef asio::ip::basic_resolver_results<Protocol> results_type;
+
+ resolve_endpoint_op(socket_ops::weak_cancel_token_type cancel_token,
+ const endpoint_type& endpoint, io_context_impl& ioc, Handler& handler)
+ : resolve_op(&resolve_endpoint_op::do_complete),
+ cancel_token_(cancel_token),
+ endpoint_(endpoint),
+ io_context_impl_(ioc),
+ handler_(ASIO_MOVE_CAST(Handler)(handler))
+ {
+ handler_work<Handler>::start(handler_);
+ }
+
+ static void do_complete(void* owner, operation* base,
+ const asio::error_code& /*ec*/,
+ std::size_t /*bytes_transferred*/)
+ {
+ // Take ownership of the operation object.
+ resolve_endpoint_op* o(static_cast<resolve_endpoint_op*>(base));
+ ptr p = { asio::detail::addressof(o->handler_), o, o };
+ handler_work<Handler> w(o->handler_);
+
+ if (owner && owner != &o->io_context_impl_)
+ {
+ // The operation is being run on the worker io_context. Time to perform
+ // the resolver operation.
+
+ // Perform the blocking endpoint resolution operation.
+ char host_name[NI_MAXHOST];
+ char service_name[NI_MAXSERV];
+ socket_ops::background_getnameinfo(o->cancel_token_, o->endpoint_.data(),
+ o->endpoint_.size(), host_name, NI_MAXHOST, service_name, NI_MAXSERV,
+ o->endpoint_.protocol().type(), o->ec_);
+ o->results_ = results_type::create(o->endpoint_, host_name, service_name);
+
+ // Pass operation back to main io_context for completion.
+ o->io_context_impl_.post_deferred_completion(o);
+ p.v = p.p = 0;
+ }
+ else
+ {
+ // The operation has been returned to the main io_context. The completion
+ // handler is ready to be delivered.
+
+ ASIO_HANDLER_COMPLETION((*o));
+
+ // 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::binder2<Handler, asio::error_code, results_type>
+ handler(o->handler_, o->ec_, o->results_);
+ p.h = asio::detail::addressof(handler.handler_);
+ p.reset();
+
+ if (owner)
+ {
+ fenced_block b(fenced_block::half);
+ ASIO_HANDLER_INVOCATION_BEGIN((handler.arg1_, "..."));
+ w.complete(handler, handler.handler_);
+ ASIO_HANDLER_INVOCATION_END;
+ }
+ }
+ }
+
+private:
+ socket_ops::weak_cancel_token_type cancel_token_;
+ endpoint_type endpoint_;
+ io_context_impl& io_context_impl_;
+ Handler handler_;
+ results_type results_;
+};
+
+} // namespace detail
+} // namespace asio
+
+#include "asio/detail/pop_options.hpp"
+
+#endif // ASIO_DETAIL_RESOLVER_ENDPOINT_OP_HPP
diff --git a/lib/asio/detail/resolve_op.hpp b/lib/asio/detail/resolve_op.hpp
new file mode 100644
index 0000000..a528aa8
--- /dev/null
+++ b/lib/asio/detail/resolve_op.hpp
@@ -0,0 +1,45 @@
+//
+// detail/resolve_op.hpp
+// ~~~~~~~~~~~~~~~~~~~~~
+//
+// Copyright (c) 2003-2018 Christopher M. Kohlhoff (chris at kohlhoff dot com)
+//
+// 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 ASIO_DETAIL_RESOLVE_OP_HPP
+#define ASIO_DETAIL_RESOLVE_OP_HPP
+
+#if defined(_MSC_VER) && (_MSC_VER >= 1200)
+# pragma once
+#endif // defined(_MSC_VER) && (_MSC_VER >= 1200)
+
+#include "asio/detail/config.hpp"
+#include "asio/error.hpp"
+#include "asio/detail/operation.hpp"
+
+#include "asio/detail/push_options.hpp"
+
+namespace asio {
+namespace detail {
+
+class resolve_op : public operation
+{
+public:
+ // The error code to be passed to the completion handler.
+ asio::error_code ec_;
+
+protected:
+ resolve_op(func_type complete_func)
+ : operation(complete_func)
+ {
+ }
+};
+
+} // namespace detail
+} // namespace asio
+
+#include "asio/detail/pop_options.hpp"
+
+#endif // ASIO_DETAIL_RESOLVE_OP_HPP
diff --git a/lib/asio/detail/resolve_query_op.hpp b/lib/asio/detail/resolve_query_op.hpp
new file mode 100644
index 0000000..0ec5a32
--- /dev/null
+++ b/lib/asio/detail/resolve_query_op.hpp
@@ -0,0 +1,134 @@
+//
+// detail/resolve_query_op.hpp
+// ~~~~~~~~~~~~~~~~~~~~~~~~~~~
+//
+// Copyright (c) 2003-2018 Christopher M. Kohlhoff (chris at kohlhoff dot com)
+//
+// 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 ASIO_DETAIL_RESOLVE_QUERY_OP_HPP
+#define ASIO_DETAIL_RESOLVE_QUERY_OP_HPP
+
+#if defined(_MSC_VER) && (_MSC_VER >= 1200)
+# pragma once
+#endif // defined(_MSC_VER) && (_MSC_VER >= 1200)
+
+#include "asio/detail/config.hpp"
+#include "asio/error.hpp"
+#include "asio/io_context.hpp"
+#include "asio/ip/basic_resolver_query.hpp"
+#include "asio/ip/basic_resolver_results.hpp"
+#include "asio/detail/bind_handler.hpp"
+#include "asio/detail/fenced_block.hpp"
+#include "asio/detail/handler_alloc_helpers.hpp"
+#include "asio/detail/handler_invoke_helpers.hpp"
+#include "asio/detail/memory.hpp"
+#include "asio/detail/resolve_op.hpp"
+#include "asio/detail/socket_ops.hpp"
+
+#include "asio/detail/push_options.hpp"
+
+namespace asio {
+namespace detail {
+
+template <typename Protocol, typename Handler>
+class resolve_query_op : public resolve_op
+{
+public:
+ ASIO_DEFINE_HANDLER_PTR(resolve_query_op);
+
+ typedef asio::ip::basic_resolver_query<Protocol> query_type;
+ typedef asio::ip::basic_resolver_results<Protocol> results_type;
+
+ resolve_query_op(socket_ops::weak_cancel_token_type cancel_token,
+ const query_type& query, io_context_impl& ioc, Handler& handler)
+ : resolve_op(&resolve_query_op::do_complete),
+ cancel_token_(cancel_token),
+ query_(query),
+ io_context_impl_(ioc),
+ handler_(ASIO_MOVE_CAST(Handler)(handler)),
+ addrinfo_(0)
+ {
+ handler_work<Handler>::start(handler_);
+ }
+
+ ~resolve_query_op()
+ {
+ if (addrinfo_)
+ socket_ops::freeaddrinfo(addrinfo_);
+ }
+
+ static void do_complete(void* owner, operation* base,
+ const asio::error_code& /*ec*/,
+ std::size_t /*bytes_transferred*/)
+ {
+ // Take ownership of the operation object.
+ resolve_query_op* o(static_cast<resolve_query_op*>(base));
+ ptr p = { asio::detail::addressof(o->handler_), o, o };
+
+ if (owner && owner != &o->io_context_impl_)
+ {
+ // The operation is being run on the worker io_context. Time to perform
+ // the resolver operation.
+
+ // Perform the blocking host resolution operation.
+ socket_ops::background_getaddrinfo(o->cancel_token_,
+ o->query_.host_name().c_str(), o->query_.service_name().c_str(),
+ o->query_.hints(), &o->addrinfo_, o->ec_);
+
+ // Pass operation back to main io_context for completion.
+ o->io_context_impl_.post_deferred_completion(o);
+ p.v = p.p = 0;
+ }
+ else
+ {
+ // The operation has been returned to the main io_context. The completion
+ // handler is ready to be delivered.
+
+ // Take ownership of the operation's outstanding work.
+ handler_work<Handler> w(o->handler_);
+
+ ASIO_HANDLER_COMPLETION((*o));
+
+ // 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::binder2<Handler, asio::error_code, results_type>
+ handler(o->handler_, o->ec_, results_type());
+ p.h = asio::detail::addressof(handler.handler_);
+ if (o->addrinfo_)
+ {
+ handler.arg2_ = results_type::create(o->addrinfo_,
+ o->query_.host_name(), o->query_.service_name());
+ }
+ p.reset();
+
+ if (owner)
+ {
+ fenced_block b(fenced_block::half);
+ ASIO_HANDLER_INVOCATION_BEGIN((handler.arg1_, "..."));
+ w.complete(handler, handler.handler_);
+ ASIO_HANDLER_INVOCATION_END;
+ }
+ }
+ }
+
+private:
+ socket_ops::weak_cancel_token_type cancel_token_;
+ query_type query_;
+ io_context_impl& io_context_impl_;
+ Handler handler_;
+ asio::detail::addrinfo_type* addrinfo_;
+};
+
+} // namespace detail
+} // namespace asio
+
+#include "asio/detail/pop_options.hpp"
+
+#endif // ASIO_DETAIL_RESOLVE_QUERY_OP_HPP
diff --git a/lib/asio/detail/resolver_service.hpp b/lib/asio/detail/resolver_service.hpp
new file mode 100644
index 0000000..11a94d1
--- /dev/null
+++ b/lib/asio/detail/resolver_service.hpp
@@ -0,0 +1,145 @@
+//
+// detail/resolver_service.hpp
+// ~~~~~~~~~~~~~~~~~~~~~~~~~~~
+//
+// Copyright (c) 2003-2018 Christopher M. Kohlhoff (chris at kohlhoff dot com)
+//
+// 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 ASIO_DETAIL_RESOLVER_SERVICE_HPP
+#define ASIO_DETAIL_RESOLVER_SERVICE_HPP
+
+#if defined(_MSC_VER) && (_MSC_VER >= 1200)
+# pragma once
+#endif // defined(_MSC_VER) && (_MSC_VER >= 1200)
+
+#include "asio/detail/config.hpp"
+
+#if !defined(ASIO_WINDOWS_RUNTIME)
+
+#include "asio/ip/basic_resolver_query.hpp"
+#include "asio/ip/basic_resolver_results.hpp"
+#include "asio/detail/concurrency_hint.hpp"
+#include "asio/detail/memory.hpp"
+#include "asio/detail/resolve_endpoint_op.hpp"
+#include "asio/detail/resolve_query_op.hpp"
+#include "asio/detail/resolver_service_base.hpp"
+
+#include "asio/detail/push_options.hpp"
+
+namespace asio {
+namespace detail {
+
+template <typename Protocol>
+class resolver_service :
+ public service_base<resolver_service<Protocol> >,
+ public resolver_service_base
+{
+public:
+ // The implementation type of the resolver. A cancellation token is used to
+ // indicate to the background thread that the operation has been cancelled.
+ typedef socket_ops::shared_cancel_token_type implementation_type;
+
+ // The endpoint type.
+ typedef typename Protocol::endpoint endpoint_type;
+
+ // The query type.
+ typedef asio::ip::basic_resolver_query<Protocol> query_type;
+
+ // The results type.
+ typedef asio::ip::basic_resolver_results<Protocol> results_type;
+
+ // Constructor.
+ resolver_service(asio::io_context& io_context)
+ : service_base<resolver_service<Protocol> >(io_context),
+ resolver_service_base(io_context)
+ {
+ }
+
+ // Destroy all user-defined handler objects owned by the service.
+ void shutdown()
+ {
+ this->base_shutdown();
+ }
+
+ // Perform any fork-related housekeeping.
+ void notify_fork(asio::io_context::fork_event fork_ev)
+ {
+ this->base_notify_fork(fork_ev);
+ }
+
+ // Resolve a query to a list of entries.
+ results_type resolve(implementation_type&, const query_type& query,
+ asio::error_code& ec)
+ {
+ asio::detail::addrinfo_type* address_info = 0;
+
+ socket_ops::getaddrinfo(query.host_name().c_str(),
+ query.service_name().c_str(), query.hints(), &address_info, ec);
+ auto_addrinfo auto_address_info(address_info);
+
+ return ec ? results_type() : results_type::create(
+ address_info, query.host_name(), query.service_name());
+ }
+
+ // Asynchronously resolve a query to a list of entries.
+ template <typename Handler>
+ void async_resolve(implementation_type& impl,
+ const query_type& query, Handler& handler)
+ {
+ // Allocate and construct an operation to wrap the handler.
+ typedef resolve_query_op<Protocol, Handler> op;
+ typename op::ptr p = { asio::detail::addressof(handler),
+ op::ptr::allocate(handler), 0 };
+ p.p = new (p.v) op(impl, query, io_context_impl_, handler);
+
+ ASIO_HANDLER_CREATION((io_context_impl_.context(),
+ *p.p, "resolver", &impl, 0, "async_resolve"));
+
+ start_resolve_op(p.p);
+ p.v = p.p = 0;
+ }
+
+ // Resolve an endpoint to a list of entries.
+ results_type resolve(implementation_type&,
+ const endpoint_type& endpoint, asio::error_code& ec)
+ {
+ char host_name[NI_MAXHOST];
+ char service_name[NI_MAXSERV];
+ socket_ops::sync_getnameinfo(endpoint.data(), endpoint.size(),
+ host_name, NI_MAXHOST, service_name, NI_MAXSERV,
+ endpoint.protocol().type(), ec);
+
+ return ec ? results_type() : results_type::create(
+ endpoint, host_name, service_name);
+ }
+
+ // Asynchronously resolve an endpoint to a list of entries.
+ template <typename Handler>
+ void async_resolve(implementation_type& impl,
+ const endpoint_type& endpoint, Handler& handler)
+ {
+ // Allocate and construct an operation to wrap the handler.
+ typedef resolve_endpoint_op<Protocol, Handler> op;
+ typename op::ptr p = { asio::detail::addressof(handler),
+ op::ptr::allocate(handler), 0 };
+ p.p = new (p.v) op(impl, endpoint, io_context_impl_, handler);
+
+ ASIO_HANDLER_CREATION((io_context_impl_.context(),
+ *p.p, "resolver", &impl, 0, "async_resolve"));
+
+ start_resolve_op(p.p);
+ p.v = p.p = 0;
+ }
+};
+
+} // namespace detail
+} // namespace asio
+
+#include "asio/detail/pop_options.hpp"
+
+#endif // !defined(ASIO_WINDOWS_RUNTIME)
+
+#endif // ASIO_DETAIL_RESOLVER_SERVICE_HPP
diff --git a/lib/asio/detail/resolver_service_base.hpp b/lib/asio/detail/resolver_service_base.hpp
new file mode 100644
index 0000000..10a7922
--- /dev/null
+++ b/lib/asio/detail/resolver_service_base.hpp
@@ -0,0 +1,140 @@
+//
+// detail/resolver_service_base.hpp
+// ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+//
+// Copyright (c) 2003-2018 Christopher M. Kohlhoff (chris at kohlhoff dot com)
+//
+// 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 ASIO_DETAIL_RESOLVER_SERVICE_BASE_HPP
+#define ASIO_DETAIL_RESOLVER_SERVICE_BASE_HPP
+
+#if defined(_MSC_VER) && (_MSC_VER >= 1200)
+# pragma once
+#endif // defined(_MSC_VER) && (_MSC_VER >= 1200)
+
+#include "asio/detail/config.hpp"
+#include "asio/error.hpp"
+#include "asio/executor_work_guard.hpp"
+#include "asio/io_context.hpp"
+#include "asio/detail/mutex.hpp"
+#include "asio/detail/noncopyable.hpp"
+#include "asio/detail/resolve_op.hpp"
+#include "asio/detail/socket_ops.hpp"
+#include "asio/detail/socket_types.hpp"
+#include "asio/detail/scoped_ptr.hpp"
+#include "asio/detail/thread.hpp"
+
+#include "asio/detail/push_options.hpp"
+
+namespace asio {
+namespace detail {
+
+class resolver_service_base
+{
+public:
+ // The implementation type of the resolver. A cancellation token is used to
+ // indicate to the background thread that the operation has been cancelled.
+ typedef socket_ops::shared_cancel_token_type implementation_type;
+
+ // Constructor.
+ ASIO_DECL resolver_service_base(asio::io_context& io_context);
+
+ // Destructor.
+ ASIO_DECL ~resolver_service_base();
+
+ // Destroy all user-defined handler objects owned by the service.
+ ASIO_DECL void base_shutdown();
+
+ // Perform any fork-related housekeeping.
+ ASIO_DECL void base_notify_fork(
+ asio::io_context::fork_event fork_ev);
+
+ // Construct a new resolver implementation.
+ ASIO_DECL void construct(implementation_type& impl);
+
+ // Destroy a resolver implementation.
+ ASIO_DECL void destroy(implementation_type&);
+
+ // Move-construct a new resolver implementation.
+ ASIO_DECL void move_construct(implementation_type& impl,
+ implementation_type& other_impl);
+
+ // Move-assign from another resolver implementation.
+ ASIO_DECL void move_assign(implementation_type& impl,
+ resolver_service_base& other_service,
+ implementation_type& other_impl);
+
+ // Cancel pending asynchronous operations.
+ ASIO_DECL void cancel(implementation_type& impl);
+
+protected:
+ // Helper function to start an asynchronous resolve operation.
+ ASIO_DECL void start_resolve_op(resolve_op* op);
+
+#if !defined(ASIO_WINDOWS_RUNTIME)
+ // Helper class to perform exception-safe cleanup of addrinfo objects.
+ class auto_addrinfo
+ : private asio::detail::noncopyable
+ {
+ public:
+ explicit auto_addrinfo(asio::detail::addrinfo_type* ai)
+ : ai_(ai)
+ {
+ }
+
+ ~auto_addrinfo()
+ {
+ if (ai_)
+ socket_ops::freeaddrinfo(ai_);
+ }
+
+ operator asio::detail::addrinfo_type*()
+ {
+ return ai_;
+ }
+
+ private:
+ asio::detail::addrinfo_type* ai_;
+ };
+#endif // !defined(ASIO_WINDOWS_RUNTIME)
+
+ // Helper class to run the work io_context in a thread.
+ class work_io_context_runner;
+
+ // Start the work thread if it's not already running.
+ ASIO_DECL void start_work_thread();
+
+ // The io_context implementation used to post completions.
+ io_context_impl& io_context_impl_;
+
+private:
+ // Mutex to protect access to internal data.
+ asio::detail::mutex mutex_;
+
+ // Private io_context used for performing asynchronous host resolution.
+ asio::detail::scoped_ptr<asio::io_context> work_io_context_;
+
+ // The work io_context implementation used to post completions.
+ io_context_impl& work_io_context_impl_;
+
+ // Work for the private io_context to perform.
+ asio::executor_work_guard<
+ asio::io_context::executor_type> work_;
+
+ // Thread used for running the work io_context's run loop.
+ asio::detail::scoped_ptr<asio::detail::thread> work_thread_;
+};
+
+} // namespace detail
+} // namespace asio
+
+#include "asio/detail/pop_options.hpp"
+
+#if defined(ASIO_HEADER_ONLY)
+# include "asio/detail/impl/resolver_service_base.ipp"
+#endif // defined(ASIO_HEADER_ONLY)
+
+#endif // ASIO_DETAIL_RESOLVER_SERVICE_BASE_HPP
diff --git a/lib/asio/detail/scheduler.hpp b/lib/asio/detail/scheduler.hpp
new file mode 100644
index 0000000..10c29b7
--- /dev/null
+++ b/lib/asio/detail/scheduler.hpp
@@ -0,0 +1,213 @@
+//
+// detail/scheduler.hpp
+// ~~~~~~~~~~~~~~~~~~~~
+//
+// Copyright (c) 2003-2018 Christopher M. Kohlhoff (chris at kohlhoff dot com)
+//
+// 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 ASIO_DETAIL_SCHEDULER_HPP
+#define ASIO_DETAIL_SCHEDULER_HPP
+
+#if defined(_MSC_VER) && (_MSC_VER >= 1200)
+# pragma once
+#endif // defined(_MSC_VER) && (_MSC_VER >= 1200)
+
+#include "asio/detail/config.hpp"
+
+#include "asio/error_code.hpp"
+#include "asio/execution_context.hpp"
+#include "asio/detail/atomic_count.hpp"
+#include "asio/detail/conditionally_enabled_event.hpp"
+#include "asio/detail/conditionally_enabled_mutex.hpp"
+#include "asio/detail/op_queue.hpp"
+#include "asio/detail/reactor_fwd.hpp"
+#include "asio/detail/scheduler_operation.hpp"
+#include "asio/detail/thread_context.hpp"
+
+#include "asio/detail/push_options.hpp"
+
+namespace asio {
+namespace detail {
+
+struct scheduler_thread_info;
+
+class scheduler
+ : public execution_context_service_base<scheduler>,
+ public thread_context
+{
+public:
+ typedef scheduler_operation operation;
+
+ // Constructor. Specifies the number of concurrent threads that are likely to
+ // run the scheduler. If set to 1 certain optimisation are performed.
+ ASIO_DECL scheduler(asio::execution_context& ctx,
+ int concurrency_hint = 0);
+
+ // Destroy all user-defined handler objects owned by the service.
+ ASIO_DECL void shutdown();
+
+ // Initialise the task, if required.
+ ASIO_DECL void init_task();
+
+ // Run the event loop until interrupted or no more work.
+ ASIO_DECL std::size_t run(asio::error_code& ec);
+
+ // Run until interrupted or one operation is performed.
+ ASIO_DECL std::size_t run_one(asio::error_code& ec);
+
+ // Run until timeout, interrupted, or one operation is performed.
+ ASIO_DECL std::size_t wait_one(
+ long usec, asio::error_code& ec);
+
+ // Poll for operations without blocking.
+ ASIO_DECL std::size_t poll(asio::error_code& ec);
+
+ // Poll for one operation without blocking.
+ ASIO_DECL std::size_t poll_one(asio::error_code& ec);
+
+ // Interrupt the event processing loop.
+ ASIO_DECL void stop();
+
+ // Determine whether the scheduler is stopped.
+ ASIO_DECL bool stopped() const;
+
+ // Restart in preparation for a subsequent run invocation.
+ ASIO_DECL void restart();
+
+ // Notify that some work has started.
+ void work_started()
+ {
+ ++outstanding_work_;
+ }
+
+ // Used to compensate for a forthcoming work_finished call. Must be called
+ // from within a scheduler-owned thread.
+ ASIO_DECL void compensating_work_started();
+
+ // Notify that some work has finished.
+ void work_finished()
+ {
+ if (--outstanding_work_ == 0)
+ stop();
+ }
+
+ // Return whether a handler can be dispatched immediately.
+ bool can_dispatch()
+ {
+ return thread_call_stack::contains(this) != 0;
+ }
+
+ // Request invocation of the given operation and return immediately. Assumes
+ // that work_started() has not yet been called for the operation.
+ ASIO_DECL void post_immediate_completion(
+ operation* op, bool is_continuation);
+
+ // Request invocation of the given operation and return immediately. Assumes
+ // that work_started() was previously called for the operation.
+ ASIO_DECL void post_deferred_completion(operation* op);
+
+ // Request invocation of the given operations and return immediately. Assumes
+ // that work_started() was previously called for each operation.
+ ASIO_DECL void post_deferred_completions(op_queue<operation>& ops);
+
+ // Enqueue the given operation following a failed attempt to dispatch the
+ // operation for immediate invocation.
+ ASIO_DECL void do_dispatch(operation* op);
+
+ // Process unfinished operations as part of a shutdownoperation. Assumes that
+ // work_started() was previously called for the operations.
+ ASIO_DECL void abandon_operations(op_queue<operation>& ops);
+
+ // Get the concurrency hint that was used to initialise the scheduler.
+ int concurrency_hint() const
+ {
+ return concurrency_hint_;
+ }
+
+private:
+ // The mutex type used by this scheduler.
+ typedef conditionally_enabled_mutex mutex;
+
+ // The event type used by this scheduler.
+ typedef conditionally_enabled_event event;
+
+ // Structure containing thread-specific data.
+ typedef scheduler_thread_info thread_info;
+
+ // Run at most one operation. May block.
+ ASIO_DECL std::size_t do_run_one(mutex::scoped_lock& lock,
+ thread_info& this_thread, const asio::error_code& ec);
+
+ // Run at most one operation with a timeout. May block.
+ ASIO_DECL std::size_t do_wait_one(mutex::scoped_lock& lock,
+ thread_info& this_thread, long usec, const asio::error_code& ec);
+
+ // Poll for at most one operation.
+ ASIO_DECL std::size_t do_poll_one(mutex::scoped_lock& lock,
+ thread_info& this_thread, const asio::error_code& ec);
+
+ // Stop the task and all idle threads.
+ ASIO_DECL void stop_all_threads(mutex::scoped_lock& lock);
+
+ // Wake a single idle thread, or the task, and always unlock the mutex.
+ ASIO_DECL void wake_one_thread_and_unlock(
+ mutex::scoped_lock& lock);
+
+ // Helper class to perform task-related operations on block exit.
+ struct task_cleanup;
+ friend struct task_cleanup;
+
+ // Helper class to call work-related operations on block exit.
+ struct work_cleanup;
+ friend struct work_cleanup;
+
+ // Whether to optimise for single-threaded use cases.
+ const bool one_thread_;
+
+ // Mutex to protect access to internal data.
+ mutable mutex mutex_;
+
+ // Event to wake up blocked threads.
+ event wakeup_event_;
+
+ // The task to be run by this service.
+ reactor* task_;
+
+ // Operation object to represent the position of the task in the queue.
+ struct task_operation : operation
+ {
+ task_operation() : operation(0) {}
+ } task_operation_;
+
+ // Whether the task has been interrupted.
+ bool task_interrupted_;
+
+ // The count of unfinished work.
+ atomic_count outstanding_work_;
+
+ // The queue of handlers that are ready to be delivered.
+ op_queue<operation> op_queue_;
+
+ // Flag to indicate that the dispatcher has been stopped.
+ bool stopped_;
+
+ // Flag to indicate that the dispatcher has been shut down.
+ bool shutdown_;
+
+ // The concurrency hint used to initialise the scheduler.
+ const int concurrency_hint_;
+};
+
+} // namespace detail
+} // namespace asio
+
+#include "asio/detail/pop_options.hpp"
+
+#if defined(ASIO_HEADER_ONLY)
+# include "asio/detail/impl/scheduler.ipp"
+#endif // defined(ASIO_HEADER_ONLY)
+
+#endif // ASIO_DETAIL_SCHEDULER_HPP
diff --git a/lib/asio/detail/scheduler_operation.hpp b/lib/asio/detail/scheduler_operation.hpp
new file mode 100644
index 0000000..1c2ce02
--- /dev/null
+++ b/lib/asio/detail/scheduler_operation.hpp
@@ -0,0 +1,78 @@
+//
+// detail/scheduler_operation.hpp
+// ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+//
+// Copyright (c) 2003-2018 Christopher M. Kohlhoff (chris at kohlhoff dot com)
+//
+// 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 ASIO_DETAIL_SCHEDULER_OPERATION_HPP
+#define ASIO_DETAIL_SCHEDULER_OPERATION_HPP
+
+#if defined(_MSC_VER) && (_MSC_VER >= 1200)
+# pragma once
+#endif // defined(_MSC_VER) && (_MSC_VER >= 1200)
+
+#include "asio/error_code.hpp"
+#include "asio/detail/handler_tracking.hpp"
+#include "asio/detail/op_queue.hpp"
+
+#include "asio/detail/push_options.hpp"
+
+namespace asio {
+namespace detail {
+
+class scheduler;
+
+// Base class for all operations. A function pointer is used instead of virtual
+// functions to avoid the associated overhead.
+class scheduler_operation ASIO_INHERIT_TRACKED_HANDLER
+{
+public:
+ typedef scheduler_operation operation_type;
+
+ void complete(void* owner, const asio::error_code& ec,
+ std::size_t bytes_transferred)
+ {
+ func_(owner, this, ec, bytes_transferred);
+ }
+
+ void destroy()
+ {
+ func_(0, this, asio::error_code(), 0);
+ }
+
+protected:
+ typedef void (*func_type)(void*,
+ scheduler_operation*,
+ const asio::error_code&, std::size_t);
+
+ scheduler_operation(func_type func)
+ : next_(0),
+ func_(func),
+ task_result_(0)
+ {
+ }
+
+ // Prevents deletion through this type.
+ ~scheduler_operation()
+ {
+ }
+
+private:
+ friend class op_queue_access;
+ scheduler_operation* next_;
+ func_type func_;
+protected:
+ friend class scheduler;
+ unsigned int task_result_; // Passed into bytes transferred.
+};
+
+} // namespace detail
+} // namespace asio
+
+#include "asio/detail/pop_options.hpp"
+
+#endif // ASIO_DETAIL_SCHEDULER_OPERATION_HPP
diff --git a/lib/asio/detail/scheduler_thread_info.hpp b/lib/asio/detail/scheduler_thread_info.hpp
new file mode 100644
index 0000000..2ffe013
--- /dev/null
+++ b/lib/asio/detail/scheduler_thread_info.hpp
@@ -0,0 +1,40 @@
+//
+// detail/scheduler_thread_info.hpp
+// ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+//
+// Copyright (c) 2003-2018 Christopher M. Kohlhoff (chris at kohlhoff dot com)
+//
+// 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 ASIO_DETAIL_SCHEDULER_THREAD_INFO_HPP
+#define ASIO_DETAIL_SCHEDULER_THREAD_INFO_HPP
+
+#if defined(_MSC_VER) && (_MSC_VER >= 1200)
+# pragma once
+#endif // defined(_MSC_VER) && (_MSC_VER >= 1200)
+
+#include "asio/detail/op_queue.hpp"
+#include "asio/detail/thread_info_base.hpp"
+
+#include "asio/detail/push_options.hpp"
+
+namespace asio {
+namespace detail {
+
+class scheduler;
+class scheduler_operation;
+
+struct scheduler_thread_info : public thread_info_base
+{
+ op_queue<scheduler_operation> private_op_queue;
+ long private_outstanding_work;
+};
+
+} // namespace detail
+} // namespace asio
+
+#include "asio/detail/pop_options.hpp"
+
+#endif // ASIO_DETAIL_SCHEDULER_THREAD_INFO_HPP
diff --git a/lib/asio/detail/scoped_lock.hpp b/lib/asio/detail/scoped_lock.hpp
new file mode 100644
index 0000000..6cbce38
--- /dev/null
+++ b/lib/asio/detail/scoped_lock.hpp
@@ -0,0 +1,101 @@
+//
+// detail/scoped_lock.hpp
+// ~~~~~~~~~~~~~~~~~~~~~~
+//
+// Copyright (c) 2003-2018 Christopher M. Kohlhoff (chris at kohlhoff dot com)
+//
+// 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 ASIO_DETAIL_SCOPED_LOCK_HPP
+#define ASIO_DETAIL_SCOPED_LOCK_HPP
+
+#if defined(_MSC_VER) && (_MSC_VER >= 1200)
+# pragma once
+#endif // defined(_MSC_VER) && (_MSC_VER >= 1200)
+
+#include "asio/detail/noncopyable.hpp"
+
+#include "asio/detail/push_options.hpp"
+
+namespace asio {
+namespace detail {
+
+// Helper class to lock and unlock a mutex automatically.
+template <typename Mutex>
+class scoped_lock
+ : private noncopyable
+{
+public:
+ // Tag type used to distinguish constructors.
+ enum adopt_lock_t { adopt_lock };
+
+ // Constructor adopts a lock that is already held.
+ scoped_lock(Mutex& m, adopt_lock_t)
+ : mutex_(m),
+ locked_(true)
+ {
+ }
+
+ // Constructor acquires the lock.
+ explicit scoped_lock(Mutex& m)
+ : mutex_(m)
+ {
+ mutex_.lock();
+ locked_ = true;
+ }
+
+ // Destructor releases the lock.
+ ~scoped_lock()
+ {
+ if (locked_)
+ mutex_.unlock();
+ }
+
+ // Explicitly acquire the lock.
+ void lock()
+ {
+ if (!locked_)
+ {
+ mutex_.lock();
+ locked_ = true;
+ }
+ }
+
+ // Explicitly release the lock.
+ void unlock()
+ {
+ if (locked_)
+ {
+ mutex_.unlock();
+ locked_ = false;
+ }
+ }
+
+ // Test whether the lock is held.
+ bool locked() const
+ {
+ return locked_;
+ }
+
+ // Get the underlying mutex.
+ Mutex& mutex()
+ {
+ return mutex_;
+ }
+
+private:
+ // The underlying mutex.
+ Mutex& mutex_;
+
+ // Whether the mutex is currently locked or unlocked.
+ bool locked_;
+};
+
+} // namespace detail
+} // namespace asio
+
+#include "asio/detail/pop_options.hpp"
+
+#endif // ASIO_DETAIL_SCOPED_LOCK_HPP
diff --git a/lib/asio/detail/scoped_ptr.hpp b/lib/asio/detail/scoped_ptr.hpp
new file mode 100644
index 0000000..3449c53
--- /dev/null
+++ b/lib/asio/detail/scoped_ptr.hpp
@@ -0,0 +1,87 @@
+//
+// detail/scoped_ptr.hpp
+// ~~~~~~~~~~~~~~~~~~~~~
+//
+// Copyright (c) 2003-2018 Christopher M. Kohlhoff (chris at kohlhoff dot com)
+//
+// 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 ASIO_DETAIL_SCOPED_PTR_HPP
+#define ASIO_DETAIL_SCOPED_PTR_HPP
+
+#if defined(_MSC_VER) && (_MSC_VER >= 1200)
+# pragma once
+#endif // defined(_MSC_VER) && (_MSC_VER >= 1200)
+
+#include "asio/detail/config.hpp"
+
+#include "asio/detail/push_options.hpp"
+
+namespace asio {
+namespace detail {
+
+template <typename T>
+class scoped_ptr
+{
+public:
+ // Constructor.
+ explicit scoped_ptr(T* p = 0)
+ : p_(p)
+ {
+ }
+
+ // Destructor.
+ ~scoped_ptr()
+ {
+ delete p_;
+ }
+
+ // Access.
+ T* get()
+ {
+ return p_;
+ }
+
+ // Access.
+ T* operator->()
+ {
+ return p_;
+ }
+
+ // Dereference.
+ T& operator*()
+ {
+ return *p_;
+ }
+
+ // Reset pointer.
+ void reset(T* p = 0)
+ {
+ delete p_;
+ p_ = p;
+ }
+
+ // Release ownership of the pointer.
+ T* release()
+ {
+ T* tmp = p_;
+ p_ = 0;
+ return tmp;
+ }
+
+private:
+ // Disallow copying and assignment.
+ scoped_ptr(const scoped_ptr&);
+ scoped_ptr& operator=(const scoped_ptr&);
+
+ T* p_;
+};
+
+} // namespace detail
+} // namespace asio
+
+#include "asio/detail/pop_options.hpp"
+
+#endif // ASIO_DETAIL_SCOPED_PTR_HPP
diff --git a/lib/asio/detail/select_interrupter.hpp b/lib/asio/detail/select_interrupter.hpp
new file mode 100644
index 0000000..1a07599
--- /dev/null
+++ b/lib/asio/detail/select_interrupter.hpp
@@ -0,0 +1,46 @@
+//
+// detail/select_interrupter.hpp
+// ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+//
+// Copyright (c) 2003-2018 Christopher M. Kohlhoff (chris at kohlhoff dot com)
+//
+// 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 ASIO_DETAIL_SELECT_INTERRUPTER_HPP
+#define ASIO_DETAIL_SELECT_INTERRUPTER_HPP
+
+#if defined(_MSC_VER) && (_MSC_VER >= 1200)
+# pragma once
+#endif // defined(_MSC_VER) && (_MSC_VER >= 1200)
+
+#include "asio/detail/config.hpp"
+
+#if !defined(ASIO_WINDOWS_RUNTIME)
+
+#if defined(ASIO_WINDOWS) || defined(__CYGWIN__) || defined(__SYMBIAN32__)
+# include "asio/detail/socket_select_interrupter.hpp"
+#elif defined(ASIO_HAS_EVENTFD)
+# include "asio/detail/eventfd_select_interrupter.hpp"
+#else
+# include "asio/detail/pipe_select_interrupter.hpp"
+#endif
+
+namespace asio {
+namespace detail {
+
+#if defined(ASIO_WINDOWS) || defined(__CYGWIN__) || defined(__SYMBIAN32__)
+typedef socket_select_interrupter select_interrupter;
+#elif defined(ASIO_HAS_EVENTFD)
+typedef eventfd_select_interrupter select_interrupter;
+#else
+typedef pipe_select_interrupter select_interrupter;
+#endif
+
+} // namespace detail
+} // namespace asio
+
+#endif // !defined(ASIO_WINDOWS_RUNTIME)
+
+#endif // ASIO_DETAIL_SELECT_INTERRUPTER_HPP
diff --git a/lib/asio/detail/select_reactor.hpp b/lib/asio/detail/select_reactor.hpp
new file mode 100644
index 0000000..0996549
--- /dev/null
+++ b/lib/asio/detail/select_reactor.hpp
@@ -0,0 +1,238 @@
+//
+// detail/select_reactor.hpp
+// ~~~~~~~~~~~~~~~~~~~~~~~~~
+//
+// Copyright (c) 2003-2018 Christopher M. Kohlhoff (chris at kohlhoff dot com)
+//
+// 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 ASIO_DETAIL_SELECT_REACTOR_HPP
+#define ASIO_DETAIL_SELECT_REACTOR_HPP
+
+#if defined(_MSC_VER) && (_MSC_VER >= 1200)
+# pragma once
+#endif // defined(_MSC_VER) && (_MSC_VER >= 1200)
+
+#include "asio/detail/config.hpp"
+
+#if defined(ASIO_HAS_IOCP) \
+ || (!defined(ASIO_HAS_DEV_POLL) \
+ && !defined(ASIO_HAS_EPOLL) \
+ && !defined(ASIO_HAS_KQUEUE) \
+ && !defined(ASIO_WINDOWS_RUNTIME))
+
+#include <cstddef>
+#include "asio/detail/fd_set_adapter.hpp"
+#include "asio/detail/limits.hpp"
+#include "asio/detail/mutex.hpp"
+#include "asio/detail/op_queue.hpp"
+#include "asio/detail/reactor_op.hpp"
+#include "asio/detail/reactor_op_queue.hpp"
+#include "asio/detail/select_interrupter.hpp"
+#include "asio/detail/socket_types.hpp"
+#include "asio/detail/timer_queue_base.hpp"
+#include "asio/detail/timer_queue_set.hpp"
+#include "asio/detail/wait_op.hpp"
+#include "asio/execution_context.hpp"
+
+#if defined(ASIO_HAS_IOCP)
+# include "asio/detail/thread.hpp"
+#endif // defined(ASIO_HAS_IOCP)
+
+#include "asio/detail/push_options.hpp"
+
+namespace asio {
+namespace detail {
+
+class select_reactor
+ : public execution_context_service_base<select_reactor>
+{
+public:
+#if defined(ASIO_WINDOWS) || defined(__CYGWIN__)
+ enum op_types { read_op = 0, write_op = 1, except_op = 2,
+ max_select_ops = 3, connect_op = 3, max_ops = 4 };
+#else // defined(ASIO_WINDOWS) || defined(__CYGWIN__)
+ enum op_types { read_op = 0, write_op = 1, except_op = 2,
+ max_select_ops = 3, connect_op = 1, max_ops = 3 };
+#endif // defined(ASIO_WINDOWS) || defined(__CYGWIN__)
+
+ // Per-descriptor data.
+ struct per_descriptor_data
+ {
+ };
+
+ // Constructor.
+ ASIO_DECL select_reactor(asio::execution_context& ctx);
+
+ // Destructor.
+ ASIO_DECL ~select_reactor();
+
+ // Destroy all user-defined handler objects owned by the service.
+ ASIO_DECL void shutdown();
+
+ // Recreate internal descriptors following a fork.
+ ASIO_DECL void notify_fork(
+ asio::execution_context::fork_event fork_ev);
+
+ // Initialise the task, but only if the reactor is not in its own thread.
+ ASIO_DECL void init_task();
+
+ // Register a socket with the reactor. Returns 0 on success, system error
+ // code on failure.
+ ASIO_DECL int register_descriptor(socket_type, per_descriptor_data&);
+
+ // Register a descriptor with an associated single operation. Returns 0 on
+ // success, system error code on failure.
+ ASIO_DECL int register_internal_descriptor(
+ int op_type, socket_type descriptor,
+ per_descriptor_data& descriptor_data, reactor_op* op);
+
+ // Post a reactor operation for immediate completion.
+ void post_immediate_completion(reactor_op* op, bool is_continuation)
+ {
+ scheduler_.post_immediate_completion(op, is_continuation);
+ }
+
+ // Start a new operation. The reactor operation will be performed when the
+ // given descriptor is flagged as ready, or an error has occurred.
+ ASIO_DECL void start_op(int op_type, socket_type descriptor,
+ per_descriptor_data&, reactor_op* op, bool is_continuation, bool);
+
+ // Cancel all operations associated with the given descriptor. The
+ // handlers associated with the descriptor will be invoked with the
+ // operation_aborted error.
+ ASIO_DECL void cancel_ops(socket_type descriptor, per_descriptor_data&);
+
+ // Cancel any operations that are running against the descriptor and remove
+ // its registration from the reactor. The reactor resources associated with
+ // the descriptor must be released by calling cleanup_descriptor_data.
+ ASIO_DECL void deregister_descriptor(socket_type descriptor,
+ per_descriptor_data&, bool closing);
+
+ // Remove the descriptor's registration from the reactor. The reactor
+ // resources associated with the descriptor must be released by calling
+ // cleanup_descriptor_data.
+ ASIO_DECL void deregister_internal_descriptor(
+ socket_type descriptor, per_descriptor_data&);
+
+ // Perform any post-deregistration cleanup tasks associated with the
+ // descriptor data.
+ ASIO_DECL void cleanup_descriptor_data(per_descriptor_data&);
+
+ // Move descriptor registration from one descriptor_data object to another.
+ ASIO_DECL void move_descriptor(socket_type descriptor,
+ per_descriptor_data& target_descriptor_data,
+ per_descriptor_data& source_descriptor_data);
+
+ // Add a new timer queue to the reactor.
+ template <typename Time_Traits>
+ void add_timer_queue(timer_queue<Time_Traits>& queue);
+
+ // Remove a timer queue from the reactor.
+ template <typename Time_Traits>
+ void remove_timer_queue(timer_queue<Time_Traits>& queue);
+
+ // Schedule a new operation in the given timer queue to expire at the
+ // specified absolute time.
+ template <typename Time_Traits>
+ void schedule_timer(timer_queue<Time_Traits>& queue,
+ const typename Time_Traits::time_type& time,
+ typename timer_queue<Time_Traits>::per_timer_data& timer, wait_op* op);
+
+ // Cancel the timer operations associated with the given token. Returns the
+ // number of operations that have been posted or dispatched.
+ template <typename Time_Traits>
+ std::size_t cancel_timer(timer_queue<Time_Traits>& queue,
+ typename timer_queue<Time_Traits>::per_timer_data& timer,
+ std::size_t max_cancelled = (std::numeric_limits<std::size_t>::max)());
+
+ // Move the timer operations associated with the given timer.
+ template <typename Time_Traits>
+ void move_timer(timer_queue<Time_Traits>& queue,
+ typename timer_queue<Time_Traits>::per_timer_data& target,
+ typename timer_queue<Time_Traits>::per_timer_data& source);
+
+ // Run select once until interrupted or events are ready to be dispatched.
+ ASIO_DECL void run(long usec, op_queue<operation>& ops);
+
+ // Interrupt the select loop.
+ ASIO_DECL void interrupt();
+
+private:
+#if defined(ASIO_HAS_IOCP)
+ // Run the select loop in the thread.
+ ASIO_DECL void run_thread();
+#endif // defined(ASIO_HAS_IOCP)
+
+ // Helper function to add a new timer queue.
+ ASIO_DECL void do_add_timer_queue(timer_queue_base& queue);
+
+ // Helper function to remove a timer queue.
+ ASIO_DECL void do_remove_timer_queue(timer_queue_base& queue);
+
+ // Get the timeout value for the select call.
+ ASIO_DECL timeval* get_timeout(long usec, timeval& tv);
+
+ // Cancel all operations associated with the given descriptor. This function
+ // does not acquire the select_reactor's mutex.
+ ASIO_DECL void cancel_ops_unlocked(socket_type descriptor,
+ const asio::error_code& ec);
+
+ // The scheduler implementation used to post completions.
+# if defined(ASIO_HAS_IOCP)
+ typedef class win_iocp_io_context scheduler_type;
+# else // defined(ASIO_HAS_IOCP)
+ typedef class scheduler scheduler_type;
+# endif // defined(ASIO_HAS_IOCP)
+ scheduler_type& scheduler_;
+
+ // Mutex to protect access to internal data.
+ asio::detail::mutex mutex_;
+
+ // The interrupter is used to break a blocking select call.
+ select_interrupter interrupter_;
+
+ // The queues of read, write and except operations.
+ reactor_op_queue<socket_type> op_queue_[max_ops];
+
+ // The file descriptor sets to be passed to the select system call.
+ fd_set_adapter fd_sets_[max_select_ops];
+
+ // The timer queues.
+ timer_queue_set timer_queues_;
+
+#if defined(ASIO_HAS_IOCP)
+ // Helper class to run the reactor loop in a thread.
+ class thread_function;
+ friend class thread_function;
+
+ // Does the reactor loop thread need to stop.
+ bool stop_thread_;
+
+ // The thread that is running the reactor loop.
+ asio::detail::thread* thread_;
+#endif // defined(ASIO_HAS_IOCP)
+
+ // Whether the service has been shut down.
+ bool shutdown_;
+};
+
+} // namespace detail
+} // namespace asio
+
+#include "asio/detail/pop_options.hpp"
+
+#include "asio/detail/impl/select_reactor.hpp"
+#if defined(ASIO_HEADER_ONLY)
+# include "asio/detail/impl/select_reactor.ipp"
+#endif // defined(ASIO_HEADER_ONLY)
+
+#endif // defined(ASIO_HAS_IOCP)
+ // || (!defined(ASIO_HAS_DEV_POLL)
+ // && !defined(ASIO_HAS_EPOLL)
+ // && !defined(ASIO_HAS_KQUEUE)
+ // && !defined(ASIO_WINDOWS_RUNTIME))
+
+#endif // ASIO_DETAIL_SELECT_REACTOR_HPP
diff --git a/lib/asio/detail/service_registry.hpp b/lib/asio/detail/service_registry.hpp
new file mode 100644
index 0000000..cda6307
--- /dev/null
+++ b/lib/asio/detail/service_registry.hpp
@@ -0,0 +1,164 @@
+//
+// detail/service_registry.hpp
+// ~~~~~~~~~~~~~~~~~~~~~~~~~~~
+//
+// Copyright (c) 2003-2018 Christopher M. Kohlhoff (chris at kohlhoff dot com)
+//
+// 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 ASIO_DETAIL_SERVICE_REGISTRY_HPP
+#define ASIO_DETAIL_SERVICE_REGISTRY_HPP
+
+#if defined(_MSC_VER) && (_MSC_VER >= 1200)
+# pragma once
+#endif // defined(_MSC_VER) && (_MSC_VER >= 1200)
+
+#include "asio/detail/config.hpp"
+#include <typeinfo>
+#include "asio/detail/mutex.hpp"
+#include "asio/detail/noncopyable.hpp"
+#include "asio/detail/type_traits.hpp"
+#include "asio/execution_context.hpp"
+
+#include "asio/detail/push_options.hpp"
+
+namespace asio {
+
+class io_context;
+
+namespace detail {
+
+template <typename T>
+class typeid_wrapper {};
+
+class service_registry
+ : private noncopyable
+{
+public:
+ // Constructor.
+ ASIO_DECL service_registry(execution_context& owner);
+
+ // Destructor.
+ ASIO_DECL ~service_registry();
+
+ // Shutdown all services.
+ ASIO_DECL void shutdown_services();
+
+ // Destroy all services.
+ ASIO_DECL void destroy_services();
+
+ // Notify all services of a fork event.
+ ASIO_DECL void notify_fork(execution_context::fork_event fork_ev);
+
+ // Get the service object corresponding to the specified service type. Will
+ // create a new service object automatically if no such object already
+ // exists. Ownership of the service object is not transferred to the caller.
+ template <typename Service>
+ Service& use_service();
+
+ // Get the service object corresponding to the specified service type. Will
+ // create a new service object automatically if no such object already
+ // exists. Ownership of the service object is not transferred to the caller.
+ // This overload is used for backwards compatibility with services that
+ // inherit from io_context::service.
+ template <typename Service>
+ Service& use_service(io_context& owner);
+
+ // Add a service object. Throws on error, in which case ownership of the
+ // object is retained by the caller.
+ template <typename Service>
+ void add_service(Service* new_service);
+
+ // Check whether a service object of the specified type already exists.
+ template <typename Service>
+ bool has_service() const;
+
+private:
+ // Initalise a service's key when the key_type typedef is not available.
+ template <typename Service>
+ static void init_key(execution_context::service::key& key, ...);
+
+#if !defined(ASIO_NO_TYPEID)
+ // Initalise a service's key when the key_type typedef is available.
+ template <typename Service>
+ static void init_key(execution_context::service::key& key,
+ typename enable_if<
+ is_base_of<typename Service::key_type, Service>::value>::type*);
+#endif // !defined(ASIO_NO_TYPEID)
+
+ // Initialise a service's key based on its id.
+ ASIO_DECL static void init_key_from_id(
+ execution_context::service::key& key,
+ const execution_context::id& id);
+
+#if !defined(ASIO_NO_TYPEID)
+ // Initialise a service's key based on its id.
+ template <typename Service>
+ static void init_key_from_id(execution_context::service::key& key,
+ const service_id<Service>& /*id*/);
+#endif // !defined(ASIO_NO_TYPEID)
+
+ // Check if a service matches the given id.
+ ASIO_DECL static bool keys_match(
+ const execution_context::service::key& key1,
+ const execution_context::service::key& key2);
+
+ // The type of a factory function used for creating a service instance.
+ typedef execution_context::service*(*factory_type)(void*);
+
+ // Factory function for creating a service instance.
+ template <typename Service, typename Owner>
+ static execution_context::service* create(void* owner);
+
+ // Destroy a service instance.
+ ASIO_DECL static void destroy(execution_context::service* service);
+
+ // Helper class to manage service pointers.
+ struct auto_service_ptr;
+ friend struct auto_service_ptr;
+ struct auto_service_ptr
+ {
+ execution_context::service* ptr_;
+ ~auto_service_ptr() { destroy(ptr_); }
+ };
+
+ // Get the service object corresponding to the specified service key. Will
+ // create a new service object automatically if no such object already
+ // exists. Ownership of the service object is not transferred to the caller.
+ ASIO_DECL execution_context::service* do_use_service(
+ const execution_context::service::key& key,
+ factory_type factory, void* owner);
+
+ // Add a service object. Throws on error, in which case ownership of the
+ // object is retained by the caller.
+ ASIO_DECL void do_add_service(
+ const execution_context::service::key& key,
+ execution_context::service* new_service);
+
+ // Check whether a service object with the specified key already exists.
+ ASIO_DECL bool do_has_service(
+ const execution_context::service::key& key) const;
+
+ // Mutex to protect access to internal data.
+ mutable asio::detail::mutex mutex_;
+
+ // The owner of this service registry and the services it contains.
+ execution_context& owner_;
+
+ // The first service in the list of contained services.
+ execution_context::service* first_service_;
+};
+
+} // namespace detail
+} // namespace asio
+
+#include "asio/detail/pop_options.hpp"
+
+#include "asio/detail/impl/service_registry.hpp"
+#if defined(ASIO_HEADER_ONLY)
+# include "asio/detail/impl/service_registry.ipp"
+#endif // defined(ASIO_HEADER_ONLY)
+
+#endif // ASIO_DETAIL_SERVICE_REGISTRY_HPP
diff --git a/lib/asio/detail/signal_blocker.hpp b/lib/asio/detail/signal_blocker.hpp
new file mode 100644
index 0000000..b684295
--- /dev/null
+++ b/lib/asio/detail/signal_blocker.hpp
@@ -0,0 +1,44 @@
+//
+// detail/signal_blocker.hpp
+// ~~~~~~~~~~~~~~~~~~~~~~~~~
+//
+// Copyright (c) 2003-2018 Christopher M. Kohlhoff (chris at kohlhoff dot com)
+//
+// 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 ASIO_DETAIL_SIGNAL_BLOCKER_HPP
+#define ASIO_DETAIL_SIGNAL_BLOCKER_HPP
+
+#if defined(_MSC_VER) && (_MSC_VER >= 1200)
+# pragma once
+#endif // defined(_MSC_VER) && (_MSC_VER >= 1200)
+
+#include "asio/detail/config.hpp"
+
+#if !defined(ASIO_HAS_THREADS) || defined(ASIO_WINDOWS) \
+ || defined(ASIO_WINDOWS_RUNTIME) \
+ || defined(__CYGWIN__) || defined(__SYMBIAN32__)
+# include "asio/detail/null_signal_blocker.hpp"
+#elif defined(ASIO_HAS_PTHREADS)
+# include "asio/detail/posix_signal_blocker.hpp"
+#else
+# error Only Windows and POSIX are supported!
+#endif
+
+namespace asio {
+namespace detail {
+
+#if !defined(ASIO_HAS_THREADS) || defined(ASIO_WINDOWS) \
+ || defined(ASIO_WINDOWS_RUNTIME) \
+ || defined(__CYGWIN__) || defined(__SYMBIAN32__)
+typedef null_signal_blocker signal_blocker;
+#elif defined(ASIO_HAS_PTHREADS)
+typedef posix_signal_blocker signal_blocker;
+#endif
+
+} // namespace detail
+} // namespace asio
+
+#endif // ASIO_DETAIL_SIGNAL_BLOCKER_HPP
diff --git a/lib/asio/detail/signal_handler.hpp b/lib/asio/detail/signal_handler.hpp
new file mode 100644
index 0000000..d1c9910
--- /dev/null
+++ b/lib/asio/detail/signal_handler.hpp
@@ -0,0 +1,86 @@
+//
+// detail/signal_handler.hpp
+// ~~~~~~~~~~~~~~~~~~~~~~~~~
+//
+// Copyright (c) 2003-2018 Christopher M. Kohlhoff (chris at kohlhoff dot com)
+//
+// 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 ASIO_DETAIL_SIGNAL_HANDLER_HPP
+#define ASIO_DETAIL_SIGNAL_HANDLER_HPP
+
+#if defined(_MSC_VER) && (_MSC_VER >= 1200)
+# pragma once
+#endif // defined(_MSC_VER) && (_MSC_VER >= 1200)
+
+#include "asio/detail/config.hpp"
+#include "asio/detail/bind_handler.hpp"
+#include "asio/detail/fenced_block.hpp"
+#include "asio/detail/handler_alloc_helpers.hpp"
+#include "asio/detail/handler_invoke_helpers.hpp"
+#include "asio/detail/handler_work.hpp"
+#include "asio/detail/memory.hpp"
+#include "asio/detail/signal_op.hpp"
+
+#include "asio/detail/push_options.hpp"
+
+namespace asio {
+namespace detail {
+
+template <typename Handler>
+class signal_handler : public signal_op
+{
+public:
+ ASIO_DEFINE_HANDLER_PTR(signal_handler);
+
+ signal_handler(Handler& h)
+ : signal_op(&signal_handler::do_complete),
+ handler_(ASIO_MOVE_CAST(Handler)(h))
+ {
+ handler_work<Handler>::start(handler_);
+ }
+
+ static void do_complete(void* owner, operation* base,
+ const asio::error_code& /*ec*/,
+ std::size_t /*bytes_transferred*/)
+ {
+ // Take ownership of the handler object.
+ signal_handler* h(static_cast<signal_handler*>(base));
+ ptr p = { asio::detail::addressof(h->handler_), h, h };
+ handler_work<Handler> w(h->handler_);
+
+ ASIO_HANDLER_COMPLETION((*h));
+
+ // 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::binder2<Handler, asio::error_code, int>
+ handler(h->handler_, h->ec_, h->signal_number_);
+ p.h = asio::detail::addressof(handler.handler_);
+ p.reset();
+
+ // Make the upcall if required.
+ if (owner)
+ {
+ fenced_block b(fenced_block::half);
+ ASIO_HANDLER_INVOCATION_BEGIN((handler.arg1_, handler.arg2_));
+ w.complete(handler, handler.handler_);
+ ASIO_HANDLER_INVOCATION_END;
+ }
+ }
+
+private:
+ Handler handler_;
+};
+
+} // namespace detail
+} // namespace asio
+
+#include "asio/detail/pop_options.hpp"
+
+#endif // ASIO_DETAIL_SIGNAL_HANDLER_HPP
diff --git a/lib/asio/detail/signal_init.hpp b/lib/asio/detail/signal_init.hpp
new file mode 100644
index 0000000..814ff51
--- /dev/null
+++ b/lib/asio/detail/signal_init.hpp
@@ -0,0 +1,47 @@
+//
+// detail/signal_init.hpp
+// ~~~~~~~~~~~~~~~~~~~~~~
+//
+// Copyright (c) 2003-2018 Christopher M. Kohlhoff (chris at kohlhoff dot com)
+//
+// 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 ASIO_DETAIL_SIGNAL_INIT_HPP
+#define ASIO_DETAIL_SIGNAL_INIT_HPP
+
+#if defined(_MSC_VER) && (_MSC_VER >= 1200)
+# pragma once
+#endif // defined(_MSC_VER) && (_MSC_VER >= 1200)
+
+#include "asio/detail/config.hpp"
+
+#if !defined(ASIO_WINDOWS) && !defined(__CYGWIN__)
+
+#include <csignal>
+
+#include "asio/detail/push_options.hpp"
+
+namespace asio {
+namespace detail {
+
+template <int Signal = SIGPIPE>
+class signal_init
+{
+public:
+ // Constructor.
+ signal_init()
+ {
+ std::signal(Signal, SIG_IGN);
+ }
+};
+
+} // namespace detail
+} // namespace asio
+
+#include "asio/detail/pop_options.hpp"
+
+#endif // !defined(ASIO_WINDOWS) && !defined(__CYGWIN__)
+
+#endif // ASIO_DETAIL_SIGNAL_INIT_HPP
diff --git a/lib/asio/detail/signal_op.hpp b/lib/asio/detail/signal_op.hpp
new file mode 100644
index 0000000..c4e364c
--- /dev/null
+++ b/lib/asio/detail/signal_op.hpp
@@ -0,0 +1,49 @@
+//
+// detail/signal_op.hpp
+// ~~~~~~~~~~~~~~~~~~~~
+//
+// Copyright (c) 2003-2018 Christopher M. Kohlhoff (chris at kohlhoff dot com)
+//
+// 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 ASIO_DETAIL_SIGNAL_OP_HPP
+#define ASIO_DETAIL_SIGNAL_OP_HPP
+
+#if defined(_MSC_VER) && (_MSC_VER >= 1200)
+# pragma once
+#endif // defined(_MSC_VER) && (_MSC_VER >= 1200)
+
+#include "asio/detail/config.hpp"
+#include "asio/detail/operation.hpp"
+
+#include "asio/detail/push_options.hpp"
+
+namespace asio {
+namespace detail {
+
+class signal_op
+ : public operation
+{
+public:
+ // The error code to be passed to the completion handler.
+ asio::error_code ec_;
+
+ // The signal number to be passed to the completion handler.
+ int signal_number_;
+
+protected:
+ signal_op(func_type func)
+ : operation(func),
+ signal_number_(0)
+ {
+ }
+};
+
+} // namespace detail
+} // namespace asio
+
+#include "asio/detail/pop_options.hpp"
+
+#endif // ASIO_DETAIL_SIGNAL_OP_HPP
diff --git a/lib/asio/detail/signal_set_service.hpp b/lib/asio/detail/signal_set_service.hpp
new file mode 100644
index 0000000..a18ab70
--- /dev/null
+++ b/lib/asio/detail/signal_set_service.hpp
@@ -0,0 +1,217 @@
+//
+// detail/signal_set_service.hpp
+// ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+//
+// Copyright (c) 2003-2018 Christopher M. Kohlhoff (chris at kohlhoff dot com)
+//
+// 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 ASIO_DETAIL_SIGNAL_SET_SERVICE_HPP
+#define ASIO_DETAIL_SIGNAL_SET_SERVICE_HPP
+
+#if defined(_MSC_VER) && (_MSC_VER >= 1200)
+# pragma once
+#endif // defined(_MSC_VER) && (_MSC_VER >= 1200)
+
+#include "asio/detail/config.hpp"
+
+#include <cstddef>
+#include <signal.h>
+#include "asio/error.hpp"
+#include "asio/io_context.hpp"
+#include "asio/detail/handler_alloc_helpers.hpp"
+#include "asio/detail/memory.hpp"
+#include "asio/detail/op_queue.hpp"
+#include "asio/detail/signal_handler.hpp"
+#include "asio/detail/signal_op.hpp"
+#include "asio/detail/socket_types.hpp"
+
+#if !defined(ASIO_WINDOWS) && !defined(__CYGWIN__)
+# include "asio/detail/reactor.hpp"
+#endif // !defined(ASIO_WINDOWS) && !defined(__CYGWIN__)
+
+#include "asio/detail/push_options.hpp"
+
+namespace asio {
+namespace detail {
+
+#if defined(NSIG) && (NSIG > 0)
+enum { max_signal_number = NSIG };
+#else
+enum { max_signal_number = 128 };
+#endif
+
+extern ASIO_DECL struct signal_state* get_signal_state();
+
+extern "C" ASIO_DECL void asio_signal_handler(int signal_number);
+
+class signal_set_service :
+ public service_base<signal_set_service>
+{
+public:
+ // Type used for tracking an individual signal registration.
+ class registration
+ {
+ public:
+ // Default constructor.
+ registration()
+ : signal_number_(0),
+ queue_(0),
+ undelivered_(0),
+ next_in_table_(0),
+ prev_in_table_(0),
+ next_in_set_(0)
+ {
+ }
+
+ private:
+ // Only this service will have access to the internal values.
+ friend class signal_set_service;
+
+ // The signal number that is registered.
+ int signal_number_;
+
+ // The waiting signal handlers.
+ op_queue<signal_op>* queue_;
+
+ // The number of undelivered signals.
+ std::size_t undelivered_;
+
+ // Pointers to adjacent registrations in the registrations_ table.
+ registration* next_in_table_;
+ registration* prev_in_table_;
+
+ // Link to next registration in the signal set.
+ registration* next_in_set_;
+ };
+
+ // The implementation type of the signal_set.
+ class implementation_type
+ {
+ public:
+ // Default constructor.
+ implementation_type()
+ : signals_(0)
+ {
+ }
+
+ private:
+ // Only this service will have access to the internal values.
+ friend class signal_set_service;
+
+ // The pending signal handlers.
+ op_queue<signal_op> queue_;
+
+ // Linked list of registered signals.
+ registration* signals_;
+ };
+
+ // Constructor.
+ ASIO_DECL signal_set_service(asio::io_context& io_context);
+
+ // Destructor.
+ ASIO_DECL ~signal_set_service();
+
+ // Destroy all user-defined handler objects owned by the service.
+ ASIO_DECL void shutdown();
+
+ // Perform fork-related housekeeping.
+ ASIO_DECL void notify_fork(
+ asio::io_context::fork_event fork_ev);
+
+ // Construct a new signal_set implementation.
+ ASIO_DECL void construct(implementation_type& impl);
+
+ // Destroy a signal_set implementation.
+ ASIO_DECL void destroy(implementation_type& impl);
+
+ // Add a signal to a signal_set.
+ ASIO_DECL asio::error_code add(implementation_type& impl,
+ int signal_number, asio::error_code& ec);
+
+ // Remove a signal to a signal_set.
+ ASIO_DECL asio::error_code remove(implementation_type& impl,
+ int signal_number, asio::error_code& ec);
+
+ // Remove all signals from a signal_set.
+ ASIO_DECL asio::error_code clear(implementation_type& impl,
+ asio::error_code& ec);
+
+ // Cancel all operations associated with the signal set.
+ ASIO_DECL asio::error_code cancel(implementation_type& impl,
+ asio::error_code& ec);
+
+ // Start an asynchronous operation to wait for a signal to be delivered.
+ template <typename Handler>
+ void async_wait(implementation_type& impl, Handler& handler)
+ {
+ // Allocate and construct an operation to wrap the handler.
+ typedef signal_handler<Handler> op;
+ typename op::ptr p = { asio::detail::addressof(handler),
+ op::ptr::allocate(handler), 0 };
+ p.p = new (p.v) op(handler);
+
+ ASIO_HANDLER_CREATION((io_context_.context(),
+ *p.p, "signal_set", &impl, 0, "async_wait"));
+
+ start_wait_op(impl, p.p);
+ p.v = p.p = 0;
+ }
+
+ // Deliver notification that a particular signal occurred.
+ ASIO_DECL static void deliver_signal(int signal_number);
+
+private:
+ // Helper function to add a service to the global signal state.
+ ASIO_DECL static void add_service(signal_set_service* service);
+
+ // Helper function to remove a service from the global signal state.
+ ASIO_DECL static void remove_service(signal_set_service* service);
+
+ // Helper function to create the pipe descriptors.
+ ASIO_DECL static void open_descriptors();
+
+ // Helper function to close the pipe descriptors.
+ ASIO_DECL static void close_descriptors();
+
+ // Helper function to start a wait operation.
+ ASIO_DECL void start_wait_op(implementation_type& impl, signal_op* op);
+
+ // The io_context instance used for dispatching handlers.
+ io_context_impl& io_context_;
+
+#if !defined(ASIO_WINDOWS) \
+ && !defined(ASIO_WINDOWS_RUNTIME) \
+ && !defined(__CYGWIN__)
+ // The type used for registering for pipe reactor notifications.
+ class pipe_read_op;
+
+ // The reactor used for waiting for pipe readiness.
+ reactor& reactor_;
+
+ // The per-descriptor reactor data used for the pipe.
+ reactor::per_descriptor_data reactor_data_;
+#endif // !defined(ASIO_WINDOWS)
+ // && !defined(ASIO_WINDOWS_RUNTIME)
+ // && !defined(__CYGWIN__)
+
+ // A mapping from signal number to the registered signal sets.
+ registration* registrations_[max_signal_number];
+
+ // Pointers to adjacent services in linked list.
+ signal_set_service* next_;
+ signal_set_service* prev_;
+};
+
+} // namespace detail
+} // namespace asio
+
+#include "asio/detail/pop_options.hpp"
+
+#if defined(ASIO_HEADER_ONLY)
+# include "asio/detail/impl/signal_set_service.ipp"
+#endif // defined(ASIO_HEADER_ONLY)
+
+#endif // ASIO_DETAIL_SIGNAL_SET_SERVICE_HPP
diff --git a/lib/asio/detail/socket_holder.hpp b/lib/asio/detail/socket_holder.hpp
new file mode 100644
index 0000000..99b081f
--- /dev/null
+++ b/lib/asio/detail/socket_holder.hpp
@@ -0,0 +1,98 @@
+//
+// detail/socket_holder.hpp
+// ~~~~~~~~~~~~~~~~~~~~~~~~
+//
+// Copyright (c) 2003-2018 Christopher M. Kohlhoff (chris at kohlhoff dot com)
+//
+// 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 ASIO_DETAIL_SOCKET_HOLDER_HPP
+#define ASIO_DETAIL_SOCKET_HOLDER_HPP
+
+#if defined(_MSC_VER) && (_MSC_VER >= 1200)
+# pragma once
+#endif // defined(_MSC_VER) && (_MSC_VER >= 1200)
+
+#include "asio/detail/config.hpp"
+#include "asio/detail/noncopyable.hpp"
+#include "asio/detail/socket_ops.hpp"
+
+#include "asio/detail/push_options.hpp"
+
+namespace asio {
+namespace detail {
+
+// Implement the resource acquisition is initialisation idiom for sockets.
+class socket_holder
+ : private noncopyable
+{
+public:
+ // Construct as an uninitialised socket.
+ socket_holder()
+ : socket_(invalid_socket)
+ {
+ }
+
+ // Construct to take ownership of the specified socket.
+ explicit socket_holder(socket_type s)
+ : socket_(s)
+ {
+ }
+
+ // Destructor.
+ ~socket_holder()
+ {
+ if (socket_ != invalid_socket)
+ {
+ asio::error_code ec;
+ socket_ops::state_type state = 0;
+ socket_ops::close(socket_, state, true, ec);
+ }
+ }
+
+ // Get the underlying socket.
+ socket_type get() const
+ {
+ return socket_;
+ }
+
+ // Reset to an uninitialised socket.
+ void reset()
+ {
+ if (socket_ != invalid_socket)
+ {
+ asio::error_code ec;
+ socket_ops::state_type state = 0;
+ socket_ops::close(socket_, state, true, ec);
+ socket_ = invalid_socket;
+ }
+ }
+
+ // Reset to take ownership of the specified socket.
+ void reset(socket_type s)
+ {
+ reset();
+ socket_ = s;
+ }
+
+ // Release ownership of the socket.
+ socket_type release()
+ {
+ socket_type tmp = socket_;
+ socket_ = invalid_socket;
+ return tmp;
+ }
+
+private:
+ // The underlying socket.
+ socket_type socket_;
+};
+
+} // namespace detail
+} // namespace asio
+
+#include "asio/detail/pop_options.hpp"
+
+#endif // ASIO_DETAIL_SOCKET_HOLDER_HPP
diff --git a/lib/asio/detail/socket_ops.hpp b/lib/asio/detail/socket_ops.hpp
new file mode 100644
index 0000000..815b0d1
--- /dev/null
+++ b/lib/asio/detail/socket_ops.hpp
@@ -0,0 +1,337 @@
+//
+// detail/socket_ops.hpp
+// ~~~~~~~~~~~~~~~~~~~~~
+//
+// Copyright (c) 2003-2018 Christopher M. Kohlhoff (chris at kohlhoff dot com)
+//
+// 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 ASIO_DETAIL_SOCKET_OPS_HPP
+#define ASIO_DETAIL_SOCKET_OPS_HPP
+
+#if defined(_MSC_VER) && (_MSC_VER >= 1200)
+# pragma once
+#endif // defined(_MSC_VER) && (_MSC_VER >= 1200)
+
+#include "asio/detail/config.hpp"
+
+#include "asio/error_code.hpp"
+#include "asio/detail/memory.hpp"
+#include "asio/detail/socket_types.hpp"
+
+#include "asio/detail/push_options.hpp"
+
+namespace asio {
+namespace detail {
+namespace socket_ops {
+
+// Socket state bits.
+enum
+{
+ // The user wants a non-blocking socket.
+ user_set_non_blocking = 1,
+
+ // The socket has been set non-blocking.
+ internal_non_blocking = 2,
+
+ // Helper "state" used to determine whether the socket is non-blocking.
+ non_blocking = user_set_non_blocking | internal_non_blocking,
+
+ // User wants connection_aborted errors, which are disabled by default.
+ enable_connection_aborted = 4,
+
+ // The user set the linger option. Needs to be checked when closing.
+ user_set_linger = 8,
+
+ // The socket is stream-oriented.
+ stream_oriented = 16,
+
+ // The socket is datagram-oriented.
+ datagram_oriented = 32,
+
+ // The socket may have been dup()-ed.
+ possible_dup = 64
+};
+
+typedef unsigned char state_type;
+
+struct noop_deleter { void operator()(void*) {} };
+typedef shared_ptr<void> shared_cancel_token_type;
+typedef weak_ptr<void> weak_cancel_token_type;
+
+#if !defined(ASIO_WINDOWS_RUNTIME)
+
+ASIO_DECL socket_type accept(socket_type s, socket_addr_type* addr,
+ std::size_t* addrlen, asio::error_code& ec);
+
+ASIO_DECL socket_type sync_accept(socket_type s,
+ state_type state, socket_addr_type* addr,
+ std::size_t* addrlen, asio::error_code& ec);
+
+#if defined(ASIO_HAS_IOCP)
+
+ASIO_DECL void complete_iocp_accept(socket_type s,
+ void* output_buffer, DWORD address_length,
+ socket_addr_type* addr, std::size_t* addrlen,
+ socket_type new_socket, asio::error_code& ec);
+
+#else // defined(ASIO_HAS_IOCP)
+
+ASIO_DECL bool non_blocking_accept(socket_type s,
+ state_type state, socket_addr_type* addr, std::size_t* addrlen,
+ asio::error_code& ec, socket_type& new_socket);
+
+#endif // defined(ASIO_HAS_IOCP)
+
+ASIO_DECL int bind(socket_type s, const socket_addr_type* addr,
+ std::size_t addrlen, asio::error_code& ec);
+
+ASIO_DECL int close(socket_type s, state_type& state,
+ bool destruction, asio::error_code& ec);
+
+ASIO_DECL bool set_user_non_blocking(socket_type s,
+ state_type& state, bool value, asio::error_code& ec);
+
+ASIO_DECL bool set_internal_non_blocking(socket_type s,
+ state_type& state, bool value, asio::error_code& ec);
+
+ASIO_DECL int shutdown(socket_type s,
+ int what, asio::error_code& ec);
+
+ASIO_DECL int connect(socket_type s, const socket_addr_type* addr,
+ std::size_t addrlen, asio::error_code& ec);
+
+ASIO_DECL void sync_connect(socket_type s, const socket_addr_type* addr,
+ std::size_t addrlen, asio::error_code& ec);
+
+#if defined(ASIO_HAS_IOCP)
+
+ASIO_DECL void complete_iocp_connect(socket_type s,
+ asio::error_code& ec);
+
+#endif // defined(ASIO_HAS_IOCP)
+
+ASIO_DECL bool non_blocking_connect(socket_type s,
+ asio::error_code& ec);
+
+ASIO_DECL int socketpair(int af, int type, int protocol,
+ socket_type sv[2], asio::error_code& ec);
+
+ASIO_DECL bool sockatmark(socket_type s, asio::error_code& ec);
+
+ASIO_DECL size_t available(socket_type s, asio::error_code& ec);
+
+ASIO_DECL int listen(socket_type s,
+ int backlog, asio::error_code& ec);
+
+#if defined(ASIO_WINDOWS) || defined(__CYGWIN__)
+typedef WSABUF buf;
+#else // defined(ASIO_WINDOWS) || defined(__CYGWIN__)
+typedef iovec buf;
+#endif // defined(ASIO_WINDOWS) || defined(__CYGWIN__)
+
+ASIO_DECL void init_buf(buf& b, void* data, size_t size);
+
+ASIO_DECL void init_buf(buf& b, const void* data, size_t size);
+
+ASIO_DECL signed_size_type recv(socket_type s, buf* bufs,
+ size_t count, int flags, asio::error_code& ec);
+
+ASIO_DECL size_t sync_recv(socket_type s, state_type state, buf* bufs,
+ size_t count, int flags, bool all_empty, asio::error_code& ec);
+
+#if defined(ASIO_HAS_IOCP)
+
+ASIO_DECL void complete_iocp_recv(state_type state,
+ const weak_cancel_token_type& cancel_token, bool all_empty,
+ asio::error_code& ec, size_t bytes_transferred);
+
+#else // defined(ASIO_HAS_IOCP)
+
+ASIO_DECL bool non_blocking_recv(socket_type s,
+ buf* bufs, size_t count, int flags, bool is_stream,
+ asio::error_code& ec, size_t& bytes_transferred);
+
+#endif // defined(ASIO_HAS_IOCP)
+
+ASIO_DECL signed_size_type recvfrom(socket_type s, buf* bufs,
+ size_t count, int flags, socket_addr_type* addr,
+ std::size_t* addrlen, asio::error_code& ec);
+
+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, asio::error_code& ec);
+
+#if defined(ASIO_HAS_IOCP)
+
+ASIO_DECL void complete_iocp_recvfrom(
+ const weak_cancel_token_type& cancel_token,
+ asio::error_code& ec);
+
+#else // defined(ASIO_HAS_IOCP)
+
+ASIO_DECL bool non_blocking_recvfrom(socket_type s,
+ buf* bufs, size_t count, int flags,
+ socket_addr_type* addr, std::size_t* addrlen,
+ asio::error_code& ec, size_t& bytes_transferred);
+
+#endif // defined(ASIO_HAS_IOCP)
+
+ASIO_DECL signed_size_type recvmsg(socket_type s, buf* bufs,
+ size_t count, int in_flags, int& out_flags,
+ asio::error_code& ec);
+
+ASIO_DECL size_t sync_recvmsg(socket_type s, state_type state,
+ buf* bufs, size_t count, int in_flags, int& out_flags,
+ asio::error_code& ec);
+
+#if defined(ASIO_HAS_IOCP)
+
+ASIO_DECL void complete_iocp_recvmsg(
+ const weak_cancel_token_type& cancel_token,
+ asio::error_code& ec);
+
+#else // defined(ASIO_HAS_IOCP)
+
+ASIO_DECL bool non_blocking_recvmsg(socket_type s,
+ buf* bufs, size_t count, int in_flags, int& out_flags,
+ asio::error_code& ec, size_t& bytes_transferred);
+
+#endif // defined(ASIO_HAS_IOCP)
+
+ASIO_DECL signed_size_type send(socket_type s, const buf* bufs,
+ size_t count, int flags, asio::error_code& ec);
+
+ASIO_DECL size_t sync_send(socket_type s, state_type state,
+ const buf* bufs, size_t count, int flags,
+ bool all_empty, asio::error_code& ec);
+
+#if defined(ASIO_HAS_IOCP)
+
+ASIO_DECL void complete_iocp_send(
+ const weak_cancel_token_type& cancel_token,
+ asio::error_code& ec);
+
+#else // defined(ASIO_HAS_IOCP)
+
+ASIO_DECL bool non_blocking_send(socket_type s,
+ const buf* bufs, size_t count, int flags,
+ asio::error_code& ec, size_t& bytes_transferred);
+
+#endif // defined(ASIO_HAS_IOCP)
+
+ASIO_DECL signed_size_type sendto(socket_type s, const buf* bufs,
+ size_t count, int flags, const socket_addr_type* addr,
+ std::size_t addrlen, asio::error_code& ec);
+
+ASIO_DECL size_t sync_sendto(socket_type s, state_type state,
+ const buf* bufs, size_t count, int flags, const socket_addr_type* addr,
+ std::size_t addrlen, asio::error_code& ec);
+
+#if !defined(ASIO_HAS_IOCP)
+
+ASIO_DECL bool non_blocking_sendto(socket_type s,
+ const buf* bufs, size_t count, int flags,
+ const socket_addr_type* addr, std::size_t addrlen,
+ asio::error_code& ec, size_t& bytes_transferred);
+
+#endif // !defined(ASIO_HAS_IOCP)
+
+ASIO_DECL socket_type socket(int af, int type, int protocol,
+ asio::error_code& ec);
+
+ASIO_DECL int setsockopt(socket_type s, state_type& state,
+ int level, int optname, const void* optval,
+ std::size_t optlen, asio::error_code& ec);
+
+ASIO_DECL int getsockopt(socket_type s, state_type state,
+ int level, int optname, void* optval,
+ size_t* optlen, asio::error_code& ec);
+
+ASIO_DECL int getpeername(socket_type s, socket_addr_type* addr,
+ std::size_t* addrlen, bool cached, asio::error_code& ec);
+
+ASIO_DECL int getsockname(socket_type s, socket_addr_type* addr,
+ std::size_t* addrlen, asio::error_code& ec);
+
+ASIO_DECL int ioctl(socket_type s, state_type& state,
+ int cmd, ioctl_arg_type* arg, asio::error_code& ec);
+
+ASIO_DECL int select(int nfds, fd_set* readfds, fd_set* writefds,
+ fd_set* exceptfds, timeval* timeout, asio::error_code& ec);
+
+ASIO_DECL int poll_read(socket_type s,
+ state_type state, int msec, asio::error_code& ec);
+
+ASIO_DECL int poll_write(socket_type s,
+ state_type state, int msec, asio::error_code& ec);
+
+ASIO_DECL int poll_error(socket_type s,
+ state_type state, int msec, asio::error_code& ec);
+
+ASIO_DECL int poll_connect(socket_type s,
+ int msec, asio::error_code& ec);
+
+#endif // !defined(ASIO_WINDOWS_RUNTIME)
+
+ASIO_DECL const char* inet_ntop(int af, const void* src, char* dest,
+ size_t length, unsigned long scope_id, asio::error_code& ec);
+
+ASIO_DECL int inet_pton(int af, const char* src, void* dest,
+ unsigned long* scope_id, asio::error_code& ec);
+
+ASIO_DECL int gethostname(char* name,
+ int namelen, asio::error_code& ec);
+
+#if !defined(ASIO_WINDOWS_RUNTIME)
+
+ASIO_DECL asio::error_code getaddrinfo(const char* host,
+ const char* service, const addrinfo_type& hints,
+ addrinfo_type** result, asio::error_code& ec);
+
+ASIO_DECL asio::error_code background_getaddrinfo(
+ const weak_cancel_token_type& cancel_token, const char* host,
+ const char* service, const addrinfo_type& hints,
+ addrinfo_type** result, asio::error_code& ec);
+
+ASIO_DECL void freeaddrinfo(addrinfo_type* ai);
+
+ASIO_DECL asio::error_code getnameinfo(
+ const socket_addr_type* addr, std::size_t addrlen,
+ char* host, std::size_t hostlen, char* serv,
+ std::size_t servlen, int flags, asio::error_code& ec);
+
+ASIO_DECL asio::error_code sync_getnameinfo(
+ const socket_addr_type* addr, std::size_t addrlen,
+ char* host, std::size_t hostlen, char* serv,
+ std::size_t servlen, int sock_type, asio::error_code& ec);
+
+ASIO_DECL asio::error_code background_getnameinfo(
+ const weak_cancel_token_type& cancel_token,
+ const socket_addr_type* addr, std::size_t addrlen,
+ char* host, std::size_t hostlen, char* serv,
+ std::size_t servlen, int sock_type, asio::error_code& ec);
+
+#endif // !defined(ASIO_WINDOWS_RUNTIME)
+
+ASIO_DECL u_long_type network_to_host_long(u_long_type value);
+
+ASIO_DECL u_long_type host_to_network_long(u_long_type value);
+
+ASIO_DECL u_short_type network_to_host_short(u_short_type value);
+
+ASIO_DECL u_short_type host_to_network_short(u_short_type value);
+
+} // namespace socket_ops
+} // namespace detail
+} // namespace asio
+
+#include "asio/detail/pop_options.hpp"
+
+#if defined(ASIO_HEADER_ONLY)
+# include "asio/detail/impl/socket_ops.ipp"
+#endif // defined(ASIO_HEADER_ONLY)
+
+#endif // ASIO_DETAIL_SOCKET_OPS_HPP
diff --git a/lib/asio/detail/socket_option.hpp b/lib/asio/detail/socket_option.hpp
new file mode 100644
index 0000000..6852d56
--- /dev/null
+++ b/lib/asio/detail/socket_option.hpp
@@ -0,0 +1,316 @@
+//
+// detail/socket_option.hpp
+// ~~~~~~~~~~~~~~~~~~~~~~~~
+//
+// Copyright (c) 2003-2018 Christopher M. Kohlhoff (chris at kohlhoff dot com)
+//
+// 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 ASIO_DETAIL_SOCKET_OPTION_HPP
+#define ASIO_DETAIL_SOCKET_OPTION_HPP
+
+#if defined(_MSC_VER) && (_MSC_VER >= 1200)
+# pragma once
+#endif // defined(_MSC_VER) && (_MSC_VER >= 1200)
+
+#include "asio/detail/config.hpp"
+#include <cstddef>
+#include <stdexcept>
+#include "asio/detail/socket_types.hpp"
+#include "asio/detail/throw_exception.hpp"
+
+#include "asio/detail/push_options.hpp"
+
+namespace asio {
+namespace detail {
+namespace socket_option {
+
+// Helper template for implementing boolean-based options.
+template <int Level, int Name>
+class boolean
+{
+public:
+ // Default constructor.
+ boolean()
+ : value_(0)
+ {
+ }
+
+ // Construct with a specific option value.
+ explicit boolean(bool v)
+ : value_(v ? 1 : 0)
+ {
+ }
+
+ // Set the current value of the boolean.
+ boolean& operator=(bool v)
+ {
+ value_ = v ? 1 : 0;
+ return *this;
+ }
+
+ // Get the current value of the boolean.
+ bool value() const
+ {
+ return !!value_;
+ }
+
+ // Convert to bool.
+ operator bool() const
+ {
+ return !!value_;
+ }
+
+ // Test for false.
+ bool operator!() const
+ {
+ return !value_;
+ }
+
+ // Get the level of the socket option.
+ template <typename Protocol>
+ int level(const Protocol&) const
+ {
+ return Level;
+ }
+
+ // Get the name of the socket option.
+ template <typename Protocol>
+ int name(const Protocol&) const
+ {
+ return Name;
+ }
+
+ // Get the address of the boolean data.
+ template <typename Protocol>
+ int* data(const Protocol&)
+ {
+ return &value_;
+ }
+
+ // Get the address of the boolean data.
+ template <typename Protocol>
+ const int* data(const Protocol&) const
+ {
+ return &value_;
+ }
+
+ // Get the size of the boolean data.
+ template <typename Protocol>
+ std::size_t size(const Protocol&) const
+ {
+ return sizeof(value_);
+ }
+
+ // Set the size of the boolean data.
+ template <typename Protocol>
+ void resize(const Protocol&, std::size_t s)
+ {
+ // On some platforms (e.g. Windows Vista), the getsockopt function will
+ // return the size of a boolean socket option as one byte, even though a
+ // four byte integer was passed in.
+ switch (s)
+ {
+ case sizeof(char):
+ value_ = *reinterpret_cast<char*>(&value_) ? 1 : 0;
+ break;
+ case sizeof(value_):
+ break;
+ default:
+ {
+ std::length_error ex("boolean socket option resize");
+ asio::detail::throw_exception(ex);
+ }
+ }
+ }
+
+private:
+ int value_;
+};
+
+// Helper template for implementing integer options.
+template <int Level, int Name>
+class integer
+{
+public:
+ // Default constructor.
+ integer()
+ : value_(0)
+ {
+ }
+
+ // Construct with a specific option value.
+ explicit integer(int v)
+ : value_(v)
+ {
+ }
+
+ // Set the value of the int option.
+ integer& operator=(int v)
+ {
+ value_ = v;
+ return *this;
+ }
+
+ // Get the current value of the int option.
+ int value() const
+ {
+ return value_;
+ }
+
+ // Get the level of the socket option.
+ template <typename Protocol>
+ int level(const Protocol&) const
+ {
+ return Level;
+ }
+
+ // Get the name of the socket option.
+ template <typename Protocol>
+ int name(const Protocol&) const
+ {
+ return Name;
+ }
+
+ // Get the address of the int data.
+ template <typename Protocol>
+ int* data(const Protocol&)
+ {
+ return &value_;
+ }
+
+ // Get the address of the int data.
+ template <typename Protocol>
+ const int* data(const Protocol&) const
+ {
+ return &value_;
+ }
+
+ // Get the size of the int data.
+ template <typename Protocol>
+ std::size_t size(const Protocol&) const
+ {
+ return sizeof(value_);
+ }
+
+ // Set the size of the int data.
+ template <typename Protocol>
+ void resize(const Protocol&, std::size_t s)
+ {
+ if (s != sizeof(value_))
+ {
+ std::length_error ex("integer socket option resize");
+ asio::detail::throw_exception(ex);
+ }
+ }
+
+private:
+ int value_;
+};
+
+// Helper template for implementing linger options.
+template <int Level, int Name>
+class linger
+{
+public:
+ // Default constructor.
+ linger()
+ {
+ value_.l_onoff = 0;
+ value_.l_linger = 0;
+ }
+
+ // Construct with specific option values.
+ linger(bool e, int t)
+ {
+ enabled(e);
+ timeout ASIO_PREVENT_MACRO_SUBSTITUTION(t);
+ }
+
+ // Set the value for whether linger is enabled.
+ void enabled(bool value)
+ {
+ value_.l_onoff = value ? 1 : 0;
+ }
+
+ // Get the value for whether linger is enabled.
+ bool enabled() const
+ {
+ return value_.l_onoff != 0;
+ }
+
+ // Set the value for the linger timeout.
+ void timeout ASIO_PREVENT_MACRO_SUBSTITUTION(int value)
+ {
+#if defined(WIN32)
+ value_.l_linger = static_cast<u_short>(value);
+#else
+ value_.l_linger = value;
+#endif
+ }
+
+ // Get the value for the linger timeout.
+ int timeout ASIO_PREVENT_MACRO_SUBSTITUTION() const
+ {
+ return static_cast<int>(value_.l_linger);
+ }
+
+ // Get the level of the socket option.
+ template <typename Protocol>
+ int level(const Protocol&) const
+ {
+ return Level;
+ }
+
+ // Get the name of the socket option.
+ template <typename Protocol>
+ int name(const Protocol&) const
+ {
+ return Name;
+ }
+
+ // Get the address of the linger data.
+ template <typename Protocol>
+ detail::linger_type* data(const Protocol&)
+ {
+ return &value_;
+ }
+
+ // Get the address of the linger data.
+ template <typename Protocol>
+ const detail::linger_type* data(const Protocol&) const
+ {
+ return &value_;
+ }
+
+ // Get the size of the linger data.
+ template <typename Protocol>
+ std::size_t size(const Protocol&) const
+ {
+ return sizeof(value_);
+ }
+
+ // Set the size of the int data.
+ template <typename Protocol>
+ void resize(const Protocol&, std::size_t s)
+ {
+ if (s != sizeof(value_))
+ {
+ std::length_error ex("linger socket option resize");
+ asio::detail::throw_exception(ex);
+ }
+ }
+
+private:
+ detail::linger_type value_;
+};
+
+} // namespace socket_option
+} // namespace detail
+} // namespace asio
+
+#include "asio/detail/pop_options.hpp"
+
+#endif // ASIO_DETAIL_SOCKET_OPTION_HPP
diff --git a/lib/asio/detail/socket_select_interrupter.hpp b/lib/asio/detail/socket_select_interrupter.hpp
new file mode 100644
index 0000000..7351070
--- /dev/null
+++ b/lib/asio/detail/socket_select_interrupter.hpp
@@ -0,0 +1,91 @@
+//
+// detail/socket_select_interrupter.hpp
+// ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+//
+// Copyright (c) 2003-2018 Christopher M. Kohlhoff (chris at kohlhoff dot com)
+//
+// 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 ASIO_DETAIL_SOCKET_SELECT_INTERRUPTER_HPP
+#define ASIO_DETAIL_SOCKET_SELECT_INTERRUPTER_HPP
+
+#if defined(_MSC_VER) && (_MSC_VER >= 1200)
+# pragma once
+#endif // defined(_MSC_VER) && (_MSC_VER >= 1200)
+
+#include "asio/detail/config.hpp"
+
+#if !defined(ASIO_WINDOWS_RUNTIME)
+
+#if defined(ASIO_WINDOWS) \
+ || defined(__CYGWIN__) \
+ || defined(__SYMBIAN32__)
+
+#include "asio/detail/socket_types.hpp"
+
+#include "asio/detail/push_options.hpp"
+
+namespace asio {
+namespace detail {
+
+class socket_select_interrupter
+{
+public:
+ // Constructor.
+ ASIO_DECL socket_select_interrupter();
+
+ // Destructor.
+ ASIO_DECL ~socket_select_interrupter();
+
+ // Recreate the interrupter's descriptors. Used after a fork.
+ ASIO_DECL void recreate();
+
+ // Interrupt the select call.
+ ASIO_DECL void interrupt();
+
+ // Reset the select interrupt. Returns true if the call was interrupted.
+ ASIO_DECL bool reset();
+
+ // Get the read descriptor to be passed to select.
+ socket_type read_descriptor() const
+ {
+ return read_descriptor_;
+ }
+
+private:
+ // Open the descriptors. Throws on error.
+ ASIO_DECL void open_descriptors();
+
+ // Close the descriptors.
+ ASIO_DECL void close_descriptors();
+
+ // The read end of a connection used to interrupt the select call. This file
+ // descriptor is passed to select such that when it is time to stop, a single
+ // byte will be written on the other end of the connection and this
+ // descriptor will become readable.
+ socket_type read_descriptor_;
+
+ // The write end of a connection used to interrupt the select call. A single
+ // byte may be written to this to wake up the select which is waiting for the
+ // other end to become readable.
+ socket_type write_descriptor_;
+};
+
+} // namespace detail
+} // namespace asio
+
+#include "asio/detail/pop_options.hpp"
+
+#if defined(ASIO_HEADER_ONLY)
+# include "asio/detail/impl/socket_select_interrupter.ipp"
+#endif // defined(ASIO_HEADER_ONLY)
+
+#endif // defined(ASIO_WINDOWS)
+ // || defined(__CYGWIN__)
+ // || defined(__SYMBIAN32__)
+
+#endif // !defined(ASIO_WINDOWS_RUNTIME)
+
+#endif // ASIO_DETAIL_SOCKET_SELECT_INTERRUPTER_HPP
diff --git a/lib/asio/detail/socket_types.hpp b/lib/asio/detail/socket_types.hpp
new file mode 100644
index 0000000..d354343
--- /dev/null
+++ b/lib/asio/detail/socket_types.hpp
@@ -0,0 +1,416 @@
+//
+// detail/socket_types.hpp
+// ~~~~~~~~~~~~~~~~~~~~~~~
+//
+// Copyright (c) 2003-2018 Christopher M. Kohlhoff (chris at kohlhoff dot com)
+//
+// 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 ASIO_DETAIL_SOCKET_TYPES_HPP
+#define ASIO_DETAIL_SOCKET_TYPES_HPP
+
+#if defined(_MSC_VER) && (_MSC_VER >= 1200)
+# pragma once
+#endif // defined(_MSC_VER) && (_MSC_VER >= 1200)
+
+#include "asio/detail/config.hpp"
+
+#if defined(ASIO_WINDOWS_RUNTIME)
+// Empty.
+#elif defined(ASIO_WINDOWS) || defined(__CYGWIN__)
+# if defined(_WINSOCKAPI_) && !defined(_WINSOCK2API_)
+# error WinSock.h has already been included
+# endif // defined(_WINSOCKAPI_) && !defined(_WINSOCK2API_)
+# if defined(__BORLANDC__)
+# include <stdlib.h> // Needed for __errno
+# if !defined(_WSPIAPI_H_)
+# define _WSPIAPI_H_
+# define ASIO_WSPIAPI_H_DEFINED
+# endif // !defined(_WSPIAPI_H_)
+# endif // defined(__BORLANDC__)
+# include <winsock2.h>
+# include <ws2tcpip.h>
+# if defined(WINAPI_FAMILY)
+# if ((WINAPI_FAMILY & WINAPI_PARTITION_DESKTOP) != 0)
+# include <windows.h>
+# endif // ((WINAPI_FAMILY & WINAPI_PARTITION_DESKTOP) != 0)
+# endif // defined(WINAPI_FAMILY)
+# if !defined(ASIO_WINDOWS_APP)
+# include <mswsock.h>
+# endif // !defined(ASIO_WINDOWS_APP)
+# if defined(ASIO_WSPIAPI_H_DEFINED)
+# undef _WSPIAPI_H_
+# undef ASIO_WSPIAPI_H_DEFINED
+# endif // defined(ASIO_WSPIAPI_H_DEFINED)
+# if !defined(ASIO_NO_DEFAULT_LINKED_LIBS)
+# if defined(UNDER_CE)
+# pragma comment(lib, "ws2.lib")
+# elif defined(_MSC_VER) || defined(__BORLANDC__)
+# pragma comment(lib, "ws2_32.lib")
+# if !defined(ASIO_WINDOWS_APP)
+# pragma comment(lib, "mswsock.lib")
+# endif // !defined(ASIO_WINDOWS_APP)
+# endif // defined(_MSC_VER) || defined(__BORLANDC__)
+# endif // !defined(ASIO_NO_DEFAULT_LINKED_LIBS)
+# include "asio/detail/old_win_sdk_compat.hpp"
+#else
+# include <sys/ioctl.h>
+# if (defined(__MACH__) && defined(__APPLE__)) \
+ || defined(__FreeBSD__) || defined(__NetBSD__) \
+ || defined(__OpenBSD__) || defined(__linux__) \
+ || defined(__EMSCRIPTEN__)
+# include <poll.h>
+# elif !defined(__SYMBIAN32__)
+# include <sys/poll.h>
+# endif
+# include <sys/types.h>
+# include <sys/stat.h>
+# include <fcntl.h>
+# if defined(__hpux)
+# include <sys/time.h>
+# endif
+# if !defined(__hpux) || defined(__SELECT)
+# include <sys/select.h>
+# endif
+# include <sys/socket.h>
+# include <sys/uio.h>
+# include <sys/un.h>
+# include <netinet/in.h>
+# if !defined(__SYMBIAN32__)
+# include <netinet/tcp.h>
+# endif
+# include <arpa/inet.h>
+# include <netdb.h>
+# include <net/if.h>
+# include <limits.h>
+# if defined(__sun)
+# include <sys/filio.h>
+# include <sys/sockio.h>
+# endif
+#endif
+
+#include "asio/detail/push_options.hpp"
+
+namespace asio {
+namespace detail {
+
+#if defined(ASIO_WINDOWS_RUNTIME)
+const int max_addr_v4_str_len = 256;
+const int max_addr_v6_str_len = 256;
+typedef unsigned __int32 u_long_type;
+typedef unsigned __int16 u_short_type;
+struct in4_addr_type { u_long_type s_addr; };
+struct in4_mreq_type { in4_addr_type imr_multiaddr, imr_interface; };
+struct in6_addr_type { unsigned char s6_addr[16]; };
+struct in6_mreq_type { in6_addr_type ipv6mr_multiaddr;
+ unsigned long ipv6mr_interface; };
+struct socket_addr_type { int sa_family; };
+struct sockaddr_in4_type { int sin_family;
+ in4_addr_type sin_addr; u_short_type sin_port; };
+struct sockaddr_in6_type { int sin6_family;
+ in6_addr_type sin6_addr; u_short_type sin6_port;
+ u_long_type sin6_flowinfo; u_long_type sin6_scope_id; };
+struct sockaddr_storage_type { int ss_family;
+ unsigned char ss_bytes[128 - sizeof(int)]; };
+struct addrinfo_type { int ai_flags;
+ int ai_family, ai_socktype, ai_protocol;
+ int ai_addrlen; const void* ai_addr;
+ const char* ai_canonname; addrinfo_type* ai_next; };
+struct linger_type { u_short_type l_onoff, l_linger; };
+typedef u_long_type ioctl_arg_type;
+typedef int signed_size_type;
+# define ASIO_OS_DEF(c) ASIO_OS_DEF_##c
+# define ASIO_OS_DEF_AF_UNSPEC 0
+# define ASIO_OS_DEF_AF_INET 2
+# define ASIO_OS_DEF_AF_INET6 23
+# define ASIO_OS_DEF_SOCK_STREAM 1
+# define ASIO_OS_DEF_SOCK_DGRAM 2
+# define ASIO_OS_DEF_SOCK_RAW 3
+# define ASIO_OS_DEF_SOCK_SEQPACKET 5
+# define ASIO_OS_DEF_IPPROTO_IP 0
+# define ASIO_OS_DEF_IPPROTO_IPV6 41
+# define ASIO_OS_DEF_IPPROTO_TCP 6
+# define ASIO_OS_DEF_IPPROTO_UDP 17
+# define ASIO_OS_DEF_IPPROTO_ICMP 1
+# define ASIO_OS_DEF_IPPROTO_ICMPV6 58
+# define ASIO_OS_DEF_FIONBIO 1
+# define ASIO_OS_DEF_FIONREAD 2
+# define ASIO_OS_DEF_INADDR_ANY 0
+# define ASIO_OS_DEF_MSG_OOB 0x1
+# define ASIO_OS_DEF_MSG_PEEK 0x2
+# define ASIO_OS_DEF_MSG_DONTROUTE 0x4
+# define ASIO_OS_DEF_MSG_EOR 0 // Not supported.
+# define ASIO_OS_DEF_SHUT_RD 0x0
+# define ASIO_OS_DEF_SHUT_WR 0x1
+# define ASIO_OS_DEF_SHUT_RDWR 0x2
+# define ASIO_OS_DEF_SOMAXCONN 0x7fffffff
+# define ASIO_OS_DEF_SOL_SOCKET 0xffff
+# define ASIO_OS_DEF_SO_BROADCAST 0x20
+# define ASIO_OS_DEF_SO_DEBUG 0x1
+# define ASIO_OS_DEF_SO_DONTROUTE 0x10
+# define ASIO_OS_DEF_SO_KEEPALIVE 0x8
+# define ASIO_OS_DEF_SO_LINGER 0x80
+# define ASIO_OS_DEF_SO_OOBINLINE 0x100
+# define ASIO_OS_DEF_SO_SNDBUF 0x1001
+# define ASIO_OS_DEF_SO_RCVBUF 0x1002
+# define ASIO_OS_DEF_SO_SNDLOWAT 0x1003
+# define ASIO_OS_DEF_SO_RCVLOWAT 0x1004
+# define ASIO_OS_DEF_SO_REUSEADDR 0x4
+# define ASIO_OS_DEF_TCP_NODELAY 0x1
+# define ASIO_OS_DEF_IP_MULTICAST_IF 2
+# define ASIO_OS_DEF_IP_MULTICAST_TTL 3
+# define ASIO_OS_DEF_IP_MULTICAST_LOOP 4
+# define ASIO_OS_DEF_IP_ADD_MEMBERSHIP 5
+# define ASIO_OS_DEF_IP_DROP_MEMBERSHIP 6
+# define ASIO_OS_DEF_IP_TTL 7
+# define ASIO_OS_DEF_IPV6_UNICAST_HOPS 4
+# define ASIO_OS_DEF_IPV6_MULTICAST_IF 9
+# define ASIO_OS_DEF_IPV6_MULTICAST_HOPS 10
+# define ASIO_OS_DEF_IPV6_MULTICAST_LOOP 11
+# define ASIO_OS_DEF_IPV6_JOIN_GROUP 12
+# define ASIO_OS_DEF_IPV6_LEAVE_GROUP 13
+# define ASIO_OS_DEF_AI_CANONNAME 0x2
+# define ASIO_OS_DEF_AI_PASSIVE 0x1
+# define ASIO_OS_DEF_AI_NUMERICHOST 0x4
+# define ASIO_OS_DEF_AI_NUMERICSERV 0x8
+# define ASIO_OS_DEF_AI_V4MAPPED 0x800
+# define ASIO_OS_DEF_AI_ALL 0x100
+# define ASIO_OS_DEF_AI_ADDRCONFIG 0x400
+#elif defined(ASIO_WINDOWS) || defined(__CYGWIN__)
+typedef SOCKET socket_type;
+const SOCKET invalid_socket = INVALID_SOCKET;
+const int socket_error_retval = SOCKET_ERROR;
+const int max_addr_v4_str_len = 256;
+const int max_addr_v6_str_len = 256;
+typedef sockaddr socket_addr_type;
+typedef in_addr in4_addr_type;
+typedef ip_mreq in4_mreq_type;
+typedef sockaddr_in sockaddr_in4_type;
+# if defined(ASIO_HAS_OLD_WIN_SDK)
+typedef in6_addr_emulation in6_addr_type;
+typedef ipv6_mreq_emulation in6_mreq_type;
+typedef sockaddr_in6_emulation sockaddr_in6_type;
+typedef sockaddr_storage_emulation sockaddr_storage_type;
+typedef addrinfo_emulation addrinfo_type;
+# else
+typedef in6_addr in6_addr_type;
+typedef ipv6_mreq in6_mreq_type;
+typedef sockaddr_in6 sockaddr_in6_type;
+typedef sockaddr_storage sockaddr_storage_type;
+typedef addrinfo addrinfo_type;
+# endif
+typedef ::linger linger_type;
+typedef unsigned long ioctl_arg_type;
+typedef u_long u_long_type;
+typedef u_short u_short_type;
+typedef int signed_size_type;
+# define ASIO_OS_DEF(c) ASIO_OS_DEF_##c
+# define ASIO_OS_DEF_AF_UNSPEC AF_UNSPEC
+# define ASIO_OS_DEF_AF_INET AF_INET
+# define ASIO_OS_DEF_AF_INET6 AF_INET6
+# define ASIO_OS_DEF_SOCK_STREAM SOCK_STREAM
+# define ASIO_OS_DEF_SOCK_DGRAM SOCK_DGRAM
+# define ASIO_OS_DEF_SOCK_RAW SOCK_RAW
+# define ASIO_OS_DEF_SOCK_SEQPACKET SOCK_SEQPACKET
+# define ASIO_OS_DEF_IPPROTO_IP IPPROTO_IP
+# define ASIO_OS_DEF_IPPROTO_IPV6 IPPROTO_IPV6
+# define ASIO_OS_DEF_IPPROTO_TCP IPPROTO_TCP
+# define ASIO_OS_DEF_IPPROTO_UDP IPPROTO_UDP
+# define ASIO_OS_DEF_IPPROTO_ICMP IPPROTO_ICMP
+# define ASIO_OS_DEF_IPPROTO_ICMPV6 IPPROTO_ICMPV6
+# define ASIO_OS_DEF_FIONBIO FIONBIO
+# define ASIO_OS_DEF_FIONREAD FIONREAD
+# define ASIO_OS_DEF_INADDR_ANY INADDR_ANY
+# define ASIO_OS_DEF_MSG_OOB MSG_OOB
+# define ASIO_OS_DEF_MSG_PEEK MSG_PEEK
+# define ASIO_OS_DEF_MSG_DONTROUTE MSG_DONTROUTE
+# define ASIO_OS_DEF_MSG_EOR 0 // Not supported on Windows.
+# define ASIO_OS_DEF_SHUT_RD SD_RECEIVE
+# define ASIO_OS_DEF_SHUT_WR SD_SEND
+# define ASIO_OS_DEF_SHUT_RDWR SD_BOTH
+# define ASIO_OS_DEF_SOMAXCONN SOMAXCONN
+# define ASIO_OS_DEF_SOL_SOCKET SOL_SOCKET
+# define ASIO_OS_DEF_SO_BROADCAST SO_BROADCAST
+# define ASIO_OS_DEF_SO_DEBUG SO_DEBUG
+# define ASIO_OS_DEF_SO_DONTROUTE SO_DONTROUTE
+# define ASIO_OS_DEF_SO_KEEPALIVE SO_KEEPALIVE
+# define ASIO_OS_DEF_SO_LINGER SO_LINGER
+# define ASIO_OS_DEF_SO_OOBINLINE SO_OOBINLINE
+# define ASIO_OS_DEF_SO_SNDBUF SO_SNDBUF
+# define ASIO_OS_DEF_SO_RCVBUF SO_RCVBUF
+# define ASIO_OS_DEF_SO_SNDLOWAT SO_SNDLOWAT
+# define ASIO_OS_DEF_SO_RCVLOWAT SO_RCVLOWAT
+# define ASIO_OS_DEF_SO_REUSEADDR SO_REUSEADDR
+# define ASIO_OS_DEF_TCP_NODELAY TCP_NODELAY
+# define ASIO_OS_DEF_IP_MULTICAST_IF IP_MULTICAST_IF
+# define ASIO_OS_DEF_IP_MULTICAST_TTL IP_MULTICAST_TTL
+# define ASIO_OS_DEF_IP_MULTICAST_LOOP IP_MULTICAST_LOOP
+# define ASIO_OS_DEF_IP_ADD_MEMBERSHIP IP_ADD_MEMBERSHIP
+# define ASIO_OS_DEF_IP_DROP_MEMBERSHIP IP_DROP_MEMBERSHIP
+# define ASIO_OS_DEF_IP_TTL IP_TTL
+# define ASIO_OS_DEF_IPV6_UNICAST_HOPS IPV6_UNICAST_HOPS
+# define ASIO_OS_DEF_IPV6_MULTICAST_IF IPV6_MULTICAST_IF
+# define ASIO_OS_DEF_IPV6_MULTICAST_HOPS IPV6_MULTICAST_HOPS
+# define ASIO_OS_DEF_IPV6_MULTICAST_LOOP IPV6_MULTICAST_LOOP
+# define ASIO_OS_DEF_IPV6_JOIN_GROUP IPV6_JOIN_GROUP
+# define ASIO_OS_DEF_IPV6_LEAVE_GROUP IPV6_LEAVE_GROUP
+# define ASIO_OS_DEF_AI_CANONNAME AI_CANONNAME
+# define ASIO_OS_DEF_AI_PASSIVE AI_PASSIVE
+# define ASIO_OS_DEF_AI_NUMERICHOST AI_NUMERICHOST
+# if defined(AI_NUMERICSERV)
+# define ASIO_OS_DEF_AI_NUMERICSERV AI_NUMERICSERV
+# else
+# define ASIO_OS_DEF_AI_NUMERICSERV 0
+# endif
+# if defined(AI_V4MAPPED)
+# define ASIO_OS_DEF_AI_V4MAPPED AI_V4MAPPED
+# else
+# define ASIO_OS_DEF_AI_V4MAPPED 0
+# endif
+# if defined(AI_ALL)
+# define ASIO_OS_DEF_AI_ALL AI_ALL
+# else
+# define ASIO_OS_DEF_AI_ALL 0
+# endif
+# if defined(AI_ADDRCONFIG)
+# define ASIO_OS_DEF_AI_ADDRCONFIG AI_ADDRCONFIG
+# else
+# define ASIO_OS_DEF_AI_ADDRCONFIG 0
+# endif
+# if defined (_WIN32_WINNT)
+const int max_iov_len = 64;
+# else
+const int max_iov_len = 16;
+# endif
+#else
+typedef int socket_type;
+const int invalid_socket = -1;
+const int socket_error_retval = -1;
+const int max_addr_v4_str_len = INET_ADDRSTRLEN;
+#if defined(INET6_ADDRSTRLEN)
+const int max_addr_v6_str_len = INET6_ADDRSTRLEN + 1 + IF_NAMESIZE;
+#else // defined(INET6_ADDRSTRLEN)
+const int max_addr_v6_str_len = 256;
+#endif // defined(INET6_ADDRSTRLEN)
+typedef sockaddr socket_addr_type;
+typedef in_addr in4_addr_type;
+# if defined(__hpux)
+// HP-UX doesn't provide ip_mreq when _XOPEN_SOURCE_EXTENDED is defined.
+struct in4_mreq_type
+{
+ struct in_addr imr_multiaddr;
+ struct in_addr imr_interface;
+};
+# else
+typedef ip_mreq in4_mreq_type;
+# endif
+typedef sockaddr_in sockaddr_in4_type;
+typedef in6_addr in6_addr_type;
+typedef ipv6_mreq in6_mreq_type;
+typedef sockaddr_in6 sockaddr_in6_type;
+typedef sockaddr_storage sockaddr_storage_type;
+typedef sockaddr_un sockaddr_un_type;
+typedef addrinfo addrinfo_type;
+typedef ::linger linger_type;
+typedef int ioctl_arg_type;
+typedef uint32_t u_long_type;
+typedef uint16_t u_short_type;
+#if defined(ASIO_HAS_SSIZE_T)
+typedef ssize_t signed_size_type;
+#else // defined(ASIO_HAS_SSIZE_T)
+typedef int signed_size_type;
+#endif // defined(ASIO_HAS_SSIZE_T)
+# define ASIO_OS_DEF(c) ASIO_OS_DEF_##c
+# define ASIO_OS_DEF_AF_UNSPEC AF_UNSPEC
+# define ASIO_OS_DEF_AF_INET AF_INET
+# define ASIO_OS_DEF_AF_INET6 AF_INET6
+# define ASIO_OS_DEF_SOCK_STREAM SOCK_STREAM
+# define ASIO_OS_DEF_SOCK_DGRAM SOCK_DGRAM
+# define ASIO_OS_DEF_SOCK_RAW SOCK_RAW
+# define ASIO_OS_DEF_SOCK_SEQPACKET SOCK_SEQPACKET
+# define ASIO_OS_DEF_IPPROTO_IP IPPROTO_IP
+# define ASIO_OS_DEF_IPPROTO_IPV6 IPPROTO_IPV6
+# define ASIO_OS_DEF_IPPROTO_TCP IPPROTO_TCP
+# define ASIO_OS_DEF_IPPROTO_UDP IPPROTO_UDP
+# define ASIO_OS_DEF_IPPROTO_ICMP IPPROTO_ICMP
+# define ASIO_OS_DEF_IPPROTO_ICMPV6 IPPROTO_ICMPV6
+# define ASIO_OS_DEF_FIONBIO FIONBIO
+# define ASIO_OS_DEF_FIONREAD FIONREAD
+# define ASIO_OS_DEF_INADDR_ANY INADDR_ANY
+# define ASIO_OS_DEF_MSG_OOB MSG_OOB
+# define ASIO_OS_DEF_MSG_PEEK MSG_PEEK
+# define ASIO_OS_DEF_MSG_DONTROUTE MSG_DONTROUTE
+# define ASIO_OS_DEF_MSG_EOR MSG_EOR
+# define ASIO_OS_DEF_SHUT_RD SHUT_RD
+# define ASIO_OS_DEF_SHUT_WR SHUT_WR
+# define ASIO_OS_DEF_SHUT_RDWR SHUT_RDWR
+# define ASIO_OS_DEF_SOMAXCONN SOMAXCONN
+# define ASIO_OS_DEF_SOL_SOCKET SOL_SOCKET
+# define ASIO_OS_DEF_SO_BROADCAST SO_BROADCAST
+# define ASIO_OS_DEF_SO_DEBUG SO_DEBUG
+# define ASIO_OS_DEF_SO_DONTROUTE SO_DONTROUTE
+# define ASIO_OS_DEF_SO_KEEPALIVE SO_KEEPALIVE
+# define ASIO_OS_DEF_SO_LINGER SO_LINGER
+# define ASIO_OS_DEF_SO_OOBINLINE SO_OOBINLINE
+# define ASIO_OS_DEF_SO_SNDBUF SO_SNDBUF
+# define ASIO_OS_DEF_SO_RCVBUF SO_RCVBUF
+# define ASIO_OS_DEF_SO_SNDLOWAT SO_SNDLOWAT
+# define ASIO_OS_DEF_SO_RCVLOWAT SO_RCVLOWAT
+# define ASIO_OS_DEF_SO_REUSEADDR SO_REUSEADDR
+# define ASIO_OS_DEF_TCP_NODELAY TCP_NODELAY
+# define ASIO_OS_DEF_IP_MULTICAST_IF IP_MULTICAST_IF
+# define ASIO_OS_DEF_IP_MULTICAST_TTL IP_MULTICAST_TTL
+# define ASIO_OS_DEF_IP_MULTICAST_LOOP IP_MULTICAST_LOOP
+# define ASIO_OS_DEF_IP_ADD_MEMBERSHIP IP_ADD_MEMBERSHIP
+# define ASIO_OS_DEF_IP_DROP_MEMBERSHIP IP_DROP_MEMBERSHIP
+# define ASIO_OS_DEF_IP_TTL IP_TTL
+# define ASIO_OS_DEF_IPV6_UNICAST_HOPS IPV6_UNICAST_HOPS
+# define ASIO_OS_DEF_IPV6_MULTICAST_IF IPV6_MULTICAST_IF
+# define ASIO_OS_DEF_IPV6_MULTICAST_HOPS IPV6_MULTICAST_HOPS
+# define ASIO_OS_DEF_IPV6_MULTICAST_LOOP IPV6_MULTICAST_LOOP
+# define ASIO_OS_DEF_IPV6_JOIN_GROUP IPV6_JOIN_GROUP
+# define ASIO_OS_DEF_IPV6_LEAVE_GROUP IPV6_LEAVE_GROUP
+# define ASIO_OS_DEF_AI_CANONNAME AI_CANONNAME
+# define ASIO_OS_DEF_AI_PASSIVE AI_PASSIVE
+# define ASIO_OS_DEF_AI_NUMERICHOST AI_NUMERICHOST
+# if defined(AI_NUMERICSERV)
+# define ASIO_OS_DEF_AI_NUMERICSERV AI_NUMERICSERV
+# else
+# define ASIO_OS_DEF_AI_NUMERICSERV 0
+# endif
+// Note: QNX Neutrino 6.3 defines AI_V4MAPPED, AI_ALL and AI_ADDRCONFIG but
+// does not implement them. Therefore they are specifically excluded here.
+# if defined(AI_V4MAPPED) && !defined(__QNXNTO__)
+# define ASIO_OS_DEF_AI_V4MAPPED AI_V4MAPPED
+# else
+# define ASIO_OS_DEF_AI_V4MAPPED 0
+# endif
+# if defined(AI_ALL) && !defined(__QNXNTO__)
+# define ASIO_OS_DEF_AI_ALL AI_ALL
+# else
+# define ASIO_OS_DEF_AI_ALL 0
+# endif
+# if defined(AI_ADDRCONFIG) && !defined(__QNXNTO__)
+# define ASIO_OS_DEF_AI_ADDRCONFIG AI_ADDRCONFIG
+# else
+# define ASIO_OS_DEF_AI_ADDRCONFIG 0
+# endif
+# if defined(IOV_MAX)
+const int max_iov_len = IOV_MAX;
+# else
+// POSIX platforms are not required to define IOV_MAX.
+const int max_iov_len = 16;
+# endif
+#endif
+const int custom_socket_option_level = 0xA5100000;
+const int enable_connection_aborted_option = 1;
+const int always_fail_option = 2;
+
+} // namespace detail
+} // namespace asio
+
+#include "asio/detail/pop_options.hpp"
+
+#endif // ASIO_DETAIL_SOCKET_TYPES_HPP
diff --git a/lib/asio/detail/solaris_fenced_block.hpp b/lib/asio/detail/solaris_fenced_block.hpp
new file mode 100644
index 0000000..d48f6a3
--- /dev/null
+++ b/lib/asio/detail/solaris_fenced_block.hpp
@@ -0,0 +1,62 @@
+//
+// detail/solaris_fenced_block.hpp
+// ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+//
+// Copyright (c) 2003-2018 Christopher M. Kohlhoff (chris at kohlhoff dot com)
+//
+// 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 ASIO_DETAIL_SOLARIS_FENCED_BLOCK_HPP
+#define ASIO_DETAIL_SOLARIS_FENCED_BLOCK_HPP
+
+#if defined(_MSC_VER) && (_MSC_VER >= 1200)
+# pragma once
+#endif // defined(_MSC_VER) && (_MSC_VER >= 1200)
+
+#include "asio/detail/config.hpp"
+
+#if defined(__sun)
+
+#include <atomic.h>
+#include "asio/detail/noncopyable.hpp"
+
+#include "asio/detail/push_options.hpp"
+
+namespace asio {
+namespace detail {
+
+class solaris_fenced_block
+ : private noncopyable
+{
+public:
+ enum half_t { half };
+ enum full_t { full };
+
+ // Constructor for a half fenced block.
+ explicit solaris_fenced_block(half_t)
+ {
+ }
+
+ // Constructor for a full fenced block.
+ explicit solaris_fenced_block(full_t)
+ {
+ membar_consumer();
+ }
+
+ // Destructor.
+ ~solaris_fenced_block()
+ {
+ membar_producer();
+ }
+};
+
+} // namespace detail
+} // namespace asio
+
+#include "asio/detail/pop_options.hpp"
+
+#endif // defined(__sun)
+
+#endif // ASIO_DETAIL_SOLARIS_FENCED_BLOCK_HPP
diff --git a/lib/asio/detail/static_mutex.hpp b/lib/asio/detail/static_mutex.hpp
new file mode 100644
index 0000000..8f2bc02
--- /dev/null
+++ b/lib/asio/detail/static_mutex.hpp
@@ -0,0 +1,52 @@
+//
+// detail/static_mutex.hpp
+// ~~~~~~~~~~~~~~~~~~~~~~~
+//
+// Copyright (c) 2003-2018 Christopher M. Kohlhoff (chris at kohlhoff dot com)
+//
+// 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 ASIO_DETAIL_STATIC_MUTEX_HPP
+#define ASIO_DETAIL_STATIC_MUTEX_HPP
+
+#if defined(_MSC_VER) && (_MSC_VER >= 1200)
+# pragma once
+#endif // defined(_MSC_VER) && (_MSC_VER >= 1200)
+
+#include "asio/detail/config.hpp"
+
+#if !defined(ASIO_HAS_THREADS)
+# include "asio/detail/null_static_mutex.hpp"
+#elif defined(ASIO_WINDOWS)
+# include "asio/detail/win_static_mutex.hpp"
+#elif defined(ASIO_HAS_PTHREADS)
+# include "asio/detail/posix_static_mutex.hpp"
+#elif defined(ASIO_HAS_STD_MUTEX_AND_CONDVAR)
+# include "asio/detail/std_static_mutex.hpp"
+#else
+# error Only Windows and POSIX are supported!
+#endif
+
+namespace asio {
+namespace detail {
+
+#if !defined(ASIO_HAS_THREADS)
+typedef null_static_mutex static_mutex;
+# define ASIO_STATIC_MUTEX_INIT ASIO_NULL_STATIC_MUTEX_INIT
+#elif defined(ASIO_WINDOWS)
+typedef win_static_mutex static_mutex;
+# define ASIO_STATIC_MUTEX_INIT ASIO_WIN_STATIC_MUTEX_INIT
+#elif defined(ASIO_HAS_PTHREADS)
+typedef posix_static_mutex static_mutex;
+# define ASIO_STATIC_MUTEX_INIT ASIO_POSIX_STATIC_MUTEX_INIT
+#elif defined(ASIO_HAS_STD_MUTEX_AND_CONDVAR)
+typedef std_static_mutex static_mutex;
+# define ASIO_STATIC_MUTEX_INIT ASIO_STD_STATIC_MUTEX_INIT
+#endif
+
+} // namespace detail
+} // namespace asio
+
+#endif // ASIO_DETAIL_STATIC_MUTEX_HPP
diff --git a/lib/asio/detail/std_event.hpp b/lib/asio/detail/std_event.hpp
new file mode 100644
index 0000000..5639ecd
--- /dev/null
+++ b/lib/asio/detail/std_event.hpp
@@ -0,0 +1,176 @@
+//
+// detail/std_event.hpp
+// ~~~~~~~~~~~~~~~~~~~~
+//
+// Copyright (c) 2003-2018 Christopher M. Kohlhoff (chris at kohlhoff dot com)
+//
+// 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 ASIO_DETAIL_STD_EVENT_HPP
+#define ASIO_DETAIL_STD_EVENT_HPP
+
+#if defined(_MSC_VER) && (_MSC_VER >= 1200)
+# pragma once
+#endif // defined(_MSC_VER) && (_MSC_VER >= 1200)
+
+#include "asio/detail/config.hpp"
+
+#if defined(ASIO_HAS_STD_MUTEX_AND_CONDVAR)
+
+#include <chrono>
+#include <condition_variable>
+#include "asio/detail/assert.hpp"
+#include "asio/detail/noncopyable.hpp"
+
+#include "asio/detail/push_options.hpp"
+
+namespace asio {
+namespace detail {
+
+class std_event
+ : private noncopyable
+{
+public:
+ // Constructor.
+ std_event()
+ : state_(0)
+ {
+ }
+
+ // Destructor.
+ ~std_event()
+ {
+ }
+
+ // Signal the event. (Retained for backward compatibility.)
+ template <typename Lock>
+ void signal(Lock& lock)
+ {
+ this->signal_all(lock);
+ }
+
+ // Signal all waiters.
+ template <typename Lock>
+ void signal_all(Lock& lock)
+ {
+ ASIO_ASSERT(lock.locked());
+ (void)lock;
+ state_ |= 1;
+ cond_.notify_all();
+ }
+
+ // Unlock the mutex and signal one waiter.
+ template <typename Lock>
+ void unlock_and_signal_one(Lock& lock)
+ {
+ ASIO_ASSERT(lock.locked());
+ state_ |= 1;
+ bool have_waiters = (state_ > 1);
+ lock.unlock();
+ if (have_waiters)
+ cond_.notify_one();
+ }
+
+ // If there's a waiter, unlock the mutex and signal it.
+ template <typename Lock>
+ bool maybe_unlock_and_signal_one(Lock& lock)
+ {
+ ASIO_ASSERT(lock.locked());
+ state_ |= 1;
+ if (state_ > 1)
+ {
+ lock.unlock();
+ cond_.notify_one();
+ return true;
+ }
+ return false;
+ }
+
+ // Reset the event.
+ template <typename Lock>
+ void clear(Lock& lock)
+ {
+ ASIO_ASSERT(lock.locked());
+ (void)lock;
+ state_ &= ~std::size_t(1);
+ }
+
+ // Wait for the event to become signalled.
+ template <typename Lock>
+ void wait(Lock& lock)
+ {
+ ASIO_ASSERT(lock.locked());
+ unique_lock_adapter u_lock(lock);
+ while ((state_ & 1) == 0)
+ {
+ waiter w(state_);
+ cond_.wait(u_lock.unique_lock_);
+ }
+ }
+
+ // Timed wait for the event to become signalled.
+ template <typename Lock>
+ bool wait_for_usec(Lock& lock, long usec)
+ {
+ ASIO_ASSERT(lock.locked());
+ unique_lock_adapter u_lock(lock);
+ if ((state_ & 1) == 0)
+ {
+ waiter w(state_);
+ cond_.wait_for(u_lock.unique_lock_, std::chrono::microseconds(usec));
+ }
+ return (state_ & 1) != 0;
+ }
+
+private:
+ // Helper class to temporarily adapt a scoped_lock into a unique_lock so that
+ // it can be passed to std::condition_variable::wait().
+ struct unique_lock_adapter
+ {
+ template <typename Lock>
+ explicit unique_lock_adapter(Lock& lock)
+ : unique_lock_(lock.mutex().mutex_, std::adopt_lock)
+ {
+ }
+
+ ~unique_lock_adapter()
+ {
+ unique_lock_.release();
+ }
+
+ std::unique_lock<std::mutex> unique_lock_;
+ };
+
+ // Helper to increment and decrement the state to track outstanding waiters.
+ class waiter
+ {
+ public:
+ explicit waiter(std::size_t& state)
+ : state_(state)
+ {
+ state_ += 2;
+ }
+
+ ~waiter()
+ {
+ state_ -= 2;
+ }
+
+ private:
+ std::size_t& state_;
+ };
+
+ std::condition_variable cond_;
+ std::size_t state_;
+};
+
+} // namespace detail
+} // namespace asio
+
+#include "asio/detail/pop_options.hpp"
+
+#endif // defined(ASIO_HAS_STD_MUTEX_AND_CONDVAR)
+
+#endif // ASIO_DETAIL_STD_EVENT_HPP
diff --git a/lib/asio/detail/std_fenced_block.hpp b/lib/asio/detail/std_fenced_block.hpp
new file mode 100644
index 0000000..0d8ade0
--- /dev/null
+++ b/lib/asio/detail/std_fenced_block.hpp
@@ -0,0 +1,62 @@
+//
+// detail/std_fenced_block.hpp
+// ~~~~~~~~~~~~~~~~~~~~~~~~~~~
+//
+// Copyright (c) 2003-2018 Christopher M. Kohlhoff (chris at kohlhoff dot com)
+//
+// 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 ASIO_DETAIL_STD_FENCED_BLOCK_HPP
+#define ASIO_DETAIL_STD_FENCED_BLOCK_HPP
+
+#if defined(_MSC_VER) && (_MSC_VER >= 1200)
+# pragma once
+#endif // defined(_MSC_VER) && (_MSC_VER >= 1200)
+
+#include "asio/detail/config.hpp"
+
+#if defined(ASIO_HAS_STD_ATOMIC)
+
+#include <atomic>
+#include "asio/detail/noncopyable.hpp"
+
+#include "asio/detail/push_options.hpp"
+
+namespace asio {
+namespace detail {
+
+class std_fenced_block
+ : private noncopyable
+{
+public:
+ enum half_t { half };
+ enum full_t { full };
+
+ // Constructor for a half fenced block.
+ explicit std_fenced_block(half_t)
+ {
+ }
+
+ // Constructor for a full fenced block.
+ explicit std_fenced_block(full_t)
+ {
+ std::atomic_thread_fence(std::memory_order_acquire);
+ }
+
+ // Destructor.
+ ~std_fenced_block()
+ {
+ std::atomic_thread_fence(std::memory_order_release);
+ }
+};
+
+} // namespace detail
+} // namespace asio
+
+#include "asio/detail/pop_options.hpp"
+
+#endif // defined(ASIO_HAS_STD_ATOMIC)
+
+#endif // ASIO_DETAIL_STD_FENCED_BLOCK_HPP
diff --git a/lib/asio/detail/std_global.hpp b/lib/asio/detail/std_global.hpp
new file mode 100644
index 0000000..0c5173e
--- /dev/null
+++ b/lib/asio/detail/std_global.hpp
@@ -0,0 +1,70 @@
+//
+// detail/std_global.hpp
+// ~~~~~~~~~~~~~~~~~~~~~
+//
+// Copyright (c) 2003-2018 Christopher M. Kohlhoff (chris at kohlhoff dot com)
+//
+// 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 ASIO_DETAIL_STD_GLOBAL_HPP
+#define ASIO_DETAIL_STD_GLOBAL_HPP
+
+#if defined(_MSC_VER) && (_MSC_VER >= 1200)
+# pragma once
+#endif // defined(_MSC_VER) && (_MSC_VER >= 1200)
+
+#include "asio/detail/config.hpp"
+
+#if defined(ASIO_HAS_STD_CALL_ONCE)
+
+#include <exception>
+#include <mutex>
+
+#include "asio/detail/push_options.hpp"
+
+namespace asio {
+namespace detail {
+
+template <typename T>
+struct std_global_impl
+{
+ // Helper function to perform initialisation.
+ static void do_init()
+ {
+ instance_.ptr_ = new T;
+ }
+
+ // Destructor automatically cleans up the global.
+ ~std_global_impl()
+ {
+ delete ptr_;
+ }
+
+ static std::once_flag init_once_;
+ static std_global_impl instance_;
+ T* ptr_;
+};
+
+template <typename T>
+std::once_flag std_global_impl<T>::init_once_;
+
+template <typename T>
+std_global_impl<T> std_global_impl<T>::instance_;
+
+template <typename T>
+T& std_global()
+{
+ std::call_once(std_global_impl<T>::init_once_, &std_global_impl<T>::do_init);
+ return *std_global_impl<T>::instance_.ptr_;
+}
+
+} // namespace detail
+} // namespace asio
+
+#include "asio/detail/pop_options.hpp"
+
+#endif // defined(ASIO_HAS_STD_CALL_ONCE)
+
+#endif // ASIO_DETAIL_STD_GLOBAL_HPP
diff --git a/lib/asio/detail/std_mutex.hpp b/lib/asio/detail/std_mutex.hpp
new file mode 100644
index 0000000..159049e
--- /dev/null
+++ b/lib/asio/detail/std_mutex.hpp
@@ -0,0 +1,73 @@
+//
+// detail/std_mutex.hpp
+// ~~~~~~~~~~~~~~~~~~~~
+//
+// Copyright (c) 2003-2018 Christopher M. Kohlhoff (chris at kohlhoff dot com)
+//
+// 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 ASIO_DETAIL_STD_MUTEX_HPP
+#define ASIO_DETAIL_STD_MUTEX_HPP
+
+#if defined(_MSC_VER) && (_MSC_VER >= 1200)
+# pragma once
+#endif // defined(_MSC_VER) && (_MSC_VER >= 1200)
+
+#include "asio/detail/config.hpp"
+
+#if defined(ASIO_HAS_STD_MUTEX_AND_CONDVAR)
+
+#include <mutex>
+#include "asio/detail/noncopyable.hpp"
+#include "asio/detail/scoped_lock.hpp"
+
+#include "asio/detail/push_options.hpp"
+
+namespace asio {
+namespace detail {
+
+class std_event;
+
+class std_mutex
+ : private noncopyable
+{
+public:
+ typedef asio::detail::scoped_lock<std_mutex> scoped_lock;
+
+ // Constructor.
+ std_mutex()
+ {
+ }
+
+ // Destructor.
+ ~std_mutex()
+ {
+ }
+
+ // Lock the mutex.
+ void lock()
+ {
+ mutex_.lock();
+ }
+
+ // Unlock the mutex.
+ void unlock()
+ {
+ mutex_.unlock();
+ }
+
+private:
+ friend class std_event;
+ std::mutex mutex_;
+};
+
+} // namespace detail
+} // namespace asio
+
+#include "asio/detail/pop_options.hpp"
+
+#endif // defined(ASIO_HAS_STD_MUTEX_AND_CONDVAR)
+
+#endif // ASIO_DETAIL_STD_MUTEX_HPP
diff --git a/lib/asio/detail/std_static_mutex.hpp b/lib/asio/detail/std_static_mutex.hpp
new file mode 100644
index 0000000..e9c9dc5
--- /dev/null
+++ b/lib/asio/detail/std_static_mutex.hpp
@@ -0,0 +1,81 @@
+//
+// detail/std_static_mutex.hpp
+// ~~~~~~~~~~~~~~~~~~~~~~~~~~~
+//
+// Copyright (c) 2003-2018 Christopher M. Kohlhoff (chris at kohlhoff dot com)
+//
+// 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 ASIO_DETAIL_STD_STATIC_MUTEX_HPP
+#define ASIO_DETAIL_STD_STATIC_MUTEX_HPP
+
+#if defined(_MSC_VER) && (_MSC_VER >= 1200)
+# pragma once
+#endif // defined(_MSC_VER) && (_MSC_VER >= 1200)
+
+#include "asio/detail/config.hpp"
+
+#if defined(ASIO_HAS_STD_MUTEX_AND_CONDVAR)
+
+#include <mutex>
+#include "asio/detail/noncopyable.hpp"
+#include "asio/detail/scoped_lock.hpp"
+
+#include "asio/detail/push_options.hpp"
+
+namespace asio {
+namespace detail {
+
+class std_event;
+
+class std_static_mutex
+ : private noncopyable
+{
+public:
+ typedef asio::detail::scoped_lock<std_static_mutex> scoped_lock;
+
+ // Constructor.
+ std_static_mutex(int)
+ {
+ }
+
+ // Destructor.
+ ~std_static_mutex()
+ {
+ }
+
+ // Initialise the mutex.
+ void init()
+ {
+ // Nothing to do.
+ }
+
+ // Lock the mutex.
+ void lock()
+ {
+ mutex_.lock();
+ }
+
+ // Unlock the mutex.
+ void unlock()
+ {
+ mutex_.unlock();
+ }
+
+private:
+ friend class std_event;
+ std::mutex mutex_;
+};
+
+#define ASIO_STD_STATIC_MUTEX_INIT 0
+
+} // namespace detail
+} // namespace asio
+
+#include "asio/detail/pop_options.hpp"
+
+#endif // defined(ASIO_HAS_STD_MUTEX_AND_CONDVAR)
+
+#endif // ASIO_DETAIL_STD_STATIC_MUTEX_HPP
diff --git a/lib/asio/detail/std_thread.hpp b/lib/asio/detail/std_thread.hpp
new file mode 100644
index 0000000..a240308
--- /dev/null
+++ b/lib/asio/detail/std_thread.hpp
@@ -0,0 +1,71 @@
+//
+// detail/std_thread.hpp
+// ~~~~~~~~~~~~~~~~~~~~~
+//
+// Copyright (c) 2003-2018 Christopher M. Kohlhoff (chris at kohlhoff dot com)
+//
+// 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 ASIO_DETAIL_STD_THREAD_HPP
+#define ASIO_DETAIL_STD_THREAD_HPP
+
+#if defined(_MSC_VER) && (_MSC_VER >= 1200)
+# pragma once
+#endif // defined(_MSC_VER) && (_MSC_VER >= 1200)
+
+#include "asio/detail/config.hpp"
+
+#if defined(ASIO_HAS_STD_THREAD)
+
+#include <thread>
+#include "asio/detail/noncopyable.hpp"
+
+#include "asio/detail/push_options.hpp"
+
+namespace asio {
+namespace detail {
+
+class std_thread
+ : private noncopyable
+{
+public:
+ // Constructor.
+ template <typename Function>
+ std_thread(Function f, unsigned int = 0)
+ : thread_(f)
+ {
+ }
+
+ // Destructor.
+ ~std_thread()
+ {
+ join();
+ }
+
+ // Wait for the thread to exit.
+ void join()
+ {
+ if (thread_.joinable())
+ thread_.join();
+ }
+
+ // Get number of CPUs.
+ static std::size_t hardware_concurrency()
+ {
+ return std::thread::hardware_concurrency();
+ }
+
+private:
+ std::thread thread_;
+};
+
+} // namespace detail
+} // namespace asio
+
+#include "asio/detail/pop_options.hpp"
+
+#endif // defined(ASIO_HAS_STD_THREAD)
+
+#endif // ASIO_DETAIL_STD_THREAD_HPP
diff --git a/lib/asio/detail/strand_executor_service.hpp b/lib/asio/detail/strand_executor_service.hpp
new file mode 100644
index 0000000..67e8427
--- /dev/null
+++ b/lib/asio/detail/strand_executor_service.hpp
@@ -0,0 +1,142 @@
+//
+// detail/strand_executor_service.hpp
+// ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+//
+// Copyright (c) 2003-2018 Christopher M. Kohlhoff (chris at kohlhoff dot com)
+//
+// 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 ASIO_DETAIL_STRAND_EXECUTOR_SERVICE_HPP
+#define ASIO_DETAIL_STRAND_EXECUTOR_SERVICE_HPP
+
+#if defined(_MSC_VER) && (_MSC_VER >= 1200)
+# pragma once
+#endif // defined(_MSC_VER) && (_MSC_VER >= 1200)
+
+#include "asio/detail/config.hpp"
+#include "asio/detail/atomic_count.hpp"
+#include "asio/detail/executor_op.hpp"
+#include "asio/detail/memory.hpp"
+#include "asio/detail/mutex.hpp"
+#include "asio/detail/op_queue.hpp"
+#include "asio/detail/scheduler_operation.hpp"
+#include "asio/detail/scoped_ptr.hpp"
+#include "asio/execution_context.hpp"
+
+#include "asio/detail/push_options.hpp"
+
+namespace asio {
+namespace detail {
+
+// Default service implementation for a strand.
+class strand_executor_service
+ : public execution_context_service_base<strand_executor_service>
+{
+public:
+ // The underlying implementation of a strand.
+ class strand_impl
+ {
+ public:
+ ASIO_DECL ~strand_impl();
+
+ private:
+ friend class strand_executor_service;
+
+ // Mutex to protect access to internal data.
+ mutex* mutex_;
+
+ // Indicates whether the strand is currently "locked" by a handler. This
+ // means that there is a handler upcall in progress, or that the strand
+ // itself has been scheduled in order to invoke some pending handlers.
+ bool locked_;
+
+ // Indicates that the strand has been shut down and will accept no further
+ // handlers.
+ bool shutdown_;
+
+ // The handlers that are waiting on the strand but should not be run until
+ // after the next time the strand is scheduled. This queue must only be
+ // modified while the mutex is locked.
+ op_queue<scheduler_operation> waiting_queue_;
+
+ // The handlers that are ready to be run. Logically speaking, these are the
+ // handlers that hold the strand's lock. The ready queue is only modified
+ // from within the strand and so may be accessed without locking the mutex.
+ op_queue<scheduler_operation> ready_queue_;
+
+ // Pointers to adjacent handle implementations in linked list.
+ strand_impl* next_;
+ strand_impl* prev_;
+
+ // The strand service in where the implementation is held.
+ strand_executor_service* service_;
+ };
+
+ typedef shared_ptr<strand_impl> implementation_type;
+
+ // Construct a new strand service for the specified context.
+ ASIO_DECL explicit strand_executor_service(execution_context& context);
+
+ // Destroy all user-defined handler objects owned by the service.
+ ASIO_DECL void shutdown();
+
+ // Create a new strand_executor implementation.
+ ASIO_DECL implementation_type create_implementation();
+
+ // Request invocation of the given function.
+ template <typename Executor, typename Function, typename Allocator>
+ static void dispatch(const implementation_type& impl, Executor& ex,
+ ASIO_MOVE_ARG(Function) function, const Allocator& a);
+
+ // Request invocation of the given function and return immediately.
+ template <typename Executor, typename Function, typename Allocator>
+ static void post(const implementation_type& impl, Executor& ex,
+ ASIO_MOVE_ARG(Function) function, const Allocator& a);
+
+ // Request invocation of the given function and return immediately.
+ template <typename Executor, typename Function, typename Allocator>
+ static void defer(const implementation_type& impl, Executor& ex,
+ ASIO_MOVE_ARG(Function) function, const Allocator& a);
+
+ // Determine whether the strand is running in the current thread.
+ ASIO_DECL static bool running_in_this_thread(
+ const implementation_type& impl);
+
+private:
+ friend class strand_impl;
+ template <typename Executor> class invoker;
+
+ // Adds a function to the strand. Returns true if it acquires the lock.
+ ASIO_DECL static bool enqueue(const implementation_type& impl,
+ scheduler_operation* op);
+
+ // Mutex to protect access to the service-wide state.
+ mutex mutex_;
+
+ // Number of mutexes shared between all strand objects.
+ enum { num_mutexes = 193 };
+
+ // Pool of mutexes.
+ scoped_ptr<mutex> mutexes_[num_mutexes];
+
+ // Extra value used when hashing to prevent recycled memory locations from
+ // getting the same mutex.
+ std::size_t salt_;
+
+ // The head of a linked list of all implementations.
+ strand_impl* impl_list_;
+};
+
+} // namespace detail
+} // namespace asio
+
+#include "asio/detail/pop_options.hpp"
+
+#include "asio/detail/impl/strand_executor_service.hpp"
+#if defined(ASIO_HEADER_ONLY)
+# include "asio/detail/impl/strand_executor_service.ipp"
+#endif // defined(ASIO_HEADER_ONLY)
+
+#endif // ASIO_DETAIL_STRAND_EXECUTOR_SERVICE_HPP
diff --git a/lib/asio/detail/strand_service.hpp b/lib/asio/detail/strand_service.hpp
new file mode 100644
index 0000000..edc14a0
--- /dev/null
+++ b/lib/asio/detail/strand_service.hpp
@@ -0,0 +1,142 @@
+//
+// detail/strand_service.hpp
+// ~~~~~~~~~~~~~~~~~~~~~~~~~
+//
+// Copyright (c) 2003-2018 Christopher M. Kohlhoff (chris at kohlhoff dot com)
+//
+// 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 ASIO_DETAIL_STRAND_SERVICE_HPP
+#define ASIO_DETAIL_STRAND_SERVICE_HPP
+
+#if defined(_MSC_VER) && (_MSC_VER >= 1200)
+# pragma once
+#endif // defined(_MSC_VER) && (_MSC_VER >= 1200)
+
+#include "asio/detail/config.hpp"
+#include "asio/io_context.hpp"
+#include "asio/detail/mutex.hpp"
+#include "asio/detail/op_queue.hpp"
+#include "asio/detail/operation.hpp"
+#include "asio/detail/scoped_ptr.hpp"
+
+#include "asio/detail/push_options.hpp"
+
+namespace asio {
+namespace detail {
+
+// Default service implementation for a strand.
+class strand_service
+ : public asio::detail::service_base<strand_service>
+{
+private:
+ // Helper class to re-post the strand on exit.
+ struct on_do_complete_exit;
+
+ // Helper class to re-post the strand on exit.
+ struct on_dispatch_exit;
+
+public:
+
+ // The underlying implementation of a strand.
+ class strand_impl
+ : public operation
+ {
+ public:
+ strand_impl();
+
+ private:
+ // Only this service will have access to the internal values.
+ friend class strand_service;
+ friend struct on_do_complete_exit;
+ friend struct on_dispatch_exit;
+
+ // Mutex to protect access to internal data.
+ asio::detail::mutex mutex_;
+
+ // Indicates whether the strand is currently "locked" by a handler. This
+ // means that there is a handler upcall in progress, or that the strand
+ // itself has been scheduled in order to invoke some pending handlers.
+ bool locked_;
+
+ // The handlers that are waiting on the strand but should not be run until
+ // after the next time the strand is scheduled. This queue must only be
+ // modified while the mutex is locked.
+ op_queue<operation> waiting_queue_;
+
+ // The handlers that are ready to be run. Logically speaking, these are the
+ // handlers that hold the strand's lock. The ready queue is only modified
+ // from within the strand and so may be accessed without locking the mutex.
+ op_queue<operation> ready_queue_;
+ };
+
+ typedef strand_impl* implementation_type;
+
+ // Construct a new strand service for the specified io_context.
+ ASIO_DECL explicit strand_service(asio::io_context& io_context);
+
+ // Destroy all user-defined handler objects owned by the service.
+ ASIO_DECL void shutdown();
+
+ // Construct a new strand implementation.
+ ASIO_DECL void construct(implementation_type& impl);
+
+ // Request the io_context to invoke the given handler.
+ template <typename Handler>
+ void dispatch(implementation_type& impl, Handler& handler);
+
+ // Request the io_context to invoke the given handler and return immediately.
+ template <typename Handler>
+ void post(implementation_type& impl, Handler& handler);
+
+ // Determine whether the strand is running in the current thread.
+ ASIO_DECL bool running_in_this_thread(
+ const implementation_type& impl) const;
+
+private:
+ // Helper function to dispatch a handler. Returns true if the handler should
+ // be dispatched immediately.
+ ASIO_DECL bool do_dispatch(implementation_type& impl, operation* op);
+
+ // Helper fiunction to post a handler.
+ ASIO_DECL void do_post(implementation_type& impl,
+ operation* op, bool is_continuation);
+
+ ASIO_DECL static void do_complete(void* owner,
+ operation* base, const asio::error_code& ec,
+ std::size_t bytes_transferred);
+
+ // The io_context implementation used to post completions.
+ io_context_impl& io_context_;
+
+ // Mutex to protect access to the array of implementations.
+ asio::detail::mutex mutex_;
+
+ // Number of implementations shared between all strand objects.
+#if defined(ASIO_STRAND_IMPLEMENTATIONS)
+ enum { num_implementations = ASIO_STRAND_IMPLEMENTATIONS };
+#else // defined(ASIO_STRAND_IMPLEMENTATIONS)
+ enum { num_implementations = 193 };
+#endif // defined(ASIO_STRAND_IMPLEMENTATIONS)
+
+ // Pool of implementations.
+ scoped_ptr<strand_impl> implementations_[num_implementations];
+
+ // Extra value used when hashing to prevent recycled memory locations from
+ // getting the same strand implementation.
+ std::size_t salt_;
+};
+
+} // namespace detail
+} // namespace asio
+
+#include "asio/detail/pop_options.hpp"
+
+#include "asio/detail/impl/strand_service.hpp"
+#if defined(ASIO_HEADER_ONLY)
+# include "asio/detail/impl/strand_service.ipp"
+#endif // defined(ASIO_HEADER_ONLY)
+
+#endif // ASIO_DETAIL_STRAND_SERVICE_HPP
diff --git a/lib/asio/detail/string_view.hpp b/lib/asio/detail/string_view.hpp
new file mode 100644
index 0000000..f09cebc
--- /dev/null
+++ b/lib/asio/detail/string_view.hpp
@@ -0,0 +1,47 @@
+//
+// detail/string_view.hpp
+// ~~~~~~~~~~~~~~~~~~~~~~
+//
+// Copyright (c) 2003-2018 Christopher M. Kohlhoff (chris at kohlhoff dot com)
+//
+// 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 ASIO_DETAIL_STRING_VIEW_HPP
+#define ASIO_DETAIL_STRING_VIEW_HPP
+
+#if defined(_MSC_VER) && (_MSC_VER >= 1200)
+# pragma once
+#endif // defined(_MSC_VER) && (_MSC_VER >= 1200)
+
+#include "asio/detail/config.hpp"
+
+#if defined(ASIO_HAS_STRING_VIEW)
+
+#if defined(ASIO_HAS_STD_STRING_VIEW)
+# include <string_view>
+#elif defined(ASIO_HAS_STD_EXPERIMENTAL_STRING_VIEW)
+# include <experimental/string_view>
+#else // defined(ASIO_HAS_STD_EXPERIMENTAL_STRING_VIEW)
+# error ASIO_HAS_STRING_VIEW is set but no string_view is available
+#endif // defined(ASIO_HAS_STD_EXPERIMENTAL_STRING_VIEW)
+
+namespace asio {
+
+#if defined(ASIO_HAS_STD_STRING_VIEW)
+using std::basic_string_view;
+using std::string_view;
+#elif defined(ASIO_HAS_STD_EXPERIMENTAL_STRING_VIEW)
+using std::experimental::basic_string_view;
+using std::experimental::string_view;
+#endif // defined(ASIO_HAS_STD_EXPERIMENTAL_STRING_VIEW)
+
+} // namespace asio
+
+# define ASIO_STRING_VIEW_PARAM asio::string_view
+#else // defined(ASIO_HAS_STRING_VIEW)
+# define ASIO_STRING_VIEW_PARAM const std::string&
+#endif // defined(ASIO_HAS_STRING_VIEW)
+
+#endif // ASIO_DETAIL_STRING_VIEW_HPP
diff --git a/lib/asio/detail/thread.hpp b/lib/asio/detail/thread.hpp
new file mode 100644
index 0000000..ea556db
--- /dev/null
+++ b/lib/asio/detail/thread.hpp
@@ -0,0 +1,60 @@
+//
+// detail/thread.hpp
+// ~~~~~~~~~~~~~~~~~
+//
+// Copyright (c) 2003-2018 Christopher M. Kohlhoff (chris at kohlhoff dot com)
+//
+// 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 ASIO_DETAIL_THREAD_HPP
+#define ASIO_DETAIL_THREAD_HPP
+
+#if defined(_MSC_VER) && (_MSC_VER >= 1200)
+# pragma once
+#endif // defined(_MSC_VER) && (_MSC_VER >= 1200)
+
+#include "asio/detail/config.hpp"
+
+#if !defined(ASIO_HAS_THREADS)
+# include "asio/detail/null_thread.hpp"
+#elif defined(ASIO_WINDOWS)
+# if defined(UNDER_CE)
+# include "asio/detail/wince_thread.hpp"
+# elif defined(ASIO_WINDOWS_APP)
+# include "asio/detail/winapp_thread.hpp"
+# else
+# include "asio/detail/win_thread.hpp"
+# endif
+#elif defined(ASIO_HAS_PTHREADS)
+# include "asio/detail/posix_thread.hpp"
+#elif defined(ASIO_HAS_STD_THREAD)
+# include "asio/detail/std_thread.hpp"
+#else
+# error Only Windows, POSIX and std::thread are supported!
+#endif
+
+namespace asio {
+namespace detail {
+
+#if !defined(ASIO_HAS_THREADS)
+typedef null_thread thread;
+#elif defined(ASIO_WINDOWS)
+# if defined(UNDER_CE)
+typedef wince_thread thread;
+# elif defined(ASIO_WINDOWS_APP)
+typedef winapp_thread thread;
+# else
+typedef win_thread thread;
+# endif
+#elif defined(ASIO_HAS_PTHREADS)
+typedef posix_thread thread;
+#elif defined(ASIO_HAS_STD_THREAD)
+typedef std_thread thread;
+#endif
+
+} // namespace detail
+} // namespace asio
+
+#endif // ASIO_DETAIL_THREAD_HPP
diff --git a/lib/asio/detail/thread_context.hpp b/lib/asio/detail/thread_context.hpp
new file mode 100644
index 0000000..88b4f31
--- /dev/null
+++ b/lib/asio/detail/thread_context.hpp
@@ -0,0 +1,42 @@
+//
+// detail/thread_context.hpp
+// ~~~~~~~~~~~~~~~~~~~~~~~~~
+//
+// Copyright (c) 2003-2018 Christopher M. Kohlhoff (chris at kohlhoff dot com)
+//
+// 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 ASIO_DETAIL_THREAD_CONTEXT_HPP
+#define ASIO_DETAIL_THREAD_CONTEXT_HPP
+
+#if defined(_MSC_VER) && (_MSC_VER >= 1200)
+# pragma once
+#endif // defined(_MSC_VER) && (_MSC_VER >= 1200)
+
+#include <climits>
+#include <cstddef>
+#include "asio/detail/call_stack.hpp"
+
+#include "asio/detail/push_options.hpp"
+
+namespace asio {
+namespace detail {
+
+class thread_info_base;
+
+// Base class for things that manage threads (scheduler, win_iocp_io_context).
+class thread_context
+{
+public:
+ // Per-thread call stack to track the state of each thread in the context.
+ typedef call_stack<thread_context, thread_info_base> thread_call_stack;
+};
+
+} // namespace detail
+} // namespace asio
+
+#include "asio/detail/pop_options.hpp"
+
+#endif // ASIO_DETAIL_THREAD_CONTEXT_HPP
diff --git a/lib/asio/detail/thread_group.hpp b/lib/asio/detail/thread_group.hpp
new file mode 100644
index 0000000..1e400b0
--- /dev/null
+++ b/lib/asio/detail/thread_group.hpp
@@ -0,0 +1,89 @@
+//
+// detail/thread_group.hpp
+// ~~~~~~~~~~~~~~~~~~~~~~~
+//
+// Copyright (c) 2003-2018 Christopher M. Kohlhoff (chris at kohlhoff dot com)
+//
+// 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 ASIO_DETAIL_THREAD_GROUP_HPP
+#define ASIO_DETAIL_THREAD_GROUP_HPP
+
+#if defined(_MSC_VER) && (_MSC_VER >= 1200)
+# pragma once
+#endif // defined(_MSC_VER) && (_MSC_VER >= 1200)
+
+#include "asio/detail/config.hpp"
+#include "asio/detail/scoped_ptr.hpp"
+#include "asio/detail/thread.hpp"
+
+namespace asio {
+namespace detail {
+
+class thread_group
+{
+public:
+ // Constructor initialises an empty thread group.
+ thread_group()
+ : first_(0)
+ {
+ }
+
+ // Destructor joins any remaining threads in the group.
+ ~thread_group()
+ {
+ join();
+ }
+
+ // Create a new thread in the group.
+ template <typename Function>
+ void create_thread(Function f)
+ {
+ first_ = new item(f, first_);
+ }
+
+ // Create new threads in the group.
+ template <typename Function>
+ void create_threads(Function f, std::size_t num_threads)
+ {
+ for (std::size_t i = 0; i < num_threads; ++i)
+ create_thread(f);
+ }
+
+ // Wait for all threads in the group to exit.
+ void join()
+ {
+ while (first_)
+ {
+ first_->thread_.join();
+ item* tmp = first_;
+ first_ = first_->next_;
+ delete tmp;
+ }
+ }
+
+private:
+ // Structure used to track a single thread in the group.
+ struct item
+ {
+ template <typename Function>
+ explicit item(Function f, item* next)
+ : thread_(f),
+ next_(next)
+ {
+ }
+
+ asio::detail::thread thread_;
+ item* next_;
+ };
+
+ // The first thread in the group.
+ item* first_;
+};
+
+} // namespace detail
+} // namespace asio
+
+#endif // ASIO_DETAIL_THREAD_GROUP_HPP
diff --git a/lib/asio/detail/thread_info_base.hpp b/lib/asio/detail/thread_info_base.hpp
new file mode 100644
index 0000000..1b22207
--- /dev/null
+++ b/lib/asio/detail/thread_info_base.hpp
@@ -0,0 +1,121 @@
+//
+// detail/thread_info_base.hpp
+// ~~~~~~~~~~~~~~~~~~~~~~~~~~~
+//
+// Copyright (c) 2003-2018 Christopher M. Kohlhoff (chris at kohlhoff dot com)
+//
+// 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 ASIO_DETAIL_THREAD_INFO_BASE_HPP
+#define ASIO_DETAIL_THREAD_INFO_BASE_HPP
+
+#if defined(_MSC_VER) && (_MSC_VER >= 1200)
+# pragma once
+#endif // defined(_MSC_VER) && (_MSC_VER >= 1200)
+
+#include <climits>
+#include <cstddef>
+#include "asio/detail/noncopyable.hpp"
+
+#include "asio/detail/push_options.hpp"
+
+namespace asio {
+namespace detail {
+
+class thread_info_base
+ : private noncopyable
+{
+public:
+ struct default_tag
+ {
+ enum { mem_index = 0 };
+ };
+
+ struct awaitee_tag
+ {
+ enum { mem_index = 1 };
+ };
+
+ thread_info_base()
+ {
+ for (int i = 0; i < max_mem_index; ++i)
+ reusable_memory_[i] = 0;
+ }
+
+ ~thread_info_base()
+ {
+ for (int i = 0; i < max_mem_index; ++i)
+ if (reusable_memory_[i])
+ ::operator delete(reusable_memory_[i]);
+ }
+
+ static void* allocate(thread_info_base* this_thread, std::size_t size)
+ {
+ return allocate(default_tag(), this_thread, size);
+ }
+
+ static void deallocate(thread_info_base* this_thread,
+ void* pointer, std::size_t size)
+ {
+ deallocate(default_tag(), this_thread, pointer, size);
+ }
+
+ template <typename Purpose>
+ static void* allocate(Purpose, thread_info_base* this_thread,
+ std::size_t size)
+ {
+ std::size_t chunks = (size + chunk_size - 1) / chunk_size;
+
+ if (this_thread && this_thread->reusable_memory_[Purpose::mem_index])
+ {
+ void* const pointer = this_thread->reusable_memory_[Purpose::mem_index];
+ this_thread->reusable_memory_[Purpose::mem_index] = 0;
+
+ unsigned char* const mem = static_cast<unsigned char*>(pointer);
+ if (static_cast<std::size_t>(mem[0]) >= chunks)
+ {
+ mem[size] = mem[0];
+ return pointer;
+ }
+
+ ::operator delete(pointer);
+ }
+
+ void* const pointer = ::operator new(chunks * chunk_size + 1);
+ unsigned char* const mem = static_cast<unsigned char*>(pointer);
+ mem[size] = (chunks <= UCHAR_MAX) ? static_cast<unsigned char>(chunks) : 0;
+ return pointer;
+ }
+
+ template <typename Purpose>
+ static void deallocate(Purpose, thread_info_base* this_thread,
+ void* pointer, std::size_t size)
+ {
+ if (size <= chunk_size * UCHAR_MAX)
+ {
+ if (this_thread && this_thread->reusable_memory_[Purpose::mem_index] == 0)
+ {
+ unsigned char* const mem = static_cast<unsigned char*>(pointer);
+ mem[0] = mem[size];
+ this_thread->reusable_memory_[Purpose::mem_index] = pointer;
+ return;
+ }
+ }
+
+ ::operator delete(pointer);
+ }
+
+private:
+ enum { chunk_size = 4 };
+ enum { max_mem_index = 2 };
+ void* reusable_memory_[max_mem_index];
+};
+
+} // namespace detail
+} // namespace asio
+
+#include "asio/detail/pop_options.hpp"
+
+#endif // ASIO_DETAIL_THREAD_INFO_BASE_HPP
diff --git a/lib/asio/detail/throw_error.hpp b/lib/asio/detail/throw_error.hpp
new file mode 100644
index 0000000..5dd8785
--- /dev/null
+++ b/lib/asio/detail/throw_error.hpp
@@ -0,0 +1,53 @@
+//
+// detail/throw_error.hpp
+// ~~~~~~~~~~~~~~~~~~~~~~
+//
+// Copyright (c) 2003-2018 Christopher M. Kohlhoff (chris at kohlhoff dot com)
+//
+// 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 ASIO_DETAIL_THROW_ERROR_HPP
+#define ASIO_DETAIL_THROW_ERROR_HPP
+
+#if defined(_MSC_VER) && (_MSC_VER >= 1200)
+# pragma once
+#endif // defined(_MSC_VER) && (_MSC_VER >= 1200)
+
+#include "asio/detail/config.hpp"
+#include "asio/error_code.hpp"
+
+#include "asio/detail/push_options.hpp"
+
+namespace asio {
+namespace detail {
+
+ASIO_DECL void do_throw_error(const asio::error_code& err);
+
+ASIO_DECL void do_throw_error(const asio::error_code& err,
+ const char* location);
+
+inline void throw_error(const asio::error_code& err)
+{
+ if (err)
+ do_throw_error(err);
+}
+
+inline void throw_error(const asio::error_code& err,
+ const char* location)
+{
+ if (err)
+ do_throw_error(err, location);
+}
+
+} // namespace detail
+} // namespace asio
+
+#include "asio/detail/pop_options.hpp"
+
+#if defined(ASIO_HEADER_ONLY)
+# include "asio/detail/impl/throw_error.ipp"
+#endif // defined(ASIO_HEADER_ONLY)
+
+#endif // ASIO_DETAIL_THROW_ERROR_HPP
diff --git a/lib/asio/detail/throw_exception.hpp b/lib/asio/detail/throw_exception.hpp
new file mode 100644
index 0000000..f9f7bfb
--- /dev/null
+++ b/lib/asio/detail/throw_exception.hpp
@@ -0,0 +1,51 @@
+//
+// detail/throw_exception.hpp
+// ~~~~~~~~~~~~~~~~~~~~~~~~~~
+//
+// Copyright (c) 2003-2018 Christopher M. Kohlhoff (chris at kohlhoff dot com)
+//
+// 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 ASIO_DETAIL_THROW_EXCEPTION_HPP
+#define ASIO_DETAIL_THROW_EXCEPTION_HPP
+
+#if defined(_MSC_VER) && (_MSC_VER >= 1200)
+# pragma once
+#endif // defined(_MSC_VER) && (_MSC_VER >= 1200)
+
+#include "asio/detail/config.hpp"
+
+#if defined(ASIO_HAS_BOOST_THROW_EXCEPTION)
+# include <boost/throw_exception.hpp>
+#endif // defined(ASIO_BOOST_THROW_EXCEPTION)
+
+namespace asio {
+namespace detail {
+
+#if defined(ASIO_HAS_BOOST_THROW_EXCEPTION)
+using boost::throw_exception;
+#else // defined(ASIO_HAS_BOOST_THROW_EXCEPTION)
+
+// Declare the throw_exception function for all targets.
+template <typename Exception>
+void throw_exception(const Exception& e);
+
+// Only define the throw_exception function when exceptions are enabled.
+// Otherwise, it is up to the application to provide a definition of this
+// function.
+# if !defined(ASIO_NO_EXCEPTIONS)
+template <typename Exception>
+void throw_exception(const Exception& e)
+{
+ throw e;
+}
+# endif // !defined(ASIO_NO_EXCEPTIONS)
+
+#endif // defined(ASIO_HAS_BOOST_THROW_EXCEPTION)
+
+} // namespace detail
+} // namespace asio
+
+#endif // ASIO_DETAIL_THROW_EXCEPTION_HPP
diff --git a/lib/asio/detail/timer_queue.hpp b/lib/asio/detail/timer_queue.hpp
new file mode 100644
index 0000000..380e779
--- /dev/null
+++ b/lib/asio/detail/timer_queue.hpp
@@ -0,0 +1,358 @@
+//
+// detail/timer_queue.hpp
+// ~~~~~~~~~~~~~~~~~~~~~~
+//
+// Copyright (c) 2003-2018 Christopher M. Kohlhoff (chris at kohlhoff dot com)
+//
+// 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 ASIO_DETAIL_TIMER_QUEUE_HPP
+#define ASIO_DETAIL_TIMER_QUEUE_HPP
+
+#if defined(_MSC_VER) && (_MSC_VER >= 1200)
+# pragma once
+#endif // defined(_MSC_VER) && (_MSC_VER >= 1200)
+
+#include "asio/detail/config.hpp"
+#include <cstddef>
+#include <vector>
+#include "asio/detail/cstdint.hpp"
+#include "asio/detail/date_time_fwd.hpp"
+#include "asio/detail/limits.hpp"
+#include "asio/detail/op_queue.hpp"
+#include "asio/detail/timer_queue_base.hpp"
+#include "asio/detail/wait_op.hpp"
+#include "asio/error.hpp"
+
+#include "asio/detail/push_options.hpp"
+
+namespace asio {
+namespace detail {
+
+template <typename Time_Traits>
+class timer_queue
+ : public timer_queue_base
+{
+public:
+ // The time type.
+ typedef typename Time_Traits::time_type time_type;
+
+ // The duration type.
+ typedef typename Time_Traits::duration_type duration_type;
+
+ // Per-timer data.
+ class per_timer_data
+ {
+ public:
+ per_timer_data() :
+ heap_index_((std::numeric_limits<std::size_t>::max)()),
+ next_(0), prev_(0)
+ {
+ }
+
+ private:
+ friend class timer_queue;
+
+ // The operations waiting on the timer.
+ op_queue<wait_op> op_queue_;
+
+ // The index of the timer in the heap.
+ std::size_t heap_index_;
+
+ // Pointers to adjacent timers in a linked list.
+ per_timer_data* next_;
+ per_timer_data* prev_;
+ };
+
+ // Constructor.
+ timer_queue()
+ : timers_(),
+ heap_()
+ {
+ }
+
+ // Add a new timer to the queue. Returns true if this is the timer that is
+ // earliest in the queue, in which case the reactor's event demultiplexing
+ // function call may need to be interrupted and restarted.
+ bool enqueue_timer(const time_type& time, per_timer_data& timer, wait_op* op)
+ {
+ // Enqueue the timer object.
+ if (timer.prev_ == 0 && &timer != timers_)
+ {
+ if (this->is_positive_infinity(time))
+ {
+ // No heap entry is required for timers that never expire.
+ timer.heap_index_ = (std::numeric_limits<std::size_t>::max)();
+ }
+ else
+ {
+ // Put the new timer at the correct position in the heap. This is done
+ // first since push_back() can throw due to allocation failure.
+ timer.heap_index_ = heap_.size();
+ heap_entry entry = { time, &timer };
+ heap_.push_back(entry);
+ up_heap(heap_.size() - 1);
+ }
+
+ // Insert the new timer into the linked list of active timers.
+ timer.next_ = timers_;
+ timer.prev_ = 0;
+ if (timers_)
+ timers_->prev_ = &timer;
+ timers_ = &timer;
+ }
+
+ // Enqueue the individual timer operation.
+ timer.op_queue_.push(op);
+
+ // Interrupt reactor only if newly added timer is first to expire.
+ return timer.heap_index_ == 0 && timer.op_queue_.front() == op;
+ }
+
+ // Whether there are no timers in the queue.
+ virtual bool empty() const
+ {
+ return timers_ == 0;
+ }
+
+ // Get the time for the timer that is earliest in the queue.
+ virtual long wait_duration_msec(long max_duration) const
+ {
+ if (heap_.empty())
+ return max_duration;
+
+ return this->to_msec(
+ Time_Traits::to_posix_duration(
+ Time_Traits::subtract(heap_[0].time_, Time_Traits::now())),
+ max_duration);
+ }
+
+ // Get the time for the timer that is earliest in the queue.
+ virtual long wait_duration_usec(long max_duration) const
+ {
+ if (heap_.empty())
+ return max_duration;
+
+ return this->to_usec(
+ Time_Traits::to_posix_duration(
+ Time_Traits::subtract(heap_[0].time_, Time_Traits::now())),
+ max_duration);
+ }
+
+ // Dequeue all timers not later than the current time.
+ virtual void get_ready_timers(op_queue<operation>& ops)
+ {
+ if (!heap_.empty())
+ {
+ const time_type now = Time_Traits::now();
+ while (!heap_.empty() && !Time_Traits::less_than(now, heap_[0].time_))
+ {
+ per_timer_data* timer = heap_[0].timer_;
+ ops.push(timer->op_queue_);
+ remove_timer(*timer);
+ }
+ }
+ }
+
+ // Dequeue all timers.
+ virtual void get_all_timers(op_queue<operation>& ops)
+ {
+ while (timers_)
+ {
+ per_timer_data* timer = timers_;
+ timers_ = timers_->next_;
+ ops.push(timer->op_queue_);
+ timer->next_ = 0;
+ timer->prev_ = 0;
+ }
+
+ heap_.clear();
+ }
+
+ // Cancel and dequeue operations for the given timer.
+ std::size_t cancel_timer(per_timer_data& timer, op_queue<operation>& ops,
+ std::size_t max_cancelled = (std::numeric_limits<std::size_t>::max)())
+ {
+ std::size_t num_cancelled = 0;
+ if (timer.prev_ != 0 || &timer == timers_)
+ {
+ while (wait_op* op = (num_cancelled != max_cancelled)
+ ? timer.op_queue_.front() : 0)
+ {
+ op->ec_ = asio::error::operation_aborted;
+ timer.op_queue_.pop();
+ ops.push(op);
+ ++num_cancelled;
+ }
+ if (timer.op_queue_.empty())
+ remove_timer(timer);
+ }
+ return num_cancelled;
+ }
+
+ // Move operations from one timer to another, empty timer.
+ void move_timer(per_timer_data& target, per_timer_data& source)
+ {
+ target.op_queue_.push(source.op_queue_);
+
+ target.heap_index_ = source.heap_index_;
+ source.heap_index_ = (std::numeric_limits<std::size_t>::max)();
+
+ if (target.heap_index_ < heap_.size())
+ heap_[target.heap_index_].timer_ = &target;
+
+ if (timers_ == &source)
+ timers_ = &target;
+ if (source.prev_)
+ source.prev_->next_ = &target;
+ if (source.next_)
+ source.next_->prev_= &target;
+ target.next_ = source.next_;
+ target.prev_ = source.prev_;
+ source.next_ = 0;
+ source.prev_ = 0;
+ }
+
+private:
+ // Move the item at the given index up the heap to its correct position.
+ void up_heap(std::size_t index)
+ {
+ while (index > 0)
+ {
+ std::size_t parent = (index - 1) / 2;
+ if (!Time_Traits::less_than(heap_[index].time_, heap_[parent].time_))
+ break;
+ swap_heap(index, parent);
+ index = parent;
+ }
+ }
+
+ // Move the item at the given index down the heap to its correct position.
+ void down_heap(std::size_t index)
+ {
+ std::size_t child = index * 2 + 1;
+ while (child < heap_.size())
+ {
+ std::size_t min_child = (child + 1 == heap_.size()
+ || Time_Traits::less_than(
+ heap_[child].time_, heap_[child + 1].time_))
+ ? child : child + 1;
+ if (Time_Traits::less_than(heap_[index].time_, heap_[min_child].time_))
+ break;
+ swap_heap(index, min_child);
+ index = min_child;
+ child = index * 2 + 1;
+ }
+ }
+
+ // Swap two entries in the heap.
+ void swap_heap(std::size_t index1, std::size_t index2)
+ {
+ heap_entry tmp = heap_[index1];
+ heap_[index1] = heap_[index2];
+ heap_[index2] = tmp;
+ heap_[index1].timer_->heap_index_ = index1;
+ heap_[index2].timer_->heap_index_ = index2;
+ }
+
+ // Remove a timer from the heap and list of timers.
+ void remove_timer(per_timer_data& timer)
+ {
+ // Remove the timer from the heap.
+ std::size_t index = timer.heap_index_;
+ if (!heap_.empty() && index < heap_.size())
+ {
+ if (index == heap_.size() - 1)
+ {
+ heap_.pop_back();
+ }
+ else
+ {
+ swap_heap(index, heap_.size() - 1);
+ heap_.pop_back();
+ if (index > 0 && Time_Traits::less_than(
+ heap_[index].time_, heap_[(index - 1) / 2].time_))
+ up_heap(index);
+ else
+ down_heap(index);
+ }
+ }
+
+ // Remove the timer from the linked list of active timers.
+ if (timers_ == &timer)
+ timers_ = timer.next_;
+ if (timer.prev_)
+ timer.prev_->next_ = timer.next_;
+ if (timer.next_)
+ timer.next_->prev_= timer.prev_;
+ timer.next_ = 0;
+ timer.prev_ = 0;
+ }
+
+ // Determine if the specified absolute time is positive infinity.
+ template <typename Time_Type>
+ static bool is_positive_infinity(const Time_Type&)
+ {
+ return false;
+ }
+
+ // Determine if the specified absolute time is positive infinity.
+ template <typename T, typename TimeSystem>
+ static bool is_positive_infinity(
+ const boost::date_time::base_time<T, TimeSystem>& time)
+ {
+ return time.is_pos_infinity();
+ }
+
+ // Helper function to convert a duration into milliseconds.
+ template <typename Duration>
+ long to_msec(const Duration& d, long max_duration) const
+ {
+ if (d.ticks() <= 0)
+ return 0;
+ int64_t msec = d.total_milliseconds();
+ if (msec == 0)
+ return 1;
+ if (msec > max_duration)
+ return max_duration;
+ return static_cast<long>(msec);
+ }
+
+ // Helper function to convert a duration into microseconds.
+ template <typename Duration>
+ long to_usec(const Duration& d, long max_duration) const
+ {
+ if (d.ticks() <= 0)
+ return 0;
+ int64_t usec = d.total_microseconds();
+ if (usec == 0)
+ return 1;
+ if (usec > max_duration)
+ return max_duration;
+ return static_cast<long>(usec);
+ }
+
+ // The head of a linked list of all active timers.
+ per_timer_data* timers_;
+
+ struct heap_entry
+ {
+ // The time when the timer should fire.
+ time_type time_;
+
+ // The associated timer with enqueued operations.
+ per_timer_data* timer_;
+ };
+
+ // The heap of timers, with the earliest timer at the front.
+ std::vector<heap_entry> heap_;
+};
+
+} // namespace detail
+} // namespace asio
+
+#include "asio/detail/pop_options.hpp"
+
+#endif // ASIO_DETAIL_TIMER_QUEUE_HPP
diff --git a/lib/asio/detail/timer_queue_base.hpp b/lib/asio/detail/timer_queue_base.hpp
new file mode 100644
index 0000000..4af995f
--- /dev/null
+++ b/lib/asio/detail/timer_queue_base.hpp
@@ -0,0 +1,68 @@
+//
+// detail/timer_queue_base.hpp
+// ~~~~~~~~~~~~~~~~~~~~~~~~~~~
+//
+// Copyright (c) 2003-2018 Christopher M. Kohlhoff (chris at kohlhoff dot com)
+//
+// 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 ASIO_DETAIL_TIMER_QUEUE_BASE_HPP
+#define ASIO_DETAIL_TIMER_QUEUE_BASE_HPP
+
+#if defined(_MSC_VER) && (_MSC_VER >= 1200)
+# pragma once
+#endif // defined(_MSC_VER) && (_MSC_VER >= 1200)
+
+#include "asio/detail/config.hpp"
+#include "asio/detail/noncopyable.hpp"
+#include "asio/detail/op_queue.hpp"
+#include "asio/detail/operation.hpp"
+
+#include "asio/detail/push_options.hpp"
+
+namespace asio {
+namespace detail {
+
+class timer_queue_base
+ : private noncopyable
+{
+public:
+ // Constructor.
+ timer_queue_base() : next_(0) {}
+
+ // Destructor.
+ virtual ~timer_queue_base() {}
+
+ // Whether there are no timers in the queue.
+ virtual bool empty() const = 0;
+
+ // Get the time to wait until the next timer.
+ virtual long wait_duration_msec(long max_duration) const = 0;
+
+ // Get the time to wait until the next timer.
+ virtual long wait_duration_usec(long max_duration) const = 0;
+
+ // Dequeue all ready timers.
+ virtual void get_ready_timers(op_queue<operation>& ops) = 0;
+
+ // Dequeue all timers.
+ virtual void get_all_timers(op_queue<operation>& ops) = 0;
+
+private:
+ friend class timer_queue_set;
+
+ // Next timer queue in the set.
+ timer_queue_base* next_;
+};
+
+template <typename Time_Traits>
+class timer_queue;
+
+} // namespace detail
+} // namespace asio
+
+#include "asio/detail/pop_options.hpp"
+
+#endif // ASIO_DETAIL_TIMER_QUEUE_BASE_HPP
diff --git a/lib/asio/detail/timer_queue_ptime.hpp b/lib/asio/detail/timer_queue_ptime.hpp
new file mode 100644
index 0000000..84e8338
--- /dev/null
+++ b/lib/asio/detail/timer_queue_ptime.hpp
@@ -0,0 +1,99 @@
+//
+// detail/timer_queue_ptime.hpp
+// ~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+//
+// Copyright (c) 2003-2018 Christopher M. Kohlhoff (chris at kohlhoff dot com)
+//
+// 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 ASIO_DETAIL_TIMER_QUEUE_PTIME_HPP
+#define ASIO_DETAIL_TIMER_QUEUE_PTIME_HPP
+
+#if defined(_MSC_VER) && (_MSC_VER >= 1200)
+# pragma once
+#endif // defined(_MSC_VER) && (_MSC_VER >= 1200)
+
+#include "asio/detail/config.hpp"
+
+#if defined(ASIO_HAS_BOOST_DATE_TIME)
+
+#include "asio/time_traits.hpp"
+#include "asio/detail/timer_queue.hpp"
+
+#include "asio/detail/push_options.hpp"
+
+namespace asio {
+namespace detail {
+
+struct forwarding_posix_time_traits : time_traits<boost::posix_time::ptime> {};
+
+// Template specialisation for the commonly used instantation.
+template <>
+class timer_queue<time_traits<boost::posix_time::ptime> >
+ : public timer_queue_base
+{
+public:
+ // The time type.
+ typedef boost::posix_time::ptime time_type;
+
+ // The duration type.
+ typedef boost::posix_time::time_duration duration_type;
+
+ // Per-timer data.
+ typedef timer_queue<forwarding_posix_time_traits>::per_timer_data
+ per_timer_data;
+
+ // Constructor.
+ ASIO_DECL timer_queue();
+
+ // Destructor.
+ ASIO_DECL virtual ~timer_queue();
+
+ // Add a new timer to the queue. Returns true if this is the timer that is
+ // earliest in the queue, in which case the reactor's event demultiplexing
+ // function call may need to be interrupted and restarted.
+ ASIO_DECL bool enqueue_timer(const time_type& time,
+ per_timer_data& timer, wait_op* op);
+
+ // Whether there are no timers in the queue.
+ ASIO_DECL virtual bool empty() const;
+
+ // Get the time for the timer that is earliest in the queue.
+ ASIO_DECL virtual long wait_duration_msec(long max_duration) const;
+
+ // Get the time for the timer that is earliest in the queue.
+ ASIO_DECL virtual long wait_duration_usec(long max_duration) const;
+
+ // Dequeue all timers not later than the current time.
+ ASIO_DECL virtual void get_ready_timers(op_queue<operation>& ops);
+
+ // Dequeue all timers.
+ ASIO_DECL virtual void get_all_timers(op_queue<operation>& ops);
+
+ // Cancel and dequeue operations for the given timer.
+ ASIO_DECL std::size_t cancel_timer(
+ per_timer_data& timer, op_queue<operation>& ops,
+ std::size_t max_cancelled = (std::numeric_limits<std::size_t>::max)());
+
+ // Move operations from one timer to another, empty timer.
+ ASIO_DECL void move_timer(per_timer_data& target,
+ per_timer_data& source);
+
+private:
+ timer_queue<forwarding_posix_time_traits> impl_;
+};
+
+} // namespace detail
+} // namespace asio
+
+#include "asio/detail/pop_options.hpp"
+
+#if defined(ASIO_HEADER_ONLY)
+# include "asio/detail/impl/timer_queue_ptime.ipp"
+#endif // defined(ASIO_HEADER_ONLY)
+
+#endif // defined(ASIO_HAS_BOOST_DATE_TIME)
+
+#endif // ASIO_DETAIL_TIMER_QUEUE_PTIME_HPP
diff --git a/lib/asio/detail/timer_queue_set.hpp b/lib/asio/detail/timer_queue_set.hpp
new file mode 100644
index 0000000..0ea372a
--- /dev/null
+++ b/lib/asio/detail/timer_queue_set.hpp
@@ -0,0 +1,66 @@
+//
+// detail/timer_queue_set.hpp
+// ~~~~~~~~~~~~~~~~~~~~~~~~~~
+//
+// Copyright (c) 2003-2018 Christopher M. Kohlhoff (chris at kohlhoff dot com)
+//
+// 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 ASIO_DETAIL_TIMER_QUEUE_SET_HPP
+#define ASIO_DETAIL_TIMER_QUEUE_SET_HPP
+
+#if defined(_MSC_VER) && (_MSC_VER >= 1200)
+# pragma once
+#endif // defined(_MSC_VER) && (_MSC_VER >= 1200)
+
+#include "asio/detail/config.hpp"
+#include "asio/detail/timer_queue_base.hpp"
+
+#include "asio/detail/push_options.hpp"
+
+namespace asio {
+namespace detail {
+
+class timer_queue_set
+{
+public:
+ // Constructor.
+ ASIO_DECL timer_queue_set();
+
+ // Add a timer queue to the set.
+ ASIO_DECL void insert(timer_queue_base* q);
+
+ // Remove a timer queue from the set.
+ ASIO_DECL void erase(timer_queue_base* q);
+
+ // Determine whether all queues are empty.
+ ASIO_DECL bool all_empty() const;
+
+ // Get the wait duration in milliseconds.
+ ASIO_DECL long wait_duration_msec(long max_duration) const;
+
+ // Get the wait duration in microseconds.
+ ASIO_DECL long wait_duration_usec(long max_duration) const;
+
+ // Dequeue all ready timers.
+ ASIO_DECL void get_ready_timers(op_queue<operation>& ops);
+
+ // Dequeue all timers.
+ ASIO_DECL void get_all_timers(op_queue<operation>& ops);
+
+private:
+ timer_queue_base* first_;
+};
+
+} // namespace detail
+} // namespace asio
+
+#include "asio/detail/pop_options.hpp"
+
+#if defined(ASIO_HEADER_ONLY)
+# include "asio/detail/impl/timer_queue_set.ipp"
+#endif // defined(ASIO_HEADER_ONLY)
+
+#endif // ASIO_DETAIL_TIMER_QUEUE_SET_HPP
diff --git a/lib/asio/detail/timer_scheduler.hpp b/lib/asio/detail/timer_scheduler.hpp
new file mode 100644
index 0000000..b1f8df4
--- /dev/null
+++ b/lib/asio/detail/timer_scheduler.hpp
@@ -0,0 +1,35 @@
+//
+// detail/timer_scheduler.hpp
+// ~~~~~~~~~~~~~~~~~~~~~~~~~~
+//
+// Copyright (c) 2003-2018 Christopher M. Kohlhoff (chris at kohlhoff dot com)
+//
+// 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 ASIO_DETAIL_TIMER_SCHEDULER_HPP
+#define ASIO_DETAIL_TIMER_SCHEDULER_HPP
+
+#if defined(_MSC_VER) && (_MSC_VER >= 1200)
+# pragma once
+#endif // defined(_MSC_VER) && (_MSC_VER >= 1200)
+
+#include "asio/detail/config.hpp"
+#include "asio/detail/timer_scheduler_fwd.hpp"
+
+#if defined(ASIO_WINDOWS_RUNTIME)
+# include "asio/detail/winrt_timer_scheduler.hpp"
+#elif defined(ASIO_HAS_IOCP)
+# include "asio/detail/win_iocp_io_context.hpp"
+#elif defined(ASIO_HAS_EPOLL)
+# include "asio/detail/epoll_reactor.hpp"
+#elif defined(ASIO_HAS_KQUEUE)
+# include "asio/detail/kqueue_reactor.hpp"
+#elif defined(ASIO_HAS_DEV_POLL)
+# include "asio/detail/dev_poll_reactor.hpp"
+#else
+# include "asio/detail/select_reactor.hpp"
+#endif
+
+#endif // ASIO_DETAIL_TIMER_SCHEDULER_HPP
diff --git a/lib/asio/detail/timer_scheduler_fwd.hpp b/lib/asio/detail/timer_scheduler_fwd.hpp
new file mode 100644
index 0000000..80bae50
--- /dev/null
+++ b/lib/asio/detail/timer_scheduler_fwd.hpp
@@ -0,0 +1,40 @@
+//
+// detail/timer_scheduler_fwd.hpp
+// ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+//
+// Copyright (c) 2003-2018 Christopher M. Kohlhoff (chris at kohlhoff dot com)
+//
+// 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 ASIO_DETAIL_TIMER_SCHEDULER_FWD_HPP
+#define ASIO_DETAIL_TIMER_SCHEDULER_FWD_HPP
+
+#if defined(_MSC_VER) && (_MSC_VER >= 1200)
+# pragma once
+#endif // defined(_MSC_VER) && (_MSC_VER >= 1200)
+
+#include "asio/detail/config.hpp"
+
+namespace asio {
+namespace detail {
+
+#if defined(ASIO_WINDOWS_RUNTIME)
+typedef class winrt_timer_scheduler timer_scheduler;
+#elif defined(ASIO_HAS_IOCP)
+typedef class win_iocp_io_context timer_scheduler;
+#elif defined(ASIO_HAS_EPOLL)
+typedef class epoll_reactor timer_scheduler;
+#elif defined(ASIO_HAS_KQUEUE)
+typedef class kqueue_reactor timer_scheduler;
+#elif defined(ASIO_HAS_DEV_POLL)
+typedef class dev_poll_reactor timer_scheduler;
+#else
+typedef class select_reactor timer_scheduler;
+#endif
+
+} // namespace detail
+} // namespace asio
+
+#endif // ASIO_DETAIL_TIMER_SCHEDULER_FWD_HPP
diff --git a/lib/asio/detail/tss_ptr.hpp b/lib/asio/detail/tss_ptr.hpp
new file mode 100644
index 0000000..e628abe
--- /dev/null
+++ b/lib/asio/detail/tss_ptr.hpp
@@ -0,0 +1,69 @@
+//
+// detail/tss_ptr.hpp
+// ~~~~~~~~~~~~~~~~~~
+//
+// Copyright (c) 2003-2018 Christopher M. Kohlhoff (chris at kohlhoff dot com)
+//
+// 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 ASIO_DETAIL_TSS_PTR_HPP
+#define ASIO_DETAIL_TSS_PTR_HPP
+
+#if defined(_MSC_VER) && (_MSC_VER >= 1200)
+# pragma once
+#endif // defined(_MSC_VER) && (_MSC_VER >= 1200)
+
+#include "asio/detail/config.hpp"
+
+#if !defined(ASIO_HAS_THREADS)
+# include "asio/detail/null_tss_ptr.hpp"
+#elif defined(ASIO_HAS_THREAD_KEYWORD_EXTENSION)
+# include "asio/detail/keyword_tss_ptr.hpp"
+#elif defined(ASIO_WINDOWS)
+# include "asio/detail/win_tss_ptr.hpp"
+#elif defined(ASIO_HAS_PTHREADS)
+# include "asio/detail/posix_tss_ptr.hpp"
+#else
+# error Only Windows and POSIX are supported!
+#endif
+
+#include "asio/detail/push_options.hpp"
+
+namespace asio {
+namespace detail {
+
+template <typename T>
+class tss_ptr
+#if !defined(ASIO_HAS_THREADS)
+ : public null_tss_ptr<T>
+#elif defined(ASIO_HAS_THREAD_KEYWORD_EXTENSION)
+ : public keyword_tss_ptr<T>
+#elif defined(ASIO_WINDOWS)
+ : public win_tss_ptr<T>
+#elif defined(ASIO_HAS_PTHREADS)
+ : public posix_tss_ptr<T>
+#endif
+{
+public:
+ void operator=(T* value)
+ {
+#if !defined(ASIO_HAS_THREADS)
+ null_tss_ptr<T>::operator=(value);
+#elif defined(ASIO_HAS_THREAD_KEYWORD_EXTENSION)
+ keyword_tss_ptr<T>::operator=(value);
+#elif defined(ASIO_WINDOWS)
+ win_tss_ptr<T>::operator=(value);
+#elif defined(ASIO_HAS_PTHREADS)
+ posix_tss_ptr<T>::operator=(value);
+#endif
+ }
+};
+
+} // namespace detail
+} // namespace asio
+
+#include "asio/detail/pop_options.hpp"
+
+#endif // ASIO_DETAIL_TSS_PTR_HPP
diff --git a/lib/asio/detail/type_traits.hpp b/lib/asio/detail/type_traits.hpp
new file mode 100644
index 0000000..edf0928
--- /dev/null
+++ b/lib/asio/detail/type_traits.hpp
@@ -0,0 +1,86 @@
+//
+// detail/type_traits.hpp
+// ~~~~~~~~~~~~~~~~~~~~~~
+//
+// Copyright (c) 2003-2018 Christopher M. Kohlhoff (chris at kohlhoff dot com)
+//
+// 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 ASIO_DETAIL_TYPE_TRAITS_HPP
+#define ASIO_DETAIL_TYPE_TRAITS_HPP
+
+#if defined(_MSC_VER) && (_MSC_VER >= 1200)
+# pragma once
+#endif // defined(_MSC_VER) && (_MSC_VER >= 1200)
+
+#include "asio/detail/config.hpp"
+
+#if defined(ASIO_HAS_STD_TYPE_TRAITS)
+# include <type_traits>
+#else // defined(ASIO_HAS_TYPE_TRAITS)
+# include <boost/type_traits/add_const.hpp>
+# include <boost/type_traits/conditional.hpp>
+# include <boost/type_traits/decay.hpp>
+# include <boost/type_traits/integral_constant.hpp>
+# include <boost/type_traits/is_base_of.hpp>
+# include <boost/type_traits/is_class.hpp>
+# include <boost/type_traits/is_const.hpp>
+# include <boost/type_traits/is_convertible.hpp>
+# include <boost/type_traits/is_function.hpp>
+# include <boost/type_traits/is_same.hpp>
+# include <boost/type_traits/remove_pointer.hpp>
+# include <boost/type_traits/remove_reference.hpp>
+# include <boost/utility/enable_if.hpp>
+# include <boost/utility/result_of.hpp>
+#endif // defined(ASIO_HAS_TYPE_TRAITS)
+
+namespace asio {
+
+#if defined(ASIO_HAS_STD_TYPE_TRAITS)
+using std::add_const;
+using std::conditional;
+using std::decay;
+using std::enable_if;
+using std::false_type;
+using std::integral_constant;
+using std::is_base_of;
+using std::is_class;
+using std::is_const;
+using std::is_convertible;
+using std::is_function;
+using std::is_same;
+using std::remove_pointer;
+using std::remove_reference;
+#if defined(ASIO_HAS_STD_INVOKE_RESULT)
+template <typename> struct result_of;
+template <typename F, typename... Args>
+struct result_of<F(Args...)> : std::invoke_result<F, Args...> {};
+#else // defined(ASIO_HAS_STD_INVOKE_RESULT)
+using std::result_of;
+#endif // defined(ASIO_HAS_STD_INVOKE_RESULT)
+using std::true_type;
+#else // defined(ASIO_HAS_STD_TYPE_TRAITS)
+using boost::add_const;
+template <bool Condition, typename Type = void>
+struct enable_if : boost::enable_if_c<Condition, Type> {};
+using boost::conditional;
+using boost::decay;
+using boost::false_type;
+using boost::integral_constant;
+using boost::is_base_of;
+using boost::is_class;
+using boost::is_const;
+using boost::is_convertible;
+using boost::is_function;
+using boost::is_same;
+using boost::remove_pointer;
+using boost::remove_reference;
+using boost::result_of;
+using boost::true_type;
+#endif // defined(ASIO_HAS_STD_TYPE_TRAITS)
+
+} // namespace asio
+
+#endif // ASIO_DETAIL_TYPE_TRAITS_HPP
diff --git a/lib/asio/detail/variadic_templates.hpp b/lib/asio/detail/variadic_templates.hpp
new file mode 100644
index 0000000..d54eb4e
--- /dev/null
+++ b/lib/asio/detail/variadic_templates.hpp
@@ -0,0 +1,119 @@
+//
+// detail/variadic_templates.hpp
+// ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+//
+// Copyright (c) 2003-2018 Christopher M. Kohlhoff (chris at kohlhoff dot com)
+//
+// 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 ASIO_DETAIL_VARIADIC_TEMPLATES_HPP
+#define ASIO_DETAIL_VARIADIC_TEMPLATES_HPP
+
+#if defined(_MSC_VER) && (_MSC_VER >= 1200)
+# pragma once
+#endif // defined(_MSC_VER) && (_MSC_VER >= 1200)
+
+#include "asio/detail/config.hpp"
+
+#if !defined(ASIO_HAS_VARIADIC_TEMPLATES)
+
+# define ASIO_VARIADIC_TPARAMS(n) ASIO_VARIADIC_TPARAMS_##n
+
+# define ASIO_VARIADIC_TPARAMS_1 \
+ typename T1
+# define ASIO_VARIADIC_TPARAMS_2 \
+ typename T1, typename T2
+# define ASIO_VARIADIC_TPARAMS_3 \
+ typename T1, typename T2, typename T3
+# define ASIO_VARIADIC_TPARAMS_4 \
+ typename T1, typename T2, typename T3, typename T4
+# define ASIO_VARIADIC_TPARAMS_5 \
+ typename T1, typename T2, typename T3, typename T4, typename T5
+
+# define ASIO_VARIADIC_TARGS(n) ASIO_VARIADIC_TARGS_##n
+
+# define ASIO_VARIADIC_TARGS_1 T1
+# define ASIO_VARIADIC_TARGS_2 T1, T2
+# define ASIO_VARIADIC_TARGS_3 T1, T2, T3
+# define ASIO_VARIADIC_TARGS_4 T1, T2, T3, T4
+# define ASIO_VARIADIC_TARGS_5 T1, T2, T3, T4, T5
+
+# define ASIO_VARIADIC_BYVAL_PARAMS(n) \
+ ASIO_VARIADIC_BYVAL_PARAMS_##n
+
+# define ASIO_VARIADIC_BYVAL_PARAMS_1 T1 x1
+# define ASIO_VARIADIC_BYVAL_PARAMS_2 T1 x1, T2 x2
+# define ASIO_VARIADIC_BYVAL_PARAMS_3 T1 x1, T2 x2, T3 x3
+# define ASIO_VARIADIC_BYVAL_PARAMS_4 T1 x1, T2 x2, T3 x3, T4 x4
+# define ASIO_VARIADIC_BYVAL_PARAMS_5 T1 x1, T2 x2, T3 x3, T4 x4, T5 x5
+
+# define ASIO_VARIADIC_BYVAL_ARGS(n) \
+ ASIO_VARIADIC_BYVAL_ARGS_##n
+
+# define ASIO_VARIADIC_BYVAL_ARGS_1 x1
+# define ASIO_VARIADIC_BYVAL_ARGS_2 x1, x2
+# define ASIO_VARIADIC_BYVAL_ARGS_3 x1, x2, x3
+# define ASIO_VARIADIC_BYVAL_ARGS_4 x1, x2, x3, x4
+# define ASIO_VARIADIC_BYVAL_ARGS_5 x1, x2, x3, x4, x5
+
+# define ASIO_VARIADIC_MOVE_PARAMS(n) \
+ ASIO_VARIADIC_MOVE_PARAMS_##n
+
+# define ASIO_VARIADIC_MOVE_PARAMS_1 \
+ ASIO_MOVE_ARG(T1) x1
+# define ASIO_VARIADIC_MOVE_PARAMS_2 \
+ ASIO_MOVE_ARG(T1) x1, ASIO_MOVE_ARG(T2) x2
+# define ASIO_VARIADIC_MOVE_PARAMS_3 \
+ ASIO_MOVE_ARG(T1) x1, ASIO_MOVE_ARG(T2) x2, \
+ ASIO_MOVE_ARG(T3) x3
+# define ASIO_VARIADIC_MOVE_PARAMS_4 \
+ ASIO_MOVE_ARG(T1) x1, ASIO_MOVE_ARG(T2) x2, \
+ ASIO_MOVE_ARG(T3) x3, ASIO_MOVE_ARG(T4) x4
+# define ASIO_VARIADIC_MOVE_PARAMS_5 \
+ ASIO_MOVE_ARG(T1) x1, ASIO_MOVE_ARG(T2) x2, \
+ ASIO_MOVE_ARG(T3) x3, ASIO_MOVE_ARG(T4) x4, \
+ ASIO_MOVE_ARG(T5) x5
+
+# define ASIO_VARIADIC_MOVE_ARGS(n) \
+ ASIO_VARIADIC_MOVE_ARGS_##n
+
+# define ASIO_VARIADIC_MOVE_ARGS_1 \
+ ASIO_MOVE_CAST(T1)(x1)
+# define ASIO_VARIADIC_MOVE_ARGS_2 \
+ ASIO_MOVE_CAST(T1)(x1), ASIO_MOVE_CAST(T2)(x2)
+# define ASIO_VARIADIC_MOVE_ARGS_3 \
+ ASIO_MOVE_CAST(T1)(x1), ASIO_MOVE_CAST(T2)(x2), \
+ ASIO_MOVE_CAST(T3)(x3)
+# define ASIO_VARIADIC_MOVE_ARGS_4 \
+ ASIO_MOVE_CAST(T1)(x1), ASIO_MOVE_CAST(T2)(x2), \
+ ASIO_MOVE_CAST(T3)(x3), ASIO_MOVE_CAST(T4)(x4)
+# define ASIO_VARIADIC_MOVE_ARGS_5 \
+ ASIO_MOVE_CAST(T1)(x1), ASIO_MOVE_CAST(T2)(x2), \
+ ASIO_MOVE_CAST(T3)(x3), ASIO_MOVE_CAST(T4)(x4), \
+ ASIO_MOVE_CAST(T5)(x5)
+
+# define ASIO_VARIADIC_DECAY(n) \
+ ASIO_VARIADIC_DECAY_##n
+
+# define ASIO_VARIADIC_DECAY_1 \
+ typename decay<T1>::type
+# define ASIO_VARIADIC_DECAY_2 \
+ typename decay<T1>::type, typename decay<T2>::type
+# define ASIO_VARIADIC_DECAY_3 \
+ typename decay<T1>::type, typename decay<T2>::type, \
+ typename decay<T3>::type
+# define ASIO_VARIADIC_DECAY_4 \
+ typename decay<T1>::type, typename decay<T2>::type, \
+ typename decay<T3>::type, typename decay<T4>::type
+# define ASIO_VARIADIC_DECAY_5 \
+ typename decay<T1>::type, typename decay<T2>::type, \
+ typename decay<T3>::type, typename decay<T4>::type, \
+ typename decay<T5>::type
+
+# define ASIO_VARIADIC_GENERATE(m) m(1) m(2) m(3) m(4) m(5)
+
+#endif // !defined(ASIO_HAS_VARIADIC_TEMPLATES)
+
+#endif // ASIO_DETAIL_VARIADIC_TEMPLATES_HPP
diff --git a/lib/asio/detail/wait_handler.hpp b/lib/asio/detail/wait_handler.hpp
new file mode 100644
index 0000000..bd3dc24
--- /dev/null
+++ b/lib/asio/detail/wait_handler.hpp
@@ -0,0 +1,85 @@
+//
+// detail/wait_handler.hpp
+// ~~~~~~~~~~~~~~~~~~~~~~~
+//
+// Copyright (c) 2003-2018 Christopher M. Kohlhoff (chris at kohlhoff dot com)
+//
+// 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 ASIO_DETAIL_WAIT_HANDLER_HPP
+#define ASIO_DETAIL_WAIT_HANDLER_HPP
+
+#if defined(_MSC_VER) && (_MSC_VER >= 1200)
+# pragma once
+#endif // defined(_MSC_VER) && (_MSC_VER >= 1200)
+
+#include "asio/detail/config.hpp"
+#include "asio/detail/fenced_block.hpp"
+#include "asio/detail/handler_alloc_helpers.hpp"
+#include "asio/detail/handler_invoke_helpers.hpp"
+#include "asio/detail/memory.hpp"
+#include "asio/detail/wait_op.hpp"
+#include "asio/io_context.hpp"
+
+#include "asio/detail/push_options.hpp"
+
+namespace asio {
+namespace detail {
+
+template <typename Handler>
+class wait_handler : public wait_op
+{
+public:
+ ASIO_DEFINE_HANDLER_PTR(wait_handler);
+
+ wait_handler(Handler& h)
+ : wait_op(&wait_handler::do_complete),
+ handler_(ASIO_MOVE_CAST(Handler)(h))
+ {
+ handler_work<Handler>::start(handler_);
+ }
+
+ static void do_complete(void* owner, operation* base,
+ const asio::error_code& /*ec*/,
+ std::size_t /*bytes_transferred*/)
+ {
+ // Take ownership of the handler object.
+ wait_handler* h(static_cast<wait_handler*>(base));
+ ptr p = { asio::detail::addressof(h->handler_), h, h };
+ handler_work<Handler> w(h->handler_);
+
+ ASIO_HANDLER_COMPLETION((*h));
+
+ // 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::binder1<Handler, asio::error_code>
+ handler(h->handler_, h->ec_);
+ p.h = asio::detail::addressof(handler.handler_);
+ p.reset();
+
+ // Make the upcall if required.
+ if (owner)
+ {
+ fenced_block b(fenced_block::half);
+ ASIO_HANDLER_INVOCATION_BEGIN((handler.arg1_));
+ w.complete(handler, handler.handler_);
+ ASIO_HANDLER_INVOCATION_END;
+ }
+ }
+
+private:
+ Handler handler_;
+};
+
+} // namespace detail
+} // namespace asio
+
+#include "asio/detail/pop_options.hpp"
+
+#endif // ASIO_DETAIL_WAIT_HANDLER_HPP
diff --git a/lib/asio/detail/wait_op.hpp b/lib/asio/detail/wait_op.hpp
new file mode 100644
index 0000000..1a3017b
--- /dev/null
+++ b/lib/asio/detail/wait_op.hpp
@@ -0,0 +1,45 @@
+//
+// detail/wait_op.hpp
+// ~~~~~~~~~~~~~~~~~~
+//
+// Copyright (c) 2003-2018 Christopher M. Kohlhoff (chris at kohlhoff dot com)
+//
+// 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 ASIO_DETAIL_WAIT_OP_HPP
+#define ASIO_DETAIL_WAIT_OP_HPP
+
+#if defined(_MSC_VER) && (_MSC_VER >= 1200)
+# pragma once
+#endif // defined(_MSC_VER) && (_MSC_VER >= 1200)
+
+#include "asio/detail/config.hpp"
+#include "asio/detail/operation.hpp"
+
+#include "asio/detail/push_options.hpp"
+
+namespace asio {
+namespace detail {
+
+class wait_op
+ : public operation
+{
+public:
+ // The error code to be passed to the completion handler.
+ asio::error_code ec_;
+
+protected:
+ wait_op(func_type func)
+ : operation(func)
+ {
+ }
+};
+
+} // namespace detail
+} // namespace asio
+
+#include "asio/detail/pop_options.hpp"
+
+#endif // ASIO_DETAIL_WAIT_OP_HPP
diff --git a/lib/asio/detail/win_event.hpp b/lib/asio/detail/win_event.hpp
new file mode 100644
index 0000000..859cdee
--- /dev/null
+++ b/lib/asio/detail/win_event.hpp
@@ -0,0 +1,151 @@
+//
+// detail/win_event.hpp
+// ~~~~~~~~~~~~~~~~~~~~
+//
+// Copyright (c) 2003-2018 Christopher M. Kohlhoff (chris at kohlhoff dot com)
+//
+// 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 ASIO_DETAIL_WIN_EVENT_HPP
+#define ASIO_DETAIL_WIN_EVENT_HPP
+
+#if defined(_MSC_VER) && (_MSC_VER >= 1200)
+# pragma once
+#endif // defined(_MSC_VER) && (_MSC_VER >= 1200)
+
+#include "asio/detail/config.hpp"
+
+#if defined(ASIO_WINDOWS)
+
+#include "asio/detail/assert.hpp"
+#include "asio/detail/noncopyable.hpp"
+#include "asio/detail/socket_types.hpp"
+
+#include "asio/detail/push_options.hpp"
+
+namespace asio {
+namespace detail {
+
+class win_event
+ : private noncopyable
+{
+public:
+ // Constructor.
+ ASIO_DECL win_event();
+
+ // Destructor.
+ ASIO_DECL ~win_event();
+
+ // Signal the event. (Retained for backward compatibility.)
+ template <typename Lock>
+ void signal(Lock& lock)
+ {
+ this->signal_all(lock);
+ }
+
+ // Signal all waiters.
+ template <typename Lock>
+ void signal_all(Lock& lock)
+ {
+ ASIO_ASSERT(lock.locked());
+ (void)lock;
+ state_ |= 1;
+ ::SetEvent(events_[0]);
+ }
+
+ // Unlock the mutex and signal one waiter.
+ template <typename Lock>
+ void unlock_and_signal_one(Lock& lock)
+ {
+ ASIO_ASSERT(lock.locked());
+ state_ |= 1;
+ bool have_waiters = (state_ > 1);
+ lock.unlock();
+ if (have_waiters)
+ ::SetEvent(events_[1]);
+ }
+
+ // If there's a waiter, unlock the mutex and signal it.
+ template <typename Lock>
+ bool maybe_unlock_and_signal_one(Lock& lock)
+ {
+ ASIO_ASSERT(lock.locked());
+ state_ |= 1;
+ if (state_ > 1)
+ {
+ lock.unlock();
+ ::SetEvent(events_[1]);
+ return true;
+ }
+ return false;
+ }
+
+ // Reset the event.
+ template <typename Lock>
+ void clear(Lock& lock)
+ {
+ ASIO_ASSERT(lock.locked());
+ (void)lock;
+ ::ResetEvent(events_[0]);
+ state_ &= ~std::size_t(1);
+ }
+
+ // Wait for the event to become signalled.
+ template <typename Lock>
+ void wait(Lock& lock)
+ {
+ ASIO_ASSERT(lock.locked());
+ while ((state_ & 1) == 0)
+ {
+ state_ += 2;
+ lock.unlock();
+#if defined(ASIO_WINDOWS_APP)
+ ::WaitForMultipleObjectsEx(2, events_, false, INFINITE, false);
+#else // defined(ASIO_WINDOWS_APP)
+ ::WaitForMultipleObjects(2, events_, false, INFINITE);
+#endif // defined(ASIO_WINDOWS_APP)
+ lock.lock();
+ state_ -= 2;
+ }
+ }
+
+ // Timed wait for the event to become signalled.
+ template <typename Lock>
+ bool wait_for_usec(Lock& lock, long usec)
+ {
+ ASIO_ASSERT(lock.locked());
+ if ((state_ & 1) == 0)
+ {
+ state_ += 2;
+ lock.unlock();
+ DWORD msec = usec > 0 ? (usec < 1000 ? 1 : usec / 1000) : 0;
+#if defined(ASIO_WINDOWS_APP)
+ ::WaitForMultipleObjectsEx(2, events_, false, msec, false);
+#else // defined(ASIO_WINDOWS_APP)
+ ::WaitForMultipleObjects(2, events_, false, msec);
+#endif // defined(ASIO_WINDOWS_APP)
+ lock.lock();
+ state_ -= 2;
+ }
+ return (state_ & 1) != 0;
+ }
+
+private:
+ HANDLE events_[2];
+ std::size_t state_;
+};
+
+} // namespace detail
+} // namespace asio
+
+#include "asio/detail/pop_options.hpp"
+
+#if defined(ASIO_HEADER_ONLY)
+# include "asio/detail/impl/win_event.ipp"
+#endif // defined(ASIO_HEADER_ONLY)
+
+#endif // defined(ASIO_WINDOWS)
+
+#endif // ASIO_DETAIL_WIN_EVENT_HPP
diff --git a/lib/asio/detail/win_fd_set_adapter.hpp b/lib/asio/detail/win_fd_set_adapter.hpp
new file mode 100644
index 0000000..8d5e700
--- /dev/null
+++ b/lib/asio/detail/win_fd_set_adapter.hpp
@@ -0,0 +1,149 @@
+//
+// detail/win_fd_set_adapter.hpp
+// ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+//
+// Copyright (c) 2003-2018 Christopher M. Kohlhoff (chris at kohlhoff dot com)
+//
+// 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 ASIO_DETAIL_WIN_FD_SET_ADAPTER_HPP
+#define ASIO_DETAIL_WIN_FD_SET_ADAPTER_HPP
+
+#if defined(_MSC_VER) && (_MSC_VER >= 1200)
+# pragma once
+#endif // defined(_MSC_VER) && (_MSC_VER >= 1200)
+
+#include "asio/detail/config.hpp"
+
+#if defined(ASIO_WINDOWS) || defined(__CYGWIN__)
+
+#include "asio/detail/noncopyable.hpp"
+#include "asio/detail/reactor_op_queue.hpp"
+#include "asio/detail/socket_types.hpp"
+
+#include "asio/detail/push_options.hpp"
+
+namespace asio {
+namespace detail {
+
+// Adapts the FD_SET type to meet the Descriptor_Set concept's requirements.
+class win_fd_set_adapter : noncopyable
+{
+public:
+ enum { default_fd_set_size = 1024 };
+
+ win_fd_set_adapter()
+ : capacity_(default_fd_set_size),
+ max_descriptor_(invalid_socket)
+ {
+ fd_set_ = static_cast<win_fd_set*>(::operator new(
+ sizeof(win_fd_set) - sizeof(SOCKET)
+ + sizeof(SOCKET) * (capacity_)));
+ fd_set_->fd_count = 0;
+ }
+
+ ~win_fd_set_adapter()
+ {
+ ::operator delete(fd_set_);
+ }
+
+ void reset()
+ {
+ fd_set_->fd_count = 0;
+ max_descriptor_ = invalid_socket;
+ }
+
+ bool set(socket_type descriptor)
+ {
+ for (u_int i = 0; i < fd_set_->fd_count; ++i)
+ if (fd_set_->fd_array[i] == descriptor)
+ return true;
+
+ reserve(fd_set_->fd_count + 1);
+ fd_set_->fd_array[fd_set_->fd_count++] = descriptor;
+ return true;
+ }
+
+ void set(reactor_op_queue<socket_type>& operations, op_queue<operation>&)
+ {
+ reactor_op_queue<socket_type>::iterator i = operations.begin();
+ while (i != operations.end())
+ {
+ reactor_op_queue<socket_type>::iterator op_iter = i++;
+ reserve(fd_set_->fd_count + 1);
+ fd_set_->fd_array[fd_set_->fd_count++] = op_iter->first;
+ }
+ }
+
+ bool is_set(socket_type descriptor) const
+ {
+ return !!__WSAFDIsSet(descriptor,
+ const_cast<fd_set*>(reinterpret_cast<const fd_set*>(fd_set_)));
+ }
+
+ operator fd_set*()
+ {
+ return reinterpret_cast<fd_set*>(fd_set_);
+ }
+
+ socket_type max_descriptor() const
+ {
+ return max_descriptor_;
+ }
+
+ void perform(reactor_op_queue<socket_type>& operations,
+ op_queue<operation>& ops) const
+ {
+ for (u_int i = 0; i < fd_set_->fd_count; ++i)
+ operations.perform_operations(fd_set_->fd_array[i], ops);
+ }
+
+private:
+ // This structure is defined to be compatible with the Windows API fd_set
+ // structure, but without being dependent on the value of FD_SETSIZE. We use
+ // the "struct hack" to allow the number of descriptors to be varied at
+ // runtime.
+ struct win_fd_set
+ {
+ u_int fd_count;
+ SOCKET fd_array[1];
+ };
+
+ // Increase the fd_set_ capacity to at least the specified number of elements.
+ void reserve(u_int n)
+ {
+ if (n <= capacity_)
+ return;
+
+ u_int new_capacity = capacity_ + capacity_ / 2;
+ if (new_capacity < n)
+ new_capacity = n;
+
+ win_fd_set* new_fd_set = static_cast<win_fd_set*>(::operator new(
+ sizeof(win_fd_set) - sizeof(SOCKET)
+ + sizeof(SOCKET) * (new_capacity)));
+
+ new_fd_set->fd_count = fd_set_->fd_count;
+ for (u_int i = 0; i < fd_set_->fd_count; ++i)
+ new_fd_set->fd_array[i] = fd_set_->fd_array[i];
+
+ ::operator delete(fd_set_);
+ fd_set_ = new_fd_set;
+ capacity_ = new_capacity;
+ }
+
+ win_fd_set* fd_set_;
+ u_int capacity_;
+ socket_type max_descriptor_;
+};
+
+} // namespace detail
+} // namespace asio
+
+#include "asio/detail/pop_options.hpp"
+
+#endif // defined(ASIO_WINDOWS) || defined(__CYGWIN__)
+
+#endif // ASIO_DETAIL_WIN_FD_SET_ADAPTER_HPP
diff --git a/lib/asio/detail/win_fenced_block.hpp b/lib/asio/detail/win_fenced_block.hpp
new file mode 100644
index 0000000..1ce6e13
--- /dev/null
+++ b/lib/asio/detail/win_fenced_block.hpp
@@ -0,0 +1,90 @@
+//
+// detail/win_fenced_block.hpp
+// ~~~~~~~~~~~~~~~~~~~~~~~~~~~
+//
+// Copyright (c) 2003-2018 Christopher M. Kohlhoff (chris at kohlhoff dot com)
+//
+// 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 ASIO_DETAIL_WIN_FENCED_BLOCK_HPP
+#define ASIO_DETAIL_WIN_FENCED_BLOCK_HPP
+
+#if defined(_MSC_VER) && (_MSC_VER >= 1200)
+# pragma once
+#endif // defined(_MSC_VER) && (_MSC_VER >= 1200)
+
+#include "asio/detail/config.hpp"
+
+#if defined(ASIO_WINDOWS) && !defined(UNDER_CE)
+
+#include "asio/detail/socket_types.hpp"
+#include "asio/detail/noncopyable.hpp"
+
+#include "asio/detail/push_options.hpp"
+
+namespace asio {
+namespace detail {
+
+class win_fenced_block
+ : private noncopyable
+{
+public:
+ enum half_t { half };
+ enum full_t { full };
+
+ // Constructor for a half fenced block.
+ explicit win_fenced_block(half_t)
+ {
+ }
+
+ // Constructor for a full fenced block.
+ explicit win_fenced_block(full_t)
+ {
+#if defined(__BORLANDC__)
+ LONG barrier = 0;
+ ::InterlockedExchange(&barrier, 1);
+#elif defined(ASIO_MSVC) \
+ && ((ASIO_MSVC < 1400) || !defined(MemoryBarrier))
+# if defined(_M_IX86)
+# pragma warning(push)
+# pragma warning(disable:4793)
+ LONG barrier;
+ __asm { xchg barrier, eax }
+# pragma warning(pop)
+# endif // defined(_M_IX86)
+#else
+ MemoryBarrier();
+#endif
+ }
+
+ // Destructor.
+ ~win_fenced_block()
+ {
+#if defined(__BORLANDC__)
+ LONG barrier = 0;
+ ::InterlockedExchange(&barrier, 1);
+#elif defined(ASIO_MSVC) \
+ && ((ASIO_MSVC < 1400) || !defined(MemoryBarrier))
+# if defined(_M_IX86)
+# pragma warning(push)
+# pragma warning(disable:4793)
+ LONG barrier;
+ __asm { xchg barrier, eax }
+# pragma warning(pop)
+# endif // defined(_M_IX86)
+#else
+ MemoryBarrier();
+#endif
+ }
+};
+
+} // namespace detail
+} // namespace asio
+
+#include "asio/detail/pop_options.hpp"
+
+#endif // defined(ASIO_WINDOWS) && !defined(UNDER_CE)
+
+#endif // ASIO_DETAIL_WIN_FENCED_BLOCK_HPP
diff --git a/lib/asio/detail/win_global.hpp b/lib/asio/detail/win_global.hpp
new file mode 100644
index 0000000..3b15a32
--- /dev/null
+++ b/lib/asio/detail/win_global.hpp
@@ -0,0 +1,73 @@
+//
+// detail/win_global.hpp
+// ~~~~~~~~~~~~~~~~~~~~~
+//
+// Copyright (c) 2003-2018 Christopher M. Kohlhoff (chris at kohlhoff dot com)
+//
+// 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 ASIO_DETAIL_WIN_GLOBAL_HPP
+#define ASIO_DETAIL_WIN_GLOBAL_HPP
+
+#if defined(_MSC_VER) && (_MSC_VER >= 1200)
+# pragma once
+#endif // defined(_MSC_VER) && (_MSC_VER >= 1200)
+
+#include "asio/detail/config.hpp"
+#include "asio/detail/static_mutex.hpp"
+#include "asio/detail/tss_ptr.hpp"
+
+#include "asio/detail/push_options.hpp"
+
+namespace asio {
+namespace detail {
+
+template <typename T>
+struct win_global_impl
+{
+ // Destructor automatically cleans up the global.
+ ~win_global_impl()
+ {
+ delete ptr_;
+ }
+
+ static win_global_impl instance_;
+ static static_mutex mutex_;
+ static T* ptr_;
+ static tss_ptr<T> tss_ptr_;
+};
+
+template <typename T>
+win_global_impl<T> win_global_impl<T>::instance_ = { 0 };
+
+template <typename T>
+static_mutex win_global_impl<T>::mutex_ = ASIO_STATIC_MUTEX_INIT;
+
+template <typename T>
+T* win_global_impl<T>::ptr_ = 0;
+
+template <typename T>
+tss_ptr<T> win_global_impl<T>::tss_ptr_;
+
+template <typename T>
+T& win_global()
+{
+ if (static_cast<T*>(win_global_impl<T>::tss_ptr_) == 0)
+ {
+ win_global_impl<T>::mutex_.init();
+ static_mutex::scoped_lock lock(win_global_impl<T>::mutex_);
+ win_global_impl<T>::ptr_ = new T;
+ win_global_impl<T>::tss_ptr_ = win_global_impl<T>::ptr_;
+ }
+
+ return *win_global_impl<T>::tss_ptr_;
+}
+
+} // namespace detail
+} // namespace asio
+
+#include "asio/detail/pop_options.hpp"
+
+#endif // ASIO_DETAIL_WIN_GLOBAL_HPP
diff --git a/lib/asio/detail/win_iocp_handle_read_op.hpp b/lib/asio/detail/win_iocp_handle_read_op.hpp
new file mode 100644
index 0000000..88e3f6c
--- /dev/null
+++ b/lib/asio/detail/win_iocp_handle_read_op.hpp
@@ -0,0 +1,111 @@
+//
+// detail/win_iocp_handle_read_op.hpp
+// ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+//
+// Copyright (c) 2003-2018 Christopher M. Kohlhoff (chris at kohlhoff dot com)
+// Copyright (c) 2008 Rep Invariant Systems, Inc. (info@repinvariant.com)
+//
+// 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 ASIO_DETAIL_WIN_IOCP_HANDLE_READ_OP_HPP
+#define ASIO_DETAIL_WIN_IOCP_HANDLE_READ_OP_HPP
+
+#if defined(_MSC_VER) && (_MSC_VER >= 1200)
+# pragma once
+#endif // defined(_MSC_VER) && (_MSC_VER >= 1200)
+
+#include "asio/detail/config.hpp"
+
+#if defined(ASIO_HAS_IOCP)
+
+#include "asio/error.hpp"
+#include "asio/detail/bind_handler.hpp"
+#include "asio/detail/buffer_sequence_adapter.hpp"
+#include "asio/detail/fenced_block.hpp"
+#include "asio/detail/handler_alloc_helpers.hpp"
+#include "asio/detail/handler_invoke_helpers.hpp"
+#include "asio/detail/memory.hpp"
+#include "asio/detail/operation.hpp"
+
+#include "asio/detail/push_options.hpp"
+
+namespace asio {
+namespace detail {
+
+template <typename MutableBufferSequence, typename Handler>
+class win_iocp_handle_read_op : public operation
+{
+public:
+ ASIO_DEFINE_HANDLER_PTR(win_iocp_handle_read_op);
+
+ win_iocp_handle_read_op(
+ const MutableBufferSequence& buffers, Handler& handler)
+ : operation(&win_iocp_handle_read_op::do_complete),
+ buffers_(buffers),
+ handler_(ASIO_MOVE_CAST(Handler)(handler))
+ {
+ handler_work<Handler>::start(handler_);
+ }
+
+ static void do_complete(void* owner, operation* base,
+ const asio::error_code& result_ec,
+ std::size_t bytes_transferred)
+ {
+ asio::error_code ec(result_ec);
+
+ // Take ownership of the operation object.
+ win_iocp_handle_read_op* o(static_cast<win_iocp_handle_read_op*>(base));
+ ptr p = { asio::detail::addressof(o->handler_), o, o };
+ handler_work<Handler> w(o->handler_);
+
+ ASIO_HANDLER_COMPLETION((*o));
+
+#if defined(ASIO_ENABLE_BUFFER_DEBUGGING)
+ if (owner)
+ {
+ // Check whether buffers are still valid.
+ buffer_sequence_adapter<asio::mutable_buffer,
+ MutableBufferSequence>::validate(o->buffers_);
+ }
+#endif // defined(ASIO_ENABLE_BUFFER_DEBUGGING)
+
+ // Map non-portable errors to their portable counterparts.
+ if (ec.value() == ERROR_HANDLE_EOF)
+ ec = asio::error::eof;
+
+ // 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::binder2<Handler, asio::error_code, std::size_t>
+ handler(o->handler_, ec, bytes_transferred);
+ p.h = asio::detail::addressof(handler.handler_);
+ p.reset();
+
+ // Make the upcall if required.
+ if (owner)
+ {
+ fenced_block b(fenced_block::half);
+ ASIO_HANDLER_INVOCATION_BEGIN((handler.arg1_, handler.arg2_));
+ w.complete(handler, handler.handler_);
+ ASIO_HANDLER_INVOCATION_END;
+ }
+ }
+
+private:
+ MutableBufferSequence buffers_;
+ Handler handler_;
+};
+
+} // namespace detail
+} // namespace asio
+
+#include "asio/detail/pop_options.hpp"
+
+#endif // defined(ASIO_HAS_IOCP)
+
+#endif // ASIO_DETAIL_WIN_IOCP_HANDLE_READ_OP_HPP
diff --git a/lib/asio/detail/win_iocp_handle_service.hpp b/lib/asio/detail/win_iocp_handle_service.hpp
new file mode 100644
index 0000000..849fe8f
--- /dev/null
+++ b/lib/asio/detail/win_iocp_handle_service.hpp
@@ -0,0 +1,323 @@
+//
+// detail/win_iocp_handle_service.hpp
+// ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+//
+// Copyright (c) 2003-2018 Christopher M. Kohlhoff (chris at kohlhoff dot com)
+// Copyright (c) 2008 Rep Invariant Systems, Inc. (info@repinvariant.com)
+//
+// 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 ASIO_DETAIL_WIN_IOCP_HANDLE_SERVICE_HPP
+#define ASIO_DETAIL_WIN_IOCP_HANDLE_SERVICE_HPP
+
+#if defined(_MSC_VER) && (_MSC_VER >= 1200)
+# pragma once
+#endif // defined(_MSC_VER) && (_MSC_VER >= 1200)
+
+#include "asio/detail/config.hpp"
+
+#if defined(ASIO_HAS_IOCP)
+
+#include "asio/error.hpp"
+#include "asio/io_context.hpp"
+#include "asio/detail/buffer_sequence_adapter.hpp"
+#include "asio/detail/cstdint.hpp"
+#include "asio/detail/handler_alloc_helpers.hpp"
+#include "asio/detail/memory.hpp"
+#include "asio/detail/mutex.hpp"
+#include "asio/detail/operation.hpp"
+#include "asio/detail/win_iocp_handle_read_op.hpp"
+#include "asio/detail/win_iocp_handle_write_op.hpp"
+#include "asio/detail/win_iocp_io_context.hpp"
+
+#include "asio/detail/push_options.hpp"
+
+namespace asio {
+namespace detail {
+
+class win_iocp_handle_service :
+ public service_base<win_iocp_handle_service>
+{
+public:
+ // The native type of a stream handle.
+ typedef HANDLE native_handle_type;
+
+ // The implementation type of the stream handle.
+ class implementation_type
+ {
+ public:
+ // Default constructor.
+ implementation_type()
+ : handle_(INVALID_HANDLE_VALUE),
+ safe_cancellation_thread_id_(0),
+ next_(0),
+ prev_(0)
+ {
+ }
+
+ private:
+ // Only this service will have access to the internal values.
+ friend class win_iocp_handle_service;
+
+ // The native stream handle representation.
+ native_handle_type handle_;
+
+ // The ID of the thread from which it is safe to cancel asynchronous
+ // operations. 0 means no asynchronous operations have been started yet.
+ // ~0 means asynchronous operations have been started from more than one
+ // thread, and cancellation is not supported for the handle.
+ DWORD safe_cancellation_thread_id_;
+
+ // Pointers to adjacent handle implementations in linked list.
+ implementation_type* next_;
+ implementation_type* prev_;
+ };
+
+ ASIO_DECL win_iocp_handle_service(asio::io_context& io_context);
+
+ // Destroy all user-defined handler objects owned by the service.
+ ASIO_DECL void shutdown();
+
+ // Construct a new handle implementation.
+ ASIO_DECL void construct(implementation_type& impl);
+
+ // Move-construct a new handle implementation.
+ ASIO_DECL void move_construct(implementation_type& impl,
+ implementation_type& other_impl);
+
+ // Move-assign from another handle implementation.
+ ASIO_DECL void move_assign(implementation_type& impl,
+ win_iocp_handle_service& other_service,
+ implementation_type& other_impl);
+
+ // Destroy a handle implementation.
+ ASIO_DECL void destroy(implementation_type& impl);
+
+ // Assign a native handle to a handle implementation.
+ ASIO_DECL asio::error_code assign(implementation_type& impl,
+ const native_handle_type& handle, asio::error_code& ec);
+
+ // Determine whether the handle is open.
+ bool is_open(const implementation_type& impl) const
+ {
+ return impl.handle_ != INVALID_HANDLE_VALUE;
+ }
+
+ // Destroy a handle implementation.
+ ASIO_DECL asio::error_code close(implementation_type& impl,
+ asio::error_code& ec);
+
+ // Get the native handle representation.
+ native_handle_type native_handle(const implementation_type& impl) const
+ {
+ return impl.handle_;
+ }
+
+ // Cancel all operations associated with the handle.
+ ASIO_DECL asio::error_code cancel(implementation_type& impl,
+ asio::error_code& ec);
+
+ // Write the given data. Returns the number of bytes written.
+ template <typename ConstBufferSequence>
+ size_t write_some(implementation_type& impl,
+ const ConstBufferSequence& buffers, asio::error_code& ec)
+ {
+ return write_some_at(impl, 0, buffers, ec);
+ }
+
+ // Write the given data at the specified offset. Returns the number of bytes
+ // written.
+ template <typename ConstBufferSequence>
+ size_t write_some_at(implementation_type& impl, uint64_t offset,
+ const ConstBufferSequence& buffers, asio::error_code& ec)
+ {
+ asio::const_buffer buffer =
+ buffer_sequence_adapter<asio::const_buffer,
+ ConstBufferSequence>::first(buffers);
+
+ return do_write(impl, offset, buffer, ec);
+ }
+
+ // Start an asynchronous write. The data being written must be valid for the
+ // lifetime of the asynchronous operation.
+ template <typename ConstBufferSequence, typename Handler>
+ void async_write_some(implementation_type& impl,
+ const ConstBufferSequence& buffers, Handler& handler)
+ {
+ // Allocate and construct an operation to wrap the handler.
+ typedef win_iocp_handle_write_op<ConstBufferSequence, Handler> op;
+ typename op::ptr p = { asio::detail::addressof(handler),
+ op::ptr::allocate(handler), 0 };
+ p.p = new (p.v) op(buffers, handler);
+
+ ASIO_HANDLER_CREATION((iocp_service_.context(), *p.p, "handle", &impl,
+ reinterpret_cast<uintmax_t>(impl.handle_), "async_write_some"));
+
+ start_write_op(impl, 0,
+ buffer_sequence_adapter<asio::const_buffer,
+ ConstBufferSequence>::first(buffers), p.p);
+ p.v = p.p = 0;
+ }
+
+ // Start an asynchronous write at a specified offset. The data being written
+ // must be valid for the lifetime of the asynchronous operation.
+ template <typename ConstBufferSequence, typename Handler>
+ void async_write_some_at(implementation_type& impl, uint64_t offset,
+ const ConstBufferSequence& buffers, Handler& handler)
+ {
+ // Allocate and construct an operation to wrap the handler.
+ typedef win_iocp_handle_write_op<ConstBufferSequence, Handler> op;
+ typename op::ptr p = { asio::detail::addressof(handler),
+ op::ptr::allocate(handler), 0 };
+ p.p = new (p.v) op(buffers, handler);
+
+ ASIO_HANDLER_CREATION((iocp_service_.context(), *p.p, "handle", &impl,
+ reinterpret_cast<uintmax_t>(impl.handle_), "async_write_some_at"));
+
+ start_write_op(impl, offset,
+ buffer_sequence_adapter<asio::const_buffer,
+ ConstBufferSequence>::first(buffers), p.p);
+ p.v = p.p = 0;
+ }
+
+ // Read some data. Returns the number of bytes received.
+ template <typename MutableBufferSequence>
+ size_t read_some(implementation_type& impl,
+ const MutableBufferSequence& buffers, asio::error_code& ec)
+ {
+ return read_some_at(impl, 0, buffers, ec);
+ }
+
+ // Read some data at a specified offset. Returns the number of bytes received.
+ template <typename MutableBufferSequence>
+ size_t read_some_at(implementation_type& impl, uint64_t offset,
+ const MutableBufferSequence& buffers, asio::error_code& ec)
+ {
+ asio::mutable_buffer buffer =
+ buffer_sequence_adapter<asio::mutable_buffer,
+ MutableBufferSequence>::first(buffers);
+
+ return do_read(impl, offset, buffer, ec);
+ }
+
+ // Start an asynchronous read. The buffer for the data being received must be
+ // valid for the lifetime of the asynchronous operation.
+ template <typename MutableBufferSequence, typename Handler>
+ void async_read_some(implementation_type& impl,
+ const MutableBufferSequence& buffers, Handler& handler)
+ {
+ // Allocate and construct an operation to wrap the handler.
+ typedef win_iocp_handle_read_op<MutableBufferSequence, Handler> op;
+ typename op::ptr p = { asio::detail::addressof(handler),
+ op::ptr::allocate(handler), 0 };
+ p.p = new (p.v) op(buffers, handler);
+
+ ASIO_HANDLER_CREATION((iocp_service_.context(), *p.p, "handle", &impl,
+ reinterpret_cast<uintmax_t>(impl.handle_), "async_read_some"));
+
+ start_read_op(impl, 0,
+ buffer_sequence_adapter<asio::mutable_buffer,
+ MutableBufferSequence>::first(buffers), p.p);
+ p.v = p.p = 0;
+ }
+
+ // Start an asynchronous read at a specified offset. The buffer for the data
+ // being received must be valid for the lifetime of the asynchronous
+ // operation.
+ template <typename MutableBufferSequence, typename Handler>
+ void async_read_some_at(implementation_type& impl, uint64_t offset,
+ const MutableBufferSequence& buffers, Handler& handler)
+ {
+ // Allocate and construct an operation to wrap the handler.
+ typedef win_iocp_handle_read_op<MutableBufferSequence, Handler> op;
+ typename op::ptr p = { asio::detail::addressof(handler),
+ op::ptr::allocate(handler), 0 };
+ p.p = new (p.v) op(buffers, handler);
+
+ ASIO_HANDLER_CREATION((iocp_service_.context(), *p.p, "handle", &impl,
+ reinterpret_cast<uintmax_t>(impl.handle_), "async_read_some_at"));
+
+ start_read_op(impl, offset,
+ buffer_sequence_adapter<asio::mutable_buffer,
+ MutableBufferSequence>::first(buffers), p.p);
+ p.v = p.p = 0;
+ }
+
+private:
+ // Prevent the use of the null_buffers type with this service.
+ size_t write_some(implementation_type& impl,
+ const null_buffers& buffers, asio::error_code& ec);
+ size_t write_some_at(implementation_type& impl, uint64_t offset,
+ const null_buffers& buffers, asio::error_code& ec);
+ template <typename Handler>
+ void async_write_some(implementation_type& impl,
+ const null_buffers& buffers, Handler& handler);
+ template <typename Handler>
+ void async_write_some_at(implementation_type& impl, uint64_t offset,
+ const null_buffers& buffers, Handler& handler);
+ size_t read_some(implementation_type& impl,
+ const null_buffers& buffers, asio::error_code& ec);
+ size_t read_some_at(implementation_type& impl, uint64_t offset,
+ const null_buffers& buffers, asio::error_code& ec);
+ template <typename Handler>
+ void async_read_some(implementation_type& impl,
+ const null_buffers& buffers, Handler& handler);
+ template <typename Handler>
+ void async_read_some_at(implementation_type& impl, uint64_t offset,
+ const null_buffers& buffers, Handler& handler);
+
+ // Helper class for waiting for synchronous operations to complete.
+ class overlapped_wrapper;
+
+ // Helper function to perform a synchronous write operation.
+ ASIO_DECL size_t do_write(implementation_type& impl,
+ uint64_t offset, const asio::const_buffer& buffer,
+ asio::error_code& ec);
+
+ // Helper function to start a write operation.
+ ASIO_DECL void start_write_op(implementation_type& impl,
+ uint64_t offset, const asio::const_buffer& buffer,
+ operation* op);
+
+ // Helper function to perform a synchronous write operation.
+ ASIO_DECL size_t do_read(implementation_type& impl,
+ uint64_t offset, const asio::mutable_buffer& buffer,
+ asio::error_code& ec);
+
+ // Helper function to start a read operation.
+ ASIO_DECL void start_read_op(implementation_type& impl,
+ uint64_t offset, const asio::mutable_buffer& buffer,
+ operation* op);
+
+ // Update the ID of the thread from which cancellation is safe.
+ ASIO_DECL void update_cancellation_thread_id(implementation_type& impl);
+
+ // Helper function to close a handle when the associated object is being
+ // destroyed.
+ ASIO_DECL void close_for_destruction(implementation_type& impl);
+
+ // The IOCP service used for running asynchronous operations and dispatching
+ // handlers.
+ win_iocp_io_context& iocp_service_;
+
+ // Mutex to protect access to the linked list of implementations.
+ mutex mutex_;
+
+ // The head of a linked list of all implementations.
+ implementation_type* impl_list_;
+};
+
+} // namespace detail
+} // namespace asio
+
+#include "asio/detail/pop_options.hpp"
+
+#if defined(ASIO_HEADER_ONLY)
+# include "asio/detail/impl/win_iocp_handle_service.ipp"
+#endif // defined(ASIO_HEADER_ONLY)
+
+#endif // defined(ASIO_HAS_IOCP)
+
+#endif // ASIO_DETAIL_WIN_IOCP_HANDLE_SERVICE_HPP
diff --git a/lib/asio/detail/win_iocp_handle_write_op.hpp b/lib/asio/detail/win_iocp_handle_write_op.hpp
new file mode 100644
index 0000000..d7bb944
--- /dev/null
+++ b/lib/asio/detail/win_iocp_handle_write_op.hpp
@@ -0,0 +1,103 @@
+//
+// detail/win_iocp_handle_write_op.hpp
+// ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+//
+// Copyright (c) 2003-2018 Christopher M. Kohlhoff (chris at kohlhoff dot com)
+// Copyright (c) 2008 Rep Invariant Systems, Inc. (info@repinvariant.com)
+//
+// 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 ASIO_DETAIL_WIN_IOCP_HANDLE_WRITE_OP_HPP
+#define ASIO_DETAIL_WIN_IOCP_HANDLE_WRITE_OP_HPP
+
+#if defined(_MSC_VER) && (_MSC_VER >= 1200)
+# pragma once
+#endif // defined(_MSC_VER) && (_MSC_VER >= 1200)
+
+#include "asio/detail/config.hpp"
+
+#if defined(ASIO_HAS_IOCP)
+
+#include "asio/error.hpp"
+#include "asio/detail/bind_handler.hpp"
+#include "asio/detail/buffer_sequence_adapter.hpp"
+#include "asio/detail/fenced_block.hpp"
+#include "asio/detail/handler_alloc_helpers.hpp"
+#include "asio/detail/handler_invoke_helpers.hpp"
+#include "asio/detail/memory.hpp"
+#include "asio/detail/operation.hpp"
+
+#include "asio/detail/push_options.hpp"
+
+namespace asio {
+namespace detail {
+
+template <typename ConstBufferSequence, typename Handler>
+class win_iocp_handle_write_op : public operation
+{
+public:
+ ASIO_DEFINE_HANDLER_PTR(win_iocp_handle_write_op);
+
+ win_iocp_handle_write_op(const ConstBufferSequence& buffers, Handler& handler)
+ : operation(&win_iocp_handle_write_op::do_complete),
+ buffers_(buffers),
+ handler_(ASIO_MOVE_CAST(Handler)(handler))
+ {
+ handler_work<Handler>::start(handler_);
+ }
+
+ static void do_complete(void* owner, operation* base,
+ const asio::error_code& ec, std::size_t bytes_transferred)
+ {
+ // Take ownership of the operation object.
+ win_iocp_handle_write_op* o(static_cast<win_iocp_handle_write_op*>(base));
+ ptr p = { asio::detail::addressof(o->handler_), o, o };
+ handler_work<Handler> w(o->handler_);
+
+ ASIO_HANDLER_COMPLETION((*o));
+
+#if defined(ASIO_ENABLE_BUFFER_DEBUGGING)
+ if (owner)
+ {
+ // Check whether buffers are still valid.
+ buffer_sequence_adapter<asio::const_buffer,
+ ConstBufferSequence>::validate(o->buffers_);
+ }
+#endif // defined(ASIO_ENABLE_BUFFER_DEBUGGING)
+
+ // 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::binder2<Handler, asio::error_code, std::size_t>
+ handler(o->handler_, ec, bytes_transferred);
+ p.h = asio::detail::addressof(handler.handler_);
+ p.reset();
+
+ // Make the upcall if required.
+ if (owner)
+ {
+ fenced_block b(fenced_block::half);
+ ASIO_HANDLER_INVOCATION_BEGIN((handler.arg1_, handler.arg2_));
+ w.complete(handler, handler.handler_);
+ ASIO_HANDLER_INVOCATION_END;
+ }
+ }
+
+private:
+ ConstBufferSequence buffers_;
+ Handler handler_;
+};
+
+} // namespace detail
+} // namespace asio
+
+#include "asio/detail/pop_options.hpp"
+
+#endif // defined(ASIO_HAS_IOCP)
+
+#endif // ASIO_DETAIL_WIN_IOCP_HANDLE_WRITE_OP_HPP
diff --git a/lib/asio/detail/win_iocp_io_context.hpp b/lib/asio/detail/win_iocp_io_context.hpp
new file mode 100644
index 0000000..11bf58b
--- /dev/null
+++ b/lib/asio/detail/win_iocp_io_context.hpp
@@ -0,0 +1,328 @@
+//
+// detail/win_iocp_io_context.hpp
+// ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+//
+// Copyright (c) 2003-2018 Christopher M. Kohlhoff (chris at kohlhoff dot com)
+//
+// 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 ASIO_DETAIL_WIN_IOCP_IO_CONTEXT_HPP
+#define ASIO_DETAIL_WIN_IOCP_IO_CONTEXT_HPP
+
+#if defined(_MSC_VER) && (_MSC_VER >= 1200)
+# pragma once
+#endif // defined(_MSC_VER) && (_MSC_VER >= 1200)
+
+#include "asio/detail/config.hpp"
+
+#if defined(ASIO_HAS_IOCP)
+
+#include "asio/detail/limits.hpp"
+#include "asio/detail/mutex.hpp"
+#include "asio/detail/op_queue.hpp"
+#include "asio/detail/scoped_ptr.hpp"
+#include "asio/detail/socket_types.hpp"
+#include "asio/detail/thread.hpp"
+#include "asio/detail/thread_context.hpp"
+#include "asio/detail/timer_queue_base.hpp"
+#include "asio/detail/timer_queue_set.hpp"
+#include "asio/detail/wait_op.hpp"
+#include "asio/detail/win_iocp_operation.hpp"
+#include "asio/detail/win_iocp_thread_info.hpp"
+#include "asio/execution_context.hpp"
+
+#include "asio/detail/push_options.hpp"
+
+namespace asio {
+namespace detail {
+
+class wait_op;
+
+class win_iocp_io_context
+ : public execution_context_service_base<win_iocp_io_context>,
+ public thread_context
+{
+public:
+ // Constructor. Specifies a concurrency hint that is passed through to the
+ // underlying I/O completion port.
+ ASIO_DECL win_iocp_io_context(asio::execution_context& ctx,
+ int concurrency_hint = -1);
+
+ // Destroy all user-defined handler objects owned by the service.
+ ASIO_DECL void shutdown();
+
+ // Initialise the task. Nothing to do here.
+ void init_task()
+ {
+ }
+
+ // Register a handle with the IO completion port.
+ ASIO_DECL asio::error_code register_handle(
+ HANDLE handle, asio::error_code& ec);
+
+ // Run the event loop until stopped or no more work.
+ ASIO_DECL size_t run(asio::error_code& ec);
+
+ // Run until stopped or one operation is performed.
+ ASIO_DECL size_t run_one(asio::error_code& ec);
+
+ // Run until timeout, interrupted, or one operation is performed.
+ ASIO_DECL size_t wait_one(long usec, asio::error_code& ec);
+
+ // Poll for operations without blocking.
+ ASIO_DECL size_t poll(asio::error_code& ec);
+
+ // Poll for one operation without blocking.
+ ASIO_DECL size_t poll_one(asio::error_code& ec);
+
+ // Stop the event processing loop.
+ ASIO_DECL void stop();
+
+ // Determine whether the io_context is stopped.
+ bool stopped() const
+ {
+ return ::InterlockedExchangeAdd(&stopped_, 0) != 0;
+ }
+
+ // Restart in preparation for a subsequent run invocation.
+ void restart()
+ {
+ ::InterlockedExchange(&stopped_, 0);
+ }
+
+ // Notify that some work has started.
+ void work_started()
+ {
+ ::InterlockedIncrement(&outstanding_work_);
+ }
+
+ // Notify that some work has finished.
+ void work_finished()
+ {
+ if (::InterlockedDecrement(&outstanding_work_) == 0)
+ stop();
+ }
+
+ // Return whether a handler can be dispatched immediately.
+ bool can_dispatch()
+ {
+ return thread_call_stack::contains(this) != 0;
+ }
+
+ // Request invocation of the given operation and return immediately. Assumes
+ // that work_started() has not yet been called for the operation.
+ void post_immediate_completion(win_iocp_operation* op, bool)
+ {
+ work_started();
+ post_deferred_completion(op);
+ }
+
+ // Request invocation of the given operation and return immediately. Assumes
+ // that work_started() was previously called for the operation.
+ ASIO_DECL void post_deferred_completion(win_iocp_operation* op);
+
+ // Request invocation of the given operation and return immediately. Assumes
+ // that work_started() was previously called for the operations.
+ ASIO_DECL void post_deferred_completions(
+ op_queue<win_iocp_operation>& ops);
+
+ // Request invocation of the given operation using the thread-private queue
+ // and return immediately. Assumes that work_started() has not yet been
+ // called for the operation.
+ void post_private_immediate_completion(win_iocp_operation* op)
+ {
+ post_immediate_completion(op, false);
+ }
+
+ // Request invocation of the given operation using the thread-private queue
+ // and return immediately. Assumes that work_started() was previously called
+ // for the operation.
+ void post_private_deferred_completion(win_iocp_operation* op)
+ {
+ post_deferred_completion(op);
+ }
+
+ // Enqueue the given operation following a failed attempt to dispatch the
+ // operation for immediate invocation.
+ void do_dispatch(operation* op)
+ {
+ post_immediate_completion(op, false);
+ }
+
+ // Process unfinished operations as part of a shutdown operation. Assumes
+ // that work_started() was previously called for the operations.
+ ASIO_DECL void abandon_operations(op_queue<operation>& ops);
+
+ // Called after starting an overlapped I/O operation that did not complete
+ // immediately. The caller must have already called work_started() prior to
+ // starting the operation.
+ ASIO_DECL void on_pending(win_iocp_operation* op);
+
+ // Called after starting an overlapped I/O operation that completed
+ // immediately. The caller must have already called work_started() prior to
+ // starting the operation.
+ ASIO_DECL void on_completion(win_iocp_operation* op,
+ DWORD last_error = 0, DWORD bytes_transferred = 0);
+
+ // Called after starting an overlapped I/O operation that completed
+ // immediately. The caller must have already called work_started() prior to
+ // starting the operation.
+ ASIO_DECL void on_completion(win_iocp_operation* op,
+ const asio::error_code& ec, DWORD bytes_transferred = 0);
+
+ // Add a new timer queue to the service.
+ template <typename Time_Traits>
+ void add_timer_queue(timer_queue<Time_Traits>& timer_queue);
+
+ // Remove a timer queue from the service.
+ template <typename Time_Traits>
+ void remove_timer_queue(timer_queue<Time_Traits>& timer_queue);
+
+ // Schedule a new operation in the given timer queue to expire at the
+ // specified absolute time.
+ template <typename Time_Traits>
+ void schedule_timer(timer_queue<Time_Traits>& queue,
+ const typename Time_Traits::time_type& time,
+ typename timer_queue<Time_Traits>::per_timer_data& timer, wait_op* op);
+
+ // Cancel the timer associated with the given token. Returns the number of
+ // handlers that have been posted or dispatched.
+ template <typename Time_Traits>
+ std::size_t cancel_timer(timer_queue<Time_Traits>& queue,
+ typename timer_queue<Time_Traits>::per_timer_data& timer,
+ std::size_t max_cancelled = (std::numeric_limits<std::size_t>::max)());
+
+ // Move the timer operations associated with the given timer.
+ template <typename Time_Traits>
+ void move_timer(timer_queue<Time_Traits>& queue,
+ typename timer_queue<Time_Traits>::per_timer_data& to,
+ typename timer_queue<Time_Traits>::per_timer_data& from);
+
+ // Get the concurrency hint that was used to initialise the io_context.
+ int concurrency_hint() const
+ {
+ return concurrency_hint_;
+ }
+
+private:
+#if defined(WINVER) && (WINVER < 0x0500)
+ typedef DWORD dword_ptr_t;
+ typedef ULONG ulong_ptr_t;
+#else // defined(WINVER) && (WINVER < 0x0500)
+ typedef DWORD_PTR dword_ptr_t;
+ typedef ULONG_PTR ulong_ptr_t;
+#endif // defined(WINVER) && (WINVER < 0x0500)
+
+ // Dequeues at most one operation from the I/O completion port, and then
+ // executes it. Returns the number of operations that were dequeued (i.e.
+ // either 0 or 1).
+ ASIO_DECL size_t do_one(DWORD msec, asio::error_code& ec);
+
+ // Helper to calculate the GetQueuedCompletionStatus timeout.
+ ASIO_DECL static DWORD get_gqcs_timeout();
+
+ // Helper function to add a new timer queue.
+ ASIO_DECL void do_add_timer_queue(timer_queue_base& queue);
+
+ // Helper function to remove a timer queue.
+ ASIO_DECL void do_remove_timer_queue(timer_queue_base& queue);
+
+ // Called to recalculate and update the timeout.
+ ASIO_DECL void update_timeout();
+
+ // Helper class to call work_finished() on block exit.
+ struct work_finished_on_block_exit;
+
+ // Helper class for managing a HANDLE.
+ struct auto_handle
+ {
+ HANDLE handle;
+ auto_handle() : handle(0) {}
+ ~auto_handle() { if (handle) ::CloseHandle(handle); }
+ };
+
+ // The IO completion port used for queueing operations.
+ auto_handle iocp_;
+
+ // The count of unfinished work.
+ long outstanding_work_;
+
+ // Flag to indicate whether the event loop has been stopped.
+ mutable long stopped_;
+
+ // Flag to indicate whether there is an in-flight stop event. Every event
+ // posted using PostQueuedCompletionStatus consumes non-paged pool, so to
+ // avoid exhausting this resouce we limit the number of outstanding events.
+ long stop_event_posted_;
+
+ // Flag to indicate whether the service has been shut down.
+ long shutdown_;
+
+ enum
+ {
+ // Timeout to use with GetQueuedCompletionStatus on older versions of
+ // Windows. Some versions of windows have a "bug" where a call to
+ // GetQueuedCompletionStatus can appear stuck even though there are events
+ // waiting on the queue. Using a timeout helps to work around the issue.
+ default_gqcs_timeout = 500,
+
+ // Maximum waitable timer timeout, in milliseconds.
+ max_timeout_msec = 5 * 60 * 1000,
+
+ // Maximum waitable timer timeout, in microseconds.
+ max_timeout_usec = max_timeout_msec * 1000,
+
+ // Completion key value used to wake up a thread to dispatch timers or
+ // completed operations.
+ wake_for_dispatch = 1,
+
+ // Completion key value to indicate that an operation has posted with the
+ // original last_error and bytes_transferred values stored in the fields of
+ // the OVERLAPPED structure.
+ overlapped_contains_result = 2
+ };
+
+ // Timeout to use with GetQueuedCompletionStatus.
+ const DWORD gqcs_timeout_;
+
+ // Function object for processing timeouts in a background thread.
+ struct timer_thread_function;
+ friend struct timer_thread_function;
+
+ // Background thread used for processing timeouts.
+ scoped_ptr<thread> timer_thread_;
+
+ // A waitable timer object used for waiting for timeouts.
+ auto_handle waitable_timer_;
+
+ // Non-zero if timers or completed operations need to be dispatched.
+ long dispatch_required_;
+
+ // Mutex for protecting access to the timer queues and completed operations.
+ mutex dispatch_mutex_;
+
+ // The timer queues.
+ timer_queue_set timer_queues_;
+
+ // The operations that are ready to dispatch.
+ op_queue<win_iocp_operation> completed_ops_;
+
+ // The concurrency hint used to initialise the io_context.
+ const int concurrency_hint_;
+};
+
+} // namespace detail
+} // namespace asio
+
+#include "asio/detail/pop_options.hpp"
+
+#include "asio/detail/impl/win_iocp_io_context.hpp"
+#if defined(ASIO_HEADER_ONLY)
+# include "asio/detail/impl/win_iocp_io_context.ipp"
+#endif // defined(ASIO_HEADER_ONLY)
+
+#endif // defined(ASIO_HAS_IOCP)
+
+#endif // ASIO_DETAIL_WIN_IOCP_IO_CONTEXT_HPP
diff --git a/lib/asio/detail/win_iocp_null_buffers_op.hpp b/lib/asio/detail/win_iocp_null_buffers_op.hpp
new file mode 100644
index 0000000..db70cb2
--- /dev/null
+++ b/lib/asio/detail/win_iocp_null_buffers_op.hpp
@@ -0,0 +1,121 @@
+//
+// detail/win_iocp_null_buffers_op.hpp
+// ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+//
+// Copyright (c) 2003-2018 Christopher M. Kohlhoff (chris at kohlhoff dot com)
+//
+// 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 ASIO_DETAIL_WIN_IOCP_NULL_BUFFERS_OP_HPP
+#define ASIO_DETAIL_WIN_IOCP_NULL_BUFFERS_OP_HPP
+
+#if defined(_MSC_VER) && (_MSC_VER >= 1200)
+# pragma once
+#endif // defined(_MSC_VER) && (_MSC_VER >= 1200)
+
+#include "asio/detail/config.hpp"
+
+#if defined(ASIO_HAS_IOCP)
+
+#include "asio/detail/bind_handler.hpp"
+#include "asio/detail/buffer_sequence_adapter.hpp"
+#include "asio/detail/fenced_block.hpp"
+#include "asio/detail/handler_alloc_helpers.hpp"
+#include "asio/detail/handler_invoke_helpers.hpp"
+#include "asio/detail/memory.hpp"
+#include "asio/detail/reactor_op.hpp"
+#include "asio/detail/socket_ops.hpp"
+#include "asio/error.hpp"
+
+#include "asio/detail/push_options.hpp"
+
+namespace asio {
+namespace detail {
+
+template <typename Handler>
+class win_iocp_null_buffers_op : public reactor_op
+{
+public:
+ ASIO_DEFINE_HANDLER_PTR(win_iocp_null_buffers_op);
+
+ win_iocp_null_buffers_op(socket_ops::weak_cancel_token_type cancel_token,
+ Handler& handler)
+ : reactor_op(&win_iocp_null_buffers_op::do_perform,
+ &win_iocp_null_buffers_op::do_complete),
+ cancel_token_(cancel_token),
+ handler_(ASIO_MOVE_CAST(Handler)(handler))
+ {
+ handler_work<Handler>::start(handler_);
+ }
+
+ static status do_perform(reactor_op*)
+ {
+ return done;
+ }
+
+ static void do_complete(void* owner, operation* base,
+ const asio::error_code& result_ec,
+ std::size_t bytes_transferred)
+ {
+ asio::error_code ec(result_ec);
+
+ // Take ownership of the operation object.
+ win_iocp_null_buffers_op* o(static_cast<win_iocp_null_buffers_op*>(base));
+ ptr p = { asio::detail::addressof(o->handler_), o, o };
+ handler_work<Handler> w(o->handler_);
+
+ ASIO_HANDLER_COMPLETION((*o));
+
+ // The reactor may have stored a result in the operation object.
+ if (o->ec_)
+ ec = o->ec_;
+
+ // Map non-portable errors to their portable counterparts.
+ if (ec.value() == ERROR_NETNAME_DELETED)
+ {
+ if (o->cancel_token_.expired())
+ ec = asio::error::operation_aborted;
+ else
+ ec = asio::error::connection_reset;
+ }
+ else if (ec.value() == ERROR_PORT_UNREACHABLE)
+ {
+ ec = asio::error::connection_refused;
+ }
+
+ // 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::binder2<Handler, asio::error_code, std::size_t>
+ handler(o->handler_, ec, bytes_transferred);
+ p.h = asio::detail::addressof(handler.handler_);
+ p.reset();
+
+ // Make the upcall if required.
+ if (owner)
+ {
+ fenced_block b(fenced_block::half);
+ ASIO_HANDLER_INVOCATION_BEGIN((handler.arg1_, handler.arg2_));
+ w.complete(handler, handler.handler_);
+ ASIO_HANDLER_INVOCATION_END;
+ }
+ }
+
+private:
+ socket_ops::weak_cancel_token_type cancel_token_;
+ Handler handler_;
+};
+
+} // namespace detail
+} // namespace asio
+
+#include "asio/detail/pop_options.hpp"
+
+#endif // defined(ASIO_HAS_IOCP)
+
+#endif // ASIO_DETAIL_WIN_IOCP_NULL_BUFFERS_OP_HPP
diff --git a/lib/asio/detail/win_iocp_operation.hpp b/lib/asio/detail/win_iocp_operation.hpp
new file mode 100644
index 0000000..81d43f0
--- /dev/null
+++ b/lib/asio/detail/win_iocp_operation.hpp
@@ -0,0 +1,96 @@
+//
+// detail/win_iocp_operation.hpp
+// ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+//
+// Copyright (c) 2003-2018 Christopher M. Kohlhoff (chris at kohlhoff dot com)
+//
+// 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 ASIO_DETAIL_WIN_IOCP_OPERATION_HPP
+#define ASIO_DETAIL_WIN_IOCP_OPERATION_HPP
+
+#if defined(_MSC_VER) && (_MSC_VER >= 1200)
+# pragma once
+#endif // defined(_MSC_VER) && (_MSC_VER >= 1200)
+
+#include "asio/detail/config.hpp"
+
+#if defined(ASIO_HAS_IOCP)
+
+#include "asio/detail/handler_tracking.hpp"
+#include "asio/detail/op_queue.hpp"
+#include "asio/detail/socket_types.hpp"
+#include "asio/error_code.hpp"
+
+#include "asio/detail/push_options.hpp"
+
+namespace asio {
+namespace detail {
+
+class win_iocp_io_context;
+
+// Base class for all operations. A function pointer is used instead of virtual
+// functions to avoid the associated overhead.
+class win_iocp_operation
+ : public OVERLAPPED
+ ASIO_ALSO_INHERIT_TRACKED_HANDLER
+{
+public:
+ typedef win_iocp_operation operation_type;
+
+ void complete(void* owner, const asio::error_code& ec,
+ std::size_t bytes_transferred)
+ {
+ func_(owner, this, ec, bytes_transferred);
+ }
+
+ void destroy()
+ {
+ func_(0, this, asio::error_code(), 0);
+ }
+
+protected:
+ typedef void (*func_type)(
+ void*, win_iocp_operation*,
+ const asio::error_code&, std::size_t);
+
+ win_iocp_operation(func_type func)
+ : next_(0),
+ func_(func)
+ {
+ reset();
+ }
+
+ // Prevents deletion through this type.
+ ~win_iocp_operation()
+ {
+ }
+
+ void reset()
+ {
+ Internal = 0;
+ InternalHigh = 0;
+ Offset = 0;
+ OffsetHigh = 0;
+ hEvent = 0;
+ ready_ = 0;
+ }
+
+private:
+ friend class op_queue_access;
+ friend class win_iocp_io_context;
+ win_iocp_operation* next_;
+ func_type func_;
+ long ready_;
+};
+
+} // namespace detail
+} // namespace asio
+
+#include "asio/detail/pop_options.hpp"
+
+#endif // defined(ASIO_HAS_IOCP)
+
+#endif // ASIO_DETAIL_WIN_IOCP_OPERATION_HPP
diff --git a/lib/asio/detail/win_iocp_overlapped_op.hpp b/lib/asio/detail/win_iocp_overlapped_op.hpp
new file mode 100644
index 0000000..2b2cc31
--- /dev/null
+++ b/lib/asio/detail/win_iocp_overlapped_op.hpp
@@ -0,0 +1,90 @@
+//
+// detail/win_iocp_overlapped_op.hpp
+// ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+//
+// Copyright (c) 2003-2018 Christopher M. Kohlhoff (chris at kohlhoff dot com)
+//
+// 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 ASIO_DETAIL_WIN_IOCP_OVERLAPPED_OP_HPP
+#define ASIO_DETAIL_WIN_IOCP_OVERLAPPED_OP_HPP
+
+#if defined(_MSC_VER) && (_MSC_VER >= 1200)
+# pragma once
+#endif // defined(_MSC_VER) && (_MSC_VER >= 1200)
+
+#include "asio/detail/config.hpp"
+
+#if defined(ASIO_HAS_IOCP)
+
+#include "asio/error.hpp"
+#include "asio/detail/bind_handler.hpp"
+#include "asio/detail/fenced_block.hpp"
+#include "asio/detail/handler_alloc_helpers.hpp"
+#include "asio/detail/handler_invoke_helpers.hpp"
+#include "asio/detail/memory.hpp"
+#include "asio/detail/operation.hpp"
+
+#include "asio/detail/push_options.hpp"
+
+namespace asio {
+namespace detail {
+
+template <typename Handler>
+class win_iocp_overlapped_op : public operation
+{
+public:
+ ASIO_DEFINE_HANDLER_PTR(win_iocp_overlapped_op);
+
+ win_iocp_overlapped_op(Handler& handler)
+ : operation(&win_iocp_overlapped_op::do_complete),
+ handler_(ASIO_MOVE_CAST(Handler)(handler))
+ {
+ handler_work<Handler>::start(handler_);
+ }
+
+ static void do_complete(void* owner, operation* base,
+ const asio::error_code& ec, std::size_t bytes_transferred)
+ {
+ // Take ownership of the operation object.
+ win_iocp_overlapped_op* o(static_cast<win_iocp_overlapped_op*>(base));
+ ptr p = { asio::detail::addressof(o->handler_), o, o };
+ handler_work<Handler> w(o->handler_);
+
+ ASIO_HANDLER_COMPLETION((*o));
+
+ // 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::binder2<Handler, asio::error_code, std::size_t>
+ handler(o->handler_, ec, bytes_transferred);
+ p.h = asio::detail::addressof(handler.handler_);
+ p.reset();
+
+ // Make the upcall if required.
+ if (owner)
+ {
+ fenced_block b(fenced_block::half);
+ ASIO_HANDLER_INVOCATION_BEGIN((handler.arg1_, handler.arg2_));
+ w.complete(handler, handler.handler_);
+ ASIO_HANDLER_INVOCATION_END;
+ }
+ }
+
+private:
+ Handler handler_;
+};
+
+} // namespace detail
+} // namespace asio
+
+#include "asio/detail/pop_options.hpp"
+
+#endif // defined(ASIO_HAS_IOCP)
+
+#endif // ASIO_DETAIL_WIN_IOCP_OVERLAPPED_OP_HPP
diff --git a/lib/asio/detail/win_iocp_overlapped_ptr.hpp b/lib/asio/detail/win_iocp_overlapped_ptr.hpp
new file mode 100644
index 0000000..7a19114
--- /dev/null
+++ b/lib/asio/detail/win_iocp_overlapped_ptr.hpp
@@ -0,0 +1,143 @@
+//
+// detail/win_iocp_overlapped_ptr.hpp
+// ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+//
+// Copyright (c) 2003-2018 Christopher M. Kohlhoff (chris at kohlhoff dot com)
+//
+// 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 ASIO_DETAIL_WIN_IOCP_OVERLAPPED_PTR_HPP
+#define ASIO_DETAIL_WIN_IOCP_OVERLAPPED_PTR_HPP
+
+#if defined(_MSC_VER) && (_MSC_VER >= 1200)
+# pragma once
+#endif // defined(_MSC_VER) && (_MSC_VER >= 1200)
+
+#include "asio/detail/config.hpp"
+
+#if defined(ASIO_HAS_IOCP)
+
+#include "asio/io_context.hpp"
+#include "asio/detail/handler_alloc_helpers.hpp"
+#include "asio/detail/memory.hpp"
+#include "asio/detail/noncopyable.hpp"
+#include "asio/detail/win_iocp_overlapped_op.hpp"
+#include "asio/detail/win_iocp_io_context.hpp"
+
+#include "asio/detail/push_options.hpp"
+
+namespace asio {
+namespace detail {
+
+// Wraps a handler to create an OVERLAPPED object for use with overlapped I/O.
+class win_iocp_overlapped_ptr
+ : private noncopyable
+{
+public:
+ // Construct an empty win_iocp_overlapped_ptr.
+ win_iocp_overlapped_ptr()
+ : ptr_(0),
+ iocp_service_(0)
+ {
+ }
+
+ // Construct an win_iocp_overlapped_ptr to contain the specified handler.
+ template <typename Handler>
+ explicit win_iocp_overlapped_ptr(
+ asio::io_context& io_context, ASIO_MOVE_ARG(Handler) handler)
+ : ptr_(0),
+ iocp_service_(0)
+ {
+ this->reset(io_context, ASIO_MOVE_CAST(Handler)(handler));
+ }
+
+ // Destructor automatically frees the OVERLAPPED object unless released.
+ ~win_iocp_overlapped_ptr()
+ {
+ reset();
+ }
+
+ // Reset to empty.
+ void reset()
+ {
+ if (ptr_)
+ {
+ ptr_->destroy();
+ ptr_ = 0;
+ iocp_service_->work_finished();
+ iocp_service_ = 0;
+ }
+ }
+
+ // Reset to contain the specified handler, freeing any current OVERLAPPED
+ // object.
+ template <typename Handler>
+ void reset(asio::io_context& io_context, Handler handler)
+ {
+ typedef win_iocp_overlapped_op<Handler> op;
+ typename op::ptr p = { asio::detail::addressof(handler),
+ op::ptr::allocate(handler), 0 };
+ p.p = new (p.v) op(handler);
+
+ ASIO_HANDLER_CREATION((io_context, *p.p,
+ "io_context", &io_context.impl_, 0, "overlapped"));
+
+ io_context.impl_.work_started();
+ reset();
+ ptr_ = p.p;
+ p.v = p.p = 0;
+ iocp_service_ = &io_context.impl_;
+ }
+
+ // Get the contained OVERLAPPED object.
+ OVERLAPPED* get()
+ {
+ return ptr_;
+ }
+
+ // Get the contained OVERLAPPED object.
+ const OVERLAPPED* get() const
+ {
+ return ptr_;
+ }
+
+ // Release ownership of the OVERLAPPED object.
+ OVERLAPPED* release()
+ {
+ if (ptr_)
+ iocp_service_->on_pending(ptr_);
+
+ OVERLAPPED* tmp = ptr_;
+ ptr_ = 0;
+ iocp_service_ = 0;
+ return tmp;
+ }
+
+ // Post completion notification for overlapped operation. Releases ownership.
+ void complete(const asio::error_code& ec,
+ std::size_t bytes_transferred)
+ {
+ if (ptr_)
+ {
+ iocp_service_->on_completion(ptr_, ec,
+ static_cast<DWORD>(bytes_transferred));
+ ptr_ = 0;
+ iocp_service_ = 0;
+ }
+ }
+
+private:
+ win_iocp_operation* ptr_;
+ win_iocp_io_context* iocp_service_;
+};
+
+} // namespace detail
+} // namespace asio
+
+#include "asio/detail/pop_options.hpp"
+
+#endif // defined(ASIO_HAS_IOCP)
+
+#endif // ASIO_DETAIL_WIN_IOCP_OVERLAPPED_PTR_HPP
diff --git a/lib/asio/detail/win_iocp_serial_port_service.hpp b/lib/asio/detail/win_iocp_serial_port_service.hpp
new file mode 100644
index 0000000..ac06348
--- /dev/null
+++ b/lib/asio/detail/win_iocp_serial_port_service.hpp
@@ -0,0 +1,230 @@
+//
+// detail/win_iocp_serial_port_service.hpp
+// ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+//
+// Copyright (c) 2003-2018 Christopher M. Kohlhoff (chris at kohlhoff dot com)
+// Copyright (c) 2008 Rep Invariant Systems, Inc. (info@repinvariant.com)
+//
+// 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 ASIO_DETAIL_WIN_IOCP_SERIAL_PORT_SERVICE_HPP
+#define ASIO_DETAIL_WIN_IOCP_SERIAL_PORT_SERVICE_HPP
+
+#if defined(_MSC_VER) && (_MSC_VER >= 1200)
+# pragma once
+#endif // defined(_MSC_VER) && (_MSC_VER >= 1200)
+
+#include "asio/detail/config.hpp"
+
+#if defined(ASIO_HAS_IOCP) && defined(ASIO_HAS_SERIAL_PORT)
+
+#include <string>
+#include "asio/error.hpp"
+#include "asio/io_context.hpp"
+#include "asio/detail/win_iocp_handle_service.hpp"
+
+#include "asio/detail/push_options.hpp"
+
+namespace asio {
+namespace detail {
+
+// Extend win_iocp_handle_service to provide serial port support.
+class win_iocp_serial_port_service :
+ public service_base<win_iocp_serial_port_service>
+{
+public:
+ // The native type of a serial port.
+ typedef win_iocp_handle_service::native_handle_type native_handle_type;
+
+ // The implementation type of the serial port.
+ typedef win_iocp_handle_service::implementation_type implementation_type;
+
+ // Constructor.
+ ASIO_DECL win_iocp_serial_port_service(
+ asio::io_context& io_context);
+
+ // Destroy all user-defined handler objects owned by the service.
+ ASIO_DECL void shutdown();
+
+ // Construct a new serial port implementation.
+ void construct(implementation_type& impl)
+ {
+ handle_service_.construct(impl);
+ }
+
+ // Move-construct a new serial port implementation.
+ void move_construct(implementation_type& impl,
+ implementation_type& other_impl)
+ {
+ handle_service_.move_construct(impl, other_impl);
+ }
+
+ // Move-assign from another serial port implementation.
+ void move_assign(implementation_type& impl,
+ win_iocp_serial_port_service& other_service,
+ implementation_type& other_impl)
+ {
+ handle_service_.move_assign(impl,
+ other_service.handle_service_, other_impl);
+ }
+
+ // Destroy a serial port implementation.
+ void destroy(implementation_type& impl)
+ {
+ handle_service_.destroy(impl);
+ }
+
+ // Open the serial port using the specified device name.
+ ASIO_DECL asio::error_code open(implementation_type& impl,
+ const std::string& device, asio::error_code& ec);
+
+ // Assign a native handle to a serial port implementation.
+ asio::error_code assign(implementation_type& impl,
+ const native_handle_type& handle, asio::error_code& ec)
+ {
+ return handle_service_.assign(impl, handle, ec);
+ }
+
+ // Determine whether the serial port is open.
+ bool is_open(const implementation_type& impl) const
+ {
+ return handle_service_.is_open(impl);
+ }
+
+ // Destroy a serial port implementation.
+ asio::error_code close(implementation_type& impl,
+ asio::error_code& ec)
+ {
+ return handle_service_.close(impl, ec);
+ }
+
+ // Get the native serial port representation.
+ native_handle_type native_handle(implementation_type& impl)
+ {
+ return handle_service_.native_handle(impl);
+ }
+
+ // Cancel all operations associated with the handle.
+ asio::error_code cancel(implementation_type& impl,
+ asio::error_code& ec)
+ {
+ return handle_service_.cancel(impl, ec);
+ }
+
+ // Set an option on the serial port.
+ template <typename SettableSerialPortOption>
+ asio::error_code set_option(implementation_type& impl,
+ const SettableSerialPortOption& option, asio::error_code& ec)
+ {
+ return do_set_option(impl,
+ &win_iocp_serial_port_service::store_option<SettableSerialPortOption>,
+ &option, ec);
+ }
+
+ // Get an option from the serial port.
+ template <typename GettableSerialPortOption>
+ asio::error_code get_option(const implementation_type& impl,
+ GettableSerialPortOption& option, asio::error_code& ec) const
+ {
+ return do_get_option(impl,
+ &win_iocp_serial_port_service::load_option<GettableSerialPortOption>,
+ &option, ec);
+ }
+
+ // Send a break sequence to the serial port.
+ asio::error_code send_break(implementation_type&,
+ asio::error_code& ec)
+ {
+ ec = asio::error::operation_not_supported;
+ return ec;
+ }
+
+ // Write the given data. Returns the number of bytes sent.
+ template <typename ConstBufferSequence>
+ size_t write_some(implementation_type& impl,
+ const ConstBufferSequence& buffers, asio::error_code& ec)
+ {
+ return handle_service_.write_some(impl, buffers, ec);
+ }
+
+ // Start an asynchronous write. The data being written must be valid for the
+ // lifetime of the asynchronous operation.
+ template <typename ConstBufferSequence, typename Handler>
+ void async_write_some(implementation_type& impl,
+ const ConstBufferSequence& buffers, Handler& handler)
+ {
+ handle_service_.async_write_some(impl, buffers, handler);
+ }
+
+ // Read some data. Returns the number of bytes received.
+ template <typename MutableBufferSequence>
+ size_t read_some(implementation_type& impl,
+ const MutableBufferSequence& buffers, asio::error_code& ec)
+ {
+ return handle_service_.read_some(impl, buffers, ec);
+ }
+
+ // Start an asynchronous read. The buffer for the data being received must be
+ // valid for the lifetime of the asynchronous operation.
+ template <typename MutableBufferSequence, typename Handler>
+ void async_read_some(implementation_type& impl,
+ const MutableBufferSequence& buffers, Handler& handler)
+ {
+ handle_service_.async_read_some(impl, buffers, handler);
+ }
+
+private:
+ // Function pointer type for storing a serial port option.
+ typedef asio::error_code (*store_function_type)(
+ const void*, ::DCB&, asio::error_code&);
+
+ // Helper function template to store a serial port option.
+ template <typename SettableSerialPortOption>
+ static asio::error_code store_option(const void* option,
+ ::DCB& storage, asio::error_code& ec)
+ {
+ static_cast<const SettableSerialPortOption*>(option)->store(storage, ec);
+ return ec;
+ }
+
+ // Helper function to set a serial port option.
+ ASIO_DECL asio::error_code do_set_option(
+ implementation_type& impl, store_function_type store,
+ const void* option, asio::error_code& ec);
+
+ // Function pointer type for loading a serial port option.
+ typedef asio::error_code (*load_function_type)(
+ void*, const ::DCB&, asio::error_code&);
+
+ // Helper function template to load a serial port option.
+ template <typename GettableSerialPortOption>
+ static asio::error_code load_option(void* option,
+ const ::DCB& storage, asio::error_code& ec)
+ {
+ static_cast<GettableSerialPortOption*>(option)->load(storage, ec);
+ return ec;
+ }
+
+ // Helper function to get a serial port option.
+ ASIO_DECL asio::error_code do_get_option(
+ const implementation_type& impl, load_function_type load,
+ void* option, asio::error_code& ec) const;
+
+ // The implementation used for initiating asynchronous operations.
+ win_iocp_handle_service handle_service_;
+};
+
+} // namespace detail
+} // namespace asio
+
+#include "asio/detail/pop_options.hpp"
+
+#if defined(ASIO_HEADER_ONLY)
+# include "asio/detail/impl/win_iocp_serial_port_service.ipp"
+#endif // defined(ASIO_HEADER_ONLY)
+
+#endif // defined(ASIO_HAS_IOCP) && defined(ASIO_HAS_SERIAL_PORT)
+
+#endif // ASIO_DETAIL_WIN_IOCP_SERIAL_PORT_SERVICE_HPP
diff --git a/lib/asio/detail/win_iocp_socket_accept_op.hpp b/lib/asio/detail/win_iocp_socket_accept_op.hpp
new file mode 100644
index 0000000..18e7335
--- /dev/null
+++ b/lib/asio/detail/win_iocp_socket_accept_op.hpp
@@ -0,0 +1,297 @@
+//
+// detail/win_iocp_socket_accept_op.hpp
+// ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+//
+// Copyright (c) 2003-2018 Christopher M. Kohlhoff (chris at kohlhoff dot com)
+//
+// 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 ASIO_DETAIL_WIN_IOCP_SOCKET_ACCEPT_OP_HPP
+#define ASIO_DETAIL_WIN_IOCP_SOCKET_ACCEPT_OP_HPP
+
+#if defined(_MSC_VER) && (_MSC_VER >= 1200)
+# pragma once
+#endif // defined(_MSC_VER) && (_MSC_VER >= 1200)
+
+#include "asio/detail/config.hpp"
+
+#if defined(ASIO_HAS_IOCP)
+
+#include "asio/detail/bind_handler.hpp"
+#include "asio/detail/buffer_sequence_adapter.hpp"
+#include "asio/detail/fenced_block.hpp"
+#include "asio/detail/handler_alloc_helpers.hpp"
+#include "asio/detail/handler_invoke_helpers.hpp"
+#include "asio/detail/memory.hpp"
+#include "asio/detail/operation.hpp"
+#include "asio/detail/socket_ops.hpp"
+#include "asio/detail/win_iocp_socket_service_base.hpp"
+#include "asio/error.hpp"
+
+#include "asio/detail/push_options.hpp"
+
+namespace asio {
+namespace detail {
+
+template <typename Socket, typename Protocol, typename Handler>
+class win_iocp_socket_accept_op : public operation
+{
+public:
+ ASIO_DEFINE_HANDLER_PTR(win_iocp_socket_accept_op);
+
+ win_iocp_socket_accept_op(win_iocp_socket_service_base& socket_service,
+ socket_type socket, Socket& peer, const Protocol& protocol,
+ typename Protocol::endpoint* peer_endpoint,
+ bool enable_connection_aborted, Handler& handler)
+ : operation(&win_iocp_socket_accept_op::do_complete),
+ socket_service_(socket_service),
+ socket_(socket),
+ peer_(peer),
+ protocol_(protocol),
+ peer_endpoint_(peer_endpoint),
+ enable_connection_aborted_(enable_connection_aborted),
+ handler_(ASIO_MOVE_CAST(Handler)(handler))
+ {
+ handler_work<Handler>::start(handler_);
+ }
+
+ socket_holder& new_socket()
+ {
+ return new_socket_;
+ }
+
+ void* output_buffer()
+ {
+ return output_buffer_;
+ }
+
+ DWORD address_length()
+ {
+ return sizeof(sockaddr_storage_type) + 16;
+ }
+
+ static void do_complete(void* owner, operation* base,
+ const asio::error_code& result_ec,
+ std::size_t /*bytes_transferred*/)
+ {
+ asio::error_code ec(result_ec);
+
+ // Take ownership of the operation object.
+ win_iocp_socket_accept_op* o(static_cast<win_iocp_socket_accept_op*>(base));
+ ptr p = { asio::detail::addressof(o->handler_), o, o };
+ handler_work<Handler> w(o->handler_);
+
+ if (owner)
+ {
+ typename Protocol::endpoint peer_endpoint;
+ std::size_t addr_len = peer_endpoint.capacity();
+ socket_ops::complete_iocp_accept(o->socket_,
+ o->output_buffer(), o->address_length(),
+ peer_endpoint.data(), &addr_len,
+ o->new_socket_.get(), ec);
+
+ // Restart the accept operation if we got the connection_aborted error
+ // and the enable_connection_aborted socket option is not set.
+ if (ec == asio::error::connection_aborted
+ && !o->enable_connection_aborted_)
+ {
+ o->reset();
+ o->socket_service_.restart_accept_op(o->socket_,
+ o->new_socket_, o->protocol_.family(),
+ o->protocol_.type(), o->protocol_.protocol(),
+ o->output_buffer(), o->address_length(), o);
+ p.v = p.p = 0;
+ return;
+ }
+
+ // If the socket was successfully accepted, transfer ownership of the
+ // socket to the peer object.
+ if (!ec)
+ {
+ o->peer_.assign(o->protocol_,
+ typename Socket::native_handle_type(
+ o->new_socket_.get(), peer_endpoint), ec);
+ if (!ec)
+ o->new_socket_.release();
+ }
+
+ // Pass endpoint back to caller.
+ if (o->peer_endpoint_)
+ *o->peer_endpoint_ = peer_endpoint;
+ }
+
+ ASIO_HANDLER_COMPLETION((*o));
+
+ // 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::binder1<Handler, asio::error_code>
+ handler(o->handler_, ec);
+ p.h = asio::detail::addressof(handler.handler_);
+ p.reset();
+
+ // Make the upcall if required.
+ if (owner)
+ {
+ fenced_block b(fenced_block::half);
+ ASIO_HANDLER_INVOCATION_BEGIN((handler.arg1_));
+ w.complete(handler, handler.handler_);
+ ASIO_HANDLER_INVOCATION_END;
+ }
+ }
+
+private:
+ win_iocp_socket_service_base& socket_service_;
+ socket_type socket_;
+ socket_holder new_socket_;
+ Socket& peer_;
+ Protocol protocol_;
+ typename Protocol::endpoint* peer_endpoint_;
+ unsigned char output_buffer_[(sizeof(sockaddr_storage_type) + 16) * 2];
+ bool enable_connection_aborted_;
+ Handler handler_;
+};
+
+#if defined(ASIO_HAS_MOVE)
+
+template <typename Protocol, typename Handler>
+class win_iocp_socket_move_accept_op : public operation
+{
+public:
+ ASIO_DEFINE_HANDLER_PTR(win_iocp_socket_move_accept_op);
+
+ win_iocp_socket_move_accept_op(
+ win_iocp_socket_service_base& socket_service, socket_type socket,
+ const Protocol& protocol, asio::io_context& peer_io_context,
+ typename Protocol::endpoint* peer_endpoint,
+ bool enable_connection_aborted, Handler& handler)
+ : operation(&win_iocp_socket_move_accept_op::do_complete),
+ socket_service_(socket_service),
+ socket_(socket),
+ peer_(peer_io_context),
+ protocol_(protocol),
+ peer_endpoint_(peer_endpoint),
+ enable_connection_aborted_(enable_connection_aborted),
+ handler_(ASIO_MOVE_CAST(Handler)(handler))
+ {
+ handler_work<Handler>::start(handler_);
+ }
+
+ socket_holder& new_socket()
+ {
+ return new_socket_;
+ }
+
+ void* output_buffer()
+ {
+ return output_buffer_;
+ }
+
+ DWORD address_length()
+ {
+ return sizeof(sockaddr_storage_type) + 16;
+ }
+
+ static void do_complete(void* owner, operation* base,
+ const asio::error_code& result_ec,
+ std::size_t /*bytes_transferred*/)
+ {
+ asio::error_code ec(result_ec);
+
+ // Take ownership of the operation object.
+ win_iocp_socket_move_accept_op* o(
+ static_cast<win_iocp_socket_move_accept_op*>(base));
+ ptr p = { asio::detail::addressof(o->handler_), o, o };
+ handler_work<Handler> w(o->handler_);
+
+ if (owner)
+ {
+ typename Protocol::endpoint peer_endpoint;
+ std::size_t addr_len = peer_endpoint.capacity();
+ socket_ops::complete_iocp_accept(o->socket_,
+ o->output_buffer(), o->address_length(),
+ peer_endpoint.data(), &addr_len,
+ o->new_socket_.get(), ec);
+
+ // Restart the accept operation if we got the connection_aborted error
+ // and the enable_connection_aborted socket option is not set.
+ if (ec == asio::error::connection_aborted
+ && !o->enable_connection_aborted_)
+ {
+ o->reset();
+ o->socket_service_.restart_accept_op(o->socket_,
+ o->new_socket_, o->protocol_.family(),
+ o->protocol_.type(), o->protocol_.protocol(),
+ o->output_buffer(), o->address_length(), o);
+ p.v = p.p = 0;
+ return;
+ }
+
+ // If the socket was successfully accepted, transfer ownership of the
+ // socket to the peer object.
+ if (!ec)
+ {
+ o->peer_.assign(o->protocol_,
+ typename Protocol::socket::native_handle_type(
+ o->new_socket_.get(), peer_endpoint), ec);
+ if (!ec)
+ o->new_socket_.release();
+ }
+
+ // Pass endpoint back to caller.
+ if (o->peer_endpoint_)
+ *o->peer_endpoint_ = peer_endpoint;
+ }
+
+ ASIO_HANDLER_COMPLETION((*o));
+
+ // 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::move_binder2<Handler,
+ asio::error_code, typename Protocol::socket>
+ handler(0, ASIO_MOVE_CAST(Handler)(o->handler_), ec,
+ ASIO_MOVE_CAST(typename Protocol::socket)(o->peer_));
+ p.h = asio::detail::addressof(handler.handler_);
+ p.reset();
+
+ // Make the upcall if required.
+ if (owner)
+ {
+ fenced_block b(fenced_block::half);
+ ASIO_HANDLER_INVOCATION_BEGIN((handler.arg1_, "..."));
+ w.complete(handler, handler.handler_);
+ ASIO_HANDLER_INVOCATION_END;
+ }
+ }
+
+private:
+ win_iocp_socket_service_base& socket_service_;
+ socket_type socket_;
+ socket_holder new_socket_;
+ typename Protocol::socket peer_;
+ Protocol protocol_;
+ typename Protocol::endpoint* peer_endpoint_;
+ unsigned char output_buffer_[(sizeof(sockaddr_storage_type) + 16) * 2];
+ bool enable_connection_aborted_;
+ Handler handler_;
+};
+
+#endif // defined(ASIO_HAS_MOVE)
+
+} // namespace detail
+} // namespace asio
+
+#include "asio/detail/pop_options.hpp"
+
+#endif // defined(ASIO_HAS_IOCP)
+
+#endif // ASIO_DETAIL_WIN_IOCP_SOCKET_ACCEPT_OP_HPP
diff --git a/lib/asio/detail/win_iocp_socket_connect_op.hpp b/lib/asio/detail/win_iocp_socket_connect_op.hpp
new file mode 100644
index 0000000..e0c52dc
--- /dev/null
+++ b/lib/asio/detail/win_iocp_socket_connect_op.hpp
@@ -0,0 +1,127 @@
+//
+// detail/win_iocp_socket_connect_op.hpp
+// ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+//
+// Copyright (c) 2003-2018 Christopher M. Kohlhoff (chris at kohlhoff dot com)
+//
+// 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 ASIO_DETAIL_WIN_IOCP_SOCKET_CONNECT_OP_HPP
+#define ASIO_DETAIL_WIN_IOCP_SOCKET_CONNECT_OP_HPP
+
+#if defined(_MSC_VER) && (_MSC_VER >= 1200)
+# pragma once
+#endif // defined(_MSC_VER) && (_MSC_VER >= 1200)
+
+#include "asio/detail/config.hpp"
+
+#if defined(ASIO_HAS_IOCP)
+
+#include "asio/detail/bind_handler.hpp"
+#include "asio/detail/fenced_block.hpp"
+#include "asio/detail/handler_alloc_helpers.hpp"
+#include "asio/detail/handler_invoke_helpers.hpp"
+#include "asio/detail/memory.hpp"
+#include "asio/detail/reactor_op.hpp"
+#include "asio/detail/socket_ops.hpp"
+#include "asio/error.hpp"
+
+#include "asio/detail/push_options.hpp"
+
+namespace asio {
+namespace detail {
+
+class win_iocp_socket_connect_op_base : public reactor_op
+{
+public:
+ win_iocp_socket_connect_op_base(socket_type socket, func_type complete_func)
+ : reactor_op(&win_iocp_socket_connect_op_base::do_perform, complete_func),
+ socket_(socket),
+ connect_ex_(false)
+ {
+ }
+
+ static status do_perform(reactor_op* base)
+ {
+ win_iocp_socket_connect_op_base* o(
+ static_cast<win_iocp_socket_connect_op_base*>(base));
+
+ return socket_ops::non_blocking_connect(
+ o->socket_, o->ec_) ? done : not_done;
+ }
+
+ socket_type socket_;
+ bool connect_ex_;
+};
+
+template <typename Handler>
+class win_iocp_socket_connect_op : public win_iocp_socket_connect_op_base
+{
+public:
+ ASIO_DEFINE_HANDLER_PTR(win_iocp_socket_connect_op);
+
+ win_iocp_socket_connect_op(socket_type socket, Handler& handler)
+ : win_iocp_socket_connect_op_base(socket,
+ &win_iocp_socket_connect_op::do_complete),
+ handler_(ASIO_MOVE_CAST(Handler)(handler))
+ {
+ handler_work<Handler>::start(handler_);
+ }
+
+ static void do_complete(void* owner, operation* base,
+ const asio::error_code& result_ec,
+ std::size_t /*bytes_transferred*/)
+ {
+ asio::error_code ec(result_ec);
+
+ // Take ownership of the operation object.
+ win_iocp_socket_connect_op* o(
+ static_cast<win_iocp_socket_connect_op*>(base));
+ ptr p = { asio::detail::addressof(o->handler_), o, o };
+ handler_work<Handler> w(o->handler_);
+
+ if (owner)
+ {
+ if (o->connect_ex_)
+ socket_ops::complete_iocp_connect(o->socket_, ec);
+ else
+ ec = o->ec_;
+ }
+
+ ASIO_HANDLER_COMPLETION((*o));
+
+ // 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::binder1<Handler, asio::error_code>
+ handler(o->handler_, ec);
+ p.h = asio::detail::addressof(handler.handler_);
+ p.reset();
+
+ // Make the upcall if required.
+ if (owner)
+ {
+ fenced_block b(fenced_block::half);
+ ASIO_HANDLER_INVOCATION_BEGIN((handler.arg1_));
+ w.complete(handler, handler.handler_);
+ ASIO_HANDLER_INVOCATION_END;
+ }
+ }
+
+private:
+ Handler handler_;
+};
+
+} // namespace detail
+} // namespace asio
+
+#include "asio/detail/pop_options.hpp"
+
+#endif // defined(ASIO_HAS_IOCP)
+
+#endif // ASIO_DETAIL_WIN_IOCP_SOCKET_CONNECT_OP_HPP
diff --git a/lib/asio/detail/win_iocp_socket_recv_op.hpp b/lib/asio/detail/win_iocp_socket_recv_op.hpp
new file mode 100644
index 0000000..4159540
--- /dev/null
+++ b/lib/asio/detail/win_iocp_socket_recv_op.hpp
@@ -0,0 +1,117 @@
+//
+// detail/win_iocp_socket_recv_op.hpp
+// ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+//
+// Copyright (c) 2003-2018 Christopher M. Kohlhoff (chris at kohlhoff dot com)
+//
+// 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 ASIO_DETAIL_WIN_IOCP_SOCKET_RECV_OP_HPP
+#define ASIO_DETAIL_WIN_IOCP_SOCKET_RECV_OP_HPP
+
+#if defined(_MSC_VER) && (_MSC_VER >= 1200)
+# pragma once
+#endif // defined(_MSC_VER) && (_MSC_VER >= 1200)
+
+#include "asio/detail/config.hpp"
+
+#if defined(ASIO_HAS_IOCP)
+
+#include "asio/detail/bind_handler.hpp"
+#include "asio/detail/buffer_sequence_adapter.hpp"
+#include "asio/detail/fenced_block.hpp"
+#include "asio/detail/handler_alloc_helpers.hpp"
+#include "asio/detail/handler_invoke_helpers.hpp"
+#include "asio/detail/memory.hpp"
+#include "asio/detail/operation.hpp"
+#include "asio/detail/socket_ops.hpp"
+#include "asio/error.hpp"
+
+#include "asio/detail/push_options.hpp"
+
+namespace asio {
+namespace detail {
+
+template <typename MutableBufferSequence, typename Handler>
+class win_iocp_socket_recv_op : public operation
+{
+public:
+ ASIO_DEFINE_HANDLER_PTR(win_iocp_socket_recv_op);
+
+ win_iocp_socket_recv_op(socket_ops::state_type state,
+ socket_ops::weak_cancel_token_type cancel_token,
+ const MutableBufferSequence& buffers, Handler& handler)
+ : operation(&win_iocp_socket_recv_op::do_complete),
+ state_(state),
+ cancel_token_(cancel_token),
+ buffers_(buffers),
+ handler_(ASIO_MOVE_CAST(Handler)(handler))
+ {
+ handler_work<Handler>::start(handler_);
+ }
+
+ static void do_complete(void* owner, operation* base,
+ const asio::error_code& result_ec,
+ std::size_t bytes_transferred)
+ {
+ asio::error_code ec(result_ec);
+
+ // Take ownership of the operation object.
+ win_iocp_socket_recv_op* o(static_cast<win_iocp_socket_recv_op*>(base));
+ ptr p = { asio::detail::addressof(o->handler_), o, o };
+ handler_work<Handler> w(o->handler_);
+
+ ASIO_HANDLER_COMPLETION((*o));
+
+#if defined(ASIO_ENABLE_BUFFER_DEBUGGING)
+ // Check whether buffers are still valid.
+ if (owner)
+ {
+ buffer_sequence_adapter<asio::mutable_buffer,
+ MutableBufferSequence>::validate(o->buffers_);
+ }
+#endif // defined(ASIO_ENABLE_BUFFER_DEBUGGING)
+
+ socket_ops::complete_iocp_recv(o->state_, o->cancel_token_,
+ buffer_sequence_adapter<asio::mutable_buffer,
+ MutableBufferSequence>::all_empty(o->buffers_),
+ ec, bytes_transferred);
+
+ // 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::binder2<Handler, asio::error_code, std::size_t>
+ handler(o->handler_, ec, bytes_transferred);
+ p.h = asio::detail::addressof(handler.handler_);
+ p.reset();
+
+ // Make the upcall if required.
+ if (owner)
+ {
+ fenced_block b(fenced_block::half);
+ ASIO_HANDLER_INVOCATION_BEGIN((handler.arg1_, handler.arg2_));
+ w.complete(handler, handler.handler_);
+ ASIO_HANDLER_INVOCATION_END;
+ }
+ }
+
+private:
+ socket_ops::state_type state_;
+ socket_ops::weak_cancel_token_type cancel_token_;
+ MutableBufferSequence buffers_;
+ Handler handler_;
+};
+
+} // namespace detail
+} // namespace asio
+
+#include "asio/detail/pop_options.hpp"
+
+#endif // defined(ASIO_HAS_IOCP)
+
+#endif // ASIO_DETAIL_WIN_IOCP_SOCKET_RECV_OP_HPP
diff --git a/lib/asio/detail/win_iocp_socket_recvfrom_op.hpp b/lib/asio/detail/win_iocp_socket_recvfrom_op.hpp
new file mode 100644
index 0000000..843ce5b
--- /dev/null
+++ b/lib/asio/detail/win_iocp_socket_recvfrom_op.hpp
@@ -0,0 +1,125 @@
+//
+// detail/win_iocp_socket_recvfrom_op.hpp
+// ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+//
+// Copyright (c) 2003-2018 Christopher M. Kohlhoff (chris at kohlhoff dot com)
+//
+// 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 ASIO_DETAIL_WIN_IOCP_SOCKET_RECVFROM_OP_HPP
+#define ASIO_DETAIL_WIN_IOCP_SOCKET_RECVFROM_OP_HPP
+
+#if defined(_MSC_VER) && (_MSC_VER >= 1200)
+# pragma once
+#endif // defined(_MSC_VER) && (_MSC_VER >= 1200)
+
+#include "asio/detail/config.hpp"
+
+#if defined(ASIO_HAS_IOCP)
+
+#include "asio/detail/bind_handler.hpp"
+#include "asio/detail/buffer_sequence_adapter.hpp"
+#include "asio/detail/fenced_block.hpp"
+#include "asio/detail/handler_alloc_helpers.hpp"
+#include "asio/detail/handler_invoke_helpers.hpp"
+#include "asio/detail/memory.hpp"
+#include "asio/detail/operation.hpp"
+#include "asio/detail/socket_ops.hpp"
+#include "asio/error.hpp"
+
+#include "asio/detail/push_options.hpp"
+
+namespace asio {
+namespace detail {
+
+template <typename MutableBufferSequence, typename Endpoint, typename Handler>
+class win_iocp_socket_recvfrom_op : public operation
+{
+public:
+ ASIO_DEFINE_HANDLER_PTR(win_iocp_socket_recvfrom_op);
+
+ win_iocp_socket_recvfrom_op(Endpoint& endpoint,
+ socket_ops::weak_cancel_token_type cancel_token,
+ const MutableBufferSequence& buffers, Handler& handler)
+ : operation(&win_iocp_socket_recvfrom_op::do_complete),
+ endpoint_(endpoint),
+ endpoint_size_(static_cast<int>(endpoint.capacity())),
+ cancel_token_(cancel_token),
+ buffers_(buffers),
+ handler_(ASIO_MOVE_CAST(Handler)(handler))
+ {
+ handler_work<Handler>::start(handler_);
+ }
+
+ int& endpoint_size()
+ {
+ return endpoint_size_;
+ }
+
+ static void do_complete(void* owner, operation* base,
+ const asio::error_code& result_ec,
+ std::size_t bytes_transferred)
+ {
+ asio::error_code ec(result_ec);
+
+ // Take ownership of the operation object.
+ win_iocp_socket_recvfrom_op* o(
+ static_cast<win_iocp_socket_recvfrom_op*>(base));
+ ptr p = { asio::detail::addressof(o->handler_), o, o };
+ handler_work<Handler> w(o->handler_);
+
+ ASIO_HANDLER_COMPLETION((*o));
+
+#if defined(ASIO_ENABLE_BUFFER_DEBUGGING)
+ // Check whether buffers are still valid.
+ if (owner)
+ {
+ buffer_sequence_adapter<asio::mutable_buffer,
+ MutableBufferSequence>::validate(o->buffers_);
+ }
+#endif // defined(ASIO_ENABLE_BUFFER_DEBUGGING)
+
+ socket_ops::complete_iocp_recvfrom(o->cancel_token_, ec);
+
+ // Record the size of the endpoint returned by the operation.
+ o->endpoint_.resize(o->endpoint_size_);
+
+ // 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::binder2<Handler, asio::error_code, std::size_t>
+ handler(o->handler_, ec, bytes_transferred);
+ p.h = asio::detail::addressof(handler.handler_);
+ p.reset();
+
+ // Make the upcall if required.
+ if (owner)
+ {
+ fenced_block b(fenced_block::half);
+ ASIO_HANDLER_INVOCATION_BEGIN((handler.arg1_, handler.arg2_));
+ w.complete(handler, handler.handler_);
+ ASIO_HANDLER_INVOCATION_END;
+ }
+ }
+
+private:
+ Endpoint& endpoint_;
+ int endpoint_size_;
+ socket_ops::weak_cancel_token_type cancel_token_;
+ MutableBufferSequence buffers_;
+ Handler handler_;
+};
+
+} // namespace detail
+} // namespace asio
+
+#include "asio/detail/pop_options.hpp"
+
+#endif // defined(ASIO_HAS_IOCP)
+
+#endif // ASIO_DETAIL_WIN_IOCP_SOCKET_RECVFROM_OP_HPP
diff --git a/lib/asio/detail/win_iocp_socket_recvmsg_op.hpp b/lib/asio/detail/win_iocp_socket_recvmsg_op.hpp
new file mode 100644
index 0000000..78f36b7
--- /dev/null
+++ b/lib/asio/detail/win_iocp_socket_recvmsg_op.hpp
@@ -0,0 +1,118 @@
+//
+// detail/win_iocp_socket_recvmsg_op.hpp
+// ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+//
+// Copyright (c) 2003-2018 Christopher M. Kohlhoff (chris at kohlhoff dot com)
+//
+// 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 ASIO_DETAIL_WIN_IOCP_SOCKET_RECVMSG_OP_HPP
+#define ASIO_DETAIL_WIN_IOCP_SOCKET_RECVMSG_OP_HPP
+
+#if defined(_MSC_VER) && (_MSC_VER >= 1200)
+# pragma once
+#endif // defined(_MSC_VER) && (_MSC_VER >= 1200)
+
+#include "asio/detail/config.hpp"
+
+#if defined(ASIO_HAS_IOCP)
+
+#include "asio/detail/bind_handler.hpp"
+#include "asio/detail/buffer_sequence_adapter.hpp"
+#include "asio/detail/fenced_block.hpp"
+#include "asio/detail/handler_alloc_helpers.hpp"
+#include "asio/detail/handler_invoke_helpers.hpp"
+#include "asio/detail/memory.hpp"
+#include "asio/detail/operation.hpp"
+#include "asio/detail/socket_ops.hpp"
+#include "asio/error.hpp"
+#include "asio/socket_base.hpp"
+
+#include "asio/detail/push_options.hpp"
+
+namespace asio {
+namespace detail {
+
+template <typename MutableBufferSequence, typename Handler>
+class win_iocp_socket_recvmsg_op : public operation
+{
+public:
+ ASIO_DEFINE_HANDLER_PTR(win_iocp_socket_recvmsg_op);
+
+ win_iocp_socket_recvmsg_op(
+ socket_ops::weak_cancel_token_type cancel_token,
+ const MutableBufferSequence& buffers,
+ socket_base::message_flags& out_flags, Handler& handler)
+ : operation(&win_iocp_socket_recvmsg_op::do_complete),
+ cancel_token_(cancel_token),
+ buffers_(buffers),
+ out_flags_(out_flags),
+ handler_(ASIO_MOVE_CAST(Handler)(handler))
+ {
+ handler_work<Handler>::start(handler_);
+ }
+
+ static void do_complete(void* owner, operation* base,
+ const asio::error_code& result_ec,
+ std::size_t bytes_transferred)
+ {
+ asio::error_code ec(result_ec);
+
+ // Take ownership of the operation object.
+ win_iocp_socket_recvmsg_op* o(
+ static_cast<win_iocp_socket_recvmsg_op*>(base));
+ ptr p = { asio::detail::addressof(o->handler_), o, o };
+ handler_work<Handler> w(o->handler_);
+
+ ASIO_HANDLER_COMPLETION((*o));
+
+#if defined(ASIO_ENABLE_BUFFER_DEBUGGING)
+ // Check whether buffers are still valid.
+ if (owner)
+ {
+ buffer_sequence_adapter<asio::mutable_buffer,
+ MutableBufferSequence>::validate(o->buffers_);
+ }
+#endif // defined(ASIO_ENABLE_BUFFER_DEBUGGING)
+
+ socket_ops::complete_iocp_recvmsg(o->cancel_token_, ec);
+ o->out_flags_ = 0;
+
+ // 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::binder2<Handler, asio::error_code, std::size_t>
+ handler(o->handler_, ec, bytes_transferred);
+ p.h = asio::detail::addressof(handler.handler_);
+ p.reset();
+
+ // Make the upcall if required.
+ if (owner)
+ {
+ fenced_block b(fenced_block::half);
+ ASIO_HANDLER_INVOCATION_BEGIN((handler.arg1_, handler.arg2_));
+ w.complete(handler, handler.handler_);
+ ASIO_HANDLER_INVOCATION_END;
+ }
+ }
+
+private:
+ socket_ops::weak_cancel_token_type cancel_token_;
+ MutableBufferSequence buffers_;
+ socket_base::message_flags& out_flags_;
+ Handler handler_;
+};
+
+} // namespace detail
+} // namespace asio
+
+#include "asio/detail/pop_options.hpp"
+
+#endif // defined(ASIO_HAS_IOCP)
+
+#endif // ASIO_DETAIL_WIN_IOCP_SOCKET_RECVMSG_OP_HPP
diff --git a/lib/asio/detail/win_iocp_socket_send_op.hpp b/lib/asio/detail/win_iocp_socket_send_op.hpp
new file mode 100644
index 0000000..e1c7ab9
--- /dev/null
+++ b/lib/asio/detail/win_iocp_socket_send_op.hpp
@@ -0,0 +1,111 @@
+//
+// detail/win_iocp_socket_send_op.hpp
+// ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+//
+// Copyright (c) 2003-2018 Christopher M. Kohlhoff (chris at kohlhoff dot com)
+//
+// 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 ASIO_DETAIL_WIN_IOCP_SOCKET_SEND_OP_HPP
+#define ASIO_DETAIL_WIN_IOCP_SOCKET_SEND_OP_HPP
+
+#if defined(_MSC_VER) && (_MSC_VER >= 1200)
+# pragma once
+#endif // defined(_MSC_VER) && (_MSC_VER >= 1200)
+
+#include "asio/detail/config.hpp"
+
+#if defined(ASIO_HAS_IOCP)
+
+#include "asio/detail/bind_handler.hpp"
+#include "asio/detail/buffer_sequence_adapter.hpp"
+#include "asio/detail/fenced_block.hpp"
+#include "asio/detail/handler_alloc_helpers.hpp"
+#include "asio/detail/handler_invoke_helpers.hpp"
+#include "asio/detail/memory.hpp"
+#include "asio/detail/operation.hpp"
+#include "asio/detail/socket_ops.hpp"
+#include "asio/error.hpp"
+
+#include "asio/detail/push_options.hpp"
+
+namespace asio {
+namespace detail {
+
+template <typename ConstBufferSequence, typename Handler>
+class win_iocp_socket_send_op : public operation
+{
+public:
+ ASIO_DEFINE_HANDLER_PTR(win_iocp_socket_send_op);
+
+ win_iocp_socket_send_op(socket_ops::weak_cancel_token_type cancel_token,
+ const ConstBufferSequence& buffers, Handler& handler)
+ : operation(&win_iocp_socket_send_op::do_complete),
+ cancel_token_(cancel_token),
+ buffers_(buffers),
+ handler_(ASIO_MOVE_CAST(Handler)(handler))
+ {
+ handler_work<Handler>::start(handler_);
+ }
+
+ static void do_complete(void* owner, operation* base,
+ const asio::error_code& result_ec,
+ std::size_t bytes_transferred)
+ {
+ asio::error_code ec(result_ec);
+
+ // Take ownership of the operation object.
+ win_iocp_socket_send_op* o(static_cast<win_iocp_socket_send_op*>(base));
+ ptr p = { asio::detail::addressof(o->handler_), o, o };
+ handler_work<Handler> w(o->handler_);
+
+ ASIO_HANDLER_COMPLETION((*o));
+
+#if defined(ASIO_ENABLE_BUFFER_DEBUGGING)
+ // Check whether buffers are still valid.
+ if (owner)
+ {
+ buffer_sequence_adapter<asio::const_buffer,
+ ConstBufferSequence>::validate(o->buffers_);
+ }
+#endif // defined(ASIO_ENABLE_BUFFER_DEBUGGING)
+
+ socket_ops::complete_iocp_send(o->cancel_token_, ec);
+
+ // 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::binder2<Handler, asio::error_code, std::size_t>
+ handler(o->handler_, ec, bytes_transferred);
+ p.h = asio::detail::addressof(handler.handler_);
+ p.reset();
+
+ // Make the upcall if required.
+ if (owner)
+ {
+ fenced_block b(fenced_block::half);
+ ASIO_HANDLER_INVOCATION_BEGIN((handler.arg1_, handler.arg2_));
+ w.complete(handler, handler.handler_);
+ ASIO_HANDLER_INVOCATION_END;
+ }
+ }
+
+private:
+ socket_ops::weak_cancel_token_type cancel_token_;
+ ConstBufferSequence buffers_;
+ Handler handler_;
+};
+
+} // namespace detail
+} // namespace asio
+
+#include "asio/detail/pop_options.hpp"
+
+#endif // defined(ASIO_HAS_IOCP)
+
+#endif // ASIO_DETAIL_WIN_IOCP_SOCKET_SEND_OP_HPP
diff --git a/lib/asio/detail/win_iocp_socket_service.hpp b/lib/asio/detail/win_iocp_socket_service.hpp
new file mode 100644
index 0000000..3f01b4d
--- /dev/null
+++ b/lib/asio/detail/win_iocp_socket_service.hpp
@@ -0,0 +1,599 @@
+//
+// detail/win_iocp_socket_service.hpp
+// ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+//
+// Copyright (c) 2003-2018 Christopher M. Kohlhoff (chris at kohlhoff dot com)
+//
+// 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 ASIO_DETAIL_WIN_IOCP_SOCKET_SERVICE_HPP
+#define ASIO_DETAIL_WIN_IOCP_SOCKET_SERVICE_HPP
+
+#if defined(_MSC_VER) && (_MSC_VER >= 1200)
+# pragma once
+#endif // defined(_MSC_VER) && (_MSC_VER >= 1200)
+
+#include "asio/detail/config.hpp"
+
+#if defined(ASIO_HAS_IOCP)
+
+#include <cstring>
+#include "asio/error.hpp"
+#include "asio/io_context.hpp"
+#include "asio/socket_base.hpp"
+#include "asio/detail/bind_handler.hpp"
+#include "asio/detail/buffer_sequence_adapter.hpp"
+#include "asio/detail/fenced_block.hpp"
+#include "asio/detail/handler_alloc_helpers.hpp"
+#include "asio/detail/handler_invoke_helpers.hpp"
+#include "asio/detail/memory.hpp"
+#include "asio/detail/mutex.hpp"
+#include "asio/detail/operation.hpp"
+#include "asio/detail/reactor_op.hpp"
+#include "asio/detail/select_reactor.hpp"
+#include "asio/detail/socket_holder.hpp"
+#include "asio/detail/socket_ops.hpp"
+#include "asio/detail/socket_types.hpp"
+#include "asio/detail/win_iocp_io_context.hpp"
+#include "asio/detail/win_iocp_null_buffers_op.hpp"
+#include "asio/detail/win_iocp_socket_accept_op.hpp"
+#include "asio/detail/win_iocp_socket_connect_op.hpp"
+#include "asio/detail/win_iocp_socket_recvfrom_op.hpp"
+#include "asio/detail/win_iocp_socket_send_op.hpp"
+#include "asio/detail/win_iocp_socket_service_base.hpp"
+
+#include "asio/detail/push_options.hpp"
+
+namespace asio {
+namespace detail {
+
+template <typename Protocol>
+class win_iocp_socket_service :
+ public service_base<win_iocp_socket_service<Protocol> >,
+ public win_iocp_socket_service_base
+{
+public:
+ // The protocol type.
+ typedef Protocol protocol_type;
+
+ // The endpoint type.
+ typedef typename Protocol::endpoint endpoint_type;
+
+ // The native type of a socket.
+ class native_handle_type
+ {
+ public:
+ native_handle_type(socket_type s)
+ : socket_(s),
+ have_remote_endpoint_(false)
+ {
+ }
+
+ native_handle_type(socket_type s, const endpoint_type& ep)
+ : socket_(s),
+ have_remote_endpoint_(true),
+ remote_endpoint_(ep)
+ {
+ }
+
+ void operator=(socket_type s)
+ {
+ socket_ = s;
+ have_remote_endpoint_ = false;
+ remote_endpoint_ = endpoint_type();
+ }
+
+ operator socket_type() const
+ {
+ return socket_;
+ }
+
+ bool have_remote_endpoint() const
+ {
+ return have_remote_endpoint_;
+ }
+
+ endpoint_type remote_endpoint() const
+ {
+ return remote_endpoint_;
+ }
+
+ private:
+ socket_type socket_;
+ bool have_remote_endpoint_;
+ endpoint_type remote_endpoint_;
+ };
+
+ // The implementation type of the socket.
+ struct implementation_type :
+ win_iocp_socket_service_base::base_implementation_type
+ {
+ // Default constructor.
+ implementation_type()
+ : protocol_(endpoint_type().protocol()),
+ have_remote_endpoint_(false),
+ remote_endpoint_()
+ {
+ }
+
+ // The protocol associated with the socket.
+ protocol_type protocol_;
+
+ // Whether we have a cached remote endpoint.
+ bool have_remote_endpoint_;
+
+ // A cached remote endpoint.
+ endpoint_type remote_endpoint_;
+ };
+
+ // Constructor.
+ win_iocp_socket_service(asio::io_context& io_context)
+ : service_base<win_iocp_socket_service<Protocol> >(io_context),
+ win_iocp_socket_service_base(io_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();
+
+ impl.have_remote_endpoint_ = other_impl.have_remote_endpoint_;
+ other_impl.have_remote_endpoint_ = false;
+
+ impl.remote_endpoint_ = other_impl.remote_endpoint_;
+ other_impl.remote_endpoint_ = endpoint_type();
+ }
+
+ // Move-assign from another socket implementation.
+ void move_assign(implementation_type& impl,
+ win_iocp_socket_service_base& 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();
+
+ impl.have_remote_endpoint_ = other_impl.have_remote_endpoint_;
+ other_impl.have_remote_endpoint_ = false;
+
+ impl.remote_endpoint_ = other_impl.remote_endpoint_;
+ other_impl.remote_endpoint_ = endpoint_type();
+ }
+
+ // Move-construct a new socket implementation from another protocol type.
+ template <typename Protocol1>
+ void converting_move_construct(implementation_type& impl,
+ win_iocp_socket_service<Protocol1>&,
+ typename win_iocp_socket_service<
+ 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();
+
+ impl.have_remote_endpoint_ = other_impl.have_remote_endpoint_;
+ other_impl.have_remote_endpoint_ = false;
+
+ impl.remote_endpoint_ = other_impl.remote_endpoint_;
+ other_impl.remote_endpoint_ = typename Protocol1::endpoint();
+ }
+
+ // Open a new socket implementation.
+ asio::error_code open(implementation_type& impl,
+ const protocol_type& protocol, asio::error_code& ec)
+ {
+ if (!do_open(impl, protocol.family(),
+ protocol.type(), protocol.protocol(), ec))
+ {
+ impl.protocol_ = protocol;
+ impl.have_remote_endpoint_ = false;
+ impl.remote_endpoint_ = endpoint_type();
+ }
+ return ec;
+ }
+
+ // Assign a native socket to a socket implementation.
+ asio::error_code assign(implementation_type& impl,
+ const protocol_type& protocol, const native_handle_type& native_socket,
+ asio::error_code& ec)
+ {
+ if (!do_assign(impl, protocol.type(), native_socket, ec))
+ {
+ impl.protocol_ = protocol;
+ impl.have_remote_endpoint_ = native_socket.have_remote_endpoint();
+ impl.remote_endpoint_ = native_socket.remote_endpoint();
+ }
+ return ec;
+ }
+
+ // Get the native socket representation.
+ native_handle_type native_handle(implementation_type& impl)
+ {
+ if (impl.have_remote_endpoint_)
+ return native_handle_type(impl.socket_, impl.remote_endpoint_);
+ return native_handle_type(impl.socket_);
+ }
+
+ // Bind the socket to the specified local endpoint.
+ asio::error_code bind(implementation_type& impl,
+ const endpoint_type& endpoint, asio::error_code& ec)
+ {
+ socket_ops::bind(impl.socket_, endpoint.data(), endpoint.size(), ec);
+ return ec;
+ }
+
+ // Set a socket option.
+ template <typename Option>
+ asio::error_code set_option(implementation_type& impl,
+ const Option& option, asio::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>
+ asio::error_code get_option(const implementation_type& impl,
+ Option& option, asio::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,
+ asio::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,
+ asio::error_code& ec) const
+ {
+ endpoint_type endpoint = impl.remote_endpoint_;
+ std::size_t addr_len = endpoint.capacity();
+ if (socket_ops::getpeername(impl.socket_, endpoint.data(),
+ &addr_len, impl.have_remote_endpoint_, ec))
+ return endpoint_type();
+ endpoint.resize(addr_len);
+ return endpoint;
+ }
+
+ // Disable sends or receives on the socket.
+ asio::error_code shutdown(base_implementation_type& impl,
+ socket_base::shutdown_type what, asio::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,
+ asio::error_code& ec)
+ {
+ buffer_sequence_adapter<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,
+ asio::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>
+ void async_send_to(implementation_type& impl,
+ const ConstBufferSequence& buffers, const endpoint_type& destination,
+ socket_base::message_flags flags, Handler& handler)
+ {
+ // Allocate and construct an operation to wrap the handler.
+ typedef win_iocp_socket_send_op<ConstBufferSequence, Handler> op;
+ typename op::ptr p = { asio::detail::addressof(handler),
+ op::ptr::allocate(handler), 0 };
+ p.p = new (p.v) op(impl.cancel_token_, buffers, handler);
+
+ ASIO_HANDLER_CREATION((io_context_, *p.p, "socket",
+ &impl, impl.socket_, "async_send_to"));
+
+ buffer_sequence_adapter<asio::const_buffer,
+ ConstBufferSequence> bufs(buffers);
+
+ start_send_to_op(impl, bufs.buffers(), bufs.count(),
+ destination.data(), static_cast<int>(destination.size()),
+ flags, p.p);
+ p.v = p.p = 0;
+ }
+
+ // Start an asynchronous wait until data can be sent without blocking.
+ template <typename Handler>
+ void async_send_to(implementation_type& impl, const null_buffers&,
+ const endpoint_type&, socket_base::message_flags, Handler& handler)
+ {
+ // Allocate and construct an operation to wrap the handler.
+ typedef win_iocp_null_buffers_op<Handler> op;
+ typename op::ptr p = { asio::detail::addressof(handler),
+ op::ptr::allocate(handler), 0 };
+ p.p = new (p.v) op(impl.cancel_token_, handler);
+
+ ASIO_HANDLER_CREATION((io_context_, *p.p, "socket",
+ &impl, impl.socket_, "async_send_to(null_buffers)"));
+
+ start_reactor_op(impl, select_reactor::write_op, p.p);
+ 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,
+ asio::error_code& ec)
+ {
+ buffer_sequence_adapter<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, asio::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>
+ void async_receive_from(implementation_type& impl,
+ const MutableBufferSequence& buffers, endpoint_type& sender_endp,
+ socket_base::message_flags flags, Handler& handler)
+ {
+ // Allocate and construct an operation to wrap the handler.
+ typedef win_iocp_socket_recvfrom_op<
+ MutableBufferSequence, endpoint_type, Handler> op;
+ typename op::ptr p = { asio::detail::addressof(handler),
+ op::ptr::allocate(handler), 0 };
+ p.p = new (p.v) op(sender_endp, impl.cancel_token_, buffers, handler);
+
+ ASIO_HANDLER_CREATION((io_context_, *p.p, "socket",
+ &impl, impl.socket_, "async_receive_from"));
+
+ buffer_sequence_adapter<asio::mutable_buffer,
+ MutableBufferSequence> bufs(buffers);
+
+ start_receive_from_op(impl, bufs.buffers(), bufs.count(),
+ sender_endp.data(), flags, &p.p->endpoint_size(), p.p);
+ p.v = p.p = 0;
+ }
+
+ // Wait until data can be received without blocking.
+ template <typename Handler>
+ void async_receive_from(implementation_type& impl,
+ const null_buffers&, endpoint_type& sender_endpoint,
+ socket_base::message_flags flags, Handler& handler)
+ {
+ // Allocate and construct an operation to wrap the handler.
+ typedef win_iocp_null_buffers_op<Handler> op;
+ typename op::ptr p = { asio::detail::addressof(handler),
+ op::ptr::allocate(handler), 0 };
+ p.p = new (p.v) op(impl.cancel_token_, handler);
+
+ ASIO_HANDLER_CREATION((io_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_null_buffers_receive_op(impl, flags, p.p);
+ p.v = p.p = 0;
+ }
+
+ // Accept a new connection.
+ template <typename Socket>
+ asio::error_code accept(implementation_type& impl, Socket& peer,
+ endpoint_type* peer_endpoint, asio::error_code& ec)
+ {
+ // We cannot accept a socket that is already open.
+ if (peer.is_open())
+ {
+ ec = 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;
+ }
+
+#if defined(ASIO_HAS_MOVE)
+ // Accept a new connection.
+ typename Protocol::socket accept(implementation_type& impl,
+ io_context* peer_io_context, endpoint_type* peer_endpoint,
+ asio::error_code& ec)
+ {
+ typename Protocol::socket peer(
+ peer_io_context ? *peer_io_context : io_context_);
+
+ 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 peer;
+ }
+#endif // defined(ASIO_HAS_MOVE)
+
+ // 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>
+ void async_accept(implementation_type& impl, Socket& peer,
+ endpoint_type* peer_endpoint, Handler& handler)
+ {
+ // Allocate and construct an operation to wrap the handler.
+ typedef win_iocp_socket_accept_op<Socket, protocol_type, Handler> op;
+ typename op::ptr p = { asio::detail::addressof(handler),
+ op::ptr::allocate(handler), 0 };
+ bool enable_connection_aborted =
+ (impl.state_ & socket_ops::enable_connection_aborted) != 0;
+ p.p = new (p.v) op(*this, impl.socket_, peer, impl.protocol_,
+ peer_endpoint, enable_connection_aborted, handler);
+
+ ASIO_HANDLER_CREATION((io_context_, *p.p, "socket",
+ &impl, impl.socket_, "async_accept"));
+
+ start_accept_op(impl, peer.is_open(), p.p->new_socket(),
+ impl.protocol_.family(), impl.protocol_.type(),
+ impl.protocol_.protocol(), p.p->output_buffer(),
+ p.p->address_length(), p.p);
+ p.v = p.p = 0;
+ }
+
+#if defined(ASIO_HAS_MOVE)
+ // Start an asynchronous accept. The peer and peer_endpoint objects
+ // must be valid until the accept's handler is invoked.
+ template <typename Handler>
+ void async_accept(implementation_type& impl,
+ asio::io_context* peer_io_context,
+ endpoint_type* peer_endpoint, Handler& handler)
+ {
+ // Allocate and construct an operation to wrap the handler.
+ typedef win_iocp_socket_move_accept_op<protocol_type, Handler> op;
+ typename op::ptr p = { asio::detail::addressof(handler),
+ op::ptr::allocate(handler), 0 };
+ bool enable_connection_aborted =
+ (impl.state_ & socket_ops::enable_connection_aborted) != 0;
+ p.p = new (p.v) op(*this, impl.socket_, impl.protocol_,
+ peer_io_context ? *peer_io_context : io_context_,
+ peer_endpoint, enable_connection_aborted, handler);
+
+ ASIO_HANDLER_CREATION((io_context_, *p.p, "socket",
+ &impl, impl.socket_, "async_accept"));
+
+ start_accept_op(impl, false, p.p->new_socket(),
+ impl.protocol_.family(), impl.protocol_.type(),
+ impl.protocol_.protocol(), p.p->output_buffer(),
+ p.p->address_length(), p.p);
+ p.v = p.p = 0;
+ }
+#endif // defined(ASIO_HAS_MOVE)
+
+ // Connect the socket to the specified endpoint.
+ asio::error_code connect(implementation_type& impl,
+ const endpoint_type& peer_endpoint, asio::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>
+ void async_connect(implementation_type& impl,
+ const endpoint_type& peer_endpoint, Handler& handler)
+ {
+ // Allocate and construct an operation to wrap the handler.
+ typedef win_iocp_socket_connect_op<Handler> op;
+ typename op::ptr p = { asio::detail::addressof(handler),
+ op::ptr::allocate(handler), 0 };
+ p.p = new (p.v) op(impl.socket_, handler);
+
+ ASIO_HANDLER_CREATION((io_context_, *p.p, "socket",
+ &impl, impl.socket_, "async_connect"));
+
+ start_connect_op(impl, impl.protocol_.family(), impl.protocol_.type(),
+ peer_endpoint.data(), static_cast<int>(peer_endpoint.size()), p.p);
+ p.v = p.p = 0;
+ }
+};
+
+} // namespace detail
+} // namespace asio
+
+#include "asio/detail/pop_options.hpp"
+
+#endif // defined(ASIO_HAS_IOCP)
+
+#endif // ASIO_DETAIL_WIN_IOCP_SOCKET_SERVICE_HPP
diff --git a/lib/asio/detail/win_iocp_socket_service_base.hpp b/lib/asio/detail/win_iocp_socket_service_base.hpp
new file mode 100644
index 0000000..ef1d718
--- /dev/null
+++ b/lib/asio/detail/win_iocp_socket_service_base.hpp
@@ -0,0 +1,591 @@
+//
+// detail/win_iocp_socket_service_base.hpp
+// ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+//
+// Copyright (c) 2003-2018 Christopher M. Kohlhoff (chris at kohlhoff dot com)
+//
+// 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 ASIO_DETAIL_WIN_IOCP_SOCKET_SERVICE_BASE_HPP
+#define ASIO_DETAIL_WIN_IOCP_SOCKET_SERVICE_BASE_HPP
+
+#if defined(_MSC_VER) && (_MSC_VER >= 1200)
+# pragma once
+#endif // defined(_MSC_VER) && (_MSC_VER >= 1200)
+
+#include "asio/detail/config.hpp"
+
+#if defined(ASIO_HAS_IOCP)
+
+#include "asio/error.hpp"
+#include "asio/io_context.hpp"
+#include "asio/socket_base.hpp"
+#include "asio/detail/bind_handler.hpp"
+#include "asio/detail/buffer_sequence_adapter.hpp"
+#include "asio/detail/fenced_block.hpp"
+#include "asio/detail/handler_alloc_helpers.hpp"
+#include "asio/detail/handler_invoke_helpers.hpp"
+#include "asio/detail/memory.hpp"
+#include "asio/detail/mutex.hpp"
+#include "asio/detail/operation.hpp"
+#include "asio/detail/reactor_op.hpp"
+#include "asio/detail/select_reactor.hpp"
+#include "asio/detail/socket_holder.hpp"
+#include "asio/detail/socket_ops.hpp"
+#include "asio/detail/socket_types.hpp"
+#include "asio/detail/win_iocp_io_context.hpp"
+#include "asio/detail/win_iocp_null_buffers_op.hpp"
+#include "asio/detail/win_iocp_socket_connect_op.hpp"
+#include "asio/detail/win_iocp_socket_send_op.hpp"
+#include "asio/detail/win_iocp_socket_recv_op.hpp"
+#include "asio/detail/win_iocp_socket_recvmsg_op.hpp"
+#include "asio/detail/win_iocp_wait_op.hpp"
+
+#include "asio/detail/push_options.hpp"
+
+namespace asio {
+namespace detail {
+
+class win_iocp_socket_service_base
+{
+public:
+ // 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_;
+
+ // We use a shared pointer as a cancellation token here to work around the
+ // broken Windows support for cancellation. MSDN says that when you call
+ // closesocket any outstanding WSARecv or WSASend operations will complete
+ // with the error ERROR_OPERATION_ABORTED. In practice they complete with
+ // ERROR_NETNAME_DELETED, which means you can't tell the difference between
+ // a local cancellation and the socket being hard-closed by the peer.
+ socket_ops::shared_cancel_token_type cancel_token_;
+
+ // Per-descriptor data used by the reactor.
+ select_reactor::per_descriptor_data reactor_data_;
+
+#if defined(ASIO_ENABLE_CANCELIO)
+ // The ID of the thread from which it is safe to cancel asynchronous
+ // operations. 0 means no asynchronous operations have been started yet.
+ // ~0 means asynchronous operations have been started from more than one
+ // thread, and cancellation is not supported for the socket.
+ DWORD safe_cancellation_thread_id_;
+#endif // defined(ASIO_ENABLE_CANCELIO)
+
+ // Pointers to adjacent socket implementations in linked list.
+ base_implementation_type* next_;
+ base_implementation_type* prev_;
+ };
+
+ // Constructor.
+ ASIO_DECL win_iocp_socket_service_base(
+ asio::io_context& io_context);
+
+ // Destroy all user-defined handler objects owned by the service.
+ ASIO_DECL void base_shutdown();
+
+ // Construct a new socket implementation.
+ ASIO_DECL void construct(base_implementation_type& impl);
+
+ // Move-construct a new socket implementation.
+ ASIO_DECL void base_move_construct(base_implementation_type& impl,
+ base_implementation_type& other_impl);
+
+ // Move-assign from another socket implementation.
+ ASIO_DECL void base_move_assign(base_implementation_type& impl,
+ win_iocp_socket_service_base& other_service,
+ base_implementation_type& other_impl);
+
+ // Destroy a socket implementation.
+ 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.
+ ASIO_DECL asio::error_code close(
+ base_implementation_type& impl, asio::error_code& ec);
+
+ // Release ownership of the socket.
+ ASIO_DECL socket_type release(
+ base_implementation_type& impl, asio::error_code& ec);
+
+ // Cancel all operations associated with the socket.
+ ASIO_DECL asio::error_code cancel(
+ base_implementation_type& impl, asio::error_code& ec);
+
+ // Determine whether the socket is at the out-of-band data mark.
+ bool at_mark(const base_implementation_type& impl,
+ asio::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,
+ asio::error_code& ec) const
+ {
+ return socket_ops::available(impl.socket_, ec);
+ }
+
+ // Place the socket into the state where it will listen for new connections.
+ asio::error_code listen(base_implementation_type& impl,
+ int backlog, asio::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>
+ asio::error_code io_control(base_implementation_type& impl,
+ IO_Control_Command& command, asio::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.
+ asio::error_code non_blocking(base_implementation_type& impl,
+ bool mode, asio::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.
+ asio::error_code native_non_blocking(base_implementation_type& impl,
+ bool mode, asio::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.
+ asio::error_code wait(base_implementation_type& impl,
+ socket_base::wait_type w, asio::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 = 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>
+ void async_wait(base_implementation_type& impl,
+ socket_base::wait_type w, Handler& handler)
+ {
+ bool is_continuation =
+ asio_handler_cont_helpers::is_continuation(handler);
+
+ // Allocate and construct an operation to wrap the handler.
+ typedef win_iocp_wait_op<Handler> op;
+ typename op::ptr p = { asio::detail::addressof(handler),
+ op::ptr::allocate(handler), 0 };
+ p.p = new (p.v) op(impl.cancel_token_, handler);
+
+ ASIO_HANDLER_CREATION((io_context_, *p.p, "socket",
+ &impl, impl.socket_, "async_wait"));
+
+ switch (w)
+ {
+ case socket_base::wait_read:
+ start_null_buffers_receive_op(impl, 0, p.p);
+ break;
+ case socket_base::wait_write:
+ start_reactor_op(impl, select_reactor::write_op, p.p);
+ break;
+ case socket_base::wait_error:
+ start_reactor_op(impl, select_reactor::except_op, p.p);
+ break;
+ default:
+ p.p->ec_ = asio::error::invalid_argument;
+ iocp_service_.post_immediate_completion(p.p, is_continuation);
+ break;
+ }
+
+ p.v = p.p = 0;
+ }
+
+ // Send the given data to the peer. Returns the number of bytes sent.
+ template <typename ConstBufferSequence>
+ size_t send(base_implementation_type& impl,
+ const ConstBufferSequence& buffers,
+ socket_base::message_flags flags, asio::error_code& ec)
+ {
+ buffer_sequence_adapter<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, asio::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>
+ void async_send(base_implementation_type& impl,
+ const ConstBufferSequence& buffers,
+ socket_base::message_flags flags, Handler& handler)
+ {
+ // Allocate and construct an operation to wrap the handler.
+ typedef win_iocp_socket_send_op<ConstBufferSequence, Handler> op;
+ typename op::ptr p = { asio::detail::addressof(handler),
+ op::ptr::allocate(handler), 0 };
+ p.p = new (p.v) op(impl.cancel_token_, buffers, handler);
+
+ ASIO_HANDLER_CREATION((io_context_, *p.p, "socket",
+ &impl, impl.socket_, "async_send"));
+
+ buffer_sequence_adapter<asio::const_buffer,
+ ConstBufferSequence> bufs(buffers);
+
+ start_send_op(impl, bufs.buffers(), bufs.count(), flags,
+ (impl.state_ & socket_ops::stream_oriented) != 0 && bufs.all_empty(),
+ p.p);
+ p.v = p.p = 0;
+ }
+
+ // Start an asynchronous wait until data can be sent without blocking.
+ template <typename Handler>
+ void async_send(base_implementation_type& impl, const null_buffers&,
+ socket_base::message_flags, Handler& handler)
+ {
+ // Allocate and construct an operation to wrap the handler.
+ typedef win_iocp_null_buffers_op<Handler> op;
+ typename op::ptr p = { asio::detail::addressof(handler),
+ op::ptr::allocate(handler), 0 };
+ p.p = new (p.v) op(impl.cancel_token_, handler);
+
+ ASIO_HANDLER_CREATION((io_context_, *p.p, "socket",
+ &impl, impl.socket_, "async_send(null_buffers)"));
+
+ start_reactor_op(impl, select_reactor::write_op, p.p);
+ 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, asio::error_code& ec)
+ {
+ buffer_sequence_adapter<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, asio::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>
+ void async_receive(base_implementation_type& impl,
+ const MutableBufferSequence& buffers,
+ socket_base::message_flags flags, Handler& handler)
+ {
+ // Allocate and construct an operation to wrap the handler.
+ typedef win_iocp_socket_recv_op<MutableBufferSequence, Handler> op;
+ typename op::ptr p = { asio::detail::addressof(handler),
+ op::ptr::allocate(handler), 0 };
+ p.p = new (p.v) op(impl.state_, impl.cancel_token_, buffers, handler);
+
+ ASIO_HANDLER_CREATION((io_context_, *p.p, "socket",
+ &impl, impl.socket_, "async_receive"));
+
+ buffer_sequence_adapter<asio::mutable_buffer,
+ MutableBufferSequence> bufs(buffers);
+
+ start_receive_op(impl, bufs.buffers(), bufs.count(), flags,
+ (impl.state_ & socket_ops::stream_oriented) != 0 && bufs.all_empty(),
+ p.p);
+ p.v = p.p = 0;
+ }
+
+ // Wait until data can be received without blocking.
+ template <typename Handler>
+ void async_receive(base_implementation_type& impl, const null_buffers&,
+ socket_base::message_flags flags, Handler& handler)
+ {
+ // Allocate and construct an operation to wrap the handler.
+ typedef win_iocp_null_buffers_op<Handler> op;
+ typename op::ptr p = { asio::detail::addressof(handler),
+ op::ptr::allocate(handler), 0 };
+ p.p = new (p.v) op(impl.cancel_token_, handler);
+
+ ASIO_HANDLER_CREATION((io_context_, *p.p, "socket",
+ &impl, impl.socket_, "async_receive(null_buffers)"));
+
+ start_null_buffers_receive_op(impl, flags, p.p);
+ 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, asio::error_code& ec)
+ {
+ buffer_sequence_adapter<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, asio::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>
+ 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)
+ {
+ // Allocate and construct an operation to wrap the handler.
+ typedef win_iocp_socket_recvmsg_op<MutableBufferSequence, Handler> op;
+ typename op::ptr p = { asio::detail::addressof(handler),
+ op::ptr::allocate(handler), 0 };
+ p.p = new (p.v) op(impl.cancel_token_, buffers, out_flags, handler);
+
+ ASIO_HANDLER_CREATION((io_context_, *p.p, "socket",
+ &impl, impl.socket_, "async_receive_with_flags"));
+
+ buffer_sequence_adapter<asio::mutable_buffer,
+ MutableBufferSequence> bufs(buffers);
+
+ start_receive_op(impl, bufs.buffers(), bufs.count(), in_flags, false, p.p);
+ p.v = p.p = 0;
+ }
+
+ // Wait until data can be received without blocking.
+ template <typename Handler>
+ 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)
+ {
+ // Allocate and construct an operation to wrap the handler.
+ typedef win_iocp_null_buffers_op<Handler> op;
+ typename op::ptr p = { asio::detail::addressof(handler),
+ op::ptr::allocate(handler), 0 };
+ p.p = new (p.v) op(impl.cancel_token_, handler);
+
+ ASIO_HANDLER_CREATION((io_context_, *p.p, "socket",
+ &impl, impl.socket_, "async_receive_with_flags(null_buffers)"));
+
+ // Reset out_flags since it can be given no sensible value at this time.
+ out_flags = 0;
+
+ start_null_buffers_receive_op(impl, in_flags, p.p);
+ p.v = p.p = 0;
+ }
+
+ // Helper function to restart an asynchronous accept operation.
+ ASIO_DECL void restart_accept_op(socket_type s,
+ socket_holder& new_socket, int family, int type, int protocol,
+ void* output_buffer, DWORD address_length, operation* op);
+
+protected:
+ // Open a new socket implementation.
+ ASIO_DECL asio::error_code do_open(
+ base_implementation_type& impl, int family, int type,
+ int protocol, asio::error_code& ec);
+
+ // Assign a native socket to a socket implementation.
+ ASIO_DECL asio::error_code do_assign(
+ base_implementation_type& impl, int type,
+ socket_type native_socket, asio::error_code& ec);
+
+ // Helper function to start an asynchronous send operation.
+ ASIO_DECL void start_send_op(base_implementation_type& impl,
+ WSABUF* buffers, std::size_t buffer_count,
+ socket_base::message_flags flags, bool noop, operation* op);
+
+ // Helper function to start an asynchronous send_to operation.
+ ASIO_DECL void start_send_to_op(base_implementation_type& impl,
+ WSABUF* buffers, std::size_t buffer_count,
+ const socket_addr_type* addr, int addrlen,
+ socket_base::message_flags flags, operation* op);
+
+ // Helper function to start an asynchronous receive operation.
+ ASIO_DECL void start_receive_op(base_implementation_type& impl,
+ WSABUF* buffers, std::size_t buffer_count,
+ socket_base::message_flags flags, bool noop, operation* op);
+
+ // Helper function to start an asynchronous null_buffers receive operation.
+ ASIO_DECL void start_null_buffers_receive_op(
+ base_implementation_type& impl,
+ socket_base::message_flags flags, reactor_op* op);
+
+ // Helper function to start an asynchronous receive_from operation.
+ ASIO_DECL void start_receive_from_op(base_implementation_type& impl,
+ WSABUF* buffers, std::size_t buffer_count, socket_addr_type* addr,
+ socket_base::message_flags flags, int* addrlen, operation* op);
+
+ // Helper function to start an asynchronous accept operation.
+ ASIO_DECL void start_accept_op(base_implementation_type& impl,
+ bool peer_is_open, socket_holder& new_socket, int family, int type,
+ int protocol, void* output_buffer, DWORD address_length, operation* op);
+
+ // Start an asynchronous read or write operation using the reactor.
+ ASIO_DECL void start_reactor_op(base_implementation_type& impl,
+ int op_type, reactor_op* op);
+
+ // Start the asynchronous connect operation using the reactor.
+ ASIO_DECL void start_connect_op(base_implementation_type& impl,
+ int family, int type, const socket_addr_type* remote_addr,
+ std::size_t remote_addrlen, win_iocp_socket_connect_op_base* op);
+
+ // Helper function to close a socket when the associated object is being
+ // destroyed.
+ ASIO_DECL void close_for_destruction(base_implementation_type& impl);
+
+ // Update the ID of the thread from which cancellation is safe.
+ ASIO_DECL void update_cancellation_thread_id(
+ base_implementation_type& impl);
+
+ // Helper function to get the reactor. If no reactor has been created yet, a
+ // new one is obtained from the io_context and a pointer to it is cached in
+ // this service.
+ ASIO_DECL select_reactor& get_reactor();
+
+ // The type of a ConnectEx function pointer, as old SDKs may not provide it.
+ typedef BOOL (PASCAL *connect_ex_fn)(SOCKET,
+ const socket_addr_type*, int, void*, DWORD, DWORD*, OVERLAPPED*);
+
+ // Helper function to get the ConnectEx pointer. If no ConnectEx pointer has
+ // been obtained yet, one is obtained using WSAIoctl and the pointer is
+ // cached. Returns a null pointer if ConnectEx is not available.
+ ASIO_DECL connect_ex_fn get_connect_ex(
+ base_implementation_type& impl, int type);
+
+ // The type of a NtSetInformationFile function pointer.
+ typedef LONG (NTAPI *nt_set_info_fn)(HANDLE, ULONG_PTR*, void*, ULONG, ULONG);
+
+ // Helper function to get the NtSetInformationFile function pointer. If no
+ // NtSetInformationFile pointer has been obtained yet, one is obtained using
+ // GetProcAddress and the pointer is cached. Returns a null pointer if
+ // NtSetInformationFile is not available.
+ ASIO_DECL nt_set_info_fn get_nt_set_info();
+
+ // Helper function to emulate InterlockedCompareExchangePointer functionality
+ // for:
+ // - very old Platform SDKs; and
+ // - platform SDKs where MSVC's /Wp64 option causes spurious warnings.
+ ASIO_DECL void* interlocked_compare_exchange_pointer(
+ void** dest, void* exch, void* cmp);
+
+ // Helper function to emulate InterlockedExchangePointer functionality for:
+ // - very old Platform SDKs; and
+ // - platform SDKs where MSVC's /Wp64 option causes spurious warnings.
+ ASIO_DECL void* interlocked_exchange_pointer(void** dest, void* val);
+
+ // The io_context used to obtain the reactor, if required.
+ asio::io_context& io_context_;
+
+ // The IOCP service used for running asynchronous operations and dispatching
+ // handlers.
+ win_iocp_io_context& iocp_service_;
+
+ // The reactor used for performing connect operations. This object is created
+ // only if needed.
+ select_reactor* reactor_;
+
+ // Pointer to ConnectEx implementation.
+ void* connect_ex_;
+
+ // Pointer to NtSetInformationFile implementation.
+ void* nt_set_info_;
+
+ // Mutex to protect access to the linked list of implementations.
+ asio::detail::mutex mutex_;
+
+ // The head of a linked list of all implementations.
+ base_implementation_type* impl_list_;
+};
+
+} // namespace detail
+} // namespace asio
+
+#include "asio/detail/pop_options.hpp"
+
+#if defined(ASIO_HEADER_ONLY)
+# include "asio/detail/impl/win_iocp_socket_service_base.ipp"
+#endif // defined(ASIO_HEADER_ONLY)
+
+#endif // defined(ASIO_HAS_IOCP)
+
+#endif // ASIO_DETAIL_WIN_IOCP_SOCKET_SERVICE_BASE_HPP
diff --git a/lib/asio/detail/win_iocp_thread_info.hpp b/lib/asio/detail/win_iocp_thread_info.hpp
new file mode 100644
index 0000000..13181e2
--- /dev/null
+++ b/lib/asio/detail/win_iocp_thread_info.hpp
@@ -0,0 +1,34 @@
+//
+// detail/win_iocp_thread_info.hpp
+// ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+//
+// Copyright (c) 2003-2018 Christopher M. Kohlhoff (chris at kohlhoff dot com)
+//
+// 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 ASIO_DETAIL_WIN_IOCP_THREAD_INFO_HPP
+#define ASIO_DETAIL_WIN_IOCP_THREAD_INFO_HPP
+
+#if defined(_MSC_VER) && (_MSC_VER >= 1200)
+# pragma once
+#endif // defined(_MSC_VER) && (_MSC_VER >= 1200)
+
+#include "asio/detail/thread_info_base.hpp"
+
+#include "asio/detail/push_options.hpp"
+
+namespace asio {
+namespace detail {
+
+struct win_iocp_thread_info : public thread_info_base
+{
+};
+
+} // namespace detail
+} // namespace asio
+
+#include "asio/detail/pop_options.hpp"
+
+#endif // ASIO_DETAIL_WIN_IOCP_THREAD_INFO_HPP
diff --git a/lib/asio/detail/win_iocp_wait_op.hpp b/lib/asio/detail/win_iocp_wait_op.hpp
new file mode 100644
index 0000000..472eea3
--- /dev/null
+++ b/lib/asio/detail/win_iocp_wait_op.hpp
@@ -0,0 +1,121 @@
+//
+// detail/win_iocp_wait_op.hpp
+// ~~~~~~~~~~~~~~~~~~~~~~~~~~~
+//
+// Copyright (c) 2003-2018 Christopher M. Kohlhoff (chris at kohlhoff dot com)
+//
+// 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 ASIO_DETAIL_WIN_IOCP_WAIT_OP_HPP
+#define ASIO_DETAIL_WIN_IOCP_WAIT_OP_HPP
+
+#if defined(_MSC_VER) && (_MSC_VER >= 1200)
+# pragma once
+#endif // defined(_MSC_VER) && (_MSC_VER >= 1200)
+
+#include "asio/detail/config.hpp"
+
+#if defined(ASIO_HAS_IOCP)
+
+#include "asio/detail/bind_handler.hpp"
+#include "asio/detail/buffer_sequence_adapter.hpp"
+#include "asio/detail/fenced_block.hpp"
+#include "asio/detail/handler_alloc_helpers.hpp"
+#include "asio/detail/handler_invoke_helpers.hpp"
+#include "asio/detail/memory.hpp"
+#include "asio/detail/reactor_op.hpp"
+#include "asio/detail/socket_ops.hpp"
+#include "asio/error.hpp"
+
+#include "asio/detail/push_options.hpp"
+
+namespace asio {
+namespace detail {
+
+template <typename Handler>
+class win_iocp_wait_op : public reactor_op
+{
+public:
+ ASIO_DEFINE_HANDLER_PTR(win_iocp_wait_op);
+
+ win_iocp_wait_op(socket_ops::weak_cancel_token_type cancel_token,
+ Handler& handler)
+ : reactor_op(&win_iocp_wait_op::do_perform,
+ &win_iocp_wait_op::do_complete),
+ cancel_token_(cancel_token),
+ handler_(ASIO_MOVE_CAST(Handler)(handler))
+ {
+ handler_work<Handler>::start(handler_);
+ }
+
+ static status do_perform(reactor_op*)
+ {
+ return done;
+ }
+
+ static void do_complete(void* owner, operation* base,
+ const asio::error_code& result_ec,
+ std::size_t /*bytes_transferred*/)
+ {
+ asio::error_code ec(result_ec);
+
+ // Take ownership of the operation object.
+ win_iocp_wait_op* o(static_cast<win_iocp_wait_op*>(base));
+ ptr p = { asio::detail::addressof(o->handler_), o, o };
+ handler_work<Handler> w(o->handler_);
+
+ ASIO_HANDLER_COMPLETION((*o));
+
+ // The reactor may have stored a result in the operation object.
+ if (o->ec_)
+ ec = o->ec_;
+
+ // Map non-portable errors to their portable counterparts.
+ if (ec.value() == ERROR_NETNAME_DELETED)
+ {
+ if (o->cancel_token_.expired())
+ ec = asio::error::operation_aborted;
+ else
+ ec = asio::error::connection_reset;
+ }
+ else if (ec.value() == ERROR_PORT_UNREACHABLE)
+ {
+ ec = asio::error::connection_refused;
+ }
+
+ // 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::binder1<Handler, asio::error_code>
+ handler(o->handler_, ec);
+ p.h = asio::detail::addressof(handler.handler_);
+ p.reset();
+
+ // Make the upcall if required.
+ if (owner)
+ {
+ fenced_block b(fenced_block::half);
+ ASIO_HANDLER_INVOCATION_BEGIN((handler.arg1_));
+ w.complete(handler, handler.handler_);
+ ASIO_HANDLER_INVOCATION_END;
+ }
+ }
+
+private:
+ socket_ops::weak_cancel_token_type cancel_token_;
+ Handler handler_;
+};
+
+} // namespace detail
+} // namespace asio
+
+#include "asio/detail/pop_options.hpp"
+
+#endif // defined(ASIO_HAS_IOCP)
+
+#endif // ASIO_DETAIL_WIN_IOCP_WAIT_OP_HPP
diff --git a/lib/asio/detail/win_mutex.hpp b/lib/asio/detail/win_mutex.hpp
new file mode 100644
index 0000000..ce52a2f
--- /dev/null
+++ b/lib/asio/detail/win_mutex.hpp
@@ -0,0 +1,78 @@
+//
+// detail/win_mutex.hpp
+// ~~~~~~~~~~~~~~~~~~~~
+//
+// Copyright (c) 2003-2018 Christopher M. Kohlhoff (chris at kohlhoff dot com)
+//
+// 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 ASIO_DETAIL_WIN_MUTEX_HPP
+#define ASIO_DETAIL_WIN_MUTEX_HPP
+
+#if defined(_MSC_VER) && (_MSC_VER >= 1200)
+# pragma once
+#endif // defined(_MSC_VER) && (_MSC_VER >= 1200)
+
+#include "asio/detail/config.hpp"
+
+#if defined(ASIO_WINDOWS)
+
+#include "asio/detail/noncopyable.hpp"
+#include "asio/detail/scoped_lock.hpp"
+#include "asio/detail/socket_types.hpp"
+
+#include "asio/detail/push_options.hpp"
+
+namespace asio {
+namespace detail {
+
+class win_mutex
+ : private noncopyable
+{
+public:
+ typedef asio::detail::scoped_lock<win_mutex> scoped_lock;
+
+ // Constructor.
+ ASIO_DECL win_mutex();
+
+ // Destructor.
+ ~win_mutex()
+ {
+ ::DeleteCriticalSection(&crit_section_);
+ }
+
+ // Lock the mutex.
+ void lock()
+ {
+ ::EnterCriticalSection(&crit_section_);
+ }
+
+ // Unlock the mutex.
+ void unlock()
+ {
+ ::LeaveCriticalSection(&crit_section_);
+ }
+
+private:
+ // Initialisation must be performed in a separate function to the constructor
+ // since the compiler does not support the use of structured exceptions and
+ // C++ exceptions in the same function.
+ ASIO_DECL int do_init();
+
+ ::CRITICAL_SECTION crit_section_;
+};
+
+} // namespace detail
+} // namespace asio
+
+#include "asio/detail/pop_options.hpp"
+
+#if defined(ASIO_HEADER_ONLY)
+# include "asio/detail/impl/win_mutex.ipp"
+#endif // defined(ASIO_HEADER_ONLY)
+
+#endif // defined(ASIO_WINDOWS)
+
+#endif // ASIO_DETAIL_WIN_MUTEX_HPP
diff --git a/lib/asio/detail/win_object_handle_service.hpp b/lib/asio/detail/win_object_handle_service.hpp
new file mode 100644
index 0000000..1d8abc9
--- /dev/null
+++ b/lib/asio/detail/win_object_handle_service.hpp
@@ -0,0 +1,184 @@
+//
+// detail/win_object_handle_service.hpp
+// ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+//
+// Copyright (c) 2003-2018 Christopher M. Kohlhoff (chris at kohlhoff dot com)
+// Copyright (c) 2011 Boris Schaeling (boris@highscore.de)
+//
+// 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 ASIO_DETAIL_WIN_OBJECT_HANDLE_SERVICE_HPP
+#define ASIO_DETAIL_WIN_OBJECT_HANDLE_SERVICE_HPP
+
+#if defined(_MSC_VER) && (_MSC_VER >= 1200)
+# pragma once
+#endif // defined(_MSC_VER) && (_MSC_VER >= 1200)
+
+#include "asio/detail/config.hpp"
+
+#if defined(ASIO_HAS_WINDOWS_OBJECT_HANDLE)
+
+#include "asio/detail/handler_alloc_helpers.hpp"
+#include "asio/detail/memory.hpp"
+#include "asio/detail/wait_handler.hpp"
+#include "asio/error.hpp"
+#include "asio/io_context.hpp"
+
+#include "asio/detail/push_options.hpp"
+
+namespace asio {
+namespace detail {
+
+class win_object_handle_service :
+ public service_base<win_object_handle_service>
+{
+public:
+ // The native type of an object handle.
+ typedef HANDLE native_handle_type;
+
+ // The implementation type of the object handle.
+ class implementation_type
+ {
+ public:
+ // Default constructor.
+ implementation_type()
+ : handle_(INVALID_HANDLE_VALUE),
+ wait_handle_(INVALID_HANDLE_VALUE),
+ owner_(0),
+ next_(0),
+ prev_(0)
+ {
+ }
+
+ private:
+ // Only this service will have access to the internal values.
+ friend class win_object_handle_service;
+
+ // The native object handle representation. May be accessed or modified
+ // without locking the mutex.
+ native_handle_type handle_;
+
+ // The handle used to unregister the wait operation. The mutex must be
+ // locked when accessing or modifying this member.
+ HANDLE wait_handle_;
+
+ // The operations waiting on the object handle. If there is a registered
+ // wait then the mutex must be locked when accessing or modifying this
+ // member
+ op_queue<wait_op> op_queue_;
+
+ // The service instance that owns the object handle implementation.
+ win_object_handle_service* owner_;
+
+ // Pointers to adjacent handle implementations in linked list. The mutex
+ // must be locked when accessing or modifying these members.
+ implementation_type* next_;
+ implementation_type* prev_;
+ };
+
+ // Constructor.
+ ASIO_DECL win_object_handle_service(
+ asio::io_context& io_context);
+
+ // Destroy all user-defined handler objects owned by the service.
+ ASIO_DECL void shutdown();
+
+ // Construct a new handle implementation.
+ ASIO_DECL void construct(implementation_type& impl);
+
+ // Move-construct a new handle implementation.
+ ASIO_DECL void move_construct(implementation_type& impl,
+ implementation_type& other_impl);
+
+ // Move-assign from another handle implementation.
+ ASIO_DECL void move_assign(implementation_type& impl,
+ win_object_handle_service& other_service,
+ implementation_type& other_impl);
+
+ // Destroy a handle implementation.
+ ASIO_DECL void destroy(implementation_type& impl);
+
+ // Assign a native handle to a handle implementation.
+ ASIO_DECL asio::error_code assign(implementation_type& impl,
+ const native_handle_type& handle, asio::error_code& ec);
+
+ // Determine whether the handle is open.
+ bool is_open(const implementation_type& impl) const
+ {
+ return impl.handle_ != INVALID_HANDLE_VALUE && impl.handle_ != 0;
+ }
+
+ // Destroy a handle implementation.
+ ASIO_DECL asio::error_code close(implementation_type& impl,
+ asio::error_code& ec);
+
+ // Get the native handle representation.
+ native_handle_type native_handle(const implementation_type& impl) const
+ {
+ return impl.handle_;
+ }
+
+ // Cancel all operations associated with the handle.
+ ASIO_DECL asio::error_code cancel(implementation_type& impl,
+ asio::error_code& ec);
+
+ // Perform a synchronous wait for the object to enter a signalled state.
+ ASIO_DECL void wait(implementation_type& impl,
+ asio::error_code& ec);
+
+ /// Start an asynchronous wait.
+ template <typename Handler>
+ void async_wait(implementation_type& impl, Handler& handler)
+ {
+ // Allocate and construct an operation to wrap the handler.
+ typedef wait_handler<Handler> op;
+ typename op::ptr p = { asio::detail::addressof(handler),
+ op::ptr::allocate(handler), 0 };
+ p.p = new (p.v) op(handler);
+
+ ASIO_HANDLER_CREATION((io_context_.context(), *p.p, "object_handle",
+ &impl, reinterpret_cast<uintmax_t>(impl.wait_handle_), "async_wait"));
+
+ start_wait_op(impl, p.p);
+ p.v = p.p = 0;
+ }
+
+private:
+ // Helper function to start an asynchronous wait operation.
+ ASIO_DECL void start_wait_op(implementation_type& impl, wait_op* op);
+
+ // Helper function to register a wait operation.
+ ASIO_DECL void register_wait_callback(
+ implementation_type& impl, mutex::scoped_lock& lock);
+
+ // Callback function invoked when the registered wait completes.
+ static ASIO_DECL VOID CALLBACK wait_callback(
+ PVOID param, BOOLEAN timeout);
+
+ // The io_context implementation used to post completions.
+ io_context_impl& io_context_;
+
+ // Mutex to protect access to internal state.
+ mutex mutex_;
+
+ // The head of a linked list of all implementations.
+ implementation_type* impl_list_;
+
+ // Flag to indicate that the dispatcher has been shut down.
+ bool shutdown_;
+};
+
+} // namespace detail
+} // namespace asio
+
+#include "asio/detail/pop_options.hpp"
+
+#if defined(ASIO_HEADER_ONLY)
+# include "asio/detail/impl/win_object_handle_service.ipp"
+#endif // defined(ASIO_HEADER_ONLY)
+
+#endif // defined(ASIO_HAS_WINDOWS_OBJECT_HANDLE)
+
+#endif // ASIO_DETAIL_WIN_OBJECT_HANDLE_SERVICE_HPP
diff --git a/lib/asio/detail/win_static_mutex.hpp b/lib/asio/detail/win_static_mutex.hpp
new file mode 100644
index 0000000..b169688
--- /dev/null
+++ b/lib/asio/detail/win_static_mutex.hpp
@@ -0,0 +1,74 @@
+//
+// detail/win_static_mutex.hpp
+// ~~~~~~~~~~~~~~~~~~~~~~~~~~~
+//
+// Copyright (c) 2003-2018 Christopher M. Kohlhoff (chris at kohlhoff dot com)
+//
+// 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 ASIO_DETAIL_WIN_STATIC_MUTEX_HPP
+#define ASIO_DETAIL_WIN_STATIC_MUTEX_HPP
+
+#if defined(_MSC_VER) && (_MSC_VER >= 1200)
+# pragma once
+#endif // defined(_MSC_VER) && (_MSC_VER >= 1200)
+
+#include "asio/detail/config.hpp"
+
+#if defined(ASIO_WINDOWS)
+
+#include "asio/detail/scoped_lock.hpp"
+
+#include "asio/detail/push_options.hpp"
+
+namespace asio {
+namespace detail {
+
+struct win_static_mutex
+{
+ typedef asio::detail::scoped_lock<win_static_mutex> scoped_lock;
+
+ // Initialise the mutex.
+ ASIO_DECL void init();
+
+ // Initialisation must be performed in a separate function to the "public"
+ // init() function since the compiler does not support the use of structured
+ // exceptions and C++ exceptions in the same function.
+ ASIO_DECL int do_init();
+
+ // Lock the mutex.
+ void lock()
+ {
+ ::EnterCriticalSection(&crit_section_);
+ }
+
+ // Unlock the mutex.
+ void unlock()
+ {
+ ::LeaveCriticalSection(&crit_section_);
+ }
+
+ bool initialised_;
+ ::CRITICAL_SECTION crit_section_;
+};
+
+#if defined(UNDER_CE)
+# define ASIO_WIN_STATIC_MUTEX_INIT { false, { 0, 0, 0, 0, 0 } }
+#else // defined(UNDER_CE)
+# define ASIO_WIN_STATIC_MUTEX_INIT { false, { 0, 0, 0, 0, 0, 0 } }
+#endif // defined(UNDER_CE)
+
+} // namespace detail
+} // namespace asio
+
+#include "asio/detail/pop_options.hpp"
+
+#if defined(ASIO_HEADER_ONLY)
+# include "asio/detail/impl/win_static_mutex.ipp"
+#endif // defined(ASIO_HEADER_ONLY)
+
+#endif // defined(ASIO_WINDOWS)
+
+#endif // ASIO_DETAIL_WIN_STATIC_MUTEX_HPP
diff --git a/lib/asio/detail/win_thread.hpp b/lib/asio/detail/win_thread.hpp
new file mode 100644
index 0000000..8b28a90
--- /dev/null
+++ b/lib/asio/detail/win_thread.hpp
@@ -0,0 +1,147 @@
+//
+// detail/win_thread.hpp
+// ~~~~~~~~~~~~~~~~~~~~~
+//
+// Copyright (c) 2003-2018 Christopher M. Kohlhoff (chris at kohlhoff dot com)
+//
+// 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 ASIO_DETAIL_WIN_THREAD_HPP
+#define ASIO_DETAIL_WIN_THREAD_HPP
+
+#if defined(_MSC_VER) && (_MSC_VER >= 1200)
+# pragma once
+#endif // defined(_MSC_VER) && (_MSC_VER >= 1200)
+
+#include "asio/detail/config.hpp"
+
+#if defined(ASIO_WINDOWS) \
+ && !defined(ASIO_WINDOWS_APP) \
+ && !defined(UNDER_CE)
+
+#include <cstddef>
+#include "asio/detail/noncopyable.hpp"
+#include "asio/detail/socket_types.hpp"
+
+#include "asio/detail/push_options.hpp"
+
+namespace asio {
+namespace detail {
+
+ASIO_DECL unsigned int __stdcall win_thread_function(void* arg);
+
+#if defined(WINVER) && (WINVER < 0x0500)
+ASIO_DECL void __stdcall apc_function(ULONG data);
+#else
+ASIO_DECL void __stdcall apc_function(ULONG_PTR data);
+#endif
+
+template <typename T>
+class win_thread_base
+{
+public:
+ static bool terminate_threads()
+ {
+ return ::InterlockedExchangeAdd(&terminate_threads_, 0) != 0;
+ }
+
+ static void set_terminate_threads(bool b)
+ {
+ ::InterlockedExchange(&terminate_threads_, b ? 1 : 0);
+ }
+
+private:
+ static long terminate_threads_;
+};
+
+template <typename T>
+long win_thread_base<T>::terminate_threads_ = 0;
+
+class win_thread
+ : private noncopyable,
+ public win_thread_base<win_thread>
+{
+public:
+ // Constructor.
+ template <typename Function>
+ win_thread(Function f, unsigned int stack_size = 0)
+ : thread_(0),
+ exit_event_(0)
+ {
+ start_thread(new func<Function>(f), stack_size);
+ }
+
+ // Destructor.
+ ASIO_DECL ~win_thread();
+
+ // Wait for the thread to exit.
+ ASIO_DECL void join();
+
+ // Get number of CPUs.
+ ASIO_DECL static std::size_t hardware_concurrency();
+
+private:
+ friend ASIO_DECL unsigned int __stdcall win_thread_function(void* arg);
+
+#if defined(WINVER) && (WINVER < 0x0500)
+ friend ASIO_DECL void __stdcall apc_function(ULONG);
+#else
+ friend ASIO_DECL void __stdcall apc_function(ULONG_PTR);
+#endif
+
+ class func_base
+ {
+ public:
+ virtual ~func_base() {}
+ virtual void run() = 0;
+ ::HANDLE entry_event_;
+ ::HANDLE exit_event_;
+ };
+
+ struct auto_func_base_ptr
+ {
+ func_base* ptr;
+ ~auto_func_base_ptr() { delete ptr; }
+ };
+
+ template <typename Function>
+ class func
+ : public func_base
+ {
+ public:
+ func(Function f)
+ : f_(f)
+ {
+ }
+
+ virtual void run()
+ {
+ f_();
+ }
+
+ private:
+ Function f_;
+ };
+
+ ASIO_DECL void start_thread(func_base* arg, unsigned int stack_size);
+
+ ::HANDLE thread_;
+ ::HANDLE exit_event_;
+};
+
+} // namespace detail
+} // namespace asio
+
+#include "asio/detail/pop_options.hpp"
+
+#if defined(ASIO_HEADER_ONLY)
+# include "asio/detail/impl/win_thread.ipp"
+#endif // defined(ASIO_HEADER_ONLY)
+
+#endif // defined(ASIO_WINDOWS)
+ // && !defined(ASIO_WINDOWS_APP)
+ // && !defined(UNDER_CE)
+
+#endif // ASIO_DETAIL_WIN_THREAD_HPP
diff --git a/lib/asio/detail/win_tss_ptr.hpp b/lib/asio/detail/win_tss_ptr.hpp
new file mode 100644
index 0000000..4207108
--- /dev/null
+++ b/lib/asio/detail/win_tss_ptr.hpp
@@ -0,0 +1,79 @@
+//
+// detail/win_tss_ptr.hpp
+// ~~~~~~~~~~~~~~~~~~~~~~
+//
+// Copyright (c) 2003-2018 Christopher M. Kohlhoff (chris at kohlhoff dot com)
+//
+// 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 ASIO_DETAIL_WIN_TSS_PTR_HPP
+#define ASIO_DETAIL_WIN_TSS_PTR_HPP
+
+#if defined(_MSC_VER) && (_MSC_VER >= 1200)
+# pragma once
+#endif // defined(_MSC_VER) && (_MSC_VER >= 1200)
+
+#include "asio/detail/config.hpp"
+
+#if defined(ASIO_WINDOWS)
+
+#include "asio/detail/noncopyable.hpp"
+#include "asio/detail/socket_types.hpp"
+
+#include "asio/detail/push_options.hpp"
+
+namespace asio {
+namespace detail {
+
+// Helper function to create thread-specific storage.
+ASIO_DECL DWORD win_tss_ptr_create();
+
+template <typename T>
+class win_tss_ptr
+ : private noncopyable
+{
+public:
+ // Constructor.
+ win_tss_ptr()
+ : tss_key_(win_tss_ptr_create())
+ {
+ }
+
+ // Destructor.
+ ~win_tss_ptr()
+ {
+ ::TlsFree(tss_key_);
+ }
+
+ // Get the value.
+ operator T*() const
+ {
+ return static_cast<T*>(::TlsGetValue(tss_key_));
+ }
+
+ // Set the value.
+ void operator=(T* value)
+ {
+ ::TlsSetValue(tss_key_, value);
+ }
+
+private:
+ // Thread-specific storage to allow unlocked access to determine whether a
+ // thread is a member of the pool.
+ DWORD tss_key_;
+};
+
+} // namespace detail
+} // namespace asio
+
+#include "asio/detail/pop_options.hpp"
+
+#if defined(ASIO_HEADER_ONLY)
+# include "asio/detail/impl/win_tss_ptr.ipp"
+#endif // defined(ASIO_HEADER_ONLY)
+
+#endif // defined(ASIO_WINDOWS)
+
+#endif // ASIO_DETAIL_WIN_TSS_PTR_HPP
diff --git a/lib/asio/detail/winapp_thread.hpp b/lib/asio/detail/winapp_thread.hpp
new file mode 100644
index 0000000..69dcf08
--- /dev/null
+++ b/lib/asio/detail/winapp_thread.hpp
@@ -0,0 +1,124 @@
+//
+// detail/winapp_thread.hpp
+// ~~~~~~~~~~~~~~~~~~~~~~~~
+//
+// Copyright (c) 2003-2018 Christopher M. Kohlhoff (chris at kohlhoff dot com)
+//
+// 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 ASIO_DETAIL_WINAPP_THREAD_HPP
+#define ASIO_DETAIL_WINAPP_THREAD_HPP
+
+#if defined(_MSC_VER) && (_MSC_VER >= 1200)
+# pragma once
+#endif // defined(_MSC_VER) && (_MSC_VER >= 1200)
+
+#include "asio/detail/config.hpp"
+
+#if defined(ASIO_WINDOWS) && defined(ASIO_WINDOWS_APP)
+
+#include "asio/detail/noncopyable.hpp"
+#include "asio/detail/scoped_ptr.hpp"
+#include "asio/detail/socket_types.hpp"
+#include "asio/detail/throw_error.hpp"
+#include "asio/error.hpp"
+
+#include "asio/detail/push_options.hpp"
+
+namespace asio {
+namespace detail {
+
+DWORD WINAPI winapp_thread_function(LPVOID arg);
+
+class winapp_thread
+ : private noncopyable
+{
+public:
+ // Constructor.
+ template <typename Function>
+ winapp_thread(Function f, unsigned int = 0)
+ {
+ scoped_ptr<func_base> arg(new func<Function>(f));
+ DWORD thread_id = 0;
+ thread_ = ::CreateThread(0, 0, winapp_thread_function,
+ arg.get(), 0, &thread_id);
+ if (!thread_)
+ {
+ DWORD last_error = ::GetLastError();
+ asio::error_code ec(last_error,
+ asio::error::get_system_category());
+ asio::detail::throw_error(ec, "thread");
+ }
+ arg.release();
+ }
+
+ // Destructor.
+ ~winapp_thread()
+ {
+ ::CloseHandle(thread_);
+ }
+
+ // Wait for the thread to exit.
+ void join()
+ {
+ ::WaitForSingleObjectEx(thread_, INFINITE, false);
+ }
+
+ // Get number of CPUs.
+ static std::size_t hardware_concurrency()
+ {
+ SYSTEM_INFO system_info;
+ ::GetNativeSystemInfo(&system_info);
+ return system_info.dwNumberOfProcessors;
+ }
+
+private:
+ friend DWORD WINAPI winapp_thread_function(LPVOID arg);
+
+ class func_base
+ {
+ public:
+ virtual ~func_base() {}
+ virtual void run() = 0;
+ };
+
+ template <typename Function>
+ class func
+ : public func_base
+ {
+ public:
+ func(Function f)
+ : f_(f)
+ {
+ }
+
+ virtual void run()
+ {
+ f_();
+ }
+
+ private:
+ Function f_;
+ };
+
+ ::HANDLE thread_;
+};
+
+inline DWORD WINAPI winapp_thread_function(LPVOID arg)
+{
+ scoped_ptr<winapp_thread::func_base> func(
+ static_cast<winapp_thread::func_base*>(arg));
+ func->run();
+ return 0;
+}
+
+} // namespace detail
+} // namespace asio
+
+#include "asio/detail/pop_options.hpp"
+
+#endif // defined(ASIO_WINDOWS) && defined(ASIO_WINDOWS_APP)
+
+#endif // ASIO_DETAIL_WINAPP_THREAD_HPP
diff --git a/lib/asio/detail/wince_thread.hpp b/lib/asio/detail/wince_thread.hpp
new file mode 100644
index 0000000..a2863f6
--- /dev/null
+++ b/lib/asio/detail/wince_thread.hpp
@@ -0,0 +1,124 @@
+//
+// detail/wince_thread.hpp
+// ~~~~~~~~~~~~~~~~~~~~~~~
+//
+// Copyright (c) 2003-2018 Christopher M. Kohlhoff (chris at kohlhoff dot com)
+//
+// 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 ASIO_DETAIL_WINCE_THREAD_HPP
+#define ASIO_DETAIL_WINCE_THREAD_HPP
+
+#if defined(_MSC_VER) && (_MSC_VER >= 1200)
+# pragma once
+#endif // defined(_MSC_VER) && (_MSC_VER >= 1200)
+
+#include "asio/detail/config.hpp"
+
+#if defined(ASIO_WINDOWS) && defined(UNDER_CE)
+
+#include "asio/detail/noncopyable.hpp"
+#include "asio/detail/scoped_ptr.hpp"
+#include "asio/detail/socket_types.hpp"
+#include "asio/detail/throw_error.hpp"
+#include "asio/error.hpp"
+
+#include "asio/detail/push_options.hpp"
+
+namespace asio {
+namespace detail {
+
+DWORD WINAPI wince_thread_function(LPVOID arg);
+
+class wince_thread
+ : private noncopyable
+{
+public:
+ // Constructor.
+ template <typename Function>
+ wince_thread(Function f, unsigned int = 0)
+ {
+ scoped_ptr<func_base> arg(new func<Function>(f));
+ DWORD thread_id = 0;
+ thread_ = ::CreateThread(0, 0, wince_thread_function,
+ arg.get(), 0, &thread_id);
+ if (!thread_)
+ {
+ DWORD last_error = ::GetLastError();
+ asio::error_code ec(last_error,
+ asio::error::get_system_category());
+ asio::detail::throw_error(ec, "thread");
+ }
+ arg.release();
+ }
+
+ // Destructor.
+ ~wince_thread()
+ {
+ ::CloseHandle(thread_);
+ }
+
+ // Wait for the thread to exit.
+ void join()
+ {
+ ::WaitForSingleObject(thread_, INFINITE);
+ }
+
+ // Get number of CPUs.
+ static std::size_t hardware_concurrency()
+ {
+ SYSTEM_INFO system_info;
+ ::GetSystemInfo(&system_info);
+ return system_info.dwNumberOfProcessors;
+ }
+
+private:
+ friend DWORD WINAPI wince_thread_function(LPVOID arg);
+
+ class func_base
+ {
+ public:
+ virtual ~func_base() {}
+ virtual void run() = 0;
+ };
+
+ template <typename Function>
+ class func
+ : public func_base
+ {
+ public:
+ func(Function f)
+ : f_(f)
+ {
+ }
+
+ virtual void run()
+ {
+ f_();
+ }
+
+ private:
+ Function f_;
+ };
+
+ ::HANDLE thread_;
+};
+
+inline DWORD WINAPI wince_thread_function(LPVOID arg)
+{
+ scoped_ptr<wince_thread::func_base> func(
+ static_cast<wince_thread::func_base*>(arg));
+ func->run();
+ return 0;
+}
+
+} // namespace detail
+} // namespace asio
+
+#include "asio/detail/pop_options.hpp"
+
+#endif // defined(ASIO_WINDOWS) && defined(UNDER_CE)
+
+#endif // ASIO_DETAIL_WINCE_THREAD_HPP
diff --git a/lib/asio/detail/winrt_async_manager.hpp b/lib/asio/detail/winrt_async_manager.hpp
new file mode 100644
index 0000000..e22ad52
--- /dev/null
+++ b/lib/asio/detail/winrt_async_manager.hpp
@@ -0,0 +1,294 @@
+//
+// detail/winrt_async_manager.hpp
+// ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+//
+// Copyright (c) 2003-2018 Christopher M. Kohlhoff (chris at kohlhoff dot com)
+//
+// 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 ASIO_DETAIL_WINRT_ASYNC_MANAGER_HPP
+#define ASIO_DETAIL_WINRT_ASYNC_MANAGER_HPP
+
+#if defined(_MSC_VER) && (_MSC_VER >= 1200)
+# pragma once
+#endif // defined(_MSC_VER) && (_MSC_VER >= 1200)
+
+#include "asio/detail/config.hpp"
+
+#if defined(ASIO_WINDOWS_RUNTIME)
+
+#include <future>
+#include "asio/detail/atomic_count.hpp"
+#include "asio/detail/winrt_async_op.hpp"
+#include "asio/error.hpp"
+#include "asio/io_context.hpp"
+
+#include "asio/detail/push_options.hpp"
+
+namespace asio {
+namespace detail {
+
+class winrt_async_manager
+ : public asio::detail::service_base<winrt_async_manager>
+{
+public:
+ // Constructor.
+ winrt_async_manager(asio::io_context& io_context)
+ : asio::detail::service_base<winrt_async_manager>(io_context),
+ io_context_(use_service<io_context_impl>(io_context)),
+ outstanding_ops_(1)
+ {
+ }
+
+ // Destructor.
+ ~winrt_async_manager()
+ {
+ }
+
+ // Destroy all user-defined handler objects owned by the service.
+ void shutdown()
+ {
+ if (--outstanding_ops_ > 0)
+ {
+ // Block until last operation is complete.
+ std::future<void> f = promise_.get_future();
+ f.wait();
+ }
+ }
+
+ void sync(Windows::Foundation::IAsyncAction^ action,
+ asio::error_code& ec)
+ {
+ using namespace Windows::Foundation;
+ using Windows::Foundation::AsyncStatus;
+
+ auto promise = std::make_shared<std::promise<asio::error_code>>();
+ auto future = promise->get_future();
+
+ action->Completed = ref new AsyncActionCompletedHandler(
+ [promise](IAsyncAction^ action, AsyncStatus status)
+ {
+ switch (status)
+ {
+ case AsyncStatus::Canceled:
+ promise->set_value(asio::error::operation_aborted);
+ break;
+ case AsyncStatus::Error:
+ case AsyncStatus::Completed:
+ default:
+ asio::error_code ec(
+ action->ErrorCode.Value,
+ asio::system_category());
+ promise->set_value(ec);
+ break;
+ }
+ });
+
+ ec = future.get();
+ }
+
+ template <typename TResult>
+ TResult sync(Windows::Foundation::IAsyncOperation<TResult>^ operation,
+ asio::error_code& ec)
+ {
+ using namespace Windows::Foundation;
+ using Windows::Foundation::AsyncStatus;
+
+ auto promise = std::make_shared<std::promise<asio::error_code>>();
+ auto future = promise->get_future();
+
+ operation->Completed = ref new AsyncOperationCompletedHandler<TResult>(
+ [promise](IAsyncOperation<TResult>^ operation, AsyncStatus status)
+ {
+ switch (status)
+ {
+ case AsyncStatus::Canceled:
+ promise->set_value(asio::error::operation_aborted);
+ break;
+ case AsyncStatus::Error:
+ case AsyncStatus::Completed:
+ default:
+ asio::error_code ec(
+ operation->ErrorCode.Value,
+ asio::system_category());
+ promise->set_value(ec);
+ break;
+ }
+ });
+
+ ec = future.get();
+ return operation->GetResults();
+ }
+
+ template <typename TResult, typename TProgress>
+ TResult sync(
+ Windows::Foundation::IAsyncOperationWithProgress<
+ TResult, TProgress>^ operation,
+ asio::error_code& ec)
+ {
+ using namespace Windows::Foundation;
+ using Windows::Foundation::AsyncStatus;
+
+ auto promise = std::make_shared<std::promise<asio::error_code>>();
+ auto future = promise->get_future();
+
+ operation->Completed
+ = ref new AsyncOperationWithProgressCompletedHandler<TResult, TProgress>(
+ [promise](IAsyncOperationWithProgress<TResult, TProgress>^ operation,
+ AsyncStatus status)
+ {
+ switch (status)
+ {
+ case AsyncStatus::Canceled:
+ promise->set_value(asio::error::operation_aborted);
+ break;
+ case AsyncStatus::Started:
+ break;
+ case AsyncStatus::Error:
+ case AsyncStatus::Completed:
+ default:
+ asio::error_code ec(
+ operation->ErrorCode.Value,
+ asio::system_category());
+ promise->set_value(ec);
+ break;
+ }
+ });
+
+ ec = future.get();
+ return operation->GetResults();
+ }
+
+ void async(Windows::Foundation::IAsyncAction^ action,
+ winrt_async_op<void>* handler)
+ {
+ using namespace Windows::Foundation;
+ using Windows::Foundation::AsyncStatus;
+
+ auto on_completed = ref new AsyncActionCompletedHandler(
+ [this, handler](IAsyncAction^ action, AsyncStatus status)
+ {
+ switch (status)
+ {
+ case AsyncStatus::Canceled:
+ handler->ec_ = asio::error::operation_aborted;
+ break;
+ case AsyncStatus::Started:
+ return;
+ case AsyncStatus::Completed:
+ case AsyncStatus::Error:
+ default:
+ handler->ec_ = asio::error_code(
+ action->ErrorCode.Value,
+ asio::system_category());
+ break;
+ }
+ io_context_.post_deferred_completion(handler);
+ if (--outstanding_ops_ == 0)
+ promise_.set_value();
+ });
+
+ io_context_.work_started();
+ ++outstanding_ops_;
+ action->Completed = on_completed;
+ }
+
+ template <typename TResult>
+ void async(Windows::Foundation::IAsyncOperation<TResult>^ operation,
+ winrt_async_op<TResult>* handler)
+ {
+ using namespace Windows::Foundation;
+ using Windows::Foundation::AsyncStatus;
+
+ auto on_completed = ref new AsyncOperationCompletedHandler<TResult>(
+ [this, handler](IAsyncOperation<TResult>^ operation, AsyncStatus status)
+ {
+ switch (status)
+ {
+ case AsyncStatus::Canceled:
+ handler->ec_ = asio::error::operation_aborted;
+ break;
+ case AsyncStatus::Started:
+ return;
+ case AsyncStatus::Completed:
+ handler->result_ = operation->GetResults();
+ // Fall through.
+ case AsyncStatus::Error:
+ default:
+ handler->ec_ = asio::error_code(
+ operation->ErrorCode.Value,
+ asio::system_category());
+ break;
+ }
+ io_context_.post_deferred_completion(handler);
+ if (--outstanding_ops_ == 0)
+ promise_.set_value();
+ });
+
+ io_context_.work_started();
+ ++outstanding_ops_;
+ operation->Completed = on_completed;
+ }
+
+ template <typename TResult, typename TProgress>
+ void async(
+ Windows::Foundation::IAsyncOperationWithProgress<
+ TResult, TProgress>^ operation,
+ winrt_async_op<TResult>* handler)
+ {
+ using namespace Windows::Foundation;
+ using Windows::Foundation::AsyncStatus;
+
+ auto on_completed
+ = ref new AsyncOperationWithProgressCompletedHandler<TResult, TProgress>(
+ [this, handler](IAsyncOperationWithProgress<
+ TResult, TProgress>^ operation, AsyncStatus status)
+ {
+ switch (status)
+ {
+ case AsyncStatus::Canceled:
+ handler->ec_ = asio::error::operation_aborted;
+ break;
+ case AsyncStatus::Started:
+ return;
+ case AsyncStatus::Completed:
+ handler->result_ = operation->GetResults();
+ // Fall through.
+ case AsyncStatus::Error:
+ default:
+ handler->ec_ = asio::error_code(
+ operation->ErrorCode.Value,
+ asio::system_category());
+ break;
+ }
+ io_context_.post_deferred_completion(handler);
+ if (--outstanding_ops_ == 0)
+ promise_.set_value();
+ });
+
+ io_context_.work_started();
+ ++outstanding_ops_;
+ operation->Completed = on_completed;
+ }
+
+private:
+ // The io_context implementation used to post completed handlers.
+ io_context_impl& io_context_;
+
+ // Count of outstanding operations.
+ atomic_count outstanding_ops_;
+
+ // Used to keep wait for outstanding operations to complete.
+ std::promise<void> promise_;
+};
+
+} // namespace detail
+} // namespace asio
+
+#include "asio/detail/pop_options.hpp"
+
+#endif // defined(ASIO_WINDOWS_RUNTIME)
+
+#endif // ASIO_DETAIL_WINRT_ASYNC_MANAGER_HPP
diff --git a/lib/asio/detail/winrt_async_op.hpp b/lib/asio/detail/winrt_async_op.hpp
new file mode 100644
index 0000000..75891a4
--- /dev/null
+++ b/lib/asio/detail/winrt_async_op.hpp
@@ -0,0 +1,65 @@
+//
+// detail/winrt_async_op.hpp
+// ~~~~~~~~~~~~~~~~~~~~~~~~~
+//
+// Copyright (c) 2003-2018 Christopher M. Kohlhoff (chris at kohlhoff dot com)
+//
+// 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 ASIO_DETAIL_WINRT_ASYNC_OP_HPP
+#define ASIO_DETAIL_WINRT_ASYNC_OP_HPP
+
+#if defined(_MSC_VER) && (_MSC_VER >= 1200)
+# pragma once
+#endif // defined(_MSC_VER) && (_MSC_VER >= 1200)
+
+#include "asio/detail/config.hpp"
+#include "asio/detail/operation.hpp"
+
+#include "asio/detail/push_options.hpp"
+
+namespace asio {
+namespace detail {
+
+template <typename TResult>
+class winrt_async_op
+ : public operation
+{
+public:
+ // The error code to be passed to the completion handler.
+ asio::error_code ec_;
+
+ // The result of the operation, to be passed to the completion handler.
+ TResult result_;
+
+protected:
+ winrt_async_op(func_type complete_func)
+ : operation(complete_func),
+ result_()
+ {
+ }
+};
+
+template <>
+class winrt_async_op<void>
+ : public operation
+{
+public:
+ // The error code to be passed to the completion handler.
+ asio::error_code ec_;
+
+protected:
+ winrt_async_op(func_type complete_func)
+ : operation(complete_func)
+ {
+ }
+};
+
+} // namespace detail
+} // namespace asio
+
+#include "asio/detail/pop_options.hpp"
+
+#endif // ASIO_DETAIL_WINRT_ASYNC_OP_HPP
diff --git a/lib/asio/detail/winrt_resolve_op.hpp b/lib/asio/detail/winrt_resolve_op.hpp
new file mode 100644
index 0000000..07efd29
--- /dev/null
+++ b/lib/asio/detail/winrt_resolve_op.hpp
@@ -0,0 +1,118 @@
+//
+// detail/winrt_resolve_op.hpp
+// ~~~~~~~~~~~~~~~~~~~~~~~~~~~
+//
+// Copyright (c) 2003-2018 Christopher M. Kohlhoff (chris at kohlhoff dot com)
+//
+// 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 ASIO_DETAIL_WINRT_RESOLVE_OP_HPP
+#define ASIO_DETAIL_WINRT_RESOLVE_OP_HPP
+
+#if defined(_MSC_VER) && (_MSC_VER >= 1200)
+# pragma once
+#endif // defined(_MSC_VER) && (_MSC_VER >= 1200)
+
+#include "asio/detail/config.hpp"
+
+#if defined(ASIO_WINDOWS_RUNTIME)
+
+#include "asio/detail/bind_handler.hpp"
+#include "asio/detail/fenced_block.hpp"
+#include "asio/detail/handler_alloc_helpers.hpp"
+#include "asio/detail/handler_invoke_helpers.hpp"
+#include "asio/detail/memory.hpp"
+#include "asio/detail/winrt_async_op.hpp"
+#include "asio/ip/basic_resolver_results.hpp"
+#include "asio/error.hpp"
+
+#include "asio/detail/push_options.hpp"
+
+namespace asio {
+namespace detail {
+
+template <typename Protocol, typename Handler>
+class winrt_resolve_op :
+ public winrt_async_op<
+ Windows::Foundation::Collections::IVectorView<
+ Windows::Networking::EndpointPair^>^>
+{
+public:
+ ASIO_DEFINE_HANDLER_PTR(winrt_resolve_op);
+
+ typedef typename Protocol::endpoint endpoint_type;
+ typedef asio::ip::basic_resolver_query<Protocol> query_type;
+ typedef asio::ip::basic_resolver_results<Protocol> results_type;
+
+ winrt_resolve_op(const query_type& query, Handler& handler)
+ : winrt_async_op<
+ Windows::Foundation::Collections::IVectorView<
+ Windows::Networking::EndpointPair^>^>(
+ &winrt_resolve_op::do_complete),
+ query_(query),
+ handler_(ASIO_MOVE_CAST(Handler)(handler))
+ {
+ handler_work<Handler>::start(handler_);
+ }
+
+ static void do_complete(void* owner, operation* base,
+ const asio::error_code&, std::size_t)
+ {
+ // Take ownership of the operation object.
+ winrt_resolve_op* o(static_cast<winrt_resolve_op*>(base));
+ ptr p = { asio::detail::addressof(o->handler_), o, o };
+ handler_work<Handler> w(o->handler_);
+
+ ASIO_HANDLER_COMPLETION((*o));
+
+ results_type results = results_type();
+ if (!o->ec_)
+ {
+ try
+ {
+ results = results_type::create(o->result_, o->query_.hints(),
+ o->query_.host_name(), o->query_.service_name());
+ }
+ catch (Platform::Exception^ e)
+ {
+ o->ec_ = asio::error_code(e->HResult,
+ asio::system_category());
+ }
+ }
+
+ // 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::binder2<Handler, asio::error_code, results_type>
+ handler(o->handler_, o->ec_, results);
+ p.h = asio::detail::addressof(handler.handler_);
+ p.reset();
+
+ // Make the upcall if required.
+ if (owner)
+ {
+ fenced_block b(fenced_block::half);
+ ASIO_HANDLER_INVOCATION_BEGIN((handler.arg1_, "..."));
+ w.complete(handler, handler.handler_);
+ ASIO_HANDLER_INVOCATION_END;
+ }
+ }
+
+private:
+ query_type query_;
+ Handler handler_;
+};
+
+} // namespace detail
+} // namespace asio
+
+#include "asio/detail/pop_options.hpp"
+
+#endif // defined(ASIO_WINDOWS_RUNTIME)
+
+#endif // ASIO_DETAIL_WINRT_RESOLVE_OP_HPP
diff --git a/lib/asio/detail/winrt_resolver_service.hpp b/lib/asio/detail/winrt_resolver_service.hpp
new file mode 100644
index 0000000..aeb4448
--- /dev/null
+++ b/lib/asio/detail/winrt_resolver_service.hpp
@@ -0,0 +1,198 @@
+//
+// detail/winrt_resolver_service.hpp
+// ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+//
+// Copyright (c) 2003-2018 Christopher M. Kohlhoff (chris at kohlhoff dot com)
+//
+// 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 ASIO_DETAIL_WINRT_RESOLVER_SERVICE_HPP
+#define ASIO_DETAIL_WINRT_RESOLVER_SERVICE_HPP
+
+#if defined(_MSC_VER) && (_MSC_VER >= 1200)
+# pragma once
+#endif // defined(_MSC_VER) && (_MSC_VER >= 1200)
+
+#include "asio/detail/config.hpp"
+
+#if defined(ASIO_WINDOWS_RUNTIME)
+
+#include "asio/ip/basic_resolver_query.hpp"
+#include "asio/ip/basic_resolver_results.hpp"
+#include "asio/detail/bind_handler.hpp"
+#include "asio/detail/memory.hpp"
+#include "asio/detail/socket_ops.hpp"
+#include "asio/detail/winrt_async_manager.hpp"
+#include "asio/detail/winrt_resolve_op.hpp"
+#include "asio/detail/winrt_utils.hpp"
+
+#include "asio/detail/push_options.hpp"
+
+namespace asio {
+namespace detail {
+
+template <typename Protocol>
+class winrt_resolver_service :
+ public service_base<winrt_resolver_service<Protocol> >
+{
+public:
+ // The implementation type of the resolver. A cancellation token is used to
+ // indicate to the asynchronous operation that the operation has been
+ // cancelled.
+ typedef socket_ops::shared_cancel_token_type implementation_type;
+
+ // The endpoint type.
+ typedef typename Protocol::endpoint endpoint_type;
+
+ // The query type.
+ typedef asio::ip::basic_resolver_query<Protocol> query_type;
+
+ // The results type.
+ typedef asio::ip::basic_resolver_results<Protocol> results_type;
+
+ // Constructor.
+ winrt_resolver_service(asio::io_context& io_context)
+ : service_base<winrt_resolver_service<Protocol> >(io_context),
+ io_context_(use_service<io_context_impl>(io_context)),
+ async_manager_(use_service<winrt_async_manager>(io_context))
+ {
+ }
+
+ // Destructor.
+ ~winrt_resolver_service()
+ {
+ }
+
+ // Destroy all user-defined handler objects owned by the service.
+ void shutdown()
+ {
+ }
+
+ // Perform any fork-related housekeeping.
+ void notify_fork(asio::io_context::fork_event)
+ {
+ }
+
+ // Construct a new resolver implementation.
+ void construct(implementation_type&)
+ {
+ }
+
+ // Move-construct a new resolver implementation.
+ void move_construct(implementation_type&,
+ implementation_type&)
+ {
+ }
+
+ // Move-assign from another resolver implementation.
+ void move_assign(implementation_type&,
+ winrt_resolver_service&, implementation_type&)
+ {
+ }
+
+ // Destroy a resolver implementation.
+ void destroy(implementation_type&)
+ {
+ }
+
+ // Cancel pending asynchronous operations.
+ void cancel(implementation_type&)
+ {
+ }
+
+ // Resolve a query to a list of entries.
+ results_type resolve(implementation_type&,
+ const query_type& query, asio::error_code& ec)
+ {
+ try
+ {
+ using namespace Windows::Networking::Sockets;
+ auto endpoint_pairs = async_manager_.sync(
+ DatagramSocket::GetEndpointPairsAsync(
+ winrt_utils::host_name(query.host_name()),
+ winrt_utils::string(query.service_name())), ec);
+
+ if (ec)
+ return results_type();
+
+ return results_type::create(
+ endpoint_pairs, query.hints(),
+ query.host_name(), query.service_name());
+ }
+ catch (Platform::Exception^ e)
+ {
+ ec = asio::error_code(e->HResult,
+ asio::system_category());
+ return results_type();
+ }
+ }
+
+ // Asynchronously resolve a query to a list of entries.
+ template <typename Handler>
+ void async_resolve(implementation_type& impl,
+ const query_type& query, Handler& handler)
+ {
+ bool is_continuation =
+ asio_handler_cont_helpers::is_continuation(handler);
+
+ // Allocate and construct an operation to wrap the handler.
+ typedef winrt_resolve_op<Protocol, Handler> op;
+ typename op::ptr p = { asio::detail::addressof(handler),
+ op::ptr::allocate(handler), 0 };
+ p.p = new (p.v) op(query, handler);
+
+ ASIO_HANDLER_CREATION((io_context_.context(),
+ *p.p, "resolver", &impl, 0, "async_resolve"));
+ (void)impl;
+
+ try
+ {
+ using namespace Windows::Networking::Sockets;
+ async_manager_.async(DatagramSocket::GetEndpointPairsAsync(
+ winrt_utils::host_name(query.host_name()),
+ winrt_utils::string(query.service_name())), p.p);
+ p.v = p.p = 0;
+ }
+ catch (Platform::Exception^ e)
+ {
+ p.p->ec_ = asio::error_code(
+ e->HResult, asio::system_category());
+ io_context_.post_immediate_completion(p.p, is_continuation);
+ p.v = p.p = 0;
+ }
+ }
+
+ // Resolve an endpoint to a list of entries.
+ results_type resolve(implementation_type&,
+ const endpoint_type&, asio::error_code& ec)
+ {
+ ec = asio::error::operation_not_supported;
+ return results_type();
+ }
+
+ // Asynchronously resolve an endpoint to a list of entries.
+ template <typename Handler>
+ void async_resolve(implementation_type&,
+ const endpoint_type&, Handler& handler)
+ {
+ asio::error_code ec = asio::error::operation_not_supported;
+ const results_type results;
+ io_context_.get_io_context().post(
+ detail::bind_handler(handler, ec, results));
+ }
+
+private:
+ io_context_impl& io_context_;
+ winrt_async_manager& async_manager_;
+};
+
+} // namespace detail
+} // namespace asio
+
+#include "asio/detail/pop_options.hpp"
+
+#endif // defined(ASIO_WINDOWS_RUNTIME)
+
+#endif // ASIO_DETAIL_WINRT_RESOLVER_SERVICE_HPP
diff --git a/lib/asio/detail/winrt_socket_connect_op.hpp b/lib/asio/detail/winrt_socket_connect_op.hpp
new file mode 100644
index 0000000..f18b445
--- /dev/null
+++ b/lib/asio/detail/winrt_socket_connect_op.hpp
@@ -0,0 +1,92 @@
+//
+// detail/winrt_socket_connect_op.hpp
+// ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+//
+// Copyright (c) 2003-2018 Christopher M. Kohlhoff (chris at kohlhoff dot com)
+//
+// 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 ASIO_DETAIL_WINRT_SOCKET_CONNECT_OP_HPP
+#define ASIO_DETAIL_WINRT_SOCKET_CONNECT_OP_HPP
+
+#if defined(_MSC_VER) && (_MSC_VER >= 1200)
+# pragma once
+#endif // defined(_MSC_VER) && (_MSC_VER >= 1200)
+
+#include "asio/detail/config.hpp"
+
+#if defined(ASIO_WINDOWS_RUNTIME)
+
+#include "asio/detail/bind_handler.hpp"
+#include "asio/detail/buffer_sequence_adapter.hpp"
+#include "asio/detail/fenced_block.hpp"
+#include "asio/detail/handler_alloc_helpers.hpp"
+#include "asio/detail/handler_invoke_helpers.hpp"
+#include "asio/detail/memory.hpp"
+#include "asio/detail/winrt_async_op.hpp"
+#include "asio/error.hpp"
+
+#include "asio/detail/push_options.hpp"
+
+namespace asio {
+namespace detail {
+
+template <typename Handler>
+class winrt_socket_connect_op :
+ public winrt_async_op<void>
+{
+public:
+ ASIO_DEFINE_HANDLER_PTR(winrt_socket_connect_op);
+
+ winrt_socket_connect_op(Handler& handler)
+ : winrt_async_op<void>(&winrt_socket_connect_op::do_complete),
+ handler_(ASIO_MOVE_CAST(Handler)(handler))
+ {
+ handler_work<Handler>::start(handler_);
+ }
+
+ static void do_complete(void* owner, operation* base,
+ const asio::error_code&, std::size_t)
+ {
+ // Take ownership of the operation object.
+ winrt_socket_connect_op* o(static_cast<winrt_socket_connect_op*>(base));
+ ptr p = { asio::detail::addressof(o->handler_), o, o };
+ handler_work<Handler> w(o->handler_);
+
+ ASIO_HANDLER_COMPLETION((*o));
+
+ // 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::binder1<Handler, asio::error_code>
+ handler(o->handler_, o->ec_);
+ p.h = asio::detail::addressof(handler.handler_);
+ p.reset();
+
+ // Make the upcall if required.
+ if (owner)
+ {
+ fenced_block b(fenced_block::half);
+ ASIO_HANDLER_INVOCATION_BEGIN((handler.arg1_));
+ w.complete(handler, handler.handler_);
+ ASIO_HANDLER_INVOCATION_END;
+ }
+ }
+
+private:
+ Handler handler_;
+};
+
+} // namespace detail
+} // namespace asio
+
+#include "asio/detail/pop_options.hpp"
+
+#endif // defined(ASIO_WINDOWS_RUNTIME)
+
+#endif // ASIO_DETAIL_WINRT_SOCKET_CONNECT_OP_HPP
diff --git a/lib/asio/detail/winrt_socket_recv_op.hpp b/lib/asio/detail/winrt_socket_recv_op.hpp
new file mode 100644
index 0000000..8f1fcf5
--- /dev/null
+++ b/lib/asio/detail/winrt_socket_recv_op.hpp
@@ -0,0 +1,112 @@
+//
+// detail/winrt_socket_recv_op.hpp
+// ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+//
+// Copyright (c) 2003-2018 Christopher M. Kohlhoff (chris at kohlhoff dot com)
+//
+// 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 ASIO_DETAIL_WINRT_SOCKET_RECV_OP_HPP
+#define ASIO_DETAIL_WINRT_SOCKET_RECV_OP_HPP
+
+#if defined(_MSC_VER) && (_MSC_VER >= 1200)
+# pragma once
+#endif // defined(_MSC_VER) && (_MSC_VER >= 1200)
+
+#include "asio/detail/config.hpp"
+
+#if defined(ASIO_WINDOWS_RUNTIME)
+
+#include "asio/detail/bind_handler.hpp"
+#include "asio/detail/buffer_sequence_adapter.hpp"
+#include "asio/detail/fenced_block.hpp"
+#include "asio/detail/handler_alloc_helpers.hpp"
+#include "asio/detail/handler_invoke_helpers.hpp"
+#include "asio/detail/memory.hpp"
+#include "asio/detail/winrt_async_op.hpp"
+#include "asio/error.hpp"
+
+#include "asio/detail/push_options.hpp"
+
+namespace asio {
+namespace detail {
+
+template <typename MutableBufferSequence, typename Handler>
+class winrt_socket_recv_op :
+ public winrt_async_op<Windows::Storage::Streams::IBuffer^>
+{
+public:
+ ASIO_DEFINE_HANDLER_PTR(winrt_socket_recv_op);
+
+ winrt_socket_recv_op(const MutableBufferSequence& buffers, Handler& handler)
+ : winrt_async_op<Windows::Storage::Streams::IBuffer^>(
+ &winrt_socket_recv_op::do_complete),
+ buffers_(buffers),
+ handler_(ASIO_MOVE_CAST(Handler)(handler))
+ {
+ handler_work<Handler>::start(handler_);
+ }
+
+ static void do_complete(void* owner, operation* base,
+ const asio::error_code&, std::size_t)
+ {
+ // Take ownership of the operation object.
+ winrt_socket_recv_op* o(static_cast<winrt_socket_recv_op*>(base));
+ ptr p = { asio::detail::addressof(o->handler_), o, o };
+ handler_work<Handler> w(o->handler_);
+
+ ASIO_HANDLER_COMPLETION((*o));
+
+#if defined(ASIO_ENABLE_BUFFER_DEBUGGING)
+ // Check whether buffers are still valid.
+ if (owner)
+ {
+ buffer_sequence_adapter<asio::mutable_buffer,
+ MutableBufferSequence>::validate(o->buffers_);
+ }
+#endif // defined(ASIO_ENABLE_BUFFER_DEBUGGING)
+
+ std::size_t bytes_transferred = o->result_ ? o->result_->Length : 0;
+ if (bytes_transferred == 0 && !o->ec_ &&
+ !buffer_sequence_adapter<asio::mutable_buffer,
+ MutableBufferSequence>::all_empty(o->buffers_))
+ {
+ o->ec_ = asio::error::eof;
+ }
+
+ // 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::binder2<Handler, asio::error_code, std::size_t>
+ handler(o->handler_, o->ec_, bytes_transferred);
+ p.h = asio::detail::addressof(handler.handler_);
+ p.reset();
+
+ // Make the upcall if required.
+ if (owner)
+ {
+ fenced_block b(fenced_block::half);
+ ASIO_HANDLER_INVOCATION_BEGIN((handler.arg1_, handler.arg2_));
+ w.complete(handler, handler.handler_);
+ ASIO_HANDLER_INVOCATION_END;
+ }
+ }
+
+private:
+ MutableBufferSequence buffers_;
+ Handler handler_;
+};
+
+} // namespace detail
+} // namespace asio
+
+#include "asio/detail/pop_options.hpp"
+
+#endif // defined(ASIO_WINDOWS_RUNTIME)
+
+#endif // ASIO_DETAIL_WINRT_SOCKET_RECV_OP_HPP
diff --git a/lib/asio/detail/winrt_socket_send_op.hpp b/lib/asio/detail/winrt_socket_send_op.hpp
new file mode 100644
index 0000000..1148c24
--- /dev/null
+++ b/lib/asio/detail/winrt_socket_send_op.hpp
@@ -0,0 +1,103 @@
+//
+// detail/winrt_socket_send_op.hpp
+// ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+//
+// Copyright (c) 2003-2018 Christopher M. Kohlhoff (chris at kohlhoff dot com)
+//
+// 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 ASIO_DETAIL_WINRT_SOCKET_SEND_OP_HPP
+#define ASIO_DETAIL_WINRT_SOCKET_SEND_OP_HPP
+
+#if defined(_MSC_VER) && (_MSC_VER >= 1200)
+# pragma once
+#endif // defined(_MSC_VER) && (_MSC_VER >= 1200)
+
+#include "asio/detail/config.hpp"
+
+#if defined(ASIO_WINDOWS_RUNTIME)
+
+#include "asio/detail/bind_handler.hpp"
+#include "asio/detail/buffer_sequence_adapter.hpp"
+#include "asio/detail/fenced_block.hpp"
+#include "asio/detail/handler_alloc_helpers.hpp"
+#include "asio/detail/handler_invoke_helpers.hpp"
+#include "asio/detail/memory.hpp"
+#include "asio/detail/winrt_async_op.hpp"
+#include "asio/error.hpp"
+
+#include "asio/detail/push_options.hpp"
+
+namespace asio {
+namespace detail {
+
+template <typename ConstBufferSequence, typename Handler>
+class winrt_socket_send_op :
+ public winrt_async_op<unsigned int>
+{
+public:
+ ASIO_DEFINE_HANDLER_PTR(winrt_socket_send_op);
+
+ winrt_socket_send_op(const ConstBufferSequence& buffers, Handler& handler)
+ : winrt_async_op<unsigned int>(&winrt_socket_send_op::do_complete),
+ buffers_(buffers),
+ handler_(ASIO_MOVE_CAST(Handler)(handler))
+ {
+ handler_work<Handler>::start(handler_);
+ }
+
+ static void do_complete(void* owner, operation* base,
+ const asio::error_code&, std::size_t)
+ {
+ // Take ownership of the operation object.
+ winrt_socket_send_op* o(static_cast<winrt_socket_send_op*>(base));
+ ptr p = { asio::detail::addressof(o->handler_), o, o };
+ handler_work<Handler> w(o->handler_);
+
+ ASIO_HANDLER_COMPLETION((*o));
+
+#if defined(ASIO_ENABLE_BUFFER_DEBUGGING)
+ // Check whether buffers are still valid.
+ if (owner)
+ {
+ buffer_sequence_adapter<asio::const_buffer,
+ ConstBufferSequence>::validate(o->buffers_);
+ }
+#endif // defined(ASIO_ENABLE_BUFFER_DEBUGGING)
+
+ // 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::binder2<Handler, asio::error_code, std::size_t>
+ handler(o->handler_, o->ec_, o->result_);
+ p.h = asio::detail::addressof(handler.handler_);
+ p.reset();
+
+ // Make the upcall if required.
+ if (owner)
+ {
+ fenced_block b(fenced_block::half);
+ ASIO_HANDLER_INVOCATION_BEGIN((handler.arg1_, handler.arg2_));
+ w.complete(handler, handler.handler_);
+ ASIO_HANDLER_INVOCATION_END;
+ }
+ }
+
+private:
+ ConstBufferSequence buffers_;
+ Handler handler_;
+};
+
+} // namespace detail
+} // namespace asio
+
+#include "asio/detail/pop_options.hpp"
+
+#endif // defined(ASIO_WINDOWS_RUNTIME)
+
+#endif // ASIO_DETAIL_WINRT_SOCKET_SEND_OP_HPP
diff --git a/lib/asio/detail/winrt_ssocket_service.hpp b/lib/asio/detail/winrt_ssocket_service.hpp
new file mode 100644
index 0000000..603724a
--- /dev/null
+++ b/lib/asio/detail/winrt_ssocket_service.hpp
@@ -0,0 +1,241 @@
+//
+// detail/winrt_ssocket_service.hpp
+// ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+//
+// Copyright (c) 2003-2018 Christopher M. Kohlhoff (chris at kohlhoff dot com)
+//
+// 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 ASIO_DETAIL_WINRT_SSOCKET_SERVICE_HPP
+#define ASIO_DETAIL_WINRT_SSOCKET_SERVICE_HPP
+
+#if defined(_MSC_VER) && (_MSC_VER >= 1200)
+# pragma once
+#endif // defined(_MSC_VER) && (_MSC_VER >= 1200)
+
+#include "asio/detail/config.hpp"
+
+#if defined(ASIO_WINDOWS_RUNTIME)
+
+#include "asio/error.hpp"
+#include "asio/io_context.hpp"
+#include "asio/detail/memory.hpp"
+#include "asio/detail/winrt_socket_connect_op.hpp"
+#include "asio/detail/winrt_ssocket_service_base.hpp"
+#include "asio/detail/winrt_utils.hpp"
+
+#include "asio/detail/push_options.hpp"
+
+namespace asio {
+namespace detail {
+
+template <typename Protocol>
+class winrt_ssocket_service :
+ public service_base<winrt_ssocket_service<Protocol> >,
+ public winrt_ssocket_service_base
+{
+public:
+ // The protocol type.
+ typedef Protocol protocol_type;
+
+ // The endpoint type.
+ typedef typename Protocol::endpoint endpoint_type;
+
+ // The native type of a socket.
+ typedef Windows::Networking::Sockets::StreamSocket^ native_handle_type;
+
+ // The implementation type of the socket.
+ struct implementation_type : base_implementation_type
+ {
+ // Default constructor.
+ implementation_type()
+ : base_implementation_type(),
+ protocol_(endpoint_type().protocol())
+ {
+ }
+
+ // The protocol associated with the socket.
+ protocol_type protocol_;
+ };
+
+ // Constructor.
+ winrt_ssocket_service(asio::io_context& io_context)
+ : service_base<winrt_ssocket_service<Protocol> >(io_context),
+ winrt_ssocket_service_base(io_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,
+ winrt_ssocket_service& 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,
+ winrt_ssocket_service<Protocol1>&,
+ typename winrt_ssocket_service<
+ 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.
+ asio::error_code open(implementation_type& impl,
+ const protocol_type& protocol, asio::error_code& ec)
+ {
+ if (is_open(impl))
+ {
+ ec = asio::error::already_open;
+ return ec;
+ }
+
+ try
+ {
+ impl.socket_ = ref new Windows::Networking::Sockets::StreamSocket;
+ impl.protocol_ = protocol;
+ ec = asio::error_code();
+ }
+ catch (Platform::Exception^ e)
+ {
+ ec = asio::error_code(e->HResult,
+ asio::system_category());
+ }
+
+ return ec;
+ }
+
+ // Assign a native socket to a socket implementation.
+ asio::error_code assign(implementation_type& impl,
+ const protocol_type& protocol, const native_handle_type& native_socket,
+ asio::error_code& ec)
+ {
+ if (is_open(impl))
+ {
+ ec = asio::error::already_open;
+ return ec;
+ }
+
+ impl.socket_ = native_socket;
+ impl.protocol_ = protocol;
+ ec = asio::error_code();
+
+ return ec;
+ }
+
+ // Bind the socket to the specified local endpoint.
+ asio::error_code bind(implementation_type&,
+ const endpoint_type&, asio::error_code& ec)
+ {
+ ec = asio::error::operation_not_supported;
+ return ec;
+ }
+
+ // Get the local endpoint.
+ endpoint_type local_endpoint(const implementation_type& impl,
+ asio::error_code& ec) const
+ {
+ endpoint_type endpoint;
+ endpoint.resize(do_get_endpoint(impl, true,
+ endpoint.data(), endpoint.size(), ec));
+ return endpoint;
+ }
+
+ // Get the remote endpoint.
+ endpoint_type remote_endpoint(const implementation_type& impl,
+ asio::error_code& ec) const
+ {
+ endpoint_type endpoint;
+ endpoint.resize(do_get_endpoint(impl, false,
+ endpoint.data(), endpoint.size(), ec));
+ return endpoint;
+ }
+
+ // Set a socket option.
+ template <typename Option>
+ asio::error_code set_option(implementation_type& impl,
+ const Option& option, asio::error_code& ec)
+ {
+ return do_set_option(impl, option.level(impl.protocol_),
+ option.name(impl.protocol_), option.data(impl.protocol_),
+ option.size(impl.protocol_), ec);
+ }
+
+ // Get a socket option.
+ template <typename Option>
+ asio::error_code get_option(const implementation_type& impl,
+ Option& option, asio::error_code& ec) const
+ {
+ std::size_t size = option.size(impl.protocol_);
+ do_get_option(impl, option.level(impl.protocol_),
+ option.name(impl.protocol_),
+ option.data(impl.protocol_), &size, ec);
+ if (!ec)
+ option.resize(impl.protocol_, size);
+ return ec;
+ }
+
+ // Connect the socket to the specified endpoint.
+ asio::error_code connect(implementation_type& impl,
+ const endpoint_type& peer_endpoint, asio::error_code& ec)
+ {
+ return do_connect(impl, peer_endpoint.data(), ec);
+ }
+
+ // Start an asynchronous connect.
+ template <typename Handler>
+ void async_connect(implementation_type& impl,
+ const endpoint_type& peer_endpoint, Handler& handler)
+ {
+ bool is_continuation =
+ asio_handler_cont_helpers::is_continuation(handler);
+
+ // Allocate and construct an operation to wrap the handler.
+ typedef winrt_socket_connect_op<Handler> op;
+ typename op::ptr p = { asio::detail::addressof(handler),
+ op::ptr::allocate(handler), 0 };
+ p.p = new (p.v) op(handler);
+
+ ASIO_HANDLER_CREATION((io_context_.context(),
+ *p.p, "socket", &impl, 0, "async_connect"));
+
+ start_connect_op(impl, peer_endpoint.data(), p.p, is_continuation);
+ p.v = p.p = 0;
+ }
+};
+
+} // namespace detail
+} // namespace asio
+
+#include "asio/detail/pop_options.hpp"
+
+#endif // defined(ASIO_WINDOWS_RUNTIME)
+
+#endif // ASIO_DETAIL_WINRT_SSOCKET_SERVICE_HPP
diff --git a/lib/asio/detail/winrt_ssocket_service_base.hpp b/lib/asio/detail/winrt_ssocket_service_base.hpp
new file mode 100644
index 0000000..61328d0
--- /dev/null
+++ b/lib/asio/detail/winrt_ssocket_service_base.hpp
@@ -0,0 +1,359 @@
+//
+// detail/winrt_ssocket_service_base.hpp
+// ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+//
+// Copyright (c) 2003-2018 Christopher M. Kohlhoff (chris at kohlhoff dot com)
+//
+// 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 ASIO_DETAIL_WINRT_SSOCKET_SERVICE_BASE_HPP
+#define ASIO_DETAIL_WINRT_SSOCKET_SERVICE_BASE_HPP
+
+#if defined(_MSC_VER) && (_MSC_VER >= 1200)
+# pragma once
+#endif // defined(_MSC_VER) && (_MSC_VER >= 1200)
+
+#include "asio/detail/config.hpp"
+
+#if defined(ASIO_WINDOWS_RUNTIME)
+
+#include "asio/buffer.hpp"
+#include "asio/error.hpp"
+#include "asio/io_context.hpp"
+#include "asio/socket_base.hpp"
+#include "asio/detail/buffer_sequence_adapter.hpp"
+#include "asio/detail/memory.hpp"
+#include "asio/detail/socket_types.hpp"
+#include "asio/detail/winrt_async_manager.hpp"
+#include "asio/detail/winrt_socket_recv_op.hpp"
+#include "asio/detail/winrt_socket_send_op.hpp"
+
+#include "asio/detail/push_options.hpp"
+
+namespace asio {
+namespace detail {
+
+class winrt_ssocket_service_base
+{
+public:
+ // The native type of a socket.
+ typedef Windows::Networking::Sockets::StreamSocket^ native_handle_type;
+
+ // The implementation type of the socket.
+ struct base_implementation_type
+ {
+ // Default constructor.
+ base_implementation_type()
+ : socket_(nullptr),
+ next_(0),
+ prev_(0)
+ {
+ }
+
+ // The underlying native socket.
+ native_handle_type socket_;
+
+ // Pointers to adjacent socket implementations in linked list.
+ base_implementation_type* next_;
+ base_implementation_type* prev_;
+ };
+
+ // Constructor.
+ ASIO_DECL winrt_ssocket_service_base(
+ asio::io_context& io_context);
+
+ // Destroy all user-defined handler objects owned by the service.
+ ASIO_DECL void base_shutdown();
+
+ // Construct a new socket implementation.
+ ASIO_DECL void construct(base_implementation_type&);
+
+ // Move-construct a new socket implementation.
+ ASIO_DECL void base_move_construct(base_implementation_type& impl,
+ base_implementation_type& other_impl);
+
+ // Move-assign from another socket implementation.
+ ASIO_DECL void base_move_assign(base_implementation_type& impl,
+ winrt_ssocket_service_base& other_service,
+ base_implementation_type& other_impl);
+
+ // Destroy a socket implementation.
+ 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_ != nullptr;
+ }
+
+ // Destroy a socket implementation.
+ ASIO_DECL asio::error_code close(
+ base_implementation_type& impl, asio::error_code& ec);
+
+ // Release ownership of the socket.
+ ASIO_DECL native_handle_type release(
+ base_implementation_type& impl, asio::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.
+ asio::error_code cancel(base_implementation_type&,
+ asio::error_code& ec)
+ {
+ ec = asio::error::operation_not_supported;
+ return ec;
+ }
+
+ // Determine whether the socket is at the out-of-band data mark.
+ bool at_mark(const base_implementation_type&,
+ asio::error_code& ec) const
+ {
+ ec = asio::error::operation_not_supported;
+ return false;
+ }
+
+ // Determine the number of bytes available for reading.
+ std::size_t available(const base_implementation_type&,
+ asio::error_code& ec) const
+ {
+ ec = asio::error::operation_not_supported;
+ return 0;
+ }
+
+ // Perform an IO control command on the socket.
+ template <typename IO_Control_Command>
+ asio::error_code io_control(base_implementation_type&,
+ IO_Control_Command&, asio::error_code& ec)
+ {
+ ec = asio::error::operation_not_supported;
+ return ec;
+ }
+
+ // Gets the non-blocking mode of the socket.
+ bool non_blocking(const base_implementation_type&) const
+ {
+ return false;
+ }
+
+ // Sets the non-blocking mode of the socket.
+ asio::error_code non_blocking(base_implementation_type&,
+ bool, asio::error_code& ec)
+ {
+ ec = asio::error::operation_not_supported;
+ return ec;
+ }
+
+ // Gets the non-blocking mode of the native socket implementation.
+ bool native_non_blocking(const base_implementation_type&) const
+ {
+ return false;
+ }
+
+ // Sets the non-blocking mode of the native socket implementation.
+ asio::error_code native_non_blocking(base_implementation_type&,
+ bool, asio::error_code& ec)
+ {
+ ec = asio::error::operation_not_supported;
+ return ec;
+ }
+
+ // Disable sends or receives on the socket.
+ asio::error_code shutdown(base_implementation_type&,
+ socket_base::shutdown_type, asio::error_code& ec)
+ {
+ ec = asio::error::operation_not_supported;
+ return ec;
+ }
+
+ // Send the given data to the peer.
+ template <typename ConstBufferSequence>
+ std::size_t send(base_implementation_type& impl,
+ const ConstBufferSequence& buffers,
+ socket_base::message_flags flags, asio::error_code& ec)
+ {
+ return do_send(impl,
+ buffer_sequence_adapter<asio::const_buffer,
+ ConstBufferSequence>::first(buffers), flags, ec);
+ }
+
+ // Wait until data can be sent without blocking.
+ std::size_t send(base_implementation_type&, const null_buffers&,
+ socket_base::message_flags, asio::error_code& ec)
+ {
+ ec = asio::error::operation_not_supported;
+ 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>
+ void async_send(base_implementation_type& impl,
+ const ConstBufferSequence& buffers,
+ socket_base::message_flags flags, Handler& handler)
+ {
+ bool is_continuation =
+ asio_handler_cont_helpers::is_continuation(handler);
+
+ // Allocate and construct an operation to wrap the handler.
+ typedef winrt_socket_send_op<ConstBufferSequence, Handler> op;
+ typename op::ptr p = { asio::detail::addressof(handler),
+ op::ptr::allocate(handler), 0 };
+ p.p = new (p.v) op(buffers, handler);
+
+ ASIO_HANDLER_CREATION((io_context_.context(),
+ *p.p, "socket", &impl, 0, "async_send"));
+
+ start_send_op(impl,
+ buffer_sequence_adapter<asio::const_buffer,
+ ConstBufferSequence>::first(buffers),
+ flags, p.p, is_continuation);
+ p.v = p.p = 0;
+ }
+
+ // Start an asynchronous wait until data can be sent without blocking.
+ template <typename Handler>
+ void async_send(base_implementation_type&, const null_buffers&,
+ socket_base::message_flags, Handler& handler)
+ {
+ asio::error_code ec = asio::error::operation_not_supported;
+ const std::size_t bytes_transferred = 0;
+ io_context_.get_io_context().post(
+ detail::bind_handler(handler, ec, bytes_transferred));
+ }
+
+ // Receive some data from the peer. Returns the number of bytes received.
+ template <typename MutableBufferSequence>
+ std::size_t receive(base_implementation_type& impl,
+ const MutableBufferSequence& buffers,
+ socket_base::message_flags flags, asio::error_code& ec)
+ {
+ return do_receive(impl,
+ buffer_sequence_adapter<asio::mutable_buffer,
+ MutableBufferSequence>::first(buffers), flags, ec);
+ }
+
+ // Wait until data can be received without blocking.
+ std::size_t receive(base_implementation_type&, const null_buffers&,
+ socket_base::message_flags, asio::error_code& ec)
+ {
+ ec = asio::error::operation_not_supported;
+ 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>
+ void async_receive(base_implementation_type& impl,
+ const MutableBufferSequence& buffers,
+ socket_base::message_flags flags, Handler& handler)
+ {
+ bool is_continuation =
+ asio_handler_cont_helpers::is_continuation(handler);
+
+ // Allocate and construct an operation to wrap the handler.
+ typedef winrt_socket_recv_op<MutableBufferSequence, Handler> op;
+ typename op::ptr p = { asio::detail::addressof(handler),
+ op::ptr::allocate(handler), 0 };
+ p.p = new (p.v) op(buffers, handler);
+
+ ASIO_HANDLER_CREATION((io_context_.context(),
+ *p.p, "socket", &impl, 0, "async_receive"));
+
+ start_receive_op(impl,
+ buffer_sequence_adapter<asio::mutable_buffer,
+ MutableBufferSequence>::first(buffers),
+ flags, p.p, is_continuation);
+ p.v = p.p = 0;
+ }
+
+ // Wait until data can be received without blocking.
+ template <typename Handler>
+ void async_receive(base_implementation_type&, const null_buffers&,
+ socket_base::message_flags, Handler& handler)
+ {
+ asio::error_code ec = asio::error::operation_not_supported;
+ const std::size_t bytes_transferred = 0;
+ io_context_.get_io_context().post(
+ detail::bind_handler(handler, ec, bytes_transferred));
+ }
+
+protected:
+ // Helper function to obtain endpoints associated with the connection.
+ ASIO_DECL std::size_t do_get_endpoint(
+ const base_implementation_type& impl, bool local,
+ void* addr, std::size_t addr_len, asio::error_code& ec) const;
+
+ // Helper function to set a socket option.
+ ASIO_DECL asio::error_code do_set_option(
+ base_implementation_type& impl,
+ int level, int optname, const void* optval,
+ std::size_t optlen, asio::error_code& ec);
+
+ // Helper function to get a socket option.
+ ASIO_DECL void do_get_option(
+ const base_implementation_type& impl,
+ int level, int optname, void* optval,
+ std::size_t* optlen, asio::error_code& ec) const;
+
+ // Helper function to perform a synchronous connect.
+ ASIO_DECL asio::error_code do_connect(
+ base_implementation_type& impl,
+ const void* addr, asio::error_code& ec);
+
+ // Helper function to start an asynchronous connect.
+ ASIO_DECL void start_connect_op(
+ base_implementation_type& impl, const void* addr,
+ winrt_async_op<void>* op, bool is_continuation);
+
+ // Helper function to perform a synchronous send.
+ ASIO_DECL std::size_t do_send(
+ base_implementation_type& impl, const asio::const_buffer& data,
+ socket_base::message_flags flags, asio::error_code& ec);
+
+ // Helper function to start an asynchronous send.
+ ASIO_DECL void start_send_op(base_implementation_type& impl,
+ const asio::const_buffer& data, socket_base::message_flags flags,
+ winrt_async_op<unsigned int>* op, bool is_continuation);
+
+ // Helper function to perform a synchronous receive.
+ ASIO_DECL std::size_t do_receive(
+ base_implementation_type& impl, const asio::mutable_buffer& data,
+ socket_base::message_flags flags, asio::error_code& ec);
+
+ // Helper function to start an asynchronous receive.
+ ASIO_DECL void start_receive_op(base_implementation_type& impl,
+ const asio::mutable_buffer& data, socket_base::message_flags flags,
+ winrt_async_op<Windows::Storage::Streams::IBuffer^>* op,
+ bool is_continuation);
+
+ // The io_context implementation used for delivering completions.
+ io_context_impl& io_context_;
+
+ // The manager that keeps track of outstanding operations.
+ winrt_async_manager& async_manager_;
+
+ // Mutex to protect access to the linked list of implementations.
+ asio::detail::mutex mutex_;
+
+ // The head of a linked list of all implementations.
+ base_implementation_type* impl_list_;
+};
+
+} // namespace detail
+} // namespace asio
+
+#include "asio/detail/pop_options.hpp"
+
+#if defined(ASIO_HEADER_ONLY)
+# include "asio/detail/impl/winrt_ssocket_service_base.ipp"
+#endif // defined(ASIO_HEADER_ONLY)
+
+#endif // defined(ASIO_WINDOWS_RUNTIME)
+
+#endif // ASIO_DETAIL_WINRT_SSOCKET_SERVICE_BASE_HPP
diff --git a/lib/asio/detail/winrt_timer_scheduler.hpp b/lib/asio/detail/winrt_timer_scheduler.hpp
new file mode 100644
index 0000000..5dec7c0
--- /dev/null
+++ b/lib/asio/detail/winrt_timer_scheduler.hpp
@@ -0,0 +1,137 @@
+//
+// detail/winrt_timer_scheduler.hpp
+// ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+//
+// Copyright (c) 2003-2018 Christopher M. Kohlhoff (chris at kohlhoff dot com)
+//
+// 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 ASIO_DETAIL_WINRT_TIMER_SCHEDULER_HPP
+#define ASIO_DETAIL_WINRT_TIMER_SCHEDULER_HPP
+
+#if defined(_MSC_VER) && (_MSC_VER >= 1200)
+# pragma once
+#endif // defined(_MSC_VER) && (_MSC_VER >= 1200)
+
+#include "asio/detail/config.hpp"
+
+#if defined(ASIO_WINDOWS_RUNTIME)
+
+#include <cstddef>
+#include "asio/detail/event.hpp"
+#include "asio/detail/limits.hpp"
+#include "asio/detail/mutex.hpp"
+#include "asio/detail/op_queue.hpp"
+#include "asio/detail/thread.hpp"
+#include "asio/detail/timer_queue_base.hpp"
+#include "asio/detail/timer_queue_set.hpp"
+#include "asio/detail/wait_op.hpp"
+#include "asio/io_context.hpp"
+
+#if defined(ASIO_HAS_IOCP)
+# include "asio/detail/thread.hpp"
+#endif // defined(ASIO_HAS_IOCP)
+
+#include "asio/detail/push_options.hpp"
+
+namespace asio {
+namespace detail {
+
+class winrt_timer_scheduler
+ : public asio::detail::service_base<winrt_timer_scheduler>
+{
+public:
+ // Constructor.
+ ASIO_DECL winrt_timer_scheduler(asio::io_context& io_context);
+
+ // Destructor.
+ ASIO_DECL ~winrt_timer_scheduler();
+
+ // Destroy all user-defined handler objects owned by the service.
+ ASIO_DECL void shutdown();
+
+ // Recreate internal descriptors following a fork.
+ ASIO_DECL void notify_fork(
+ asio::io_context::fork_event fork_ev);
+
+ // Initialise the task. No effect as this class uses its own thread.
+ ASIO_DECL void init_task();
+
+ // Add a new timer queue to the reactor.
+ template <typename Time_Traits>
+ void add_timer_queue(timer_queue<Time_Traits>& queue);
+
+ // Remove a timer queue from the reactor.
+ template <typename Time_Traits>
+ void remove_timer_queue(timer_queue<Time_Traits>& queue);
+
+ // Schedule a new operation in the given timer queue to expire at the
+ // specified absolute time.
+ template <typename Time_Traits>
+ void schedule_timer(timer_queue<Time_Traits>& queue,
+ const typename Time_Traits::time_type& time,
+ typename timer_queue<Time_Traits>::per_timer_data& timer, wait_op* op);
+
+ // Cancel the timer operations associated with the given token. Returns the
+ // number of operations that have been posted or dispatched.
+ template <typename Time_Traits>
+ std::size_t cancel_timer(timer_queue<Time_Traits>& queue,
+ typename timer_queue<Time_Traits>::per_timer_data& timer,
+ std::size_t max_cancelled = (std::numeric_limits<std::size_t>::max)());
+
+ // Move the timer operations associated with the given timer.
+ template <typename Time_Traits>
+ void move_timer(timer_queue<Time_Traits>& queue,
+ typename timer_queue<Time_Traits>::per_timer_data& to,
+ typename timer_queue<Time_Traits>::per_timer_data& from);
+
+private:
+ // Run the select loop in the thread.
+ ASIO_DECL void run_thread();
+
+ // Entry point for the select loop thread.
+ ASIO_DECL static void call_run_thread(winrt_timer_scheduler* reactor);
+
+ // Helper function to add a new timer queue.
+ ASIO_DECL void do_add_timer_queue(timer_queue_base& queue);
+
+ // Helper function to remove a timer queue.
+ ASIO_DECL void do_remove_timer_queue(timer_queue_base& queue);
+
+ // The io_context implementation used to post completions.
+ io_context_impl& io_context_;
+
+ // Mutex used to protect internal variables.
+ asio::detail::mutex mutex_;
+
+ // Event used to wake up background thread.
+ asio::detail::event event_;
+
+ // The timer queues.
+ timer_queue_set timer_queues_;
+
+ // The background thread that is waiting for timers to expire.
+ asio::detail::thread* thread_;
+
+ // Does the background thread need to stop.
+ bool stop_thread_;
+
+ // Whether the service has been shut down.
+ bool shutdown_;
+};
+
+} // namespace detail
+} // namespace asio
+
+#include "asio/detail/pop_options.hpp"
+
+#include "asio/detail/impl/winrt_timer_scheduler.hpp"
+#if defined(ASIO_HEADER_ONLY)
+# include "asio/detail/impl/winrt_timer_scheduler.ipp"
+#endif // defined(ASIO_HEADER_ONLY)
+
+#endif // defined(ASIO_WINDOWS_RUNTIME)
+
+#endif // ASIO_DETAIL_WINRT_TIMER_SCHEDULER_HPP
diff --git a/lib/asio/detail/winrt_utils.hpp b/lib/asio/detail/winrt_utils.hpp
new file mode 100644
index 0000000..22a2489
--- /dev/null
+++ b/lib/asio/detail/winrt_utils.hpp
@@ -0,0 +1,106 @@
+//
+// detail/winrt_utils.hpp
+// ~~~~~~~~~~~~~~~~~~~~~~
+//
+// Copyright (c) 2003-2018 Christopher M. Kohlhoff (chris at kohlhoff dot com)
+//
+// 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 ASIO_DETAIL_WINRT_UTILS_HPP
+#define ASIO_DETAIL_WINRT_UTILS_HPP
+
+#if defined(_MSC_VER) && (_MSC_VER >= 1200)
+# pragma once
+#endif // defined(_MSC_VER) && (_MSC_VER >= 1200)
+
+#include "asio/detail/config.hpp"
+
+#if defined(ASIO_WINDOWS_RUNTIME)
+
+#include <codecvt>
+#include <cstdlib>
+#include <future>
+#include <locale>
+#include <robuffer.h>
+#include <windows.storage.streams.h>
+#include <wrl/implements.h>
+#include "asio/buffer.hpp"
+#include "asio/error_code.hpp"
+#include "asio/detail/memory.hpp"
+#include "asio/detail/socket_ops.hpp"
+
+#include "asio/detail/push_options.hpp"
+
+namespace asio {
+namespace detail {
+namespace winrt_utils {
+
+inline Platform::String^ string(const char* from)
+{
+ std::wstring tmp(from, from + std::strlen(from));
+ return ref new Platform::String(tmp.c_str());
+}
+
+inline Platform::String^ string(const std::string& from)
+{
+ std::wstring tmp(from.begin(), from.end());
+ return ref new Platform::String(tmp.c_str());
+}
+
+inline std::string string(Platform::String^ from)
+{
+ std::wstring_convert<std::codecvt_utf8<wchar_t>> converter;
+ return converter.to_bytes(from->Data());
+}
+
+inline Platform::String^ string(unsigned short from)
+{
+ return string(std::to_string(from));
+}
+
+template <typename T>
+inline Platform::String^ string(const T& from)
+{
+ return string(from.to_string());
+}
+
+inline int integer(Platform::String^ from)
+{
+ return _wtoi(from->Data());
+}
+
+template <typename T>
+inline Windows::Networking::HostName^ host_name(const T& from)
+{
+ return ref new Windows::Networking::HostName((string)(from));
+}
+
+template <typename ConstBufferSequence>
+inline Windows::Storage::Streams::IBuffer^ buffer_dup(
+ const ConstBufferSequence& buffers)
+{
+ using Microsoft::WRL::ComPtr;
+ using asio::buffer_size;
+ std::size_t size = buffer_size(buffers);
+ auto b = ref new Windows::Storage::Streams::Buffer(size);
+ ComPtr<IInspectable> insp = reinterpret_cast<IInspectable*>(b);
+ ComPtr<Windows::Storage::Streams::IBufferByteAccess> bacc;
+ insp.As(&bacc);
+ byte* bytes = nullptr;
+ bacc->Buffer(&bytes);
+ asio::buffer_copy(asio::buffer(bytes, size), buffers);
+ b->Length = size;
+ return b;
+}
+
+} // namespace winrt_utils
+} // namespace detail
+} // namespace asio
+
+#include "asio/detail/pop_options.hpp"
+
+#endif // defined(ASIO_WINDOWS_RUNTIME)
+
+#endif // ASIO_DETAIL_WINRT_UTILS_HPP
diff --git a/lib/asio/detail/winsock_init.hpp b/lib/asio/detail/winsock_init.hpp
new file mode 100644
index 0000000..9094363
--- /dev/null
+++ b/lib/asio/detail/winsock_init.hpp
@@ -0,0 +1,128 @@
+//
+// detail/winsock_init.hpp
+// ~~~~~~~~~~~~~~~~~~~~~~~
+//
+// Copyright (c) 2003-2018 Christopher M. Kohlhoff (chris at kohlhoff dot com)
+//
+// 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 ASIO_DETAIL_WINSOCK_INIT_HPP
+#define ASIO_DETAIL_WINSOCK_INIT_HPP
+
+#if defined(_MSC_VER) && (_MSC_VER >= 1200)
+# pragma once
+#endif // defined(_MSC_VER) && (_MSC_VER >= 1200)
+
+#include "asio/detail/config.hpp"
+
+#if defined(ASIO_WINDOWS) || defined(__CYGWIN__)
+
+#include "asio/detail/push_options.hpp"
+
+namespace asio {
+namespace detail {
+
+class winsock_init_base
+{
+protected:
+ // Structure to track result of initialisation and number of uses. POD is used
+ // to ensure that the values are zero-initialised prior to any code being run.
+ struct data
+ {
+ long init_count_;
+ long result_;
+ };
+
+ ASIO_DECL static void startup(data& d,
+ unsigned char major, unsigned char minor);
+
+ ASIO_DECL static void manual_startup(data& d);
+
+ ASIO_DECL static void cleanup(data& d);
+
+ ASIO_DECL static void manual_cleanup(data& d);
+
+ ASIO_DECL static void throw_on_error(data& d);
+};
+
+template <int Major = 2, int Minor = 0>
+class winsock_init : private winsock_init_base
+{
+public:
+ winsock_init(bool allow_throw = true)
+ {
+ startup(data_, Major, Minor);
+ if (allow_throw)
+ throw_on_error(data_);
+ }
+
+ winsock_init(const winsock_init&)
+ {
+ startup(data_, Major, Minor);
+ throw_on_error(data_);
+ }
+
+ ~winsock_init()
+ {
+ cleanup(data_);
+ }
+
+ // This class may be used to indicate that user code will manage Winsock
+ // initialisation and cleanup. This may be required in the case of a DLL, for
+ // example, where it is not safe to initialise Winsock from global object
+ // constructors.
+ //
+ // To prevent asio from initialising Winsock, the object must be constructed
+ // before any Asio's own global objects. With MSVC, this may be accomplished
+ // by adding the following code to the DLL:
+ //
+ // #pragma warning(push)
+ // #pragma warning(disable:4073)
+ // #pragma init_seg(lib)
+ // asio::detail::winsock_init<>::manual manual_winsock_init;
+ // #pragma warning(pop)
+ class manual
+ {
+ public:
+ manual()
+ {
+ manual_startup(data_);
+ }
+
+ manual(const manual&)
+ {
+ manual_startup(data_);
+ }
+
+ ~manual()
+ {
+ manual_cleanup(data_);
+ }
+ };
+
+private:
+ friend class manual;
+ static data data_;
+};
+
+template <int Major, int Minor>
+winsock_init_base::data winsock_init<Major, Minor>::data_;
+
+// Static variable to ensure that winsock is initialised before main, and
+// therefore before any other threads can get started.
+static const winsock_init<>& winsock_init_instance = winsock_init<>(false);
+
+} // namespace detail
+} // namespace asio
+
+#include "asio/detail/pop_options.hpp"
+
+#if defined(ASIO_HEADER_ONLY)
+# include "asio/detail/impl/winsock_init.ipp"
+#endif // defined(ASIO_HEADER_ONLY)
+
+#endif // defined(ASIO_WINDOWS) || defined(__CYGWIN__)
+
+#endif // ASIO_DETAIL_WINSOCK_INIT_HPP
diff --git a/lib/asio/detail/work_dispatcher.hpp b/lib/asio/detail/work_dispatcher.hpp
new file mode 100644
index 0000000..7abce49
--- /dev/null
+++ b/lib/asio/detail/work_dispatcher.hpp
@@ -0,0 +1,72 @@
+//
+// detail/work_dispatcher.hpp
+// ~~~~~~~~~~~~~~~~~~~~~~~~~~
+//
+// Copyright (c) 2003-2018 Christopher M. Kohlhoff (chris at kohlhoff dot com)
+//
+// 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 ASIO_DETAIL_WORK_DISPATCHER_HPP
+#define ASIO_DETAIL_WORK_DISPATCHER_HPP
+
+#if defined(_MSC_VER) && (_MSC_VER >= 1200)
+# pragma once
+#endif // defined(_MSC_VER) && (_MSC_VER >= 1200)
+
+#include "asio/detail/config.hpp"
+#include "asio/associated_executor.hpp"
+#include "asio/associated_allocator.hpp"
+#include "asio/executor_work_guard.hpp"
+
+#include "asio/detail/push_options.hpp"
+
+namespace asio {
+namespace detail {
+
+template <typename Handler>
+class work_dispatcher
+{
+public:
+ work_dispatcher(Handler& handler)
+ : work_((get_associated_executor)(handler)),
+ handler_(ASIO_MOVE_CAST(Handler)(handler))
+ {
+ }
+
+#if defined(ASIO_HAS_MOVE)
+ work_dispatcher(const work_dispatcher& other)
+ : work_(other.work_),
+ handler_(other.handler_)
+ {
+ }
+
+ work_dispatcher(work_dispatcher&& other)
+ : work_(ASIO_MOVE_CAST(executor_work_guard<
+ typename associated_executor<Handler>::type>)(other.work_)),
+ handler_(ASIO_MOVE_CAST(Handler)(other.handler_))
+ {
+ }
+#endif // defined(ASIO_HAS_MOVE)
+
+ void operator()()
+ {
+ typename associated_allocator<Handler>::type alloc(
+ (get_associated_allocator)(handler_));
+ work_.get_executor().dispatch(
+ ASIO_MOVE_CAST(Handler)(handler_), alloc);
+ work_.reset();
+ }
+
+private:
+ executor_work_guard<typename associated_executor<Handler>::type> work_;
+ Handler handler_;
+};
+
+} // namespace detail
+} // namespace asio
+
+#include "asio/detail/pop_options.hpp"
+
+#endif // ASIO_DETAIL_WORK_DISPATCHER_HPP
diff --git a/lib/asio/detail/wrapped_handler.hpp b/lib/asio/detail/wrapped_handler.hpp
new file mode 100644
index 0000000..751f0ea
--- /dev/null
+++ b/lib/asio/detail/wrapped_handler.hpp
@@ -0,0 +1,291 @@
+//
+// detail/wrapped_handler.hpp
+// ~~~~~~~~~~~~~~~~~~~~~~~~~~
+//
+// Copyright (c) 2003-2018 Christopher M. Kohlhoff (chris at kohlhoff dot com)
+//
+// 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 ASIO_DETAIL_WRAPPED_HANDLER_HPP
+#define ASIO_DETAIL_WRAPPED_HANDLER_HPP
+
+#if defined(_MSC_VER) && (_MSC_VER >= 1200)
+# pragma once
+#endif // defined(_MSC_VER) && (_MSC_VER >= 1200)
+
+#include "asio/detail/bind_handler.hpp"
+#include "asio/detail/handler_alloc_helpers.hpp"
+#include "asio/detail/handler_cont_helpers.hpp"
+#include "asio/detail/handler_invoke_helpers.hpp"
+
+#include "asio/detail/push_options.hpp"
+
+namespace asio {
+namespace detail {
+
+struct is_continuation_delegated
+{
+ template <typename Dispatcher, typename Handler>
+ bool operator()(Dispatcher&, Handler& handler) const
+ {
+ return asio_handler_cont_helpers::is_continuation(handler);
+ }
+};
+
+struct is_continuation_if_running
+{
+ template <typename Dispatcher, typename Handler>
+ bool operator()(Dispatcher& dispatcher, Handler&) const
+ {
+ return dispatcher.running_in_this_thread();
+ }
+};
+
+template <typename Dispatcher, typename Handler,
+ typename IsContinuation = is_continuation_delegated>
+class wrapped_handler
+{
+public:
+ typedef void result_type;
+
+ wrapped_handler(Dispatcher dispatcher, Handler& handler)
+ : dispatcher_(dispatcher),
+ handler_(ASIO_MOVE_CAST(Handler)(handler))
+ {
+ }
+
+#if defined(ASIO_HAS_MOVE)
+ wrapped_handler(const wrapped_handler& other)
+ : dispatcher_(other.dispatcher_),
+ handler_(other.handler_)
+ {
+ }
+
+ wrapped_handler(wrapped_handler&& other)
+ : dispatcher_(other.dispatcher_),
+ handler_(ASIO_MOVE_CAST(Handler)(other.handler_))
+ {
+ }
+#endif // defined(ASIO_HAS_MOVE)
+
+ void operator()()
+ {
+ dispatcher_.dispatch(ASIO_MOVE_CAST(Handler)(handler_));
+ }
+
+ void operator()() const
+ {
+ dispatcher_.dispatch(handler_);
+ }
+
+ template <typename Arg1>
+ void operator()(const Arg1& arg1)
+ {
+ dispatcher_.dispatch(detail::bind_handler(handler_, arg1));
+ }
+
+ template <typename Arg1>
+ void operator()(const Arg1& arg1) const
+ {
+ dispatcher_.dispatch(detail::bind_handler(handler_, arg1));
+ }
+
+ template <typename Arg1, typename Arg2>
+ void operator()(const Arg1& arg1, const Arg2& arg2)
+ {
+ dispatcher_.dispatch(detail::bind_handler(handler_, arg1, arg2));
+ }
+
+ template <typename Arg1, typename Arg2>
+ void operator()(const Arg1& arg1, const Arg2& arg2) const
+ {
+ dispatcher_.dispatch(detail::bind_handler(handler_, arg1, arg2));
+ }
+
+ template <typename Arg1, typename Arg2, typename Arg3>
+ void operator()(const Arg1& arg1, const Arg2& arg2, const Arg3& arg3)
+ {
+ dispatcher_.dispatch(detail::bind_handler(handler_, arg1, arg2, arg3));
+ }
+
+ template <typename Arg1, typename Arg2, typename Arg3>
+ void operator()(const Arg1& arg1, const Arg2& arg2, const Arg3& arg3) const
+ {
+ dispatcher_.dispatch(detail::bind_handler(handler_, arg1, arg2, arg3));
+ }
+
+ template <typename Arg1, typename Arg2, typename Arg3, typename Arg4>
+ void operator()(const Arg1& arg1, const Arg2& arg2, const Arg3& arg3,
+ const Arg4& arg4)
+ {
+ dispatcher_.dispatch(
+ detail::bind_handler(handler_, arg1, arg2, arg3, arg4));
+ }
+
+ template <typename Arg1, typename Arg2, typename Arg3, typename Arg4>
+ void operator()(const Arg1& arg1, const Arg2& arg2, const Arg3& arg3,
+ const Arg4& arg4) const
+ {
+ dispatcher_.dispatch(
+ detail::bind_handler(handler_, arg1, arg2, arg3, arg4));
+ }
+
+ template <typename Arg1, typename Arg2, typename Arg3, typename Arg4,
+ typename Arg5>
+ void operator()(const Arg1& arg1, const Arg2& arg2, const Arg3& arg3,
+ const Arg4& arg4, const Arg5& arg5)
+ {
+ dispatcher_.dispatch(
+ detail::bind_handler(handler_, arg1, arg2, arg3, arg4, arg5));
+ }
+
+ template <typename Arg1, typename Arg2, typename Arg3, typename Arg4,
+ typename Arg5>
+ void operator()(const Arg1& arg1, const Arg2& arg2, const Arg3& arg3,
+ const Arg4& arg4, const Arg5& arg5) const
+ {
+ dispatcher_.dispatch(
+ detail::bind_handler(handler_, arg1, arg2, arg3, arg4, arg5));
+ }
+
+//private:
+ Dispatcher dispatcher_;
+ Handler handler_;
+};
+
+template <typename Handler, typename Context>
+class rewrapped_handler
+{
+public:
+ explicit rewrapped_handler(Handler& handler, const Context& context)
+ : context_(context),
+ handler_(ASIO_MOVE_CAST(Handler)(handler))
+ {
+ }
+
+ explicit rewrapped_handler(const Handler& handler, const Context& context)
+ : context_(context),
+ handler_(handler)
+ {
+ }
+
+#if defined(ASIO_HAS_MOVE)
+ rewrapped_handler(const rewrapped_handler& other)
+ : context_(other.context_),
+ handler_(other.handler_)
+ {
+ }
+
+ rewrapped_handler(rewrapped_handler&& other)
+ : context_(ASIO_MOVE_CAST(Context)(other.context_)),
+ handler_(ASIO_MOVE_CAST(Handler)(other.handler_))
+ {
+ }
+#endif // defined(ASIO_HAS_MOVE)
+
+ void operator()()
+ {
+ handler_();
+ }
+
+ void operator()() const
+ {
+ handler_();
+ }
+
+//private:
+ Context context_;
+ Handler handler_;
+};
+
+template <typename Dispatcher, typename Handler, typename IsContinuation>
+inline void* asio_handler_allocate(std::size_t size,
+ wrapped_handler<Dispatcher, Handler, IsContinuation>* this_handler)
+{
+ return asio_handler_alloc_helpers::allocate(
+ size, this_handler->handler_);
+}
+
+template <typename Dispatcher, typename Handler, typename IsContinuation>
+inline void asio_handler_deallocate(void* pointer, std::size_t size,
+ wrapped_handler<Dispatcher, Handler, IsContinuation>* this_handler)
+{
+ asio_handler_alloc_helpers::deallocate(
+ pointer, size, this_handler->handler_);
+}
+
+template <typename Dispatcher, typename Handler, typename IsContinuation>
+inline bool asio_handler_is_continuation(
+ wrapped_handler<Dispatcher, Handler, IsContinuation>* this_handler)
+{
+ return IsContinuation()(this_handler->dispatcher_, this_handler->handler_);
+}
+
+template <typename Function, typename Dispatcher,
+ typename Handler, typename IsContinuation>
+inline void asio_handler_invoke(Function& function,
+ wrapped_handler<Dispatcher, Handler, IsContinuation>* this_handler)
+{
+ this_handler->dispatcher_.dispatch(
+ rewrapped_handler<Function, Handler>(
+ function, this_handler->handler_));
+}
+
+template <typename Function, typename Dispatcher,
+ typename Handler, typename IsContinuation>
+inline void asio_handler_invoke(const Function& function,
+ wrapped_handler<Dispatcher, Handler, IsContinuation>* this_handler)
+{
+ this_handler->dispatcher_.dispatch(
+ rewrapped_handler<Function, Handler>(
+ function, this_handler->handler_));
+}
+
+template <typename Handler, typename Context>
+inline void* asio_handler_allocate(std::size_t size,
+ rewrapped_handler<Handler, Context>* this_handler)
+{
+ return asio_handler_alloc_helpers::allocate(
+ size, this_handler->context_);
+}
+
+template <typename Handler, typename Context>
+inline void asio_handler_deallocate(void* pointer, std::size_t size,
+ rewrapped_handler<Handler, Context>* this_handler)
+{
+ asio_handler_alloc_helpers::deallocate(
+ pointer, size, this_handler->context_);
+}
+
+template <typename Dispatcher, typename Context>
+inline bool asio_handler_is_continuation(
+ rewrapped_handler<Dispatcher, Context>* this_handler)
+{
+ return asio_handler_cont_helpers::is_continuation(
+ this_handler->context_);
+}
+
+template <typename Function, typename Handler, typename Context>
+inline void asio_handler_invoke(Function& function,
+ rewrapped_handler<Handler, Context>* this_handler)
+{
+ asio_handler_invoke_helpers::invoke(
+ function, this_handler->context_);
+}
+
+template <typename Function, typename Handler, typename Context>
+inline void asio_handler_invoke(const Function& function,
+ rewrapped_handler<Handler, Context>* this_handler)
+{
+ asio_handler_invoke_helpers::invoke(
+ function, this_handler->context_);
+}
+
+} // namespace detail
+} // namespace asio
+
+#include "asio/detail/pop_options.hpp"
+
+#endif // ASIO_DETAIL_WRAPPED_HANDLER_HPP