summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
Diffstat (limited to '3rdParty/Boost/boost/asio/detail')
-rw-r--r--3rdParty/Boost/boost/asio/detail/bind_handler.hpp351
-rw-r--r--3rdParty/Boost/boost/asio/detail/buffer_resize_guard.hpp72
-rw-r--r--3rdParty/Boost/boost/asio/detail/buffered_stream_storage.hpp129
-rw-r--r--3rdParty/Boost/boost/asio/detail/call_stack.hpp92
-rw-r--r--3rdParty/Boost/boost/asio/detail/consuming_buffers.hpp246
-rw-r--r--3rdParty/Boost/boost/asio/detail/deadline_timer_service.hpp203
-rw-r--r--3rdParty/Boost/boost/asio/detail/descriptor_ops.hpp178
-rw-r--r--3rdParty/Boost/boost/asio/detail/dev_poll_reactor.hpp678
-rw-r--r--3rdParty/Boost/boost/asio/detail/dev_poll_reactor_fwd.hpp42
-rw-r--r--3rdParty/Boost/boost/asio/detail/epoll_reactor.hpp733
-rw-r--r--3rdParty/Boost/boost/asio/detail/epoll_reactor_fwd.hpp49
-rw-r--r--3rdParty/Boost/boost/asio/detail/event.hpp52
-rw-r--r--3rdParty/Boost/boost/asio/detail/eventfd_select_interrupter.hpp157
-rw-r--r--3rdParty/Boost/boost/asio/detail/fd_set_adapter.hpp43
-rw-r--r--3rdParty/Boost/boost/asio/detail/handler_alloc_helpers.hpp258
-rw-r--r--3rdParty/Boost/boost/asio/detail/handler_base_from_member.hpp78
-rw-r--r--3rdParty/Boost/boost/asio/detail/handler_invoke_helpers.hpp47
-rw-r--r--3rdParty/Boost/boost/asio/detail/handler_queue.hpp231
-rw-r--r--3rdParty/Boost/boost/asio/detail/hash_map.hpp292
-rw-r--r--3rdParty/Boost/boost/asio/detail/indirect_handler_queue.hpp293
-rw-r--r--3rdParty/Boost/boost/asio/detail/io_control.hpp139
-rw-r--r--3rdParty/Boost/boost/asio/detail/kqueue_reactor.hpp714
-rw-r--r--3rdParty/Boost/boost/asio/detail/kqueue_reactor_fwd.hpp43
-rw-r--r--3rdParty/Boost/boost/asio/detail/mutex.hpp52
-rw-r--r--3rdParty/Boost/boost/asio/detail/noncopyable.hpp57
-rw-r--r--3rdParty/Boost/boost/asio/detail/null_event.hpp73
-rw-r--r--3rdParty/Boost/boost/asio/detail/null_mutex.hpp68
-rw-r--r--3rdParty/Boost/boost/asio/detail/null_signal_blocker.hpp65
-rw-r--r--3rdParty/Boost/boost/asio/detail/null_thread.hpp70
-rw-r--r--3rdParty/Boost/boost/asio/detail/null_tss_ptr.hpp72
-rw-r--r--3rdParty/Boost/boost/asio/detail/old_win_sdk_compat.hpp342
-rw-r--r--3rdParty/Boost/boost/asio/detail/pipe_select_interrupter.hpp117
-rw-r--r--3rdParty/Boost/boost/asio/detail/pop_options.hpp88
-rw-r--r--3rdParty/Boost/boost/asio/detail/posix_event.hpp106
-rw-r--r--3rdParty/Boost/boost/asio/detail/posix_fd_set_adapter.hpp83
-rw-r--r--3rdParty/Boost/boost/asio/detail/posix_mutex.hpp109
-rw-r--r--3rdParty/Boost/boost/asio/detail/posix_signal_blocker.hpp92
-rw-r--r--3rdParty/Boost/boost/asio/detail/posix_thread.hpp131
-rw-r--r--3rdParty/Boost/boost/asio/detail/posix_tss_ptr.hpp90
-rw-r--r--3rdParty/Boost/boost/asio/detail/push_options.hpp114
-rw-r--r--3rdParty/Boost/boost/asio/detail/reactive_descriptor_service.hpp712
-rw-r--r--3rdParty/Boost/boost/asio/detail/reactive_serial_port_service.hpp270
-rw-r--r--3rdParty/Boost/boost/asio/detail/reactive_socket_service.hpp1788
-rw-r--r--3rdParty/Boost/boost/asio/detail/reactor_op_queue.hpp456
-rw-r--r--3rdParty/Boost/boost/asio/detail/resolver_service.hpp359
-rw-r--r--3rdParty/Boost/boost/asio/detail/scoped_lock.hpp93
-rw-r--r--3rdParty/Boost/boost/asio/detail/select_interrupter.hpp46
-rw-r--r--3rdParty/Boost/boost/asio/detail/select_reactor.hpp546
-rw-r--r--3rdParty/Boost/boost/asio/detail/select_reactor_fwd.hpp33
-rw-r--r--3rdParty/Boost/boost/asio/detail/service_base.hpp51
-rw-r--r--3rdParty/Boost/boost/asio/detail/service_id.hpp39
-rw-r--r--3rdParty/Boost/boost/asio/detail/service_registry.hpp228
-rw-r--r--3rdParty/Boost/boost/asio/detail/service_registry_fwd.hpp32
-rw-r--r--3rdParty/Boost/boost/asio/detail/signal_blocker.hpp52
-rw-r--r--3rdParty/Boost/boost/asio/detail/signal_init.hpp53
-rw-r--r--3rdParty/Boost/boost/asio/detail/socket_holder.hpp97
-rw-r--r--3rdParty/Boost/boost/asio/detail/socket_ops.hpp1913
-rw-r--r--3rdParty/Boost/boost/asio/detail/socket_option.hpp311
-rw-r--r--3rdParty/Boost/boost/asio/detail/socket_select_interrupter.hpp189
-rw-r--r--3rdParty/Boost/boost/asio/detail/socket_types.hpp212
-rw-r--r--3rdParty/Boost/boost/asio/detail/strand_service.hpp532
-rw-r--r--3rdParty/Boost/boost/asio/detail/task_io_service.hpp438
-rw-r--r--3rdParty/Boost/boost/asio/detail/task_io_service_2lock.hpp475
-rw-r--r--3rdParty/Boost/boost/asio/detail/task_io_service_fwd.hpp33
-rw-r--r--3rdParty/Boost/boost/asio/detail/thread.hpp60
-rw-r--r--3rdParty/Boost/boost/asio/detail/throw_error.hpp46
-rw-r--r--3rdParty/Boost/boost/asio/detail/timer_queue.hpp438
-rw-r--r--3rdParty/Boost/boost/asio/detail/timer_queue_base.hpp64
-rw-r--r--3rdParty/Boost/boost/asio/detail/tss_ptr.hpp67
-rw-r--r--3rdParty/Boost/boost/asio/detail/win_event.hpp105
-rw-r--r--3rdParty/Boost/boost/asio/detail/win_fd_set_adapter.hpp90
-rw-r--r--3rdParty/Boost/boost/asio/detail/win_iocp_handle_service.hpp834
-rw-r--r--3rdParty/Boost/boost/asio/detail/win_iocp_io_service.hpp738
-rw-r--r--3rdParty/Boost/boost/asio/detail/win_iocp_io_service_fwd.hpp53
-rw-r--r--3rdParty/Boost/boost/asio/detail/win_iocp_overlapped_ptr.hpp210
-rw-r--r--3rdParty/Boost/boost/asio/detail/win_iocp_serial_port_service.hpp294
-rw-r--r--3rdParty/Boost/boost/asio/detail/win_iocp_socket_service.hpp2417
-rw-r--r--3rdParty/Boost/boost/asio/detail/win_mutex.hpp151
-rw-r--r--3rdParty/Boost/boost/asio/detail/win_signal_blocker.hpp69
-rw-r--r--3rdParty/Boost/boost/asio/detail/win_thread.hpp234
-rw-r--r--3rdParty/Boost/boost/asio/detail/win_tss_ptr.hpp97
-rw-r--r--3rdParty/Boost/boost/asio/detail/wince_thread.hpp126
-rw-r--r--3rdParty/Boost/boost/asio/detail/winsock_init.hpp122
-rw-r--r--3rdParty/Boost/boost/asio/detail/wrapped_handler.hpp211
84 files changed, 22233 insertions, 0 deletions
diff --git a/3rdParty/Boost/boost/asio/detail/bind_handler.hpp b/3rdParty/Boost/boost/asio/detail/bind_handler.hpp
new file mode 100644
index 0000000..3a9ad01
--- /dev/null
+++ b/3rdParty/Boost/boost/asio/detail/bind_handler.hpp
@@ -0,0 +1,351 @@
+//
+// bind_handler.hpp
+// ~~~~~~~~~~~~~~~~
+//
+// Copyright (c) 2003-2008 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 BOOST_ASIO_DETAIL_BIND_HANDLER_HPP
+#define BOOST_ASIO_DETAIL_BIND_HANDLER_HPP
+
+#if defined(_MSC_VER) && (_MSC_VER >= 1200)
+# pragma once
+#endif // defined(_MSC_VER) && (_MSC_VER >= 1200)
+
+#include <boost/asio/detail/push_options.hpp>
+
+#include <boost/asio/detail/handler_alloc_helpers.hpp>
+#include <boost/asio/detail/handler_invoke_helpers.hpp>
+
+namespace boost {
+namespace asio {
+namespace detail {
+
+template <typename Handler, typename Arg1>
+class binder1
+{
+public:
+ binder1(const Handler& handler, const Arg1& arg1)
+ : handler_(handler),
+ arg1_(arg1)
+ {
+ }
+
+ void operator()()
+ {
+ handler_(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 boost_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)
+{
+ boost_asio_handler_alloc_helpers::deallocate(
+ pointer, size, &this_handler->handler_);
+}
+
+template <typename Function, typename Handler, typename Arg1>
+inline void asio_handler_invoke(const Function& function,
+ binder1<Handler, Arg1>* this_handler)
+{
+ boost_asio_handler_invoke_helpers::invoke(
+ function, &this_handler->handler_);
+}
+
+template <typename Handler, typename Arg1>
+inline binder1<Handler, Arg1> bind_handler(const Handler& handler,
+ const Arg1& arg1)
+{
+ return binder1<Handler, Arg1>(handler, arg1);
+}
+
+template <typename Handler, typename Arg1, typename Arg2>
+class binder2
+{
+public:
+ binder2(const Handler& handler, const Arg1& arg1, const Arg2& arg2)
+ : handler_(handler),
+ arg1_(arg1),
+ arg2_(arg2)
+ {
+ }
+
+ void operator()()
+ {
+ handler_(arg1_, 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 boost_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)
+{
+ boost_asio_handler_alloc_helpers::deallocate(
+ pointer, size, &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)
+{
+ boost_asio_handler_invoke_helpers::invoke(
+ function, &this_handler->handler_);
+}
+
+template <typename Handler, typename Arg1, typename Arg2>
+inline binder2<Handler, Arg1, Arg2> bind_handler(const Handler& handler,
+ const Arg1& arg1, const Arg2& arg2)
+{
+ return binder2<Handler, Arg1, Arg2>(handler, arg1, arg2);
+}
+
+template <typename Handler, typename Arg1, typename Arg2, typename Arg3>
+class binder3
+{
+public:
+ binder3(const Handler& handler, const Arg1& arg1, const Arg2& arg2,
+ const Arg3& arg3)
+ : handler_(handler),
+ arg1_(arg1),
+ arg2_(arg2),
+ arg3_(arg3)
+ {
+ }
+
+ void operator()()
+ {
+ handler_(arg1_, arg2_, 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 boost_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)
+{
+ boost_asio_handler_alloc_helpers::deallocate(
+ pointer, size, &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)
+{
+ boost_asio_handler_invoke_helpers::invoke(
+ function, &this_handler->handler_);
+}
+
+template <typename Handler, typename Arg1, typename Arg2, typename Arg3>
+inline binder3<Handler, Arg1, Arg2, Arg3> bind_handler(const Handler& handler,
+ const Arg1& arg1, const Arg2& arg2, const Arg3& arg3)
+{
+ return binder3<Handler, Arg1, Arg2, Arg3>(handler, arg1, arg2, arg3);
+}
+
+template <typename Handler, typename Arg1, typename Arg2, typename Arg3,
+ typename Arg4>
+class binder4
+{
+public:
+ binder4(const Handler& handler, const Arg1& arg1, const Arg2& arg2,
+ const Arg3& arg3, const Arg4& arg4)
+ : handler_(handler),
+ arg1_(arg1),
+ arg2_(arg2),
+ arg3_(arg3),
+ arg4_(arg4)
+ {
+ }
+
+ void operator()()
+ {
+ handler_(arg1_, arg2_, arg3_, 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 boost_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)
+{
+ boost_asio_handler_alloc_helpers::deallocate(
+ pointer, size, &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)
+{
+ boost_asio_handler_invoke_helpers::invoke(
+ function, &this_handler->handler_);
+}
+
+template <typename Handler, typename Arg1, typename Arg2, typename Arg3,
+ typename Arg4>
+inline binder4<Handler, Arg1, Arg2, Arg3, Arg4> bind_handler(
+ const Handler& handler, const Arg1& arg1, const Arg2& arg2,
+ const Arg3& arg3, const Arg4& arg4)
+{
+ return binder4<Handler, Arg1, Arg2, Arg3, Arg4>(handler, arg1, arg2, arg3,
+ arg4);
+}
+
+template <typename Handler, typename Arg1, typename Arg2, typename Arg3,
+ typename Arg4, typename Arg5>
+class binder5
+{
+public:
+ binder5(const Handler& handler, const Arg1& arg1, const Arg2& arg2,
+ const Arg3& arg3, const Arg4& arg4, const Arg5& arg5)
+ : handler_(handler),
+ arg1_(arg1),
+ arg2_(arg2),
+ arg3_(arg3),
+ arg4_(arg4),
+ arg5_(arg5)
+ {
+ }
+
+ void operator()()
+ {
+ handler_(arg1_, arg2_, arg3_, arg4_, 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 boost_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)
+{
+ boost_asio_handler_alloc_helpers::deallocate(
+ pointer, size, &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)
+{
+ boost_asio_handler_invoke_helpers::invoke(
+ function, &this_handler->handler_);
+}
+
+template <typename Handler, typename Arg1, typename Arg2, typename Arg3,
+ typename Arg4, typename Arg5>
+inline binder5<Handler, Arg1, Arg2, Arg3, Arg4, Arg5> bind_handler(
+ const Handler& handler, const Arg1& arg1, const Arg2& arg2,
+ const Arg3& arg3, const Arg4& arg4, const Arg5& arg5)
+{
+ return binder5<Handler, Arg1, Arg2, Arg3, Arg4, Arg5>(handler, arg1, arg2,
+ arg3, arg4, arg5);
+}
+
+} // namespace detail
+} // namespace asio
+} // namespace boost
+
+#include <boost/asio/detail/pop_options.hpp>
+
+#endif // BOOST_ASIO_DETAIL_BIND_HANDLER_HPP
diff --git a/3rdParty/Boost/boost/asio/detail/buffer_resize_guard.hpp b/3rdParty/Boost/boost/asio/detail/buffer_resize_guard.hpp
new file mode 100644
index 0000000..63d957c
--- /dev/null
+++ b/3rdParty/Boost/boost/asio/detail/buffer_resize_guard.hpp
@@ -0,0 +1,72 @@
+//
+// buffer_resize_guard.hpp
+// ~~~~~~~~~~~~~~~~~~~~~~~
+//
+// Copyright (c) 2003-2008 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 BOOST_ASIO_DETAIL_BUFFER_RESIZE_GUARD_HPP
+#define BOOST_ASIO_DETAIL_BUFFER_RESIZE_GUARD_HPP
+
+#if defined(_MSC_VER) && (_MSC_VER >= 1200)
+# pragma once
+#endif // defined(_MSC_VER) && (_MSC_VER >= 1200)
+
+#include <boost/asio/detail/push_options.hpp>
+
+#include <boost/asio/detail/push_options.hpp>
+#include <limits>
+#include <boost/config.hpp>
+#include <boost/asio/detail/pop_options.hpp>
+
+namespace boost {
+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 BOOST_PREVENT_MACRO_SUBSTITUTION())
+ {
+ buffer_.resize(old_size_);
+ }
+ }
+
+ // Commit the resize transaction.
+ void commit()
+ {
+ old_size_
+ = std::numeric_limits<size_t>::max BOOST_PREVENT_MACRO_SUBSTITUTION();
+ }
+
+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
+} // namespace boost
+
+#include <boost/asio/detail/pop_options.hpp>
+
+#endif // BOOST_ASIO_DETAIL_BUFFER_RESIZE_GUARD_HPP
diff --git a/3rdParty/Boost/boost/asio/detail/buffered_stream_storage.hpp b/3rdParty/Boost/boost/asio/detail/buffered_stream_storage.hpp
new file mode 100644
index 0000000..f20bf27
--- /dev/null
+++ b/3rdParty/Boost/boost/asio/detail/buffered_stream_storage.hpp
@@ -0,0 +1,129 @@
+//
+// buffered_stream_storage.hpp
+// ~~~~~~~~~~~~~~~~~~~~~~~~~~~
+//
+// Copyright (c) 2003-2008 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 BOOST_ASIO_DETAIL_BUFFERED_STREAM_STORAGE_HPP
+#define BOOST_ASIO_DETAIL_BUFFERED_STREAM_STORAGE_HPP
+
+#if defined(_MSC_VER) && (_MSC_VER >= 1200)
+# pragma once
+#endif // defined(_MSC_VER) && (_MSC_VER >= 1200)
+
+#include <boost/asio/detail/push_options.hpp>
+
+#include <boost/asio/detail/push_options.hpp>
+#include <boost/config.hpp>
+#include <cassert>
+#include <cstddef>
+#include <cstring>
+#include <vector>
+#include <boost/asio/detail/pop_options.hpp>
+
+namespace boost {
+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 capacity)
+ : begin_offset_(0),
+ end_offset_(0),
+ buffer_(capacity)
+ {
+ }
+
+ /// Clear the buffer.
+ void clear()
+ {
+ begin_offset_ = 0;
+ end_offset_ = 0;
+ }
+
+ // Return a pointer to the beginning of the unread data.
+ byte_type* data()
+ {
+ return &buffer_[0] + begin_offset_;
+ }
+
+ // Return a pointer to the beginning of the unread data.
+ const byte_type* data() const
+ {
+ return &buffer_[0] + 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)
+ {
+ 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)
+ {
+ 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
+} // namespace boost
+
+#include <boost/asio/detail/pop_options.hpp>
+
+#endif // BOOST_ASIO_DETAIL_BUFFERED_STREAM_STORAGE_HPP
diff --git a/3rdParty/Boost/boost/asio/detail/call_stack.hpp b/3rdParty/Boost/boost/asio/detail/call_stack.hpp
new file mode 100644
index 0000000..0096741
--- /dev/null
+++ b/3rdParty/Boost/boost/asio/detail/call_stack.hpp
@@ -0,0 +1,92 @@
+//
+// call_stack.hpp
+// ~~~~~~~~~~~~~~
+//
+// Copyright (c) 2003-2008 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 BOOST_ASIO_DETAIL_CALL_STACK_HPP
+#define BOOST_ASIO_DETAIL_CALL_STACK_HPP
+
+#if defined(_MSC_VER) && (_MSC_VER >= 1200)
+# pragma once
+#endif // defined(_MSC_VER) && (_MSC_VER >= 1200)
+
+#include <boost/asio/detail/push_options.hpp>
+
+#include <boost/asio/detail/noncopyable.hpp>
+#include <boost/asio/detail/tss_ptr.hpp>
+
+namespace boost {
+namespace asio {
+namespace detail {
+
+// Helper class to determine whether or not the current thread is inside an
+// invocation of io_service::run() for a specified io_service object.
+template <typename Owner>
+class call_stack
+{
+public:
+ // Context class automatically pushes an owner on to the stack.
+ class context
+ : private noncopyable
+ {
+ public:
+ // Push the owner on to the stack.
+ explicit context(Owner* d)
+ : owner_(d),
+ next_(call_stack<Owner>::top_)
+ {
+ call_stack<Owner>::top_ = this;
+ }
+
+ // Pop the owner from the stack.
+ ~context()
+ {
+ call_stack<Owner>::top_ = next_;
+ }
+
+ private:
+ friend class call_stack<Owner>;
+
+ // The owner associated with the context.
+ Owner* owner_;
+
+ // The next element in the stack.
+ context* next_;
+ };
+
+ friend class context;
+
+ // Determine whether the specified owner is on the stack.
+ static bool contains(Owner* d)
+ {
+ context* elem = top_;
+ while (elem)
+ {
+ if (elem->owner_ == d)
+ return true;
+ elem = elem->next_;
+ }
+ return false;
+ }
+
+private:
+ // The top of the stack of calls for the current thread.
+ static tss_ptr<context> top_;
+};
+
+template <typename Owner>
+tss_ptr<typename call_stack<Owner>::context>
+call_stack<Owner>::top_;
+
+} // namespace detail
+} // namespace asio
+} // namespace boost
+
+#include <boost/asio/detail/pop_options.hpp>
+
+#endif // BOOST_ASIO_DETAIL_CALL_STACK_HPP
diff --git a/3rdParty/Boost/boost/asio/detail/consuming_buffers.hpp b/3rdParty/Boost/boost/asio/detail/consuming_buffers.hpp
new file mode 100644
index 0000000..0ed811d
--- /dev/null
+++ b/3rdParty/Boost/boost/asio/detail/consuming_buffers.hpp
@@ -0,0 +1,246 @@
+//
+// consuming_buffers.hpp
+// ~~~~~~~~~~~~~~~~~~~~~
+//
+// Copyright (c) 2003-2008 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 BOOST_ASIO_DETAIL_CONSUMING_BUFFERS_HPP
+#define BOOST_ASIO_DETAIL_CONSUMING_BUFFERS_HPP
+
+#if defined(_MSC_VER) && (_MSC_VER >= 1200)
+# pragma once
+#endif // defined(_MSC_VER) && (_MSC_VER >= 1200)
+
+#include <boost/asio/detail/push_options.hpp>
+
+#include <boost/asio/detail/push_options.hpp>
+#include <algorithm>
+#include <cstddef>
+#include <limits>
+#include <boost/config.hpp>
+#include <boost/iterator/iterator_facade.hpp>
+#include <boost/asio/detail/pop_options.hpp>
+
+#include <boost/asio/buffer.hpp>
+#include <boost/asio/completion_condition.hpp>
+
+namespace boost {
+namespace asio {
+namespace detail {
+
+// A proxy iterator for a sub-range in a list of buffers.
+template <typename Buffer, typename Buffer_Iterator>
+class consuming_buffers_iterator
+ : public boost::iterator_facade<
+ consuming_buffers_iterator<Buffer, Buffer_Iterator>,
+ const Buffer, boost::forward_traversal_tag>
+{
+public:
+ // Default constructor creates an end iterator.
+ consuming_buffers_iterator()
+ : at_end_(true)
+ {
+ }
+
+ // Construct with a buffer for the first entry and an iterator
+ // range for the remaining entries.
+ consuming_buffers_iterator(bool at_end, const Buffer& first,
+ Buffer_Iterator begin_remainder, Buffer_Iterator end_remainder,
+ std::size_t max_size)
+ : at_end_(max_size > 0 ? at_end : true),
+ first_(buffer(first, max_size)),
+ begin_remainder_(begin_remainder),
+ end_remainder_(end_remainder),
+ offset_(0),
+ max_size_(max_size)
+ {
+ }
+
+private:
+ friend class boost::iterator_core_access;
+
+ void increment()
+ {
+ if (!at_end_)
+ {
+ if (begin_remainder_ == end_remainder_
+ || offset_ + buffer_size(first_) >= max_size_)
+ {
+ at_end_ = true;
+ }
+ else
+ {
+ offset_ += buffer_size(first_);
+ first_ = buffer(*begin_remainder_++, max_size_ - offset_);
+ }
+ }
+ }
+
+ bool equal(const consuming_buffers_iterator& other) const
+ {
+ if (at_end_ && other.at_end_)
+ return true;
+ return !at_end_ && !other.at_end_
+ && buffer_cast<const void*>(first_)
+ == buffer_cast<const void*>(other.first_)
+ && buffer_size(first_) == buffer_size(other.first_)
+ && begin_remainder_ == other.begin_remainder_
+ && end_remainder_ == other.end_remainder_;
+ }
+
+ const Buffer& dereference() const
+ {
+ return first_;
+ }
+
+ bool at_end_;
+ Buffer first_;
+ Buffer_Iterator begin_remainder_;
+ Buffer_Iterator end_remainder_;
+ std::size_t offset_;
+ std::size_t max_size_;
+};
+
+// A proxy for a sub-range in a list of buffers.
+template <typename Buffer, typename Buffers>
+class consuming_buffers
+{
+public:
+ // The type for each element in the list of buffers.
+ typedef Buffer value_type;
+
+ // A forward-only iterator type that may be used to read elements.
+ typedef consuming_buffers_iterator<Buffer, typename Buffers::const_iterator>
+ const_iterator;
+
+ // Construct to represent the entire list of buffers.
+ consuming_buffers(const Buffers& buffers)
+ : buffers_(buffers),
+ at_end_(buffers_.begin() == buffers_.end()),
+ first_(*buffers_.begin()),
+ begin_remainder_(buffers_.begin()),
+ max_size_((std::numeric_limits<std::size_t>::max)())
+ {
+ if (!at_end_)
+ ++begin_remainder_;
+ }
+
+ // Copy constructor.
+ consuming_buffers(const consuming_buffers& other)
+ : buffers_(other.buffers_),
+ at_end_(other.at_end_),
+ first_(other.first_),
+ begin_remainder_(buffers_.begin()),
+ max_size_(other.max_size_)
+ {
+ typename Buffers::const_iterator first = other.buffers_.begin();
+ typename Buffers::const_iterator second = other.begin_remainder_;
+ std::advance(begin_remainder_, std::distance(first, second));
+ }
+
+ // Assignment operator.
+ consuming_buffers& operator=(const consuming_buffers& other)
+ {
+ buffers_ = other.buffers_;
+ at_end_ = other.at_end_;
+ first_ = other.first_;
+ begin_remainder_ = buffers_.begin();
+ typename Buffers::const_iterator first = other.buffers_.begin();
+ typename Buffers::const_iterator second = other.begin_remainder_;
+ std::advance(begin_remainder_, std::distance(first, second));
+ max_size_ = other.max_size_;
+ return *this;
+ }
+
+ // Get a forward-only iterator to the first element.
+ const_iterator begin() const
+ {
+ return const_iterator(at_end_, first_,
+ begin_remainder_, buffers_.end(), max_size_);
+ }
+
+ // Get a forward-only iterator for one past the last element.
+ const_iterator end() const
+ {
+ return const_iterator();
+ }
+
+ // Set the maximum size for a single transfer.
+ void set_max_size(std::size_t max_size)
+ {
+ max_size_ = max_size;
+ }
+
+ // Consume the specified number of bytes from the buffers.
+ void consume(std::size_t size)
+ {
+ // Remove buffers from the start until the specified size is reached.
+ while (size > 0 && !at_end_)
+ {
+ if (buffer_size(first_) <= size)
+ {
+ size -= buffer_size(first_);
+ if (begin_remainder_ == buffers_.end())
+ at_end_ = true;
+ else
+ first_ = *begin_remainder_++;
+ }
+ else
+ {
+ first_ = first_ + size;
+ size = 0;
+ }
+ }
+
+ // Remove any more empty buffers at the start.
+ while (!at_end_ && buffer_size(first_) == 0)
+ {
+ if (begin_remainder_ == buffers_.end())
+ at_end_ = true;
+ else
+ first_ = *begin_remainder_++;
+ }
+ }
+
+private:
+ Buffers buffers_;
+ bool at_end_;
+ Buffer first_;
+ typename Buffers::const_iterator begin_remainder_;
+ std::size_t max_size_;
+};
+
+// 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, boost::asio::null_buffers>
+ : public boost::asio::null_buffers
+{
+public:
+ consuming_buffers(const boost::asio::null_buffers&)
+ {
+ // No-op.
+ }
+
+ void set_max_size(std::size_t)
+ {
+ // No-op.
+ }
+
+ void consume(std::size_t)
+ {
+ // No-op.
+ }
+};
+
+} // namespace detail
+} // namespace asio
+} // namespace boost
+
+#include <boost/asio/detail/pop_options.hpp>
+
+#endif // BOOST_ASIO_DETAIL_CONSUMING_BUFFERS_HPP
diff --git a/3rdParty/Boost/boost/asio/detail/deadline_timer_service.hpp b/3rdParty/Boost/boost/asio/detail/deadline_timer_service.hpp
new file mode 100644
index 0000000..16206a7
--- /dev/null
+++ b/3rdParty/Boost/boost/asio/detail/deadline_timer_service.hpp
@@ -0,0 +1,203 @@
+//
+// deadline_timer_service.hpp
+// ~~~~~~~~~~~~~~~~~~~~~~~~~~
+//
+// Copyright (c) 2003-2008 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 BOOST_ASIO_DETAIL_DEADLINE_TIMER_SERVICE_HPP
+#define BOOST_ASIO_DETAIL_DEADLINE_TIMER_SERVICE_HPP
+
+#if defined(_MSC_VER) && (_MSC_VER >= 1200)
+# pragma once
+#endif // defined(_MSC_VER) && (_MSC_VER >= 1200)
+
+#include <boost/asio/detail/push_options.hpp>
+
+#include <boost/asio/detail/push_options.hpp>
+#include <cstddef>
+#include <boost/config.hpp>
+#include <boost/date_time/posix_time/posix_time_types.hpp>
+#include <boost/asio/detail/pop_options.hpp>
+
+#include <boost/asio/error.hpp>
+#include <boost/asio/io_service.hpp>
+#include <boost/asio/detail/bind_handler.hpp>
+#include <boost/asio/detail/handler_base_from_member.hpp>
+#include <boost/asio/detail/noncopyable.hpp>
+#include <boost/asio/detail/service_base.hpp>
+#include <boost/asio/detail/socket_ops.hpp>
+#include <boost/asio/detail/socket_types.hpp>
+#include <boost/asio/detail/timer_queue.hpp>
+
+namespace boost {
+namespace asio {
+namespace detail {
+
+template <typename Time_Traits, typename Timer_Scheduler>
+class deadline_timer_service
+ : public boost::asio::detail::service_base<
+ deadline_timer_service<Time_Traits, Timer_Scheduler> >
+{
+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 boost::asio::detail::noncopyable
+ {
+ time_type expiry;
+ bool might_have_pending_waits;
+ };
+
+ // Constructor.
+ deadline_timer_service(boost::asio::io_service& io_service)
+ : boost::asio::detail::service_base<
+ deadline_timer_service<Time_Traits, Timer_Scheduler> >(io_service),
+ scheduler_(boost::asio::use_service<Timer_Scheduler>(io_service))
+ {
+ 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_service()
+ {
+ }
+
+ // 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)
+ {
+ boost::system::error_code ec;
+ cancel(impl, ec);
+ }
+
+ // Cancel any asynchronous wait operations associated with the timer.
+ std::size_t cancel(implementation_type& impl, boost::system::error_code& ec)
+ {
+ if (!impl.might_have_pending_waits)
+ {
+ ec = boost::system::error_code();
+ return 0;
+ }
+ std::size_t count = scheduler_.cancel_timer(timer_queue_, &impl);
+ impl.might_have_pending_waits = false;
+ ec = boost::system::error_code();
+ return count;
+ }
+
+ // Get the expiry time for the timer as an absolute time.
+ time_type expires_at(const implementation_type& impl) const
+ {
+ return impl.expiry;
+ }
+
+ // Set the expiry time for the timer as an absolute time.
+ std::size_t expires_at(implementation_type& impl,
+ const time_type& expiry_time, boost::system::error_code& ec)
+ {
+ std::size_t count = cancel(impl, ec);
+ impl.expiry = expiry_time;
+ ec = boost::system::error_code();
+ return count;
+ }
+
+ // Get the expiry time for the timer relative to now.
+ duration_type expires_from_now(const implementation_type& impl) const
+ {
+ return Time_Traits::subtract(expires_at(impl), Time_Traits::now());
+ }
+
+ // Set the expiry time for the timer relative to now.
+ std::size_t expires_from_now(implementation_type& impl,
+ const duration_type& expiry_time, boost::system::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, boost::system::error_code& ec)
+ {
+ time_type now = Time_Traits::now();
+ while (Time_Traits::less_than(now, impl.expiry))
+ {
+ boost::posix_time::time_duration timeout =
+ Time_Traits::to_posix_duration(Time_Traits::subtract(impl.expiry, now));
+ ::timeval tv;
+ tv.tv_sec = timeout.total_seconds();
+ tv.tv_usec = timeout.total_microseconds() % 1000000;
+ boost::system::error_code ec;
+ socket_ops::select(0, 0, 0, 0, &tv, ec);
+ now = Time_Traits::now();
+ }
+ ec = boost::system::error_code();
+ }
+
+ template <typename Handler>
+ class wait_handler :
+ public handler_base_from_member<Handler>
+ {
+ public:
+ wait_handler(boost::asio::io_service& io_service, Handler handler)
+ : handler_base_from_member<Handler>(handler),
+ io_service_(io_service),
+ work_(io_service)
+ {
+ }
+
+ void operator()(const boost::system::error_code& result)
+ {
+ io_service_.post(detail::bind_handler(this->handler_, result));
+ }
+
+ private:
+ boost::asio::io_service& io_service_;
+ boost::asio::io_service::work work_;
+ };
+
+ // Start an asynchronous wait on the timer.
+ template <typename Handler>
+ void async_wait(implementation_type& impl, Handler handler)
+ {
+ impl.might_have_pending_waits = true;
+ scheduler_.schedule_timer(timer_queue_, impl.expiry,
+ wait_handler<Handler>(this->get_io_service(), handler), &impl);
+ }
+
+private:
+ // 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
+} // namespace boost
+
+#include <boost/asio/detail/pop_options.hpp>
+
+#endif // BOOST_ASIO_DETAIL_DEADLINE_TIMER_SERVICE_HPP
diff --git a/3rdParty/Boost/boost/asio/detail/descriptor_ops.hpp b/3rdParty/Boost/boost/asio/detail/descriptor_ops.hpp
new file mode 100644
index 0000000..2ee1988
--- /dev/null
+++ b/3rdParty/Boost/boost/asio/detail/descriptor_ops.hpp
@@ -0,0 +1,178 @@
+//
+// descriptor_ops.hpp
+// ~~~~~~~~~~~~~~~~~~
+//
+// Copyright (c) 2003-2008 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 BOOST_ASIO_DETAIL_DESCRIPTOR_OPS_HPP
+#define BOOST_ASIO_DETAIL_DESCRIPTOR_OPS_HPP
+
+#if defined(_MSC_VER) && (_MSC_VER >= 1200)
+# pragma once
+#endif // defined(_MSC_VER) && (_MSC_VER >= 1200)
+
+#include <boost/asio/detail/push_options.hpp>
+
+#include <boost/asio/detail/push_options.hpp>
+#include <boost/config.hpp>
+#include <cerrno>
+#include <boost/asio/detail/pop_options.hpp>
+
+#include <boost/asio/error.hpp>
+#include <boost/asio/detail/socket_types.hpp>
+
+#if !defined(BOOST_WINDOWS) && !defined(__CYGWIN__)
+
+namespace boost {
+namespace asio {
+namespace detail {
+namespace descriptor_ops {
+
+inline void clear_error(boost::system::error_code& ec)
+{
+ errno = 0;
+ ec = boost::system::error_code();
+}
+
+template <typename ReturnType>
+inline ReturnType error_wrapper(ReturnType return_value,
+ boost::system::error_code& ec)
+{
+ ec = boost::system::error_code(errno,
+ boost::asio::error::get_system_category());
+ return return_value;
+}
+
+inline int open(const char* path, int flags, boost::system::error_code& ec)
+{
+ clear_error(ec);
+ int result = error_wrapper(::open(path, flags), ec);
+ if (result >= 0)
+ clear_error(ec);
+ return result;
+}
+
+inline int close(int d, boost::system::error_code& ec)
+{
+ clear_error(ec);
+ int result = error_wrapper(::close(d), ec);
+ if (result == 0)
+ clear_error(ec);
+ 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);
+}
+
+typedef iovec buf;
+
+inline void init_buf(buf& b, void* data, size_t size)
+{
+ init_buf_iov_base(b.iov_base, data);
+ b.iov_len = size;
+}
+
+inline void init_buf(buf& b, const void* data, size_t size)
+{
+ init_buf_iov_base(b.iov_base, const_cast<void*>(data));
+ b.iov_len = size;
+}
+
+inline int scatter_read(int d, buf* bufs, size_t count,
+ boost::system::error_code& ec)
+{
+ clear_error(ec);
+ int result = error_wrapper(::readv(d, bufs, static_cast<int>(count)), ec);
+ if (result >= 0)
+ clear_error(ec);
+ return result;
+}
+
+inline int gather_write(int d, const buf* bufs, size_t count,
+ boost::system::error_code& ec)
+{
+ clear_error(ec);
+ int result = error_wrapper(::writev(d, bufs, static_cast<int>(count)), ec);
+ if (result >= 0)
+ clear_error(ec);
+ return result;
+}
+
+inline int ioctl(int d, long cmd, ioctl_arg_type* arg,
+ boost::system::error_code& ec)
+{
+ clear_error(ec);
+ int result = error_wrapper(::ioctl(d, cmd, arg), ec);
+ if (result >= 0)
+ clear_error(ec);
+ return result;
+}
+
+inline int fcntl(int d, long cmd, boost::system::error_code& ec)
+{
+ clear_error(ec);
+ int result = error_wrapper(::fcntl(d, cmd), ec);
+ if (result != -1)
+ clear_error(ec);
+ return result;
+}
+
+inline int fcntl(int d, long cmd, long arg, boost::system::error_code& ec)
+{
+ clear_error(ec);
+ int result = error_wrapper(::fcntl(d, cmd, arg), ec);
+ if (result != -1)
+ clear_error(ec);
+ return result;
+}
+
+inline int poll_read(int d, boost::system::error_code& ec)
+{
+ clear_error(ec);
+ pollfd fds;
+ fds.fd = d;
+ fds.events = POLLIN;
+ fds.revents = 0;
+ clear_error(ec);
+ int result = error_wrapper(::poll(&fds, 1, -1), ec);
+ if (result >= 0)
+ clear_error(ec);
+ return result;
+}
+
+inline int poll_write(int d, boost::system::error_code& ec)
+{
+ clear_error(ec);
+ pollfd fds;
+ fds.fd = d;
+ fds.events = POLLOUT;
+ fds.revents = 0;
+ clear_error(ec);
+ int result = error_wrapper(::poll(&fds, 1, -1), ec);
+ if (result >= 0)
+ clear_error(ec);
+ return result;
+}
+
+} // namespace descriptor_ops
+} // namespace detail
+} // namespace asio
+} // namespace boost
+
+#endif // !defined(BOOST_WINDOWS) && !defined(__CYGWIN__)
+
+#include <boost/asio/detail/pop_options.hpp>
+
+#endif // BOOST_ASIO_DETAIL_DESCRIPTOR_OPS_HPP
diff --git a/3rdParty/Boost/boost/asio/detail/dev_poll_reactor.hpp b/3rdParty/Boost/boost/asio/detail/dev_poll_reactor.hpp
new file mode 100644
index 0000000..8739085
--- /dev/null
+++ b/3rdParty/Boost/boost/asio/detail/dev_poll_reactor.hpp
@@ -0,0 +1,678 @@
+//
+// dev_poll_reactor.hpp
+// ~~~~~~~~~~~~~~~~~~~~
+//
+// Copyright (c) 2003-2008 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 BOOST_ASIO_DETAIL_DEV_POLL_REACTOR_HPP
+#define BOOST_ASIO_DETAIL_DEV_POLL_REACTOR_HPP
+
+#if defined(_MSC_VER) && (_MSC_VER >= 1200)
+# pragma once
+#endif // defined(_MSC_VER) && (_MSC_VER >= 1200)
+
+#include <boost/asio/detail/push_options.hpp>
+
+#include <boost/asio/detail/dev_poll_reactor_fwd.hpp>
+
+#if defined(BOOST_ASIO_HAS_DEV_POLL)
+
+#include <boost/asio/detail/push_options.hpp>
+#include <cstddef>
+#include <vector>
+#include <boost/config.hpp>
+#include <boost/date_time/posix_time/posix_time_types.hpp>
+#include <boost/throw_exception.hpp>
+#include <sys/devpoll.h>
+#include <boost/system/system_error.hpp>
+#include <boost/asio/detail/pop_options.hpp>
+
+#include <boost/asio/error.hpp>
+#include <boost/asio/io_service.hpp>
+#include <boost/asio/detail/bind_handler.hpp>
+#include <boost/asio/detail/hash_map.hpp>
+#include <boost/asio/detail/mutex.hpp>
+#include <boost/asio/detail/task_io_service.hpp>
+#include <boost/asio/detail/thread.hpp>
+#include <boost/asio/detail/reactor_op_queue.hpp>
+#include <boost/asio/detail/select_interrupter.hpp>
+#include <boost/asio/detail/service_base.hpp>
+#include <boost/asio/detail/signal_blocker.hpp>
+#include <boost/asio/detail/socket_types.hpp>
+#include <boost/asio/detail/timer_queue.hpp>
+
+namespace boost {
+namespace asio {
+namespace detail {
+
+template <bool Own_Thread>
+class dev_poll_reactor
+ : public boost::asio::detail::service_base<dev_poll_reactor<Own_Thread> >
+{
+public:
+ // Per-descriptor data.
+ struct per_descriptor_data
+ {
+ };
+
+ // Constructor.
+ dev_poll_reactor(boost::asio::io_service& io_service)
+ : boost::asio::detail::service_base<
+ dev_poll_reactor<Own_Thread> >(io_service),
+ mutex_(),
+ dev_poll_fd_(do_dev_poll_create()),
+ wait_in_progress_(false),
+ interrupter_(),
+ read_op_queue_(),
+ write_op_queue_(),
+ except_op_queue_(),
+ pending_cancellations_(),
+ stop_thread_(false),
+ thread_(0),
+ shutdown_(false)
+ {
+ // Start the reactor's internal thread only if needed.
+ if (Own_Thread)
+ {
+ boost::asio::detail::signal_blocker sb;
+ thread_ = new boost::asio::detail::thread(
+ bind_handler(&dev_poll_reactor::call_run_thread, this));
+ }
+
+ // Add the interrupter's descriptor to /dev/poll.
+ ::pollfd ev = { 0 };
+ ev.fd = interrupter_.read_descriptor();
+ ev.events = POLLIN | POLLERR;
+ ev.revents = 0;
+ ::write(dev_poll_fd_, &ev, sizeof(ev));
+ }
+
+ // Destructor.
+ ~dev_poll_reactor()
+ {
+ shutdown_service();
+ ::close(dev_poll_fd_);
+ }
+
+ // Destroy all user-defined handler objects owned by the service.
+ void shutdown_service()
+ {
+ boost::asio::detail::mutex::scoped_lock lock(mutex_);
+ shutdown_ = true;
+ stop_thread_ = true;
+ lock.unlock();
+
+ if (thread_)
+ {
+ interrupter_.interrupt();
+ thread_->join();
+ delete thread_;
+ thread_ = 0;
+ }
+
+ read_op_queue_.destroy_operations();
+ write_op_queue_.destroy_operations();
+ except_op_queue_.destroy_operations();
+
+ for (std::size_t i = 0; i < timer_queues_.size(); ++i)
+ timer_queues_[i]->destroy_timers();
+ timer_queues_.clear();
+ }
+
+ // Initialise the task, but only if the reactor is not in its own thread.
+ void init_task()
+ {
+ if (!Own_Thread)
+ {
+ typedef task_io_service<dev_poll_reactor<Own_Thread> >
+ task_io_service_type;
+ use_service<task_io_service_type>(this->get_io_service()).init_task();
+ }
+ }
+
+ // Register a socket with the reactor. Returns 0 on success, system error
+ // code on failure.
+ int register_descriptor(socket_type, per_descriptor_data&)
+ {
+ return 0;
+ }
+
+ // Start a new read operation. The handler object will be invoked when the
+ // given descriptor is ready to be read, or an error has occurred.
+ template <typename Handler>
+ void start_read_op(socket_type descriptor, per_descriptor_data&,
+ Handler handler, bool allow_speculative_read = true)
+ {
+ boost::asio::detail::mutex::scoped_lock lock(mutex_);
+
+ if (shutdown_)
+ return;
+
+ if (allow_speculative_read)
+ {
+ if (!read_op_queue_.has_operation(descriptor))
+ {
+ boost::system::error_code ec;
+ std::size_t bytes_transferred = 0;
+ if (handler.perform(ec, bytes_transferred))
+ {
+ handler.complete(ec, bytes_transferred);
+ return;
+ }
+ }
+ }
+
+ if (read_op_queue_.enqueue_operation(descriptor, handler))
+ {
+ ::pollfd& ev = add_pending_event_change(descriptor);
+ ev.events = POLLIN | POLLERR | POLLHUP;
+ if (write_op_queue_.has_operation(descriptor))
+ ev.events |= POLLOUT;
+ if (except_op_queue_.has_operation(descriptor))
+ ev.events |= POLLPRI;
+ interrupter_.interrupt();
+ }
+ }
+
+ // Start a new write operation. The handler object will be invoked when the
+ // given descriptor is ready to be written, or an error has occurred.
+ template <typename Handler>
+ void start_write_op(socket_type descriptor, per_descriptor_data&,
+ Handler handler, bool allow_speculative_write = true)
+ {
+ boost::asio::detail::mutex::scoped_lock lock(mutex_);
+
+ if (shutdown_)
+ return;
+
+ if (allow_speculative_write)
+ {
+ if (!write_op_queue_.has_operation(descriptor))
+ {
+ boost::system::error_code ec;
+ std::size_t bytes_transferred = 0;
+ if (handler.perform(ec, bytes_transferred))
+ {
+ handler.complete(ec, bytes_transferred);
+ return;
+ }
+ }
+ }
+
+ if (write_op_queue_.enqueue_operation(descriptor, handler))
+ {
+ ::pollfd& ev = add_pending_event_change(descriptor);
+ ev.events = POLLOUT | POLLERR | POLLHUP;
+ if (read_op_queue_.has_operation(descriptor))
+ ev.events |= POLLIN;
+ if (except_op_queue_.has_operation(descriptor))
+ ev.events |= POLLPRI;
+ interrupter_.interrupt();
+ }
+ }
+
+ // Start a new exception operation. The handler object will be invoked when
+ // the given descriptor has exception information, or an error has occurred.
+ template <typename Handler>
+ void start_except_op(socket_type descriptor,
+ per_descriptor_data&, Handler handler)
+ {
+ boost::asio::detail::mutex::scoped_lock lock(mutex_);
+
+ if (shutdown_)
+ return;
+
+ if (except_op_queue_.enqueue_operation(descriptor, handler))
+ {
+ ::pollfd& ev = add_pending_event_change(descriptor);
+ ev.events = POLLPRI | POLLERR | POLLHUP;
+ if (read_op_queue_.has_operation(descriptor))
+ ev.events |= POLLIN;
+ if (write_op_queue_.has_operation(descriptor))
+ ev.events |= POLLOUT;
+ interrupter_.interrupt();
+ }
+ }
+
+ // Start a new write operation. The handler object will be invoked when the
+ // information available, or an error has occurred.
+ template <typename Handler>
+ void start_connect_op(socket_type descriptor,
+ per_descriptor_data&, Handler handler)
+ {
+ boost::asio::detail::mutex::scoped_lock lock(mutex_);
+
+ if (shutdown_)
+ return;
+
+ if (write_op_queue_.enqueue_operation(descriptor, handler))
+ {
+ ::pollfd& ev = add_pending_event_change(descriptor);
+ ev.events = POLLOUT | POLLERR | POLLHUP;
+ if (read_op_queue_.has_operation(descriptor))
+ ev.events |= POLLIN;
+ if (except_op_queue_.has_operation(descriptor))
+ ev.events |= POLLPRI;
+ interrupter_.interrupt();
+ }
+ }
+
+ // Cancel all operations associated with the given descriptor. The
+ // handlers associated with the descriptor will be invoked with the
+ // operation_aborted error.
+ void cancel_ops(socket_type descriptor, per_descriptor_data&)
+ {
+ boost::asio::detail::mutex::scoped_lock lock(mutex_);
+ cancel_ops_unlocked(descriptor);
+ }
+
+ // Cancel any operations that are running against the descriptor and remove
+ // its registration from the reactor.
+ void close_descriptor(socket_type descriptor, per_descriptor_data&)
+ {
+ boost::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);
+ }
+
+ // Add a new timer queue to the reactor.
+ template <typename Time_Traits>
+ void add_timer_queue(timer_queue<Time_Traits>& timer_queue)
+ {
+ boost::asio::detail::mutex::scoped_lock lock(mutex_);
+ timer_queues_.push_back(&timer_queue);
+ }
+
+ // Remove a timer queue from the reactor.
+ template <typename Time_Traits>
+ void remove_timer_queue(timer_queue<Time_Traits>& timer_queue)
+ {
+ boost::asio::detail::mutex::scoped_lock lock(mutex_);
+ for (std::size_t i = 0; i < timer_queues_.size(); ++i)
+ {
+ if (timer_queues_[i] == &timer_queue)
+ {
+ timer_queues_.erase(timer_queues_.begin() + i);
+ return;
+ }
+ }
+ }
+
+ // Schedule a timer in the given timer queue to expire at the specified
+ // absolute time. The handler object will be invoked when the timer expires.
+ template <typename Time_Traits, typename Handler>
+ void schedule_timer(timer_queue<Time_Traits>& timer_queue,
+ const typename Time_Traits::time_type& time, Handler handler, void* token)
+ {
+ boost::asio::detail::mutex::scoped_lock lock(mutex_);
+ if (!shutdown_)
+ if (timer_queue.enqueue_timer(time, handler, token))
+ interrupter_.interrupt();
+ }
+
+ // 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>& timer_queue, void* token)
+ {
+ boost::asio::detail::mutex::scoped_lock lock(mutex_);
+ std::size_t n = timer_queue.cancel_timer(token);
+ if (n > 0)
+ interrupter_.interrupt();
+ return n;
+ }
+
+private:
+ friend class task_io_service<dev_poll_reactor<Own_Thread> >;
+
+ // Run /dev/poll once until interrupted or events are ready to be dispatched.
+ void run(bool block)
+ {
+ boost::asio::detail::mutex::scoped_lock lock(mutex_);
+
+ // Dispatch any operation cancellations that were made while the select
+ // loop was not running.
+ read_op_queue_.perform_cancellations();
+ write_op_queue_.perform_cancellations();
+ except_op_queue_.perform_cancellations();
+ for (std::size_t i = 0; i < timer_queues_.size(); ++i)
+ timer_queues_[i]->dispatch_cancellations();
+
+ // Check if the thread is supposed to stop.
+ if (stop_thread_)
+ {
+ complete_operations_and_timers(lock);
+ return;
+ }
+
+ // We can return immediately if there's no work to do and the reactor is
+ // not supposed to block.
+ if (!block && read_op_queue_.empty() && write_op_queue_.empty()
+ && except_op_queue_.empty() && all_timer_queues_are_empty())
+ {
+ complete_operations_and_timers(lock);
+ return;
+ }
+
+ // Write the pending event registration changes to the /dev/poll descriptor.
+ std::size_t events_size = sizeof(::pollfd) * pending_event_changes_.size();
+ errno = 0;
+ int result = ::write(dev_poll_fd_,
+ &pending_event_changes_[0], events_size);
+ if (result != static_cast<int>(events_size))
+ {
+ for (std::size_t i = 0; i < pending_event_changes_.size(); ++i)
+ {
+ int descriptor = pending_event_changes_[i].fd;
+ boost::system::error_code ec = boost::system::error_code(
+ errno, boost::asio::error::get_system_category());
+ read_op_queue_.perform_all_operations(descriptor, ec);
+ write_op_queue_.perform_all_operations(descriptor, ec);
+ except_op_queue_.perform_all_operations(descriptor, ec);
+ }
+ }
+ pending_event_changes_.clear();
+ pending_event_change_index_.clear();
+
+ int timeout = block ? get_timeout() : 0;
+ wait_in_progress_ = true;
+ lock.unlock();
+
+ // Block on the /dev/poll descriptor.
+ ::pollfd events[128] = { { 0 } };
+ ::dvpoll dp = { 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();
+ wait_in_progress_ = false;
+
+ // Block signals while performing operations.
+ boost::asio::detail::signal_blocker sb;
+
+ // 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;
+ boost::system::error_code ec;
+
+ // 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 = except_op_queue_.perform_operation(descriptor, ec);
+ else
+ more_except = except_op_queue_.has_operation(descriptor);
+
+ if (events[i].events & (POLLIN | POLLERR | POLLHUP))
+ more_reads = read_op_queue_.perform_operation(descriptor, ec);
+ else
+ more_reads = read_op_queue_.has_operation(descriptor);
+
+ if (events[i].events & (POLLOUT | POLLERR | POLLHUP))
+ more_writes = write_op_queue_.perform_operation(descriptor, ec);
+ else
+ more_writes = write_op_queue_.has_operation(descriptor);
+
+ if ((events[i].events & (POLLERR | POLLHUP)) != 0
+ && (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 };
+ ev.fd = descriptor;
+ ev.events = POLLREMOVE;
+ ev.revents = 0;
+ ::write(dev_poll_fd_, &ev, sizeof(ev));
+ }
+ else
+ {
+ ::pollfd ev = { 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))
+ {
+ ec = boost::system::error_code(errno,
+ boost::asio::error::get_system_category());
+ read_op_queue_.perform_all_operations(descriptor, ec);
+ write_op_queue_.perform_all_operations(descriptor, ec);
+ except_op_queue_.perform_all_operations(descriptor, ec);
+ }
+ }
+ }
+ }
+ read_op_queue_.perform_cancellations();
+ write_op_queue_.perform_cancellations();
+ except_op_queue_.perform_cancellations();
+ for (std::size_t i = 0; i < timer_queues_.size(); ++i)
+ {
+ timer_queues_[i]->dispatch_timers();
+ timer_queues_[i]->dispatch_cancellations();
+ }
+
+ // Issue any pending cancellations.
+ for (size_t i = 0; i < pending_cancellations_.size(); ++i)
+ cancel_ops_unlocked(pending_cancellations_[i]);
+ pending_cancellations_.clear();
+
+ complete_operations_and_timers(lock);
+ }
+
+ // Run the select loop in the thread.
+ void run_thread()
+ {
+ boost::asio::detail::mutex::scoped_lock lock(mutex_);
+ while (!stop_thread_)
+ {
+ lock.unlock();
+ run(true);
+ lock.lock();
+ }
+ }
+
+ // Entry point for the select loop thread.
+ static void call_run_thread(dev_poll_reactor* reactor)
+ {
+ reactor->run_thread();
+ }
+
+ // Interrupt the select loop.
+ void interrupt()
+ {
+ interrupter_.interrupt();
+ }
+
+ // Create the /dev/poll file descriptor. Throws an exception if the descriptor
+ // cannot be created.
+ static int do_dev_poll_create()
+ {
+ int fd = ::open("/dev/poll", O_RDWR);
+ if (fd == -1)
+ {
+ boost::throw_exception(
+ boost::system::system_error(
+ boost::system::error_code(errno,
+ boost::asio::error::get_system_category()),
+ "/dev/poll"));
+ }
+ return fd;
+ }
+
+ // Check if all timer queues are empty.
+ bool all_timer_queues_are_empty() const
+ {
+ for (std::size_t i = 0; i < timer_queues_.size(); ++i)
+ if (!timer_queues_[i]->empty())
+ return false;
+ return true;
+ }
+
+ // 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.
+ int get_timeout()
+ {
+ if (all_timer_queues_are_empty())
+ return -1;
+
+ // 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.
+ boost::posix_time::time_duration minimum_wait_duration
+ = boost::posix_time::minutes(5);
+
+ for (std::size_t i = 0; i < timer_queues_.size(); ++i)
+ {
+ boost::posix_time::time_duration wait_duration
+ = timer_queues_[i]->wait_duration();
+ if (wait_duration < minimum_wait_duration)
+ minimum_wait_duration = wait_duration;
+ }
+
+ if (minimum_wait_duration > boost::posix_time::time_duration())
+ {
+ int milliseconds = minimum_wait_duration.total_milliseconds();
+ return milliseconds > 0 ? milliseconds : 1;
+ }
+ else
+ {
+ return 0;
+ }
+ }
+
+ // 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.
+ void cancel_ops_unlocked(socket_type descriptor)
+ {
+ bool interrupt = read_op_queue_.cancel_operations(descriptor);
+ interrupt = write_op_queue_.cancel_operations(descriptor) || interrupt;
+ interrupt = except_op_queue_.cancel_operations(descriptor) || interrupt;
+ if (interrupt)
+ interrupter_.interrupt();
+ }
+
+ // Clean up operations and timers. We must not hold the lock since the
+ // destructors may make calls back into this reactor. We make a copy of the
+ // vector of timer queues since the original may be modified while the lock
+ // is not held.
+ void complete_operations_and_timers(
+ boost::asio::detail::mutex::scoped_lock& lock)
+ {
+ timer_queues_for_cleanup_ = timer_queues_;
+ lock.unlock();
+ read_op_queue_.complete_operations();
+ write_op_queue_.complete_operations();
+ except_op_queue_.complete_operations();
+ for (std::size_t i = 0; i < timer_queues_for_cleanup_.size(); ++i)
+ timer_queues_for_cleanup_[i]->complete_timers();
+ }
+
+ // Add a pending event entry for the given descriptor.
+ ::pollfd& 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];
+ }
+ }
+
+ // Mutex to protect access to internal data.
+ boost::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_;
+
+ // Whether the DP_POLL operation is currently in progress
+ bool wait_in_progress_;
+
+ // The interrupter is used to break a blocking DP_POLL operation.
+ select_interrupter interrupter_;
+
+ // The queue of read operations.
+ reactor_op_queue<socket_type> read_op_queue_;
+
+ // The queue of write operations.
+ reactor_op_queue<socket_type> write_op_queue_;
+
+ // The queue of except operations.
+ reactor_op_queue<socket_type> except_op_queue_;
+
+ // The timer queues.
+ std::vector<timer_queue_base*> timer_queues_;
+
+ // A copy of the timer queues, used when cleaning up timers. The copy is
+ // stored as a class data member to avoid unnecessary memory allocation.
+ std::vector<timer_queue_base*> timer_queues_for_cleanup_;
+
+ // The descriptors that are pending cancellation.
+ std::vector<socket_type> pending_cancellations_;
+
+ // Does the reactor loop thread need to stop.
+ bool stop_thread_;
+
+ // The thread that is running the reactor loop.
+ boost::asio::detail::thread* thread_;
+
+ // Whether the service has been shut down.
+ bool shutdown_;
+};
+
+} // namespace detail
+} // namespace asio
+} // namespace boost
+
+#endif // defined(BOOST_ASIO_HAS_DEV_POLL)
+
+#include <boost/asio/detail/pop_options.hpp>
+
+#endif // BOOST_ASIO_DETAIL_DEV_POLL_REACTOR_HPP
diff --git a/3rdParty/Boost/boost/asio/detail/dev_poll_reactor_fwd.hpp b/3rdParty/Boost/boost/asio/detail/dev_poll_reactor_fwd.hpp
new file mode 100644
index 0000000..3308575
--- /dev/null
+++ b/3rdParty/Boost/boost/asio/detail/dev_poll_reactor_fwd.hpp
@@ -0,0 +1,42 @@
+//
+// dev_poll_reactor_fwd.hpp
+// ~~~~~~~~~~~~~~~~~~~~~~~~
+//
+// Copyright (c) 2003-2008 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 BOOST_ASIO_DETAIL_DEV_POLL_REACTOR_FWD_HPP
+#define BOOST_ASIO_DETAIL_DEV_POLL_REACTOR_FWD_HPP
+
+#if defined(_MSC_VER) && (_MSC_VER >= 1200)
+# pragma once
+#endif // defined(_MSC_VER) && (_MSC_VER >= 1200)
+
+#include <boost/asio/detail/push_options.hpp>
+
+#if !defined(BOOST_ASIO_DISABLE_DEV_POLL)
+#if defined(__sun) // This service is only supported on Solaris.
+
+// Define this to indicate that /dev/poll is supported on the target platform.
+#define BOOST_ASIO_HAS_DEV_POLL 1
+
+namespace boost {
+namespace asio {
+namespace detail {
+
+template <bool Own_Thread>
+class dev_poll_reactor;
+
+} // namespace detail
+} // namespace asio
+} // namespace boost
+
+#endif // defined(__sun)
+#endif // !defined(BOOST_ASIO_DISABLE_DEV_POLL)
+
+#include <boost/asio/detail/pop_options.hpp>
+
+#endif // BOOST_ASIO_DETAIL_DEV_POLL_REACTOR_FWD_HPP
diff --git a/3rdParty/Boost/boost/asio/detail/epoll_reactor.hpp b/3rdParty/Boost/boost/asio/detail/epoll_reactor.hpp
new file mode 100644
index 0000000..2770c6a
--- /dev/null
+++ b/3rdParty/Boost/boost/asio/detail/epoll_reactor.hpp
@@ -0,0 +1,733 @@
+//
+// epoll_reactor.hpp
+// ~~~~~~~~~~~~~~~~~
+//
+// Copyright (c) 2003-2008 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 BOOST_ASIO_DETAIL_EPOLL_REACTOR_HPP
+#define BOOST_ASIO_DETAIL_EPOLL_REACTOR_HPP
+
+#if defined(_MSC_VER) && (_MSC_VER >= 1200)
+# pragma once
+#endif // defined(_MSC_VER) && (_MSC_VER >= 1200)
+
+#include <boost/asio/detail/push_options.hpp>
+
+#include <boost/asio/detail/epoll_reactor_fwd.hpp>
+
+#if defined(BOOST_ASIO_HAS_EPOLL)
+
+#include <boost/asio/detail/push_options.hpp>
+#include <cstddef>
+#include <vector>
+#include <sys/epoll.h>
+#include <boost/config.hpp>
+#include <boost/date_time/posix_time/posix_time_types.hpp>
+#include <boost/throw_exception.hpp>
+#include <boost/system/system_error.hpp>
+#include <boost/asio/detail/pop_options.hpp>
+
+#include <boost/asio/error.hpp>
+#include <boost/asio/io_service.hpp>
+#include <boost/asio/detail/bind_handler.hpp>
+#include <boost/asio/detail/hash_map.hpp>
+#include <boost/asio/detail/mutex.hpp>
+#include <boost/asio/detail/task_io_service.hpp>
+#include <boost/asio/detail/thread.hpp>
+#include <boost/asio/detail/reactor_op_queue.hpp>
+#include <boost/asio/detail/select_interrupter.hpp>
+#include <boost/asio/detail/service_base.hpp>
+#include <boost/asio/detail/signal_blocker.hpp>
+#include <boost/asio/detail/socket_types.hpp>
+#include <boost/asio/detail/timer_queue.hpp>
+
+namespace boost {
+namespace asio {
+namespace detail {
+
+template <bool Own_Thread>
+class epoll_reactor
+ : public boost::asio::detail::service_base<epoll_reactor<Own_Thread> >
+{
+public:
+ // Per-descriptor data.
+ struct per_descriptor_data
+ {
+ bool allow_speculative_read;
+ bool allow_speculative_write;
+ };
+
+ // Constructor.
+ epoll_reactor(boost::asio::io_service& io_service)
+ : boost::asio::detail::service_base<epoll_reactor<Own_Thread> >(io_service),
+ mutex_(),
+ epoll_fd_(do_epoll_create()),
+ wait_in_progress_(false),
+ interrupter_(),
+ read_op_queue_(),
+ write_op_queue_(),
+ except_op_queue_(),
+ pending_cancellations_(),
+ stop_thread_(false),
+ thread_(0),
+ shutdown_(false),
+ need_epoll_wait_(true)
+ {
+ // Start the reactor's internal thread only if needed.
+ if (Own_Thread)
+ {
+ boost::asio::detail::signal_blocker sb;
+ thread_ = new boost::asio::detail::thread(
+ bind_handler(&epoll_reactor::call_run_thread, this));
+ }
+
+ // Add the interrupter's descriptor to epoll.
+ epoll_event ev = { 0, { 0 } };
+ ev.events = EPOLLIN | EPOLLERR;
+ ev.data.fd = interrupter_.read_descriptor();
+ epoll_ctl(epoll_fd_, EPOLL_CTL_ADD, interrupter_.read_descriptor(), &ev);
+ }
+
+ // Destructor.
+ ~epoll_reactor()
+ {
+ shutdown_service();
+ close(epoll_fd_);
+ }
+
+ // Destroy all user-defined handler objects owned by the service.
+ void shutdown_service()
+ {
+ boost::asio::detail::mutex::scoped_lock lock(mutex_);
+ shutdown_ = true;
+ stop_thread_ = true;
+ lock.unlock();
+
+ if (thread_)
+ {
+ interrupter_.interrupt();
+ thread_->join();
+ delete thread_;
+ thread_ = 0;
+ }
+
+ read_op_queue_.destroy_operations();
+ write_op_queue_.destroy_operations();
+ except_op_queue_.destroy_operations();
+
+ for (std::size_t i = 0; i < timer_queues_.size(); ++i)
+ timer_queues_[i]->destroy_timers();
+ timer_queues_.clear();
+ }
+
+ // Initialise the task, but only if the reactor is not in its own thread.
+ void init_task()
+ {
+ if (!Own_Thread)
+ {
+ typedef task_io_service<epoll_reactor<Own_Thread> > task_io_service_type;
+ use_service<task_io_service_type>(this->get_io_service()).init_task();
+ }
+ }
+
+ // Register a socket with the reactor. Returns 0 on success, system error
+ // code on failure.
+ int register_descriptor(socket_type descriptor,
+ per_descriptor_data& descriptor_data)
+ {
+ // No need to lock according to epoll documentation.
+
+ descriptor_data.allow_speculative_read = true;
+ descriptor_data.allow_speculative_write = true;
+
+ epoll_event ev = { 0, { 0 } };
+ ev.events = 0;
+ ev.data.fd = descriptor;
+ int result = epoll_ctl(epoll_fd_, EPOLL_CTL_ADD, descriptor, &ev);
+ if (result != 0)
+ return errno;
+ return 0;
+ }
+
+ // Start a new read operation. The handler object will be invoked when the
+ // given descriptor is ready to be read, or an error has occurred.
+ template <typename Handler>
+ void start_read_op(socket_type descriptor,
+ per_descriptor_data& descriptor_data,
+ Handler handler, bool allow_speculative_read = true)
+ {
+ if (allow_speculative_read && descriptor_data.allow_speculative_read)
+ {
+ boost::system::error_code ec;
+ std::size_t bytes_transferred = 0;
+ if (handler.perform(ec, bytes_transferred))
+ {
+ handler.complete(ec, bytes_transferred);
+ return;
+ }
+
+ // We only get one shot at a speculative read in this function.
+ allow_speculative_read = false;
+ }
+
+ boost::asio::detail::mutex::scoped_lock lock(mutex_);
+
+ if (shutdown_)
+ return;
+
+ if (!allow_speculative_read)
+ need_epoll_wait_ = true;
+ else if (!read_op_queue_.has_operation(descriptor))
+ {
+ // Speculative reads are ok as there are no queued read operations.
+ descriptor_data.allow_speculative_read = true;
+
+ boost::system::error_code ec;
+ std::size_t bytes_transferred = 0;
+ if (handler.perform(ec, bytes_transferred))
+ {
+ handler.complete(ec, bytes_transferred);
+ return;
+ }
+ }
+
+ // Speculative reads are not ok as there will be queued read operations.
+ descriptor_data.allow_speculative_read = false;
+
+ if (read_op_queue_.enqueue_operation(descriptor, handler))
+ {
+ epoll_event ev = { 0, { 0 } };
+ ev.events = EPOLLIN | EPOLLERR | EPOLLHUP;
+ if (write_op_queue_.has_operation(descriptor))
+ ev.events |= EPOLLOUT;
+ if (except_op_queue_.has_operation(descriptor))
+ ev.events |= EPOLLPRI;
+ ev.data.fd = descriptor;
+
+ int result = epoll_ctl(epoll_fd_, EPOLL_CTL_MOD, descriptor, &ev);
+ if (result != 0 && errno == ENOENT)
+ result = epoll_ctl(epoll_fd_, EPOLL_CTL_ADD, descriptor, &ev);
+ if (result != 0)
+ {
+ boost::system::error_code ec(errno,
+ boost::asio::error::get_system_category());
+ read_op_queue_.perform_all_operations(descriptor, ec);
+ }
+ }
+ }
+
+ // Start a new write operation. The handler object will be invoked when the
+ // given descriptor is ready to be written, or an error has occurred.
+ template <typename Handler>
+ void start_write_op(socket_type descriptor,
+ per_descriptor_data& descriptor_data,
+ Handler handler, bool allow_speculative_write = true)
+ {
+ if (allow_speculative_write && descriptor_data.allow_speculative_write)
+ {
+ boost::system::error_code ec;
+ std::size_t bytes_transferred = 0;
+ if (handler.perform(ec, bytes_transferred))
+ {
+ handler.complete(ec, bytes_transferred);
+ return;
+ }
+
+ // We only get one shot at a speculative write in this function.
+ allow_speculative_write = false;
+ }
+
+ boost::asio::detail::mutex::scoped_lock lock(mutex_);
+
+ if (shutdown_)
+ return;
+
+ if (!allow_speculative_write)
+ need_epoll_wait_ = true;
+ else if (!write_op_queue_.has_operation(descriptor))
+ {
+ // Speculative writes are ok as there are no queued write operations.
+ descriptor_data.allow_speculative_write = true;
+
+ boost::system::error_code ec;
+ std::size_t bytes_transferred = 0;
+ if (handler.perform(ec, bytes_transferred))
+ {
+ handler.complete(ec, bytes_transferred);
+ return;
+ }
+ }
+
+ // Speculative writes are not ok as there will be queued write operations.
+ descriptor_data.allow_speculative_write = false;
+
+ if (write_op_queue_.enqueue_operation(descriptor, handler))
+ {
+ epoll_event ev = { 0, { 0 } };
+ ev.events = EPOLLOUT | EPOLLERR | EPOLLHUP;
+ if (read_op_queue_.has_operation(descriptor))
+ ev.events |= EPOLLIN;
+ if (except_op_queue_.has_operation(descriptor))
+ ev.events |= EPOLLPRI;
+ ev.data.fd = descriptor;
+
+ int result = epoll_ctl(epoll_fd_, EPOLL_CTL_MOD, descriptor, &ev);
+ if (result != 0 && errno == ENOENT)
+ result = epoll_ctl(epoll_fd_, EPOLL_CTL_ADD, descriptor, &ev);
+ if (result != 0)
+ {
+ boost::system::error_code ec(errno,
+ boost::asio::error::get_system_category());
+ write_op_queue_.perform_all_operations(descriptor, ec);
+ }
+ }
+ }
+
+ // Start a new exception operation. The handler object will be invoked when
+ // the given descriptor has exception information, or an error has occurred.
+ template <typename Handler>
+ void start_except_op(socket_type descriptor,
+ per_descriptor_data&, Handler handler)
+ {
+ boost::asio::detail::mutex::scoped_lock lock(mutex_);
+
+ if (shutdown_)
+ return;
+
+ if (except_op_queue_.enqueue_operation(descriptor, handler))
+ {
+ epoll_event ev = { 0, { 0 } };
+ ev.events = EPOLLPRI | EPOLLERR | EPOLLHUP;
+ if (read_op_queue_.has_operation(descriptor))
+ ev.events |= EPOLLIN;
+ if (write_op_queue_.has_operation(descriptor))
+ ev.events |= EPOLLOUT;
+ ev.data.fd = descriptor;
+
+ int result = epoll_ctl(epoll_fd_, EPOLL_CTL_MOD, descriptor, &ev);
+ if (result != 0 && errno == ENOENT)
+ result = epoll_ctl(epoll_fd_, EPOLL_CTL_ADD, descriptor, &ev);
+ if (result != 0)
+ {
+ boost::system::error_code ec(errno,
+ boost::asio::error::get_system_category());
+ except_op_queue_.perform_all_operations(descriptor, ec);
+ }
+ }
+ }
+
+ // Start a new write operation. The handler object will be invoked when the
+ // given descriptor is ready for writing or an error has occurred. Speculative
+ // writes are not allowed.
+ template <typename Handler>
+ void start_connect_op(socket_type descriptor,
+ per_descriptor_data& descriptor_data, Handler handler)
+ {
+ boost::asio::detail::mutex::scoped_lock lock(mutex_);
+
+ if (shutdown_)
+ return;
+
+ // Speculative writes are not ok as there will be queued write operations.
+ descriptor_data.allow_speculative_write = false;
+
+ if (write_op_queue_.enqueue_operation(descriptor, handler))
+ {
+ epoll_event ev = { 0, { 0 } };
+ ev.events = EPOLLOUT | EPOLLERR | EPOLLHUP;
+ if (read_op_queue_.has_operation(descriptor))
+ ev.events |= EPOLLIN;
+ if (except_op_queue_.has_operation(descriptor))
+ ev.events |= EPOLLPRI;
+ ev.data.fd = descriptor;
+
+ int result = epoll_ctl(epoll_fd_, EPOLL_CTL_MOD, descriptor, &ev);
+ if (result != 0 && errno == ENOENT)
+ result = epoll_ctl(epoll_fd_, EPOLL_CTL_ADD, descriptor, &ev);
+ if (result != 0)
+ {
+ boost::system::error_code ec(errno,
+ boost::asio::error::get_system_category());
+ write_op_queue_.perform_all_operations(descriptor, ec);
+ }
+ }
+ }
+
+ // Cancel all operations associated with the given descriptor. The
+ // handlers associated with the descriptor will be invoked with the
+ // operation_aborted error.
+ void cancel_ops(socket_type descriptor, per_descriptor_data&)
+ {
+ boost::asio::detail::mutex::scoped_lock lock(mutex_);
+ cancel_ops_unlocked(descriptor);
+ }
+
+ // Cancel any operations that are running against the descriptor and remove
+ // its registration from the reactor.
+ void close_descriptor(socket_type descriptor, per_descriptor_data&)
+ {
+ boost::asio::detail::mutex::scoped_lock lock(mutex_);
+
+ // Remove the descriptor from epoll.
+ epoll_event ev = { 0, { 0 } };
+ epoll_ctl(epoll_fd_, EPOLL_CTL_DEL, descriptor, &ev);
+
+ // Cancel any outstanding operations associated with the descriptor.
+ cancel_ops_unlocked(descriptor);
+ }
+
+ // Add a new timer queue to the reactor.
+ template <typename Time_Traits>
+ void add_timer_queue(timer_queue<Time_Traits>& timer_queue)
+ {
+ boost::asio::detail::mutex::scoped_lock lock(mutex_);
+ timer_queues_.push_back(&timer_queue);
+ }
+
+ // Remove a timer queue from the reactor.
+ template <typename Time_Traits>
+ void remove_timer_queue(timer_queue<Time_Traits>& timer_queue)
+ {
+ boost::asio::detail::mutex::scoped_lock lock(mutex_);
+ for (std::size_t i = 0; i < timer_queues_.size(); ++i)
+ {
+ if (timer_queues_[i] == &timer_queue)
+ {
+ timer_queues_.erase(timer_queues_.begin() + i);
+ return;
+ }
+ }
+ }
+
+ // Schedule a timer in the given timer queue to expire at the specified
+ // absolute time. The handler object will be invoked when the timer expires.
+ template <typename Time_Traits, typename Handler>
+ void schedule_timer(timer_queue<Time_Traits>& timer_queue,
+ const typename Time_Traits::time_type& time, Handler handler, void* token)
+ {
+ boost::asio::detail::mutex::scoped_lock lock(mutex_);
+ if (!shutdown_)
+ if (timer_queue.enqueue_timer(time, handler, token))
+ interrupter_.interrupt();
+ }
+
+ // 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>& timer_queue, void* token)
+ {
+ boost::asio::detail::mutex::scoped_lock lock(mutex_);
+ std::size_t n = timer_queue.cancel_timer(token);
+ if (n > 0)
+ interrupter_.interrupt();
+ return n;
+ }
+
+private:
+ friend class task_io_service<epoll_reactor<Own_Thread> >;
+
+ // Run epoll once until interrupted or events are ready to be dispatched.
+ void run(bool block)
+ {
+ boost::asio::detail::mutex::scoped_lock lock(mutex_);
+
+ // Dispatch any operation cancellations that were made while the select
+ // loop was not running.
+ read_op_queue_.perform_cancellations();
+ write_op_queue_.perform_cancellations();
+ except_op_queue_.perform_cancellations();
+ for (std::size_t i = 0; i < timer_queues_.size(); ++i)
+ timer_queues_[i]->dispatch_cancellations();
+
+ // Check if the thread is supposed to stop.
+ if (stop_thread_)
+ {
+ complete_operations_and_timers(lock);
+ return;
+ }
+
+ // We can return immediately if there's no work to do and the reactor is
+ // not supposed to block.
+ if (!block && read_op_queue_.empty() && write_op_queue_.empty()
+ && except_op_queue_.empty() && all_timer_queues_are_empty())
+ {
+ complete_operations_and_timers(lock);
+ return;
+ }
+
+ int timeout = block ? get_timeout() : 0;
+ wait_in_progress_ = true;
+ lock.unlock();
+
+ // Block on the epoll descriptor.
+ epoll_event events[128];
+ int num_events = (block || need_epoll_wait_)
+ ? epoll_wait(epoll_fd_, events, 128, timeout)
+ : 0;
+
+ lock.lock();
+ wait_in_progress_ = false;
+
+ // Block signals while performing operations.
+ boost::asio::detail::signal_blocker sb;
+
+ // Dispatch the waiting events.
+ for (int i = 0; i < num_events; ++i)
+ {
+ int descriptor = events[i].data.fd;
+ if (descriptor == interrupter_.read_descriptor())
+ {
+ interrupter_.reset();
+ }
+ else
+ {
+ bool more_reads = false;
+ bool more_writes = false;
+ bool more_except = false;
+ boost::system::error_code ec;
+
+ // Exception operations must be processed first to ensure that any
+ // out-of-band data is read before normal data.
+ if (events[i].events & (EPOLLPRI | EPOLLERR | EPOLLHUP))
+ more_except = except_op_queue_.perform_operation(descriptor, ec);
+ else
+ more_except = except_op_queue_.has_operation(descriptor);
+
+ if (events[i].events & (EPOLLIN | EPOLLERR | EPOLLHUP))
+ more_reads = read_op_queue_.perform_operation(descriptor, ec);
+ else
+ more_reads = read_op_queue_.has_operation(descriptor);
+
+ if (events[i].events & (EPOLLOUT | EPOLLERR | EPOLLHUP))
+ more_writes = write_op_queue_.perform_operation(descriptor, ec);
+ else
+ more_writes = write_op_queue_.has_operation(descriptor);
+
+ if ((events[i].events & (EPOLLERR | EPOLLHUP)) != 0
+ && (events[i].events & ~(EPOLLERR | EPOLLHUP)) == 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 epoll. The
+ // epoll_wait system call can produce EPOLLHUP or EPOLLERR events
+ // when there is no operation pending, so if we do not remove the
+ // descriptor we can end up in a tight loop of repeated
+ // calls to epoll_wait.
+ epoll_event ev = { 0, { 0 } };
+ epoll_ctl(epoll_fd_, EPOLL_CTL_DEL, descriptor, &ev);
+ }
+ else
+ {
+ epoll_event ev = { 0, { 0 } };
+ ev.events = EPOLLERR | EPOLLHUP;
+ if (more_reads)
+ ev.events |= EPOLLIN;
+ if (more_writes)
+ ev.events |= EPOLLOUT;
+ if (more_except)
+ ev.events |= EPOLLPRI;
+ ev.data.fd = descriptor;
+ int result = epoll_ctl(epoll_fd_, EPOLL_CTL_MOD, descriptor, &ev);
+ if (result != 0 && errno == ENOENT)
+ result = epoll_ctl(epoll_fd_, EPOLL_CTL_ADD, descriptor, &ev);
+ if (result != 0)
+ {
+ ec = boost::system::error_code(errno,
+ boost::asio::error::get_system_category());
+ read_op_queue_.perform_all_operations(descriptor, ec);
+ write_op_queue_.perform_all_operations(descriptor, ec);
+ except_op_queue_.perform_all_operations(descriptor, ec);
+ }
+ }
+ }
+ }
+ read_op_queue_.perform_cancellations();
+ write_op_queue_.perform_cancellations();
+ except_op_queue_.perform_cancellations();
+ for (std::size_t i = 0; i < timer_queues_.size(); ++i)
+ {
+ timer_queues_[i]->dispatch_timers();
+ timer_queues_[i]->dispatch_cancellations();
+ }
+
+ // Issue any pending cancellations.
+ for (size_t i = 0; i < pending_cancellations_.size(); ++i)
+ cancel_ops_unlocked(pending_cancellations_[i]);
+ pending_cancellations_.clear();
+
+ // Determine whether epoll_wait should be called when the reactor next runs.
+ need_epoll_wait_ = !read_op_queue_.empty()
+ || !write_op_queue_.empty() || !except_op_queue_.empty();
+
+ complete_operations_and_timers(lock);
+ }
+
+ // Run the select loop in the thread.
+ void run_thread()
+ {
+ boost::asio::detail::mutex::scoped_lock lock(mutex_);
+ while (!stop_thread_)
+ {
+ lock.unlock();
+ run(true);
+ lock.lock();
+ }
+ }
+
+ // Entry point for the select loop thread.
+ static void call_run_thread(epoll_reactor* reactor)
+ {
+ reactor->run_thread();
+ }
+
+ // Interrupt the select loop.
+ void interrupt()
+ {
+ interrupter_.interrupt();
+ }
+
+ // 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.
+ static int do_epoll_create()
+ {
+ int fd = epoll_create(epoll_size);
+ if (fd == -1)
+ {
+ boost::throw_exception(
+ boost::system::system_error(
+ boost::system::error_code(errno,
+ boost::asio::error::get_system_category()),
+ "epoll"));
+ }
+ return fd;
+ }
+
+ // Check if all timer queues are empty.
+ bool all_timer_queues_are_empty() const
+ {
+ for (std::size_t i = 0; i < timer_queues_.size(); ++i)
+ if (!timer_queues_[i]->empty())
+ return false;
+ return true;
+ }
+
+ // 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.
+ int get_timeout()
+ {
+ if (all_timer_queues_are_empty())
+ return -1;
+
+ // 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.
+ boost::posix_time::time_duration minimum_wait_duration
+ = boost::posix_time::minutes(5);
+
+ for (std::size_t i = 0; i < timer_queues_.size(); ++i)
+ {
+ boost::posix_time::time_duration wait_duration
+ = timer_queues_[i]->wait_duration();
+ if (wait_duration < minimum_wait_duration)
+ minimum_wait_duration = wait_duration;
+ }
+
+ if (minimum_wait_duration > boost::posix_time::time_duration())
+ {
+ int milliseconds = minimum_wait_duration.total_milliseconds();
+ return milliseconds > 0 ? milliseconds : 1;
+ }
+ else
+ {
+ return 0;
+ }
+ }
+
+ // 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 epoll_reactor's mutex.
+ void cancel_ops_unlocked(socket_type descriptor)
+ {
+ bool interrupt = read_op_queue_.cancel_operations(descriptor);
+ interrupt = write_op_queue_.cancel_operations(descriptor) || interrupt;
+ interrupt = except_op_queue_.cancel_operations(descriptor) || interrupt;
+ if (interrupt)
+ interrupter_.interrupt();
+ }
+
+ // Clean up operations and timers. We must not hold the lock since the
+ // destructors may make calls back into this reactor. We make a copy of the
+ // vector of timer queues since the original may be modified while the lock
+ // is not held.
+ void complete_operations_and_timers(
+ boost::asio::detail::mutex::scoped_lock& lock)
+ {
+ timer_queues_for_cleanup_ = timer_queues_;
+ lock.unlock();
+ read_op_queue_.complete_operations();
+ write_op_queue_.complete_operations();
+ except_op_queue_.complete_operations();
+ for (std::size_t i = 0; i < timer_queues_for_cleanup_.size(); ++i)
+ timer_queues_for_cleanup_[i]->complete_timers();
+ }
+
+ // Mutex to protect access to internal data.
+ boost::asio::detail::mutex mutex_;
+
+ // The epoll file descriptor.
+ int epoll_fd_;
+
+ // Whether the epoll_wait call is currently in progress
+ bool wait_in_progress_;
+
+ // The interrupter is used to break a blocking epoll_wait call.
+ select_interrupter interrupter_;
+
+ // The queue of read operations.
+ reactor_op_queue<socket_type> read_op_queue_;
+
+ // The queue of write operations.
+ reactor_op_queue<socket_type> write_op_queue_;
+
+ // The queue of except operations.
+ reactor_op_queue<socket_type> except_op_queue_;
+
+ // The timer queues.
+ std::vector<timer_queue_base*> timer_queues_;
+
+ // A copy of the timer queues, used when cleaning up timers. The copy is
+ // stored as a class data member to avoid unnecessary memory allocation.
+ std::vector<timer_queue_base*> timer_queues_for_cleanup_;
+
+ // The descriptors that are pending cancellation.
+ std::vector<socket_type> pending_cancellations_;
+
+ // Does the reactor loop thread need to stop.
+ bool stop_thread_;
+
+ // The thread that is running the reactor loop.
+ boost::asio::detail::thread* thread_;
+
+ // Whether the service has been shut down.
+ bool shutdown_;
+
+ // Whether we need to call epoll_wait the next time the reactor is run.
+ bool need_epoll_wait_;
+};
+
+} // namespace detail
+} // namespace asio
+} // namespace boost
+
+#endif // defined(BOOST_ASIO_HAS_EPOLL)
+
+#include <boost/asio/detail/pop_options.hpp>
+
+#endif // BOOST_ASIO_DETAIL_EPOLL_REACTOR_HPP
diff --git a/3rdParty/Boost/boost/asio/detail/epoll_reactor_fwd.hpp b/3rdParty/Boost/boost/asio/detail/epoll_reactor_fwd.hpp
new file mode 100644
index 0000000..567a966
--- /dev/null
+++ b/3rdParty/Boost/boost/asio/detail/epoll_reactor_fwd.hpp
@@ -0,0 +1,49 @@
+//
+// epoll_reactor_fwd.hpp
+// ~~~~~~~~~~~~~~~~~~~~~
+//
+// Copyright (c) 2003-2008 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 BOOST_ASIO_DETAIL_EPOLL_REACTOR_FWD_HPP
+#define BOOST_ASIO_DETAIL_EPOLL_REACTOR_FWD_HPP
+
+#if defined(_MSC_VER) && (_MSC_VER >= 1200)
+# pragma once
+#endif // defined(_MSC_VER) && (_MSC_VER >= 1200)
+
+#include <boost/asio/detail/push_options.hpp>
+
+#if !defined(BOOST_ASIO_DISABLE_EPOLL)
+#if defined(__linux__) // This service is only supported on Linux.
+
+#include <boost/asio/detail/push_options.hpp>
+#include <linux/version.h>
+#include <boost/asio/detail/pop_options.hpp>
+
+#if LINUX_VERSION_CODE >= KERNEL_VERSION (2,5,45) // Only kernels >= 2.5.45.
+
+// Define this to indicate that epoll is supported on the target platform.
+#define BOOST_ASIO_HAS_EPOLL 1
+
+namespace boost {
+namespace asio {
+namespace detail {
+
+template <bool Own_Thread>
+class epoll_reactor;
+
+} // namespace detail
+} // namespace asio
+} // namespace boost
+
+#endif // LINUX_VERSION_CODE >= KERNEL_VERSION (2,5,45)
+#endif // defined(__linux__)
+#endif // !defined(BOOST_ASIO_DISABLE_EPOLL)
+
+#include <boost/asio/detail/pop_options.hpp>
+
+#endif // BOOST_ASIO_DETAIL_EPOLL_REACTOR_FWD_HPP
diff --git a/3rdParty/Boost/boost/asio/detail/event.hpp b/3rdParty/Boost/boost/asio/detail/event.hpp
new file mode 100644
index 0000000..67a0118
--- /dev/null
+++ b/3rdParty/Boost/boost/asio/detail/event.hpp
@@ -0,0 +1,52 @@
+//
+// event.hpp
+// ~~~~~~~~~
+//
+// Copyright (c) 2003-2008 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 BOOST_ASIO_DETAIL_EVENT_HPP
+#define BOOST_ASIO_DETAIL_EVENT_HPP
+
+#if defined(_MSC_VER) && (_MSC_VER >= 1200)
+# pragma once
+#endif // defined(_MSC_VER) && (_MSC_VER >= 1200)
+
+#include <boost/asio/detail/push_options.hpp>
+
+#include <boost/asio/detail/push_options.hpp>
+#include <boost/config.hpp>
+#include <boost/asio/detail/pop_options.hpp>
+
+#if !defined(BOOST_HAS_THREADS)
+# include <boost/asio/detail/null_event.hpp>
+#elif defined(BOOST_WINDOWS)
+# include <boost/asio/detail/win_event.hpp>
+#elif defined(BOOST_HAS_PTHREADS)
+# include <boost/asio/detail/posix_event.hpp>
+#else
+# error Only Windows and POSIX are supported!
+#endif
+
+namespace boost {
+namespace asio {
+namespace detail {
+
+#if !defined(BOOST_HAS_THREADS)
+typedef null_event event;
+#elif defined(BOOST_WINDOWS)
+typedef win_event event;
+#elif defined(BOOST_HAS_PTHREADS)
+typedef posix_event event;
+#endif
+
+} // namespace detail
+} // namespace asio
+} // namespace boost
+
+#include <boost/asio/detail/pop_options.hpp>
+
+#endif // BOOST_ASIO_DETAIL_EVENT_HPP
diff --git a/3rdParty/Boost/boost/asio/detail/eventfd_select_interrupter.hpp b/3rdParty/Boost/boost/asio/detail/eventfd_select_interrupter.hpp
new file mode 100644
index 0000000..cac8405
--- /dev/null
+++ b/3rdParty/Boost/boost/asio/detail/eventfd_select_interrupter.hpp
@@ -0,0 +1,157 @@
+//
+// eventfd_select_interrupter.hpp
+// ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+//
+// Copyright (c) 2003-2008 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 BOOST_ASIO_DETAIL_EVENTFD_SELECT_INTERRUPTER_HPP
+#define BOOST_ASIO_DETAIL_EVENTFD_SELECT_INTERRUPTER_HPP
+
+#if defined(_MSC_VER) && (_MSC_VER >= 1200)
+# pragma once
+#endif // defined(_MSC_VER) && (_MSC_VER >= 1200)
+
+#include <boost/asio/detail/push_options.hpp>
+
+#include <boost/asio/detail/push_options.hpp>
+#include <boost/config.hpp>
+#include <boost/throw_exception.hpp>
+#include <boost/system/system_error.hpp>
+#include <boost/asio/detail/pop_options.hpp>
+
+#if defined(linux)
+# if !defined(BOOST_ASIO_DISABLE_EVENTFD)
+# include <linux/version.h>
+# if LINUX_VERSION_CODE >= KERNEL_VERSION(2,6,22)
+# define BOOST_ASIO_HAS_EVENTFD
+# endif // LINUX_VERSION_CODE >= KERNEL_VERSION(2,6,22)
+# endif // !defined(BOOST_ASIO_DISABLE_EVENTFD)
+#endif // defined(linux)
+
+#if defined(BOOST_ASIO_HAS_EVENTFD)
+
+#include <boost/asio/detail/push_options.hpp>
+#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 <boost/asio/detail/pop_options.hpp>
+
+#include <boost/asio/error.hpp>
+#include <boost/asio/detail/socket_types.hpp>
+
+namespace boost {
+namespace asio {
+namespace detail {
+
+class eventfd_select_interrupter
+{
+public:
+ // Constructor.
+ eventfd_select_interrupter()
+ {
+#if __GLIBC__ == 2 && __GLIBC_MINOR__ < 8
+ write_descriptor_ = read_descriptor_ = syscall(__NR_eventfd, 0);
+#else // __GLIBC__ == 2 && __GLIBC_MINOR__ < 8
+ write_descriptor_ = read_descriptor_ = ::eventfd(0, 0);
+#endif // __GLIBC__ == 2 && __GLIBC_MINOR__ < 8
+ if (read_descriptor_ != -1)
+ {
+ ::fcntl(read_descriptor_, F_SETFL, O_NONBLOCK);
+ }
+ else
+ {
+ 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);
+ }
+ else
+ {
+ boost::system::error_code ec(errno,
+ boost::asio::error::get_system_category());
+ boost::system::system_error e(ec, "eventfd_select_interrupter");
+ boost::throw_exception(e);
+ }
+ }
+ }
+
+ // Destructor.
+ ~eventfd_select_interrupter()
+ {
+ if (write_descriptor_ != -1 && write_descriptor_ != read_descriptor_)
+ ::close(write_descriptor_);
+ if (read_descriptor_ != -1)
+ ::close(read_descriptor_);
+ }
+
+ // Interrupt the select call.
+ void interrupt()
+ {
+ uint64_t counter(1UL);
+ int result = ::write(write_descriptor_, &counter, sizeof(uint64_t));
+ (void)result;
+ }
+
+ // Reset the select interrupt. Returns true if the call was interrupted.
+ bool reset()
+ {
+ if (write_descriptor_ == read_descriptor_)
+ {
+ // Only perform one read. The kernel maintains an atomic counter.
+ uint64_t counter(0);
+ int bytes_read = ::read(read_descriptor_, &counter, sizeof(uint64_t));
+ bool was_interrupted = (bytes_read > 0);
+ return was_interrupted;
+ }
+ else
+ {
+ // Clear all data from the pipe.
+ char data[1024];
+ int bytes_read = ::read(read_descriptor_, data, sizeof(data));
+ bool was_interrupted = (bytes_read > 0);
+ while (bytes_read == sizeof(data))
+ bytes_read = ::read(read_descriptor_, data, sizeof(data));
+ return was_interrupted;
+ }
+ }
+
+ // Get the read descriptor to be passed to select.
+ int read_descriptor() const
+ {
+ return read_descriptor_;
+ }
+
+private:
+ // 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
+} // namespace boost
+
+#endif // defined(BOOST_ASIO_HAS_EVENTFD)
+
+#include <boost/asio/detail/pop_options.hpp>
+
+#endif // BOOST_ASIO_DETAIL_EVENTFD_SELECT_INTERRUPTER_HPP
diff --git a/3rdParty/Boost/boost/asio/detail/fd_set_adapter.hpp b/3rdParty/Boost/boost/asio/detail/fd_set_adapter.hpp
new file mode 100644
index 0000000..3fff01e
--- /dev/null
+++ b/3rdParty/Boost/boost/asio/detail/fd_set_adapter.hpp
@@ -0,0 +1,43 @@
+//
+// fd_set_adapter.hpp
+// ~~~~~~~~~~~~~~~~~~
+//
+// Copyright (c) 2003-2008 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 BOOST_ASIO_DETAIL_FD_SET_ADAPTER_HPP
+#define BOOST_ASIO_DETAIL_FD_SET_ADAPTER_HPP
+
+#if defined(_MSC_VER) && (_MSC_VER >= 1200)
+# pragma once
+#endif // defined(_MSC_VER) && (_MSC_VER >= 1200)
+
+#include <boost/asio/detail/push_options.hpp>
+
+#include <boost/asio/detail/push_options.hpp>
+#include <boost/config.hpp>
+#include <boost/asio/detail/pop_options.hpp>
+
+#include <boost/asio/detail/posix_fd_set_adapter.hpp>
+#include <boost/asio/detail/win_fd_set_adapter.hpp>
+
+namespace boost {
+namespace asio {
+namespace detail {
+
+#if defined(BOOST_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
+} // namespace boost
+
+#include <boost/asio/detail/pop_options.hpp>
+
+#endif // BOOST_ASIO_DETAIL_FD_SET_ADAPTER_HPP
diff --git a/3rdParty/Boost/boost/asio/detail/handler_alloc_helpers.hpp b/3rdParty/Boost/boost/asio/detail/handler_alloc_helpers.hpp
new file mode 100644
index 0000000..bfc918b
--- /dev/null
+++ b/3rdParty/Boost/boost/asio/detail/handler_alloc_helpers.hpp
@@ -0,0 +1,258 @@
+//
+// handler_alloc_helpers.hpp
+// ~~~~~~~~~~~~~~~~~~~~~~~~~
+//
+// Copyright (c) 2003-2008 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 BOOST_ASIO_DETAIL_HANDLER_ALLOC_HELPERS_HPP
+#define BOOST_ASIO_DETAIL_HANDLER_ALLOC_HELPERS_HPP
+
+#if defined(_MSC_VER) && (_MSC_VER >= 1200)
+# pragma once
+#endif // defined(_MSC_VER) && (_MSC_VER >= 1200)
+
+#include <boost/asio/detail/push_options.hpp>
+
+#include <boost/asio/detail/push_options.hpp>
+#include <boost/detail/workaround.hpp>
+#include <boost/asio/detail/pop_options.hpp>
+
+#include <boost/asio/handler_alloc_hook.hpp>
+#include <boost/asio/detail/noncopyable.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
+// boost_asio_handler_alloc_helpers namespace is defined here for that purpose.
+namespace boost_asio_handler_alloc_helpers {
+
+template <typename Handler>
+inline void* allocate(std::size_t s, Handler* h)
+{
+#if BOOST_WORKAROUND(__BORLANDC__, BOOST_TESTED_AT(0x564))
+ return ::operator new(s);
+#else
+ using namespace boost::asio;
+ return asio_handler_allocate(s, h);
+#endif
+}
+
+template <typename Handler>
+inline void deallocate(void* p, std::size_t s, Handler* h)
+{
+#if BOOST_WORKAROUND(__BORLANDC__, BOOST_TESTED_AT(0x564))
+ ::operator delete(p);
+#else
+ using namespace boost::asio;
+ asio_handler_deallocate(p, s, h);
+#endif
+}
+
+} // namespace boost_asio_handler_alloc_helpers
+
+namespace boost {
+namespace asio {
+namespace detail {
+
+// Traits for handler allocation.
+template <typename Handler, typename Object>
+struct handler_alloc_traits
+{
+ typedef Handler handler_type;
+ typedef Object value_type;
+ typedef Object* pointer_type;
+ BOOST_STATIC_CONSTANT(std::size_t, value_size = sizeof(Object));
+};
+
+template <typename Alloc_Traits>
+class handler_ptr;
+
+// Helper class to provide RAII on uninitialised handler memory.
+template <typename Alloc_Traits>
+class raw_handler_ptr
+ : private noncopyable
+{
+public:
+ typedef typename Alloc_Traits::handler_type handler_type;
+ typedef typename Alloc_Traits::value_type value_type;
+ typedef typename Alloc_Traits::pointer_type pointer_type;
+ BOOST_STATIC_CONSTANT(std::size_t, value_size = Alloc_Traits::value_size);
+
+ // Constructor allocates the memory.
+ raw_handler_ptr(handler_type& handler)
+ : handler_(handler),
+ pointer_(static_cast<pointer_type>(
+ boost_asio_handler_alloc_helpers::allocate(value_size, &handler_)))
+ {
+ }
+
+ // Destructor automatically deallocates memory, unless it has been stolen by
+ // a handler_ptr object.
+ ~raw_handler_ptr()
+ {
+ if (pointer_)
+ boost_asio_handler_alloc_helpers::deallocate(
+ pointer_, value_size, &handler_);
+ }
+
+private:
+ friend class handler_ptr<Alloc_Traits>;
+ handler_type& handler_;
+ pointer_type pointer_;
+};
+
+// Helper class to provide RAII on uninitialised handler memory.
+template <typename Alloc_Traits>
+class handler_ptr
+ : private noncopyable
+{
+public:
+ typedef typename Alloc_Traits::handler_type handler_type;
+ typedef typename Alloc_Traits::value_type value_type;
+ typedef typename Alloc_Traits::pointer_type pointer_type;
+ BOOST_STATIC_CONSTANT(std::size_t, value_size = Alloc_Traits::value_size);
+ typedef raw_handler_ptr<Alloc_Traits> raw_ptr_type;
+
+ // Take ownership of existing memory.
+ handler_ptr(handler_type& handler, pointer_type pointer)
+ : handler_(handler),
+ pointer_(pointer)
+ {
+ }
+
+ // Construct object in raw memory and take ownership if construction succeeds.
+ handler_ptr(raw_ptr_type& raw_ptr)
+ : handler_(raw_ptr.handler_),
+ pointer_(new (raw_ptr.pointer_) value_type)
+ {
+ raw_ptr.pointer_ = 0;
+ }
+
+ // Construct object in raw memory and take ownership if construction succeeds.
+ template <typename Arg1>
+ handler_ptr(raw_ptr_type& raw_ptr, Arg1& a1)
+ : handler_(raw_ptr.handler_),
+ pointer_(new (raw_ptr.pointer_) value_type(a1))
+ {
+ raw_ptr.pointer_ = 0;
+ }
+
+ // Construct object in raw memory and take ownership if construction succeeds.
+ template <typename Arg1, typename Arg2>
+ handler_ptr(raw_ptr_type& raw_ptr, Arg1& a1, Arg2& a2)
+ : handler_(raw_ptr.handler_),
+ pointer_(new (raw_ptr.pointer_) value_type(a1, a2))
+ {
+ raw_ptr.pointer_ = 0;
+ }
+
+ // Construct object in raw memory and take ownership if construction succeeds.
+ template <typename Arg1, typename Arg2, typename Arg3>
+ handler_ptr(raw_ptr_type& raw_ptr, Arg1& a1, Arg2& a2, Arg3& a3)
+ : handler_(raw_ptr.handler_),
+ pointer_(new (raw_ptr.pointer_) value_type(a1, a2, a3))
+ {
+ raw_ptr.pointer_ = 0;
+ }
+
+ // Construct object in raw memory and take ownership if construction succeeds.
+ template <typename Arg1, typename Arg2, typename Arg3, typename Arg4>
+ handler_ptr(raw_ptr_type& raw_ptr, Arg1& a1, Arg2& a2, Arg3& a3, Arg4& a4)
+ : handler_(raw_ptr.handler_),
+ pointer_(new (raw_ptr.pointer_) value_type(a1, a2, a3, a4))
+ {
+ raw_ptr.pointer_ = 0;
+ }
+
+ // Construct object in raw memory and take ownership if construction succeeds.
+ template <typename Arg1, typename Arg2, typename Arg3, typename Arg4,
+ typename Arg5>
+ handler_ptr(raw_ptr_type& raw_ptr, Arg1& a1, Arg2& a2, Arg3& a3, Arg4& a4,
+ Arg5& a5)
+ : handler_(raw_ptr.handler_),
+ pointer_(new (raw_ptr.pointer_) value_type(a1, a2, a3, a4, a5))
+ {
+ raw_ptr.pointer_ = 0;
+ }
+
+ // Construct object in raw memory and take ownership if construction succeeds.
+ template <typename Arg1, typename Arg2, typename Arg3, typename Arg4,
+ typename Arg5, typename Arg6>
+ handler_ptr(raw_ptr_type& raw_ptr, Arg1& a1, Arg2& a2, Arg3& a3, Arg4& a4,
+ Arg5& a5, Arg6& a6)
+ : handler_(raw_ptr.handler_),
+ pointer_(new (raw_ptr.pointer_) value_type(a1, a2, a3, a4, a5, a6))
+ {
+ raw_ptr.pointer_ = 0;
+ }
+
+ // Construct object in raw memory and take ownership if construction succeeds.
+ template <typename Arg1, typename Arg2, typename Arg3, typename Arg4,
+ typename Arg5, typename Arg6, typename Arg7>
+ handler_ptr(raw_ptr_type& raw_ptr, Arg1& a1, Arg2& a2, Arg3& a3, Arg4& a4,
+ Arg5& a5, Arg6& a6, Arg7& a7)
+ : handler_(raw_ptr.handler_),
+ pointer_(new (raw_ptr.pointer_) value_type(a1, a2, a3, a4, a5, a6, a7))
+ {
+ raw_ptr.pointer_ = 0;
+ }
+
+ // Construct object in raw memory and take ownership if construction succeeds.
+ template <typename Arg1, typename Arg2, typename Arg3, typename Arg4,
+ typename Arg5, typename Arg6, typename Arg7, typename Arg8>
+ handler_ptr(raw_ptr_type& raw_ptr, Arg1& a1, Arg2& a2, Arg3& a3, Arg4& a4,
+ Arg5& a5, Arg6& a6, Arg7& a7, Arg8& a8)
+ : handler_(raw_ptr.handler_),
+ pointer_(new (raw_ptr.pointer_) value_type(
+ a1, a2, a3, a4, a5, a6, a7, a8))
+ {
+ raw_ptr.pointer_ = 0;
+ }
+
+ // Destructor automatically deallocates memory, unless it has been released.
+ ~handler_ptr()
+ {
+ reset();
+ }
+
+ // Get the memory.
+ pointer_type get() const
+ {
+ return pointer_;
+ }
+
+ // Release ownership of the memory.
+ pointer_type release()
+ {
+ pointer_type tmp = pointer_;
+ pointer_ = 0;
+ return tmp;
+ }
+
+ // Explicitly destroy and deallocate the memory.
+ void reset()
+ {
+ if (pointer_)
+ {
+ pointer_->value_type::~value_type();
+ boost_asio_handler_alloc_helpers::deallocate(
+ pointer_, value_size, &handler_);
+ pointer_ = 0;
+ }
+ }
+
+private:
+ handler_type& handler_;
+ pointer_type pointer_;
+};
+
+} // namespace detail
+} // namespace asio
+} // namespace boost
+
+#include <boost/asio/detail/pop_options.hpp>
+
+#endif // BOOST_ASIO_DETAIL_HANDLER_ALLOC_HELPERS_HPP
diff --git a/3rdParty/Boost/boost/asio/detail/handler_base_from_member.hpp b/3rdParty/Boost/boost/asio/detail/handler_base_from_member.hpp
new file mode 100644
index 0000000..4bd95ed
--- /dev/null
+++ b/3rdParty/Boost/boost/asio/detail/handler_base_from_member.hpp
@@ -0,0 +1,78 @@
+//
+// handler_base_from_member.hpp
+// ~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+//
+// Copyright (c) 2003-2008 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 BOOST_ASIO_DETAIL_HANDLER_BASE_FROM_MEMBER_HPP
+#define BOOST_ASIO_DETAIL_HANDLER_BASE_FROM_MEMBER_HPP
+
+#if defined(_MSC_VER) && (_MSC_VER >= 1200)
+# pragma once
+#endif // defined(_MSC_VER) && (_MSC_VER >= 1200)
+
+#include <boost/asio/detail/push_options.hpp>
+
+#include <boost/asio/detail/handler_alloc_helpers.hpp>
+#include <boost/asio/detail/handler_invoke_helpers.hpp>
+
+namespace boost {
+namespace asio {
+namespace detail {
+
+// Base class for classes that need a handler data member. Forwards the custom
+// allocation and invocation hooks to the contained handler.
+template <typename Handler>
+class handler_base_from_member
+{
+public:
+ handler_base_from_member(Handler handler)
+ : handler_(handler)
+ {
+ }
+
+//protected:
+ Handler handler_;
+
+protected:
+ // Protected destructor to prevent deletion through this type.
+ ~handler_base_from_member()
+ {
+ }
+};
+
+template <typename Handler>
+inline void* asio_handler_allocate(std::size_t size,
+ handler_base_from_member<Handler>* this_handler)
+{
+ return boost_asio_handler_alloc_helpers::allocate(
+ size, &this_handler->handler_);
+}
+
+template <typename Handler>
+inline void asio_handler_deallocate(void* pointer, std::size_t size,
+ handler_base_from_member<Handler>* this_handler)
+{
+ boost_asio_handler_alloc_helpers::deallocate(
+ pointer, size, &this_handler->handler_);
+}
+
+template <typename Function, typename Handler>
+inline void asio_handler_invoke(const Function& function,
+ handler_base_from_member<Handler>* this_handler)
+{
+ boost_asio_handler_invoke_helpers::invoke(
+ function, &this_handler->handler_);
+}
+
+} // namespace detail
+} // namespace asio
+} // namespace boost
+
+#include <boost/asio/detail/pop_options.hpp>
+
+#endif // BOOST_ASIO_DETAIL_HANDLER_BASE_FROM_MEMBER_HPP
diff --git a/3rdParty/Boost/boost/asio/detail/handler_invoke_helpers.hpp b/3rdParty/Boost/boost/asio/detail/handler_invoke_helpers.hpp
new file mode 100644
index 0000000..4da384a
--- /dev/null
+++ b/3rdParty/Boost/boost/asio/detail/handler_invoke_helpers.hpp
@@ -0,0 +1,47 @@
+//
+// handler_invoke_helpers.hpp
+// ~~~~~~~~~~~~~~~~~~~~~~~~~~
+//
+// Copyright (c) 2003-2008 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 BOOST_ASIO_DETAIL_HANDLER_INVOKE_HELPERS_HPP
+#define BOOST_ASIO_DETAIL_HANDLER_INVOKE_HELPERS_HPP
+
+#if defined(_MSC_VER) && (_MSC_VER >= 1200)
+# pragma once
+#endif // defined(_MSC_VER) && (_MSC_VER >= 1200)
+
+#include <boost/asio/detail/push_options.hpp>
+
+#include <boost/asio/detail/push_options.hpp>
+#include <boost/detail/workaround.hpp>
+#include <boost/asio/detail/pop_options.hpp>
+
+#include <boost/asio/handler_invoke_hook.hpp>
+
+// Calls to asio_handler_invoke must be made from a namespace that does not
+// contain overloads of this function. The boost_asio_handler_invoke_helpers
+// namespace is defined here for that purpose.
+namespace boost_asio_handler_invoke_helpers {
+
+template <typename Function, typename Context>
+inline void invoke(const Function& function, Context* context)
+{
+#if BOOST_WORKAROUND(__BORLANDC__, BOOST_TESTED_AT(0x564))
+ Function tmp(function);
+ tmp();
+#else
+ using namespace boost::asio;
+ asio_handler_invoke(function, context);
+#endif
+}
+
+} // namespace boost_asio_handler_invoke_helpers
+
+#include <boost/asio/detail/pop_options.hpp>
+
+#endif // BOOST_ASIO_DETAIL_HANDLER_INVOKE_HELPERS_HPP
diff --git a/3rdParty/Boost/boost/asio/detail/handler_queue.hpp b/3rdParty/Boost/boost/asio/detail/handler_queue.hpp
new file mode 100644
index 0000000..ccc1b0c
--- /dev/null
+++ b/3rdParty/Boost/boost/asio/detail/handler_queue.hpp
@@ -0,0 +1,231 @@
+//
+// handler_queue.hpp
+// ~~~~~~~~~~~~~~~~~
+//
+// Copyright (c) 2003-2008 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 BOOST_ASIO_DETAIL_HANDLER_QUEUE_HPP
+#define BOOST_ASIO_DETAIL_HANDLER_QUEUE_HPP
+
+#if defined(_MSC_VER) && (_MSC_VER >= 1200)
+# pragma once
+#endif // defined(_MSC_VER) && (_MSC_VER >= 1200)
+
+#include <boost/asio/detail/push_options.hpp>
+
+#include <boost/asio/detail/handler_alloc_helpers.hpp>
+#include <boost/asio/detail/handler_invoke_helpers.hpp>
+#include <boost/asio/detail/noncopyable.hpp>
+
+namespace boost {
+namespace asio {
+namespace detail {
+
+class handler_queue
+ : private noncopyable
+{
+public:
+ // Base class for handlers in the queue.
+ class handler
+ : private noncopyable
+ {
+ public:
+ void invoke()
+ {
+ invoke_func_(this);
+ }
+
+ void destroy()
+ {
+ destroy_func_(this);
+ }
+
+ protected:
+ typedef void (*invoke_func_type)(handler*);
+ typedef void (*destroy_func_type)(handler*);
+
+ handler(invoke_func_type invoke_func,
+ destroy_func_type destroy_func)
+ : next_(0),
+ invoke_func_(invoke_func),
+ destroy_func_(destroy_func)
+ {
+ }
+
+ ~handler()
+ {
+ }
+
+ private:
+ friend class handler_queue;
+ handler* next_;
+ invoke_func_type invoke_func_;
+ destroy_func_type destroy_func_;
+ };
+
+ // Smart point to manager handler lifetimes.
+ class scoped_ptr
+ : private noncopyable
+ {
+ public:
+ explicit scoped_ptr(handler* h)
+ : handler_(h)
+ {
+ }
+
+ ~scoped_ptr()
+ {
+ if (handler_)
+ handler_->destroy();
+ }
+
+ handler* get() const
+ {
+ return handler_;
+ }
+
+ handler* release()
+ {
+ handler* tmp = handler_;
+ handler_ = 0;
+ return tmp;
+ }
+
+ private:
+ handler* handler_;
+ };
+
+ // Constructor.
+ handler_queue()
+ : front_(0),
+ back_(0)
+ {
+ }
+
+ // Wrap a handler to be pushed into the queue.
+ template <typename Handler>
+ static handler* wrap(Handler h)
+ {
+ // Allocate and construct an object to wrap the handler.
+ typedef handler_wrapper<Handler> value_type;
+ typedef handler_alloc_traits<Handler, value_type> alloc_traits;
+ raw_handler_ptr<alloc_traits> raw_ptr(h);
+ handler_ptr<alloc_traits> ptr(raw_ptr, h);
+ return ptr.release();
+ }
+
+ // Get the handler at the front of the queue.
+ handler* front()
+ {
+ return front_;
+ }
+
+ // Pop a handler from the front of the queue.
+ void pop()
+ {
+ if (front_)
+ {
+ handler* tmp = front_;
+ front_ = front_->next_;
+ if (front_ == 0)
+ back_ = 0;
+ tmp->next_= 0;
+ }
+ }
+
+ // Push a handler on to the back of the queue.
+ void push(handler* h)
+ {
+ h->next_ = 0;
+ if (back_)
+ {
+ back_->next_ = h;
+ back_ = h;
+ }
+ else
+ {
+ front_ = back_ = h;
+ }
+ }
+
+ // Whether the queue is empty.
+ bool empty() const
+ {
+ return front_ == 0;
+ }
+
+private:
+ // Template wrapper for handlers.
+ template <typename Handler>
+ class handler_wrapper
+ : public handler
+ {
+ public:
+ handler_wrapper(Handler h)
+ : handler(
+ &handler_wrapper<Handler>::do_call,
+ &handler_wrapper<Handler>::do_destroy),
+ handler_(h)
+ {
+ }
+
+ static void do_call(handler* base)
+ {
+ // Take ownership of the handler object.
+ typedef handler_wrapper<Handler> this_type;
+ this_type* h(static_cast<this_type*>(base));
+ typedef handler_alloc_traits<Handler, this_type> alloc_traits;
+ handler_ptr<alloc_traits> ptr(h->handler_, h);
+
+ // Make a copy of the handler so that the memory can be deallocated before
+ // the upcall is made.
+ Handler handler(h->handler_);
+
+ // Free the memory associated with the handler.
+ ptr.reset();
+
+ // Make the upcall.
+ boost_asio_handler_invoke_helpers::invoke(handler, &handler);
+ }
+
+ static void do_destroy(handler* base)
+ {
+ // Take ownership of the handler object.
+ typedef handler_wrapper<Handler> this_type;
+ this_type* h(static_cast<this_type*>(base));
+ typedef handler_alloc_traits<Handler, this_type> alloc_traits;
+ handler_ptr<alloc_traits> ptr(h->handler_, h);
+
+ // 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(h->handler_);
+ (void)handler;
+
+ // Free the memory associated with the handler.
+ ptr.reset();
+ }
+
+ private:
+ Handler handler_;
+ };
+
+ // The front of the queue.
+ handler* front_;
+
+ // The back of the queue.
+ handler* back_;
+};
+
+} // namespace detail
+} // namespace asio
+} // namespace boost
+
+#include <boost/asio/detail/pop_options.hpp>
+
+#endif // BOOST_ASIO_DETAIL_HANDLER_QUEUE_HPP
diff --git a/3rdParty/Boost/boost/asio/detail/hash_map.hpp b/3rdParty/Boost/boost/asio/detail/hash_map.hpp
new file mode 100644
index 0000000..923ae57
--- /dev/null
+++ b/3rdParty/Boost/boost/asio/detail/hash_map.hpp
@@ -0,0 +1,292 @@
+//
+// hash_map.hpp
+// ~~~~~~~~~~~~
+//
+// Copyright (c) 2003-2008 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 BOOST_ASIO_DETAIL_HASH_MAP_HPP
+#define BOOST_ASIO_DETAIL_HASH_MAP_HPP
+
+#if defined(_MSC_VER) && (_MSC_VER >= 1200)
+# pragma once
+#endif // defined(_MSC_VER) && (_MSC_VER >= 1200)
+
+#include <boost/asio/detail/push_options.hpp>
+
+#include <boost/asio/detail/push_options.hpp>
+#include <cassert>
+#include <list>
+#include <utility>
+#include <vector>
+#include <boost/functional/hash.hpp>
+#include <boost/asio/detail/pop_options.hpp>
+
+#include <boost/asio/detail/noncopyable.hpp>
+#include <boost/asio/detail/socket_types.hpp>
+
+namespace boost {
+namespace asio {
+namespace detail {
+
+template <typename T>
+inline std::size_t calculate_hash_value(const T& t)
+{
+ return boost::hash_value(t);
+}
+
+#if defined(_WIN64)
+inline std::size_t calculate_hash_value(SOCKET s)
+{
+ return static_cast<std::size_t>(s);
+}
+#endif // defined(_WIN64)
+
+// 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)
+ {
+ rehash(hash_size(0));
+ }
+
+ // 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)
+ {
+ size_t bucket = calculate_hash_value(k) % buckets_.size();
+ iterator it = buckets_[bucket].first;
+ if (it == values_.end())
+ return values_.end();
+ iterator end = buckets_[bucket].last;
+ ++end;
+ while (it != end)
+ {
+ if (it->first == k)
+ return it;
+ ++it;
+ }
+ return values_.end();
+ }
+
+ // Find an entry in the map.
+ const_iterator find(const K& k) const
+ {
+ size_t bucket = calculate_hash_value(k) % buckets_.size();
+ const_iterator it = buckets_[bucket].first;
+ if (it == values_.end())
+ return it;
+ const_iterator end = buckets_[bucket].last;
+ ++end;
+ while (it != end)
+ {
+ 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 >= buckets_.size())
+ rehash(hash_size(size_ + 1));
+ size_t bucket = calculate_hash_value(v.first) % buckets_.size();
+ 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 = buckets_[bucket].last;
+ ++end;
+ while (it != end)
+ {
+ if (it->first == v.first)
+ return std::pair<iterator, bool>(it, false);
+ ++it;
+ }
+ buckets_[bucket].last = values_insert(end, v);
+ ++size_;
+ return std::pair<iterator, bool>(buckets_[bucket].last, true);
+ }
+
+ // Erase an entry from the map.
+ void erase(iterator it)
+ {
+ assert(it != values_.end());
+
+ size_t bucket = calculate_hash_value(it->first) % buckets_.size();
+ 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_;
+ }
+
+ // Remove all entries from the map.
+ void clear()
+ {
+ // Clear the values.
+ values_.clear();
+ size_ = 0;
+
+ // Initialise all buckets to empty.
+ for (size_t i = 0; i < buckets_.size(); ++i)
+ buckets_[i].first = buckets_[i].last = values_.end();
+ }
+
+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(BOOST_ASIO_HASH_MAP_BUCKETS)
+ BOOST_ASIO_HASH_MAP_BUCKETS
+#else // BOOST_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 // BOOST_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)
+ {
+ iterator end = values_.end();
+
+ // Update number of buckets and initialise all buckets to empty.
+ buckets_.resize(num_buckets);
+ for (std::size_t i = 0; i < buckets_.size(); ++i)
+ buckets_[i].first = buckets_[i].last = end;
+
+ // Put all values back into the hash.
+ iterator iter = values_.begin();
+ while (iter != end)
+ {
+ std::size_t bucket = calculate_hash_value(iter->first) % buckets_.size();
+ if (buckets_[bucket].last == end)
+ {
+ buckets_[bucket].first = buckets_[bucket].last = 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.
+ std::vector<bucket_type> buckets_;
+};
+
+} // namespace detail
+} // namespace asio
+} // namespace boost
+
+#include <boost/asio/detail/pop_options.hpp>
+
+#endif // BOOST_ASIO_DETAIL_HASH_MAP_HPP
diff --git a/3rdParty/Boost/boost/asio/detail/indirect_handler_queue.hpp b/3rdParty/Boost/boost/asio/detail/indirect_handler_queue.hpp
new file mode 100644
index 0000000..2775078
--- /dev/null
+++ b/3rdParty/Boost/boost/asio/detail/indirect_handler_queue.hpp
@@ -0,0 +1,293 @@
+//
+// indirect_handler_queue.hpp
+// ~~~~~~~~~~~~~~~~~~~~~~~~~~
+//
+// Copyright (c) 2003-2008 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 BOOST_ASIO_DETAIL_INDIRECT_HANDLER_QUEUE_HPP
+#define BOOST_ASIO_DETAIL_INDIRECT_HANDLER_QUEUE_HPP
+
+#if defined(_MSC_VER) && (_MSC_VER >= 1200)
+# pragma once
+#endif // defined(_MSC_VER) && (_MSC_VER >= 1200)
+
+#include <boost/asio/detail/push_options.hpp>
+
+#include <boost/asio/detail/handler_alloc_helpers.hpp>
+#include <boost/asio/detail/handler_invoke_helpers.hpp>
+#include <boost/asio/detail/noncopyable.hpp>
+
+#if defined(_MSC_VER) && (_MSC_VER >= 1310)
+extern "C" void _ReadWriteBarrier();
+# pragma intrinsic(_ReadWriteBarrier)
+#endif // defined(_MSC_VER) && (_MSC_VER >= 1310)
+
+namespace boost {
+namespace asio {
+namespace detail {
+
+class indirect_handler_queue
+ : private noncopyable
+{
+public:
+ class handler;
+
+ // Element for a node in the queue.
+ class node
+ {
+ public:
+ node()
+ : version_(0),
+ handler_(0),
+ next_(0)
+ {
+ }
+
+ private:
+ friend class indirect_handler_queue;
+ unsigned long version_;
+ handler* handler_;
+ node* next_;
+ };
+
+ // Base class for handlers in the queue.
+ class handler
+ : private noncopyable
+ {
+ public:
+ void invoke()
+ {
+ invoke_func_(this);
+ }
+
+ void destroy()
+ {
+ destroy_func_(this);
+ }
+
+ protected:
+ typedef void (*invoke_func_type)(handler*);
+ typedef void (*destroy_func_type)(handler*);
+
+ handler(invoke_func_type invoke_func,
+ destroy_func_type destroy_func)
+ : node_(new node),
+ invoke_func_(invoke_func),
+ destroy_func_(destroy_func)
+ {
+ }
+
+ ~handler()
+ {
+ if (node_)
+ delete node_;
+ }
+
+ private:
+ friend class indirect_handler_queue;
+ node* node_;
+ invoke_func_type invoke_func_;
+ destroy_func_type destroy_func_;
+ };
+
+ // Smart point to manager handler lifetimes.
+ class scoped_ptr
+ : private noncopyable
+ {
+ public:
+ explicit scoped_ptr(handler* h)
+ : handler_(h)
+ {
+ }
+
+ ~scoped_ptr()
+ {
+ if (handler_)
+ handler_->destroy();
+ }
+
+ handler* get() const
+ {
+ return handler_;
+ }
+
+ handler* release()
+ {
+ handler* tmp = handler_;
+ handler_ = 0;
+ return tmp;
+ }
+
+ private:
+ handler* handler_;
+ };
+
+ // Constructor.
+ indirect_handler_queue()
+ : front_(new node),
+ back_(front_),
+ next_version_(1)
+ {
+ }
+
+ // Destructor.
+ ~indirect_handler_queue()
+ {
+ while (front_)
+ {
+ node* tmp = front_;
+ front_ = front_->next_;
+ delete tmp;
+ }
+ }
+
+ // Wrap a handler to be pushed into the queue.
+ template <typename Handler>
+ static handler* wrap(Handler h)
+ {
+ // Allocate and construct an object to wrap the handler.
+ typedef handler_wrapper<Handler> value_type;
+ typedef handler_alloc_traits<Handler, value_type> alloc_traits;
+ raw_handler_ptr<alloc_traits> raw_ptr(h);
+ handler_ptr<alloc_traits> ptr(raw_ptr, h);
+ return ptr.release();
+ }
+
+ // Determine whether the queue has something ready to pop.
+ bool poppable()
+ {
+ return front_->next_ != 0;
+ }
+
+ // The version number at the front of the queue.
+ unsigned long front_version()
+ {
+ return front_->version_;
+ }
+
+ // The version number at the back of the queue.
+ unsigned long back_version()
+ {
+ return back_->version_;
+ }
+
+ // Pop a handler from the front of the queue.
+ handler* pop()
+ {
+ node* n = front_;
+ node* new_front = n->next_;
+ if (new_front)
+ {
+ handler* h = new_front->handler_;
+ h->node_ = n;
+ new_front->handler_ = 0;
+ front_ = new_front;
+ return h;
+ }
+ return 0;
+ }
+
+ // Push a handler on to the back of the queue.
+ void push(handler* h)
+ {
+ node* n = h->node_;
+ h->node_ = 0;
+ n->version_ = next_version_;
+ next_version_ += 2;
+ n->handler_ = h;
+ n->next_ = 0;
+ memory_barrier();
+ back_->next_ = n;
+ back_ = n;
+ }
+
+private:
+ // Template wrapper for handlers.
+ template <typename Handler>
+ class handler_wrapper
+ : public handler
+ {
+ public:
+ handler_wrapper(Handler h)
+ : handler(
+ &handler_wrapper<Handler>::do_call,
+ &handler_wrapper<Handler>::do_destroy),
+ handler_(h)
+ {
+ }
+
+ static void do_call(handler* base)
+ {
+ // Take ownership of the handler object.
+ typedef handler_wrapper<Handler> this_type;
+ this_type* h(static_cast<this_type*>(base));
+ typedef handler_alloc_traits<Handler, this_type> alloc_traits;
+ handler_ptr<alloc_traits> ptr(h->handler_, h);
+
+ // Make a copy of the handler so that the memory can be deallocated before
+ // the upcall is made.
+ Handler handler(h->handler_);
+
+ // Free the memory associated with the handler.
+ ptr.reset();
+
+ // Make the upcall.
+ boost_asio_handler_invoke_helpers::invoke(handler, &handler);
+ }
+
+ static void do_destroy(handler* base)
+ {
+ // Take ownership of the handler object.
+ typedef handler_wrapper<Handler> this_type;
+ this_type* h(static_cast<this_type*>(base));
+ typedef handler_alloc_traits<Handler, this_type> alloc_traits;
+ handler_ptr<alloc_traits> ptr(h->handler_, h);
+
+ // 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(h->handler_);
+ (void)handler;
+
+ // Free the memory associated with the handler.
+ ptr.reset();
+ }
+
+ private:
+ Handler handler_;
+ };
+
+ // Helper function to create a memory barrier.
+ static void memory_barrier()
+ {
+#if defined(_GLIBCXX_WRITE_MEM_BARRIER)
+ _GLIBCXX_WRITE_MEM_BARRIER;
+#elif defined(_MSC_VER) && (_MSC_VER >= 1310)
+ _ReadWriteBarrier();
+#else
+# error memory barrier required
+#endif
+ }
+
+ // The front of the queue.
+ node* front_;
+
+ // The back of the queue.
+ node* back_;
+
+ // The next version counter to be assigned to a node.
+ unsigned long next_version_;
+};
+
+} // namespace detail
+} // namespace asio
+} // namespace boost
+
+#include <boost/asio/detail/pop_options.hpp>
+
+#endif // BOOST_ASIO_DETAIL_INDIRECT_HANDLER_QUEUE_HPP
diff --git a/3rdParty/Boost/boost/asio/detail/io_control.hpp b/3rdParty/Boost/boost/asio/detail/io_control.hpp
new file mode 100644
index 0000000..6730dc3
--- /dev/null
+++ b/3rdParty/Boost/boost/asio/detail/io_control.hpp
@@ -0,0 +1,139 @@
+//
+// io_control.hpp
+// ~~~~~~~~~~~~~~
+//
+// Copyright (c) 2003-2008 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 BOOST_ASIO_DETAIL_IO_CONTROL_HPP
+#define BOOST_ASIO_DETAIL_IO_CONTROL_HPP
+
+#if defined(_MSC_VER) && (_MSC_VER >= 1200)
+# pragma once
+#endif // defined(_MSC_VER) && (_MSC_VER >= 1200)
+
+#include <boost/asio/detail/push_options.hpp>
+
+#include <boost/asio/detail/push_options.hpp>
+#include <cstddef>
+#include <boost/config.hpp>
+#include <boost/asio/detail/pop_options.hpp>
+
+#include <boost/asio/detail/socket_types.hpp>
+
+namespace boost {
+namespace asio {
+namespace detail {
+namespace io_control {
+
+// IO control command for non-blocking I/O.
+class non_blocking_io
+{
+public:
+ // Default constructor.
+ non_blocking_io()
+ : value_(0)
+ {
+ }
+
+ // Construct with a specific command value.
+ non_blocking_io(bool value)
+ : value_(value ? 1 : 0)
+ {
+ }
+
+ // Get the name of the IO control command.
+ int name() const
+ {
+ return FIONBIO;
+ }
+
+ // Set the value of the I/O control command.
+ void set(bool value)
+ {
+ value_ = value ? 1 : 0;
+ }
+
+ // Get the current value of the I/O control command.
+ bool get() const
+ {
+ return value_ != 0;
+ }
+
+ // 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_;
+};
+
+// 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 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
+} // namespace boost
+
+#include <boost/asio/detail/pop_options.hpp>
+
+#endif // BOOST_ASIO_DETAIL_IO_CONTROL_HPP
diff --git a/3rdParty/Boost/boost/asio/detail/kqueue_reactor.hpp b/3rdParty/Boost/boost/asio/detail/kqueue_reactor.hpp
new file mode 100644
index 0000000..179b7d4
--- /dev/null
+++ b/3rdParty/Boost/boost/asio/detail/kqueue_reactor.hpp
@@ -0,0 +1,714 @@
+//
+// kqueue_reactor.hpp
+// ~~~~~~~~~~~~~~~~~~
+//
+// Copyright (c) 2003-2008 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 BOOST_ASIO_DETAIL_KQUEUE_REACTOR_HPP
+#define BOOST_ASIO_DETAIL_KQUEUE_REACTOR_HPP
+
+#if defined(_MSC_VER) && (_MSC_VER >= 1200)
+# pragma once
+#endif // defined(_MSC_VER) && (_MSC_VER >= 1200)
+
+#include <boost/asio/detail/push_options.hpp>
+
+#include <boost/asio/detail/kqueue_reactor_fwd.hpp>
+
+#if defined(BOOST_ASIO_HAS_KQUEUE)
+
+#include <boost/asio/detail/push_options.hpp>
+#include <cstddef>
+#include <vector>
+#include <sys/types.h>
+#include <sys/event.h>
+#include <sys/time.h>
+#include <boost/config.hpp>
+#include <boost/date_time/posix_time/posix_time_types.hpp>
+#include <boost/throw_exception.hpp>
+#include <boost/system/system_error.hpp>
+#include <boost/asio/detail/pop_options.hpp>
+
+#include <boost/asio/error.hpp>
+#include <boost/asio/io_service.hpp>
+#include <boost/asio/detail/bind_handler.hpp>
+#include <boost/asio/detail/mutex.hpp>
+#include <boost/asio/detail/task_io_service.hpp>
+#include <boost/asio/detail/thread.hpp>
+#include <boost/asio/detail/reactor_op_queue.hpp>
+#include <boost/asio/detail/select_interrupter.hpp>
+#include <boost/asio/detail/service_base.hpp>
+#include <boost/asio/detail/signal_blocker.hpp>
+#include <boost/asio/detail/socket_types.hpp>
+#include <boost/asio/detail/timer_queue.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)
+
+namespace boost {
+namespace asio {
+namespace detail {
+
+template <bool Own_Thread>
+class kqueue_reactor
+ : public boost::asio::detail::service_base<kqueue_reactor<Own_Thread> >
+{
+public:
+ // Per-descriptor data.
+ struct per_descriptor_data
+ {
+ bool allow_speculative_read;
+ bool allow_speculative_write;
+ };
+
+ // Constructor.
+ kqueue_reactor(boost::asio::io_service& io_service)
+ : boost::asio::detail::service_base<
+ kqueue_reactor<Own_Thread> >(io_service),
+ mutex_(),
+ kqueue_fd_(do_kqueue_create()),
+ wait_in_progress_(false),
+ interrupter_(),
+ read_op_queue_(),
+ write_op_queue_(),
+ except_op_queue_(),
+ pending_cancellations_(),
+ stop_thread_(false),
+ thread_(0),
+ shutdown_(false),
+ need_kqueue_wait_(true)
+ {
+ // Start the reactor's internal thread only if needed.
+ if (Own_Thread)
+ {
+ boost::asio::detail::signal_blocker sb;
+ thread_ = new boost::asio::detail::thread(
+ bind_handler(&kqueue_reactor::call_run_thread, this));
+ }
+
+ // Add the interrupter's descriptor to the kqueue.
+ struct kevent event;
+ EV_SET(&event, interrupter_.read_descriptor(),
+ EVFILT_READ, EV_ADD, 0, 0, 0);
+ ::kevent(kqueue_fd_, &event, 1, 0, 0, 0);
+ }
+
+ // Destructor.
+ ~kqueue_reactor()
+ {
+ shutdown_service();
+ close(kqueue_fd_);
+ }
+
+ // Destroy all user-defined handler objects owned by the service.
+ void shutdown_service()
+ {
+ boost::asio::detail::mutex::scoped_lock lock(mutex_);
+ shutdown_ = true;
+ stop_thread_ = true;
+ lock.unlock();
+
+ if (thread_)
+ {
+ interrupter_.interrupt();
+ thread_->join();
+ delete thread_;
+ thread_ = 0;
+ }
+
+ read_op_queue_.destroy_operations();
+ write_op_queue_.destroy_operations();
+ except_op_queue_.destroy_operations();
+
+ for (std::size_t i = 0; i < timer_queues_.size(); ++i)
+ timer_queues_[i]->destroy_timers();
+ timer_queues_.clear();
+ }
+
+ // Initialise the task, but only if the reactor is not in its own thread.
+ void init_task()
+ {
+ if (!Own_Thread)
+ {
+ typedef task_io_service<kqueue_reactor<Own_Thread> > task_io_service_type;
+ use_service<task_io_service_type>(this->get_io_service()).init_task();
+ }
+ }
+
+ // Register a socket with the reactor. Returns 0 on success, system error
+ // code on failure.
+ int register_descriptor(socket_type, per_descriptor_data& descriptor_data)
+ {
+ descriptor_data.allow_speculative_read = true;
+ descriptor_data.allow_speculative_write = true;
+
+ return 0;
+ }
+
+ // Start a new read operation. The handler object will be invoked when the
+ // given descriptor is ready to be read, or an error has occurred.
+ template <typename Handler>
+ void start_read_op(socket_type descriptor,
+ per_descriptor_data& descriptor_data, Handler handler,
+ bool allow_speculative_read = true)
+ {
+ if (allow_speculative_read && descriptor_data.allow_speculative_read)
+ {
+ boost::system::error_code ec;
+ std::size_t bytes_transferred = 0;
+ if (handler.perform(ec, bytes_transferred))
+ {
+ handler.complete(ec, bytes_transferred);
+ return;
+ }
+
+ // We only get one shot at a speculative read in this function.
+ allow_speculative_read = false;
+ }
+
+ boost::asio::detail::mutex::scoped_lock lock(mutex_);
+
+ if (shutdown_)
+ return;
+
+ if (!allow_speculative_read)
+ need_kqueue_wait_ = true;
+ else if (!read_op_queue_.has_operation(descriptor))
+ {
+ // Speculative reads are ok as there are no queued read operations.
+ descriptor_data.allow_speculative_read = true;
+
+ boost::system::error_code ec;
+ std::size_t bytes_transferred = 0;
+ if (handler.perform(ec, bytes_transferred))
+ {
+ handler.complete(ec, bytes_transferred);
+ return;
+ }
+ }
+
+ // Speculative reads are not ok as there will be queued read operations.
+ descriptor_data.allow_speculative_read = false;
+
+ if (read_op_queue_.enqueue_operation(descriptor, handler))
+ {
+ struct kevent event;
+ EV_SET(&event, descriptor, EVFILT_READ, EV_ADD, 0, 0, 0);
+ if (::kevent(kqueue_fd_, &event, 1, 0, 0, 0) == -1)
+ {
+ boost::system::error_code ec(errno,
+ boost::asio::error::get_system_category());
+ read_op_queue_.perform_all_operations(descriptor, ec);
+ }
+ }
+ }
+
+ // Start a new write operation. The handler object will be invoked when the
+ // given descriptor is ready to be written, or an error has occurred.
+ template <typename Handler>
+ void start_write_op(socket_type descriptor,
+ per_descriptor_data& descriptor_data, Handler handler,
+ bool allow_speculative_write = true)
+ {
+ if (allow_speculative_write && descriptor_data.allow_speculative_write)
+ {
+ boost::system::error_code ec;
+ std::size_t bytes_transferred = 0;
+ if (handler.perform(ec, bytes_transferred))
+ {
+ handler.complete(ec, bytes_transferred);
+ return;
+ }
+
+ // We only get one shot at a speculative write in this function.
+ allow_speculative_write = false;
+ }
+
+ boost::asio::detail::mutex::scoped_lock lock(mutex_);
+
+ if (shutdown_)
+ return;
+
+ if (!allow_speculative_write)
+ need_kqueue_wait_ = true;
+ else if (!write_op_queue_.has_operation(descriptor))
+ {
+ // Speculative writes are ok as there are no queued write operations.
+ descriptor_data.allow_speculative_write = true;
+
+ boost::system::error_code ec;
+ std::size_t bytes_transferred = 0;
+ if (handler.perform(ec, bytes_transferred))
+ {
+ handler.complete(ec, bytes_transferred);
+ return;
+ }
+ }
+
+ // Speculative writes are not ok as there will be queued write operations.
+ descriptor_data.allow_speculative_write = false;
+
+ if (write_op_queue_.enqueue_operation(descriptor, handler))
+ {
+ struct kevent event;
+ EV_SET(&event, descriptor, EVFILT_WRITE, EV_ADD, 0, 0, 0);
+ if (::kevent(kqueue_fd_, &event, 1, 0, 0, 0) == -1)
+ {
+ boost::system::error_code ec(errno,
+ boost::asio::error::get_system_category());
+ write_op_queue_.perform_all_operations(descriptor, ec);
+ }
+ }
+ }
+
+ // Start a new exception operation. The handler object will be invoked when
+ // the given descriptor has exception information, or an error has occurred.
+ template <typename Handler>
+ void start_except_op(socket_type descriptor,
+ per_descriptor_data&, Handler handler)
+ {
+ boost::asio::detail::mutex::scoped_lock lock(mutex_);
+
+ if (shutdown_)
+ return;
+
+ if (except_op_queue_.enqueue_operation(descriptor, handler))
+ {
+ struct kevent event;
+ if (read_op_queue_.has_operation(descriptor))
+ EV_SET(&event, descriptor, EVFILT_READ, EV_ADD, 0, 0, 0);
+ else
+ EV_SET(&event, descriptor, EVFILT_READ, EV_ADD, EV_OOBAND, 0, 0);
+ if (::kevent(kqueue_fd_, &event, 1, 0, 0, 0) == -1)
+ {
+ boost::system::error_code ec(errno,
+ boost::asio::error::get_system_category());
+ except_op_queue_.perform_all_operations(descriptor, ec);
+ }
+ }
+ }
+
+ // Start a new write operation. The handler object will be invoked when the
+ // given descriptor is ready to be written, or an error has occurred.
+ template <typename Handler>
+ void start_connect_op(socket_type descriptor,
+ per_descriptor_data& descriptor_data, Handler handler)
+ {
+ boost::asio::detail::mutex::scoped_lock lock(mutex_);
+
+ if (shutdown_)
+ return;
+
+ // Speculative writes are not ok as there will be queued write operations.
+ descriptor_data.allow_speculative_write = false;
+
+ if (write_op_queue_.enqueue_operation(descriptor, handler))
+ {
+ struct kevent event;
+ EV_SET(&event, descriptor, EVFILT_WRITE, EV_ADD, 0, 0, 0);
+ if (::kevent(kqueue_fd_, &event, 1, 0, 0, 0) == -1)
+ {
+ boost::system::error_code ec(errno,
+ boost::asio::error::get_system_category());
+ write_op_queue_.perform_all_operations(descriptor, ec);
+ }
+ }
+ }
+
+ // Cancel all operations associated with the given descriptor. The
+ // handlers associated with the descriptor will be invoked with the
+ // operation_aborted error.
+ void cancel_ops(socket_type descriptor, per_descriptor_data&)
+ {
+ boost::asio::detail::mutex::scoped_lock lock(mutex_);
+ cancel_ops_unlocked(descriptor);
+ }
+
+ // Cancel any operations that are running against the descriptor and remove
+ // its registration from the reactor.
+ void close_descriptor(socket_type descriptor, per_descriptor_data&)
+ {
+ boost::asio::detail::mutex::scoped_lock lock(mutex_);
+
+ // Remove the descriptor from kqueue.
+ struct kevent event[2];
+ EV_SET(&event[0], descriptor, EVFILT_READ, EV_DELETE, 0, 0, 0);
+ EV_SET(&event[1], descriptor, EVFILT_WRITE, EV_DELETE, 0, 0, 0);
+ ::kevent(kqueue_fd_, event, 2, 0, 0, 0);
+
+ // Cancel any outstanding operations associated with the descriptor.
+ cancel_ops_unlocked(descriptor);
+ }
+
+ // Add a new timer queue to the reactor.
+ template <typename Time_Traits>
+ void add_timer_queue(timer_queue<Time_Traits>& timer_queue)
+ {
+ boost::asio::detail::mutex::scoped_lock lock(mutex_);
+ timer_queues_.push_back(&timer_queue);
+ }
+
+ // Remove a timer queue from the reactor.
+ template <typename Time_Traits>
+ void remove_timer_queue(timer_queue<Time_Traits>& timer_queue)
+ {
+ boost::asio::detail::mutex::scoped_lock lock(mutex_);
+ for (std::size_t i = 0; i < timer_queues_.size(); ++i)
+ {
+ if (timer_queues_[i] == &timer_queue)
+ {
+ timer_queues_.erase(timer_queues_.begin() + i);
+ return;
+ }
+ }
+ }
+
+ // Schedule a timer in the given timer queue to expire at the specified
+ // absolute time. The handler object will be invoked when the timer expires.
+ template <typename Time_Traits, typename Handler>
+ void schedule_timer(timer_queue<Time_Traits>& timer_queue,
+ const typename Time_Traits::time_type& time, Handler handler, void* token)
+ {
+ boost::asio::detail::mutex::scoped_lock lock(mutex_);
+ if (!shutdown_)
+ if (timer_queue.enqueue_timer(time, handler, token))
+ interrupter_.interrupt();
+ }
+
+ // 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>& timer_queue, void* token)
+ {
+ boost::asio::detail::mutex::scoped_lock lock(mutex_);
+ std::size_t n = timer_queue.cancel_timer(token);
+ if (n > 0)
+ interrupter_.interrupt();
+ return n;
+ }
+
+private:
+ friend class task_io_service<kqueue_reactor<Own_Thread> >;
+
+ // Run the kqueue loop.
+ void run(bool block)
+ {
+ boost::asio::detail::mutex::scoped_lock lock(mutex_);
+
+ // Dispatch any operation cancellations that were made while the select
+ // loop was not running.
+ read_op_queue_.perform_cancellations();
+ write_op_queue_.perform_cancellations();
+ except_op_queue_.perform_cancellations();
+ for (std::size_t i = 0; i < timer_queues_.size(); ++i)
+ timer_queues_[i]->dispatch_cancellations();
+
+ // Check if the thread is supposed to stop.
+ if (stop_thread_)
+ {
+ complete_operations_and_timers(lock);
+ return;
+ }
+
+ // We can return immediately if there's no work to do and the reactor is
+ // not supposed to block.
+ if (!block && read_op_queue_.empty() && write_op_queue_.empty()
+ && except_op_queue_.empty() && all_timer_queues_are_empty())
+ {
+ complete_operations_and_timers(lock);
+ return;
+ }
+
+ // Determine how long to block while waiting for events.
+ timespec timeout_buf = { 0, 0 };
+ timespec* timeout = block ? get_timeout(timeout_buf) : &timeout_buf;
+
+ wait_in_progress_ = true;
+ lock.unlock();
+
+ // Block on the kqueue descriptor.
+ struct kevent events[128];
+ int num_events = (block || need_kqueue_wait_)
+ ? kevent(kqueue_fd_, 0, 0, events, 128, timeout)
+ : 0;
+
+ lock.lock();
+ wait_in_progress_ = false;
+
+ // Block signals while performing operations.
+ boost::asio::detail::signal_blocker sb;
+
+ // Dispatch the waiting events.
+ for (int i = 0; i < num_events; ++i)
+ {
+ int descriptor = events[i].ident;
+ if (descriptor == interrupter_.read_descriptor())
+ {
+ interrupter_.reset();
+ }
+ else if (events[i].filter == EVFILT_READ)
+ {
+ // Dispatch operations associated with the descriptor.
+ bool more_reads = false;
+ bool more_except = false;
+ if (events[i].flags & EV_ERROR)
+ {
+ boost::system::error_code error(
+ events[i].data, boost::asio::error::get_system_category());
+ except_op_queue_.perform_all_operations(descriptor, error);
+ read_op_queue_.perform_all_operations(descriptor, error);
+ }
+ else if (events[i].flags & EV_OOBAND)
+ {
+ boost::system::error_code error;
+ more_except = except_op_queue_.perform_operation(descriptor, error);
+ if (events[i].data > 0)
+ more_reads = read_op_queue_.perform_operation(descriptor, error);
+ else
+ more_reads = read_op_queue_.has_operation(descriptor);
+ }
+ else
+ {
+ boost::system::error_code error;
+ more_reads = read_op_queue_.perform_operation(descriptor, error);
+ more_except = except_op_queue_.has_operation(descriptor);
+ }
+
+ // Update the descriptor in the kqueue.
+ struct kevent event;
+ if (more_reads)
+ EV_SET(&event, descriptor, EVFILT_READ, EV_ADD, 0, 0, 0);
+ else if (more_except)
+ EV_SET(&event, descriptor, EVFILT_READ, EV_ADD, EV_OOBAND, 0, 0);
+ else
+ EV_SET(&event, descriptor, EVFILT_READ, EV_DELETE, 0, 0, 0);
+ if (::kevent(kqueue_fd_, &event, 1, 0, 0, 0) == -1)
+ {
+ boost::system::error_code error(errno,
+ boost::asio::error::get_system_category());
+ except_op_queue_.perform_all_operations(descriptor, error);
+ read_op_queue_.perform_all_operations(descriptor, error);
+ }
+ }
+ else if (events[i].filter == EVFILT_WRITE)
+ {
+ // Dispatch operations associated with the descriptor.
+ bool more_writes = false;
+ if (events[i].flags & EV_ERROR)
+ {
+ boost::system::error_code error(
+ events[i].data, boost::asio::error::get_system_category());
+ write_op_queue_.perform_all_operations(descriptor, error);
+ }
+ else
+ {
+ boost::system::error_code error;
+ more_writes = write_op_queue_.perform_operation(descriptor, error);
+ }
+
+ // Update the descriptor in the kqueue.
+ struct kevent event;
+ if (more_writes)
+ EV_SET(&event, descriptor, EVFILT_WRITE, EV_ADD, 0, 0, 0);
+ else
+ EV_SET(&event, descriptor, EVFILT_WRITE, EV_DELETE, 0, 0, 0);
+ if (::kevent(kqueue_fd_, &event, 1, 0, 0, 0) == -1)
+ {
+ boost::system::error_code error(errno,
+ boost::asio::error::get_system_category());
+ write_op_queue_.perform_all_operations(descriptor, error);
+ }
+ }
+ }
+
+ read_op_queue_.perform_cancellations();
+ write_op_queue_.perform_cancellations();
+ except_op_queue_.perform_cancellations();
+ for (std::size_t i = 0; i < timer_queues_.size(); ++i)
+ {
+ timer_queues_[i]->dispatch_timers();
+ timer_queues_[i]->dispatch_cancellations();
+ }
+
+ // Issue any pending cancellations.
+ for (std::size_t i = 0; i < pending_cancellations_.size(); ++i)
+ cancel_ops_unlocked(pending_cancellations_[i]);
+ pending_cancellations_.clear();
+
+ // Determine whether kqueue needs to be called next time the reactor is run.
+ need_kqueue_wait_ = !read_op_queue_.empty()
+ || !write_op_queue_.empty() || !except_op_queue_.empty();
+
+ complete_operations_and_timers(lock);
+ }
+
+ // Run the select loop in the thread.
+ void run_thread()
+ {
+ boost::asio::detail::mutex::scoped_lock lock(mutex_);
+ while (!stop_thread_)
+ {
+ lock.unlock();
+ run(true);
+ lock.lock();
+ }
+ }
+
+ // Entry point for the select loop thread.
+ static void call_run_thread(kqueue_reactor* reactor)
+ {
+ reactor->run_thread();
+ }
+
+ // Interrupt the select loop.
+ void interrupt()
+ {
+ interrupter_.interrupt();
+ }
+
+ // Create the kqueue file descriptor. Throws an exception if the descriptor
+ // cannot be created.
+ static int do_kqueue_create()
+ {
+ int fd = kqueue();
+ if (fd == -1)
+ {
+ boost::throw_exception(
+ boost::system::system_error(
+ boost::system::error_code(errno,
+ boost::asio::error::get_system_category()),
+ "kqueue"));
+ }
+ return fd;
+ }
+
+ // Check if all timer queues are empty.
+ bool all_timer_queues_are_empty() const
+ {
+ for (std::size_t i = 0; i < timer_queues_.size(); ++i)
+ if (!timer_queues_[i]->empty())
+ return false;
+ return true;
+ }
+
+ // Get the timeout value for the kevent call.
+ timespec* get_timeout(timespec& ts)
+ {
+ if (all_timer_queues_are_empty())
+ return 0;
+
+ // 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.
+ boost::posix_time::time_duration minimum_wait_duration
+ = boost::posix_time::minutes(5);
+
+ for (std::size_t i = 0; i < timer_queues_.size(); ++i)
+ {
+ boost::posix_time::time_duration wait_duration
+ = timer_queues_[i]->wait_duration();
+ if (wait_duration < minimum_wait_duration)
+ minimum_wait_duration = wait_duration;
+ }
+
+ if (minimum_wait_duration > boost::posix_time::time_duration())
+ {
+ ts.tv_sec = minimum_wait_duration.total_seconds();
+ ts.tv_nsec = minimum_wait_duration.total_nanoseconds() % 1000000000;
+ }
+ else
+ {
+ ts.tv_sec = 0;
+ ts.tv_nsec = 0;
+ }
+
+ return &ts;
+ }
+
+ // 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 kqueue_reactor's mutex.
+ void cancel_ops_unlocked(socket_type descriptor)
+ {
+ bool interrupt = read_op_queue_.cancel_operations(descriptor);
+ interrupt = write_op_queue_.cancel_operations(descriptor) || interrupt;
+ interrupt = except_op_queue_.cancel_operations(descriptor) || interrupt;
+ if (interrupt)
+ interrupter_.interrupt();
+ }
+
+ // Clean up operations and timers. We must not hold the lock since the
+ // destructors may make calls back into this reactor. We make a copy of the
+ // vector of timer queues since the original may be modified while the lock
+ // is not held.
+ void complete_operations_and_timers(
+ boost::asio::detail::mutex::scoped_lock& lock)
+ {
+ timer_queues_for_cleanup_ = timer_queues_;
+ lock.unlock();
+ read_op_queue_.complete_operations();
+ write_op_queue_.complete_operations();
+ except_op_queue_.complete_operations();
+ for (std::size_t i = 0; i < timer_queues_for_cleanup_.size(); ++i)
+ timer_queues_for_cleanup_[i]->complete_timers();
+ }
+
+ // Mutex to protect access to internal data.
+ boost::asio::detail::mutex mutex_;
+
+ // The kqueue file descriptor.
+ int kqueue_fd_;
+
+ // Whether the kqueue wait call is currently in progress
+ bool wait_in_progress_;
+
+ // The interrupter is used to break a blocking kevent call.
+ select_interrupter interrupter_;
+
+ // The queue of read operations.
+ reactor_op_queue<socket_type> read_op_queue_;
+
+ // The queue of write operations.
+ reactor_op_queue<socket_type> write_op_queue_;
+
+ // The queue of except operations.
+ reactor_op_queue<socket_type> except_op_queue_;
+
+ // The timer queues.
+ std::vector<timer_queue_base*> timer_queues_;
+
+ // A copy of the timer queues, used when cleaning up timers. The copy is
+ // stored as a class data member to avoid unnecessary memory allocation.
+ std::vector<timer_queue_base*> timer_queues_for_cleanup_;
+
+ // The descriptors that are pending cancellation.
+ std::vector<socket_type> pending_cancellations_;
+
+ // Does the reactor loop thread need to stop.
+ bool stop_thread_;
+
+ // The thread that is running the reactor loop.
+ boost::asio::detail::thread* thread_;
+
+ // Whether the service has been shut down.
+ bool shutdown_;
+
+ // Whether we need to call kqueue the next time the reactor is run.
+ bool need_kqueue_wait_;
+};
+
+} // namespace detail
+} // namespace asio
+} // namespace boost
+
+#endif // defined(BOOST_ASIO_HAS_KQUEUE)
+
+#include <boost/asio/detail/pop_options.hpp>
+
+#endif // BOOST_ASIO_DETAIL_KQUEUE_REACTOR_HPP
diff --git a/3rdParty/Boost/boost/asio/detail/kqueue_reactor_fwd.hpp b/3rdParty/Boost/boost/asio/detail/kqueue_reactor_fwd.hpp
new file mode 100644
index 0000000..e3df284
--- /dev/null
+++ b/3rdParty/Boost/boost/asio/detail/kqueue_reactor_fwd.hpp
@@ -0,0 +1,43 @@
+//
+// kqueue_reactor_fwd.hpp
+// ~~~~~~~~~~~~~~~~~~~~~~
+//
+// Copyright (c) 2003-2008 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 BOOST_ASIO_DETAIL_KQUEUE_REACTOR_FWD_HPP
+#define BOOST_ASIO_DETAIL_KQUEUE_REACTOR_FWD_HPP
+
+#if defined(_MSC_VER) && (_MSC_VER >= 1200)
+# pragma once
+#endif // defined(_MSC_VER) && (_MSC_VER >= 1200)
+
+#include <boost/asio/detail/push_options.hpp>
+
+#if !defined(BOOST_ASIO_DISABLE_KQUEUE)
+#if defined(__MACH__) && defined(__APPLE__)
+
+// Define this to indicate that epoll is supported on the target platform.
+#define BOOST_ASIO_HAS_KQUEUE 1
+
+namespace boost {
+namespace asio {
+namespace detail {
+
+template <bool Own_Thread>
+class kqueue_reactor;
+
+} // namespace detail
+} // namespace asio
+} // namespace boost
+
+#endif // defined(__MACH__) && defined(__APPLE__)
+#endif // !defined(BOOST_ASIO_DISABLE_KQUEUE)
+
+#include <boost/asio/detail/pop_options.hpp>
+
+#endif // BOOST_ASIO_DETAIL_KQUEUE_REACTOR_FWD_HPP
diff --git a/3rdParty/Boost/boost/asio/detail/mutex.hpp b/3rdParty/Boost/boost/asio/detail/mutex.hpp
new file mode 100644
index 0000000..4f64a28
--- /dev/null
+++ b/3rdParty/Boost/boost/asio/detail/mutex.hpp
@@ -0,0 +1,52 @@
+//
+// mutex.hpp
+// ~~~~~~~~~
+//
+// Copyright (c) 2003-2008 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 BOOST_ASIO_DETAIL_MUTEX_HPP
+#define BOOST_ASIO_DETAIL_MUTEX_HPP
+
+#if defined(_MSC_VER) && (_MSC_VER >= 1200)
+# pragma once
+#endif // defined(_MSC_VER) && (_MSC_VER >= 1200)
+
+#include <boost/asio/detail/push_options.hpp>
+
+#include <boost/asio/detail/push_options.hpp>
+#include <boost/config.hpp>
+#include <boost/asio/detail/pop_options.hpp>
+
+#if !defined(BOOST_HAS_THREADS)
+# include <boost/asio/detail/null_mutex.hpp>
+#elif defined(BOOST_WINDOWS)
+# include <boost/asio/detail/win_mutex.hpp>
+#elif defined(BOOST_HAS_PTHREADS)
+# include <boost/asio/detail/posix_mutex.hpp>
+#else
+# error Only Windows and POSIX are supported!
+#endif
+
+namespace boost {
+namespace asio {
+namespace detail {
+
+#if !defined(BOOST_HAS_THREADS)
+typedef null_mutex mutex;
+#elif defined(BOOST_WINDOWS)
+typedef win_mutex mutex;
+#elif defined(BOOST_HAS_PTHREADS)
+typedef posix_mutex mutex;
+#endif
+
+} // namespace detail
+} // namespace asio
+} // namespace boost
+
+#include <boost/asio/detail/pop_options.hpp>
+
+#endif // BOOST_ASIO_DETAIL_MUTEX_HPP
diff --git a/3rdParty/Boost/boost/asio/detail/noncopyable.hpp b/3rdParty/Boost/boost/asio/detail/noncopyable.hpp
new file mode 100644
index 0000000..3a09538
--- /dev/null
+++ b/3rdParty/Boost/boost/asio/detail/noncopyable.hpp
@@ -0,0 +1,57 @@
+//
+// noncopyable.hpp
+// ~~~~~~~~~~~~~~~
+//
+// Copyright (c) 2003-2008 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 BOOST_ASIO_DETAIL_NONCOPYABLE_HPP
+#define BOOST_ASIO_DETAIL_NONCOPYABLE_HPP
+
+#if defined(_MSC_VER) && (_MSC_VER >= 1200)
+# pragma once
+#endif // defined(_MSC_VER) && (_MSC_VER >= 1200)
+
+#include <boost/asio/detail/push_options.hpp>
+
+#include <boost/asio/detail/push_options.hpp>
+#include <boost/config.hpp>
+#include <boost/noncopyable.hpp>
+#include <boost/detail/workaround.hpp>
+#include <boost/asio/detail/pop_options.hpp>
+
+namespace boost {
+namespace asio {
+namespace detail {
+
+#if BOOST_WORKAROUND(__BORLANDC__, BOOST_TESTED_AT(0x564))
+// Redefine the noncopyable class for Borland C++ since that compiler does not
+// apply the empty base optimisation unless the base class contains a dummy
+// char data member.
+class noncopyable
+{
+protected:
+ noncopyable() {}
+ ~noncopyable() {}
+private:
+ noncopyable(const noncopyable&);
+ const noncopyable& operator=(const noncopyable&);
+ char dummy_;
+};
+#else
+using boost::noncopyable;
+#endif
+
+} // namespace detail
+
+using boost::asio::detail::noncopyable;
+
+} // namespace asio
+} // namespace boost
+
+#include <boost/asio/detail/pop_options.hpp>
+
+#endif // BOOST_ASIO_DETAIL_NONCOPYABLE_HPP
diff --git a/3rdParty/Boost/boost/asio/detail/null_event.hpp b/3rdParty/Boost/boost/asio/detail/null_event.hpp
new file mode 100644
index 0000000..4b667e7
--- /dev/null
+++ b/3rdParty/Boost/boost/asio/detail/null_event.hpp
@@ -0,0 +1,73 @@
+//
+// null_event.hpp
+// ~~~~~~~~~~~~~~
+//
+// Copyright (c) 2003-2008 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 BOOST_ASIO_DETAIL_NULL_EVENT_HPP
+#define BOOST_ASIO_DETAIL_NULL_EVENT_HPP
+
+#if defined(_MSC_VER) && (_MSC_VER >= 1200)
+# pragma once
+#endif // defined(_MSC_VER) && (_MSC_VER >= 1200)
+
+#include <boost/asio/detail/push_options.hpp>
+
+#include <boost/asio/detail/push_options.hpp>
+#include <boost/config.hpp>
+#include <boost/asio/detail/pop_options.hpp>
+
+#if !defined(BOOST_HAS_THREADS)
+
+#include <boost/asio/detail/noncopyable.hpp>
+
+namespace boost {
+namespace asio {
+namespace detail {
+
+class null_event
+ : private noncopyable
+{
+public:
+ // Constructor.
+ null_event()
+ {
+ }
+
+ // Destructor.
+ ~null_event()
+ {
+ }
+
+ // Signal the event.
+ template <typename Lock>
+ void signal(Lock&)
+ {
+ }
+
+ // Reset the event.
+ template <typename Lock>
+ void clear(Lock&)
+ {
+ }
+
+ // Wait for the event to become signalled.
+ template <typename Lock>
+ void wait(Lock&)
+ {
+ }
+};
+
+} // namespace detail
+} // namespace asio
+} // namespace boost
+
+#endif // !defined(BOOST_HAS_THREADS)
+
+#include <boost/asio/detail/pop_options.hpp>
+
+#endif // BOOST_ASIO_DETAIL_NULL_EVENT_HPP
diff --git a/3rdParty/Boost/boost/asio/detail/null_mutex.hpp b/3rdParty/Boost/boost/asio/detail/null_mutex.hpp
new file mode 100644
index 0000000..64bf871
--- /dev/null
+++ b/3rdParty/Boost/boost/asio/detail/null_mutex.hpp
@@ -0,0 +1,68 @@
+//
+// null_mutex.hpp
+// ~~~~~~~~~~~~~~
+//
+// Copyright (c) 2003-2008 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 BOOST_ASIO_DETAIL_NULL_MUTEX_HPP
+#define BOOST_ASIO_DETAIL_NULL_MUTEX_HPP
+
+#if defined(_MSC_VER) && (_MSC_VER >= 1200)
+# pragma once
+#endif // defined(_MSC_VER) && (_MSC_VER >= 1200)
+
+#include <boost/asio/detail/push_options.hpp>
+
+#include <boost/asio/detail/push_options.hpp>
+#include <boost/config.hpp>
+#include <boost/asio/detail/pop_options.hpp>
+
+#if !defined(BOOST_HAS_THREADS)
+
+#include <boost/asio/detail/noncopyable.hpp>
+#include <boost/asio/detail/scoped_lock.hpp>
+
+namespace boost {
+namespace asio {
+namespace detail {
+
+class null_mutex
+ : private noncopyable
+{
+public:
+ typedef boost::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
+} // namespace boost
+
+#endif // !defined(BOOST_HAS_THREADS)
+
+#include <boost/asio/detail/pop_options.hpp>
+
+#endif // BOOST_ASIO_DETAIL_NULL_MUTEX_HPP
diff --git a/3rdParty/Boost/boost/asio/detail/null_signal_blocker.hpp b/3rdParty/Boost/boost/asio/detail/null_signal_blocker.hpp
new file mode 100644
index 0000000..1fc65c8
--- /dev/null
+++ b/3rdParty/Boost/boost/asio/detail/null_signal_blocker.hpp
@@ -0,0 +1,65 @@
+//
+// null_signal_blocker.hpp
+// ~~~~~~~~~~~~~~~~~~~~~~~
+//
+// Copyright (c) 2003-2008 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 BOOST_ASIO_DETAIL_NULL_SIGNAL_BLOCKER_HPP
+#define BOOST_ASIO_DETAIL_NULL_SIGNAL_BLOCKER_HPP
+
+#if defined(_MSC_VER) && (_MSC_VER >= 1200)
+# pragma once
+#endif // defined(_MSC_VER) && (_MSC_VER >= 1200)
+
+#include <boost/asio/detail/push_options.hpp>
+
+#include <boost/asio/detail/push_options.hpp>
+#include <boost/config.hpp>
+#include <boost/asio/detail/pop_options.hpp>
+
+#if !defined(BOOST_HAS_THREADS)
+
+#include <boost/asio/detail/noncopyable.hpp>
+
+namespace boost {
+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
+} // namespace boost
+
+#endif // !defined(BOOST_HAS_THREADS)
+
+#include <boost/asio/detail/pop_options.hpp>
+
+#endif // BOOST_ASIO_DETAIL_NULL_SIGNAL_BLOCKER_HPP
diff --git a/3rdParty/Boost/boost/asio/detail/null_thread.hpp b/3rdParty/Boost/boost/asio/detail/null_thread.hpp
new file mode 100644
index 0000000..5aed211
--- /dev/null
+++ b/3rdParty/Boost/boost/asio/detail/null_thread.hpp
@@ -0,0 +1,70 @@
+//
+// null_thread.hpp
+// ~~~~~~~~~~~~~~~
+//
+// Copyright (c) 2003-2008 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 BOOST_ASIO_DETAIL_NULL_THREAD_HPP
+#define BOOST_ASIO_DETAIL_NULL_THREAD_HPP
+
+#if defined(_MSC_VER) && (_MSC_VER >= 1200)
+# pragma once
+#endif // defined(_MSC_VER) && (_MSC_VER >= 1200)
+
+#include <boost/asio/detail/push_options.hpp>
+
+#include <boost/asio/detail/push_options.hpp>
+#include <boost/config.hpp>
+#include <boost/system/system_error.hpp>
+#include <boost/asio/detail/pop_options.hpp>
+
+#if !defined(BOOST_HAS_THREADS)
+
+#include <boost/asio/detail/push_options.hpp>
+#include <boost/throw_exception.hpp>
+#include <boost/asio/detail/pop_options.hpp>
+
+#include <boost/asio/error.hpp>
+#include <boost/asio/detail/noncopyable.hpp>
+
+namespace boost {
+namespace asio {
+namespace detail {
+
+class null_thread
+ : private noncopyable
+{
+public:
+ // Constructor.
+ template <typename Function>
+ null_thread(Function f)
+ {
+ boost::system::system_error e(
+ boost::asio::error::operation_not_supported, "thread");
+ boost::throw_exception(e);
+ }
+
+ // Destructor.
+ ~null_thread()
+ {
+ }
+
+ // Wait for the thread to exit.
+ void join()
+ {
+ }
+};
+
+} // namespace detail
+} // namespace asio
+} // namespace boost
+
+#endif // !defined(BOOST_HAS_THREADS)
+
+#include <boost/asio/detail/pop_options.hpp>
+
+#endif // BOOST_ASIO_DETAIL_NULL_THREAD_HPP
diff --git a/3rdParty/Boost/boost/asio/detail/null_tss_ptr.hpp b/3rdParty/Boost/boost/asio/detail/null_tss_ptr.hpp
new file mode 100644
index 0000000..ba4b8f8
--- /dev/null
+++ b/3rdParty/Boost/boost/asio/detail/null_tss_ptr.hpp
@@ -0,0 +1,72 @@
+//
+// null_tss_ptr.hpp
+// ~~~~~~~~~~~~~~~~
+//
+// Copyright (c) 2003-2008 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 BOOST_ASIO_DETAIL_NULL_TSS_PTR_HPP
+#define BOOST_ASIO_DETAIL_NULL_TSS_PTR_HPP
+
+#if defined(_MSC_VER) && (_MSC_VER >= 1200)
+# pragma once
+#endif // defined(_MSC_VER) && (_MSC_VER >= 1200)
+
+#include <boost/asio/detail/push_options.hpp>
+
+#include <boost/asio/detail/push_options.hpp>
+#include <boost/config.hpp>
+#include <boost/asio/detail/pop_options.hpp>
+
+#if !defined(BOOST_HAS_THREADS)
+
+#include <boost/asio/detail/noncopyable.hpp>
+
+namespace boost {
+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
+} // namespace boost
+
+#endif // !defined(BOOST_HAS_THREADS)
+
+#include <boost/asio/detail/pop_options.hpp>
+
+#endif // BOOST_ASIO_DETAIL_NULL_TSS_PTR_HPP
diff --git a/3rdParty/Boost/boost/asio/detail/old_win_sdk_compat.hpp b/3rdParty/Boost/boost/asio/detail/old_win_sdk_compat.hpp
new file mode 100644
index 0000000..5f0aba1
--- /dev/null
+++ b/3rdParty/Boost/boost/asio/detail/old_win_sdk_compat.hpp
@@ -0,0 +1,342 @@
+//
+// old_win_sdk_compat.hpp
+// ~~~~~~~~~~~~~~~~~~~~~~
+//
+// Copyright (c) 2003-2008 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 BOOST_ASIO_DETAIL_OLD_WIN_SDK_COMPAT_HPP
+#define BOOST_ASIO_DETAIL_OLD_WIN_SDK_COMPAT_HPP
+
+#if defined(_MSC_VER) && (_MSC_VER >= 1200)
+# pragma once
+#endif // defined(_MSC_VER) && (_MSC_VER >= 1200)
+
+#include <boost/asio/detail/push_options.hpp>
+
+#include <boost/asio/detail/push_options.hpp>
+#include <boost/config.hpp>
+#include <boost/asio/detail/pop_options.hpp>
+
+#if defined(BOOST_WINDOWS) || defined(__CYGWIN__)
+
+// Guess whether we are building against on old Platform SDK.
+#if !defined(IN6ADDR_ANY_INIT)
+#define BOOST_ASIO_HAS_OLD_WIN_SDK 1
+#endif // !defined(IN6ADDR_ANY_INIT)
+
+#if defined(BOOST_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.
+
+namespace boost {
+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;
+};
+
+#if !defined(IN6ADDR_ANY_INIT)
+# define IN6ADDR_ANY_INIT { 0 }
+#endif
+
+#if !defined(IN6ADDR_LOOPBACK_INIT)
+# define IN6ADDR_LOOPBACK_INIT { 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,1 }
+#endif
+
+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
+
+inline int IN6_IS_ADDR_UNSPECIFIED(const in6_addr_emulation* a)
+{
+ return ((a->s6_addr[0] == 0)
+ && (a->s6_addr[1] == 0)
+ && (a->s6_addr[2] == 0)
+ && (a->s6_addr[3] == 0)
+ && (a->s6_addr[4] == 0)
+ && (a->s6_addr[5] == 0)
+ && (a->s6_addr[6] == 0)
+ && (a->s6_addr[7] == 0)
+ && (a->s6_addr[8] == 0)
+ && (a->s6_addr[9] == 0)
+ && (a->s6_addr[10] == 0)
+ && (a->s6_addr[11] == 0)
+ && (a->s6_addr[12] == 0)
+ && (a->s6_addr[13] == 0)
+ && (a->s6_addr[14] == 0)
+ && (a->s6_addr[15] == 0));
+}
+
+inline int IN6_IS_ADDR_LOOPBACK(const in6_addr_emulation* a)
+{
+ return ((a->s6_addr[0] == 0)
+ && (a->s6_addr[1] == 0)
+ && (a->s6_addr[2] == 0)
+ && (a->s6_addr[3] == 0)
+ && (a->s6_addr[4] == 0)
+ && (a->s6_addr[5] == 0)
+ && (a->s6_addr[6] == 0)
+ && (a->s6_addr[7] == 0)
+ && (a->s6_addr[8] == 0)
+ && (a->s6_addr[9] == 0)
+ && (a->s6_addr[10] == 0)
+ && (a->s6_addr[11] == 0)
+ && (a->s6_addr[12] == 0)
+ && (a->s6_addr[13] == 0)
+ && (a->s6_addr[14] == 0)
+ && (a->s6_addr[15] == 1));
+}
+
+inline int IN6_IS_ADDR_MULTICAST(const in6_addr_emulation* a)
+{
+ return (a->s6_addr[0] == 0xff);
+}
+
+inline int IN6_IS_ADDR_LINKLOCAL(const in6_addr_emulation* a)
+{
+ return ((a->s6_addr[0] == 0xfe) && ((a->s6_addr[1] & 0xc0) == 0x80));
+}
+
+inline int IN6_IS_ADDR_SITELOCAL(const in6_addr_emulation* a)
+{
+ return ((a->s6_addr[0] == 0xfe) && ((a->s6_addr[1] & 0xc0) == 0xc0));
+}
+
+inline int IN6_IS_ADDR_V4MAPPED(const in6_addr_emulation* a)
+{
+ return ((a->s6_addr[0] == 0)
+ && (a->s6_addr[1] == 0)
+ && (a->s6_addr[2] == 0)
+ && (a->s6_addr[3] == 0)
+ && (a->s6_addr[4] == 0)
+ && (a->s6_addr[5] == 0)
+ && (a->s6_addr[6] == 0)
+ && (a->s6_addr[7] == 0)
+ && (a->s6_addr[8] == 0)
+ && (a->s6_addr[9] == 0)
+ && (a->s6_addr[10] == 0xff)
+ && (a->s6_addr[11] == 0xff));
+}
+
+inline int IN6_IS_ADDR_V4COMPAT(const in6_addr_emulation* a)
+{
+ return ((a->s6_addr[0] == 0)
+ && (a->s6_addr[1] == 0)
+ && (a->s6_addr[2] == 0)
+ && (a->s6_addr[3] == 0)
+ && (a->s6_addr[4] == 0)
+ && (a->s6_addr[5] == 0)
+ && (a->s6_addr[6] == 0)
+ && (a->s6_addr[7] == 0)
+ && (a->s6_addr[8] == 0)
+ && (a->s6_addr[9] == 0)
+ && (a->s6_addr[10] == 0xff)
+ && (a->s6_addr[11] == 0xff)
+ && !((a->s6_addr[12] == 0)
+ && (a->s6_addr[13] == 0)
+ && (a->s6_addr[14] == 0)
+ && ((a->s6_addr[15] == 0) || (a->s6_addr[15] == 1))));
+}
+
+inline int IN6_IS_ADDR_MC_NODELOCAL(const in6_addr_emulation* a)
+{
+ return IN6_IS_ADDR_MULTICAST(a) && ((a->s6_addr[1] & 0xf) == 1);
+}
+
+inline int IN6_IS_ADDR_MC_LINKLOCAL(const in6_addr_emulation* a)
+{
+ return IN6_IS_ADDR_MULTICAST(a) && ((a->s6_addr[1] & 0xf) == 2);
+}
+
+inline int IN6_IS_ADDR_MC_SITELOCAL(const in6_addr_emulation* a)
+{
+ return IN6_IS_ADDR_MULTICAST(a) && ((a->s6_addr[1] & 0xf) == 5);
+}
+
+inline int IN6_IS_ADDR_MC_ORGLOCAL(const in6_addr_emulation* a)
+{
+ return IN6_IS_ADDR_MULTICAST(a) && ((a->s6_addr[1] & 0xf) == 8);
+}
+
+inline int IN6_IS_ADDR_MC_GLOBAL(const in6_addr_emulation* a)
+{
+ return IN6_IS_ADDR_MULTICAST(a) && ((a->s6_addr[1] & 0xf) == 0xe);
+}
+
+} // namespace detail
+} // namespace asio
+} // namespace boost
+
+#endif // defined(BOOST_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(BOOST_WINDOWS) || defined(__CYGWIN__)
+
+#include <boost/asio/detail/pop_options.hpp>
+
+#endif // BOOST_ASIO_DETAIL_OLD_WIN_SDK_COMPAT_HPP
diff --git a/3rdParty/Boost/boost/asio/detail/pipe_select_interrupter.hpp b/3rdParty/Boost/boost/asio/detail/pipe_select_interrupter.hpp
new file mode 100644
index 0000000..51b8c02
--- /dev/null
+++ b/3rdParty/Boost/boost/asio/detail/pipe_select_interrupter.hpp
@@ -0,0 +1,117 @@
+//
+// pipe_select_interrupter.hpp
+// ~~~~~~~~~~~~~~~~~~~~~~~~~~~
+//
+// Copyright (c) 2003-2008 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 BOOST_ASIO_DETAIL_PIPE_SELECT_INTERRUPTER_HPP
+#define BOOST_ASIO_DETAIL_PIPE_SELECT_INTERRUPTER_HPP
+
+#if defined(_MSC_VER) && (_MSC_VER >= 1200)
+# pragma once
+#endif // defined(_MSC_VER) && (_MSC_VER >= 1200)
+
+#include <boost/asio/detail/push_options.hpp>
+
+#include <boost/asio/detail/push_options.hpp>
+#include <boost/config.hpp>
+#include <boost/throw_exception.hpp>
+#include <boost/system/system_error.hpp>
+#include <boost/asio/detail/pop_options.hpp>
+
+#if !defined(BOOST_WINDOWS) && !defined(__CYGWIN__)
+
+#include <boost/asio/detail/push_options.hpp>
+#include <fcntl.h>
+#include <boost/asio/detail/pop_options.hpp>
+
+#include <boost/asio/error.hpp>
+#include <boost/asio/detail/socket_types.hpp>
+
+namespace boost {
+namespace asio {
+namespace detail {
+
+class pipe_select_interrupter
+{
+public:
+ // Constructor.
+ pipe_select_interrupter()
+ {
+ 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);
+ }
+ else
+ {
+ boost::system::error_code ec(errno,
+ boost::asio::error::get_system_category());
+ boost::system::system_error e(ec, "pipe_select_interrupter");
+ boost::throw_exception(e);
+ }
+ }
+
+ // Destructor.
+ ~pipe_select_interrupter()
+ {
+ if (read_descriptor_ != -1)
+ ::close(read_descriptor_);
+ if (write_descriptor_ != -1)
+ ::close(write_descriptor_);
+ }
+
+ // Interrupt the select call.
+ void interrupt()
+ {
+ char byte = 0;
+ int result = ::write(write_descriptor_, &byte, 1);
+ (void)result;
+ }
+
+ // Reset the select interrupt. Returns true if the call was interrupted.
+ bool reset()
+ {
+ char data[1024];
+ int bytes_read = ::read(read_descriptor_, data, sizeof(data));
+ bool was_interrupted = (bytes_read > 0);
+ while (bytes_read == sizeof(data))
+ bytes_read = ::read(read_descriptor_, data, sizeof(data));
+ return was_interrupted;
+ }
+
+ // Get the read descriptor to be passed to select.
+ int read_descriptor() const
+ {
+ return read_descriptor_;
+ }
+
+private:
+ // 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
+} // namespace boost
+
+#endif // !defined(BOOST_WINDOWS) && !defined(__CYGWIN__)
+
+#include <boost/asio/detail/pop_options.hpp>
+
+#endif // BOOST_ASIO_DETAIL_PIPE_SELECT_INTERRUPTER_HPP
diff --git a/3rdParty/Boost/boost/asio/detail/pop_options.hpp b/3rdParty/Boost/boost/asio/detail/pop_options.hpp
new file mode 100644
index 0000000..7f56662
--- /dev/null
+++ b/3rdParty/Boost/boost/asio/detail/pop_options.hpp
@@ -0,0 +1,88 @@
+//
+// pop_options.hpp
+// ~~~~~~~~~~~~~~~
+//
+// Copyright (c) 2003-2008 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++
+
+#elif defined(__GNUC__)
+
+// GNU C++
+
+# if defined(__MINGW32__) || defined(__CYGWIN__)
+# pragma pack (pop)
+# endif
+
+#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)
+
+#endif
diff --git a/3rdParty/Boost/boost/asio/detail/posix_event.hpp b/3rdParty/Boost/boost/asio/detail/posix_event.hpp
new file mode 100644
index 0000000..f838342
--- /dev/null
+++ b/3rdParty/Boost/boost/asio/detail/posix_event.hpp
@@ -0,0 +1,106 @@
+//
+// posix_event.hpp
+// ~~~~~~~~~~~~~~~
+//
+// Copyright (c) 2003-2008 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 BOOST_ASIO_DETAIL_POSIX_EVENT_HPP
+#define BOOST_ASIO_DETAIL_POSIX_EVENT_HPP
+
+#if defined(_MSC_VER) && (_MSC_VER >= 1200)
+# pragma once
+#endif // defined(_MSC_VER) && (_MSC_VER >= 1200)
+
+#include <boost/asio/detail/push_options.hpp>
+
+#include <boost/asio/detail/push_options.hpp>
+#include <boost/config.hpp>
+#include <boost/system/system_error.hpp>
+#include <boost/asio/detail/pop_options.hpp>
+
+#if defined(BOOST_HAS_PTHREADS)
+
+#include <boost/asio/detail/push_options.hpp>
+#include <boost/assert.hpp>
+#include <boost/throw_exception.hpp>
+#include <pthread.h>
+#include <boost/asio/detail/pop_options.hpp>
+
+#include <boost/asio/error.hpp>
+#include <boost/asio/detail/noncopyable.hpp>
+
+namespace boost {
+namespace asio {
+namespace detail {
+
+class posix_event
+ : private noncopyable
+{
+public:
+ // Constructor.
+ posix_event()
+ : signalled_(false)
+ {
+ int error = ::pthread_cond_init(&cond_, 0);
+ if (error != 0)
+ {
+ boost::system::system_error e(
+ boost::system::error_code(error,
+ boost::asio::error::get_system_category()),
+ "event");
+ boost::throw_exception(e);
+ }
+ }
+
+ // Destructor.
+ ~posix_event()
+ {
+ ::pthread_cond_destroy(&cond_);
+ }
+
+ // Signal the event.
+ template <typename Lock>
+ void signal(Lock& lock)
+ {
+ BOOST_ASSERT(lock.locked());
+ (void)lock;
+ signalled_ = true;
+ ::pthread_cond_signal(&cond_); // Ignore EINVAL.
+ }
+
+ // Reset the event.
+ template <typename Lock>
+ void clear(Lock& lock)
+ {
+ BOOST_ASSERT(lock.locked());
+ (void)lock;
+ signalled_ = false;
+ }
+
+ // Wait for the event to become signalled.
+ template <typename Lock>
+ void wait(Lock& lock)
+ {
+ BOOST_ASSERT(lock.locked());
+ while (!signalled_)
+ ::pthread_cond_wait(&cond_, &lock.mutex().mutex_); // Ignore EINVAL.
+ }
+
+private:
+ ::pthread_cond_t cond_;
+ bool signalled_;
+};
+
+} // namespace detail
+} // namespace asio
+} // namespace boost
+
+#endif // defined(BOOST_HAS_PTHREADS)
+
+#include <boost/asio/detail/pop_options.hpp>
+
+#endif // BOOST_ASIO_DETAIL_POSIX_EVENT_HPP
diff --git a/3rdParty/Boost/boost/asio/detail/posix_fd_set_adapter.hpp b/3rdParty/Boost/boost/asio/detail/posix_fd_set_adapter.hpp
new file mode 100644
index 0000000..121b396
--- /dev/null
+++ b/3rdParty/Boost/boost/asio/detail/posix_fd_set_adapter.hpp
@@ -0,0 +1,83 @@
+//
+// posix_fd_set_adapter.hpp
+// ~~~~~~~~~~~~~~~~~~~~~~~~
+//
+// Copyright (c) 2003-2008 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 BOOST_ASIO_DETAIL_POSIX_FD_SET_ADAPTER_HPP
+#define BOOST_ASIO_DETAIL_POSIX_FD_SET_ADAPTER_HPP
+
+#if defined(_MSC_VER) && (_MSC_VER >= 1200)
+# pragma once
+#endif // defined(_MSC_VER) && (_MSC_VER >= 1200)
+
+#include <boost/asio/detail/push_options.hpp>
+
+#include <boost/asio/detail/push_options.hpp>
+#include <cstring>
+#include <boost/asio/detail/pop_options.hpp>
+
+#include <boost/asio/detail/socket_types.hpp>
+
+#if !defined(BOOST_WINDOWS) && !defined(__CYGWIN__)
+
+namespace boost {
+namespace asio {
+namespace detail {
+
+// Adapts the FD_SET type to meet the Descriptor_Set concept's requirements.
+class posix_fd_set_adapter
+{
+public:
+ posix_fd_set_adapter()
+ : max_descriptor_(invalid_socket)
+ {
+ 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;
+ }
+
+ 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_;
+ }
+
+private:
+ mutable fd_set fd_set_;
+ socket_type max_descriptor_;
+};
+
+} // namespace detail
+} // namespace asio
+} // namespace boost
+
+#endif // !defined(BOOST_WINDOWS) && !defined(__CYGWIN__)
+
+#include <boost/asio/detail/pop_options.hpp>
+
+#endif // BOOST_ASIO_DETAIL_POSIX_FD_SET_ADAPTER_HPP
diff --git a/3rdParty/Boost/boost/asio/detail/posix_mutex.hpp b/3rdParty/Boost/boost/asio/detail/posix_mutex.hpp
new file mode 100644
index 0000000..219d6d0
--- /dev/null
+++ b/3rdParty/Boost/boost/asio/detail/posix_mutex.hpp
@@ -0,0 +1,109 @@
+//
+// posix_mutex.hpp
+// ~~~~~~~~~~~~~~~
+//
+// Copyright (c) 2003-2008 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 BOOST_ASIO_DETAIL_POSIX_MUTEX_HPP
+#define BOOST_ASIO_DETAIL_POSIX_MUTEX_HPP
+
+#if defined(_MSC_VER) && (_MSC_VER >= 1200)
+# pragma once
+#endif // defined(_MSC_VER) && (_MSC_VER >= 1200)
+
+#include <boost/asio/detail/push_options.hpp>
+
+#include <boost/asio/detail/push_options.hpp>
+#include <boost/config.hpp>
+#include <boost/system/system_error.hpp>
+#include <boost/asio/detail/pop_options.hpp>
+
+#if defined(BOOST_HAS_PTHREADS)
+
+#include <boost/asio/detail/push_options.hpp>
+#include <boost/throw_exception.hpp>
+#include <pthread.h>
+#include <boost/asio/detail/pop_options.hpp>
+
+#include <boost/asio/error.hpp>
+#include <boost/asio/detail/noncopyable.hpp>
+#include <boost/asio/detail/scoped_lock.hpp>
+
+namespace boost {
+namespace asio {
+namespace detail {
+
+class posix_event;
+
+class posix_mutex
+ : private noncopyable
+{
+public:
+ typedef boost::asio::detail::scoped_lock<posix_mutex> scoped_lock;
+
+ // Constructor.
+ posix_mutex()
+ {
+ int error = ::pthread_mutex_init(&mutex_, 0);
+ if (error != 0)
+ {
+ boost::system::system_error e(
+ boost::system::error_code(error,
+ boost::asio::error::get_system_category()),
+ "mutex");
+ boost::throw_exception(e);
+ }
+ }
+
+ // Destructor.
+ ~posix_mutex()
+ {
+ ::pthread_mutex_destroy(&mutex_);
+ }
+
+ // Lock the mutex.
+ void lock()
+ {
+ int error = ::pthread_mutex_lock(&mutex_);
+ if (error != 0)
+ {
+ boost::system::system_error e(
+ boost::system::error_code(error,
+ boost::asio::error::get_system_category()),
+ "mutex");
+ boost::throw_exception(e);
+ }
+ }
+
+ // Unlock the mutex.
+ void unlock()
+ {
+ int error = ::pthread_mutex_unlock(&mutex_);
+ if (error != 0)
+ {
+ boost::system::system_error e(
+ boost::system::error_code(error,
+ boost::asio::error::get_system_category()),
+ "mutex");
+ boost::throw_exception(e);
+ }
+ }
+
+private:
+ friend class posix_event;
+ ::pthread_mutex_t mutex_;
+};
+
+} // namespace detail
+} // namespace asio
+} // namespace boost
+
+#endif // defined(BOOST_HAS_PTHREADS)
+
+#include <boost/asio/detail/pop_options.hpp>
+
+#endif // BOOST_ASIO_DETAIL_POSIX_MUTEX_HPP
diff --git a/3rdParty/Boost/boost/asio/detail/posix_signal_blocker.hpp b/3rdParty/Boost/boost/asio/detail/posix_signal_blocker.hpp
new file mode 100644
index 0000000..f8234fb
--- /dev/null
+++ b/3rdParty/Boost/boost/asio/detail/posix_signal_blocker.hpp
@@ -0,0 +1,92 @@
+//
+// posix_signal_blocker.hpp
+// ~~~~~~~~~~~~~~~~~~~~~~~~
+//
+// Copyright (c) 2003-2008 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 BOOST_ASIO_DETAIL_POSIX_SIGNAL_BLOCKER_HPP
+#define BOOST_ASIO_DETAIL_POSIX_SIGNAL_BLOCKER_HPP
+
+#if defined(_MSC_VER) && (_MSC_VER >= 1200)
+# pragma once
+#endif // defined(_MSC_VER) && (_MSC_VER >= 1200)
+
+#include <boost/asio/detail/push_options.hpp>
+
+#include <boost/asio/detail/push_options.hpp>
+#include <boost/config.hpp>
+#include <boost/asio/detail/pop_options.hpp>
+
+#if defined(BOOST_HAS_PTHREADS)
+
+#include <boost/asio/detail/push_options.hpp>
+#include <csignal>
+#include <pthread.h>
+#include <signal.h>
+#include <boost/asio/detail/pop_options.hpp>
+
+#include <boost/asio/detail/noncopyable.hpp>
+
+namespace boost {
+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
+} // namespace boost
+
+#endif // defined(BOOST_HAS_PTHREADS)
+
+#include <boost/asio/detail/pop_options.hpp>
+
+#endif // BOOST_ASIO_DETAIL_POSIX_SIGNAL_BLOCKER_HPP
diff --git a/3rdParty/Boost/boost/asio/detail/posix_thread.hpp b/3rdParty/Boost/boost/asio/detail/posix_thread.hpp
new file mode 100644
index 0000000..1e38618
--- /dev/null
+++ b/3rdParty/Boost/boost/asio/detail/posix_thread.hpp
@@ -0,0 +1,131 @@
+//
+// posix_thread.hpp
+// ~~~~~~~~~~~~~~~~
+//
+// Copyright (c) 2003-2008 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 BOOST_ASIO_DETAIL_POSIX_THREAD_HPP
+#define BOOST_ASIO_DETAIL_POSIX_THREAD_HPP
+
+#if defined(_MSC_VER) && (_MSC_VER >= 1200)
+# pragma once
+#endif // defined(_MSC_VER) && (_MSC_VER >= 1200)
+
+#include <boost/asio/detail/push_options.hpp>
+
+#include <boost/asio/detail/push_options.hpp>
+#include <boost/config.hpp>
+#include <boost/system/system_error.hpp>
+#include <boost/asio/detail/pop_options.hpp>
+
+#if defined(BOOST_HAS_PTHREADS)
+
+#include <boost/asio/detail/push_options.hpp>
+#include <memory>
+#include <boost/throw_exception.hpp>
+#include <pthread.h>
+#include <boost/asio/detail/pop_options.hpp>
+
+#include <boost/asio/error.hpp>
+#include <boost/asio/detail/noncopyable.hpp>
+
+namespace boost {
+namespace asio {
+namespace detail {
+
+extern "C" void* asio_detail_posix_thread_function(void* arg);
+
+class posix_thread
+ : private noncopyable
+{
+public:
+ // Constructor.
+ template <typename Function>
+ posix_thread(Function f)
+ : joined_(false)
+ {
+ std::auto_ptr<func_base> arg(new func<Function>(f));
+ int error = ::pthread_create(&thread_, 0,
+ asio_detail_posix_thread_function, arg.get());
+ if (error != 0)
+ {
+ boost::system::system_error e(
+ boost::system::error_code(error,
+ boost::asio::error::get_system_category()),
+ "thread");
+ boost::throw_exception(e);
+ }
+ arg.release();
+ }
+
+ // Destructor.
+ ~posix_thread()
+ {
+ if (!joined_)
+ ::pthread_detach(thread_);
+ }
+
+ // Wait for the thread to exit.
+ void join()
+ {
+ if (!joined_)
+ {
+ ::pthread_join(thread_, 0);
+ joined_ = true;
+ }
+ }
+
+private:
+ friend void* asio_detail_posix_thread_function(void* 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_;
+ };
+
+ ::pthread_t thread_;
+ bool joined_;
+};
+
+inline void* asio_detail_posix_thread_function(void* arg)
+{
+ std::auto_ptr<posix_thread::func_base> f(
+ static_cast<posix_thread::func_base*>(arg));
+ f->run();
+ return 0;
+}
+
+} // namespace detail
+} // namespace asio
+} // namespace boost
+
+#endif // defined(BOOST_HAS_PTHREADS)
+
+#include <boost/asio/detail/pop_options.hpp>
+
+#endif // BOOST_ASIO_DETAIL_POSIX_THREAD_HPP
diff --git a/3rdParty/Boost/boost/asio/detail/posix_tss_ptr.hpp b/3rdParty/Boost/boost/asio/detail/posix_tss_ptr.hpp
new file mode 100644
index 0000000..f53c2dc
--- /dev/null
+++ b/3rdParty/Boost/boost/asio/detail/posix_tss_ptr.hpp
@@ -0,0 +1,90 @@
+//
+// posix_tss_ptr.hpp
+// ~~~~~~~~~~~~~~~~~
+//
+// Copyright (c) 2003-2008 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 BOOST_ASIO_DETAIL_POSIX_TSS_PTR_HPP
+#define BOOST_ASIO_DETAIL_POSIX_TSS_PTR_HPP
+
+#if defined(_MSC_VER) && (_MSC_VER >= 1200)
+# pragma once
+#endif // defined(_MSC_VER) && (_MSC_VER >= 1200)
+
+#include <boost/asio/detail/push_options.hpp>
+
+#include <boost/asio/detail/push_options.hpp>
+#include <boost/config.hpp>
+#include <boost/system/system_error.hpp>
+#include <boost/asio/detail/pop_options.hpp>
+
+#if defined(BOOST_HAS_PTHREADS)
+
+#include <boost/asio/detail/push_options.hpp>
+#include <boost/throw_exception.hpp>
+#include <pthread.h>
+#include <boost/asio/detail/pop_options.hpp>
+
+#include <boost/asio/error.hpp>
+#include <boost/asio/detail/noncopyable.hpp>
+
+namespace boost {
+namespace asio {
+namespace detail {
+
+template <typename T>
+class posix_tss_ptr
+ : private noncopyable
+{
+public:
+ // Constructor.
+ posix_tss_ptr()
+ {
+ int error = ::pthread_key_create(&tss_key_, 0);
+ if (error != 0)
+ {
+ boost::system::system_error e(
+ boost::system::error_code(error,
+ boost::asio::error::get_system_category()),
+ "tss");
+ boost::throw_exception(e);
+ }
+ }
+
+ // 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
+} // namespace boost
+
+#endif // defined(BOOST_HAS_PTHREADS)
+
+#include <boost/asio/detail/pop_options.hpp>
+
+#endif // BOOST_ASIO_DETAIL_POSIX_TSS_PTR_HPP
diff --git a/3rdParty/Boost/boost/asio/detail/push_options.hpp b/3rdParty/Boost/boost/asio/detail/push_options.hpp
new file mode 100644
index 0000000..47524b2
--- /dev/null
+++ b/3rdParty/Boost/boost/asio/detail/push_options.hpp
@@ -0,0 +1,114 @@
+//
+// push_options.hpp
+// ~~~~~~~~~~~~~~~~
+//
+// Copyright (c) 2003-2008 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++
+
+#elif defined(__GNUC__)
+
+// GNU C++
+
+# if defined(__MINGW32__) || defined(__CYGWIN__)
+# pragma pack (push, 8)
+# endif
+
+#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:4244)
+# pragma warning (disable:4355)
+# pragma warning (disable:4512)
+# pragma warning (disable:4675)
+# 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)
+
+#endif
diff --git a/3rdParty/Boost/boost/asio/detail/reactive_descriptor_service.hpp b/3rdParty/Boost/boost/asio/detail/reactive_descriptor_service.hpp
new file mode 100644
index 0000000..ad828aa
--- /dev/null
+++ b/3rdParty/Boost/boost/asio/detail/reactive_descriptor_service.hpp
@@ -0,0 +1,712 @@
+//
+// reactive_descriptor_service.hpp
+// ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+//
+// Copyright (c) 2003-2008 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 BOOST_ASIO_DETAIL_REACTIVE_DESCRIPTOR_SERVICE_HPP
+#define BOOST_ASIO_DETAIL_REACTIVE_DESCRIPTOR_SERVICE_HPP
+
+#if defined(_MSC_VER) && (_MSC_VER >= 1200)
+# pragma once
+#endif // defined(_MSC_VER) && (_MSC_VER >= 1200)
+
+#include <boost/asio/detail/push_options.hpp>
+
+#include <boost/asio/buffer.hpp>
+#include <boost/asio/error.hpp>
+#include <boost/asio/io_service.hpp>
+#include <boost/asio/detail/bind_handler.hpp>
+#include <boost/asio/detail/handler_base_from_member.hpp>
+#include <boost/asio/detail/noncopyable.hpp>
+#include <boost/asio/detail/service_base.hpp>
+#include <boost/asio/detail/descriptor_ops.hpp>
+
+#if !defined(BOOST_WINDOWS) && !defined(__CYGWIN__)
+
+namespace boost {
+namespace asio {
+namespace detail {
+
+template <typename Reactor>
+class reactive_descriptor_service
+ : public boost::asio::detail::service_base<
+ reactive_descriptor_service<Reactor> >
+{
+public:
+ // The native type of a descriptor.
+ typedef int native_type;
+
+ // The implementation type of the descriptor.
+ class implementation_type
+ : private boost::asio::detail::noncopyable
+ {
+ public:
+ // Default constructor.
+ implementation_type()
+ : descriptor_(-1),
+ flags_(0)
+ {
+ }
+
+ private:
+ // Only this service will have access to the internal values.
+ friend class reactive_descriptor_service<Reactor>;
+
+ // The native descriptor representation.
+ int descriptor_;
+
+ enum
+ {
+ user_set_non_blocking = 1, // The user wants a non-blocking descriptor.
+ internal_non_blocking = 2 // The descriptor has been set non-blocking.
+ };
+
+ // Flags indicating the current state of the descriptor.
+ unsigned char flags_;
+
+ // Per-descriptor data used by the reactor.
+ typename Reactor::per_descriptor_data reactor_data_;
+ };
+
+ // The maximum number of buffers to support in a single operation.
+ enum { max_buffers = 64 < max_iov_len ? 64 : max_iov_len };
+
+ // Constructor.
+ reactive_descriptor_service(boost::asio::io_service& io_service)
+ : boost::asio::detail::service_base<
+ reactive_descriptor_service<Reactor> >(io_service),
+ reactor_(boost::asio::use_service<Reactor>(io_service))
+ {
+ reactor_.init_task();
+ }
+
+ // Destroy all user-defined handler objects owned by the service.
+ void shutdown_service()
+ {
+ }
+
+ // Construct a new descriptor implementation.
+ void construct(implementation_type& impl)
+ {
+ impl.descriptor_ = -1;
+ impl.flags_ = 0;
+ }
+
+ // Destroy a descriptor implementation.
+ void destroy(implementation_type& impl)
+ {
+ if (impl.descriptor_ != -1)
+ {
+ reactor_.close_descriptor(impl.descriptor_, impl.reactor_data_);
+
+ if (impl.flags_ & implementation_type::internal_non_blocking)
+ {
+ ioctl_arg_type non_blocking = 0;
+ boost::system::error_code ignored_ec;
+ descriptor_ops::ioctl(impl.descriptor_,
+ FIONBIO, &non_blocking, ignored_ec);
+ impl.flags_ &= ~implementation_type::internal_non_blocking;
+ }
+
+ boost::system::error_code ignored_ec;
+ descriptor_ops::close(impl.descriptor_, ignored_ec);
+
+ impl.descriptor_ = -1;
+ }
+ }
+
+ // Assign a native descriptor to a descriptor implementation.
+ boost::system::error_code assign(implementation_type& impl,
+ const native_type& native_descriptor, boost::system::error_code& ec)
+ {
+ if (is_open(impl))
+ {
+ ec = boost::asio::error::already_open;
+ return ec;
+ }
+
+ if (int err = reactor_.register_descriptor(
+ native_descriptor, impl.reactor_data_))
+ {
+ ec = boost::system::error_code(err,
+ boost::asio::error::get_system_category());
+ return ec;
+ }
+
+ impl.descriptor_ = native_descriptor;
+ impl.flags_ = 0;
+ ec = boost::system::error_code();
+ return ec;
+ }
+
+ // Determine whether the descriptor is open.
+ bool is_open(const implementation_type& impl) const
+ {
+ return impl.descriptor_ != -1;
+ }
+
+ // Destroy a descriptor implementation.
+ boost::system::error_code close(implementation_type& impl,
+ boost::system::error_code& ec)
+ {
+ if (is_open(impl))
+ {
+ reactor_.close_descriptor(impl.descriptor_, impl.reactor_data_);
+
+ if (impl.flags_ & implementation_type::internal_non_blocking)
+ {
+ ioctl_arg_type non_blocking = 0;
+ boost::system::error_code ignored_ec;
+ descriptor_ops::ioctl(impl.descriptor_,
+ FIONBIO, &non_blocking, ignored_ec);
+ impl.flags_ &= ~implementation_type::internal_non_blocking;
+ }
+
+ if (descriptor_ops::close(impl.descriptor_, ec) == -1)
+ return ec;
+
+ impl.descriptor_ = -1;
+ }
+
+ ec = boost::system::error_code();
+ return ec;
+ }
+
+ // Get the native descriptor representation.
+ native_type native(const implementation_type& impl) const
+ {
+ return impl.descriptor_;
+ }
+
+ // Cancel all operations associated with the descriptor.
+ boost::system::error_code cancel(implementation_type& impl,
+ boost::system::error_code& ec)
+ {
+ if (!is_open(impl))
+ {
+ ec = boost::asio::error::bad_descriptor;
+ return ec;
+ }
+
+ reactor_.cancel_ops(impl.descriptor_, impl.reactor_data_);
+ ec = boost::system::error_code();
+ return ec;
+ }
+
+ // Perform an IO control command on the descriptor.
+ template <typename IO_Control_Command>
+ boost::system::error_code io_control(implementation_type& impl,
+ IO_Control_Command& command, boost::system::error_code& ec)
+ {
+ if (!is_open(impl))
+ {
+ ec = boost::asio::error::bad_descriptor;
+ return ec;
+ }
+
+ if (command.name() == static_cast<int>(FIONBIO))
+ {
+ if (command.get())
+ impl.flags_ |= implementation_type::user_set_non_blocking;
+ else
+ impl.flags_ &= ~implementation_type::user_set_non_blocking;
+ ec = boost::system::error_code();
+ }
+ else
+ {
+ descriptor_ops::ioctl(impl.descriptor_, command.name(),
+ static_cast<ioctl_arg_type*>(command.data()), ec);
+ }
+ return ec;
+ }
+
+ // Write some data to the descriptor.
+ template <typename ConstBufferSequence>
+ size_t write_some(implementation_type& impl,
+ const ConstBufferSequence& buffers, boost::system::error_code& ec)
+ {
+ if (!is_open(impl))
+ {
+ ec = boost::asio::error::bad_descriptor;
+ return 0;
+ }
+
+ // Copy buffers into array.
+ descriptor_ops::buf bufs[max_buffers];
+ typename ConstBufferSequence::const_iterator iter = buffers.begin();
+ typename ConstBufferSequence::const_iterator end = buffers.end();
+ size_t i = 0;
+ size_t total_buffer_size = 0;
+ for (; iter != end && i < max_buffers; ++iter, ++i)
+ {
+ boost::asio::const_buffer buffer(*iter);
+ descriptor_ops::init_buf(bufs[i],
+ boost::asio::buffer_cast<const void*>(buffer),
+ boost::asio::buffer_size(buffer));
+ total_buffer_size += boost::asio::buffer_size(buffer);
+ }
+
+ // A request to read_some 0 bytes on a stream is a no-op.
+ if (total_buffer_size == 0)
+ {
+ ec = boost::system::error_code();
+ return 0;
+ }
+
+ // Make descriptor non-blocking if user wants non-blocking.
+ if (impl.flags_ & implementation_type::user_set_non_blocking)
+ {
+ if (!(impl.flags_ & implementation_type::internal_non_blocking))
+ {
+ ioctl_arg_type non_blocking = 1;
+ if (descriptor_ops::ioctl(impl.descriptor_,
+ FIONBIO, &non_blocking, ec))
+ return 0;
+ impl.flags_ |= implementation_type::internal_non_blocking;
+ }
+ }
+
+ // Send the data.
+ for (;;)
+ {
+ // Try to complete the operation without blocking.
+ int bytes_sent = descriptor_ops::gather_write(
+ impl.descriptor_, bufs, i, ec);
+
+ // Check if operation succeeded.
+ if (bytes_sent >= 0)
+ return bytes_sent;
+
+ // Operation failed.
+ if ((impl.flags_ & implementation_type::user_set_non_blocking)
+ || (ec != boost::asio::error::would_block
+ && ec != boost::asio::error::try_again))
+ return 0;
+
+ // Wait for descriptor to become ready.
+ if (descriptor_ops::poll_write(impl.descriptor_, ec) < 0)
+ return 0;
+ }
+ }
+
+ // Wait until data can be written without blocking.
+ size_t write_some(implementation_type& impl,
+ const null_buffers&, boost::system::error_code& ec)
+ {
+ if (!is_open(impl))
+ {
+ ec = boost::asio::error::bad_descriptor;
+ return 0;
+ }
+
+ // Wait for descriptor to become ready.
+ descriptor_ops::poll_write(impl.descriptor_, ec);
+
+ return 0;
+ }
+
+ template <typename ConstBufferSequence, typename Handler>
+ class write_operation :
+ public handler_base_from_member<Handler>
+ {
+ public:
+ write_operation(int descriptor, boost::asio::io_service& io_service,
+ const ConstBufferSequence& buffers, Handler handler)
+ : handler_base_from_member<Handler>(handler),
+ descriptor_(descriptor),
+ io_service_(io_service),
+ work_(io_service),
+ buffers_(buffers)
+ {
+ }
+
+ bool perform(boost::system::error_code& ec,
+ std::size_t& bytes_transferred)
+ {
+ // Check whether the operation was successful.
+ if (ec)
+ {
+ bytes_transferred = 0;
+ return true;
+ }
+
+ // Copy buffers into array.
+ descriptor_ops::buf bufs[max_buffers];
+ typename ConstBufferSequence::const_iterator iter = buffers_.begin();
+ typename ConstBufferSequence::const_iterator end = buffers_.end();
+ size_t i = 0;
+ for (; iter != end && i < max_buffers; ++iter, ++i)
+ {
+ boost::asio::const_buffer buffer(*iter);
+ descriptor_ops::init_buf(bufs[i],
+ boost::asio::buffer_cast<const void*>(buffer),
+ boost::asio::buffer_size(buffer));
+ }
+
+ // Write the data.
+ int bytes = descriptor_ops::gather_write(descriptor_, bufs, i, ec);
+
+ // Check if we need to run the operation again.
+ if (ec == boost::asio::error::would_block
+ || ec == boost::asio::error::try_again)
+ return false;
+
+ bytes_transferred = (bytes < 0 ? 0 : bytes);
+ return true;
+ }
+
+ void complete(const boost::system::error_code& ec,
+ std::size_t bytes_transferred)
+ {
+ io_service_.post(bind_handler(this->handler_, ec, bytes_transferred));
+ }
+
+ private:
+ int descriptor_;
+ boost::asio::io_service& io_service_;
+ boost::asio::io_service::work work_;
+ ConstBufferSequence buffers_;
+ };
+
+ // 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)
+ {
+ if (!is_open(impl))
+ {
+ this->get_io_service().post(bind_handler(handler,
+ boost::asio::error::bad_descriptor, 0));
+ }
+ else
+ {
+ // Determine total size of buffers.
+ typename ConstBufferSequence::const_iterator iter = buffers.begin();
+ typename ConstBufferSequence::const_iterator end = buffers.end();
+ size_t i = 0;
+ size_t total_buffer_size = 0;
+ for (; iter != end && i < max_buffers; ++iter, ++i)
+ {
+ boost::asio::const_buffer buffer(*iter);
+ total_buffer_size += boost::asio::buffer_size(buffer);
+ }
+
+ // A request to read_some 0 bytes on a stream is a no-op.
+ if (total_buffer_size == 0)
+ {
+ this->get_io_service().post(bind_handler(handler,
+ boost::system::error_code(), 0));
+ return;
+ }
+
+ // Make descriptor non-blocking.
+ if (!(impl.flags_ & implementation_type::internal_non_blocking))
+ {
+ ioctl_arg_type non_blocking = 1;
+ boost::system::error_code ec;
+ if (descriptor_ops::ioctl(impl.descriptor_, FIONBIO, &non_blocking, ec))
+ {
+ this->get_io_service().post(bind_handler(handler, ec, 0));
+ return;
+ }
+ impl.flags_ |= implementation_type::internal_non_blocking;
+ }
+
+ reactor_.start_write_op(impl.descriptor_, impl.reactor_data_,
+ write_operation<ConstBufferSequence, Handler>(
+ impl.descriptor_, this->get_io_service(), buffers, handler));
+ }
+ }
+
+ template <typename Handler>
+ class null_buffers_operation :
+ public handler_base_from_member<Handler>
+ {
+ public:
+ null_buffers_operation(boost::asio::io_service& io_service, Handler handler)
+ : handler_base_from_member<Handler>(handler),
+ work_(io_service)
+ {
+ }
+
+ bool perform(boost::system::error_code&,
+ std::size_t& bytes_transferred)
+ {
+ bytes_transferred = 0;
+ return true;
+ }
+
+ void complete(const boost::system::error_code& ec,
+ std::size_t bytes_transferred)
+ {
+ work_.get_io_service().post(bind_handler(
+ this->handler_, ec, bytes_transferred));
+ }
+
+ private:
+ boost::asio::io_service::work work_;
+ };
+
+ // 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)
+ {
+ if (!is_open(impl))
+ {
+ this->get_io_service().post(bind_handler(handler,
+ boost::asio::error::bad_descriptor, 0));
+ }
+ else
+ {
+ reactor_.start_write_op(impl.descriptor_, impl.reactor_data_,
+ null_buffers_operation<Handler>(this->get_io_service(), handler),
+ false);
+ }
+ }
+
+ // 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, boost::system::error_code& ec)
+ {
+ if (!is_open(impl))
+ {
+ ec = boost::asio::error::bad_descriptor;
+ return 0;
+ }
+
+ // Copy buffers into array.
+ descriptor_ops::buf bufs[max_buffers];
+ typename MutableBufferSequence::const_iterator iter = buffers.begin();
+ typename MutableBufferSequence::const_iterator end = buffers.end();
+ size_t i = 0;
+ size_t total_buffer_size = 0;
+ for (; iter != end && i < max_buffers; ++iter, ++i)
+ {
+ boost::asio::mutable_buffer buffer(*iter);
+ descriptor_ops::init_buf(bufs[i],
+ boost::asio::buffer_cast<void*>(buffer),
+ boost::asio::buffer_size(buffer));
+ total_buffer_size += boost::asio::buffer_size(buffer);
+ }
+
+ // A request to read_some 0 bytes on a stream is a no-op.
+ if (total_buffer_size == 0)
+ {
+ ec = boost::system::error_code();
+ return 0;
+ }
+
+ // Make descriptor non-blocking if user wants non-blocking.
+ if (impl.flags_ & implementation_type::user_set_non_blocking)
+ {
+ if (!(impl.flags_ & implementation_type::internal_non_blocking))
+ {
+ ioctl_arg_type non_blocking = 1;
+ if (descriptor_ops::ioctl(impl.descriptor_, FIONBIO, &non_blocking, ec))
+ return 0;
+ impl.flags_ |= implementation_type::internal_non_blocking;
+ }
+ }
+
+ // Read some data.
+ for (;;)
+ {
+ // Try to complete the operation without blocking.
+ int bytes_read = descriptor_ops::scatter_read(
+ impl.descriptor_, bufs, i, ec);
+
+ // Check if operation succeeded.
+ if (bytes_read > 0)
+ return bytes_read;
+
+ // Check for EOF.
+ if (bytes_read == 0)
+ {
+ ec = boost::asio::error::eof;
+ return 0;
+ }
+
+ // Operation failed.
+ if ((impl.flags_ & implementation_type::user_set_non_blocking)
+ || (ec != boost::asio::error::would_block
+ && ec != boost::asio::error::try_again))
+ return 0;
+
+ // Wait for descriptor to become ready.
+ if (descriptor_ops::poll_read(impl.descriptor_, ec) < 0)
+ return 0;
+ }
+ }
+
+ // Wait until data can be read without blocking.
+ size_t read_some(implementation_type& impl,
+ const null_buffers&, boost::system::error_code& ec)
+ {
+ if (!is_open(impl))
+ {
+ ec = boost::asio::error::bad_descriptor;
+ return 0;
+ }
+
+ // Wait for descriptor to become ready.
+ descriptor_ops::poll_read(impl.descriptor_, ec);
+
+ return 0;
+ }
+
+ template <typename MutableBufferSequence, typename Handler>
+ class read_operation :
+ public handler_base_from_member<Handler>
+ {
+ public:
+ read_operation(int descriptor, boost::asio::io_service& io_service,
+ const MutableBufferSequence& buffers, Handler handler)
+ : handler_base_from_member<Handler>(handler),
+ descriptor_(descriptor),
+ io_service_(io_service),
+ work_(io_service),
+ buffers_(buffers)
+ {
+ }
+
+ bool perform(boost::system::error_code& ec,
+ std::size_t& bytes_transferred)
+ {
+ // Check whether the operation was successful.
+ if (ec)
+ {
+ bytes_transferred = 0;
+ return true;
+ }
+
+ // Copy buffers into array.
+ descriptor_ops::buf bufs[max_buffers];
+ typename MutableBufferSequence::const_iterator iter = buffers_.begin();
+ typename MutableBufferSequence::const_iterator end = buffers_.end();
+ size_t i = 0;
+ for (; iter != end && i < max_buffers; ++iter, ++i)
+ {
+ boost::asio::mutable_buffer buffer(*iter);
+ descriptor_ops::init_buf(bufs[i],
+ boost::asio::buffer_cast<void*>(buffer),
+ boost::asio::buffer_size(buffer));
+ }
+
+ // Read some data.
+ int bytes = descriptor_ops::scatter_read(descriptor_, bufs, i, ec);
+ if (bytes == 0)
+ ec = boost::asio::error::eof;
+
+ // Check if we need to run the operation again.
+ if (ec == boost::asio::error::would_block
+ || ec == boost::asio::error::try_again)
+ return false;
+
+ bytes_transferred = (bytes < 0 ? 0 : bytes);
+ return true;
+ }
+
+ void complete(const boost::system::error_code& ec,
+ std::size_t bytes_transferred)
+ {
+ io_service_.post(bind_handler(this->handler_, ec, bytes_transferred));
+ }
+
+ private:
+ int descriptor_;
+ boost::asio::io_service& io_service_;
+ boost::asio::io_service::work work_;
+ MutableBufferSequence buffers_;
+ };
+
+ // 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)
+ {
+ if (!is_open(impl))
+ {
+ this->get_io_service().post(bind_handler(handler,
+ boost::asio::error::bad_descriptor, 0));
+ }
+ else
+ {
+ // Determine total size of buffers.
+ typename MutableBufferSequence::const_iterator iter = buffers.begin();
+ typename MutableBufferSequence::const_iterator end = buffers.end();
+ size_t i = 0;
+ size_t total_buffer_size = 0;
+ for (; iter != end && i < max_buffers; ++iter, ++i)
+ {
+ boost::asio::mutable_buffer buffer(*iter);
+ total_buffer_size += boost::asio::buffer_size(buffer);
+ }
+
+ // A request to read_some 0 bytes on a stream is a no-op.
+ if (total_buffer_size == 0)
+ {
+ this->get_io_service().post(bind_handler(handler,
+ boost::system::error_code(), 0));
+ return;
+ }
+
+ // Make descriptor non-blocking.
+ if (!(impl.flags_ & implementation_type::internal_non_blocking))
+ {
+ ioctl_arg_type non_blocking = 1;
+ boost::system::error_code ec;
+ if (descriptor_ops::ioctl(impl.descriptor_, FIONBIO, &non_blocking, ec))
+ {
+ this->get_io_service().post(bind_handler(handler, ec, 0));
+ return;
+ }
+ impl.flags_ |= implementation_type::internal_non_blocking;
+ }
+
+ reactor_.start_read_op(impl.descriptor_, impl.reactor_data_,
+ read_operation<MutableBufferSequence, Handler>(
+ impl.descriptor_, this->get_io_service(), buffers, handler));
+ }
+ }
+
+ // Wait until data can be read without blocking.
+ template <typename Handler>
+ void async_read_some(implementation_type& impl,
+ const null_buffers&, Handler handler)
+ {
+ if (!is_open(impl))
+ {
+ this->get_io_service().post(bind_handler(handler,
+ boost::asio::error::bad_descriptor, 0));
+ }
+ else
+ {
+ reactor_.start_read_op(impl.descriptor_, impl.reactor_data_,
+ null_buffers_operation<Handler>(this->get_io_service(), handler),
+ false);
+ }
+ }
+
+private:
+ // The selector that performs event demultiplexing for the service.
+ Reactor& reactor_;
+};
+
+} // namespace detail
+} // namespace asio
+} // namespace boost
+
+#endif // !defined(BOOST_WINDOWS) && !defined(__CYGWIN__)
+
+#include <boost/asio/detail/pop_options.hpp>
+
+#endif // BOOST_ASIO_DETAIL_REACTIVE_DESCRIPTOR_SERVICE_HPP
diff --git a/3rdParty/Boost/boost/asio/detail/reactive_serial_port_service.hpp b/3rdParty/Boost/boost/asio/detail/reactive_serial_port_service.hpp
new file mode 100644
index 0000000..0beff14
--- /dev/null
+++ b/3rdParty/Boost/boost/asio/detail/reactive_serial_port_service.hpp
@@ -0,0 +1,270 @@
+//
+// reactive_serial_port_service.hpp
+// ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+//
+// Copyright (c) 2003-2008 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 BOOST_ASIO_DETAIL_REACTIVE_SERIAL_PORT_SERVICE_HPP
+#define BOOST_ASIO_DETAIL_REACTIVE_SERIAL_PORT_SERVICE_HPP
+
+#if defined(_MSC_VER) && (_MSC_VER >= 1200)
+# pragma once
+#endif // defined(_MSC_VER) && (_MSC_VER >= 1200)
+
+#include <boost/asio/detail/push_options.hpp>
+
+#include <boost/asio/detail/push_options.hpp>
+#include <cstring>
+#include <string>
+#include <boost/asio/detail/pop_options.hpp>
+
+#include <boost/asio/serial_port_base.hpp>
+
+#if defined(BOOST_ASIO_HAS_SERIAL_PORT) \
+ && !defined(BOOST_WINDOWS) && !defined(__CYGWIN__)
+
+#include <boost/asio/error.hpp>
+#include <boost/asio/io_service.hpp>
+#include <boost/asio/detail/descriptor_ops.hpp>
+#include <boost/asio/detail/reactive_descriptor_service.hpp>
+
+namespace boost {
+namespace asio {
+namespace detail {
+
+// Extend reactive_descriptor_service to provide serial port support.
+template <typename Reactor>
+class reactive_serial_port_service
+ : public boost::asio::detail::service_base<
+ reactive_serial_port_service<Reactor> >
+{
+public:
+ // The native type of a stream handle.
+ typedef typename reactive_descriptor_service<Reactor>::native_type
+ native_type;
+
+ // The implementation type of the stream handle.
+ typedef typename reactive_descriptor_service<Reactor>::implementation_type
+ implementation_type;
+
+ reactive_serial_port_service(boost::asio::io_service& io_service)
+ : boost::asio::detail::service_base<
+ reactive_serial_port_service>(io_service),
+ descriptor_service_(boost::asio::use_service<
+ reactive_descriptor_service<Reactor> >(io_service))
+ {
+ }
+
+ // Destroy all user-defined handler objects owned by the service.
+ void shutdown_service()
+ {
+ }
+
+ // Construct a new handle implementation.
+ void construct(implementation_type& impl)
+ {
+ descriptor_service_.construct(impl);
+ }
+
+ // Destroy a handle implementation.
+ void destroy(implementation_type& impl)
+ {
+ descriptor_service_.destroy(impl);
+ }
+
+ // Open the serial port using the specified device name.
+ boost::system::error_code open(implementation_type& impl,
+ const std::string& device, boost::system::error_code& ec)
+ {
+ if (is_open(impl))
+ {
+ ec = boost::asio::error::already_open;
+ return ec;
+ }
+
+ 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)
+ {
+ boost::system::error_code ignored_ec;
+ descriptor_ops::close(fd, ignored_ec);
+ return ec;
+ }
+
+ // Set up default serial port options.
+ termios ios;
+ descriptor_ops::clear_error(ec);
+ s = descriptor_ops::error_wrapper(::tcgetattr(fd, &ios), ec);
+ if (s >= 0)
+ {
+#if defined(_BSD_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;
+ descriptor_ops::clear_error(ec);
+ s = descriptor_ops::error_wrapper(::tcsetattr(fd, TCSANOW, &ios), ec);
+ }
+ if (s < 0)
+ {
+ boost::system::error_code ignored_ec;
+ descriptor_ops::close(fd, ignored_ec);
+ return ec;
+ }
+
+ // We're done. Take ownership of the serial port descriptor.
+ if (descriptor_service_.assign(impl, fd, ec))
+ {
+ boost::system::error_code ignored_ec;
+ descriptor_ops::close(fd, ignored_ec);
+ }
+
+ return ec;
+ }
+
+ // Assign a native handle to a handle implementation.
+ boost::system::error_code assign(implementation_type& impl,
+ const native_type& native_descriptor, boost::system::error_code& ec)
+ {
+ return descriptor_service_.assign(impl, native_descriptor, ec);
+ }
+
+ // Determine whether the handle is open.
+ bool is_open(const implementation_type& impl) const
+ {
+ return descriptor_service_.is_open(impl);
+ }
+
+ // Destroy a handle implementation.
+ boost::system::error_code close(implementation_type& impl,
+ boost::system::error_code& ec)
+ {
+ return descriptor_service_.close(impl, ec);
+ }
+
+ // Get the native handle representation.
+ native_type native(implementation_type& impl)
+ {
+ return descriptor_service_.native(impl);
+ }
+
+ // Cancel all operations associated with the handle.
+ boost::system::error_code cancel(implementation_type& impl,
+ boost::system::error_code& ec)
+ {
+ return descriptor_service_.cancel(impl, ec);
+ }
+
+ // Set an option on the serial port.
+ template <typename SettableSerialPortOption>
+ boost::system::error_code set_option(implementation_type& impl,
+ const SettableSerialPortOption& option, boost::system::error_code& ec)
+ {
+ termios ios;
+ descriptor_ops::clear_error(ec);
+ descriptor_ops::error_wrapper(::tcgetattr(
+ descriptor_service_.native(impl), &ios), ec);
+ if (ec)
+ return ec;
+
+ if (option.store(ios, ec))
+ return ec;
+
+ descriptor_ops::clear_error(ec);
+ descriptor_ops::error_wrapper(::tcsetattr(
+ descriptor_service_.native(impl), TCSANOW, &ios), ec);
+ return ec;
+ }
+
+ // Get an option from the serial port.
+ template <typename GettableSerialPortOption>
+ boost::system::error_code get_option(const implementation_type& impl,
+ GettableSerialPortOption& option, boost::system::error_code& ec) const
+ {
+ termios ios;
+ descriptor_ops::clear_error(ec);
+ descriptor_ops::error_wrapper(::tcgetattr(
+ descriptor_service_.native(impl), &ios), ec);
+ if (ec)
+ return ec;
+
+ return option.load(ios, ec);
+ }
+
+ // Send a break sequence to the serial port.
+ boost::system::error_code send_break(implementation_type& impl,
+ boost::system::error_code& ec)
+ {
+ descriptor_ops::clear_error(ec);
+ descriptor_ops::error_wrapper(::tcsendbreak(
+ descriptor_service_.native(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, boost::system::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, boost::system::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:
+ // The handle service used for initiating asynchronous operations.
+ reactive_descriptor_service<Reactor>& descriptor_service_;
+};
+
+} // namespace detail
+} // namespace asio
+} // namespace boost
+
+#endif // defined(BOOST_ASIO_HAS_SERIAL_PORT)
+ // && !defined(BOOST_WINDOWS) && !defined(__CYGWIN__)
+
+#include <boost/asio/detail/pop_options.hpp>
+
+#endif // BOOST_ASIO_DETAIL_REACTIVE_SERIAL_PORT_SERVICE_HPP
diff --git a/3rdParty/Boost/boost/asio/detail/reactive_socket_service.hpp b/3rdParty/Boost/boost/asio/detail/reactive_socket_service.hpp
new file mode 100644
index 0000000..54b8cbd
--- /dev/null
+++ b/3rdParty/Boost/boost/asio/detail/reactive_socket_service.hpp
@@ -0,0 +1,1788 @@
+//
+// reactive_socket_service.hpp
+// ~~~~~~~~~~~~~~~~~~~~~~~~~~~
+//
+// Copyright (c) 2003-2008 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 BOOST_ASIO_DETAIL_REACTIVE_SOCKET_SERVICE_HPP
+#define BOOST_ASIO_DETAIL_REACTIVE_SOCKET_SERVICE_HPP
+
+#if defined(_MSC_VER) && (_MSC_VER >= 1200)
+# pragma once
+#endif // defined(_MSC_VER) && (_MSC_VER >= 1200)
+
+#include <boost/asio/detail/push_options.hpp>
+
+#include <boost/asio/detail/push_options.hpp>
+#include <boost/shared_ptr.hpp>
+#include <boost/asio/detail/pop_options.hpp>
+
+#include <boost/asio/buffer.hpp>
+#include <boost/asio/error.hpp>
+#include <boost/asio/io_service.hpp>
+#include <boost/asio/socket_base.hpp>
+#include <boost/asio/detail/bind_handler.hpp>
+#include <boost/asio/detail/handler_base_from_member.hpp>
+#include <boost/asio/detail/noncopyable.hpp>
+#include <boost/asio/detail/service_base.hpp>
+#include <boost/asio/detail/socket_holder.hpp>
+#include <boost/asio/detail/socket_ops.hpp>
+#include <boost/asio/detail/socket_types.hpp>
+
+namespace boost {
+namespace asio {
+namespace detail {
+
+template <typename Protocol, typename Reactor>
+class reactive_socket_service
+ : public boost::asio::detail::service_base<
+ reactive_socket_service<Protocol, Reactor> >
+{
+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_type;
+
+ // The implementation type of the socket.
+ class implementation_type
+ : private boost::asio::detail::noncopyable
+ {
+ public:
+ // Default constructor.
+ implementation_type()
+ : socket_(invalid_socket),
+ flags_(0),
+ protocol_(endpoint_type().protocol())
+ {
+ }
+
+ private:
+ // Only this service will have access to the internal values.
+ friend class reactive_socket_service<Protocol, Reactor>;
+
+ // The native socket representation.
+ socket_type socket_;
+
+ enum
+ {
+ // The user wants a non-blocking socket.
+ user_set_non_blocking = 1,
+
+ // The implementation wants a non-blocking socket (in order to be able to
+ // perform asynchronous read and write operations).
+ internal_non_blocking = 2,
+
+ // Helper "flag" 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
+ };
+
+ // Flags indicating the current state of the socket.
+ unsigned char flags_;
+
+ // The protocol associated with the socket.
+ protocol_type protocol_;
+
+ // Per-descriptor data used by the reactor.
+ typename Reactor::per_descriptor_data reactor_data_;
+ };
+
+ // The maximum number of buffers to support in a single operation.
+ enum { max_buffers = 64 < max_iov_len ? 64 : max_iov_len };
+
+ // Constructor.
+ reactive_socket_service(boost::asio::io_service& io_service)
+ : boost::asio::detail::service_base<
+ reactive_socket_service<Protocol, Reactor> >(io_service),
+ reactor_(boost::asio::use_service<Reactor>(io_service))
+ {
+ reactor_.init_task();
+ }
+
+ // Destroy all user-defined handler objects owned by the service.
+ void shutdown_service()
+ {
+ }
+
+ // Construct a new socket implementation.
+ void construct(implementation_type& impl)
+ {
+ impl.socket_ = invalid_socket;
+ impl.flags_ = 0;
+ }
+
+ // Destroy a socket implementation.
+ void destroy(implementation_type& impl)
+ {
+ if (impl.socket_ != invalid_socket)
+ {
+ reactor_.close_descriptor(impl.socket_, impl.reactor_data_);
+
+ if (impl.flags_ & implementation_type::non_blocking)
+ {
+ ioctl_arg_type non_blocking = 0;
+ boost::system::error_code ignored_ec;
+ socket_ops::ioctl(impl.socket_, FIONBIO, &non_blocking, ignored_ec);
+ impl.flags_ &= ~implementation_type::non_blocking;
+ }
+
+ if (impl.flags_ & implementation_type::user_set_linger)
+ {
+ ::linger opt;
+ opt.l_onoff = 0;
+ opt.l_linger = 0;
+ boost::system::error_code ignored_ec;
+ socket_ops::setsockopt(impl.socket_,
+ SOL_SOCKET, SO_LINGER, &opt, sizeof(opt), ignored_ec);
+ }
+
+ boost::system::error_code ignored_ec;
+ socket_ops::close(impl.socket_, ignored_ec);
+
+ impl.socket_ = invalid_socket;
+ }
+ }
+
+ // Open a new socket implementation.
+ boost::system::error_code open(implementation_type& impl,
+ const protocol_type& protocol, boost::system::error_code& ec)
+ {
+ if (is_open(impl))
+ {
+ ec = boost::asio::error::already_open;
+ return ec;
+ }
+
+ socket_holder sock(socket_ops::socket(protocol.family(),
+ protocol.type(), protocol.protocol(), ec));
+ if (sock.get() == invalid_socket)
+ return ec;
+
+ if (int err = reactor_.register_descriptor(sock.get(), impl.reactor_data_))
+ {
+ ec = boost::system::error_code(err,
+ boost::asio::error::get_system_category());
+ return ec;
+ }
+
+ impl.socket_ = sock.release();
+ impl.flags_ = 0;
+ impl.protocol_ = protocol;
+ ec = boost::system::error_code();
+ return ec;
+ }
+
+ // Assign a native socket to a socket implementation.
+ boost::system::error_code assign(implementation_type& impl,
+ const protocol_type& protocol, const native_type& native_socket,
+ boost::system::error_code& ec)
+ {
+ if (is_open(impl))
+ {
+ ec = boost::asio::error::already_open;
+ return ec;
+ }
+
+ if (int err = reactor_.register_descriptor(
+ native_socket, impl.reactor_data_))
+ {
+ ec = boost::system::error_code(err,
+ boost::asio::error::get_system_category());
+ return ec;
+ }
+
+ impl.socket_ = native_socket;
+ impl.flags_ = 0;
+ impl.protocol_ = protocol;
+ ec = boost::system::error_code();
+ return ec;
+ }
+
+ // Determine whether the socket is open.
+ bool is_open(const implementation_type& impl) const
+ {
+ return impl.socket_ != invalid_socket;
+ }
+
+ // Destroy a socket implementation.
+ boost::system::error_code close(implementation_type& impl,
+ boost::system::error_code& ec)
+ {
+ if (is_open(impl))
+ {
+ reactor_.close_descriptor(impl.socket_, impl.reactor_data_);
+
+ if (impl.flags_ & implementation_type::non_blocking)
+ {
+ ioctl_arg_type non_blocking = 0;
+ boost::system::error_code ignored_ec;
+ socket_ops::ioctl(impl.socket_, FIONBIO, &non_blocking, ignored_ec);
+ impl.flags_ &= ~implementation_type::non_blocking;
+ }
+
+ if (socket_ops::close(impl.socket_, ec) == socket_error_retval)
+ return ec;
+
+ impl.socket_ = invalid_socket;
+ }
+
+ ec = boost::system::error_code();
+ return ec;
+ }
+
+ // Get the native socket representation.
+ native_type native(implementation_type& impl)
+ {
+ return impl.socket_;
+ }
+
+ // Cancel all operations associated with the socket.
+ boost::system::error_code cancel(implementation_type& impl,
+ boost::system::error_code& ec)
+ {
+ if (!is_open(impl))
+ {
+ ec = boost::asio::error::bad_descriptor;
+ return ec;
+ }
+
+ reactor_.cancel_ops(impl.socket_, impl.reactor_data_);
+ ec = boost::system::error_code();
+ return ec;
+ }
+
+ // Determine whether the socket is at the out-of-band data mark.
+ bool at_mark(const implementation_type& impl,
+ boost::system::error_code& ec) const
+ {
+ if (!is_open(impl))
+ {
+ ec = boost::asio::error::bad_descriptor;
+ return false;
+ }
+
+ boost::asio::detail::ioctl_arg_type value = 0;
+ socket_ops::ioctl(impl.socket_, SIOCATMARK, &value, ec);
+#if defined(ENOTTY)
+ if (ec.value() == ENOTTY)
+ ec = boost::asio::error::not_socket;
+#endif // defined(ENOTTY)
+ return ec ? false : value != 0;
+ }
+
+ // Determine the number of bytes available for reading.
+ std::size_t available(const implementation_type& impl,
+ boost::system::error_code& ec) const
+ {
+ if (!is_open(impl))
+ {
+ ec = boost::asio::error::bad_descriptor;
+ return 0;
+ }
+
+ boost::asio::detail::ioctl_arg_type value = 0;
+ socket_ops::ioctl(impl.socket_, FIONREAD, &value, ec);
+#if defined(ENOTTY)
+ if (ec.value() == ENOTTY)
+ ec = boost::asio::error::not_socket;
+#endif // defined(ENOTTY)
+ return ec ? static_cast<std::size_t>(0) : static_cast<std::size_t>(value);
+ }
+
+ // Bind the socket to the specified local endpoint.
+ boost::system::error_code bind(implementation_type& impl,
+ const endpoint_type& endpoint, boost::system::error_code& ec)
+ {
+ if (!is_open(impl))
+ {
+ ec = boost::asio::error::bad_descriptor;
+ return ec;
+ }
+
+ socket_ops::bind(impl.socket_, endpoint.data(), endpoint.size(), ec);
+ return ec;
+ }
+
+ // Place the socket into the state where it will listen for new connections.
+ boost::system::error_code listen(implementation_type& impl, int backlog,
+ boost::system::error_code& ec)
+ {
+ if (!is_open(impl))
+ {
+ ec = boost::asio::error::bad_descriptor;
+ return ec;
+ }
+
+ socket_ops::listen(impl.socket_, backlog, ec);
+ return ec;
+ }
+
+ // Set a socket option.
+ template <typename Option>
+ boost::system::error_code set_option(implementation_type& impl,
+ const Option& option, boost::system::error_code& ec)
+ {
+ if (!is_open(impl))
+ {
+ ec = boost::asio::error::bad_descriptor;
+ return ec;
+ }
+
+ if (option.level(impl.protocol_) == custom_socket_option_level
+ && option.name(impl.protocol_) == enable_connection_aborted_option)
+ {
+ if (option.size(impl.protocol_) != sizeof(int))
+ {
+ ec = boost::asio::error::invalid_argument;
+ }
+ else
+ {
+ if (*reinterpret_cast<const int*>(option.data(impl.protocol_)))
+ impl.flags_ |= implementation_type::enable_connection_aborted;
+ else
+ impl.flags_ &= ~implementation_type::enable_connection_aborted;
+ ec = boost::system::error_code();
+ }
+ return ec;
+ }
+ else
+ {
+ if (option.level(impl.protocol_) == SOL_SOCKET
+ && option.name(impl.protocol_) == SO_LINGER)
+ {
+ impl.flags_ |= implementation_type::user_set_linger;
+ }
+
+ socket_ops::setsockopt(impl.socket_,
+ option.level(impl.protocol_), option.name(impl.protocol_),
+ option.data(impl.protocol_), option.size(impl.protocol_), ec);
+
+#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 (!ec && impl.protocol_.type() == SOCK_DGRAM
+ && option.level(impl.protocol_) == SOL_SOCKET
+ && option.name(impl.protocol_) == SO_REUSEADDR)
+ {
+ boost::system::error_code ignored_ec;
+ socket_ops::setsockopt(impl.socket_, SOL_SOCKET, SO_REUSEPORT,
+ option.data(impl.protocol_), option.size(impl.protocol_),
+ ignored_ec);
+ }
+#endif
+
+ return ec;
+ }
+ }
+
+ // Set a socket option.
+ template <typename Option>
+ boost::system::error_code get_option(const implementation_type& impl,
+ Option& option, boost::system::error_code& ec) const
+ {
+ if (!is_open(impl))
+ {
+ ec = boost::asio::error::bad_descriptor;
+ return ec;
+ }
+
+ if (option.level(impl.protocol_) == custom_socket_option_level
+ && option.name(impl.protocol_) == enable_connection_aborted_option)
+ {
+ if (option.size(impl.protocol_) != sizeof(int))
+ {
+ ec = boost::asio::error::invalid_argument;
+ }
+ else
+ {
+ int* target = reinterpret_cast<int*>(option.data(impl.protocol_));
+ if (impl.flags_ & implementation_type::enable_connection_aborted)
+ *target = 1;
+ else
+ *target = 0;
+ option.resize(impl.protocol_, sizeof(int));
+ ec = boost::system::error_code();
+ }
+ return ec;
+ }
+ else
+ {
+ size_t size = option.size(impl.protocol_);
+ socket_ops::getsockopt(impl.socket_,
+ option.level(impl.protocol_), option.name(impl.protocol_),
+ option.data(impl.protocol_), &size, ec);
+ if (!ec)
+ option.resize(impl.protocol_, size);
+ return ec;
+ }
+ }
+
+ // Perform an IO control command on the socket.
+ template <typename IO_Control_Command>
+ boost::system::error_code io_control(implementation_type& impl,
+ IO_Control_Command& command, boost::system::error_code& ec)
+ {
+ if (!is_open(impl))
+ {
+ ec = boost::asio::error::bad_descriptor;
+ return ec;
+ }
+
+ if (command.name() == static_cast<int>(FIONBIO))
+ {
+ // Flags are manipulated in a temporary variable so that the socket
+ // implementation is not updated unless the ioctl operation succeeds.
+ unsigned char new_flags = impl.flags_;
+ if (*static_cast<ioctl_arg_type*>(command.data()))
+ new_flags |= implementation_type::user_set_non_blocking;
+ else
+ new_flags &= ~implementation_type::user_set_non_blocking;
+
+ // Perform ioctl on socket if the non-blocking state has changed.
+ if (!(impl.flags_ & implementation_type::non_blocking)
+ && (new_flags & implementation_type::non_blocking))
+ {
+ ioctl_arg_type non_blocking = 1;
+ socket_ops::ioctl(impl.socket_, FIONBIO, &non_blocking, ec);
+ }
+ else if ((impl.flags_ & implementation_type::non_blocking)
+ && !(new_flags & implementation_type::non_blocking))
+ {
+ ioctl_arg_type non_blocking = 0;
+ socket_ops::ioctl(impl.socket_, FIONBIO, &non_blocking, ec);
+ }
+ else
+ {
+ ec = boost::system::error_code();
+ }
+
+ // Update socket implementation's flags only if successful.
+ if (!ec)
+ impl.flags_ = new_flags;
+ }
+ else
+ {
+ socket_ops::ioctl(impl.socket_, command.name(),
+ static_cast<ioctl_arg_type*>(command.data()), ec);
+ }
+ return ec;
+ }
+
+ // Get the local endpoint.
+ endpoint_type local_endpoint(const implementation_type& impl,
+ boost::system::error_code& ec) const
+ {
+ if (!is_open(impl))
+ {
+ ec = boost::asio::error::bad_descriptor;
+ return endpoint_type();
+ }
+
+ endpoint_type endpoint;
+ std::size_t addr_len = endpoint.capacity();
+ if (socket_ops::getsockname(impl.socket_, endpoint.data(), &addr_len, ec))
+ return endpoint_type();
+ endpoint.resize(addr_len);
+ return endpoint;
+ }
+
+ // Get the remote endpoint.
+ endpoint_type remote_endpoint(const implementation_type& impl,
+ boost::system::error_code& ec) const
+ {
+ if (!is_open(impl))
+ {
+ ec = boost::asio::error::bad_descriptor;
+ return endpoint_type();
+ }
+
+ endpoint_type endpoint;
+ std::size_t addr_len = endpoint.capacity();
+ if (socket_ops::getpeername(impl.socket_, endpoint.data(), &addr_len, ec))
+ return endpoint_type();
+ endpoint.resize(addr_len);
+ return endpoint;
+ }
+
+ /// Disable sends or receives on the socket.
+ boost::system::error_code shutdown(implementation_type& impl,
+ socket_base::shutdown_type what, boost::system::error_code& ec)
+ {
+ if (!is_open(impl))
+ {
+ ec = boost::asio::error::bad_descriptor;
+ return ec;
+ }
+
+ socket_ops::shutdown(impl.socket_, what, ec);
+ return ec;
+ }
+
+ // Send the given data to the peer.
+ template <typename ConstBufferSequence>
+ size_t send(implementation_type& impl, const ConstBufferSequence& buffers,
+ socket_base::message_flags flags, boost::system::error_code& ec)
+ {
+ if (!is_open(impl))
+ {
+ ec = boost::asio::error::bad_descriptor;
+ return 0;
+ }
+
+ // Copy buffers into array.
+ socket_ops::buf bufs[max_buffers];
+ typename ConstBufferSequence::const_iterator iter = buffers.begin();
+ typename ConstBufferSequence::const_iterator end = buffers.end();
+ size_t i = 0;
+ size_t total_buffer_size = 0;
+ for (; iter != end && i < max_buffers; ++iter, ++i)
+ {
+ boost::asio::const_buffer buffer(*iter);
+ socket_ops::init_buf(bufs[i],
+ boost::asio::buffer_cast<const void*>(buffer),
+ boost::asio::buffer_size(buffer));
+ total_buffer_size += boost::asio::buffer_size(buffer);
+ }
+
+ // A request to receive 0 bytes on a stream socket is a no-op.
+ if (impl.protocol_.type() == SOCK_STREAM && total_buffer_size == 0)
+ {
+ ec = boost::system::error_code();
+ return 0;
+ }
+
+ // Send the data.
+ for (;;)
+ {
+ // Try to complete the operation without blocking.
+ int bytes_sent = socket_ops::send(impl.socket_, bufs, i, flags, ec);
+
+ // Check if operation succeeded.
+ if (bytes_sent >= 0)
+ return bytes_sent;
+
+ // Operation failed.
+ if ((impl.flags_ & implementation_type::user_set_non_blocking)
+ || (ec != boost::asio::error::would_block
+ && ec != boost::asio::error::try_again))
+ return 0;
+
+ // Wait for socket to become ready.
+ if (socket_ops::poll_write(impl.socket_, ec) < 0)
+ return 0;
+ }
+ }
+
+ // Wait until data can be sent without blocking.
+ size_t send(implementation_type& impl, const null_buffers&,
+ socket_base::message_flags, boost::system::error_code& ec)
+ {
+ if (!is_open(impl))
+ {
+ ec = boost::asio::error::bad_descriptor;
+ return 0;
+ }
+
+ // Wait for socket to become ready.
+ socket_ops::poll_write(impl.socket_, ec);
+
+ return 0;
+ }
+
+ template <typename ConstBufferSequence, typename Handler>
+ class send_operation :
+ public handler_base_from_member<Handler>
+ {
+ public:
+ send_operation(socket_type socket, boost::asio::io_service& io_service,
+ const ConstBufferSequence& buffers, socket_base::message_flags flags,
+ Handler handler)
+ : handler_base_from_member<Handler>(handler),
+ socket_(socket),
+ io_service_(io_service),
+ work_(io_service),
+ buffers_(buffers),
+ flags_(flags)
+ {
+ }
+
+ bool perform(boost::system::error_code& ec,
+ std::size_t& bytes_transferred)
+ {
+ // Check whether the operation was successful.
+ if (ec)
+ {
+ bytes_transferred = 0;
+ return true;
+ }
+
+ // Copy buffers into array.
+ socket_ops::buf bufs[max_buffers];
+ typename ConstBufferSequence::const_iterator iter = buffers_.begin();
+ typename ConstBufferSequence::const_iterator end = buffers_.end();
+ size_t i = 0;
+ for (; iter != end && i < max_buffers; ++iter, ++i)
+ {
+ boost::asio::const_buffer buffer(*iter);
+ socket_ops::init_buf(bufs[i],
+ boost::asio::buffer_cast<const void*>(buffer),
+ boost::asio::buffer_size(buffer));
+ }
+
+ // Send the data.
+ int bytes = socket_ops::send(socket_, bufs, i, flags_, ec);
+
+ // Check if we need to run the operation again.
+ if (ec == boost::asio::error::would_block
+ || ec == boost::asio::error::try_again)
+ return false;
+
+ bytes_transferred = (bytes < 0 ? 0 : bytes);
+ return true;
+ }
+
+ void complete(const boost::system::error_code& ec,
+ std::size_t bytes_transferred)
+ {
+ io_service_.post(bind_handler(this->handler_, ec, bytes_transferred));
+ }
+
+ private:
+ socket_type socket_;
+ boost::asio::io_service& io_service_;
+ boost::asio::io_service::work work_;
+ ConstBufferSequence buffers_;
+ socket_base::message_flags flags_;
+ };
+
+ // 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& impl, const ConstBufferSequence& buffers,
+ socket_base::message_flags flags, Handler handler)
+ {
+ if (!is_open(impl))
+ {
+ this->get_io_service().post(bind_handler(handler,
+ boost::asio::error::bad_descriptor, 0));
+ }
+ else
+ {
+ if (impl.protocol_.type() == SOCK_STREAM)
+ {
+ // Determine total size of buffers.
+ typename ConstBufferSequence::const_iterator iter = buffers.begin();
+ typename ConstBufferSequence::const_iterator end = buffers.end();
+ size_t i = 0;
+ size_t total_buffer_size = 0;
+ for (; iter != end && i < max_buffers; ++iter, ++i)
+ {
+ boost::asio::const_buffer buffer(*iter);
+ total_buffer_size += boost::asio::buffer_size(buffer);
+ }
+
+ // A request to receive 0 bytes on a stream socket is a no-op.
+ if (total_buffer_size == 0)
+ {
+ this->get_io_service().post(bind_handler(handler,
+ boost::system::error_code(), 0));
+ return;
+ }
+ }
+
+ // Make socket non-blocking.
+ if (!(impl.flags_ & implementation_type::internal_non_blocking))
+ {
+ if (!(impl.flags_ & implementation_type::non_blocking))
+ {
+ ioctl_arg_type non_blocking = 1;
+ boost::system::error_code ec;
+ if (socket_ops::ioctl(impl.socket_, FIONBIO, &non_blocking, ec))
+ {
+ this->get_io_service().post(bind_handler(handler, ec, 0));
+ return;
+ }
+ }
+ impl.flags_ |= implementation_type::internal_non_blocking;
+ }
+
+ reactor_.start_write_op(impl.socket_, impl.reactor_data_,
+ send_operation<ConstBufferSequence, Handler>(
+ impl.socket_, this->get_io_service(), buffers, flags, handler));
+ }
+ }
+
+ template <typename Handler>
+ class null_buffers_operation :
+ public handler_base_from_member<Handler>
+ {
+ public:
+ null_buffers_operation(boost::asio::io_service& io_service, Handler handler)
+ : handler_base_from_member<Handler>(handler),
+ work_(io_service)
+ {
+ }
+
+ bool perform(boost::system::error_code&,
+ std::size_t& bytes_transferred)
+ {
+ bytes_transferred = 0;
+ return true;
+ }
+
+ void complete(const boost::system::error_code& ec,
+ std::size_t bytes_transferred)
+ {
+ work_.get_io_service().post(bind_handler(
+ this->handler_, ec, bytes_transferred));
+ }
+
+ private:
+ boost::asio::io_service::work work_;
+ };
+
+ // Start an asynchronous wait until data can be sent without blocking.
+ template <typename Handler>
+ void async_send(implementation_type& impl, const null_buffers&,
+ socket_base::message_flags, Handler handler)
+ {
+ if (!is_open(impl))
+ {
+ this->get_io_service().post(bind_handler(handler,
+ boost::asio::error::bad_descriptor, 0));
+ }
+ else
+ {
+ reactor_.start_write_op(impl.socket_, impl.reactor_data_,
+ null_buffers_operation<Handler>(this->get_io_service(), handler),
+ false);
+ }
+ }
+
+ // Send a datagram to the specified endpoint. Returns the number of bytes
+ // sent.
+ template <typename ConstBufferSequence>
+ size_t send_to(implementation_type& impl, const ConstBufferSequence& buffers,
+ const endpoint_type& destination, socket_base::message_flags flags,
+ boost::system::error_code& ec)
+ {
+ if (!is_open(impl))
+ {
+ ec = boost::asio::error::bad_descriptor;
+ return 0;
+ }
+
+ // Copy buffers into array.
+ socket_ops::buf bufs[max_buffers];
+ typename ConstBufferSequence::const_iterator iter = buffers.begin();
+ typename ConstBufferSequence::const_iterator end = buffers.end();
+ size_t i = 0;
+ for (; iter != end && i < max_buffers; ++iter, ++i)
+ {
+ boost::asio::const_buffer buffer(*iter);
+ socket_ops::init_buf(bufs[i],
+ boost::asio::buffer_cast<const void*>(buffer),
+ boost::asio::buffer_size(buffer));
+ }
+
+ // Send the data.
+ for (;;)
+ {
+ // Try to complete the operation without blocking.
+ int bytes_sent = socket_ops::sendto(impl.socket_, bufs, i, flags,
+ destination.data(), destination.size(), ec);
+
+ // Check if operation succeeded.
+ if (bytes_sent >= 0)
+ return bytes_sent;
+
+ // Operation failed.
+ if ((impl.flags_ & implementation_type::user_set_non_blocking)
+ || (ec != boost::asio::error::would_block
+ && ec != boost::asio::error::try_again))
+ return 0;
+
+ // Wait for socket to become ready.
+ if (socket_ops::poll_write(impl.socket_, ec) < 0)
+ return 0;
+ }
+ }
+
+ // Wait until data can be sent without blocking.
+ size_t send_to(implementation_type& impl, const null_buffers&,
+ socket_base::message_flags, const endpoint_type&,
+ boost::system::error_code& ec)
+ {
+ if (!is_open(impl))
+ {
+ ec = boost::asio::error::bad_descriptor;
+ return 0;
+ }
+
+ // Wait for socket to become ready.
+ socket_ops::poll_write(impl.socket_, ec);
+
+ return 0;
+ }
+
+ template <typename ConstBufferSequence, typename Handler>
+ class send_to_operation :
+ public handler_base_from_member<Handler>
+ {
+ public:
+ send_to_operation(socket_type socket, boost::asio::io_service& io_service,
+ const ConstBufferSequence& buffers, const endpoint_type& endpoint,
+ socket_base::message_flags flags, Handler handler)
+ : handler_base_from_member<Handler>(handler),
+ socket_(socket),
+ io_service_(io_service),
+ work_(io_service),
+ buffers_(buffers),
+ destination_(endpoint),
+ flags_(flags)
+ {
+ }
+
+ bool perform(boost::system::error_code& ec,
+ std::size_t& bytes_transferred)
+ {
+ // Check whether the operation was successful.
+ if (ec)
+ {
+ bytes_transferred = 0;
+ return true;
+ }
+
+ // Copy buffers into array.
+ socket_ops::buf bufs[max_buffers];
+ typename ConstBufferSequence::const_iterator iter = buffers_.begin();
+ typename ConstBufferSequence::const_iterator end = buffers_.end();
+ size_t i = 0;
+ for (; iter != end && i < max_buffers; ++iter, ++i)
+ {
+ boost::asio::const_buffer buffer(*iter);
+ socket_ops::init_buf(bufs[i],
+ boost::asio::buffer_cast<const void*>(buffer),
+ boost::asio::buffer_size(buffer));
+ }
+
+ // Send the data.
+ int bytes = socket_ops::sendto(socket_, bufs, i, flags_,
+ destination_.data(), destination_.size(), ec);
+
+ // Check if we need to run the operation again.
+ if (ec == boost::asio::error::would_block
+ || ec == boost::asio::error::try_again)
+ return false;
+
+ bytes_transferred = (bytes < 0 ? 0 : bytes);
+ return true;
+ }
+
+ void complete(const boost::system::error_code& ec,
+ std::size_t bytes_transferred)
+ {
+ io_service_.post(bind_handler(this->handler_, ec, bytes_transferred));
+ }
+
+ private:
+ socket_type socket_;
+ boost::asio::io_service& io_service_;
+ boost::asio::io_service::work work_;
+ ConstBufferSequence buffers_;
+ endpoint_type destination_;
+ socket_base::message_flags flags_;
+ };
+
+ // 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)
+ {
+ if (!is_open(impl))
+ {
+ this->get_io_service().post(bind_handler(handler,
+ boost::asio::error::bad_descriptor, 0));
+ }
+ else
+ {
+ // Make socket non-blocking.
+ if (!(impl.flags_ & implementation_type::internal_non_blocking))
+ {
+ if (!(impl.flags_ & implementation_type::non_blocking))
+ {
+ ioctl_arg_type non_blocking = 1;
+ boost::system::error_code ec;
+ if (socket_ops::ioctl(impl.socket_, FIONBIO, &non_blocking, ec))
+ {
+ this->get_io_service().post(bind_handler(handler, ec, 0));
+ return;
+ }
+ }
+ impl.flags_ |= implementation_type::internal_non_blocking;
+ }
+
+ reactor_.start_write_op(impl.socket_, impl.reactor_data_,
+ send_to_operation<ConstBufferSequence, Handler>(
+ impl.socket_, this->get_io_service(), buffers,
+ destination, flags, handler));
+ }
+ }
+
+ // Start an asynchronous wait until data can be sent without blocking.
+ template <typename Handler>
+ void async_send_to(implementation_type& impl, const null_buffers&,
+ socket_base::message_flags, const endpoint_type&, Handler handler)
+ {
+ if (!is_open(impl))
+ {
+ this->get_io_service().post(bind_handler(handler,
+ boost::asio::error::bad_descriptor, 0));
+ }
+ else
+ {
+ reactor_.start_write_op(impl.socket_, impl.reactor_data_,
+ null_buffers_operation<Handler>(this->get_io_service(), handler),
+ false);
+ }
+ }
+
+ // Receive some data from the peer. Returns the number of bytes received.
+ template <typename MutableBufferSequence>
+ size_t receive(implementation_type& impl,
+ const MutableBufferSequence& buffers,
+ socket_base::message_flags flags, boost::system::error_code& ec)
+ {
+ if (!is_open(impl))
+ {
+ ec = boost::asio::error::bad_descriptor;
+ return 0;
+ }
+
+ // Copy buffers into array.
+ socket_ops::buf bufs[max_buffers];
+ typename MutableBufferSequence::const_iterator iter = buffers.begin();
+ typename MutableBufferSequence::const_iterator end = buffers.end();
+ size_t i = 0;
+ size_t total_buffer_size = 0;
+ for (; iter != end && i < max_buffers; ++iter, ++i)
+ {
+ boost::asio::mutable_buffer buffer(*iter);
+ socket_ops::init_buf(bufs[i],
+ boost::asio::buffer_cast<void*>(buffer),
+ boost::asio::buffer_size(buffer));
+ total_buffer_size += boost::asio::buffer_size(buffer);
+ }
+
+ // A request to receive 0 bytes on a stream socket is a no-op.
+ if (impl.protocol_.type() == SOCK_STREAM && total_buffer_size == 0)
+ {
+ ec = boost::system::error_code();
+ return 0;
+ }
+
+ // Receive some data.
+ for (;;)
+ {
+ // Try to complete the operation without blocking.
+ int bytes_recvd = socket_ops::recv(impl.socket_, bufs, i, flags, ec);
+
+ // Check if operation succeeded.
+ if (bytes_recvd > 0)
+ return bytes_recvd;
+
+ // Check for EOF.
+ if (bytes_recvd == 0 && impl.protocol_.type() == SOCK_STREAM)
+ {
+ ec = boost::asio::error::eof;
+ return 0;
+ }
+
+ // Operation failed.
+ if ((impl.flags_ & implementation_type::user_set_non_blocking)
+ || (ec != boost::asio::error::would_block
+ && ec != boost::asio::error::try_again))
+ return 0;
+
+ // Wait for socket to become ready.
+ if (socket_ops::poll_read(impl.socket_, ec) < 0)
+ return 0;
+ }
+ }
+
+ // Wait until data can be received without blocking.
+ size_t receive(implementation_type& impl, const null_buffers&,
+ socket_base::message_flags, boost::system::error_code& ec)
+ {
+ if (!is_open(impl))
+ {
+ ec = boost::asio::error::bad_descriptor;
+ return 0;
+ }
+
+ // Wait for socket to become ready.
+ socket_ops::poll_read(impl.socket_, ec);
+
+ return 0;
+ }
+
+ template <typename MutableBufferSequence, typename Handler>
+ class receive_operation :
+ public handler_base_from_member<Handler>
+ {
+ public:
+ receive_operation(socket_type socket, int protocol_type,
+ boost::asio::io_service& io_service,
+ const MutableBufferSequence& buffers,
+ socket_base::message_flags flags, Handler handler)
+ : handler_base_from_member<Handler>(handler),
+ socket_(socket),
+ protocol_type_(protocol_type),
+ io_service_(io_service),
+ work_(io_service),
+ buffers_(buffers),
+ flags_(flags)
+ {
+ }
+
+ bool perform(boost::system::error_code& ec,
+ std::size_t& bytes_transferred)
+ {
+ // Check whether the operation was successful.
+ if (ec)
+ {
+ bytes_transferred = 0;
+ return true;
+ }
+
+ // Copy buffers into array.
+ socket_ops::buf bufs[max_buffers];
+ typename MutableBufferSequence::const_iterator iter = buffers_.begin();
+ typename MutableBufferSequence::const_iterator end = buffers_.end();
+ size_t i = 0;
+ for (; iter != end && i < max_buffers; ++iter, ++i)
+ {
+ boost::asio::mutable_buffer buffer(*iter);
+ socket_ops::init_buf(bufs[i],
+ boost::asio::buffer_cast<void*>(buffer),
+ boost::asio::buffer_size(buffer));
+ }
+
+ // Receive some data.
+ int bytes = socket_ops::recv(socket_, bufs, i, flags_, ec);
+ if (bytes == 0 && protocol_type_ == SOCK_STREAM)
+ ec = boost::asio::error::eof;
+
+ // Check if we need to run the operation again.
+ if (ec == boost::asio::error::would_block
+ || ec == boost::asio::error::try_again)
+ return false;
+
+ bytes_transferred = (bytes < 0 ? 0 : bytes);
+ return true;
+ }
+
+ void complete(const boost::system::error_code& ec,
+ std::size_t bytes_transferred)
+ {
+ io_service_.post(bind_handler(this->handler_, ec, bytes_transferred));
+ }
+
+ private:
+ socket_type socket_;
+ int protocol_type_;
+ boost::asio::io_service& io_service_;
+ boost::asio::io_service::work work_;
+ MutableBufferSequence buffers_;
+ socket_base::message_flags flags_;
+ };
+
+ // 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& impl,
+ const MutableBufferSequence& buffers,
+ socket_base::message_flags flags, Handler handler)
+ {
+ if (!is_open(impl))
+ {
+ this->get_io_service().post(bind_handler(handler,
+ boost::asio::error::bad_descriptor, 0));
+ }
+ else
+ {
+ if (impl.protocol_.type() == SOCK_STREAM)
+ {
+ // Determine total size of buffers.
+ typename MutableBufferSequence::const_iterator iter = buffers.begin();
+ typename MutableBufferSequence::const_iterator end = buffers.end();
+ size_t i = 0;
+ size_t total_buffer_size = 0;
+ for (; iter != end && i < max_buffers; ++iter, ++i)
+ {
+ boost::asio::mutable_buffer buffer(*iter);
+ total_buffer_size += boost::asio::buffer_size(buffer);
+ }
+
+ // A request to receive 0 bytes on a stream socket is a no-op.
+ if (total_buffer_size == 0)
+ {
+ this->get_io_service().post(bind_handler(handler,
+ boost::system::error_code(), 0));
+ return;
+ }
+ }
+
+ // Make socket non-blocking.
+ if (!(impl.flags_ & implementation_type::internal_non_blocking))
+ {
+ if (!(impl.flags_ & implementation_type::non_blocking))
+ {
+ ioctl_arg_type non_blocking = 1;
+ boost::system::error_code ec;
+ if (socket_ops::ioctl(impl.socket_, FIONBIO, &non_blocking, ec))
+ {
+ this->get_io_service().post(bind_handler(handler, ec, 0));
+ return;
+ }
+ }
+ impl.flags_ |= implementation_type::internal_non_blocking;
+ }
+
+ if (flags & socket_base::message_out_of_band)
+ {
+ reactor_.start_except_op(impl.socket_, impl.reactor_data_,
+ receive_operation<MutableBufferSequence, Handler>(
+ impl.socket_, impl.protocol_.type(),
+ this->get_io_service(), buffers, flags, handler));
+ }
+ else
+ {
+ reactor_.start_read_op(impl.socket_, impl.reactor_data_,
+ receive_operation<MutableBufferSequence, Handler>(
+ impl.socket_, impl.protocol_.type(),
+ this->get_io_service(), buffers, flags, handler));
+ }
+ }
+ }
+
+ // Wait until data can be received without blocking.
+ template <typename Handler>
+ void async_receive(implementation_type& impl, const null_buffers&,
+ socket_base::message_flags flags, Handler handler)
+ {
+ if (!is_open(impl))
+ {
+ this->get_io_service().post(bind_handler(handler,
+ boost::asio::error::bad_descriptor, 0));
+ }
+ else if (flags & socket_base::message_out_of_band)
+ {
+ reactor_.start_except_op(impl.socket_, impl.reactor_data_,
+ null_buffers_operation<Handler>(this->get_io_service(), handler));
+ }
+ else
+ {
+ reactor_.start_read_op(impl.socket_, impl.reactor_data_,
+ null_buffers_operation<Handler>(this->get_io_service(), handler),
+ false);
+ }
+ }
+
+ // Receive a datagram with the endpoint of the sender. Returns the number of
+ // bytes received.
+ template <typename MutableBufferSequence>
+ size_t receive_from(implementation_type& impl,
+ const MutableBufferSequence& buffers,
+ endpoint_type& sender_endpoint, socket_base::message_flags flags,
+ boost::system::error_code& ec)
+ {
+ if (!is_open(impl))
+ {
+ ec = boost::asio::error::bad_descriptor;
+ return 0;
+ }
+
+ // Copy buffers into array.
+ socket_ops::buf bufs[max_buffers];
+ typename MutableBufferSequence::const_iterator iter = buffers.begin();
+ typename MutableBufferSequence::const_iterator end = buffers.end();
+ size_t i = 0;
+ for (; iter != end && i < max_buffers; ++iter, ++i)
+ {
+ boost::asio::mutable_buffer buffer(*iter);
+ socket_ops::init_buf(bufs[i],
+ boost::asio::buffer_cast<void*>(buffer),
+ boost::asio::buffer_size(buffer));
+ }
+
+ // Receive some data.
+ for (;;)
+ {
+ // Try to complete the operation without blocking.
+ std::size_t addr_len = sender_endpoint.capacity();
+ int bytes_recvd = socket_ops::recvfrom(impl.socket_, bufs, i, flags,
+ sender_endpoint.data(), &addr_len, ec);
+
+ // Check if operation succeeded.
+ if (bytes_recvd > 0)
+ {
+ sender_endpoint.resize(addr_len);
+ return bytes_recvd;
+ }
+
+ // Check for EOF.
+ if (bytes_recvd == 0 && impl.protocol_.type() == SOCK_STREAM)
+ {
+ ec = boost::asio::error::eof;
+ return 0;
+ }
+
+ // Operation failed.
+ if ((impl.flags_ & implementation_type::user_set_non_blocking)
+ || (ec != boost::asio::error::would_block
+ && ec != boost::asio::error::try_again))
+ return 0;
+
+ // Wait for socket to become ready.
+ if (socket_ops::poll_read(impl.socket_, ec) < 0)
+ return 0;
+ }
+ }
+
+ // Wait until data can be received without blocking.
+ size_t receive_from(implementation_type& impl, const null_buffers&,
+ endpoint_type& sender_endpoint, socket_base::message_flags,
+ boost::system::error_code& ec)
+ {
+ if (!is_open(impl))
+ {
+ ec = boost::asio::error::bad_descriptor;
+ return 0;
+ }
+
+ // Wait for socket to become ready.
+ socket_ops::poll_read(impl.socket_, ec);
+
+ // Reset endpoint since it can be given no sensible value at this time.
+ sender_endpoint = endpoint_type();
+
+ return 0;
+ }
+
+ template <typename MutableBufferSequence, typename Handler>
+ class receive_from_operation :
+ public handler_base_from_member<Handler>
+ {
+ public:
+ receive_from_operation(socket_type socket, int protocol_type,
+ boost::asio::io_service& io_service,
+ const MutableBufferSequence& buffers, endpoint_type& endpoint,
+ socket_base::message_flags flags, Handler handler)
+ : handler_base_from_member<Handler>(handler),
+ socket_(socket),
+ protocol_type_(protocol_type),
+ io_service_(io_service),
+ work_(io_service),
+ buffers_(buffers),
+ sender_endpoint_(endpoint),
+ flags_(flags)
+ {
+ }
+
+ bool perform(boost::system::error_code& ec,
+ std::size_t& bytes_transferred)
+ {
+ // Check whether the operation was successful.
+ if (ec)
+ {
+ bytes_transferred = 0;
+ return true;
+ }
+
+ // Copy buffers into array.
+ socket_ops::buf bufs[max_buffers];
+ typename MutableBufferSequence::const_iterator iter = buffers_.begin();
+ typename MutableBufferSequence::const_iterator end = buffers_.end();
+ size_t i = 0;
+ for (; iter != end && i < max_buffers; ++iter, ++i)
+ {
+ boost::asio::mutable_buffer buffer(*iter);
+ socket_ops::init_buf(bufs[i],
+ boost::asio::buffer_cast<void*>(buffer),
+ boost::asio::buffer_size(buffer));
+ }
+
+ // Receive some data.
+ std::size_t addr_len = sender_endpoint_.capacity();
+ int bytes = socket_ops::recvfrom(socket_, bufs, i, flags_,
+ sender_endpoint_.data(), &addr_len, ec);
+ if (bytes == 0 && protocol_type_ == SOCK_STREAM)
+ ec = boost::asio::error::eof;
+
+ // Check if we need to run the operation again.
+ if (ec == boost::asio::error::would_block
+ || ec == boost::asio::error::try_again)
+ return false;
+
+ sender_endpoint_.resize(addr_len);
+ bytes_transferred = (bytes < 0 ? 0 : bytes);
+ return true;
+ }
+
+ void complete(const boost::system::error_code& ec,
+ std::size_t bytes_transferred)
+ {
+ io_service_.post(bind_handler(this->handler_, ec, bytes_transferred));
+ }
+
+ private:
+ socket_type socket_;
+ int protocol_type_;
+ boost::asio::io_service& io_service_;
+ boost::asio::io_service::work work_;
+ MutableBufferSequence buffers_;
+ endpoint_type& sender_endpoint_;
+ socket_base::message_flags flags_;
+ };
+
+ // 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)
+ {
+ if (!is_open(impl))
+ {
+ this->get_io_service().post(bind_handler(handler,
+ boost::asio::error::bad_descriptor, 0));
+ }
+ else
+ {
+ // Make socket non-blocking.
+ if (!(impl.flags_ & implementation_type::internal_non_blocking))
+ {
+ if (!(impl.flags_ & implementation_type::non_blocking))
+ {
+ ioctl_arg_type non_blocking = 1;
+ boost::system::error_code ec;
+ if (socket_ops::ioctl(impl.socket_, FIONBIO, &non_blocking, ec))
+ {
+ this->get_io_service().post(bind_handler(handler, ec, 0));
+ return;
+ }
+ }
+ impl.flags_ |= implementation_type::internal_non_blocking;
+ }
+
+ reactor_.start_read_op(impl.socket_, impl.reactor_data_,
+ receive_from_operation<MutableBufferSequence, Handler>(
+ impl.socket_, impl.protocol_.type(), this->get_io_service(),
+ buffers, sender_endpoint, flags, handler));
+ }
+ }
+
+ // 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)
+ {
+ if (!is_open(impl))
+ {
+ this->get_io_service().post(bind_handler(handler,
+ boost::asio::error::bad_descriptor, 0));
+ }
+ else
+ {
+ // Reset endpoint since it can be given no sensible value at this time.
+ sender_endpoint = endpoint_type();
+
+ if (flags & socket_base::message_out_of_band)
+ {
+ reactor_.start_except_op(impl.socket_, impl.reactor_data_,
+ null_buffers_operation<Handler>(this->get_io_service(), handler));
+ }
+ else
+ {
+ reactor_.start_read_op(impl.socket_, impl.reactor_data_,
+ null_buffers_operation<Handler>(this->get_io_service(), handler),
+ false);
+ }
+ }
+ }
+
+ // Accept a new connection.
+ template <typename Socket>
+ boost::system::error_code accept(implementation_type& impl,
+ Socket& peer, endpoint_type* peer_endpoint, boost::system::error_code& ec)
+ {
+ if (!is_open(impl))
+ {
+ ec = boost::asio::error::bad_descriptor;
+ return ec;
+ }
+
+ // We cannot accept a socket that is already open.
+ if (peer.is_open())
+ {
+ ec = boost::asio::error::already_open;
+ return ec;
+ }
+
+ // Accept a socket.
+ for (;;)
+ {
+ // Try to complete the operation without blocking.
+ boost::system::error_code ec;
+ socket_holder new_socket;
+ std::size_t addr_len = 0;
+ if (peer_endpoint)
+ {
+ addr_len = peer_endpoint->capacity();
+ new_socket.reset(socket_ops::accept(impl.socket_,
+ peer_endpoint->data(), &addr_len, ec));
+ }
+ else
+ {
+ new_socket.reset(socket_ops::accept(impl.socket_, 0, 0, ec));
+ }
+
+ // Check if operation succeeded.
+ if (new_socket.get() >= 0)
+ {
+ if (peer_endpoint)
+ peer_endpoint->resize(addr_len);
+ peer.assign(impl.protocol_, new_socket.get(), ec);
+ if (!ec)
+ new_socket.release();
+ return ec;
+ }
+
+ // Operation failed.
+ if (ec == boost::asio::error::would_block
+ || ec == boost::asio::error::try_again)
+ {
+ if (impl.flags_ & implementation_type::user_set_non_blocking)
+ return ec;
+ // Fall through to retry operation.
+ }
+ else if (ec == boost::asio::error::connection_aborted)
+ {
+ if (impl.flags_ & implementation_type::enable_connection_aborted)
+ return ec;
+ // Fall through to retry operation.
+ }
+#if defined(EPROTO)
+ else if (ec.value() == EPROTO)
+ {
+ if (impl.flags_ & implementation_type::enable_connection_aborted)
+ return ec;
+ // Fall through to retry operation.
+ }
+#endif // defined(EPROTO)
+ else
+ return ec;
+
+ // Wait for socket to become ready.
+ if (socket_ops::poll_read(impl.socket_, ec) < 0)
+ return ec;
+ }
+ }
+
+ template <typename Socket, typename Handler>
+ class accept_operation :
+ public handler_base_from_member<Handler>
+ {
+ public:
+ accept_operation(socket_type socket, boost::asio::io_service& io_service,
+ Socket& peer, const protocol_type& protocol,
+ endpoint_type* peer_endpoint, bool enable_connection_aborted,
+ Handler handler)
+ : handler_base_from_member<Handler>(handler),
+ socket_(socket),
+ io_service_(io_service),
+ work_(io_service),
+ peer_(peer),
+ protocol_(protocol),
+ peer_endpoint_(peer_endpoint),
+ enable_connection_aborted_(enable_connection_aborted)
+ {
+ }
+
+ bool perform(boost::system::error_code& ec, std::size_t&)
+ {
+ // Check whether the operation was successful.
+ if (ec)
+ return true;
+
+ // Accept the waiting connection.
+ socket_holder new_socket;
+ std::size_t addr_len = 0;
+ if (peer_endpoint_)
+ {
+ addr_len = peer_endpoint_->capacity();
+ new_socket.reset(socket_ops::accept(socket_,
+ peer_endpoint_->data(), &addr_len, ec));
+ }
+ else
+ {
+ new_socket.reset(socket_ops::accept(socket_, 0, 0, ec));
+ }
+
+ // Check if we need to run the operation again.
+ if (ec == boost::asio::error::would_block
+ || ec == boost::asio::error::try_again)
+ return false;
+ if (ec == boost::asio::error::connection_aborted
+ && !enable_connection_aborted_)
+ return false;
+#if defined(EPROTO)
+ if (ec.value() == EPROTO && !enable_connection_aborted_)
+ return false;
+#endif // defined(EPROTO)
+
+ // Transfer ownership of the new socket to the peer object.
+ if (!ec)
+ {
+ if (peer_endpoint_)
+ peer_endpoint_->resize(addr_len);
+ peer_.assign(protocol_, new_socket.get(), ec);
+ if (!ec)
+ new_socket.release();
+ }
+
+ return true;
+ }
+
+ void complete(const boost::system::error_code& ec, std::size_t)
+ {
+ io_service_.post(bind_handler(this->handler_, ec));
+ }
+
+ private:
+ socket_type socket_;
+ boost::asio::io_service& io_service_;
+ boost::asio::io_service::work work_;
+ Socket& peer_;
+ protocol_type protocol_;
+ endpoint_type* peer_endpoint_;
+ bool enable_connection_aborted_;
+ };
+
+ // 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)
+ {
+ if (!is_open(impl))
+ {
+ this->get_io_service().post(bind_handler(handler,
+ boost::asio::error::bad_descriptor));
+ }
+ else if (peer.is_open())
+ {
+ this->get_io_service().post(bind_handler(handler,
+ boost::asio::error::already_open));
+ }
+ else
+ {
+ // Make socket non-blocking.
+ if (!(impl.flags_ & implementation_type::internal_non_blocking))
+ {
+ if (!(impl.flags_ & implementation_type::non_blocking))
+ {
+ ioctl_arg_type non_blocking = 1;
+ boost::system::error_code ec;
+ if (socket_ops::ioctl(impl.socket_, FIONBIO, &non_blocking, ec))
+ {
+ this->get_io_service().post(bind_handler(handler, ec));
+ return;
+ }
+ }
+ impl.flags_ |= implementation_type::internal_non_blocking;
+ }
+
+ reactor_.start_read_op(impl.socket_, impl.reactor_data_,
+ accept_operation<Socket, Handler>(
+ impl.socket_, this->get_io_service(),
+ peer, impl.protocol_, peer_endpoint,
+ (impl.flags_ & implementation_type::enable_connection_aborted) != 0,
+ handler));
+ }
+ }
+
+ // Connect the socket to the specified endpoint.
+ boost::system::error_code connect(implementation_type& impl,
+ const endpoint_type& peer_endpoint, boost::system::error_code& ec)
+ {
+ if (!is_open(impl))
+ {
+ ec = boost::asio::error::bad_descriptor;
+ return ec;
+ }
+
+ // Perform the connect operation.
+ socket_ops::connect(impl.socket_,
+ peer_endpoint.data(), peer_endpoint.size(), ec);
+ if (ec != boost::asio::error::in_progress
+ && ec != boost::asio::error::would_block)
+ {
+ // The connect operation finished immediately.
+ return ec;
+ }
+
+ // Wait for socket to become ready.
+ if (socket_ops::poll_connect(impl.socket_, ec) < 0)
+ return ec;
+
+ // Get the error code from the connect operation.
+ int connect_error = 0;
+ size_t connect_error_len = sizeof(connect_error);
+ if (socket_ops::getsockopt(impl.socket_, SOL_SOCKET, SO_ERROR,
+ &connect_error, &connect_error_len, ec) == socket_error_retval)
+ return ec;
+
+ // Return the result of the connect operation.
+ ec = boost::system::error_code(connect_error,
+ boost::asio::error::get_system_category());
+ return ec;
+ }
+
+ template <typename Handler>
+ class connect_operation :
+ public handler_base_from_member<Handler>
+ {
+ public:
+ connect_operation(socket_type socket,
+ boost::asio::io_service& io_service, Handler handler)
+ : handler_base_from_member<Handler>(handler),
+ socket_(socket),
+ io_service_(io_service),
+ work_(io_service)
+ {
+ }
+
+ bool perform(boost::system::error_code& ec, std::size_t&)
+ {
+ // Check whether the operation was successful.
+ if (ec)
+ return true;
+
+ // Get the error code from the connect operation.
+ int connect_error = 0;
+ size_t connect_error_len = sizeof(connect_error);
+ if (socket_ops::getsockopt(socket_, SOL_SOCKET, SO_ERROR,
+ &connect_error, &connect_error_len, ec) == socket_error_retval)
+ return true;
+
+ // The connection failed so the handler will be posted with an error code.
+ if (connect_error)
+ {
+ ec = boost::system::error_code(connect_error,
+ boost::asio::error::get_system_category());
+ return true;
+ }
+
+ return true;
+ }
+
+ void complete(const boost::system::error_code& ec, std::size_t)
+ {
+ io_service_.post(bind_handler(this->handler_, ec));
+ }
+
+ private:
+ socket_type socket_;
+ boost::asio::io_service& io_service_;
+ boost::asio::io_service::work work_;
+ };
+
+ // Start an asynchronous connect.
+ template <typename Handler>
+ void async_connect(implementation_type& impl,
+ const endpoint_type& peer_endpoint, Handler handler)
+ {
+ if (!is_open(impl))
+ {
+ this->get_io_service().post(bind_handler(handler,
+ boost::asio::error::bad_descriptor));
+ return;
+ }
+
+ // Make socket non-blocking.
+ if (!(impl.flags_ & implementation_type::internal_non_blocking))
+ {
+ if (!(impl.flags_ & implementation_type::non_blocking))
+ {
+ ioctl_arg_type non_blocking = 1;
+ boost::system::error_code ec;
+ if (socket_ops::ioctl(impl.socket_, FIONBIO, &non_blocking, ec))
+ {
+ this->get_io_service().post(bind_handler(handler, ec));
+ return;
+ }
+ }
+ impl.flags_ |= implementation_type::internal_non_blocking;
+ }
+
+ // Start the connect operation. The socket is already marked as non-blocking
+ // so the connection will take place asynchronously.
+ boost::system::error_code ec;
+ if (socket_ops::connect(impl.socket_, peer_endpoint.data(),
+ peer_endpoint.size(), ec) == 0)
+ {
+ // The connect operation has finished successfully so we need to post the
+ // handler immediately.
+ this->get_io_service().post(bind_handler(handler,
+ boost::system::error_code()));
+ }
+ else if (ec == boost::asio::error::in_progress
+ || ec == boost::asio::error::would_block)
+ {
+ // The connection is happening in the background, and we need to wait
+ // until the socket becomes writeable.
+ reactor_.start_connect_op(impl.socket_, impl.reactor_data_,
+ connect_operation<Handler>(impl.socket_,
+ this->get_io_service(), handler));
+ }
+ else
+ {
+ // The connect operation has failed, so post the handler immediately.
+ this->get_io_service().post(bind_handler(handler, ec));
+ }
+ }
+
+private:
+ // The selector that performs event demultiplexing for the service.
+ Reactor& reactor_;
+};
+
+} // namespace detail
+} // namespace asio
+} // namespace boost
+
+#include <boost/asio/detail/pop_options.hpp>
+
+#endif // BOOST_ASIO_DETAIL_REACTIVE_SOCKET_SERVICE_HPP
diff --git a/3rdParty/Boost/boost/asio/detail/reactor_op_queue.hpp b/3rdParty/Boost/boost/asio/detail/reactor_op_queue.hpp
new file mode 100644
index 0000000..0fbbf23
--- /dev/null
+++ b/3rdParty/Boost/boost/asio/detail/reactor_op_queue.hpp
@@ -0,0 +1,456 @@
+//
+// reactor_op_queue.hpp
+// ~~~~~~~~~~~~~~~~~~~~
+//
+// Copyright (c) 2003-2008 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 BOOST_ASIO_DETAIL_REACTOR_OP_QUEUE_HPP
+#define BOOST_ASIO_DETAIL_REACTOR_OP_QUEUE_HPP
+
+#if defined(_MSC_VER) && (_MSC_VER >= 1200)
+# pragma once
+#endif // defined(_MSC_VER) && (_MSC_VER >= 1200)
+
+#include <boost/asio/detail/push_options.hpp>
+
+#include <boost/asio/detail/push_options.hpp>
+#include <memory>
+#include <boost/asio/detail/pop_options.hpp>
+
+#include <boost/asio/error.hpp>
+#include <boost/asio/detail/handler_alloc_helpers.hpp>
+#include <boost/asio/detail/hash_map.hpp>
+#include <boost/asio/detail/noncopyable.hpp>
+
+namespace boost {
+namespace asio {
+namespace detail {
+
+template <typename Descriptor>
+class reactor_op_queue
+ : private noncopyable
+{
+public:
+ // Constructor.
+ reactor_op_queue()
+ : operations_(),
+ cancelled_operations_(0),
+ complete_operations_(0)
+ {
+ }
+
+ // 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.
+ template <typename Operation>
+ bool enqueue_operation(Descriptor descriptor, Operation operation)
+ {
+ // Allocate and construct an object to wrap the handler.
+ typedef handler_alloc_traits<Operation, op<Operation> > alloc_traits;
+ raw_handler_ptr<alloc_traits> raw_ptr(operation);
+ handler_ptr<alloc_traits> ptr(raw_ptr, descriptor, operation);
+
+ typedef typename operation_map::iterator iterator;
+ typedef typename operation_map::value_type value_type;
+ std::pair<iterator, bool> entry =
+ operations_.insert(value_type(descriptor, ptr.get()));
+ if (entry.second)
+ {
+ ptr.release();
+ return true;
+ }
+
+ op_base* current_op = entry.first->second;
+ while (current_op->next_)
+ current_op = current_op->next_;
+ current_op->next_ = ptr.release();
+
+ return false;
+ }
+
+ // Cancel all operations associated with the descriptor. Any operations
+ // pending for the descriptor will be notified that they have been cancelled
+ // next time perform_cancellations is called. 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)
+ {
+ typename operation_map::iterator i = operations_.find(descriptor);
+ if (i != operations_.end())
+ {
+ op_base* last_op = i->second;
+ while (last_op->next_)
+ last_op = last_op->next_;
+ last_op->next_ = cancelled_operations_;
+ cancelled_operations_ = i->second;
+ operations_.erase(i);
+ return true;
+ }
+
+ return false;
+ }
+
+ // 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 first operation corresponding to the descriptor. Returns true
+ // if there are more operations queued for the descriptor.
+ bool perform_operation(Descriptor descriptor,
+ const boost::system::error_code& result)
+ {
+ typename operation_map::iterator i = operations_.find(descriptor);
+ if (i != operations_.end())
+ {
+ op_base* this_op = i->second;
+ i->second = this_op->next_;
+ this_op->next_ = complete_operations_;
+ complete_operations_ = this_op;
+ bool done = this_op->perform(result);
+ if (done)
+ {
+ // Operation has finished.
+ if (i->second)
+ {
+ return true;
+ }
+ else
+ {
+ operations_.erase(i);
+ return false;
+ }
+ }
+ else
+ {
+ // Operation wants to be called again. Leave it at the front of the
+ // queue for this descriptor, and remove from the completed list.
+ complete_operations_ = this_op->next_;
+ this_op->next_ = i->second;
+ i->second = this_op;
+ return true;
+ }
+ }
+ return false;
+ }
+
+ // Perform all operations corresponding to the descriptor.
+ void perform_all_operations(Descriptor descriptor,
+ const boost::system::error_code& result)
+ {
+ typename operation_map::iterator i = operations_.find(descriptor);
+ if (i != operations_.end())
+ {
+ while (i->second)
+ {
+ op_base* this_op = i->second;
+ i->second = this_op->next_;
+ this_op->next_ = complete_operations_;
+ complete_operations_ = this_op;
+ bool done = this_op->perform(result);
+ if (!done)
+ {
+ // Operation has not finished yet, so leave at front of queue, and
+ // remove from the completed list.
+ complete_operations_ = this_op->next_;
+ this_op->next_ = i->second;
+ i->second = this_op;
+ return;
+ }
+ }
+ operations_.erase(i);
+ }
+ }
+
+ // Fill a descriptor set with the descriptors corresponding to each active
+ // operation.
+ template <typename Descriptor_Set>
+ void get_descriptors(Descriptor_Set& descriptors)
+ {
+ typename operation_map::iterator i = operations_.begin();
+ while (i != operations_.end())
+ {
+ Descriptor descriptor = i->first;
+ ++i;
+ if (!descriptors.set(descriptor))
+ {
+ boost::system::error_code ec(error::fd_set_failure);
+ perform_all_operations(descriptor, ec);
+ }
+ }
+ }
+
+ // Perform the operations corresponding to the ready file descriptors
+ // contained in the given descriptor set.
+ template <typename Descriptor_Set>
+ void perform_operations_for_descriptors(const Descriptor_Set& descriptors,
+ const boost::system::error_code& result)
+ {
+ typename operation_map::iterator i = operations_.begin();
+ while (i != operations_.end())
+ {
+ typename operation_map::iterator op_iter = i++;
+ if (descriptors.is_set(op_iter->first))
+ {
+ op_base* this_op = op_iter->second;
+ op_iter->second = this_op->next_;
+ this_op->next_ = complete_operations_;
+ complete_operations_ = this_op;
+ bool done = this_op->perform(result);
+ if (done)
+ {
+ if (!op_iter->second)
+ operations_.erase(op_iter);
+ }
+ else
+ {
+ // Operation has not finished yet, so leave at front of queue, and
+ // remove from the completed list.
+ complete_operations_ = this_op->next_;
+ this_op->next_ = op_iter->second;
+ op_iter->second = this_op;
+ }
+ }
+ }
+ }
+
+ // Perform any pending cancels for operations.
+ void perform_cancellations()
+ {
+ while (cancelled_operations_)
+ {
+ op_base* this_op = cancelled_operations_;
+ cancelled_operations_ = this_op->next_;
+ this_op->next_ = complete_operations_;
+ complete_operations_ = this_op;
+ this_op->perform(boost::asio::error::operation_aborted);
+ }
+ }
+
+ // Complete all operations that are waiting to be completed.
+ void complete_operations()
+ {
+ while (complete_operations_)
+ {
+ op_base* next_op = complete_operations_->next_;
+ complete_operations_->next_ = 0;
+ complete_operations_->complete();
+ complete_operations_ = next_op;
+ }
+ }
+
+ // Destroy all operations owned by the queue.
+ void destroy_operations()
+ {
+ while (cancelled_operations_)
+ {
+ op_base* next_op = cancelled_operations_->next_;
+ cancelled_operations_->next_ = 0;
+ cancelled_operations_->destroy();
+ cancelled_operations_ = next_op;
+ }
+
+ while (complete_operations_)
+ {
+ op_base* next_op = complete_operations_->next_;
+ complete_operations_->next_ = 0;
+ complete_operations_->destroy();
+ complete_operations_ = next_op;
+ }
+
+ typename operation_map::iterator i = operations_.begin();
+ while (i != operations_.end())
+ {
+ typename operation_map::iterator op_iter = i++;
+ op_base* curr_op = op_iter->second;
+ operations_.erase(op_iter);
+ while (curr_op)
+ {
+ op_base* next_op = curr_op->next_;
+ curr_op->next_ = 0;
+ curr_op->destroy();
+ curr_op = next_op;
+ }
+ }
+ }
+
+private:
+ // Base class for reactor operations. A function pointer is used instead of
+ // virtual functions to avoid the associated overhead.
+ class op_base
+ {
+ public:
+ // Get the descriptor associated with the operation.
+ Descriptor descriptor() const
+ {
+ return descriptor_;
+ }
+
+ // Perform the operation.
+ bool perform(const boost::system::error_code& result)
+ {
+ result_ = result;
+ return perform_func_(this, result_, bytes_transferred_);
+ }
+
+ // Destroy the operation and post the handler.
+ void complete()
+ {
+ complete_func_(this, result_, bytes_transferred_);
+ }
+
+ // Destroy the operation.
+ void destroy()
+ {
+ destroy_func_(this);
+ }
+
+ protected:
+ typedef bool (*perform_func_type)(op_base*,
+ boost::system::error_code&, std::size_t&);
+ typedef void (*complete_func_type)(op_base*,
+ const boost::system::error_code&, std::size_t);
+ typedef void (*destroy_func_type)(op_base*);
+
+ // Construct an operation for the given descriptor.
+ op_base(perform_func_type perform_func, complete_func_type complete_func,
+ destroy_func_type destroy_func, Descriptor descriptor)
+ : perform_func_(perform_func),
+ complete_func_(complete_func),
+ destroy_func_(destroy_func),
+ descriptor_(descriptor),
+ result_(),
+ bytes_transferred_(0),
+ next_(0)
+ {
+ }
+
+ // Prevent deletion through this type.
+ ~op_base()
+ {
+ }
+
+ private:
+ friend class reactor_op_queue<Descriptor>;
+
+ // The function to be called to perform the operation.
+ perform_func_type perform_func_;
+
+ // The function to be called to delete the operation and post the handler.
+ complete_func_type complete_func_;
+
+ // The function to be called to delete the operation.
+ destroy_func_type destroy_func_;
+
+ // The descriptor associated with the operation.
+ Descriptor descriptor_;
+
+ // The result of the operation.
+ boost::system::error_code result_;
+
+ // The number of bytes transferred in the operation.
+ std::size_t bytes_transferred_;
+
+ // The next operation for the same file descriptor.
+ op_base* next_;
+ };
+
+ // Adaptor class template for operations.
+ template <typename Operation>
+ class op
+ : public op_base
+ {
+ public:
+ // Constructor.
+ op(Descriptor descriptor, Operation operation)
+ : op_base(&op<Operation>::do_perform, &op<Operation>::do_complete,
+ &op<Operation>::do_destroy, descriptor),
+ operation_(operation)
+ {
+ }
+
+ // Perform the operation.
+ static bool do_perform(op_base* base,
+ boost::system::error_code& result, std::size_t& bytes_transferred)
+ {
+ return static_cast<op<Operation>*>(base)->operation_.perform(
+ result, bytes_transferred);
+ }
+
+ // Destroy the operation and post the handler.
+ static void do_complete(op_base* base,
+ const boost::system::error_code& result, std::size_t bytes_transferred)
+ {
+ // Take ownership of the operation object.
+ typedef op<Operation> this_type;
+ this_type* this_op(static_cast<this_type*>(base));
+ typedef handler_alloc_traits<Operation, this_type> alloc_traits;
+ handler_ptr<alloc_traits> ptr(this_op->operation_, this_op);
+
+ // Make a copy of the error_code and the operation so that the memory can
+ // be deallocated before the upcall is made.
+ boost::system::error_code ec(result);
+ Operation operation(this_op->operation_);
+
+ // Free the memory associated with the operation.
+ ptr.reset();
+
+ // Make the upcall.
+ operation.complete(ec, bytes_transferred);
+ }
+
+ // Destroy the operation.
+ static void do_destroy(op_base* base)
+ {
+ // Take ownership of the operation object.
+ typedef op<Operation> this_type;
+ this_type* this_op(static_cast<this_type*>(base));
+ typedef handler_alloc_traits<Operation, this_type> alloc_traits;
+ handler_ptr<alloc_traits> ptr(this_op->operation_, this_op);
+
+ // A sub-object of the operation may be the true owner of the memory
+ // associated with the operation. Consequently, a local copy of the
+ // operation is required to ensure that any owning sub-object remains
+ // valid until after we have deallocated the memory here.
+ Operation operation(this_op->operation_);
+ (void)operation;
+
+ // Free the memory associated with the operation.
+ ptr.reset();
+ }
+
+ private:
+ Operation operation_;
+ };
+
+ // The type for a map of operations.
+ typedef hash_map<Descriptor, op_base*> operation_map;
+
+ // The operations that are currently executing asynchronously.
+ operation_map operations_;
+
+ // The list of operations that have been cancelled.
+ op_base* cancelled_operations_;
+
+ // The list of operations waiting to be completed.
+ op_base* complete_operations_;
+};
+
+} // namespace detail
+} // namespace asio
+} // namespace boost
+
+#include <boost/asio/detail/pop_options.hpp>
+
+#endif // BOOST_ASIO_DETAIL_REACTOR_OP_QUEUE_HPP
diff --git a/3rdParty/Boost/boost/asio/detail/resolver_service.hpp b/3rdParty/Boost/boost/asio/detail/resolver_service.hpp
new file mode 100644
index 0000000..9b0aac9
--- /dev/null
+++ b/3rdParty/Boost/boost/asio/detail/resolver_service.hpp
@@ -0,0 +1,359 @@
+//
+// resolver_service.hpp
+// ~~~~~~~~~~~~~~~~~~~~
+//
+// Copyright (c) 2003-2008 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 BOOST_ASIO_DETAIL_RESOLVER_SERVICE_HPP
+#define BOOST_ASIO_DETAIL_RESOLVER_SERVICE_HPP
+
+#if defined(_MSC_VER) && (_MSC_VER >= 1200)
+# pragma once
+#endif // defined(_MSC_VER) && (_MSC_VER >= 1200)
+
+#include <boost/asio/detail/push_options.hpp>
+
+#include <boost/asio/detail/push_options.hpp>
+#include <cstring>
+#include <boost/scoped_ptr.hpp>
+#include <boost/shared_ptr.hpp>
+#include <boost/weak_ptr.hpp>
+#include <boost/asio/detail/pop_options.hpp>
+
+#include <boost/asio/error.hpp>
+#include <boost/asio/io_service.hpp>
+#include <boost/asio/detail/bind_handler.hpp>
+#include <boost/asio/detail/mutex.hpp>
+#include <boost/asio/detail/noncopyable.hpp>
+#include <boost/asio/detail/service_base.hpp>
+#include <boost/asio/detail/socket_ops.hpp>
+#include <boost/asio/detail/socket_types.hpp>
+#include <boost/asio/detail/thread.hpp>
+
+namespace boost {
+namespace asio {
+namespace detail {
+
+template <typename Protocol>
+class resolver_service
+ : public boost::asio::detail::service_base<resolver_service<Protocol> >
+{
+private:
+ // Helper class to perform exception-safe cleanup of addrinfo objects.
+ class auto_addrinfo
+ : private boost::asio::detail::noncopyable
+ {
+ public:
+ explicit auto_addrinfo(boost::asio::detail::addrinfo_type* ai)
+ : ai_(ai)
+ {
+ }
+
+ ~auto_addrinfo()
+ {
+ if (ai_)
+ socket_ops::freeaddrinfo(ai_);
+ }
+
+ operator boost::asio::detail::addrinfo_type*()
+ {
+ return ai_;
+ }
+
+ private:
+ boost::asio::detail::addrinfo_type* ai_;
+ };
+
+public:
+ // The implementation type of the resolver. The shared pointer is used as a
+ // cancellation token to indicate to the background thread that the operation
+ // has been cancelled.
+ typedef boost::shared_ptr<void> implementation_type;
+ struct noop_deleter { void operator()(void*) {} };
+
+ // The endpoint type.
+ typedef typename Protocol::endpoint endpoint_type;
+
+ // The query type.
+ typedef typename Protocol::resolver_query query_type;
+
+ // The iterator type.
+ typedef typename Protocol::resolver_iterator iterator_type;
+
+ // Constructor.
+ resolver_service(boost::asio::io_service& io_service)
+ : boost::asio::detail::service_base<
+ resolver_service<Protocol> >(io_service),
+ mutex_(),
+ work_io_service_(new boost::asio::io_service),
+ work_(new boost::asio::io_service::work(*work_io_service_)),
+ work_thread_(0)
+ {
+ }
+
+ // Destructor.
+ ~resolver_service()
+ {
+ shutdown_service();
+ }
+
+ // Destroy all user-defined handler objects owned by the service.
+ void shutdown_service()
+ {
+ work_.reset();
+ if (work_io_service_)
+ {
+ work_io_service_->stop();
+ if (work_thread_)
+ {
+ work_thread_->join();
+ work_thread_.reset();
+ }
+ work_io_service_.reset();
+ }
+ }
+
+ // Construct a new resolver implementation.
+ void construct(implementation_type& impl)
+ {
+ impl.reset(static_cast<void*>(0), noop_deleter());
+ }
+
+ // Destroy a resolver implementation.
+ void destroy(implementation_type&)
+ {
+ }
+
+ // Cancel pending asynchronous operations.
+ void cancel(implementation_type& impl)
+ {
+ impl.reset(static_cast<void*>(0), noop_deleter());
+ }
+
+ // Resolve a query to a list of entries.
+ iterator_type resolve(implementation_type&, const query_type& query,
+ boost::system::error_code& ec)
+ {
+ boost::asio::detail::addrinfo_type* address_info = 0;
+ std::string host_name = query.host_name();
+ std::string service_name = query.service_name();
+ boost::asio::detail::addrinfo_type hints = query.hints();
+
+ socket_ops::getaddrinfo(host_name.length() ? host_name.c_str() : 0,
+ service_name.c_str(), &hints, &address_info, ec);
+ auto_addrinfo auto_address_info(address_info);
+
+ if (ec)
+ return iterator_type();
+
+ return iterator_type::create(address_info, host_name, service_name);
+ }
+
+ template <typename Handler>
+ class resolve_query_handler
+ {
+ public:
+ resolve_query_handler(implementation_type impl, const query_type& query,
+ boost::asio::io_service& io_service, Handler handler)
+ : impl_(impl),
+ query_(query),
+ io_service_(io_service),
+ work_(io_service),
+ handler_(handler)
+ {
+ }
+
+ void operator()()
+ {
+ // Check if the operation has been cancelled.
+ if (impl_.expired())
+ {
+ iterator_type iterator;
+ io_service_.post(boost::asio::detail::bind_handler(handler_,
+ boost::asio::error::operation_aborted, iterator));
+ return;
+ }
+
+ // Perform the blocking host resolution operation.
+ boost::asio::detail::addrinfo_type* address_info = 0;
+ std::string host_name = query_.host_name();
+ std::string service_name = query_.service_name();
+ boost::asio::detail::addrinfo_type hints = query_.hints();
+ boost::system::error_code ec;
+ socket_ops::getaddrinfo(host_name.length() ? host_name.c_str() : 0,
+ service_name.c_str(), &hints, &address_info, ec);
+ auto_addrinfo auto_address_info(address_info);
+
+ // Invoke the handler and pass the result.
+ iterator_type iterator;
+ if (!ec)
+ iterator = iterator_type::create(address_info, host_name, service_name);
+ io_service_.post(boost::asio::detail::bind_handler(
+ handler_, ec, iterator));
+ }
+
+ private:
+ boost::weak_ptr<void> impl_;
+ query_type query_;
+ boost::asio::io_service& io_service_;
+ boost::asio::io_service::work work_;
+ Handler handler_;
+ };
+
+ // Asynchronously resolve a query to a list of entries.
+ template <typename Handler>
+ void async_resolve(implementation_type& impl, const query_type& query,
+ Handler handler)
+ {
+ if (work_io_service_)
+ {
+ start_work_thread();
+ work_io_service_->post(
+ resolve_query_handler<Handler>(
+ impl, query, this->get_io_service(), handler));
+ }
+ }
+
+ // Resolve an endpoint to a list of entries.
+ iterator_type resolve(implementation_type&,
+ const endpoint_type& endpoint, boost::system::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.
+ char host_name[NI_MAXHOST];
+ char service_name[NI_MAXSERV];
+ int flags = endpoint.protocol().type() == SOCK_DGRAM ? NI_DGRAM : 0;
+ socket_ops::getnameinfo(endpoint.data(), endpoint.size(),
+ host_name, NI_MAXHOST, service_name, NI_MAXSERV, flags, ec);
+ if (ec)
+ {
+ flags |= NI_NUMERICSERV;
+ socket_ops::getnameinfo(endpoint.data(), endpoint.size(),
+ host_name, NI_MAXHOST, service_name, NI_MAXSERV, flags, ec);
+ }
+
+ if (ec)
+ return iterator_type();
+
+ return iterator_type::create(endpoint, host_name, service_name);
+ }
+
+ template <typename Handler>
+ class resolve_endpoint_handler
+ {
+ public:
+ resolve_endpoint_handler(implementation_type impl,
+ const endpoint_type& endpoint, boost::asio::io_service& io_service,
+ Handler handler)
+ : impl_(impl),
+ endpoint_(endpoint),
+ io_service_(io_service),
+ work_(io_service),
+ handler_(handler)
+ {
+ }
+
+ void operator()()
+ {
+ // Check if the operation has been cancelled.
+ if (impl_.expired())
+ {
+ iterator_type iterator;
+ io_service_.post(boost::asio::detail::bind_handler(handler_,
+ boost::asio::error::operation_aborted, iterator));
+ return;
+ }
+
+
+ // First try resolving with the service name. If that fails try resolving
+ // but allow the service to be returned as a number.
+ char host_name[NI_MAXHOST];
+ char service_name[NI_MAXSERV];
+ int flags = endpoint_.protocol().type() == SOCK_DGRAM ? NI_DGRAM : 0;
+ boost::system::error_code ec;
+ socket_ops::getnameinfo(endpoint_.data(), endpoint_.size(),
+ host_name, NI_MAXHOST, service_name, NI_MAXSERV, flags, ec);
+ if (ec)
+ {
+ flags |= NI_NUMERICSERV;
+ socket_ops::getnameinfo(endpoint_.data(), endpoint_.size(),
+ host_name, NI_MAXHOST, service_name, NI_MAXSERV, flags, ec);
+ }
+
+ // Invoke the handler and pass the result.
+ iterator_type iterator;
+ if (!ec)
+ iterator = iterator_type::create(endpoint_, host_name, service_name);
+ io_service_.post(boost::asio::detail::bind_handler(
+ handler_, ec, iterator));
+ }
+
+ private:
+ boost::weak_ptr<void> impl_;
+ endpoint_type endpoint_;
+ boost::asio::io_service& io_service_;
+ boost::asio::io_service::work work_;
+ Handler handler_;
+ };
+
+ // Asynchronously resolve an endpoint to a list of entries.
+ template <typename Handler>
+ void async_resolve(implementation_type& impl, const endpoint_type& endpoint,
+ Handler handler)
+ {
+ if (work_io_service_)
+ {
+ start_work_thread();
+ work_io_service_->post(
+ resolve_endpoint_handler<Handler>(
+ impl, endpoint, this->get_io_service(), handler));
+ }
+ }
+
+private:
+ // Helper class to run the work io_service in a thread.
+ class work_io_service_runner
+ {
+ public:
+ work_io_service_runner(boost::asio::io_service& io_service)
+ : io_service_(io_service) {}
+ void operator()() { io_service_.run(); }
+ private:
+ boost::asio::io_service& io_service_;
+ };
+
+ // Start the work thread if it's not already running.
+ void start_work_thread()
+ {
+ boost::asio::detail::mutex::scoped_lock lock(mutex_);
+ if (!work_thread_)
+ {
+ work_thread_.reset(new boost::asio::detail::thread(
+ work_io_service_runner(*work_io_service_)));
+ }
+ }
+
+ // Mutex to protect access to internal data.
+ boost::asio::detail::mutex mutex_;
+
+ // Private io_service used for performing asynchronous host resolution.
+ boost::scoped_ptr<boost::asio::io_service> work_io_service_;
+
+ // Work for the private io_service to perform.
+ boost::scoped_ptr<boost::asio::io_service::work> work_;
+
+ // Thread used for running the work io_service's run loop.
+ boost::scoped_ptr<boost::asio::detail::thread> work_thread_;
+};
+
+} // namespace detail
+} // namespace asio
+} // namespace boost
+
+#include <boost/asio/detail/pop_options.hpp>
+
+#endif // BOOST_ASIO_DETAIL_RESOLVER_SERVICE_HPP
diff --git a/3rdParty/Boost/boost/asio/detail/scoped_lock.hpp b/3rdParty/Boost/boost/asio/detail/scoped_lock.hpp
new file mode 100644
index 0000000..1dd2842
--- /dev/null
+++ b/3rdParty/Boost/boost/asio/detail/scoped_lock.hpp
@@ -0,0 +1,93 @@
+//
+// scoped_lock.hpp
+// ~~~~~~~~~~~~~~~
+//
+// Copyright (c) 2003-2008 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 BOOST_ASIO_DETAIL_SCOPED_LOCK_HPP
+#define BOOST_ASIO_DETAIL_SCOPED_LOCK_HPP
+
+#if defined(_MSC_VER) && (_MSC_VER >= 1200)
+# pragma once
+#endif // defined(_MSC_VER) && (_MSC_VER >= 1200)
+
+#include <boost/asio/detail/push_options.hpp>
+
+#include <boost/asio/detail/noncopyable.hpp>
+
+namespace boost {
+namespace asio {
+namespace detail {
+
+// Helper class to lock and unlock a mutex automatically.
+template <typename Mutex>
+class scoped_lock
+ : private noncopyable
+{
+public:
+ // Constructor acquires the lock.
+ 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
+} // namespace boost
+
+#include <boost/asio/detail/pop_options.hpp>
+
+#endif // BOOST_ASIO_DETAIL_SCOPED_LOCK_HPP
diff --git a/3rdParty/Boost/boost/asio/detail/select_interrupter.hpp b/3rdParty/Boost/boost/asio/detail/select_interrupter.hpp
new file mode 100644
index 0000000..8bb952c
--- /dev/null
+++ b/3rdParty/Boost/boost/asio/detail/select_interrupter.hpp
@@ -0,0 +1,46 @@
+//
+// select_interrupter.hpp
+// ~~~~~~~~~~~~~~~~~~~~~~
+//
+// Copyright (c) 2003-2008 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 BOOST_ASIO_DETAIL_SELECT_INTERRUPTER_HPP
+#define BOOST_ASIO_DETAIL_SELECT_INTERRUPTER_HPP
+
+#if defined(_MSC_VER) && (_MSC_VER >= 1200)
+# pragma once
+#endif // defined(_MSC_VER) && (_MSC_VER >= 1200)
+
+#include <boost/asio/detail/push_options.hpp>
+
+#include <boost/asio/detail/push_options.hpp>
+#include <boost/config.hpp>
+#include <boost/asio/detail/pop_options.hpp>
+
+#include <boost/asio/detail/eventfd_select_interrupter.hpp>
+#include <boost/asio/detail/pipe_select_interrupter.hpp>
+#include <boost/asio/detail/socket_select_interrupter.hpp>
+
+namespace boost {
+namespace asio {
+namespace detail {
+
+#if defined(BOOST_WINDOWS) || defined(__CYGWIN__)
+typedef socket_select_interrupter select_interrupter;
+#elif defined(BOOST_ASIO_HAS_EVENTFD)
+typedef eventfd_select_interrupter select_interrupter;
+#else
+typedef pipe_select_interrupter select_interrupter;
+#endif
+
+} // namespace detail
+} // namespace asio
+} // namespace boost
+
+#include <boost/asio/detail/pop_options.hpp>
+
+#endif // BOOST_ASIO_DETAIL_SELECT_INTERRUPTER_HPP
diff --git a/3rdParty/Boost/boost/asio/detail/select_reactor.hpp b/3rdParty/Boost/boost/asio/detail/select_reactor.hpp
new file mode 100644
index 0000000..77caf54
--- /dev/null
+++ b/3rdParty/Boost/boost/asio/detail/select_reactor.hpp
@@ -0,0 +1,546 @@
+//
+// select_reactor.hpp
+// ~~~~~~~~~~~~~~~~~~
+//
+// Copyright (c) 2003-2008 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 BOOST_ASIO_DETAIL_SELECT_REACTOR_HPP
+#define BOOST_ASIO_DETAIL_SELECT_REACTOR_HPP
+
+#if defined(_MSC_VER) && (_MSC_VER >= 1200)
+# pragma once
+#endif // defined(_MSC_VER) && (_MSC_VER >= 1200)
+
+#include <boost/asio/detail/push_options.hpp>
+
+#include <boost/asio/detail/socket_types.hpp> // Must come before posix_time.
+
+#include <boost/asio/detail/push_options.hpp>
+#include <cstddef>
+#include <boost/config.hpp>
+#include <boost/date_time/posix_time/posix_time_types.hpp>
+#include <boost/shared_ptr.hpp>
+#include <vector>
+#include <boost/asio/detail/pop_options.hpp>
+
+#include <boost/asio/io_service.hpp>
+#include <boost/asio/detail/bind_handler.hpp>
+#include <boost/asio/detail/fd_set_adapter.hpp>
+#include <boost/asio/detail/mutex.hpp>
+#include <boost/asio/detail/noncopyable.hpp>
+#include <boost/asio/detail/reactor_op_queue.hpp>
+#include <boost/asio/detail/select_interrupter.hpp>
+#include <boost/asio/detail/select_reactor_fwd.hpp>
+#include <boost/asio/detail/service_base.hpp>
+#include <boost/asio/detail/signal_blocker.hpp>
+#include <boost/asio/detail/socket_ops.hpp>
+#include <boost/asio/detail/socket_types.hpp>
+#include <boost/asio/detail/task_io_service.hpp>
+#include <boost/asio/detail/thread.hpp>
+#include <boost/asio/detail/timer_queue.hpp>
+
+namespace boost {
+namespace asio {
+namespace detail {
+
+template <bool Own_Thread>
+class select_reactor
+ : public boost::asio::detail::service_base<select_reactor<Own_Thread> >
+{
+public:
+ // Per-descriptor data.
+ struct per_descriptor_data
+ {
+ };
+
+ // Constructor.
+ select_reactor(boost::asio::io_service& io_service)
+ : boost::asio::detail::service_base<
+ select_reactor<Own_Thread> >(io_service),
+ mutex_(),
+ select_in_progress_(false),
+ interrupter_(),
+ read_op_queue_(),
+ write_op_queue_(),
+ except_op_queue_(),
+ pending_cancellations_(),
+ stop_thread_(false),
+ thread_(0),
+ shutdown_(false)
+ {
+ if (Own_Thread)
+ {
+ boost::asio::detail::signal_blocker sb;
+ thread_ = new boost::asio::detail::thread(
+ bind_handler(&select_reactor::call_run_thread, this));
+ }
+ }
+
+ // Destructor.
+ ~select_reactor()
+ {
+ shutdown_service();
+ }
+
+ // Destroy all user-defined handler objects owned by the service.
+ void shutdown_service()
+ {
+ boost::asio::detail::mutex::scoped_lock lock(mutex_);
+ shutdown_ = true;
+ stop_thread_ = true;
+ lock.unlock();
+
+ if (thread_)
+ {
+ interrupter_.interrupt();
+ thread_->join();
+ delete thread_;
+ thread_ = 0;
+ }
+
+ read_op_queue_.destroy_operations();
+ write_op_queue_.destroy_operations();
+ except_op_queue_.destroy_operations();
+
+ for (std::size_t i = 0; i < timer_queues_.size(); ++i)
+ timer_queues_[i]->destroy_timers();
+ timer_queues_.clear();
+ }
+
+ // Initialise the task, but only if the reactor is not in its own thread.
+ void init_task()
+ {
+ if (!Own_Thread)
+ {
+ typedef task_io_service<select_reactor<Own_Thread> > task_io_service_type;
+ use_service<task_io_service_type>(this->get_io_service()).init_task();
+ }
+ }
+
+ // Register a socket with the reactor. Returns 0 on success, system error
+ // code on failure.
+ int register_descriptor(socket_type, per_descriptor_data&)
+ {
+ return 0;
+ }
+
+ // Start a new read operation. The handler object will be invoked when the
+ // given descriptor is ready to be read, or an error has occurred.
+ template <typename Handler>
+ void start_read_op(socket_type descriptor, per_descriptor_data&,
+ Handler handler, bool /*allow_speculative_read*/ = true)
+ {
+ boost::asio::detail::mutex::scoped_lock lock(mutex_);
+ if (!shutdown_)
+ if (read_op_queue_.enqueue_operation(descriptor, handler))
+ interrupter_.interrupt();
+ }
+
+ // Start a new write operation. The handler object will be invoked when the
+ // given descriptor is ready to be written, or an error has occurred.
+ template <typename Handler>
+ void start_write_op(socket_type descriptor, per_descriptor_data&,
+ Handler handler, bool /*allow_speculative_write*/ = true)
+ {
+ boost::asio::detail::mutex::scoped_lock lock(mutex_);
+ if (!shutdown_)
+ if (write_op_queue_.enqueue_operation(descriptor, handler))
+ interrupter_.interrupt();
+ }
+
+ // Start a new exception operation. The handler object will be invoked when
+ // the given descriptor has exception information, or an error has occurred.
+ template <typename Handler>
+ void start_except_op(socket_type descriptor,
+ per_descriptor_data&, Handler handler)
+ {
+ boost::asio::detail::mutex::scoped_lock lock(mutex_);
+ if (!shutdown_)
+ if (except_op_queue_.enqueue_operation(descriptor, handler))
+ interrupter_.interrupt();
+ }
+
+ // Wrapper for connect handlers to enable the handler object to be placed
+ // in both the write and the except operation queues, but ensure that only
+ // one of the handlers is called.
+ template <typename Handler>
+ class connect_handler_wrapper
+ {
+ public:
+ connect_handler_wrapper(socket_type descriptor,
+ boost::shared_ptr<bool> completed,
+ select_reactor<Own_Thread>& reactor, Handler handler)
+ : descriptor_(descriptor),
+ completed_(completed),
+ reactor_(reactor),
+ handler_(handler)
+ {
+ }
+
+ bool perform(boost::system::error_code& ec,
+ std::size_t& bytes_transferred)
+ {
+ // Check whether one of the handlers has already been called. If it has,
+ // then we don't want to do anything in this handler.
+ if (*completed_)
+ {
+ completed_.reset(); // Indicate that this handler should not complete.
+ return true;
+ }
+
+ // Cancel the other reactor operation for the connection.
+ *completed_ = true;
+ reactor_.enqueue_cancel_ops_unlocked(descriptor_);
+
+ // Call the contained handler.
+ return handler_.perform(ec, bytes_transferred);
+ }
+
+ void complete(const boost::system::error_code& ec,
+ std::size_t bytes_transferred)
+ {
+ if (completed_.get())
+ handler_.complete(ec, bytes_transferred);
+ }
+
+ private:
+ socket_type descriptor_;
+ boost::shared_ptr<bool> completed_;
+ select_reactor<Own_Thread>& reactor_;
+ Handler handler_;
+ };
+
+ // Start new write and exception operations. The handler object will be
+ // invoked when the given descriptor is ready for writing or has exception
+ // information available, or an error has occurred. The handler will be called
+ // only once.
+ template <typename Handler>
+ void start_connect_op(socket_type descriptor,
+ per_descriptor_data&, Handler handler)
+ {
+ boost::asio::detail::mutex::scoped_lock lock(mutex_);
+ if (!shutdown_)
+ {
+ boost::shared_ptr<bool> completed(new bool(false));
+ connect_handler_wrapper<Handler> wrapped_handler(
+ descriptor, completed, *this, handler);
+ bool interrupt = write_op_queue_.enqueue_operation(
+ descriptor, wrapped_handler);
+ interrupt = except_op_queue_.enqueue_operation(
+ descriptor, wrapped_handler) || interrupt;
+ if (interrupt)
+ interrupter_.interrupt();
+ }
+ }
+
+ // Cancel all operations associated with the given descriptor. The
+ // handlers associated with the descriptor will be invoked with the
+ // operation_aborted error.
+ void cancel_ops(socket_type descriptor, per_descriptor_data&)
+ {
+ boost::asio::detail::mutex::scoped_lock lock(mutex_);
+ cancel_ops_unlocked(descriptor);
+ }
+
+ // Enqueue cancellation of all operations associated with the given
+ // descriptor. The handlers associated with the descriptor will be invoked
+ // with the operation_aborted error. This function does not acquire the
+ // select_reactor's mutex, and so should only be used when the reactor lock is
+ // already held.
+ void enqueue_cancel_ops_unlocked(socket_type descriptor)
+ {
+ pending_cancellations_.push_back(descriptor);
+ }
+
+ // Cancel any operations that are running against the descriptor and remove
+ // its registration from the reactor.
+ void close_descriptor(socket_type descriptor, per_descriptor_data&)
+ {
+ boost::asio::detail::mutex::scoped_lock lock(mutex_);
+ cancel_ops_unlocked(descriptor);
+ }
+
+ // Add a new timer queue to the reactor.
+ template <typename Time_Traits>
+ void add_timer_queue(timer_queue<Time_Traits>& timer_queue)
+ {
+ boost::asio::detail::mutex::scoped_lock lock(mutex_);
+ timer_queues_.push_back(&timer_queue);
+ }
+
+ // Remove a timer queue from the reactor.
+ template <typename Time_Traits>
+ void remove_timer_queue(timer_queue<Time_Traits>& timer_queue)
+ {
+ boost::asio::detail::mutex::scoped_lock lock(mutex_);
+ for (std::size_t i = 0; i < timer_queues_.size(); ++i)
+ {
+ if (timer_queues_[i] == &timer_queue)
+ {
+ timer_queues_.erase(timer_queues_.begin() + i);
+ return;
+ }
+ }
+ }
+
+ // Schedule a timer in the given timer queue to expire at the specified
+ // absolute time. The handler object will be invoked when the timer expires.
+ template <typename Time_Traits, typename Handler>
+ void schedule_timer(timer_queue<Time_Traits>& timer_queue,
+ const typename Time_Traits::time_type& time, Handler handler, void* token)
+ {
+ boost::asio::detail::mutex::scoped_lock lock(mutex_);
+ if (!shutdown_)
+ if (timer_queue.enqueue_timer(time, handler, token))
+ interrupter_.interrupt();
+ }
+
+ // 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>& timer_queue, void* token)
+ {
+ boost::asio::detail::mutex::scoped_lock lock(mutex_);
+ std::size_t n = timer_queue.cancel_timer(token);
+ if (n > 0)
+ interrupter_.interrupt();
+ return n;
+ }
+
+private:
+ friend class task_io_service<select_reactor<Own_Thread> >;
+
+ // Run select once until interrupted or events are ready to be dispatched.
+ void run(bool block)
+ {
+ boost::asio::detail::mutex::scoped_lock lock(mutex_);
+
+ // Dispatch any operation cancellations that were made while the select
+ // loop was not running.
+ read_op_queue_.perform_cancellations();
+ write_op_queue_.perform_cancellations();
+ except_op_queue_.perform_cancellations();
+ for (std::size_t i = 0; i < timer_queues_.size(); ++i)
+ timer_queues_[i]->dispatch_cancellations();
+
+ // Check if the thread is supposed to stop.
+ if (stop_thread_)
+ {
+ complete_operations_and_timers(lock);
+ return;
+ }
+
+ // We can return immediately if there's no work to do and the reactor is
+ // not supposed to block.
+ if (!block && read_op_queue_.empty() && write_op_queue_.empty()
+ && except_op_queue_.empty() && all_timer_queues_are_empty())
+ {
+ complete_operations_and_timers(lock);
+ return;
+ }
+
+ // Set up the descriptor sets.
+ fd_set_adapter read_fds;
+ read_fds.set(interrupter_.read_descriptor());
+ read_op_queue_.get_descriptors(read_fds);
+ fd_set_adapter write_fds;
+ write_op_queue_.get_descriptors(write_fds);
+ fd_set_adapter except_fds;
+ except_op_queue_.get_descriptors(except_fds);
+ socket_type max_fd = read_fds.max_descriptor();
+ if (write_fds.max_descriptor() > max_fd)
+ max_fd = write_fds.max_descriptor();
+ if (except_fds.max_descriptor() > max_fd)
+ max_fd = except_fds.max_descriptor();
+
+ // Block on the select call without holding the lock so that new
+ // operations can be started while the call is executing.
+ timeval tv_buf = { 0, 0 };
+ timeval* tv = block ? get_timeout(tv_buf) : &tv_buf;
+ select_in_progress_ = true;
+ lock.unlock();
+ boost::system::error_code ec;
+ int retval = socket_ops::select(static_cast<int>(max_fd + 1),
+ read_fds, write_fds, except_fds, tv, ec);
+ lock.lock();
+ select_in_progress_ = false;
+
+ // Block signals while dispatching operations.
+ boost::asio::detail::signal_blocker sb;
+
+ // Reset the interrupter.
+ if (retval > 0 && read_fds.is_set(interrupter_.read_descriptor()))
+ interrupter_.reset();
+
+ // Dispatch all ready operations.
+ if (retval > 0)
+ {
+ // Exception operations must be processed first to ensure that any
+ // out-of-band data is read before normal data.
+ except_op_queue_.perform_operations_for_descriptors(
+ except_fds, boost::system::error_code());
+ read_op_queue_.perform_operations_for_descriptors(
+ read_fds, boost::system::error_code());
+ write_op_queue_.perform_operations_for_descriptors(
+ write_fds, boost::system::error_code());
+ except_op_queue_.perform_cancellations();
+ read_op_queue_.perform_cancellations();
+ write_op_queue_.perform_cancellations();
+ }
+ for (std::size_t i = 0; i < timer_queues_.size(); ++i)
+ {
+ timer_queues_[i]->dispatch_timers();
+ timer_queues_[i]->dispatch_cancellations();
+ }
+
+ // Issue any pending cancellations.
+ for (size_t i = 0; i < pending_cancellations_.size(); ++i)
+ cancel_ops_unlocked(pending_cancellations_[i]);
+ pending_cancellations_.clear();
+
+ complete_operations_and_timers(lock);
+ }
+
+ // Run the select loop in the thread.
+ void run_thread()
+ {
+ boost::asio::detail::mutex::scoped_lock lock(mutex_);
+ while (!stop_thread_)
+ {
+ lock.unlock();
+ run(true);
+ lock.lock();
+ }
+ }
+
+ // Entry point for the select loop thread.
+ static void call_run_thread(select_reactor* reactor)
+ {
+ reactor->run_thread();
+ }
+
+ // Interrupt the select loop.
+ void interrupt()
+ {
+ interrupter_.interrupt();
+ }
+
+ // Check if all timer queues are empty.
+ bool all_timer_queues_are_empty() const
+ {
+ for (std::size_t i = 0; i < timer_queues_.size(); ++i)
+ if (!timer_queues_[i]->empty())
+ return false;
+ return true;
+ }
+
+ // Get the timeout value for the select call.
+ timeval* get_timeout(timeval& tv)
+ {
+ if (all_timer_queues_are_empty())
+ return 0;
+
+ // 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.
+ boost::posix_time::time_duration minimum_wait_duration
+ = boost::posix_time::minutes(5);
+
+ for (std::size_t i = 0; i < timer_queues_.size(); ++i)
+ {
+ boost::posix_time::time_duration wait_duration
+ = timer_queues_[i]->wait_duration();
+ if (wait_duration < minimum_wait_duration)
+ minimum_wait_duration = wait_duration;
+ }
+
+ if (minimum_wait_duration > boost::posix_time::time_duration())
+ {
+ tv.tv_sec = minimum_wait_duration.total_seconds();
+ tv.tv_usec = minimum_wait_duration.total_microseconds() % 1000000;
+ }
+ else
+ {
+ tv.tv_sec = 0;
+ tv.tv_usec = 0;
+ }
+
+ return &tv;
+ }
+
+ // 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 select_reactor's mutex.
+ void cancel_ops_unlocked(socket_type descriptor)
+ {
+ bool interrupt = read_op_queue_.cancel_operations(descriptor);
+ interrupt = write_op_queue_.cancel_operations(descriptor) || interrupt;
+ interrupt = except_op_queue_.cancel_operations(descriptor) || interrupt;
+ if (interrupt)
+ interrupter_.interrupt();
+ }
+
+ // Clean up operations and timers. We must not hold the lock since the
+ // destructors may make calls back into this reactor. We make a copy of the
+ // vector of timer queues since the original may be modified while the lock
+ // is not held.
+ void complete_operations_and_timers(
+ boost::asio::detail::mutex::scoped_lock& lock)
+ {
+ timer_queues_for_cleanup_ = timer_queues_;
+ lock.unlock();
+ read_op_queue_.complete_operations();
+ write_op_queue_.complete_operations();
+ except_op_queue_.complete_operations();
+ for (std::size_t i = 0; i < timer_queues_for_cleanup_.size(); ++i)
+ timer_queues_for_cleanup_[i]->complete_timers();
+ }
+
+ // Mutex to protect access to internal data.
+ boost::asio::detail::mutex mutex_;
+
+ // Whether the select loop is currently running or not.
+ bool select_in_progress_;
+
+ // The interrupter is used to break a blocking select call.
+ select_interrupter interrupter_;
+
+ // The queue of read operations.
+ reactor_op_queue<socket_type> read_op_queue_;
+
+ // The queue of write operations.
+ reactor_op_queue<socket_type> write_op_queue_;
+
+ // The queue of exception operations.
+ reactor_op_queue<socket_type> except_op_queue_;
+
+ // The timer queues.
+ std::vector<timer_queue_base*> timer_queues_;
+
+ // A copy of the timer queues, used when cleaning up timers. The copy is
+ // stored as a class data member to avoid unnecessary memory allocation.
+ std::vector<timer_queue_base*> timer_queues_for_cleanup_;
+
+ // The descriptors that are pending cancellation.
+ std::vector<socket_type> pending_cancellations_;
+
+ // Does the reactor loop thread need to stop.
+ bool stop_thread_;
+
+ // The thread that is running the reactor loop.
+ boost::asio::detail::thread* thread_;
+
+ // Whether the service has been shut down.
+ bool shutdown_;
+};
+
+} // namespace detail
+} // namespace asio
+} // namespace boost
+
+#include <boost/asio/detail/pop_options.hpp>
+
+#endif // BOOST_ASIO_DETAIL_SELECT_REACTOR_HPP
diff --git a/3rdParty/Boost/boost/asio/detail/select_reactor_fwd.hpp b/3rdParty/Boost/boost/asio/detail/select_reactor_fwd.hpp
new file mode 100644
index 0000000..3bd5d86
--- /dev/null
+++ b/3rdParty/Boost/boost/asio/detail/select_reactor_fwd.hpp
@@ -0,0 +1,33 @@
+//
+// select_reactor_fwd.hpp
+// ~~~~~~~~~~~~~~~~~~~~~~
+//
+// Copyright (c) 2003-2008 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 BOOST_ASIO_DETAIL_SELECT_REACTOR_FWD_HPP
+#define BOOST_ASIO_DETAIL_SELECT_REACTOR_FWD_HPP
+
+#if defined(_MSC_VER) && (_MSC_VER >= 1200)
+# pragma once
+#endif // defined(_MSC_VER) && (_MSC_VER >= 1200)
+
+#include <boost/asio/detail/push_options.hpp>
+
+namespace boost {
+namespace asio {
+namespace detail {
+
+template <bool Own_Thread>
+class select_reactor;
+
+} // namespace detail
+} // namespace asio
+} // namespace boost
+
+#include <boost/asio/detail/pop_options.hpp>
+
+#endif // BOOST_ASIO_DETAIL_SELECT_REACTOR_FWD_HPP
diff --git a/3rdParty/Boost/boost/asio/detail/service_base.hpp b/3rdParty/Boost/boost/asio/detail/service_base.hpp
new file mode 100644
index 0000000..f01cdaf
--- /dev/null
+++ b/3rdParty/Boost/boost/asio/detail/service_base.hpp
@@ -0,0 +1,51 @@
+//
+// service_base.hpp
+// ~~~~~~~~~~~~~~~~
+//
+// Copyright (c) 2003-2008 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 BOOST_ASIO_DETAIL_SERVICE_BASE_HPP
+#define BOOST_ASIO_DETAIL_SERVICE_BASE_HPP
+
+#if defined(_MSC_VER) && (_MSC_VER >= 1200)
+# pragma once
+#endif // defined(_MSC_VER) && (_MSC_VER >= 1200)
+
+#include <boost/asio/detail/push_options.hpp>
+
+#include <boost/asio/io_service.hpp>
+#include <boost/asio/detail/service_id.hpp>
+
+namespace boost {
+namespace asio {
+namespace detail {
+
+// Special service base class to keep classes header-file only.
+template <typename Type>
+class service_base
+ : public boost::asio::io_service::service
+{
+public:
+ static boost::asio::detail::service_id<Type> id;
+
+ // Constructor.
+ service_base(boost::asio::io_service& io_service)
+ : boost::asio::io_service::service(io_service)
+ {
+ }
+};
+
+template <typename Type>
+boost::asio::detail::service_id<Type> service_base<Type>::id;
+
+} // namespace detail
+} // namespace asio
+} // namespace boost
+
+#include <boost/asio/detail/pop_options.hpp>
+
+#endif // BOOST_ASIO_DETAIL_SERVICE_BASE_HPP
diff --git a/3rdParty/Boost/boost/asio/detail/service_id.hpp b/3rdParty/Boost/boost/asio/detail/service_id.hpp
new file mode 100644
index 0000000..f249ddf
--- /dev/null
+++ b/3rdParty/Boost/boost/asio/detail/service_id.hpp
@@ -0,0 +1,39 @@
+//
+// service_id.hpp
+// ~~~~~~~~~~~~~~
+//
+// Copyright (c) 2003-2008 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 BOOST_ASIO_DETAIL_SERVICE_ID_HPP
+#define BOOST_ASIO_DETAIL_SERVICE_ID_HPP
+
+#if defined(_MSC_VER) && (_MSC_VER >= 1200)
+# pragma once
+#endif // defined(_MSC_VER) && (_MSC_VER >= 1200)
+
+#include <boost/asio/detail/push_options.hpp>
+
+#include <boost/asio/io_service.hpp>
+
+namespace boost {
+namespace asio {
+namespace detail {
+
+// Special derived service id type to keep classes header-file only.
+template <typename Type>
+class service_id
+ : public boost::asio::io_service::id
+{
+};
+
+} // namespace detail
+} // namespace asio
+} // namespace boost
+
+#include <boost/asio/detail/pop_options.hpp>
+
+#endif // BOOST_ASIO_DETAIL_SERVICE_ID_HPP
diff --git a/3rdParty/Boost/boost/asio/detail/service_registry.hpp b/3rdParty/Boost/boost/asio/detail/service_registry.hpp
new file mode 100644
index 0000000..6b25663
--- /dev/null
+++ b/3rdParty/Boost/boost/asio/detail/service_registry.hpp
@@ -0,0 +1,228 @@
+//
+// service_registry.hpp
+// ~~~~~~~~~~~~~~~~~~~~
+//
+// Copyright (c) 2003-2008 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 BOOST_ASIO_DETAIL_SERVICE_REGISTRY_HPP
+#define BOOST_ASIO_DETAIL_SERVICE_REGISTRY_HPP
+
+#if defined(_MSC_VER) && (_MSC_VER >= 1200)
+# pragma once
+#endif // defined(_MSC_VER) && (_MSC_VER >= 1200)
+
+#include <boost/asio/detail/push_options.hpp>
+
+#include <boost/asio/detail/push_options.hpp>
+#include <memory>
+#include <typeinfo>
+#include <boost/asio/detail/pop_options.hpp>
+
+#include <boost/asio/io_service.hpp>
+#include <boost/asio/detail/mutex.hpp>
+#include <boost/asio/detail/noncopyable.hpp>
+#include <boost/asio/detail/service_id.hpp>
+
+#if defined(BOOST_NO_TYPEID)
+# if !defined(BOOST_ASIO_NO_TYPEID)
+# define BOOST_ASIO_NO_TYPEID
+# endif // !defined(BOOST_ASIO_NO_TYPEID)
+#endif // defined(BOOST_NO_TYPEID)
+
+namespace boost {
+namespace asio {
+namespace detail {
+
+#if defined(__GNUC__)
+# if (__GNUC__ == 4 && __GNUC_MINOR__ >= 1) || (__GNUC__ > 4)
+# pragma GCC visibility push (default)
+# endif // (__GNUC__ == 4 && __GNUC_MINOR__ >= 1) || (__GNUC__ > 4)
+#endif // defined(__GNUC__)
+
+template <typename T>
+class typeid_wrapper {};
+
+#if defined(__GNUC__)
+# if (__GNUC__ == 4 && __GNUC_MINOR__ >= 1) || (__GNUC__ > 4)
+# pragma GCC visibility pop
+# endif // (__GNUC__ == 4 && __GNUC_MINOR__ >= 1) || (__GNUC__ > 4)
+#endif // defined(__GNUC__)
+
+class service_registry
+ : private noncopyable
+{
+public:
+ // Constructor.
+ service_registry(boost::asio::io_service& o)
+ : owner_(o),
+ first_service_(0)
+ {
+ }
+
+ // Destructor.
+ ~service_registry()
+ {
+ // Shutdown all services. This must be done in a separate loop before the
+ // services are destroyed since the destructors of user-defined handler
+ // objects may try to access other service objects.
+ boost::asio::io_service::service* service = first_service_;
+ while (service)
+ {
+ service->shutdown_service();
+ service = service->next_;
+ }
+
+ // Destroy all services.
+ while (first_service_)
+ {
+ boost::asio::io_service::service* next_service = first_service_->next_;
+ delete first_service_;
+ first_service_ = next_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.
+ template <typename Service>
+ Service& use_service()
+ {
+ boost::asio::detail::mutex::scoped_lock lock(mutex_);
+
+ // First see if there is an existing service object for the given type.
+ boost::asio::io_service::service* service = first_service_;
+ while (service)
+ {
+ if (service_id_matches(*service, Service::id))
+ return *static_cast<Service*>(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();
+ std::auto_ptr<Service> new_service(new Service(owner_));
+ init_service_id(*new_service, Service::id);
+ Service& new_service_ref = *new_service;
+ 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 (service_id_matches(*service, Service::id))
+ return *static_cast<Service*>(service);
+ service = service->next_;
+ }
+
+ // Service was successfully initialised, pass ownership to registry.
+ new_service->next_ = first_service_;
+ first_service_ = new_service.release();
+
+ return new_service_ref;
+ }
+
+ // Add a service object. Returns false on error, in which case ownership of
+ // the object is retained by the caller.
+ template <typename Service>
+ bool add_service(Service* new_service)
+ {
+ boost::asio::detail::mutex::scoped_lock lock(mutex_);
+
+ // Check if there is an existing service object for the given type.
+ boost::asio::io_service::service* service = first_service_;
+ while (service)
+ {
+ if (service_id_matches(*service, Service::id))
+ return false;
+ service = service->next_;
+ }
+
+ // Take ownership of the service object.
+ init_service_id(*new_service, Service::id);
+ new_service->next_ = first_service_;
+ first_service_ = new_service;
+
+ return true;
+ }
+
+ // Check whether a service object of the specified type already exists.
+ template <typename Service>
+ bool has_service() const
+ {
+ boost::asio::detail::mutex::scoped_lock lock(mutex_);
+
+ boost::asio::io_service::service* service = first_service_;
+ while (service)
+ {
+ if (service_id_matches(*service, Service::id))
+ return true;
+ service = service->next_;
+ }
+
+ return false;
+ }
+
+private:
+ // Set a service's id.
+ void init_service_id(boost::asio::io_service::service& service,
+ const boost::asio::io_service::id& id)
+ {
+ service.type_info_ = 0;
+ service.id_ = &id;
+ }
+
+#if !defined(BOOST_ASIO_NO_TYPEID)
+ // Set a service's id.
+ template <typename Service>
+ void init_service_id(boost::asio::io_service::service& service,
+ const boost::asio::detail::service_id<Service>& /*id*/)
+ {
+ service.type_info_ = &typeid(typeid_wrapper<Service>);
+ service.id_ = 0;
+ }
+#endif // !defined(BOOST_ASIO_NO_TYPEID)
+
+ // Check if a service matches the given id.
+ static bool service_id_matches(
+ const boost::asio::io_service::service& service,
+ const boost::asio::io_service::id& id)
+ {
+ return service.id_ == &id;
+ }
+
+#if !defined(BOOST_ASIO_NO_TYPEID)
+ // Check if a service matches the given id.
+ template <typename Service>
+ static bool service_id_matches(
+ const boost::asio::io_service::service& service,
+ const boost::asio::detail::service_id<Service>& /*id*/)
+ {
+ return service.type_info_ != 0
+ && *service.type_info_ == typeid(typeid_wrapper<Service>);
+ }
+#endif // !defined(BOOST_ASIO_NO_TYPEID)
+
+ // Mutex to protect access to internal data.
+ mutable boost::asio::detail::mutex mutex_;
+
+ // The owner of this service registry and the services it contains.
+ boost::asio::io_service& owner_;
+
+ // The first service in the list of contained services.
+ boost::asio::io_service::service* first_service_;
+};
+
+} // namespace detail
+} // namespace asio
+} // namespace boost
+
+#include <boost/asio/detail/pop_options.hpp>
+
+#endif // BOOST_ASIO_DETAIL_SERVICE_REGISTRY_HPP
diff --git a/3rdParty/Boost/boost/asio/detail/service_registry_fwd.hpp b/3rdParty/Boost/boost/asio/detail/service_registry_fwd.hpp
new file mode 100644
index 0000000..e32647b
--- /dev/null
+++ b/3rdParty/Boost/boost/asio/detail/service_registry_fwd.hpp
@@ -0,0 +1,32 @@
+//
+// service_registry_fwd.hpp
+// ~~~~~~~~~~~~~~~~~~~~~~~~
+//
+// Copyright (c) 2003-2008 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 BOOST_ASIO_DETAIL_SERVICE_REGISTRY_FWD_HPP
+#define BOOST_ASIO_DETAIL_SERVICE_REGISTRY_FWD_HPP
+
+#if defined(_MSC_VER) && (_MSC_VER >= 1200)
+# pragma once
+#endif // defined(_MSC_VER) && (_MSC_VER >= 1200)
+
+#include <boost/asio/detail/push_options.hpp>
+
+namespace boost {
+namespace asio {
+namespace detail {
+
+class service_registry;
+
+} // namespace detail
+} // namespace asio
+} // namespace boost
+
+#include <boost/asio/detail/pop_options.hpp>
+
+#endif // BOOST_ASIO_DETAIL_SERVICE_REGISTRY_FWD_HPP
diff --git a/3rdParty/Boost/boost/asio/detail/signal_blocker.hpp b/3rdParty/Boost/boost/asio/detail/signal_blocker.hpp
new file mode 100644
index 0000000..a770549
--- /dev/null
+++ b/3rdParty/Boost/boost/asio/detail/signal_blocker.hpp
@@ -0,0 +1,52 @@
+//
+// signal_blocker.hpp
+// ~~~~~~~~~~~~~~~~~~
+//
+// Copyright (c) 2003-2008 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 BOOST_ASIO_DETAIL_SIGNAL_BLOCKER_HPP
+#define BOOST_ASIO_DETAIL_SIGNAL_BLOCKER_HPP
+
+#if defined(_MSC_VER) && (_MSC_VER >= 1200)
+# pragma once
+#endif // defined(_MSC_VER) && (_MSC_VER >= 1200)
+
+#include <boost/asio/detail/push_options.hpp>
+
+#include <boost/asio/detail/push_options.hpp>
+#include <boost/config.hpp>
+#include <boost/asio/detail/pop_options.hpp>
+
+#if !defined(BOOST_HAS_THREADS)
+# include <boost/asio/detail/null_signal_blocker.hpp>
+#elif defined(BOOST_WINDOWS) || defined(__CYGWIN__)
+# include <boost/asio/detail/win_signal_blocker.hpp>
+#elif defined(BOOST_HAS_PTHREADS)
+# include <boost/asio/detail/posix_signal_blocker.hpp>
+#else
+# error Only Windows and POSIX are supported!
+#endif
+
+namespace boost {
+namespace asio {
+namespace detail {
+
+#if !defined(BOOST_HAS_THREADS)
+typedef null_signal_blocker signal_blocker;
+#elif defined(BOOST_WINDOWS) || defined(__CYGWIN__)
+typedef win_signal_blocker signal_blocker;
+#elif defined(BOOST_HAS_PTHREADS)
+typedef posix_signal_blocker signal_blocker;
+#endif
+
+} // namespace detail
+} // namespace asio
+} // namespace boost
+
+#include <boost/asio/detail/pop_options.hpp>
+
+#endif // BOOST_ASIO_DETAIL_SIGNAL_BLOCKER_HPP
diff --git a/3rdParty/Boost/boost/asio/detail/signal_init.hpp b/3rdParty/Boost/boost/asio/detail/signal_init.hpp
new file mode 100644
index 0000000..e5a3d37
--- /dev/null
+++ b/3rdParty/Boost/boost/asio/detail/signal_init.hpp
@@ -0,0 +1,53 @@
+//
+// signal_init.hpp
+// ~~~~~~~~~~~~~~~
+//
+// Copyright (c) 2003-2008 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 BOOST_ASIO_DETAIL_SIGNAL_INIT_HPP
+#define BOOST_ASIO_DETAIL_SIGNAL_INIT_HPP
+
+#if defined(_MSC_VER) && (_MSC_VER >= 1200)
+# pragma once
+#endif // defined(_MSC_VER) && (_MSC_VER >= 1200)
+
+#include <boost/asio/detail/push_options.hpp>
+
+#include <boost/asio/detail/push_options.hpp>
+#include <boost/config.hpp>
+#include <boost/asio/detail/pop_options.hpp>
+
+#if !defined(BOOST_WINDOWS) && !defined(__CYGWIN__)
+
+#include <boost/asio/detail/push_options.hpp>
+#include <csignal>
+#include <boost/asio/detail/pop_options.hpp>
+
+namespace boost {
+namespace asio {
+namespace detail {
+
+template <int Signal = SIGPIPE>
+class signal_init
+{
+public:
+ // Constructor.
+ signal_init()
+ {
+ std::signal(Signal, SIG_IGN);
+ }
+};
+
+} // namespace detail
+} // namespace asio
+} // namespace boost
+
+#endif // !defined(BOOST_WINDOWS) && !defined(__CYGWIN__)
+
+#include <boost/asio/detail/pop_options.hpp>
+
+#endif // BOOST_ASIO_DETAIL_SIGNAL_INIT_HPP
diff --git a/3rdParty/Boost/boost/asio/detail/socket_holder.hpp b/3rdParty/Boost/boost/asio/detail/socket_holder.hpp
new file mode 100644
index 0000000..be144a6
--- /dev/null
+++ b/3rdParty/Boost/boost/asio/detail/socket_holder.hpp
@@ -0,0 +1,97 @@
+//
+// socket_holder.hpp
+// ~~~~~~~~~~~~~~~~~
+//
+// Copyright (c) 2003-2008 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 BOOST_ASIO_DETAIL_SOCKET_HOLDER_HPP
+#define BOOST_ASIO_DETAIL_SOCKET_HOLDER_HPP
+
+#if defined(_MSC_VER) && (_MSC_VER >= 1200)
+# pragma once
+#endif // defined(_MSC_VER) && (_MSC_VER >= 1200)
+
+#include <boost/asio/detail/push_options.hpp>
+
+#include <boost/asio/detail/noncopyable.hpp>
+#include <boost/asio/detail/socket_ops.hpp>
+
+namespace boost {
+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)
+ {
+ boost::system::error_code ec;
+ socket_ops::close(socket_, ec);
+ }
+ }
+
+ // Get the underlying socket.
+ socket_type get() const
+ {
+ return socket_;
+ }
+
+ // Reset to an uninitialised socket.
+ void reset()
+ {
+ if (socket_ != invalid_socket)
+ {
+ boost::system::error_code ec;
+ socket_ops::close(socket_, 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
+} // namespace boost
+
+#include <boost/asio/detail/pop_options.hpp>
+
+#endif // BOOST_ASIO_DETAIL_SOCKET_HOLDER_HPP
diff --git a/3rdParty/Boost/boost/asio/detail/socket_ops.hpp b/3rdParty/Boost/boost/asio/detail/socket_ops.hpp
new file mode 100644
index 0000000..4969017
--- /dev/null
+++ b/3rdParty/Boost/boost/asio/detail/socket_ops.hpp
@@ -0,0 +1,1913 @@
+//
+// socket_ops.hpp
+// ~~~~~~~~~~~~~~
+//
+// Copyright (c) 2003-2008 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 BOOST_ASIO_DETAIL_SOCKET_OPS_HPP
+#define BOOST_ASIO_DETAIL_SOCKET_OPS_HPP
+
+#if defined(_MSC_VER) && (_MSC_VER >= 1200)
+# pragma once
+#endif // defined(_MSC_VER) && (_MSC_VER >= 1200)
+
+#include <boost/asio/detail/push_options.hpp>
+
+#include <boost/asio/detail/push_options.hpp>
+#include <boost/config.hpp>
+#include <boost/assert.hpp>
+#include <cstdio>
+#include <cstdlib>
+#include <cstring>
+#include <cerrno>
+#include <boost/detail/workaround.hpp>
+#include <new>
+#include <boost/asio/detail/pop_options.hpp>
+
+#include <boost/asio/error.hpp>
+#include <boost/asio/detail/socket_types.hpp>
+
+namespace boost {
+namespace asio {
+namespace detail {
+namespace socket_ops {
+
+#if defined(BOOST_WINDOWS) || defined(__CYGWIN__)
+struct msghdr { int msg_namelen; };
+#endif // defined(BOOST_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)
+
+inline void clear_error(boost::system::error_code& ec)
+{
+#if defined(BOOST_WINDOWS) || defined(__CYGWIN__)
+ WSASetLastError(0);
+#else
+ errno = 0;
+#endif
+ ec = boost::system::error_code();
+}
+
+template <typename ReturnType>
+inline ReturnType error_wrapper(ReturnType return_value,
+ boost::system::error_code& ec)
+{
+#if defined(BOOST_WINDOWS) || defined(__CYGWIN__)
+ ec = boost::system::error_code(WSAGetLastError(),
+ boost::asio::error::get_system_category());
+#else
+ ec = boost::system::error_code(errno,
+ boost::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;
+}
+
+inline socket_type accept(socket_type s, socket_addr_type* addr,
+ std::size_t* addrlen, boost::system::error_code& ec)
+{
+ clear_error(ec);
+
+ 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
+
+ clear_error(ec);
+ return new_s;
+}
+
+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);
+}
+
+inline int bind(socket_type s, const socket_addr_type* addr,
+ std::size_t addrlen, boost::system::error_code& ec)
+{
+ clear_error(ec);
+ int result = error_wrapper(call_bind(
+ &msghdr::msg_namelen, s, addr, addrlen), ec);
+ if (result == 0)
+ clear_error(ec);
+ return result;
+}
+
+inline int close(socket_type s, boost::system::error_code& ec)
+{
+ clear_error(ec);
+#if defined(BOOST_WINDOWS) || defined(__CYGWIN__)
+ int result = error_wrapper(::closesocket(s), ec);
+#else // defined(BOOST_WINDOWS) || defined(__CYGWIN__)
+ int result = error_wrapper(::close(s), ec);
+#endif // defined(BOOST_WINDOWS) || defined(__CYGWIN__)
+ if (result == 0)
+ clear_error(ec);
+ return result;
+}
+
+inline int shutdown(socket_type s, int what, boost::system::error_code& ec)
+{
+ clear_error(ec);
+ int result = error_wrapper(::shutdown(s, what), ec);
+ if (result == 0)
+ clear_error(ec);
+ 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);
+}
+
+inline int connect(socket_type s, const socket_addr_type* addr,
+ std::size_t addrlen, boost::system::error_code& ec)
+{
+ clear_error(ec);
+ int result = error_wrapper(call_connect(
+ &msghdr::msg_namelen, s, addr, addrlen), ec);
+ if (result == 0)
+ clear_error(ec);
+ return result;
+}
+
+inline int socketpair(int af, int type, int protocol,
+ socket_type sv[2], boost::system::error_code& ec)
+{
+#if defined(BOOST_WINDOWS) || defined(__CYGWIN__)
+ (void)(af);
+ (void)(type);
+ (void)(protocol);
+ (void)(sv);
+ ec = boost::asio::error::operation_not_supported;
+ return -1;
+#else
+ clear_error(ec);
+ int result = error_wrapper(::socketpair(af, type, protocol, sv), ec);
+ if (result == 0)
+ clear_error(ec);
+ return result;
+#endif
+}
+
+inline int listen(socket_type s, int backlog, boost::system::error_code& ec)
+{
+ clear_error(ec);
+ int result = error_wrapper(::listen(s, backlog), ec);
+ if (result == 0)
+ clear_error(ec);
+ 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(BOOST_WINDOWS) || defined(__CYGWIN__)
+typedef WSABUF buf;
+#else // defined(BOOST_WINDOWS) || defined(__CYGWIN__)
+typedef iovec buf;
+#endif // defined(BOOST_WINDOWS) || defined(__CYGWIN__)
+
+inline void init_buf(buf& b, void* data, size_t size)
+{
+#if defined(BOOST_WINDOWS) || defined(__CYGWIN__)
+ b.buf = static_cast<char*>(data);
+ b.len = static_cast<u_long>(size);
+#else // defined(BOOST_WINDOWS) || defined(__CYGWIN__)
+ init_buf_iov_base(b.iov_base, data);
+ b.iov_len = size;
+#endif // defined(BOOST_WINDOWS) || defined(__CYGWIN__)
+}
+
+inline void init_buf(buf& b, const void* data, size_t size)
+{
+#if defined(BOOST_WINDOWS) || defined(__CYGWIN__)
+ b.buf = static_cast<char*>(const_cast<void*>(data));
+ b.len = static_cast<u_long>(size);
+#else // defined(BOOST_WINDOWS) || defined(__CYGWIN__)
+ init_buf_iov_base(b.iov_base, const_cast<void*>(data));
+ b.iov_len = size;
+#endif // defined(BOOST_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));
+}
+
+inline int recv(socket_type s, buf* bufs, size_t count, int flags,
+ boost::system::error_code& ec)
+{
+ clear_error(ec);
+#if defined(BOOST_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 (result != 0)
+ return -1;
+ clear_error(ec);
+ return bytes_transferred;
+#else // defined(BOOST_WINDOWS) || defined(__CYGWIN__)
+ msghdr msg = msghdr();
+ msg.msg_iov = bufs;
+ msg.msg_iovlen = count;
+ int result = error_wrapper(::recvmsg(s, &msg, flags), ec);
+ if (result >= 0)
+ clear_error(ec);
+ return result;
+#endif // defined(BOOST_WINDOWS) || defined(__CYGWIN__)
+}
+
+inline int recvfrom(socket_type s, buf* bufs, size_t count, int flags,
+ socket_addr_type* addr, std::size_t* addrlen,
+ boost::system::error_code& ec)
+{
+ clear_error(ec);
+#if defined(BOOST_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 (result != 0)
+ return -1;
+ clear_error(ec);
+ return bytes_transferred;
+#else // defined(BOOST_WINDOWS) || defined(__CYGWIN__)
+ msghdr msg = msghdr();
+ init_msghdr_msg_name(msg.msg_name, addr);
+ msg.msg_namelen = *addrlen;
+ msg.msg_iov = bufs;
+ msg.msg_iovlen = count;
+ int result = error_wrapper(::recvmsg(s, &msg, flags), ec);
+ *addrlen = msg.msg_namelen;
+ if (result >= 0)
+ clear_error(ec);
+ return result;
+#endif // defined(BOOST_WINDOWS) || defined(__CYGWIN__)
+}
+
+inline int send(socket_type s, const buf* bufs, size_t count, int flags,
+ boost::system::error_code& ec)
+{
+ clear_error(ec);
+#if defined(BOOST_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 (result != 0)
+ return -1;
+ clear_error(ec);
+ return bytes_transferred;
+#else // defined(BOOST_WINDOWS) || defined(__CYGWIN__)
+ msghdr msg = msghdr();
+ msg.msg_iov = const_cast<buf*>(bufs);
+ msg.msg_iovlen = count;
+#if defined(__linux__)
+ flags |= MSG_NOSIGNAL;
+#endif // defined(__linux__)
+ int result = error_wrapper(::sendmsg(s, &msg, flags), ec);
+ if (result >= 0)
+ clear_error(ec);
+ return result;
+#endif // defined(BOOST_WINDOWS) || defined(__CYGWIN__)
+}
+
+inline int sendto(socket_type s, const buf* bufs, size_t count, int flags,
+ const socket_addr_type* addr, std::size_t addrlen,
+ boost::system::error_code& ec)
+{
+ clear_error(ec);
+#if defined(BOOST_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 (result != 0)
+ return -1;
+ clear_error(ec);
+ return bytes_transferred;
+#else // defined(BOOST_WINDOWS) || defined(__CYGWIN__)
+ msghdr msg = msghdr();
+ init_msghdr_msg_name(msg.msg_name, addr);
+ msg.msg_namelen = addrlen;
+ msg.msg_iov = const_cast<buf*>(bufs);
+ msg.msg_iovlen = count;
+#if defined(__linux__)
+ flags |= MSG_NOSIGNAL;
+#endif // defined(__linux__)
+ int result = error_wrapper(::sendmsg(s, &msg, flags), ec);
+ if (result >= 0)
+ clear_error(ec);
+ return result;
+#endif // defined(BOOST_WINDOWS) || defined(__CYGWIN__)
+}
+
+inline socket_type socket(int af, int type, int protocol,
+ boost::system::error_code& ec)
+{
+ clear_error(ec);
+#if defined(BOOST_WINDOWS) || defined(__CYGWIN__)
+ socket_type s = error_wrapper(::WSASocket(af, type, protocol, 0, 0,
+ WSA_FLAG_OVERLAPPED), ec);
+ if (s == invalid_socket)
+ return s;
+
+ if (af == 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));
+ }
+
+ clear_error(ec);
+
+ 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)
+ clear_error(ec);
+ 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);
+}
+
+inline int setsockopt(socket_type s, int level, int optname,
+ const void* optval, std::size_t optlen, boost::system::error_code& ec)
+{
+ if (level == custom_socket_option_level && optname == always_fail_option)
+ {
+ ec = boost::asio::error::invalid_argument;
+ return -1;
+ }
+
+#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_error(ec);
+ return error_wrapper(sso(s, level, optname,
+ reinterpret_cast<const char*>(optval),
+ static_cast<int>(optlen)), ec);
+ }
+ }
+ ec = boost::asio::error::fault;
+ return -1;
+#else // defined(__BORLANDC__)
+ clear_error(ec);
+ int result = error_wrapper(call_setsockopt(&msghdr::msg_namelen,
+ s, level, optname, optval, optlen), ec);
+ if (result == 0)
+ clear_error(ec);
+ 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;
+}
+
+inline int getsockopt(socket_type s, int level, int optname, void* optval,
+ size_t* optlen, boost::system::error_code& ec)
+{
+ if (level == custom_socket_option_level && optname == always_fail_option)
+ {
+ ec = boost::asio::error::invalid_argument;
+ return -1;
+ }
+
+#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_error(ec);
+ 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;
+ clear_error(ec);
+ }
+ return result;
+ }
+ }
+ ec = boost::asio::error::fault;
+ return -1;
+#elif defined(BOOST_WINDOWS) || defined(__CYGWIN__)
+ clear_error(ec);
+ 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;
+ clear_error(ec);
+ }
+ if (result == 0)
+ clear_error(ec);
+ return result;
+#else // defined(BOOST_WINDOWS) || defined(__CYGWIN__)
+ clear_error(ec);
+ 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)
+ clear_error(ec);
+ return result;
+#endif // defined(BOOST_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;
+}
+
+inline int getpeername(socket_type s, socket_addr_type* addr,
+ std::size_t* addrlen, boost::system::error_code& ec)
+{
+ clear_error(ec);
+ int result = error_wrapper(call_getpeername(
+ &msghdr::msg_namelen, s, addr, addrlen), ec);
+ if (result == 0)
+ clear_error(ec);
+ 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;
+}
+
+inline int getsockname(socket_type s, socket_addr_type* addr,
+ std::size_t* addrlen, boost::system::error_code& ec)
+{
+ clear_error(ec);
+ int result = error_wrapper(call_getsockname(
+ &msghdr::msg_namelen, s, addr, addrlen), ec);
+ if (result == 0)
+ clear_error(ec);
+ return result;
+}
+
+inline int ioctl(socket_type s, long cmd, ioctl_arg_type* arg,
+ boost::system::error_code& ec)
+{
+ clear_error(ec);
+#if defined(BOOST_WINDOWS) || defined(__CYGWIN__)
+ int result = error_wrapper(::ioctlsocket(s, cmd, arg), ec);
+#else // defined(BOOST_WINDOWS) || defined(__CYGWIN__)
+ int result = error_wrapper(::ioctl(s, cmd, arg), ec);
+#endif // defined(BOOST_WINDOWS) || defined(__CYGWIN__)
+ if (result >= 0)
+ clear_error(ec);
+ return result;
+}
+
+inline int select(int nfds, fd_set* readfds, fd_set* writefds,
+ fd_set* exceptfds, timeval* timeout, boost::system::error_code& ec)
+{
+ clear_error(ec);
+#if defined(BOOST_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 = boost::system::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(BOOST_WINDOWS) || defined(__CYGWIN__)
+
+#if defined(__hpux) && defined(__HP_aCC)
+ 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)
+ clear_error(ec);
+ return result;
+#endif
+}
+
+inline int poll_read(socket_type s, boost::system::error_code& ec)
+{
+#if defined(BOOST_WINDOWS) || defined(__CYGWIN__)
+ FD_SET fds;
+ FD_ZERO(&fds);
+ FD_SET(s, &fds);
+ clear_error(ec);
+ int result = error_wrapper(::select(s, &fds, 0, 0, 0), ec);
+ if (result >= 0)
+ clear_error(ec);
+ return result;
+#else // defined(BOOST_WINDOWS) || defined(__CYGWIN__)
+ pollfd fds;
+ fds.fd = s;
+ fds.events = POLLIN;
+ fds.revents = 0;
+ clear_error(ec);
+ int result = error_wrapper(::poll(&fds, 1, -1), ec);
+ if (result >= 0)
+ clear_error(ec);
+ return result;
+#endif // defined(BOOST_WINDOWS) || defined(__CYGWIN__)
+}
+
+inline int poll_write(socket_type s, boost::system::error_code& ec)
+{
+#if defined(BOOST_WINDOWS) || defined(__CYGWIN__)
+ FD_SET fds;
+ FD_ZERO(&fds);
+ FD_SET(s, &fds);
+ clear_error(ec);
+ int result = error_wrapper(::select(s, 0, &fds, 0, 0), ec);
+ if (result >= 0)
+ clear_error(ec);
+ return result;
+#else // defined(BOOST_WINDOWS) || defined(__CYGWIN__)
+ pollfd fds;
+ fds.fd = s;
+ fds.events = POLLOUT;
+ fds.revents = 0;
+ clear_error(ec);
+ int result = error_wrapper(::poll(&fds, 1, -1), ec);
+ if (result >= 0)
+ clear_error(ec);
+ return result;
+#endif // defined(BOOST_WINDOWS) || defined(__CYGWIN__)
+}
+
+inline int poll_connect(socket_type s, boost::system::error_code& ec)
+{
+#if defined(BOOST_WINDOWS) || defined(__CYGWIN__)
+ 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);
+ clear_error(ec);
+ int result = error_wrapper(::select(s, 0, &write_fds, &except_fds, 0), ec);
+ if (result >= 0)
+ clear_error(ec);
+ return result;
+#else // defined(BOOST_WINDOWS) || defined(__CYGWIN__)
+ pollfd fds;
+ fds.fd = s;
+ fds.events = POLLOUT;
+ fds.revents = 0;
+ clear_error(ec);
+ int result = error_wrapper(::poll(&fds, 1, -1), ec);
+ if (result >= 0)
+ clear_error(ec);
+ return result;
+#endif // defined(BOOST_WINDOWS) || defined(__CYGWIN__)
+}
+
+inline const char* inet_ntop(int af, const void* src, char* dest, size_t length,
+ unsigned long scope_id, boost::system::error_code& ec)
+{
+ clear_error(ec);
+#if defined(BOOST_WINDOWS) || defined(__CYGWIN__)
+ using namespace std; // For memcpy.
+
+ if (af != AF_INET && af != AF_INET6)
+ {
+ ec = boost::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 == AF_INET)
+ {
+ address_length = sizeof(sockaddr_in4_type);
+ address.v4.sin_family = 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 = 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)
+ 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, 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)
+ clear_error(ec);
+
+ // Windows may not set an error code on failure.
+ else if (result == socket_error_retval && !ec)
+ ec = boost::asio::error::invalid_argument;
+
+ return result == socket_error_retval ? 0 : dest;
+#else // defined(BOOST_WINDOWS) || defined(__CYGWIN__)
+ const char* result = error_wrapper(::inet_ntop(af, src, dest, length), ec);
+ if (result == 0 && !ec)
+ ec = boost::asio::error::invalid_argument;
+ if (result != 0 && af == 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 = IN6_IS_ADDR_LINKLOCAL(ipv6_address);
+ if (!is_link_local || if_indextoname(scope_id, if_name + 1) == 0)
+ sprintf(if_name + 1, "%lu", scope_id);
+ strcat(dest, if_name);
+ }
+ return result;
+#endif // defined(BOOST_WINDOWS) || defined(__CYGWIN__)
+}
+
+inline int inet_pton(int af, const char* src, void* dest,
+ unsigned long* scope_id, boost::system::error_code& ec)
+{
+ clear_error(ec);
+#if defined(BOOST_WINDOWS) || defined(__CYGWIN__)
+ using namespace std; // For memcpy and strcmp.
+
+ if (af != AF_INET && af != AF_INET6)
+ {
+ ec = boost::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)
+ int num_wide_chars = 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 == AF_INET)
+ {
+ if (result != socket_error_retval)
+ {
+ memcpy(dest, &address.v4.sin_addr, sizeof(in4_addr_type));
+ clear_error(ec);
+ }
+ else if (strcmp(src, "255.255.255.255") == 0)
+ {
+ static_cast<in4_addr_type*>(dest)->s_addr = INADDR_NONE;
+ clear_error(ec);
+ }
+ }
+ 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;
+ clear_error(ec);
+ }
+ }
+
+ // Windows may not set an error code on failure.
+ if (result == socket_error_retval && !ec)
+ ec = boost::asio::error::invalid_argument;
+
+ if (result != socket_error_retval)
+ clear_error(ec);
+
+ return result == socket_error_retval ? -1 : 1;
+#else // defined(BOOST_WINDOWS) || defined(__CYGWIN__)
+ int result = error_wrapper(::inet_pton(af, src, dest), ec);
+ if (result <= 0 && !ec)
+ ec = boost::asio::error::invalid_argument;
+ if (result > 0 && af == AF_INET6 && scope_id)
+ {
+ using namespace std; // For strchr and atoi.
+ *scope_id = 0;
+ if (const char* if_name = strchr(src, '%'))
+ {
+ in6_addr_type* ipv6_address = static_cast<in6_addr_type*>(dest);
+ bool is_link_local = IN6_IS_ADDR_LINKLOCAL(ipv6_address);
+ if (is_link_local)
+ *scope_id = if_nametoindex(if_name + 1);
+ if (*scope_id == 0)
+ *scope_id = atoi(if_name + 1);
+ }
+ }
+ return result;
+#endif // defined(BOOST_WINDOWS) || defined(__CYGWIN__)
+}
+
+inline int gethostname(char* name, int namelen, boost::system::error_code& ec)
+{
+ clear_error(ec);
+ int result = error_wrapper(::gethostname(name, namelen), ec);
+#if defined(BOOST_WINDOWS)
+ if (result == 0)
+ clear_error(ec);
+#endif
+ return result;
+}
+
+#if defined(BOOST_WINDOWS) || defined(__CYGWIN__) \
+ || defined(__MACH__) && defined(__APPLE__)
+
+// The following functions are only needed for emulation of getaddrinfo and
+// getnameinfo.
+
+inline boost::system::error_code translate_netdb_error(int error)
+{
+ switch (error)
+ {
+ case 0:
+ return boost::system::error_code();
+ case HOST_NOT_FOUND:
+ return boost::asio::error::host_not_found;
+ case TRY_AGAIN:
+ return boost::asio::error::host_not_found_try_again;
+ case NO_RECOVERY:
+ return boost::asio::error::no_recovery;
+ case NO_DATA:
+ return boost::asio::error::no_data;
+ default:
+ BOOST_ASSERT(false);
+ return boost::asio::error::invalid_argument;
+ }
+}
+
+inline hostent* gethostbyaddr(const char* addr, int length, int af,
+ hostent* result, char* buffer, int buflength, boost::system::error_code& ec)
+{
+ clear_error(ec);
+#if defined(BOOST_WINDOWS) || defined(__CYGWIN__)
+ (void)(buffer);
+ (void)(buflength);
+ hostent* retval = error_wrapper(::gethostbyaddr(addr, length, af), ec);
+ if (!retval)
+ return 0;
+ clear_error(ec);
+ *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, boost::system::error_code& ec)
+{
+ clear_error(ec);
+#if defined(BOOST_WINDOWS) || defined(__CYGWIN__)
+ (void)(buffer);
+ (void)(buflength);
+ (void)(ai_flags);
+ if (af != AF_INET)
+ {
+ ec = boost::asio::error::address_family_not_supported;
+ return 0;
+ }
+ hostent* retval = error_wrapper(::gethostbyname(name), ec);
+ if (!retval)
+ return 0;
+ clear_error(ec);
+ *result = *retval;
+ return result;
+#elif defined(__sun) || defined(__QNX__)
+ (void)(ai_flags);
+ if (af != AF_INET)
+ {
+ ec = boost::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 != AF_INET)
+ {
+ ec = boost::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 AF_INET:
+ search[search_count].host = "0.0.0.0";
+ search[search_count].family = AF_INET;
+ ++search_count;
+ break;
+ case AF_INET6:
+ search[search_count].host = "0::0";
+ search[search_count].family = AF_INET6;
+ ++search_count;
+ break;
+ case AF_UNSPEC:
+ search[search_count].host = "0::0";
+ search[search_count].family = AF_INET6;
+ ++search_count;
+ search[search_count].host = "0.0.0.0";
+ search[search_count].family = AF_INET;
+ ++search_count;
+ break;
+ default:
+ break;
+ }
+ }
+ else
+ {
+ // No host and not AI_PASSIVE means connect to local host.
+ switch (hints->ai_family)
+ {
+ case AF_INET:
+ search[search_count].host = "localhost";
+ search[search_count].family = AF_INET;
+ ++search_count;
+ break;
+ case AF_INET6:
+ search[search_count].host = "localhost";
+ search[search_count].family = AF_INET6;
+ ++search_count;
+ break;
+ case AF_UNSPEC:
+ search[search_count].host = "localhost";
+ search[search_count].family = AF_INET6;
+ ++search_count;
+ search[search_count].host = "localhost";
+ search[search_count].family = AF_INET;
+ ++search_count;
+ break;
+ default:
+ break;
+ }
+ }
+ }
+ else
+ {
+ // Host is specified.
+ switch (hints->ai_family)
+ {
+ case AF_INET:
+ search[search_count].host = host;
+ search[search_count].family = AF_INET;
+ ++search_count;
+ break;
+ case AF_INET6:
+ search[search_count].host = host;
+ search[search_count].family = AF_INET6;
+ ++search_count;
+ break;
+ case AF_UNSPEC:
+ search[search_count].host = host;
+ search[search_count].family = AF_INET6;
+ ++search_count;
+ search[search_count].host = host;
+ search[search_count].family = 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 BOOST_WORKAROUND(BOOST_MSVC, >= 1400) && !defined(UNDER_CE)
+ strcpy_s(target, max_size, source);
+#else
+ *target = 0;
+ strncat(target, source, max_size);
+#endif
+}
+
+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 AF_INET:
+ {
+ sockaddr_in4_type* sinptr = gai_alloc<sockaddr_in4_type>();
+ if (sinptr == 0)
+ return EAI_MEMORY;
+ sinptr->sin_family = 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 AF_INET6:
+ {
+ sockaddr_in6_type* sin6ptr = gai_alloc<sockaddr_in6_type>();
+ if (sin6ptr == 0)
+ return EAI_MEMORY;
+ sin6ptr->sin6_family = 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 AF_INET:
+ {
+ sockaddr_in4_type* sinptr =
+ reinterpret_cast<sockaddr_in4_type*>(ai->ai_addr);
+ sinptr->sin_port = port;
+ ++num_found;
+ break;
+ }
+ case 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(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 AF_UNSPEC:
+ break;
+ case AF_INET:
+ case AF_INET6:
+ 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 = 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 != AF_INET6)
+ hints.ai_flags &= ~AI_V4MAPPED;
+#endif
+#if defined(AI_ALL)
+ if (hints.ai_family != 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;
+ boost::system::error_code ec;
+ if (socket_ops::inet_pton(AF_INET, sptr->host, &inaddr, 0, ec) == 1)
+ {
+ if (hints.ai_family != AF_UNSPEC && hints.ai_family != AF_INET)
+ {
+ freeaddrinfo_emulation(aihead);
+ gai_free(canon);
+ return EAI_FAMILY;
+ }
+ if (sptr->family == AF_INET)
+ {
+ rc = gai_aistruct(&ainext, &hints, &inaddr, 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(AF_INET6, sptr->host, &in6addr, 0, ec) == 1)
+ {
+ if (hints.ai_family != AF_UNSPEC && hints.ai_family != AF_INET6)
+ {
+ freeaddrinfo_emulation(aihead);
+ gai_free(canon);
+ return EAI_FAMILY;
+ }
+ if (sptr->family == AF_INET6)
+ {
+ rc = gai_aistruct(&ainext, &hints, &in6addr, 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 == boost::asio::error::host_not_found)
+ return EAI_NONAME;
+ if (ec == boost::asio::error::host_not_found_try_again)
+ return EAI_AGAIN;
+ if (ec == boost::asio::error::no_recovery)
+ return EAI_FAIL;
+ if (ec == boost::asio::error::no_data)
+ return EAI_NONAME;
+ return EAI_NONAME;
+ }
+
+ // Check for address family mismatch if one was specified.
+ if (hints.ai_family != 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 boost::system::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,
+ boost::system::error_code& ec)
+{
+ using namespace std;
+
+ const char* addr;
+ size_t addr_len;
+ unsigned short port;
+ switch (sa->sa_family)
+ {
+ case AF_INET:
+ if (salen != sizeof(sockaddr_in4_type))
+ {
+ return ec = boost::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 AF_INET6:
+ if (salen != sizeof(sockaddr_in6_type))
+ {
+ return ec = boost::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 = boost::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 = boost::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 = boost::asio::error::no_buffer_space;
+ }
+#if BOOST_WORKAROUND(BOOST_MSVC, >= 1400) && !defined(UNDER_CE)
+ sprintf_s(serv, servlen, "%u", ntohs(port));
+#else
+ sprintf(serv, "%u", ntohs(port));
+#endif
+ }
+ else
+ {
+#if defined(BOOST_HAS_THREADS) && defined(BOOST_HAS_PTHREADS)
+ static ::pthread_mutex_t mutex = PTHREAD_MUTEX_INITIALIZER;
+ ::pthread_mutex_lock(&mutex);
+#endif // defined(BOOST_HAS_THREADS) && defined(BOOST_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 = boost::asio::error::no_buffer_space;
+ }
+#if BOOST_WORKAROUND(BOOST_MSVC, >= 1400) && !defined(UNDER_CE)
+ sprintf_s(serv, servlen, "%u", ntohs(port));
+#else
+ sprintf(serv, "%u", ntohs(port));
+#endif
+ }
+#if defined(BOOST_HAS_THREADS) && defined(BOOST_HAS_PTHREADS)
+ ::pthread_mutex_unlock(&mutex);
+#endif // defined(BOOST_HAS_THREADS) && defined(BOOST_HAS_PTHREADS)
+ }
+ }
+
+ clear_error(ec);
+ return ec;
+}
+
+#endif // defined(BOOST_WINDOWS) || defined(__CYGWIN__)
+ // || defined(__MACH__) && defined(__APPLE__)
+
+inline boost::system::error_code translate_addrinfo_error(int error)
+{
+ switch (error)
+ {
+ case 0:
+ return boost::system::error_code();
+ case EAI_AGAIN:
+ return boost::asio::error::host_not_found_try_again;
+ case EAI_BADFLAGS:
+ return boost::asio::error::invalid_argument;
+ case EAI_FAIL:
+ return boost::asio::error::no_recovery;
+ case EAI_FAMILY:
+ return boost::asio::error::address_family_not_supported;
+ case EAI_MEMORY:
+ return boost::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 boost::asio::error::host_not_found;
+ case EAI_SERVICE:
+ return boost::asio::error::service_not_found;
+ case EAI_SOCKTYPE:
+ return boost::asio::error::socket_type_not_supported;
+ default: // Possibly the non-portable EAI_SYSTEM.
+#if defined(BOOST_WINDOWS) || defined(__CYGWIN__)
+ return boost::system::error_code(
+ WSAGetLastError(), boost::asio::error::get_system_category());
+#else
+ return boost::system::error_code(
+ errno, boost::asio::error::get_system_category());
+#endif
+ }
+}
+
+inline boost::system::error_code getaddrinfo(const char* host,
+ const char* service, const addrinfo_type* hints, addrinfo_type** result,
+ boost::system::error_code& ec)
+{
+ clear_error(ec);
+#if defined(BOOST_WINDOWS) || defined(__CYGWIN__)
+# if defined(_WIN32_WINNT) && (_WIN32_WINNT >= 0x0501) || defined(UNDER_CE)
+ // 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(__MACH__) && defined(__APPLE__)
+ int error = getaddrinfo_emulation(host, service, hints, result);
+ return ec = translate_addrinfo_error(error);
+#else
+ int error = ::getaddrinfo(host, service, hints, result);
+ return ec = translate_addrinfo_error(error);
+#endif
+}
+
+inline void freeaddrinfo(addrinfo_type* ai)
+{
+#if defined(BOOST_WINDOWS) || defined(__CYGWIN__)
+# if defined(_WIN32_WINNT) && (_WIN32_WINNT >= 0x0501) || defined(UNDER_CE)
+ // 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(__MACH__) && defined(__APPLE__)
+ freeaddrinfo_emulation(ai);
+#else
+ ::freeaddrinfo(ai);
+#endif
+}
+
+inline boost::system::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, boost::system::error_code& ec)
+{
+#if defined(BOOST_WINDOWS) || defined(__CYGWIN__)
+# if defined(_WIN32_WINNT) && (_WIN32_WINNT >= 0x0501) || defined(UNDER_CE)
+ // Building for Windows XP, Windows Server 2003, or later.
+ clear_error(ec);
+ 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_error(ec);
+ 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_error(ec);
+ return getnameinfo_emulation(addr, addrlen,
+ host, hostlen, serv, servlen, flags, ec);
+# endif
+#elif defined(__MACH__) && defined(__APPLE__)
+ using namespace std; // For memcpy.
+ sockaddr_storage_type tmp_addr;
+ memcpy(&tmp_addr, addr, addrlen);
+ tmp_addr.ss_len = addrlen;
+ addr = reinterpret_cast<socket_addr_type*>(&tmp_addr);
+ clear_error(ec);
+ return getnameinfo_emulation(addr, addrlen,
+ host, hostlen, serv, servlen, flags, ec);
+#else
+ clear_error(ec);
+ int error = ::getnameinfo(addr, addrlen, host, hostlen, serv, servlen, flags);
+ return ec = translate_addrinfo_error(error);
+#endif
+}
+
+inline u_long_type network_to_host_long(u_long_type value)
+{
+ return ntohl(value);
+}
+
+inline u_long_type host_to_network_long(u_long_type value)
+{
+ return htonl(value);
+}
+
+inline u_short_type network_to_host_short(u_short_type value)
+{
+ return ntohs(value);
+}
+
+inline u_short_type host_to_network_short(u_short_type value)
+{
+ return htons(value);
+}
+
+} // namespace socket_ops
+} // namespace detail
+} // namespace asio
+} // namespace boost
+
+#include <boost/asio/detail/pop_options.hpp>
+
+#endif // BOOST_ASIO_DETAIL_SOCKET_OPS_HPP
diff --git a/3rdParty/Boost/boost/asio/detail/socket_option.hpp b/3rdParty/Boost/boost/asio/detail/socket_option.hpp
new file mode 100644
index 0000000..c0d7b74
--- /dev/null
+++ b/3rdParty/Boost/boost/asio/detail/socket_option.hpp
@@ -0,0 +1,311 @@
+//
+// socket_option.hpp
+// ~~~~~~~~~~~~~~~~~
+//
+// Copyright (c) 2003-2008 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 BOOST_ASIO_DETAIL_SOCKET_OPTION_HPP
+#define BOOST_ASIO_DETAIL_SOCKET_OPTION_HPP
+
+#if defined(_MSC_VER) && (_MSC_VER >= 1200)
+# pragma once
+#endif // defined(_MSC_VER) && (_MSC_VER >= 1200)
+
+#include <boost/asio/detail/push_options.hpp>
+
+#include <boost/asio/detail/push_options.hpp>
+#include <cstddef>
+#include <stdexcept>
+#include <boost/config.hpp>
+#include <boost/asio/detail/pop_options.hpp>
+
+#include <boost/asio/detail/socket_types.hpp>
+
+namespace boost {
+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:
+ throw std::length_error("boolean socket option resize");
+ }
+ }
+
+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_))
+ throw std::length_error("integer socket option resize");
+ }
+
+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 BOOST_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 BOOST_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 BOOST_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>
+ ::linger* data(const Protocol&)
+ {
+ return &value_;
+ }
+
+ // Get the address of the linger data.
+ template <typename Protocol>
+ const ::linger* 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_))
+ throw std::length_error("linger socket option resize");
+ }
+
+private:
+ ::linger value_;
+};
+
+} // namespace socket_option
+} // namespace detail
+} // namespace asio
+} // namespace boost
+
+#include <boost/asio/detail/pop_options.hpp>
+
+#endif // BOOST_ASIO_DETAIL_SOCKET_OPTION_HPP
diff --git a/3rdParty/Boost/boost/asio/detail/socket_select_interrupter.hpp b/3rdParty/Boost/boost/asio/detail/socket_select_interrupter.hpp
new file mode 100644
index 0000000..a767ba0
--- /dev/null
+++ b/3rdParty/Boost/boost/asio/detail/socket_select_interrupter.hpp
@@ -0,0 +1,189 @@
+//
+// socket_select_interrupter.hpp
+// ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+//
+// Copyright (c) 2003-2008 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 BOOST_ASIO_DETAIL_SOCKET_SELECT_INTERRUPTER_HPP
+#define BOOST_ASIO_DETAIL_SOCKET_SELECT_INTERRUPTER_HPP
+
+#if defined(_MSC_VER) && (_MSC_VER >= 1200)
+# pragma once
+#endif // defined(_MSC_VER) && (_MSC_VER >= 1200)
+
+#include <boost/asio/detail/push_options.hpp>
+
+#include <boost/asio/detail/push_options.hpp>
+#include <cstdlib>
+#include <boost/throw_exception.hpp>
+#include <boost/system/system_error.hpp>
+#include <boost/asio/detail/pop_options.hpp>
+
+#include <boost/asio/error.hpp>
+#include <boost/asio/detail/socket_holder.hpp>
+#include <boost/asio/detail/socket_ops.hpp>
+#include <boost/asio/detail/socket_types.hpp>
+
+namespace boost {
+namespace asio {
+namespace detail {
+
+class socket_select_interrupter
+{
+public:
+ // Constructor.
+ socket_select_interrupter()
+ {
+ boost::system::error_code ec;
+ socket_holder acceptor(socket_ops::socket(
+ AF_INET, SOCK_STREAM, IPPROTO_TCP, ec));
+ if (acceptor.get() == invalid_socket)
+ {
+ boost::system::system_error e(ec, "socket_select_interrupter");
+ boost::throw_exception(e);
+ }
+
+ int opt = 1;
+ socket_ops::setsockopt(acceptor.get(),
+ 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 = inet_addr("127.0.0.1");
+ addr.sin_port = 0;
+ if (socket_ops::bind(acceptor.get(), (const socket_addr_type*)&addr,
+ addr_len, ec) == socket_error_retval)
+ {
+ boost::system::system_error e(ec, "socket_select_interrupter");
+ boost::throw_exception(e);
+ }
+
+ if (socket_ops::getsockname(acceptor.get(), (socket_addr_type*)&addr,
+ &addr_len, ec) == socket_error_retval)
+ {
+ boost::system::system_error e(ec, "socket_select_interrupter");
+ boost::throw_exception(e);
+ }
+
+ if (socket_ops::listen(acceptor.get(),
+ SOMAXCONN, ec) == socket_error_retval)
+ {
+ boost::system::system_error e(ec, "socket_select_interrupter");
+ boost::throw_exception(e);
+ }
+
+ socket_holder client(socket_ops::socket(
+ AF_INET, SOCK_STREAM, IPPROTO_TCP, ec));
+ if (client.get() == invalid_socket)
+ {
+ boost::system::system_error e(ec, "socket_select_interrupter");
+ boost::throw_exception(e);
+ }
+
+ if (socket_ops::connect(client.get(), (const socket_addr_type*)&addr,
+ addr_len, ec) == socket_error_retval)
+ {
+ boost::system::system_error e(ec, "socket_select_interrupter");
+ boost::throw_exception(e);
+ }
+
+ socket_holder server(socket_ops::accept(acceptor.get(), 0, 0, ec));
+ if (server.get() == invalid_socket)
+ {
+ boost::system::system_error e(ec, "socket_select_interrupter");
+ boost::throw_exception(e);
+ }
+
+ ioctl_arg_type non_blocking = 1;
+ if (socket_ops::ioctl(client.get(), FIONBIO, &non_blocking, ec))
+ {
+ boost::system::system_error e(ec, "socket_select_interrupter");
+ boost::throw_exception(e);
+ }
+
+ opt = 1;
+ socket_ops::setsockopt(client.get(),
+ IPPROTO_TCP, TCP_NODELAY, &opt, sizeof(opt), ec);
+
+ non_blocking = 1;
+ if (socket_ops::ioctl(server.get(), FIONBIO, &non_blocking, ec))
+ {
+ boost::system::system_error e(ec, "socket_select_interrupter");
+ boost::throw_exception(e);
+ }
+
+ opt = 1;
+ socket_ops::setsockopt(server.get(),
+ IPPROTO_TCP, TCP_NODELAY, &opt, sizeof(opt), ec);
+
+ read_descriptor_ = server.release();
+ write_descriptor_ = client.release();
+ }
+
+ // Destructor.
+ ~socket_select_interrupter()
+ {
+ boost::system::error_code ec;
+ if (read_descriptor_ != invalid_socket)
+ socket_ops::close(read_descriptor_, ec);
+ if (write_descriptor_ != invalid_socket)
+ socket_ops::close(write_descriptor_, ec);
+ }
+
+ // Interrupt the select call.
+ void interrupt()
+ {
+ char byte = 0;
+ socket_ops::buf b;
+ socket_ops::init_buf(b, &byte, 1);
+ boost::system::error_code ec;
+ socket_ops::send(write_descriptor_, &b, 1, 0, ec);
+ }
+
+ // Reset the select interrupt. Returns true if the call was interrupted.
+ bool reset()
+ {
+ char data[1024];
+ socket_ops::buf b;
+ socket_ops::init_buf(b, data, sizeof(data));
+ boost::system::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;
+ }
+
+ // Get the read descriptor to be passed to select.
+ socket_type read_descriptor() const
+ {
+ return read_descriptor_;
+ }
+
+private:
+ // 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
+} // namespace boost
+
+#include <boost/asio/detail/pop_options.hpp>
+
+#endif // BOOST_ASIO_DETAIL_SOCKET_SELECT_INTERRUPTER_HPP
diff --git a/3rdParty/Boost/boost/asio/detail/socket_types.hpp b/3rdParty/Boost/boost/asio/detail/socket_types.hpp
new file mode 100644
index 0000000..c7b6a75
--- /dev/null
+++ b/3rdParty/Boost/boost/asio/detail/socket_types.hpp
@@ -0,0 +1,212 @@
+//
+// socket_types.hpp
+// ~~~~~~~~~~~~~~~~
+//
+// Copyright (c) 2003-2008 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 BOOST_ASIO_DETAIL_SOCKET_TYPES_HPP
+#define BOOST_ASIO_DETAIL_SOCKET_TYPES_HPP
+
+#if defined(_MSC_VER) && (_MSC_VER >= 1200)
+# pragma once
+#endif // defined(_MSC_VER) && (_MSC_VER >= 1200)
+
+#include <boost/asio/detail/push_options.hpp>
+
+#include <boost/asio/detail/push_options.hpp>
+#include <boost/config.hpp>
+#include <boost/asio/detail/pop_options.hpp>
+
+#include <boost/asio/detail/push_options.hpp>
+#if defined(BOOST_WINDOWS) || defined(__CYGWIN__)
+# if defined(_WINSOCKAPI_) && !defined(_WINSOCK2API_)
+# error WinSock.h has already been included
+# endif // defined(_WINSOCKAPI_) && !defined(_WINSOCK2API_)
+# 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__)
+# include <stdlib.h> // Needed for __errno
+# 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)
+# if !defined(_WSPIAPI_H_)
+# define _WSPIAPI_H_
+# define BOOST_ASIO_WSPIAPI_H_DEFINED
+# endif // !defined(_WSPIAPI_H_)
+# endif // defined(__BORLANDC__)
+# if !defined(BOOST_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(BOOST_ASIO_NO_WIN32_LEAN_AND_MEAN)
+# 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)
+# if !defined(NOMINMAX)
+# define NOMINMAX 1
+# endif // !defined(NOMINMAX)
+# endif // defined(__CYGWIN__)
+# include <winsock2.h>
+# include <ws2tcpip.h>
+# include <mswsock.h>
+# if defined(BOOST_ASIO_WSPIAPI_H_DEFINED)
+# undef _WSPIAPI_H_
+# undef BOOST_ASIO_WSPIAPI_H_DEFINED
+# endif // defined(BOOST_ASIO_WSPIAPI_H_DEFINED)
+# if !defined(BOOST_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")
+# pragma comment(lib, "mswsock.lib")
+# endif // defined(_MSC_VER) || defined(__BORLANDC__)
+# endif // !defined(BOOST_ASIO_NO_DEFAULT_LINKED_LIBS)
+# include <boost/asio/detail/old_win_sdk_compat.hpp>
+#else
+# include <sys/ioctl.h>
+# include <sys/poll.h>
+# include <sys/types.h>
+# if defined(__hpux) && !defined(__HP_aCC)
+# include <sys/time.h>
+# else
+# include <sys/select.h>
+# endif
+# include <sys/socket.h>
+# include <sys/uio.h>
+# include <sys/un.h>
+# include <netinet/in.h>
+# include <netinet/tcp.h>
+# 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 <boost/asio/detail/pop_options.hpp>
+
+namespace boost {
+namespace asio {
+namespace detail {
+
+#if defined(BOOST_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(BOOST_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 unsigned long ioctl_arg_type;
+typedef u_long u_long_type;
+typedef u_short u_short_type;
+const int shutdown_receive = SD_RECEIVE;
+const int shutdown_send = SD_SEND;
+const int shutdown_both = SD_BOTH;
+const int message_peek = MSG_PEEK;
+const int message_out_of_band = MSG_OOB;
+const int message_do_not_route = MSG_DONTROUTE;
+# 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;
+const int max_addr_v6_str_len = INET6_ADDRSTRLEN + 1 + IF_NAMESIZE;
+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 int ioctl_arg_type;
+typedef uint32_t u_long_type;
+typedef uint16_t u_short_type;
+const int shutdown_receive = SHUT_RD;
+const int shutdown_send = SHUT_WR;
+const int shutdown_both = SHUT_RDWR;
+const int message_peek = MSG_PEEK;
+const int message_out_of_band = MSG_OOB;
+const int message_do_not_route = MSG_DONTROUTE;
+# 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
+} // namespace boost
+
+#include <boost/asio/detail/pop_options.hpp>
+
+#endif // BOOST_ASIO_DETAIL_SOCKET_TYPES_HPP
diff --git a/3rdParty/Boost/boost/asio/detail/strand_service.hpp b/3rdParty/Boost/boost/asio/detail/strand_service.hpp
new file mode 100644
index 0000000..2c89a61
--- /dev/null
+++ b/3rdParty/Boost/boost/asio/detail/strand_service.hpp
@@ -0,0 +1,532 @@
+//
+// strand_service.hpp
+// ~~~~~~~~~~~~~~~~~~
+//
+// Copyright (c) 2003-2008 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 BOOST_ASIO_DETAIL_STRAND_SERVICE_HPP
+#define BOOST_ASIO_DETAIL_STRAND_SERVICE_HPP
+
+#if defined(_MSC_VER) && (_MSC_VER >= 1200)
+# pragma once
+#endif // defined(_MSC_VER) && (_MSC_VER >= 1200)
+
+#include <boost/asio/detail/push_options.hpp>
+
+#include <boost/asio/detail/push_options.hpp>
+#include <boost/aligned_storage.hpp>
+#include <boost/assert.hpp>
+#include <boost/detail/atomic_count.hpp>
+#include <boost/intrusive_ptr.hpp>
+#include <boost/asio/detail/pop_options.hpp>
+
+#include <boost/asio/io_service.hpp>
+#include <boost/asio/detail/bind_handler.hpp>
+#include <boost/asio/detail/call_stack.hpp>
+#include <boost/asio/detail/handler_alloc_helpers.hpp>
+#include <boost/asio/detail/handler_invoke_helpers.hpp>
+#include <boost/asio/detail/mutex.hpp>
+#include <boost/asio/detail/noncopyable.hpp>
+#include <boost/asio/detail/service_base.hpp>
+
+namespace boost {
+namespace asio {
+namespace detail {
+
+// Default service implementation for a strand.
+class strand_service
+ : public boost::asio::detail::service_base<strand_service>
+{
+public:
+ class handler_base;
+ class invoke_current_handler;
+ class post_next_waiter_on_exit;
+
+ // The underlying implementation of a strand.
+ class strand_impl
+ {
+#if defined (__BORLANDC__)
+ public:
+#else
+ private:
+#endif
+ void add_ref()
+ {
+ ++ref_count_;
+ }
+
+ void release()
+ {
+ if (--ref_count_ == 0)
+ delete this;
+ }
+
+ private:
+ // Only this service will have access to the internal values.
+ friend class strand_service;
+ friend class post_next_waiter_on_exit;
+ friend class invoke_current_handler;
+
+ strand_impl(strand_service& owner)
+ : owner_(owner),
+ current_handler_(0),
+ first_waiter_(0),
+ last_waiter_(0),
+ ref_count_(0)
+ {
+ // Insert implementation into linked list of all implementations.
+ boost::asio::detail::mutex::scoped_lock lock(owner_.mutex_);
+ next_ = owner_.impl_list_;
+ prev_ = 0;
+ if (owner_.impl_list_)
+ owner_.impl_list_->prev_ = this;
+ owner_.impl_list_ = this;
+ }
+
+ ~strand_impl()
+ {
+ // Remove implementation from linked list of all implementations.
+ boost::asio::detail::mutex::scoped_lock lock(owner_.mutex_);
+ if (owner_.impl_list_ == this)
+ owner_.impl_list_ = next_;
+ if (prev_)
+ prev_->next_ = next_;
+ if (next_)
+ next_->prev_= prev_;
+ next_ = 0;
+ prev_ = 0;
+ lock.unlock();
+
+ if (current_handler_)
+ {
+ current_handler_->destroy();
+ }
+
+ while (first_waiter_)
+ {
+ handler_base* next = first_waiter_->next_;
+ first_waiter_->destroy();
+ first_waiter_ = next;
+ }
+ }
+
+ // Mutex to protect access to internal data.
+ boost::asio::detail::mutex mutex_;
+
+ // The service that owns this implementation.
+ strand_service& owner_;
+
+ // The handler that is ready to execute. If this pointer is non-null then it
+ // indicates that a handler holds the lock.
+ handler_base* current_handler_;
+
+ // The start of the list of waiting handlers for the strand.
+ handler_base* first_waiter_;
+
+ // The end of the list of waiting handlers for the strand.
+ handler_base* last_waiter_;
+
+ // Storage for posted handlers.
+ typedef boost::aligned_storage<128> handler_storage_type;
+#if defined(__BORLANDC__)
+ boost::aligned_storage<128> handler_storage_;
+#else
+ handler_storage_type handler_storage_;
+#endif
+
+ // Pointers to adjacent socket implementations in linked list.
+ strand_impl* next_;
+ strand_impl* prev_;
+
+ // The reference count on the strand implementation.
+ boost::detail::atomic_count ref_count_;
+
+#if !defined(__BORLANDC__)
+ friend void intrusive_ptr_add_ref(strand_impl* p)
+ {
+ p->add_ref();
+ }
+
+ friend void intrusive_ptr_release(strand_impl* p)
+ {
+ p->release();
+ }
+#endif
+ };
+
+ friend class strand_impl;
+
+ typedef boost::intrusive_ptr<strand_impl> implementation_type;
+
+ // Base class for all handler types.
+ class handler_base
+ {
+ public:
+ typedef void (*invoke_func_type)(handler_base*,
+ strand_service&, implementation_type&);
+ typedef void (*destroy_func_type)(handler_base*);
+
+ handler_base(invoke_func_type invoke_func, destroy_func_type destroy_func)
+ : next_(0),
+ invoke_func_(invoke_func),
+ destroy_func_(destroy_func)
+ {
+ }
+
+ void invoke(strand_service& service_impl, implementation_type& impl)
+ {
+ invoke_func_(this, service_impl, impl);
+ }
+
+ void destroy()
+ {
+ destroy_func_(this);
+ }
+
+ protected:
+ ~handler_base()
+ {
+ }
+
+ private:
+ friend class strand_service;
+ friend class strand_impl;
+ friend class post_next_waiter_on_exit;
+ handler_base* next_;
+ invoke_func_type invoke_func_;
+ destroy_func_type destroy_func_;
+ };
+
+ // Helper class to allow handlers to be dispatched.
+ class invoke_current_handler
+ {
+ public:
+ invoke_current_handler(strand_service& service_impl,
+ const implementation_type& impl)
+ : service_impl_(service_impl),
+ impl_(impl)
+ {
+ }
+
+ void operator()()
+ {
+ impl_->current_handler_->invoke(service_impl_, impl_);
+ }
+
+ friend void* asio_handler_allocate(std::size_t size,
+ invoke_current_handler* this_handler)
+ {
+ return this_handler->do_handler_allocate(size);
+ }
+
+ friend void asio_handler_deallocate(void*, std::size_t,
+ invoke_current_handler*)
+ {
+ }
+
+ void* do_handler_allocate(std::size_t size)
+ {
+#if defined(__BORLANDC__)
+ BOOST_ASSERT(size <= boost::aligned_storage<128>::size);
+#else
+ BOOST_ASSERT(size <= strand_impl::handler_storage_type::size);
+#endif
+ (void)size;
+ return impl_->handler_storage_.address();
+ }
+
+ // The asio_handler_invoke hook is not defined here since the default one
+ // provides the correct behaviour, and including it here breaks MSVC 7.1
+ // in some situations.
+
+ private:
+ strand_service& service_impl_;
+ implementation_type impl_;
+ };
+
+ // Helper class to automatically enqueue next waiter on block exit.
+ class post_next_waiter_on_exit
+ {
+ public:
+ post_next_waiter_on_exit(strand_service& service_impl,
+ implementation_type& impl)
+ : service_impl_(service_impl),
+ impl_(impl),
+ cancelled_(false)
+ {
+ }
+
+ ~post_next_waiter_on_exit()
+ {
+ if (!cancelled_)
+ {
+ boost::asio::detail::mutex::scoped_lock lock(impl_->mutex_);
+ impl_->current_handler_ = impl_->first_waiter_;
+ if (impl_->current_handler_)
+ {
+ impl_->first_waiter_ = impl_->first_waiter_->next_;
+ if (impl_->first_waiter_ == 0)
+ impl_->last_waiter_ = 0;
+ lock.unlock();
+ service_impl_.get_io_service().post(
+ invoke_current_handler(service_impl_, impl_));
+ }
+ }
+ }
+
+ void cancel()
+ {
+ cancelled_ = true;
+ }
+
+ private:
+ strand_service& service_impl_;
+ implementation_type& impl_;
+ bool cancelled_;
+ };
+
+ // Class template for a waiter.
+ template <typename Handler>
+ class handler_wrapper
+ : public handler_base
+ {
+ public:
+ handler_wrapper(Handler handler)
+ : handler_base(&handler_wrapper<Handler>::do_invoke,
+ &handler_wrapper<Handler>::do_destroy),
+ handler_(handler)
+ {
+ }
+
+ static void do_invoke(handler_base* base,
+ strand_service& service_impl, implementation_type& impl)
+ {
+ // Take ownership of the handler object.
+ typedef handler_wrapper<Handler> this_type;
+ this_type* h(static_cast<this_type*>(base));
+ typedef handler_alloc_traits<Handler, this_type> alloc_traits;
+ handler_ptr<alloc_traits> ptr(h->handler_, h);
+
+ post_next_waiter_on_exit p1(service_impl, impl);
+
+ // Make a copy of the handler so that the memory can be deallocated before
+ // the upcall is made.
+ Handler handler(h->handler_);
+
+ // A handler object must still be valid when the next waiter is posted
+ // since destroying the last handler might cause the strand object to be
+ // destroyed. Therefore we create a second post_next_waiter_on_exit object
+ // that will be destroyed before the handler object.
+ p1.cancel();
+ post_next_waiter_on_exit p2(service_impl, impl);
+
+ // Free the memory associated with the handler.
+ ptr.reset();
+
+ // Indicate that this strand is executing on the current thread.
+ call_stack<strand_impl>::context ctx(impl.get());
+
+ // Make the upcall.
+ boost_asio_handler_invoke_helpers::invoke(handler, &handler);
+ }
+
+ static void do_destroy(handler_base* base)
+ {
+ // Take ownership of the handler object.
+ typedef handler_wrapper<Handler> this_type;
+ this_type* h(static_cast<this_type*>(base));
+ typedef handler_alloc_traits<Handler, this_type> alloc_traits;
+ handler_ptr<alloc_traits> ptr(h->handler_, h);
+
+ // 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(h->handler_);
+ (void)handler;
+
+ // Free the memory associated with the handler.
+ ptr.reset();
+ }
+
+ private:
+ Handler handler_;
+ };
+
+ // Construct a new strand service for the specified io_service.
+ explicit strand_service(boost::asio::io_service& io_service)
+ : boost::asio::detail::service_base<strand_service>(io_service),
+ mutex_(),
+ impl_list_(0)
+ {
+ }
+
+ // Destroy all user-defined handler objects owned by the service.
+ void shutdown_service()
+ {
+ // Construct a list of all handlers to be destroyed.
+ boost::asio::detail::mutex::scoped_lock lock(mutex_);
+ strand_impl* impl = impl_list_;
+ handler_base* first_handler = 0;
+ while (impl)
+ {
+ if (impl->current_handler_)
+ {
+ impl->current_handler_->next_ = first_handler;
+ first_handler = impl->current_handler_;
+ impl->current_handler_ = 0;
+ }
+ if (impl->first_waiter_)
+ {
+ impl->last_waiter_->next_ = first_handler;
+ first_handler = impl->first_waiter_;
+ impl->first_waiter_ = 0;
+ impl->last_waiter_ = 0;
+ }
+ impl = impl->next_;
+ }
+
+ // Destroy all handlers without holding the lock.
+ lock.unlock();
+ while (first_handler)
+ {
+ handler_base* next = first_handler->next_;
+ first_handler->destroy();
+ first_handler = next;
+ }
+ }
+
+ // Construct a new strand implementation.
+ void construct(implementation_type& impl)
+ {
+ impl = implementation_type(new strand_impl(*this));
+ }
+
+ // Destroy a strand implementation.
+ void destroy(implementation_type& impl)
+ {
+ implementation_type().swap(impl);
+ }
+
+ // Request the io_service to invoke the given handler.
+ template <typename Handler>
+ void dispatch(implementation_type& impl, Handler handler)
+ {
+ if (call_stack<strand_impl>::contains(impl.get()))
+ {
+ boost_asio_handler_invoke_helpers::invoke(handler, &handler);
+ }
+ else
+ {
+ // Allocate and construct an object to wrap the handler.
+ typedef handler_wrapper<Handler> value_type;
+ typedef handler_alloc_traits<Handler, value_type> alloc_traits;
+ raw_handler_ptr<alloc_traits> raw_ptr(handler);
+ handler_ptr<alloc_traits> ptr(raw_ptr, handler);
+
+ boost::asio::detail::mutex::scoped_lock lock(impl->mutex_);
+
+ if (impl->current_handler_ == 0)
+ {
+ // This handler now has the lock, so can be dispatched immediately.
+ impl->current_handler_ = ptr.release();
+ lock.unlock();
+ this->get_io_service().dispatch(invoke_current_handler(*this, impl));
+ }
+ else
+ {
+ // Another handler already holds the lock, so this handler must join
+ // the list of waiters. The handler will be posted automatically when
+ // its turn comes.
+ if (impl->last_waiter_)
+ {
+ impl->last_waiter_->next_ = ptr.get();
+ impl->last_waiter_ = impl->last_waiter_->next_;
+ }
+ else
+ {
+ impl->first_waiter_ = ptr.get();
+ impl->last_waiter_ = ptr.get();
+ }
+ ptr.release();
+ }
+ }
+ }
+
+ // Request the io_service to invoke the given handler and return immediately.
+ template <typename Handler>
+ void post(implementation_type& impl, Handler handler)
+ {
+ // Allocate and construct an object to wrap the handler.
+ typedef handler_wrapper<Handler> value_type;
+ typedef handler_alloc_traits<Handler, value_type> alloc_traits;
+ raw_handler_ptr<alloc_traits> raw_ptr(handler);
+ handler_ptr<alloc_traits> ptr(raw_ptr, handler);
+
+ boost::asio::detail::mutex::scoped_lock lock(impl->mutex_);
+
+ if (impl->current_handler_ == 0)
+ {
+ // This handler now has the lock, so can be dispatched immediately.
+ impl->current_handler_ = ptr.release();
+ lock.unlock();
+ this->get_io_service().post(invoke_current_handler(*this, impl));
+ }
+ else
+ {
+ // Another handler already holds the lock, so this handler must join the
+ // list of waiters. The handler will be posted automatically when its turn
+ // comes.
+ if (impl->last_waiter_)
+ {
+ impl->last_waiter_->next_ = ptr.get();
+ impl->last_waiter_ = impl->last_waiter_->next_;
+ }
+ else
+ {
+ impl->first_waiter_ = ptr.get();
+ impl->last_waiter_ = ptr.get();
+ }
+ ptr.release();
+ }
+ }
+
+private:
+ // Mutex to protect access to the linked list of implementations.
+ boost::asio::detail::mutex mutex_;
+
+ // The head of a linked list of all implementations.
+ strand_impl* impl_list_;
+};
+
+} // namespace detail
+} // namespace asio
+} // namespace boost
+
+#if defined(__BORLANDC__)
+
+namespace boost {
+
+inline void intrusive_ptr_add_ref(
+ boost::asio::detail::strand_service::strand_impl* p)
+{
+ p->add_ref();
+}
+
+inline void intrusive_ptr_release(
+ boost::asio::detail::strand_service::strand_impl* p)
+{
+ p->release();
+}
+
+} // namespace boost
+
+#endif // defined(__BORLANDC__)
+
+#include <boost/asio/detail/pop_options.hpp>
+
+#endif // BOOST_ASIO_DETAIL_STRAND_SERVICE_HPP
diff --git a/3rdParty/Boost/boost/asio/detail/task_io_service.hpp b/3rdParty/Boost/boost/asio/detail/task_io_service.hpp
new file mode 100644
index 0000000..eeae6b0
--- /dev/null
+++ b/3rdParty/Boost/boost/asio/detail/task_io_service.hpp
@@ -0,0 +1,438 @@
+//
+// task_io_service.hpp
+// ~~~~~~~~~~~~~~~~~~~
+//
+// Copyright (c) 2003-2008 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 BOOST_ASIO_DETAIL_TASK_IO_SERVICE_HPP
+#define BOOST_ASIO_DETAIL_TASK_IO_SERVICE_HPP
+
+#if defined(_MSC_VER) && (_MSC_VER >= 1200)
+# pragma once
+#endif // defined(_MSC_VER) && (_MSC_VER >= 1200)
+
+#if defined(BOOST_ASIO_ENABLE_TWO_LOCK_QUEUE)
+#include <boost/asio/detail/task_io_service_2lock.hpp>
+#else // defined(BOOST_ASIO_ENABLE_TWO_LOCK_QUEUE)
+
+#include <boost/asio/detail/push_options.hpp>
+
+#include <boost/asio/io_service.hpp>
+#include <boost/asio/detail/call_stack.hpp>
+#include <boost/asio/detail/event.hpp>
+#include <boost/asio/detail/handler_alloc_helpers.hpp>
+#include <boost/asio/detail/handler_invoke_helpers.hpp>
+#include <boost/asio/detail/handler_queue.hpp>
+#include <boost/asio/detail/mutex.hpp>
+#include <boost/asio/detail/service_base.hpp>
+#include <boost/asio/detail/task_io_service_fwd.hpp>
+
+namespace boost {
+namespace asio {
+namespace detail {
+
+template <typename Task>
+class task_io_service
+ : public boost::asio::detail::service_base<task_io_service<Task> >
+{
+public:
+ // Constructor.
+ task_io_service(boost::asio::io_service& io_service)
+ : boost::asio::detail::service_base<task_io_service<Task> >(io_service),
+ mutex_(),
+ task_(0),
+ task_interrupted_(true),
+ outstanding_work_(0),
+ stopped_(false),
+ shutdown_(false),
+ first_idle_thread_(0)
+ {
+ }
+
+ void init(size_t /*concurrency_hint*/)
+ {
+ }
+
+ // Destroy all user-defined handler objects owned by the service.
+ void shutdown_service()
+ {
+ boost::asio::detail::mutex::scoped_lock lock(mutex_);
+ shutdown_ = true;
+ lock.unlock();
+
+ // Destroy handler objects.
+ while (!handler_queue_.empty())
+ {
+ handler_queue::handler* h = handler_queue_.front();
+ handler_queue_.pop();
+ if (h != &task_handler_)
+ h->destroy();
+ }
+
+ // Reset to initial state.
+ task_ = 0;
+ }
+
+ // Initialise the task, if required.
+ void init_task()
+ {
+ boost::asio::detail::mutex::scoped_lock lock(mutex_);
+ if (!shutdown_ && !task_)
+ {
+ task_ = &use_service<Task>(this->get_io_service());
+ handler_queue_.push(&task_handler_);
+ interrupt_one_idle_thread(lock);
+ }
+ }
+
+ // Run the event loop until interrupted or no more work.
+ size_t run(boost::system::error_code& ec)
+ {
+ typename call_stack<task_io_service>::context ctx(this);
+
+ idle_thread_info this_idle_thread;
+ this_idle_thread.next = 0;
+
+ boost::asio::detail::mutex::scoped_lock lock(mutex_);
+
+ size_t n = 0;
+ while (do_one(lock, &this_idle_thread, ec))
+ if (n != (std::numeric_limits<size_t>::max)())
+ ++n;
+ return n;
+ }
+
+ // Run until interrupted or one operation is performed.
+ size_t run_one(boost::system::error_code& ec)
+ {
+ typename call_stack<task_io_service>::context ctx(this);
+
+ idle_thread_info this_idle_thread;
+ this_idle_thread.next = 0;
+
+ boost::asio::detail::mutex::scoped_lock lock(mutex_);
+
+ return do_one(lock, &this_idle_thread, ec);
+ }
+
+ // Poll for operations without blocking.
+ size_t poll(boost::system::error_code& ec)
+ {
+ typename call_stack<task_io_service>::context ctx(this);
+
+ boost::asio::detail::mutex::scoped_lock lock(mutex_);
+
+ size_t n = 0;
+ while (do_one(lock, 0, ec))
+ if (n != (std::numeric_limits<size_t>::max)())
+ ++n;
+ return n;
+ }
+
+ // Poll for one operation without blocking.
+ size_t poll_one(boost::system::error_code& ec)
+ {
+ typename call_stack<task_io_service>::context ctx(this);
+
+ boost::asio::detail::mutex::scoped_lock lock(mutex_);
+
+ return do_one(lock, 0, ec);
+ }
+
+ // Interrupt the event processing loop.
+ void stop()
+ {
+ boost::asio::detail::mutex::scoped_lock lock(mutex_);
+ stop_all_threads(lock);
+ }
+
+ // Reset in preparation for a subsequent run invocation.
+ void reset()
+ {
+ boost::asio::detail::mutex::scoped_lock lock(mutex_);
+ stopped_ = false;
+ }
+
+ // Notify that some work has started.
+ void work_started()
+ {
+ boost::asio::detail::mutex::scoped_lock lock(mutex_);
+ ++outstanding_work_;
+ }
+
+ // Notify that some work has finished.
+ void work_finished()
+ {
+ boost::asio::detail::mutex::scoped_lock lock(mutex_);
+ if (--outstanding_work_ == 0)
+ stop_all_threads(lock);
+ }
+
+ // Request invocation of the given handler.
+ template <typename Handler>
+ void dispatch(Handler handler)
+ {
+ if (call_stack<task_io_service>::contains(this))
+ boost_asio_handler_invoke_helpers::invoke(handler, &handler);
+ else
+ post(handler);
+ }
+
+ // Request invocation of the given handler and return immediately.
+ template <typename Handler>
+ void post(Handler handler)
+ {
+ // Allocate and construct an operation to wrap the handler.
+ handler_queue::scoped_ptr ptr(handler_queue::wrap(handler));
+
+ boost::asio::detail::mutex::scoped_lock lock(mutex_);
+
+ // If the service has been shut down we silently discard the handler.
+ if (shutdown_)
+ return;
+
+ // Add the handler to the end of the queue.
+ handler_queue_.push(ptr.get());
+ ptr.release();
+
+ // An undelivered handler is treated as unfinished work.
+ ++outstanding_work_;
+
+ // Wake up a thread to execute the handler.
+ if (!interrupt_one_idle_thread(lock))
+ {
+ if (!task_interrupted_ && task_)
+ {
+ task_interrupted_ = true;
+ task_->interrupt();
+ }
+ }
+ }
+
+private:
+ struct idle_thread_info;
+
+ size_t do_one(boost::asio::detail::mutex::scoped_lock& lock,
+ idle_thread_info* this_idle_thread, boost::system::error_code& ec)
+ {
+ if (outstanding_work_ == 0 && !stopped_)
+ {
+ stop_all_threads(lock);
+ ec = boost::system::error_code();
+ return 0;
+ }
+
+ bool polling = !this_idle_thread;
+ bool task_has_run = false;
+ while (!stopped_)
+ {
+ if (!handler_queue_.empty())
+ {
+ // Prepare to execute first handler from queue.
+ handler_queue::handler* h = handler_queue_.front();
+ handler_queue_.pop();
+
+ if (h == &task_handler_)
+ {
+ bool more_handlers = (!handler_queue_.empty());
+ task_interrupted_ = more_handlers || polling;
+
+ // If the task has already run and we're polling then we're done.
+ if (task_has_run && polling)
+ {
+ task_interrupted_ = true;
+ handler_queue_.push(&task_handler_);
+ ec = boost::system::error_code();
+ return 0;
+ }
+ task_has_run = true;
+
+ lock.unlock();
+ task_cleanup c(lock, *this);
+
+ // Run the task. May throw an exception. Only block if the handler
+ // queue is empty and we have an idle_thread_info object, otherwise
+ // we want to return as soon as possible.
+ task_->run(!more_handlers && !polling);
+ }
+ else
+ {
+ lock.unlock();
+ handler_cleanup c(lock, *this);
+
+ // Invoke the handler. May throw an exception.
+ h->invoke(); // invoke() deletes the handler object
+
+ ec = boost::system::error_code();
+ return 1;
+ }
+ }
+ else if (this_idle_thread)
+ {
+ // Nothing to run right now, so just wait for work to do.
+ this_idle_thread->next = first_idle_thread_;
+ first_idle_thread_ = this_idle_thread;
+ this_idle_thread->wakeup_event.clear(lock);
+ this_idle_thread->wakeup_event.wait(lock);
+ }
+ else
+ {
+ ec = boost::system::error_code();
+ return 0;
+ }
+ }
+
+ ec = boost::system::error_code();
+ return 0;
+ }
+
+ // Stop the task and all idle threads.
+ void stop_all_threads(
+ boost::asio::detail::mutex::scoped_lock& lock)
+ {
+ stopped_ = true;
+ interrupt_all_idle_threads(lock);
+ if (!task_interrupted_ && task_)
+ {
+ task_interrupted_ = true;
+ task_->interrupt();
+ }
+ }
+
+ // Interrupt a single idle thread. Returns true if a thread was interrupted,
+ // false if no running thread could be found to interrupt.
+ bool interrupt_one_idle_thread(
+ boost::asio::detail::mutex::scoped_lock& lock)
+ {
+ if (first_idle_thread_)
+ {
+ idle_thread_info* idle_thread = first_idle_thread_;
+ first_idle_thread_ = idle_thread->next;
+ idle_thread->next = 0;
+ idle_thread->wakeup_event.signal(lock);
+ return true;
+ }
+ return false;
+ }
+
+ // Interrupt all idle threads.
+ void interrupt_all_idle_threads(
+ boost::asio::detail::mutex::scoped_lock& lock)
+ {
+ while (first_idle_thread_)
+ {
+ idle_thread_info* idle_thread = first_idle_thread_;
+ first_idle_thread_ = idle_thread->next;
+ idle_thread->next = 0;
+ idle_thread->wakeup_event.signal(lock);
+ }
+ }
+
+ // Helper class to perform task-related operations on block exit.
+ class task_cleanup;
+ friend class task_cleanup;
+ class task_cleanup
+ {
+ public:
+ task_cleanup(boost::asio::detail::mutex::scoped_lock& lock,
+ task_io_service& task_io_svc)
+ : lock_(lock),
+ task_io_service_(task_io_svc)
+ {
+ }
+
+ ~task_cleanup()
+ {
+ // Reinsert the task at the end of the handler queue.
+ lock_.lock();
+ task_io_service_.task_interrupted_ = true;
+ task_io_service_.handler_queue_.push(&task_io_service_.task_handler_);
+ }
+
+ private:
+ boost::asio::detail::mutex::scoped_lock& lock_;
+ task_io_service& task_io_service_;
+ };
+
+ // Helper class to perform handler-related operations on block exit.
+ class handler_cleanup;
+ friend class handler_cleanup;
+ class handler_cleanup
+ {
+ public:
+ handler_cleanup(boost::asio::detail::mutex::scoped_lock& lock,
+ task_io_service& task_io_svc)
+ : lock_(lock),
+ task_io_service_(task_io_svc)
+ {
+ }
+
+ ~handler_cleanup()
+ {
+ lock_.lock();
+ if (--task_io_service_.outstanding_work_ == 0)
+ task_io_service_.stop_all_threads(lock_);
+ }
+
+ private:
+ boost::asio::detail::mutex::scoped_lock& lock_;
+ task_io_service& task_io_service_;
+ };
+
+ // Mutex to protect access to internal data.
+ boost::asio::detail::mutex mutex_;
+
+ // The task to be run by this service.
+ Task* task_;
+
+ // Handler object to represent the position of the task in the queue.
+ class task_handler
+ : public handler_queue::handler
+ {
+ public:
+ task_handler()
+ : handler_queue::handler(0, 0)
+ {
+ }
+ } task_handler_;
+
+ // Whether the task has been interrupted.
+ bool task_interrupted_;
+
+ // The count of unfinished work.
+ int outstanding_work_;
+
+ // The queue of handlers that are ready to be delivered.
+ handler_queue handler_queue_;
+
+ // Flag to indicate that the dispatcher has been stopped.
+ bool stopped_;
+
+ // Flag to indicate that the dispatcher has been shut down.
+ bool shutdown_;
+
+ // Structure containing information about an idle thread.
+ struct idle_thread_info
+ {
+ event wakeup_event;
+ idle_thread_info* next;
+ };
+
+ // The number of threads that are currently idle.
+ idle_thread_info* first_idle_thread_;
+};
+
+} // namespace detail
+} // namespace asio
+} // namespace boost
+
+#include <boost/system/error_code.hpp>
+#include <boost/asio/detail/pop_options.hpp>
+
+#endif // defined(BOOST_ASIO_ENABLE_TWO_LOCK_QUEUE)
+
+#endif // BOOST_ASIO_DETAIL_TASK_IO_SERVICE_HPP
diff --git a/3rdParty/Boost/boost/asio/detail/task_io_service_2lock.hpp b/3rdParty/Boost/boost/asio/detail/task_io_service_2lock.hpp
new file mode 100644
index 0000000..bd406cb
--- /dev/null
+++ b/3rdParty/Boost/boost/asio/detail/task_io_service_2lock.hpp
@@ -0,0 +1,475 @@
+//
+// task_io_service_2lock.hpp
+// ~~~~~~~~~~~~~~~~~~~~~~~~~
+//
+// Copyright (c) 2003-2008 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 BOOST_ASIO_DETAIL_TASK_IO_SERVICE_2LOCK_HPP
+#define BOOST_ASIO_DETAIL_TASK_IO_SERVICE_2LOCK_HPP
+
+#if defined(_MSC_VER) && (_MSC_VER >= 1200)
+# pragma once
+#endif // defined(_MSC_VER) && (_MSC_VER >= 1200)
+
+#include <boost/asio/detail/push_options.hpp>
+
+#include <boost/asio/io_service.hpp>
+#include <boost/asio/detail/call_stack.hpp>
+#include <boost/asio/detail/event.hpp>
+#include <boost/asio/detail/handler_alloc_helpers.hpp>
+#include <boost/asio/detail/handler_invoke_helpers.hpp>
+#include <boost/asio/detail/indirect_handler_queue.hpp>
+#include <boost/asio/detail/mutex.hpp>
+#include <boost/asio/detail/service_base.hpp>
+#include <boost/asio/detail/task_io_service_fwd.hpp>
+
+#include <boost/asio/detail/push_options.hpp>
+#include <boost/detail/atomic_count.hpp>
+#include <boost/system/error_code.hpp>
+#include <boost/asio/detail/pop_options.hpp>
+
+namespace boost {
+namespace asio {
+namespace detail {
+
+// An alternative task_io_service implementation based on a two-lock queue.
+
+template <typename Task>
+class task_io_service
+ : public boost::asio::detail::service_base<task_io_service<Task> >
+{
+public:
+ typedef indirect_handler_queue handler_queue;
+
+ // Constructor.
+ task_io_service(boost::asio::io_service& io_service)
+ : boost::asio::detail::service_base<task_io_service<Task> >(io_service),
+ front_mutex_(),
+ back_mutex_(),
+ task_(&use_service<Task>(io_service)),
+ outstanding_work_(0),
+ front_stopped_(false),
+ back_stopped_(false),
+ back_shutdown_(false),
+ back_first_idle_thread_(0),
+ back_task_thread_(0)
+ {
+ }
+
+ void init(size_t /*concurrency_hint*/)
+ {
+ }
+
+ // Destroy all user-defined handler objects owned by the service.
+ void shutdown_service()
+ {
+ boost::asio::detail::mutex::scoped_lock back_lock(back_mutex_);
+ back_shutdown_ = true;
+ back_lock.unlock();
+
+ // Destroy handler objects.
+ while (handler_queue::handler* h = handler_queue_.pop())
+ if (h != &task_handler_)
+ h->destroy();
+
+ // Reset to initial state.
+ task_ = 0;
+ }
+
+ // Initialise the task, if required.
+ void init_task()
+ {
+ boost::asio::detail::mutex::scoped_lock back_lock(back_mutex_);
+ if (!back_shutdown_ && !task_)
+ {
+ task_ = &use_service<Task>(this->get_io_service());
+ handler_queue_.push(&task_handler_);
+ interrupt_one_idle_thread(back_lock);
+ }
+ }
+
+ // Run the event loop until interrupted or no more work.
+ size_t run(boost::system::error_code& ec)
+ {
+ if (outstanding_work_ == 0)
+ {
+ stop();
+ ec = boost::system::error_code();
+ return 0;
+ }
+
+ typename call_stack<task_io_service>::context ctx(this);
+
+ idle_thread_info this_idle_thread;
+ this_idle_thread.next = 0;
+
+ size_t n = 0;
+ while (do_one(&this_idle_thread, ec))
+ if (n != (std::numeric_limits<size_t>::max)())
+ ++n;
+ return n;
+ }
+
+ // Run until interrupted or one operation is performed.
+ size_t run_one(boost::system::error_code& ec)
+ {
+ if (outstanding_work_ == 0)
+ {
+ stop();
+ ec = boost::system::error_code();
+ return 0;
+ }
+
+ typename call_stack<task_io_service>::context ctx(this);
+
+ idle_thread_info this_idle_thread;
+ this_idle_thread.next = 0;
+
+ return do_one(&this_idle_thread, ec);
+ }
+
+ // Poll for operations without blocking.
+ size_t poll(boost::system::error_code& ec)
+ {
+ if (outstanding_work_ == 0)
+ {
+ stop();
+ ec = boost::system::error_code();
+ return 0;
+ }
+
+ typename call_stack<task_io_service>::context ctx(this);
+
+ size_t n = 0;
+ while (do_one(0, ec))
+ if (n != (std::numeric_limits<size_t>::max)())
+ ++n;
+ return n;
+ }
+
+ // Poll for one operation without blocking.
+ size_t poll_one(boost::system::error_code& ec)
+ {
+ if (outstanding_work_ == 0)
+ {
+ stop();
+ ec = boost::system::error_code();
+ return 0;
+ }
+
+ typename call_stack<task_io_service>::context ctx(this);
+
+ return do_one(0, ec);
+ }
+
+ // Interrupt the event processing loop.
+ void stop()
+ {
+ boost::asio::detail::mutex::scoped_lock front_lock(front_mutex_);
+ front_stopped_ = true;
+ front_lock.unlock();
+
+ boost::asio::detail::mutex::scoped_lock back_lock(back_mutex_);
+ back_stopped_ = true;
+ interrupt_all_idle_threads(back_lock);
+ }
+
+ // Reset in preparation for a subsequent run invocation.
+ void reset()
+ {
+ boost::asio::detail::mutex::scoped_lock front_lock(front_mutex_);
+ front_stopped_ = false;
+ front_lock.unlock();
+
+ boost::asio::detail::mutex::scoped_lock back_lock(back_mutex_);
+ back_stopped_ = false;
+ }
+
+ // Notify that some work has started.
+ void work_started()
+ {
+ ++outstanding_work_;
+ }
+
+ // Notify that some work has finished.
+ void work_finished()
+ {
+ if (--outstanding_work_ == 0)
+ stop();
+ }
+
+ // Request invocation of the given handler.
+ template <typename Handler>
+ void dispatch(Handler handler)
+ {
+ if (call_stack<task_io_service>::contains(this))
+ boost_asio_handler_invoke_helpers::invoke(handler, &handler);
+ else
+ post(handler);
+ }
+
+ // Request invocation of the given handler and return immediately.
+ template <typename Handler>
+ void post(Handler handler)
+ {
+ // Allocate and construct an operation to wrap the handler.
+ handler_queue::scoped_ptr ptr(handler_queue::wrap(handler));
+
+ boost::asio::detail::mutex::scoped_lock back_lock(back_mutex_);
+
+ // If the service has been shut down we silently discard the handler.
+ if (back_shutdown_)
+ return;
+
+ // Add the handler to the end of the queue.
+ handler_queue_.push(ptr.get());
+ ptr.release();
+
+ // An undelivered handler is treated as unfinished work.
+ ++outstanding_work_;
+
+ // Wake up a thread to execute the handler.
+ interrupt_one_idle_thread(back_lock);
+ }
+
+private:
+ struct idle_thread_info;
+
+ size_t do_one(idle_thread_info* this_idle_thread,
+ boost::system::error_code& ec)
+ {
+ bool task_has_run = false;
+ for (;;)
+ {
+ // The front lock must be held before we can pop items from the queue.
+ boost::asio::detail::mutex::scoped_lock front_lock(front_mutex_);
+ if (front_stopped_)
+ {
+ ec = boost::system::error_code();
+ return 0;
+ }
+
+ if (handler_queue::handler* h = handler_queue_.pop())
+ {
+ if (h == &task_handler_)
+ {
+ bool more_handlers = handler_queue_.poppable();
+ unsigned long front_version = handler_queue_.front_version();
+ front_lock.unlock();
+
+ // The task is always added to the back of the queue when we exit
+ // this block.
+ task_cleanup c(*this);
+
+ // If we're polling and the task has already run then we're done.
+ bool polling = !this_idle_thread;
+ if (task_has_run && polling)
+ {
+ ec = boost::system::error_code();
+ return 0;
+ }
+
+ // If we're considering going idle we need to check whether the queue
+ // is still empty. If it is, add the thread to the list of idle
+ // threads.
+ if (!more_handlers && !polling)
+ {
+ boost::asio::detail::mutex::scoped_lock back_lock(back_mutex_);
+ if (back_stopped_)
+ {
+ ec = boost::system::error_code();
+ return 0;
+ }
+ else if (front_version == handler_queue_.back_version())
+ {
+ back_task_thread_ = this_idle_thread;
+ }
+ else
+ {
+ more_handlers = true;
+ }
+ }
+
+ // Run the task. May throw an exception. Only block if the handler
+ // queue is empty and we're not polling, otherwise we want to return
+ // as soon as possible.
+ task_has_run = true;
+ task_->run(!more_handlers && !polling);
+ }
+ else
+ {
+ front_lock.unlock();
+ handler_cleanup c(*this);
+
+ // Invoke the handler. May throw an exception.
+ h->invoke(); // invoke() deletes the handler object
+
+ ec = boost::system::error_code();
+ return 1;
+ }
+ }
+ else if (this_idle_thread)
+ {
+ unsigned long front_version = handler_queue_.front_version();
+ front_lock.unlock();
+
+ // If we're considering going idle we need to check whether the queue
+ // is still empty. If it is, add the thread to the list of idle
+ // threads.
+ boost::asio::detail::mutex::scoped_lock back_lock(back_mutex_);
+ if (back_stopped_)
+ {
+ ec = boost::system::error_code();
+ return 0;
+ }
+ else if (front_version == handler_queue_.back_version())
+ {
+ this_idle_thread->next = back_first_idle_thread_;
+ back_first_idle_thread_ = this_idle_thread;
+ this_idle_thread->wakeup_event.clear(back_lock);
+ this_idle_thread->wakeup_event.wait(back_lock);
+ }
+ }
+ else
+ {
+ ec = boost::system::error_code();
+ return 0;
+ }
+ }
+ }
+
+ // Interrupt a single idle thread.
+ void interrupt_one_idle_thread(
+ boost::asio::detail::mutex::scoped_lock& back_lock)
+ {
+ if (back_first_idle_thread_)
+ {
+ idle_thread_info* idle_thread = back_first_idle_thread_;
+ back_first_idle_thread_ = idle_thread->next;
+ idle_thread->next = 0;
+ idle_thread->wakeup_event.signal(back_lock);
+ }
+ else if (back_task_thread_ && task_)
+ {
+ back_task_thread_ = 0;
+ task_->interrupt();
+ }
+ }
+
+ // Interrupt all idle threads.
+ void interrupt_all_idle_threads(
+ boost::asio::detail::mutex::scoped_lock& back_lock)
+ {
+ while (back_first_idle_thread_)
+ {
+ idle_thread_info* idle_thread = back_first_idle_thread_;
+ back_first_idle_thread_ = idle_thread->next;
+ idle_thread->next = 0;
+ idle_thread->wakeup_event.signal(back_lock);
+ }
+
+ if (back_task_thread_ && task_)
+ {
+ back_task_thread_ = 0;
+ task_->interrupt();
+ }
+ }
+
+ // Helper class to perform task-related operations on block exit.
+ class task_cleanup;
+ friend class task_cleanup;
+ class task_cleanup
+ {
+ public:
+ task_cleanup(task_io_service& task_io_svc)
+ : task_io_service_(task_io_svc)
+ {
+ }
+
+ ~task_cleanup()
+ {
+ // Reinsert the task at the end of the handler queue.
+ boost::asio::detail::mutex::scoped_lock back_lock(
+ task_io_service_.back_mutex_);
+ task_io_service_.back_task_thread_ = 0;
+ task_io_service_.handler_queue_.push(&task_io_service_.task_handler_);
+ }
+
+ private:
+ task_io_service& task_io_service_;
+ };
+
+ // Helper class to perform handler-related operations on block exit.
+ class handler_cleanup
+ {
+ public:
+ handler_cleanup(task_io_service& task_io_svc)
+ : task_io_service_(task_io_svc)
+ {
+ }
+
+ ~handler_cleanup()
+ {
+ task_io_service_.work_finished();
+ }
+
+ private:
+ task_io_service& task_io_service_;
+ };
+
+ // Mutexes to protect access to internal data.
+ boost::asio::detail::mutex front_mutex_;
+ boost::asio::detail::mutex back_mutex_;
+
+ // The task to be run by this service.
+ Task* task_;
+
+ // Handler object to represent the position of the task in the queue.
+ class task_handler
+ : public handler_queue::handler
+ {
+ public:
+ task_handler()
+ : handler_queue::handler(0, 0)
+ {
+ }
+ } task_handler_;
+
+ // The count of unfinished work.
+ boost::detail::atomic_count outstanding_work_;
+
+ // The queue of handlers that are ready to be delivered.
+ handler_queue handler_queue_;
+
+ // Flag to indicate that the dispatcher has been stopped.
+ bool front_stopped_;
+ bool back_stopped_;
+
+ // Flag to indicate that the dispatcher has been shut down.
+ bool back_shutdown_;
+
+ // Structure containing information about an idle thread.
+ struct idle_thread_info
+ {
+ event wakeup_event;
+ idle_thread_info* next;
+ };
+
+ // The number of threads that are currently idle.
+ idle_thread_info* back_first_idle_thread_;
+
+ // The thread that is currently blocked on the task.
+ idle_thread_info* back_task_thread_;
+};
+
+} // namespace detail
+} // namespace asio
+} // namespace boost
+
+#include <boost/asio/detail/pop_options.hpp>
+
+#endif // BOOST_ASIO_DETAIL_TASK_IO_SERVICE_2LOCK_HPP
diff --git a/3rdParty/Boost/boost/asio/detail/task_io_service_fwd.hpp b/3rdParty/Boost/boost/asio/detail/task_io_service_fwd.hpp
new file mode 100644
index 0000000..6dc8955
--- /dev/null
+++ b/3rdParty/Boost/boost/asio/detail/task_io_service_fwd.hpp
@@ -0,0 +1,33 @@
+//
+// task_io_service_fwd.hpp
+// ~~~~~~~~~~~~~~~~~~~~~~~
+//
+// Copyright (c) 2003-2008 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 BOOST_ASIO_DETAIL_TASK_IO_SERVICE_FWD_HPP
+#define BOOST_ASIO_DETAIL_TASK_IO_SERVICE_FWD_HPP
+
+#if defined(_MSC_VER) && (_MSC_VER >= 1200)
+# pragma once
+#endif // defined(_MSC_VER) && (_MSC_VER >= 1200)
+
+#include <boost/asio/detail/push_options.hpp>
+
+namespace boost {
+namespace asio {
+namespace detail {
+
+template <typename Task>
+class task_io_service;
+
+} // namespace detail
+} // namespace asio
+} // namespace boost
+
+#include <boost/asio/detail/pop_options.hpp>
+
+#endif // BOOST_ASIO_DETAIL_TASK_IO_SERVICE_FWD_HPP
diff --git a/3rdParty/Boost/boost/asio/detail/thread.hpp b/3rdParty/Boost/boost/asio/detail/thread.hpp
new file mode 100644
index 0000000..3db5805
--- /dev/null
+++ b/3rdParty/Boost/boost/asio/detail/thread.hpp
@@ -0,0 +1,60 @@
+//
+// thread.hpp
+// ~~~~~~~~~~
+//
+// Copyright (c) 2003-2008 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 BOOST_ASIO_DETAIL_THREAD_HPP
+#define BOOST_ASIO_DETAIL_THREAD_HPP
+
+#if defined(_MSC_VER) && (_MSC_VER >= 1200)
+# pragma once
+#endif // defined(_MSC_VER) && (_MSC_VER >= 1200)
+
+#include <boost/asio/detail/push_options.hpp>
+
+#include <boost/asio/detail/push_options.hpp>
+#include <boost/config.hpp>
+#include <boost/asio/detail/pop_options.hpp>
+
+#if !defined(BOOST_HAS_THREADS)
+# include <boost/asio/detail/null_thread.hpp>
+#elif defined(BOOST_WINDOWS)
+# if defined(UNDER_CE)
+# include <boost/asio/detail/wince_thread.hpp>
+# else
+# include <boost/asio/detail/win_thread.hpp>
+# endif
+#elif defined(BOOST_HAS_PTHREADS)
+# include <boost/asio/detail/posix_thread.hpp>
+#else
+# error Only Windows and POSIX are supported!
+#endif
+
+namespace boost {
+namespace asio {
+namespace detail {
+
+#if !defined(BOOST_HAS_THREADS)
+typedef null_thread thread;
+#elif defined(BOOST_WINDOWS)
+# if defined(UNDER_CE)
+typedef wince_thread thread;
+# else
+typedef win_thread thread;
+# endif
+#elif defined(BOOST_HAS_PTHREADS)
+typedef posix_thread thread;
+#endif
+
+} // namespace detail
+} // namespace asio
+} // namespace boost
+
+#include <boost/asio/detail/pop_options.hpp>
+
+#endif // BOOST_ASIO_DETAIL_THREAD_HPP
diff --git a/3rdParty/Boost/boost/asio/detail/throw_error.hpp b/3rdParty/Boost/boost/asio/detail/throw_error.hpp
new file mode 100644
index 0000000..0786c40
--- /dev/null
+++ b/3rdParty/Boost/boost/asio/detail/throw_error.hpp
@@ -0,0 +1,46 @@
+//
+// throw_error.hpp
+// ~~~~~~~~~~~~~~~
+//
+// Copyright (c) 2003-2008 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 BOOST_ASIO_DETAIL_THROW_ERROR_HPP
+#define BOOST_ASIO_DETAIL_THROW_ERROR_HPP
+
+#if defined(_MSC_VER) && (_MSC_VER >= 1200)
+# pragma once
+#endif // defined(_MSC_VER) && (_MSC_VER >= 1200)
+
+#include <boost/asio/detail/push_options.hpp>
+
+#include <boost/asio/detail/push_options.hpp>
+#include <boost/throw_exception.hpp>
+#include <boost/system/error_code.hpp>
+#include <boost/system/system_error.hpp>
+#include <boost/asio/detail/pop_options.hpp>
+
+
+namespace boost {
+namespace asio {
+namespace detail {
+
+inline void throw_error(const boost::system::error_code& err)
+{
+ if (err)
+ {
+ boost::system::system_error e(err);
+ boost::throw_exception(e);
+ }
+}
+
+} // namespace detail
+} // namespace asio
+} // namespace boost
+
+#include <boost/asio/detail/pop_options.hpp>
+
+#endif // BOOST_ASIO_DETAIL_THROW_ERROR_HPP
diff --git a/3rdParty/Boost/boost/asio/detail/timer_queue.hpp b/3rdParty/Boost/boost/asio/detail/timer_queue.hpp
new file mode 100644
index 0000000..f5370e5
--- /dev/null
+++ b/3rdParty/Boost/boost/asio/detail/timer_queue.hpp
@@ -0,0 +1,438 @@
+//
+// timer_queue.hpp
+// ~~~~~~~~~~~~~~~
+//
+// Copyright (c) 2003-2008 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 BOOST_ASIO_DETAIL_TIMER_QUEUE_HPP
+#define BOOST_ASIO_DETAIL_TIMER_QUEUE_HPP
+
+#if defined(_MSC_VER) && (_MSC_VER >= 1200)
+# pragma once
+#endif // defined(_MSC_VER) && (_MSC_VER >= 1200)
+
+#include <boost/asio/detail/push_options.hpp>
+
+#include <boost/asio/detail/push_options.hpp>
+#include <cstddef>
+#include <functional>
+#include <limits>
+#include <memory>
+#include <vector>
+#include <boost/config.hpp>
+#include <boost/asio/detail/pop_options.hpp>
+
+#include <boost/asio/error.hpp>
+#include <boost/asio/detail/handler_alloc_helpers.hpp>
+#include <boost/asio/detail/hash_map.hpp>
+#include <boost/asio/detail/noncopyable.hpp>
+#include <boost/asio/detail/timer_queue_base.hpp>
+
+namespace boost {
+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;
+
+ // Constructor.
+ timer_queue()
+ : timers_(),
+ heap_(),
+ cancelled_timers_(0),
+ complete_timers_(0)
+ {
+ }
+
+ // 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.
+ template <typename Handler>
+ bool enqueue_timer(const time_type& time, Handler handler, void* token)
+ {
+ // Ensure that there is space for the timer in the heap. We reserve here so
+ // that the push_back below will not throw due to a reallocation failure.
+ heap_.reserve(heap_.size() + 1);
+
+ // Create a new timer object.
+ std::auto_ptr<timer<Handler> > new_timer(
+ new timer<Handler>(time, handler, token));
+
+ // Insert the new timer into the hash.
+ typedef typename hash_map<void*, timer_base*>::iterator iterator;
+ typedef typename hash_map<void*, timer_base*>::value_type value_type;
+ std::pair<iterator, bool> result =
+ timers_.insert(value_type(token, new_timer.get()));
+ if (!result.second)
+ {
+ result.first->second->prev_ = new_timer.get();
+ new_timer->next_ = result.first->second;
+ result.first->second = new_timer.get();
+ }
+
+ // Put the timer at the correct position in the heap.
+ new_timer->heap_index_ = heap_.size();
+ heap_.push_back(new_timer.get());
+ up_heap(heap_.size() - 1);
+ bool is_first = (heap_[0] == new_timer.get());
+
+ // Ownership of the timer is transferred to the timer queue.
+ new_timer.release();
+
+ return is_first;
+ }
+
+ // Whether there are no timers in the queue.
+ virtual bool empty() const
+ {
+ return heap_.empty();
+ }
+
+ // Get the time for the timer that is earliest in the queue.
+ virtual boost::posix_time::time_duration wait_duration() const
+ {
+ if (heap_.empty())
+ return boost::posix_time::pos_infin;
+ return Time_Traits::to_posix_duration(
+ Time_Traits::subtract(heap_[0]->time_, Time_Traits::now()));
+ }
+
+ // Dispatch the timers that are earlier than the specified time.
+ virtual void dispatch_timers()
+ {
+ const time_type now = Time_Traits::now();
+ while (!heap_.empty() && !Time_Traits::less_than(now, heap_[0]->time_))
+ {
+ timer_base* t = heap_[0];
+ remove_timer(t);
+ t->result_ = boost::system::error_code();
+ t->prev_ = 0;
+ t->next_ = complete_timers_;
+ complete_timers_ = t;
+ }
+ }
+
+ // Cancel the timers with the given token. Any timers pending for the token
+ // will be notified that they have been cancelled next time
+ // dispatch_cancellations is called. Returns the number of timers that were
+ // cancelled.
+ std::size_t cancel_timer(void* timer_token)
+ {
+ std::size_t num_cancelled = 0;
+ typedef typename hash_map<void*, timer_base*>::iterator iterator;
+ iterator it = timers_.find(timer_token);
+ if (it != timers_.end())
+ {
+ timer_base* t = it->second;
+ while (t)
+ {
+ timer_base* next = t->next_;
+ remove_timer(t);
+ t->prev_ = 0;
+ t->next_ = cancelled_timers_;
+ cancelled_timers_ = t;
+ t = next;
+ ++num_cancelled;
+ }
+ }
+ return num_cancelled;
+ }
+
+ // Dispatch any pending cancels for timers.
+ virtual void dispatch_cancellations()
+ {
+ while (cancelled_timers_)
+ {
+ timer_base* this_timer = cancelled_timers_;
+ this_timer->result_ = boost::asio::error::operation_aborted;
+ cancelled_timers_ = this_timer->next_;
+ this_timer->next_ = complete_timers_;
+ complete_timers_ = this_timer;
+ }
+ }
+
+ // Complete any timers that are waiting to be completed.
+ virtual void complete_timers()
+ {
+ while (complete_timers_)
+ {
+ timer_base* this_timer = complete_timers_;
+ complete_timers_ = this_timer->next_;
+ this_timer->next_ = 0;
+ this_timer->complete();
+ }
+ }
+
+ // Destroy all timers.
+ virtual void destroy_timers()
+ {
+ typename hash_map<void*, timer_base*>::iterator i = timers_.begin();
+ typename hash_map<void*, timer_base*>::iterator end = timers_.end();
+ while (i != end)
+ {
+ timer_base* t = i->second;
+ typename hash_map<void*, timer_base*>::iterator old_i = i++;
+ timers_.erase(old_i);
+ destroy_timer_list(t);
+ }
+ heap_.clear();
+ timers_.clear();
+ destroy_timer_list(cancelled_timers_);
+ destroy_timer_list(complete_timers_);
+ }
+
+private:
+ // Base class for timer operations. Function pointers are used instead of
+ // virtual functions to avoid the associated overhead.
+ class timer_base
+ {
+ public:
+ // Delete the timer and post the handler.
+ void complete()
+ {
+ complete_func_(this, result_);
+ }
+
+ // Delete the timer.
+ void destroy()
+ {
+ destroy_func_(this);
+ }
+
+ protected:
+ typedef void (*complete_func_type)(timer_base*,
+ const boost::system::error_code&);
+ typedef void (*destroy_func_type)(timer_base*);
+
+ // Constructor.
+ timer_base(complete_func_type complete_func, destroy_func_type destroy_func,
+ const time_type& time, void* token)
+ : complete_func_(complete_func),
+ destroy_func_(destroy_func),
+ time_(time),
+ token_(token),
+ next_(0),
+ prev_(0),
+ heap_index_(
+ std::numeric_limits<size_t>::max BOOST_PREVENT_MACRO_SUBSTITUTION())
+ {
+ }
+
+ // Prevent deletion through this type.
+ ~timer_base()
+ {
+ }
+
+ private:
+ friend class timer_queue<Time_Traits>;
+
+ // The function to be called to delete the timer and post the handler.
+ complete_func_type complete_func_;
+
+ // The function to be called to delete the timer.
+ destroy_func_type destroy_func_;
+
+ // The result of the timer operation.
+ boost::system::error_code result_;
+
+ // The time when the timer should fire.
+ time_type time_;
+
+ // The token associated with the timer.
+ void* token_;
+
+ // The next timer known to the queue.
+ timer_base* next_;
+
+ // The previous timer known to the queue.
+ timer_base* prev_;
+
+ // The index of the timer in the heap.
+ size_t heap_index_;
+ };
+
+ // Adaptor class template for using handlers in timers.
+ template <typename Handler>
+ class timer
+ : public timer_base
+ {
+ public:
+ // Constructor.
+ timer(const time_type& time, Handler handler, void* token)
+ : timer_base(&timer<Handler>::complete_handler,
+ &timer<Handler>::destroy_handler, time, token),
+ handler_(handler)
+ {
+ }
+
+ // Delete the timer and post the handler.
+ static void complete_handler(timer_base* base,
+ const boost::system::error_code& result)
+ {
+ // Take ownership of the timer object.
+ typedef timer<Handler> this_type;
+ this_type* this_timer(static_cast<this_type*>(base));
+ typedef handler_alloc_traits<Handler, this_type> alloc_traits;
+ handler_ptr<alloc_traits> ptr(this_timer->handler_, this_timer);
+
+ // Make a copy of the error_code and the handler so that the memory can
+ // be deallocated before the upcall is made.
+ boost::system::error_code ec(result);
+ Handler handler(this_timer->handler_);
+
+ // Free the memory associated with the handler.
+ ptr.reset();
+
+ // Make the upcall.
+ handler(ec);
+ }
+
+ // Delete the timer.
+ static void destroy_handler(timer_base* base)
+ {
+ // Take ownership of the timer object.
+ typedef timer<Handler> this_type;
+ this_type* this_timer(static_cast<this_type*>(base));
+ typedef handler_alloc_traits<Handler, this_type> alloc_traits;
+ handler_ptr<alloc_traits> ptr(this_timer->handler_, this_timer);
+
+ // 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(this_timer->handler_);
+ (void)handler;
+
+ // Free the memory associated with the handler.
+ ptr.reset();
+ }
+
+ private:
+ Handler handler_;
+ };
+
+ // Move the item at the given index up the heap to its correct position.
+ void up_heap(size_t index)
+ {
+ size_t parent = (index - 1) / 2;
+ while (index > 0
+ && Time_Traits::less_than(heap_[index]->time_, heap_[parent]->time_))
+ {
+ swap_heap(index, parent);
+ index = parent;
+ parent = (index - 1) / 2;
+ }
+ }
+
+ // Move the item at the given index down the heap to its correct position.
+ void down_heap(size_t index)
+ {
+ size_t child = index * 2 + 1;
+ while (child < heap_.size())
+ {
+ 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(size_t index1, size_t index2)
+ {
+ timer_base* tmp = heap_[index1];
+ heap_[index1] = heap_[index2];
+ heap_[index2] = tmp;
+ heap_[index1]->heap_index_ = index1;
+ heap_[index2]->heap_index_ = index2;
+ }
+
+ // Remove a timer from the heap and list of timers.
+ void remove_timer(timer_base* t)
+ {
+ // Remove the timer from the heap.
+ size_t index = t->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();
+ size_t parent = (index - 1) / 2;
+ if (index > 0 && Time_Traits::less_than(
+ heap_[index]->time_, heap_[parent]->time_))
+ up_heap(index);
+ else
+ down_heap(index);
+ }
+ }
+
+ // Remove the timer from the hash.
+ typedef typename hash_map<void*, timer_base*>::iterator iterator;
+ iterator it = timers_.find(t->token_);
+ if (it != timers_.end())
+ {
+ if (it->second == t)
+ it->second = t->next_;
+ if (t->prev_)
+ t->prev_->next_ = t->next_;
+ if (t->next_)
+ t->next_->prev_ = t->prev_;
+ if (it->second == 0)
+ timers_.erase(it);
+ }
+ }
+
+ // Destroy all timers in a linked list.
+ void destroy_timer_list(timer_base*& t)
+ {
+ while (t)
+ {
+ timer_base* next = t->next_;
+ t->next_ = 0;
+ t->destroy();
+ t = next;
+ }
+ }
+
+ // A hash of timer token to linked lists of timers.
+ hash_map<void*, timer_base*> timers_;
+
+ // The heap of timers, with the earliest timer at the front.
+ std::vector<timer_base*> heap_;
+
+ // The list of timers to be cancelled.
+ timer_base* cancelled_timers_;
+
+ // The list of timers waiting to be completed.
+ timer_base* complete_timers_;
+};
+
+} // namespace detail
+} // namespace asio
+} // namespace boost
+
+#include <boost/asio/detail/pop_options.hpp>
+
+#endif // BOOST_ASIO_DETAIL_TIMER_QUEUE_HPP
diff --git a/3rdParty/Boost/boost/asio/detail/timer_queue_base.hpp b/3rdParty/Boost/boost/asio/detail/timer_queue_base.hpp
new file mode 100644
index 0000000..1d986c0
--- /dev/null
+++ b/3rdParty/Boost/boost/asio/detail/timer_queue_base.hpp
@@ -0,0 +1,64 @@
+//
+// timer_queue_base.hpp
+// ~~~~~~~~~~~~~~~~~~~~
+//
+// Copyright (c) 2003-2008 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 BOOST_ASIO_DETAIL_TIMER_QUEUE_BASE_HPP
+#define BOOST_ASIO_DETAIL_TIMER_QUEUE_BASE_HPP
+
+#if defined(_MSC_VER) && (_MSC_VER >= 1200)
+# pragma once
+#endif // defined(_MSC_VER) && (_MSC_VER >= 1200)
+
+#include <boost/asio/detail/push_options.hpp>
+
+#include <boost/asio/detail/socket_types.hpp> // Must come before posix_time.
+
+#include <boost/asio/detail/push_options.hpp>
+#include <boost/date_time/posix_time/posix_time_types.hpp>
+#include <boost/asio/detail/pop_options.hpp>
+
+#include <boost/asio/detail/noncopyable.hpp>
+
+namespace boost {
+namespace asio {
+namespace detail {
+
+class timer_queue_base
+ : private noncopyable
+{
+public:
+ // 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 boost::posix_time::time_duration wait_duration() const = 0;
+
+ // Dispatch all ready timers.
+ virtual void dispatch_timers() = 0;
+
+ // Dispatch any pending cancels for timers.
+ virtual void dispatch_cancellations() = 0;
+
+ // Complete all timers that are waiting to be completed.
+ virtual void complete_timers() = 0;
+
+ // Destroy all timers.
+ virtual void destroy_timers() = 0;
+};
+
+} // namespace detail
+} // namespace asio
+} // namespace boost
+
+#include <boost/asio/detail/pop_options.hpp>
+
+#endif // BOOST_ASIO_DETAIL_TIMER_QUEUE_BASE_HPP
diff --git a/3rdParty/Boost/boost/asio/detail/tss_ptr.hpp b/3rdParty/Boost/boost/asio/detail/tss_ptr.hpp
new file mode 100644
index 0000000..2cfd641
--- /dev/null
+++ b/3rdParty/Boost/boost/asio/detail/tss_ptr.hpp
@@ -0,0 +1,67 @@
+//
+// tss_ptr.hpp
+// ~~~~~~~~~~~
+//
+// Copyright (c) 2003-2008 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 BOOST_ASIO_DETAIL_TSS_PTR_HPP
+#define BOOST_ASIO_DETAIL_TSS_PTR_HPP
+
+#if defined(_MSC_VER) && (_MSC_VER >= 1200)
+# pragma once
+#endif // defined(_MSC_VER) && (_MSC_VER >= 1200)
+
+#include <boost/asio/detail/push_options.hpp>
+
+#include <boost/asio/detail/push_options.hpp>
+#include <boost/config.hpp>
+#include <boost/asio/detail/pop_options.hpp>
+
+#if !defined(BOOST_HAS_THREADS)
+# include <boost/asio/detail/null_tss_ptr.hpp>
+#elif defined(BOOST_WINDOWS)
+# include <boost/asio/detail/win_tss_ptr.hpp>
+#elif defined(BOOST_HAS_PTHREADS)
+# include <boost/asio/detail/posix_tss_ptr.hpp>
+#else
+# error Only Windows and POSIX are supported!
+#endif
+
+namespace boost {
+namespace asio {
+namespace detail {
+
+template <typename T>
+class tss_ptr
+#if !defined(BOOST_HAS_THREADS)
+ : public null_tss_ptr<T>
+#elif defined(BOOST_WINDOWS)
+ : public win_tss_ptr<T>
+#elif defined(BOOST_HAS_PTHREADS)
+ : public posix_tss_ptr<T>
+#endif
+{
+public:
+ void operator=(T* value)
+ {
+#if !defined(BOOST_HAS_THREADS)
+ null_tss_ptr<T>::operator=(value);
+#elif defined(BOOST_WINDOWS)
+ win_tss_ptr<T>::operator=(value);
+#elif defined(BOOST_HAS_PTHREADS)
+ posix_tss_ptr<T>::operator=(value);
+#endif
+ }
+};
+
+} // namespace detail
+} // namespace asio
+} // namespace boost
+
+#include <boost/asio/detail/pop_options.hpp>
+
+#endif // BOOST_ASIO_DETAIL_TSS_PTR_HPP
diff --git a/3rdParty/Boost/boost/asio/detail/win_event.hpp b/3rdParty/Boost/boost/asio/detail/win_event.hpp
new file mode 100644
index 0000000..d0a135e
--- /dev/null
+++ b/3rdParty/Boost/boost/asio/detail/win_event.hpp
@@ -0,0 +1,105 @@
+//
+// win_event.hpp
+// ~~~~~~~~~~~~~
+//
+// Copyright (c) 2003-2008 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 BOOST_ASIO_DETAIL_WIN_EVENT_HPP
+#define BOOST_ASIO_DETAIL_WIN_EVENT_HPP
+
+#if defined(_MSC_VER) && (_MSC_VER >= 1200)
+# pragma once
+#endif // defined(_MSC_VER) && (_MSC_VER >= 1200)
+
+#include <boost/asio/detail/push_options.hpp>
+
+#include <boost/asio/detail/push_options.hpp>
+#include <boost/config.hpp>
+#include <boost/system/system_error.hpp>
+#include <boost/asio/detail/pop_options.hpp>
+
+#if defined(BOOST_WINDOWS)
+
+#include <boost/asio/error.hpp>
+#include <boost/asio/detail/noncopyable.hpp>
+#include <boost/asio/detail/socket_types.hpp>
+
+#include <boost/asio/detail/push_options.hpp>
+#include <boost/assert.hpp>
+#include <boost/throw_exception.hpp>
+#include <boost/asio/detail/pop_options.hpp>
+
+namespace boost {
+namespace asio {
+namespace detail {
+
+class win_event
+ : private noncopyable
+{
+public:
+ // Constructor.
+ win_event()
+ : event_(::CreateEvent(0, true, false, 0))
+ {
+ if (!event_)
+ {
+ DWORD last_error = ::GetLastError();
+ boost::system::system_error e(
+ boost::system::error_code(last_error,
+ boost::asio::error::get_system_category()),
+ "event");
+ boost::throw_exception(e);
+ }
+ }
+
+ // Destructor.
+ ~win_event()
+ {
+ ::CloseHandle(event_);
+ }
+
+ // Signal the event.
+ template <typename Lock>
+ void signal(Lock& lock)
+ {
+ BOOST_ASSERT(lock.locked());
+ (void)lock;
+ ::SetEvent(event_);
+ }
+
+ // Reset the event.
+ template <typename Lock>
+ void clear(Lock& lock)
+ {
+ BOOST_ASSERT(lock.locked());
+ (void)lock;
+ ::ResetEvent(event_);
+ }
+
+ // Wait for the event to become signalled.
+ template <typename Lock>
+ void wait(Lock& lock)
+ {
+ BOOST_ASSERT(lock.locked());
+ lock.unlock();
+ ::WaitForSingleObject(event_, INFINITE);
+ lock.lock();
+ }
+
+private:
+ HANDLE event_;
+};
+
+} // namespace detail
+} // namespace asio
+} // namespace boost
+
+#endif // defined(BOOST_WINDOWS)
+
+#include <boost/asio/detail/pop_options.hpp>
+
+#endif // BOOST_ASIO_DETAIL_WIN_EVENT_HPP
diff --git a/3rdParty/Boost/boost/asio/detail/win_fd_set_adapter.hpp b/3rdParty/Boost/boost/asio/detail/win_fd_set_adapter.hpp
new file mode 100644
index 0000000..9127a41
--- /dev/null
+++ b/3rdParty/Boost/boost/asio/detail/win_fd_set_adapter.hpp
@@ -0,0 +1,90 @@
+//
+// win_fd_set_adapter.hpp
+// ~~~~~~~~~~~~~~~~~~~~~~
+//
+// Copyright (c) 2003-2008 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 BOOST_ASIO_DETAIL_WIN_FD_SET_ADAPTER_HPP
+#define BOOST_ASIO_DETAIL_WIN_FD_SET_ADAPTER_HPP
+
+#if defined(_MSC_VER) && (_MSC_VER >= 1200)
+# pragma once
+#endif // defined(_MSC_VER) && (_MSC_VER >= 1200)
+
+#include <boost/asio/detail/push_options.hpp>
+
+#include <boost/asio/detail/socket_types.hpp>
+
+#if defined(BOOST_WINDOWS) || defined(__CYGWIN__)
+
+namespace boost {
+namespace asio {
+namespace detail {
+
+// Adapts the FD_SET type to meet the Descriptor_Set concept's requirements.
+class win_fd_set_adapter
+{
+public:
+ enum { win_fd_set_size = 1024 };
+
+ win_fd_set_adapter()
+ : max_descriptor_(invalid_socket)
+ {
+ fd_set_.fd_count = 0;
+ }
+
+ 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;
+ if (fd_set_.fd_count < win_fd_set_size)
+ {
+ fd_set_.fd_array[fd_set_.fd_count++] = descriptor;
+ return true;
+ }
+ return false;
+ }
+
+ 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_;
+ }
+
+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.
+ struct win_fd_set
+ {
+ u_int fd_count;
+ SOCKET fd_array[win_fd_set_size];
+ };
+
+ win_fd_set fd_set_;
+ socket_type max_descriptor_;
+};
+
+} // namespace detail
+} // namespace asio
+} // namespace boost
+
+#endif // defined(BOOST_WINDOWS) || defined(__CYGWIN__)
+
+#include <boost/asio/detail/pop_options.hpp>
+
+#endif // BOOST_ASIO_DETAIL_WIN_FD_SET_ADAPTER_HPP
diff --git a/3rdParty/Boost/boost/asio/detail/win_iocp_handle_service.hpp b/3rdParty/Boost/boost/asio/detail/win_iocp_handle_service.hpp
new file mode 100644
index 0000000..fd204de
--- /dev/null
+++ b/3rdParty/Boost/boost/asio/detail/win_iocp_handle_service.hpp
@@ -0,0 +1,834 @@
+//
+// win_iocp_handle_service.hpp
+// ~~~~~~~~~~~~~~~~~~~~~~~~~~~
+//
+// Copyright (c) 2003-2008 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 BOOST_ASIO_DETAIL_WIN_IOCP_HANDLE_SERVICE_HPP
+#define BOOST_ASIO_DETAIL_WIN_IOCP_HANDLE_SERVICE_HPP
+
+#if defined(_MSC_VER) && (_MSC_VER >= 1200)
+# pragma once
+#endif // defined(_MSC_VER) && (_MSC_VER >= 1200)
+
+#include <boost/asio/detail/push_options.hpp>
+
+#include <boost/asio/detail/win_iocp_io_service_fwd.hpp>
+
+#if defined(BOOST_ASIO_HAS_IOCP)
+
+#include <boost/asio/detail/push_options.hpp>
+#include <boost/cstdint.hpp>
+#include <boost/asio/detail/pop_options.hpp>
+
+#include <boost/asio/buffer.hpp>
+#include <boost/asio/error.hpp>
+#include <boost/asio/io_service.hpp>
+#include <boost/asio/detail/bind_handler.hpp>
+#include <boost/asio/detail/handler_alloc_helpers.hpp>
+#include <boost/asio/detail/handler_invoke_helpers.hpp>
+#include <boost/asio/detail/mutex.hpp>
+#include <boost/asio/detail/win_iocp_io_service.hpp>
+
+namespace boost {
+namespace asio {
+namespace detail {
+
+class win_iocp_handle_service
+ : public boost::asio::detail::service_base<win_iocp_handle_service>
+{
+public:
+ // Base class for all operations.
+ typedef win_iocp_io_service::operation operation;
+
+ // The native type of a stream handle.
+ typedef HANDLE native_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_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_;
+ };
+
+ win_iocp_handle_service(boost::asio::io_service& io_service)
+ : boost::asio::detail::service_base<win_iocp_handle_service>(io_service),
+ iocp_service_(boost::asio::use_service<win_iocp_io_service>(io_service)),
+ mutex_(),
+ impl_list_(0)
+ {
+ }
+
+ // Destroy all user-defined handler objects owned by the service.
+ void shutdown_service()
+ {
+ // Close all implementations, causing all operations to complete.
+ boost::asio::detail::mutex::scoped_lock lock(mutex_);
+ implementation_type* impl = impl_list_;
+ while (impl)
+ {
+ close_for_destruction(*impl);
+ impl = impl->next_;
+ }
+ }
+
+ // Construct a new handle implementation.
+ void construct(implementation_type& impl)
+ {
+ impl.handle_ = INVALID_HANDLE_VALUE;
+ impl.safe_cancellation_thread_id_ = 0;
+
+ // Insert implementation into linked list of all implementations.
+ boost::asio::detail::mutex::scoped_lock lock(mutex_);
+ impl.next_ = impl_list_;
+ impl.prev_ = 0;
+ if (impl_list_)
+ impl_list_->prev_ = &impl;
+ impl_list_ = &impl;
+ }
+
+ // Destroy a handle implementation.
+ void destroy(implementation_type& impl)
+ {
+ close_for_destruction(impl);
+
+ // Remove implementation from linked list of all implementations.
+ boost::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;
+ }
+
+ // Assign a native handle to a handle implementation.
+ boost::system::error_code assign(implementation_type& impl,
+ const native_type& native_handle, boost::system::error_code& ec)
+ {
+ if (is_open(impl))
+ {
+ ec = boost::asio::error::already_open;
+ return ec;
+ }
+
+ if (iocp_service_.register_handle(native_handle, ec))
+ return ec;
+
+ impl.handle_ = native_handle;
+ ec = boost::system::error_code();
+ return 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.
+ boost::system::error_code close(implementation_type& impl,
+ boost::system::error_code& ec)
+ {
+ if (is_open(impl))
+ {
+ if (!::CloseHandle(impl.handle_))
+ {
+ DWORD last_error = ::GetLastError();
+ ec = boost::system::error_code(last_error,
+ boost::asio::error::get_system_category());
+ return ec;
+ }
+
+ impl.handle_ = INVALID_HANDLE_VALUE;
+ impl.safe_cancellation_thread_id_ = 0;
+ }
+
+ ec = boost::system::error_code();
+ return ec;
+ }
+
+ // Get the native handle representation.
+ native_type native(const implementation_type& impl) const
+ {
+ return impl.handle_;
+ }
+
+ // Cancel all operations associated with the handle.
+ boost::system::error_code cancel(implementation_type& impl,
+ boost::system::error_code& ec)
+ {
+ if (!is_open(impl))
+ {
+ ec = boost::asio::error::bad_descriptor;
+ }
+ else 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 = boost::system::error_code();
+ }
+ else
+ {
+ ec = boost::system::error_code(last_error,
+ boost::asio::error::get_system_category());
+ }
+ }
+ else
+ {
+ ec = boost::system::error_code();
+ }
+ }
+ else if (impl.safe_cancellation_thread_id_ == 0)
+ {
+ // No operations have been started, so there's nothing to cancel.
+ ec = boost::system::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 = boost::system::error_code(last_error,
+ boost::asio::error::get_system_category());
+ }
+ else
+ {
+ ec = boost::system::error_code();
+ }
+ }
+ else
+ {
+ // Asynchronous operations have been started from more than one thread,
+ // so cancellation is not safe.
+ ec = boost::asio::error::operation_not_supported;
+ }
+
+ return ec;
+ }
+
+ class overlapped_wrapper
+ : public OVERLAPPED
+ {
+ public:
+ explicit overlapped_wrapper(boost::system::error_code& ec)
+ {
+ Internal = 0;
+ InternalHigh = 0;
+ Offset = 0;
+ OffsetHigh = 0;
+
+ // Create a non-signalled manual-reset event, for GetOverlappedResult.
+ hEvent = ::CreateEvent(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.
+ *reinterpret_cast<DWORD_PTR*>(&hEvent) |= 1;
+ }
+ else
+ {
+ DWORD last_error = ::GetLastError();
+ ec = boost::system::error_code(last_error,
+ boost::asio::error::get_system_category());
+ }
+ }
+
+ ~overlapped_wrapper()
+ {
+ if (hEvent)
+ {
+ ::CloseHandle(hEvent);
+ }
+ }
+ };
+
+ // Write the given data. Returns the number of bytes written.
+ template <typename ConstBufferSequence>
+ size_t write_some(implementation_type& impl,
+ const ConstBufferSequence& buffers, boost::system::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, boost::uint64_t offset,
+ const ConstBufferSequence& buffers, boost::system::error_code& ec)
+ {
+ if (!is_open(impl))
+ {
+ ec = boost::asio::error::bad_descriptor;
+ return 0;
+ }
+
+ // Find first buffer of non-zero length.
+ boost::asio::const_buffer buffer;
+ typename ConstBufferSequence::const_iterator iter = buffers.begin();
+ typename ConstBufferSequence::const_iterator end = buffers.end();
+ for (DWORD i = 0; iter != end; ++iter, ++i)
+ {
+ buffer = boost::asio::const_buffer(*iter);
+ if (boost::asio::buffer_size(buffer) != 0)
+ break;
+ }
+
+ // A request to write 0 bytes on a handle is a no-op.
+ if (boost::asio::buffer_size(buffer) == 0)
+ {
+ ec = boost::system::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_,
+ boost::asio::buffer_cast<LPCVOID>(buffer),
+ static_cast<DWORD>(boost::asio::buffer_size(buffer)), 0, &overlapped);
+ if (!ok)
+ {
+ DWORD last_error = ::GetLastError();
+ if (last_error != ERROR_IO_PENDING)
+ {
+ ec = boost::system::error_code(last_error,
+ boost::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 = boost::system::error_code(last_error,
+ boost::asio::error::get_system_category());
+ }
+
+ ec = boost::system::error_code();
+ return bytes_transferred;
+ }
+
+ template <typename ConstBufferSequence, typename Handler>
+ class write_operation
+ : public operation
+ {
+ public:
+ write_operation(win_iocp_io_service& io_service,
+ const ConstBufferSequence& buffers, Handler handler)
+ : operation(io_service,
+ &write_operation<ConstBufferSequence, Handler>::do_completion_impl,
+ &write_operation<ConstBufferSequence, Handler>::destroy_impl),
+ work_(io_service.get_io_service()),
+ buffers_(buffers),
+ handler_(handler)
+ {
+ }
+
+ private:
+ static void do_completion_impl(operation* op,
+ DWORD last_error, size_t bytes_transferred)
+ {
+ // Take ownership of the operation object.
+ typedef write_operation<ConstBufferSequence, Handler> op_type;
+ op_type* handler_op(static_cast<op_type*>(op));
+ typedef handler_alloc_traits<Handler, op_type> alloc_traits;
+ handler_ptr<alloc_traits> ptr(handler_op->handler_, handler_op);
+
+#if defined(BOOST_ASIO_ENABLE_BUFFER_DEBUGGING)
+ // Check whether buffers are still valid.
+ typename ConstBufferSequence::const_iterator iter
+ = handler_op->buffers_.begin();
+ typename ConstBufferSequence::const_iterator end
+ = handler_op->buffers_.end();
+ while (iter != end)
+ {
+ boost::asio::const_buffer buffer(*iter);
+ boost::asio::buffer_cast<const char*>(buffer);
+ ++iter;
+ }
+#endif // defined(BOOST_ASIO_ENABLE_BUFFER_DEBUGGING)
+
+ // Make a copy of the handler so that the memory can be deallocated before
+ // the upcall is made.
+ Handler handler(handler_op->handler_);
+
+ // Free the memory associated with the handler.
+ ptr.reset();
+
+ // Call the handler.
+ boost::system::error_code ec(last_error,
+ boost::asio::error::get_system_category());
+ boost_asio_handler_invoke_helpers::invoke(
+ bind_handler(handler, ec, bytes_transferred), &handler);
+ }
+
+ static void destroy_impl(operation* op)
+ {
+ // Take ownership of the operation object.
+ typedef write_operation<ConstBufferSequence, Handler> op_type;
+ op_type* handler_op(static_cast<op_type*>(op));
+ typedef handler_alloc_traits<Handler, op_type> alloc_traits;
+ handler_ptr<alloc_traits> ptr(handler_op->handler_, handler_op);
+
+ // 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(handler_op->handler_);
+ (void)handler;
+
+ // Free the memory associated with the handler.
+ ptr.reset();
+ }
+
+ boost::asio::io_service::work work_;
+ ConstBufferSequence buffers_;
+ Handler handler_;
+ };
+
+ // 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)
+ {
+ async_write_some_at(impl, 0, buffers, handler);
+ }
+
+ // 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, boost::uint64_t offset,
+ const ConstBufferSequence& buffers, Handler handler)
+ {
+ if (!is_open(impl))
+ {
+ this->get_io_service().post(bind_handler(handler,
+ boost::asio::error::bad_descriptor, 0));
+ return;
+ }
+
+ // Update the ID of the thread from which cancellation is safe.
+ 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);
+
+ // Allocate and construct an operation to wrap the handler.
+ typedef write_operation<ConstBufferSequence, Handler> value_type;
+ typedef handler_alloc_traits<Handler, value_type> alloc_traits;
+ raw_handler_ptr<alloc_traits> raw_ptr(handler);
+ handler_ptr<alloc_traits> ptr(raw_ptr, iocp_service_, buffers, handler);
+
+ // Find first buffer of non-zero length.
+ boost::asio::const_buffer buffer;
+ typename ConstBufferSequence::const_iterator iter = buffers.begin();
+ typename ConstBufferSequence::const_iterator end = buffers.end();
+ for (DWORD i = 0; iter != end; ++iter, ++i)
+ {
+ buffer = boost::asio::const_buffer(*iter);
+ if (boost::asio::buffer_size(buffer) != 0)
+ break;
+ }
+
+ // A request to write 0 bytes on a handle is a no-op.
+ if (boost::asio::buffer_size(buffer) == 0)
+ {
+ boost::asio::io_service::work work(this->get_io_service());
+ ptr.reset();
+ boost::system::error_code error;
+ iocp_service_.post(bind_handler(handler, error, 0));
+ return;
+ }
+
+ // Write the data.
+ DWORD bytes_transferred = 0;
+ ptr.get()->Offset = offset & 0xFFFFFFFF;
+ ptr.get()->OffsetHigh = (offset >> 32) & 0xFFFFFFFF;
+ BOOL ok = ::WriteFile(impl.handle_,
+ boost::asio::buffer_cast<LPCVOID>(buffer),
+ static_cast<DWORD>(boost::asio::buffer_size(buffer)),
+ &bytes_transferred, ptr.get());
+ DWORD last_error = ::GetLastError();
+
+ // Check if the operation completed immediately.
+ if (!ok && last_error != ERROR_IO_PENDING)
+ {
+ boost::asio::io_service::work work(this->get_io_service());
+ ptr.reset();
+ boost::system::error_code ec(last_error,
+ boost::asio::error::get_system_category());
+ iocp_service_.post(bind_handler(handler, ec, bytes_transferred));
+ }
+ else
+ {
+ ptr.release();
+ }
+ }
+
+ // Read some data. Returns the number of bytes received.
+ template <typename MutableBufferSequence>
+ size_t read_some(implementation_type& impl,
+ const MutableBufferSequence& buffers, boost::system::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, boost::uint64_t offset,
+ const MutableBufferSequence& buffers, boost::system::error_code& ec)
+ {
+ if (!is_open(impl))
+ {
+ ec = boost::asio::error::bad_descriptor;
+ return 0;
+ }
+
+ // Find first buffer of non-zero length.
+ boost::asio::mutable_buffer buffer;
+ typename MutableBufferSequence::const_iterator iter = buffers.begin();
+ typename MutableBufferSequence::const_iterator end = buffers.end();
+ for (DWORD i = 0; iter != end; ++iter, ++i)
+ {
+ buffer = boost::asio::mutable_buffer(*iter);
+ if (boost::asio::buffer_size(buffer) != 0)
+ break;
+ }
+
+ // A request to read 0 bytes on a stream handle is a no-op.
+ if (boost::asio::buffer_size(buffer) == 0)
+ {
+ ec = boost::system::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_,
+ boost::asio::buffer_cast<LPVOID>(buffer),
+ static_cast<DWORD>(boost::asio::buffer_size(buffer)), 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 = boost::asio::error::eof;
+ }
+ else
+ {
+ ec = boost::system::error_code(last_error,
+ boost::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 = boost::asio::error::eof;
+ }
+ else
+ {
+ ec = boost::system::error_code(last_error,
+ boost::asio::error::get_system_category());
+ }
+ }
+
+ ec = boost::system::error_code();
+ return bytes_transferred;
+ }
+
+ template <typename MutableBufferSequence, typename Handler>
+ class read_operation
+ : public operation
+ {
+ public:
+ read_operation(win_iocp_io_service& io_service,
+ const MutableBufferSequence& buffers, Handler handler)
+ : operation(io_service,
+ &read_operation<
+ MutableBufferSequence, Handler>::do_completion_impl,
+ &read_operation<
+ MutableBufferSequence, Handler>::destroy_impl),
+ work_(io_service.get_io_service()),
+ buffers_(buffers),
+ handler_(handler)
+ {
+ }
+
+ private:
+ static void do_completion_impl(operation* op,
+ DWORD last_error, size_t bytes_transferred)
+ {
+ // Take ownership of the operation object.
+ typedef read_operation<MutableBufferSequence, Handler> op_type;
+ op_type* handler_op(static_cast<op_type*>(op));
+ typedef handler_alloc_traits<Handler, op_type> alloc_traits;
+ handler_ptr<alloc_traits> ptr(handler_op->handler_, handler_op);
+
+#if defined(BOOST_ASIO_ENABLE_BUFFER_DEBUGGING)
+ // Check whether buffers are still valid.
+ typename MutableBufferSequence::const_iterator iter
+ = handler_op->buffers_.begin();
+ typename MutableBufferSequence::const_iterator end
+ = handler_op->buffers_.end();
+ while (iter != end)
+ {
+ boost::asio::mutable_buffer buffer(*iter);
+ boost::asio::buffer_cast<char*>(buffer);
+ ++iter;
+ }
+#endif // defined(BOOST_ASIO_ENABLE_BUFFER_DEBUGGING)
+
+ // Check for the end-of-file condition.
+ boost::system::error_code ec(last_error,
+ boost::asio::error::get_system_category());
+ if (!ec && bytes_transferred == 0 || last_error == ERROR_HANDLE_EOF)
+ {
+ ec = boost::asio::error::eof;
+ }
+
+ // Make a copy of the handler so that the memory can be deallocated before
+ // the upcall is made.
+ Handler handler(handler_op->handler_);
+
+ // Free the memory associated with the handler.
+ ptr.reset();
+
+ // Call the handler.
+ boost_asio_handler_invoke_helpers::invoke(
+ bind_handler(handler, ec, bytes_transferred), &handler);
+ }
+
+ static void destroy_impl(operation* op)
+ {
+ // Take ownership of the operation object.
+ typedef read_operation<MutableBufferSequence, Handler> op_type;
+ op_type* handler_op(static_cast<op_type*>(op));
+ typedef boost::asio::detail::handler_alloc_traits<
+ Handler, op_type> alloc_traits;
+ boost::asio::detail::handler_ptr<alloc_traits> ptr(
+ handler_op->handler_, handler_op);
+
+ // 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(handler_op->handler_);
+ (void)handler;
+
+ // Free the memory associated with the handler.
+ ptr.reset();
+ }
+
+ boost::asio::io_service::work work_;
+ MutableBufferSequence buffers_;
+ Handler handler_;
+ };
+
+ // 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)
+ {
+ async_read_some_at(impl, 0, buffers, handler);
+ }
+
+ // 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, boost::uint64_t offset,
+ const MutableBufferSequence& buffers, Handler handler)
+ {
+ if (!is_open(impl))
+ {
+ this->get_io_service().post(bind_handler(handler,
+ boost::asio::error::bad_descriptor, 0));
+ return;
+ }
+
+ // Update the ID of the thread from which cancellation is safe.
+ 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);
+
+ // Allocate and construct an operation to wrap the handler.
+ typedef read_operation<MutableBufferSequence, Handler> value_type;
+ typedef handler_alloc_traits<Handler, value_type> alloc_traits;
+ raw_handler_ptr<alloc_traits> raw_ptr(handler);
+ handler_ptr<alloc_traits> ptr(raw_ptr, iocp_service_, buffers, handler);
+
+ // Find first buffer of non-zero length.
+ boost::asio::mutable_buffer buffer;
+ typename MutableBufferSequence::const_iterator iter = buffers.begin();
+ typename MutableBufferSequence::const_iterator end = buffers.end();
+ for (DWORD i = 0; iter != end; ++iter, ++i)
+ {
+ buffer = boost::asio::mutable_buffer(*iter);
+ if (boost::asio::buffer_size(buffer) != 0)
+ break;
+ }
+
+ // A request to receive 0 bytes on a stream handle is a no-op.
+ if (boost::asio::buffer_size(buffer) == 0)
+ {
+ boost::asio::io_service::work work(this->get_io_service());
+ ptr.reset();
+ boost::system::error_code error;
+ iocp_service_.post(bind_handler(handler, error, 0));
+ return;
+ }
+
+ // Read some data.
+ DWORD bytes_transferred = 0;
+ ptr.get()->Offset = offset & 0xFFFFFFFF;
+ ptr.get()->OffsetHigh = (offset >> 32) & 0xFFFFFFFF;
+ BOOL ok = ::ReadFile(impl.handle_,
+ boost::asio::buffer_cast<LPVOID>(buffer),
+ static_cast<DWORD>(boost::asio::buffer_size(buffer)),
+ &bytes_transferred, ptr.get());
+ DWORD last_error = ::GetLastError();
+ if (!ok && last_error != ERROR_IO_PENDING && last_error != ERROR_MORE_DATA)
+ {
+ boost::asio::io_service::work work(this->get_io_service());
+ ptr.reset();
+ boost::system::error_code ec(last_error,
+ boost::asio::error::get_system_category());
+ iocp_service_.post(bind_handler(handler, ec, bytes_transferred));
+ }
+ else
+ {
+ ptr.release();
+ }
+ }
+
+private:
+ // Prevent the use of the null_buffers type with this service.
+ size_t write_some(implementation_type& impl,
+ const null_buffers& buffers, boost::system::error_code& ec);
+ size_t write_some_at(implementation_type& impl, boost::uint64_t offset,
+ const null_buffers& buffers, boost::system::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, boost::uint64_t offset,
+ const null_buffers& buffers, Handler handler);
+ size_t read_some(implementation_type& impl,
+ const null_buffers& buffers, boost::system::error_code& ec);
+ size_t read_some_at(implementation_type& impl, boost::uint64_t offset,
+ const null_buffers& buffers, boost::system::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, boost::uint64_t offset,
+ const null_buffers& buffers, Handler handler);
+
+ // Helper function to close a handle when the associated object is being
+ // destroyed.
+ void close_for_destruction(implementation_type& impl)
+ {
+ if (is_open(impl))
+ {
+ ::CloseHandle(impl.handle_);
+ impl.handle_ = INVALID_HANDLE_VALUE;
+ impl.safe_cancellation_thread_id_ = 0;
+ }
+ }
+
+ // The IOCP service used for running asynchronous operations and dispatching
+ // handlers.
+ win_iocp_io_service& iocp_service_;
+
+ // Mutex to protect access to the linked list of implementations.
+ boost::asio::detail::mutex mutex_;
+
+ // The head of a linked list of all implementations.
+ implementation_type* impl_list_;
+};
+
+} // namespace detail
+} // namespace asio
+} // namespace boost
+
+#endif // defined(BOOST_ASIO_HAS_IOCP)
+
+#include <boost/asio/detail/pop_options.hpp>
+
+#endif // BOOST_ASIO_DETAIL_WIN_IOCP_HANDLE_SERVICE_HPP
diff --git a/3rdParty/Boost/boost/asio/detail/win_iocp_io_service.hpp b/3rdParty/Boost/boost/asio/detail/win_iocp_io_service.hpp
new file mode 100644
index 0000000..5818542
--- /dev/null
+++ b/3rdParty/Boost/boost/asio/detail/win_iocp_io_service.hpp
@@ -0,0 +1,738 @@
+//
+// win_iocp_io_service.hpp
+// ~~~~~~~~~~~~~~~~~~~~~~~
+//
+// Copyright (c) 2003-2008 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 BOOST_ASIO_DETAIL_WIN_IOCP_IO_SERVICE_HPP
+#define BOOST_ASIO_DETAIL_WIN_IOCP_IO_SERVICE_HPP
+
+#if defined(_MSC_VER) && (_MSC_VER >= 1200)
+# pragma once
+#endif // defined(_MSC_VER) && (_MSC_VER >= 1200)
+
+#include <boost/asio/detail/push_options.hpp>
+
+#include <boost/asio/detail/win_iocp_io_service_fwd.hpp>
+
+#if defined(BOOST_ASIO_HAS_IOCP)
+
+#include <boost/asio/detail/push_options.hpp>
+#include <limits>
+#include <boost/throw_exception.hpp>
+#include <boost/system/system_error.hpp>
+#include <boost/asio/detail/pop_options.hpp>
+
+#include <boost/asio/io_service.hpp>
+#include <boost/asio/detail/call_stack.hpp>
+#include <boost/asio/detail/handler_alloc_helpers.hpp>
+#include <boost/asio/detail/handler_invoke_helpers.hpp>
+#include <boost/asio/detail/service_base.hpp>
+#include <boost/asio/detail/socket_types.hpp>
+#include <boost/asio/detail/timer_queue.hpp>
+#include <boost/asio/detail/mutex.hpp>
+
+namespace boost {
+namespace asio {
+namespace detail {
+
+class win_iocp_io_service
+ : public boost::asio::detail::service_base<win_iocp_io_service>
+{
+public:
+ // Base class for all operations. A function pointer is used instead of
+ // virtual functions to avoid the associated overhead.
+ //
+ // This class inherits from OVERLAPPED so that we can downcast to get back to
+ // the operation pointer from the LPOVERLAPPED out parameter of
+ // GetQueuedCompletionStatus.
+ class operation
+ : public OVERLAPPED
+ {
+ public:
+ typedef void (*invoke_func_type)(operation*, DWORD, size_t);
+ typedef void (*destroy_func_type)(operation*);
+
+ operation(win_iocp_io_service& iocp_service,
+ invoke_func_type invoke_func, destroy_func_type destroy_func)
+ : outstanding_operations_(&iocp_service.outstanding_operations_),
+ invoke_func_(invoke_func),
+ destroy_func_(destroy_func)
+ {
+ Internal = 0;
+ InternalHigh = 0;
+ Offset = 0;
+ OffsetHigh = 0;
+ hEvent = 0;
+
+ ::InterlockedIncrement(outstanding_operations_);
+ }
+
+ void do_completion(DWORD last_error, size_t bytes_transferred)
+ {
+ invoke_func_(this, last_error, bytes_transferred);
+ }
+
+ void destroy()
+ {
+ destroy_func_(this);
+ }
+
+ protected:
+ // Prevent deletion through this type.
+ ~operation()
+ {
+ ::InterlockedDecrement(outstanding_operations_);
+ }
+
+ private:
+ long* outstanding_operations_;
+ invoke_func_type invoke_func_;
+ destroy_func_type destroy_func_;
+ };
+
+
+ // Constructor.
+ win_iocp_io_service(boost::asio::io_service& io_service)
+ : boost::asio::detail::service_base<win_iocp_io_service>(io_service),
+ iocp_(),
+ outstanding_work_(0),
+ outstanding_operations_(0),
+ stopped_(0),
+ shutdown_(0),
+ timer_thread_(0),
+ timer_interrupt_issued_(false)
+ {
+ }
+
+ void init(size_t concurrency_hint)
+ {
+ iocp_.handle = ::CreateIoCompletionPort(INVALID_HANDLE_VALUE, 0, 0,
+ static_cast<DWORD>((std::min<size_t>)(concurrency_hint, DWORD(~0))));
+ if (!iocp_.handle)
+ {
+ DWORD last_error = ::GetLastError();
+ boost::system::system_error e(
+ boost::system::error_code(last_error,
+ boost::asio::error::get_system_category()),
+ "iocp");
+ boost::throw_exception(e);
+ }
+ }
+
+ // Destroy all user-defined handler objects owned by the service.
+ void shutdown_service()
+ {
+ ::InterlockedExchange(&shutdown_, 1);
+
+ while (::InterlockedExchangeAdd(&outstanding_operations_, 0) > 0)
+ {
+ DWORD bytes_transferred = 0;
+#if (WINVER < 0x0500)
+ DWORD completion_key = 0;
+#else
+ DWORD_PTR completion_key = 0;
+#endif
+ LPOVERLAPPED overlapped = 0;
+ ::GetQueuedCompletionStatus(iocp_.handle, &bytes_transferred,
+ &completion_key, &overlapped, INFINITE);
+ if (overlapped)
+ static_cast<operation*>(overlapped)->destroy();
+ }
+
+ for (std::size_t i = 0; i < timer_queues_.size(); ++i)
+ timer_queues_[i]->destroy_timers();
+ timer_queues_.clear();
+ }
+
+ // Initialise the task. Nothing to do here.
+ void init_task()
+ {
+ }
+
+ // Register a handle with the IO completion port.
+ boost::system::error_code register_handle(
+ HANDLE handle, boost::system::error_code& ec)
+ {
+ if (::CreateIoCompletionPort(handle, iocp_.handle, 0, 0) == 0)
+ {
+ DWORD last_error = ::GetLastError();
+ ec = boost::system::error_code(last_error,
+ boost::asio::error::get_system_category());
+ }
+ else
+ {
+ ec = boost::system::error_code();
+ }
+ return ec;
+ }
+
+ // Run the event loop until stopped or no more work.
+ size_t run(boost::system::error_code& ec)
+ {
+ if (::InterlockedExchangeAdd(&outstanding_work_, 0) == 0)
+ {
+ ec = boost::system::error_code();
+ return 0;
+ }
+
+ call_stack<win_iocp_io_service>::context ctx(this);
+
+ size_t n = 0;
+ while (do_one(true, ec))
+ if (n != (std::numeric_limits<size_t>::max)())
+ ++n;
+ return n;
+ }
+
+ // Run until stopped or one operation is performed.
+ size_t run_one(boost::system::error_code& ec)
+ {
+ if (::InterlockedExchangeAdd(&outstanding_work_, 0) == 0)
+ {
+ ec = boost::system::error_code();
+ return 0;
+ }
+
+ call_stack<win_iocp_io_service>::context ctx(this);
+
+ return do_one(true, ec);
+ }
+
+ // Poll for operations without blocking.
+ size_t poll(boost::system::error_code& ec)
+ {
+ if (::InterlockedExchangeAdd(&outstanding_work_, 0) == 0)
+ {
+ ec = boost::system::error_code();
+ return 0;
+ }
+
+ call_stack<win_iocp_io_service>::context ctx(this);
+
+ size_t n = 0;
+ while (do_one(false, ec))
+ if (n != (std::numeric_limits<size_t>::max)())
+ ++n;
+ return n;
+ }
+
+ // Poll for one operation without blocking.
+ size_t poll_one(boost::system::error_code& ec)
+ {
+ if (::InterlockedExchangeAdd(&outstanding_work_, 0) == 0)
+ {
+ ec = boost::system::error_code();
+ return 0;
+ }
+
+ call_stack<win_iocp_io_service>::context ctx(this);
+
+ return do_one(false, ec);
+ }
+
+ // Stop the event processing loop.
+ void stop()
+ {
+ if (::InterlockedExchange(&stopped_, 1) == 0)
+ {
+ if (!::PostQueuedCompletionStatus(iocp_.handle, 0, 0, 0))
+ {
+ DWORD last_error = ::GetLastError();
+ boost::system::system_error e(
+ boost::system::error_code(last_error,
+ boost::asio::error::get_system_category()),
+ "pqcs");
+ boost::throw_exception(e);
+ }
+ }
+ }
+
+ // Reset in preparation for a subsequent run invocation.
+ void reset()
+ {
+ ::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();
+ }
+
+ // Request invocation of the given handler.
+ template <typename Handler>
+ void dispatch(Handler handler)
+ {
+ if (call_stack<win_iocp_io_service>::contains(this))
+ boost_asio_handler_invoke_helpers::invoke(handler, &handler);
+ else
+ post(handler);
+ }
+
+ // Request invocation of the given handler and return immediately.
+ template <typename Handler>
+ void post(Handler handler)
+ {
+ // If the service has been shut down we silently discard the handler.
+ if (::InterlockedExchangeAdd(&shutdown_, 0) != 0)
+ return;
+
+ // Allocate and construct an operation to wrap the handler.
+ typedef handler_operation<Handler> value_type;
+ typedef handler_alloc_traits<Handler, value_type> alloc_traits;
+ raw_handler_ptr<alloc_traits> raw_ptr(handler);
+ handler_ptr<alloc_traits> ptr(raw_ptr, *this, handler);
+
+ // Enqueue the operation on the I/O completion port.
+ if (!::PostQueuedCompletionStatus(iocp_.handle, 0, 0, ptr.get()))
+ {
+ DWORD last_error = ::GetLastError();
+ boost::system::system_error e(
+ boost::system::error_code(last_error,
+ boost::asio::error::get_system_category()),
+ "pqcs");
+ boost::throw_exception(e);
+ }
+
+ // Operation has been successfully posted.
+ ptr.release();
+ }
+
+ // Request invocation of the given OVERLAPPED-derived operation.
+ void post_completion(operation* op, DWORD op_last_error,
+ DWORD bytes_transferred)
+ {
+ // Enqueue the operation on the I/O completion port.
+ if (!::PostQueuedCompletionStatus(iocp_.handle,
+ bytes_transferred, op_last_error, op))
+ {
+ DWORD last_error = ::GetLastError();
+ boost::system::system_error e(
+ boost::system::error_code(last_error,
+ boost::asio::error::get_system_category()),
+ "pqcs");
+ boost::throw_exception(e);
+ }
+ }
+
+ // Add a new timer queue to the service.
+ template <typename Time_Traits>
+ void add_timer_queue(timer_queue<Time_Traits>& timer_queue)
+ {
+ boost::asio::detail::mutex::scoped_lock lock(timer_mutex_);
+ timer_queues_.push_back(&timer_queue);
+ }
+
+ // Remove a timer queue from the service.
+ template <typename Time_Traits>
+ void remove_timer_queue(timer_queue<Time_Traits>& timer_queue)
+ {
+ boost::asio::detail::mutex::scoped_lock lock(timer_mutex_);
+ for (std::size_t i = 0; i < timer_queues_.size(); ++i)
+ {
+ if (timer_queues_[i] == &timer_queue)
+ {
+ timer_queues_.erase(timer_queues_.begin() + i);
+ return;
+ }
+ }
+ }
+
+ // Schedule a timer in the given timer queue to expire at the specified
+ // absolute time. The handler object will be invoked when the timer expires.
+ template <typename Time_Traits, typename Handler>
+ void schedule_timer(timer_queue<Time_Traits>& timer_queue,
+ const typename Time_Traits::time_type& time, Handler handler, void* token)
+ {
+ // If the service has been shut down we silently discard the timer.
+ if (::InterlockedExchangeAdd(&shutdown_, 0) != 0)
+ return;
+
+ boost::asio::detail::mutex::scoped_lock lock(timer_mutex_);
+ if (timer_queue.enqueue_timer(time, handler, token))
+ {
+ if (!timer_interrupt_issued_)
+ {
+ timer_interrupt_issued_ = true;
+ lock.unlock();
+ ::PostQueuedCompletionStatus(iocp_.handle,
+ 0, steal_timer_dispatching, 0);
+ }
+ }
+ }
+
+ // 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>& timer_queue, void* token)
+ {
+ // If the service has been shut down we silently ignore the cancellation.
+ if (::InterlockedExchangeAdd(&shutdown_, 0) != 0)
+ return 0;
+
+ boost::asio::detail::mutex::scoped_lock lock(timer_mutex_);
+ std::size_t n = timer_queue.cancel_timer(token);
+ if (n > 0 && !timer_interrupt_issued_)
+ {
+ timer_interrupt_issued_ = true;
+ lock.unlock();
+ ::PostQueuedCompletionStatus(iocp_.handle,
+ 0, steal_timer_dispatching, 0);
+ }
+ return n;
+ }
+
+private:
+ // 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).
+ size_t do_one(bool block, boost::system::error_code& ec)
+ {
+ long this_thread_id = static_cast<long>(::GetCurrentThreadId());
+
+ for (;;)
+ {
+ // Try to acquire responsibility for dispatching timers.
+ bool dispatching_timers = (::InterlockedCompareExchange(
+ &timer_thread_, this_thread_id, 0) == 0);
+
+ // Calculate timeout for GetQueuedCompletionStatus call.
+ DWORD timeout = max_timeout;
+ if (dispatching_timers)
+ {
+ boost::asio::detail::mutex::scoped_lock lock(timer_mutex_);
+ timer_interrupt_issued_ = false;
+ timeout = get_timeout();
+ }
+
+ // Get the next operation from the queue.
+ DWORD bytes_transferred = 0;
+#if (WINVER < 0x0500)
+ DWORD completion_key = 0;
+#else
+ DWORD_PTR completion_key = 0;
+#endif
+ LPOVERLAPPED overlapped = 0;
+ ::SetLastError(0);
+ BOOL ok = ::GetQueuedCompletionStatus(iocp_.handle, &bytes_transferred,
+ &completion_key, &overlapped, block ? timeout : 0);
+ DWORD last_error = ::GetLastError();
+
+ // Dispatch any pending timers.
+ if (dispatching_timers)
+ {
+ try
+ {
+ boost::asio::detail::mutex::scoped_lock lock(timer_mutex_);
+ if (!timer_queues_.empty())
+ {
+ timer_queues_copy_ = timer_queues_;
+ for (std::size_t i = 0; i < timer_queues_copy_.size(); ++i)
+ {
+ timer_queues_copy_[i]->dispatch_timers();
+ timer_queues_copy_[i]->dispatch_cancellations();
+ timer_queues_copy_[i]->complete_timers();
+ }
+ }
+ }
+ catch (...)
+ {
+ // Transfer responsibility for dispatching timers to another thread.
+ if (::InterlockedCompareExchange(&timer_thread_,
+ 0, this_thread_id) == this_thread_id)
+ {
+ ::PostQueuedCompletionStatus(iocp_.handle,
+ 0, transfer_timer_dispatching, 0);
+ }
+
+ throw;
+ }
+ }
+
+ if (!ok && overlapped == 0)
+ {
+ if (block && last_error == WAIT_TIMEOUT)
+ {
+ // Relinquish responsibility for dispatching timers.
+ if (dispatching_timers)
+ {
+ ::InterlockedCompareExchange(&timer_thread_, 0, this_thread_id);
+ }
+
+ continue;
+ }
+
+ // Transfer responsibility for dispatching timers to another thread.
+ if (dispatching_timers && ::InterlockedCompareExchange(
+ &timer_thread_, 0, this_thread_id) == this_thread_id)
+ {
+ ::PostQueuedCompletionStatus(iocp_.handle,
+ 0, transfer_timer_dispatching, 0);
+ }
+
+ ec = boost::system::error_code();
+ return 0;
+ }
+ else if (overlapped)
+ {
+ // We may have been passed a last_error value in the completion_key.
+ if (last_error == 0)
+ {
+ last_error = completion_key;
+ }
+
+ // Transfer responsibility for dispatching timers to another thread.
+ if (dispatching_timers && ::InterlockedCompareExchange(
+ &timer_thread_, 0, this_thread_id) == this_thread_id)
+ {
+ ::PostQueuedCompletionStatus(iocp_.handle,
+ 0, transfer_timer_dispatching, 0);
+ }
+
+ // Ensure that the io_service does not exit due to running out of work
+ // while we make the upcall.
+ auto_work work(*this);
+
+ // Dispatch the operation.
+ operation* op = static_cast<operation*>(overlapped);
+ op->do_completion(last_error, bytes_transferred);
+
+ ec = boost::system::error_code();
+ return 1;
+ }
+ else if (completion_key == transfer_timer_dispatching)
+ {
+ // Woken up to try to acquire responsibility for dispatching timers.
+ ::InterlockedCompareExchange(&timer_thread_, 0, this_thread_id);
+ }
+ else if (completion_key == steal_timer_dispatching)
+ {
+ // Woken up to steal responsibility for dispatching timers.
+ ::InterlockedExchange(&timer_thread_, 0);
+ }
+ else
+ {
+ // Relinquish responsibility for dispatching timers. If the io_service
+ // is not being stopped then the thread will get an opportunity to
+ // reacquire timer responsibility on the next loop iteration.
+ if (dispatching_timers)
+ {
+ ::InterlockedCompareExchange(&timer_thread_, 0, this_thread_id);
+ }
+
+ // The stopped_ flag is always checked to ensure that any leftover
+ // interrupts from a previous run invocation are ignored.
+ if (::InterlockedExchangeAdd(&stopped_, 0) != 0)
+ {
+ // Wake up next thread that is blocked on GetQueuedCompletionStatus.
+ if (!::PostQueuedCompletionStatus(iocp_.handle, 0, 0, 0))
+ {
+ last_error = ::GetLastError();
+ ec = boost::system::error_code(last_error,
+ boost::asio::error::get_system_category());
+ return 0;
+ }
+
+ ec = boost::system::error_code();
+ return 0;
+ }
+ }
+ }
+ }
+
+ // Check if all timer queues are empty.
+ bool all_timer_queues_are_empty() const
+ {
+ for (std::size_t i = 0; i < timer_queues_.size(); ++i)
+ if (!timer_queues_[i]->empty())
+ return false;
+ return true;
+ }
+
+ // Get the timeout value for the GetQueuedCompletionStatus call. The timeout
+ // value is returned as a number of milliseconds. We will wait no longer than
+ // 1000 milliseconds.
+ DWORD get_timeout()
+ {
+ if (all_timer_queues_are_empty())
+ return max_timeout;
+
+ boost::posix_time::time_duration minimum_wait_duration
+ = boost::posix_time::milliseconds(max_timeout);
+
+ for (std::size_t i = 0; i < timer_queues_.size(); ++i)
+ {
+ boost::posix_time::time_duration wait_duration
+ = timer_queues_[i]->wait_duration();
+ if (wait_duration < minimum_wait_duration)
+ minimum_wait_duration = wait_duration;
+ }
+
+ if (minimum_wait_duration > boost::posix_time::time_duration())
+ {
+ int milliseconds = minimum_wait_duration.total_milliseconds();
+ return static_cast<DWORD>(milliseconds > 0 ? milliseconds : 1);
+ }
+ else
+ {
+ return 0;
+ }
+ }
+
+ struct auto_work
+ {
+ auto_work(win_iocp_io_service& io_service)
+ : io_service_(io_service)
+ {
+ io_service_.work_started();
+ }
+
+ ~auto_work()
+ {
+ io_service_.work_finished();
+ }
+
+ private:
+ win_iocp_io_service& io_service_;
+ };
+
+ template <typename Handler>
+ struct handler_operation
+ : public operation
+ {
+ handler_operation(win_iocp_io_service& io_service,
+ Handler handler)
+ : operation(io_service, &handler_operation<Handler>::do_completion_impl,
+ &handler_operation<Handler>::destroy_impl),
+ io_service_(io_service),
+ handler_(handler)
+ {
+ io_service_.work_started();
+ }
+
+ ~handler_operation()
+ {
+ io_service_.work_finished();
+ }
+
+ private:
+ // Prevent copying and assignment.
+ handler_operation(const handler_operation&);
+ void operator=(const handler_operation&);
+
+ static void do_completion_impl(operation* op, DWORD, size_t)
+ {
+ // Take ownership of the operation object.
+ typedef handler_operation<Handler> op_type;
+ op_type* handler_op(static_cast<op_type*>(op));
+ typedef handler_alloc_traits<Handler, op_type> alloc_traits;
+ handler_ptr<alloc_traits> ptr(handler_op->handler_, handler_op);
+
+ // Make a copy of the handler so that the memory can be deallocated before
+ // the upcall is made.
+ Handler handler(handler_op->handler_);
+
+ // Free the memory associated with the handler.
+ ptr.reset();
+
+ // Make the upcall.
+ boost_asio_handler_invoke_helpers::invoke(handler, &handler);
+ }
+
+ static void destroy_impl(operation* op)
+ {
+ // Take ownership of the operation object.
+ typedef handler_operation<Handler> op_type;
+ op_type* handler_op(static_cast<op_type*>(op));
+ typedef handler_alloc_traits<Handler, op_type> alloc_traits;
+ handler_ptr<alloc_traits> ptr(handler_op->handler_, handler_op);
+
+ // 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(handler_op->handler_);
+ (void)handler;
+
+ // Free the memory associated with the handler.
+ ptr.reset();
+ }
+
+ win_iocp_io_service& io_service_;
+ Handler handler_;
+ };
+
+ // The IO completion port used for queueing operations.
+ struct iocp_holder
+ {
+ HANDLE handle;
+ iocp_holder() : handle(0) {}
+ ~iocp_holder() { if (handle) ::CloseHandle(handle); }
+ } iocp_;
+
+ // The count of unfinished work.
+ long outstanding_work_;
+
+ // The count of unfinished operations.
+ long outstanding_operations_;
+ friend class operation;
+
+ // Flag to indicate whether the event loop has been stopped.
+ long stopped_;
+
+ // Flag to indicate whether the service has been shut down.
+ long shutdown_;
+
+ enum
+ {
+ // Maximum GetQueuedCompletionStatus timeout, in milliseconds.
+ max_timeout = 500,
+
+ // Completion key value to indicate that responsibility for dispatching
+ // timers is being cooperatively transferred from one thread to another.
+ transfer_timer_dispatching = 1,
+
+ // Completion key value to indicate that responsibility for dispatching
+ // timers should be stolen from another thread.
+ steal_timer_dispatching = 2
+ };
+
+ // The thread that's currently in charge of dispatching timers.
+ long timer_thread_;
+
+ // Mutex for protecting access to the timer queues.
+ mutex timer_mutex_;
+
+ // Whether a thread has been interrupted to process a new timeout.
+ bool timer_interrupt_issued_;
+
+ // The timer queues.
+ std::vector<timer_queue_base*> timer_queues_;
+
+ // A copy of the timer queues, used when dispatching, cancelling and cleaning
+ // up timers. The copy is stored as a class data member to avoid unnecessary
+ // memory allocation.
+ std::vector<timer_queue_base*> timer_queues_copy_;
+};
+
+} // namespace detail
+} // namespace asio
+} // namespace boost
+
+#endif // defined(BOOST_ASIO_HAS_IOCP)
+
+#include <boost/asio/detail/pop_options.hpp>
+
+#endif // BOOST_ASIO_DETAIL_WIN_IOCP_IO_SERVICE_HPP
diff --git a/3rdParty/Boost/boost/asio/detail/win_iocp_io_service_fwd.hpp b/3rdParty/Boost/boost/asio/detail/win_iocp_io_service_fwd.hpp
new file mode 100644
index 0000000..c9e6060
--- /dev/null
+++ b/3rdParty/Boost/boost/asio/detail/win_iocp_io_service_fwd.hpp
@@ -0,0 +1,53 @@
+//
+// win_iocp_io_service_fwd.hpp
+// ~~~~~~~~~~~~~~~~~~~~~~~~~~~
+//
+// Copyright (c) 2003-2008 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 BOOST_ASIO_DETAIL_WIN_IOCP_IO_SERVICE_FWD_HPP
+#define BOOST_ASIO_DETAIL_WIN_IOCP_IO_SERVICE_FWD_HPP
+
+#if defined(_MSC_VER) && (_MSC_VER >= 1200)
+# pragma once
+#endif // defined(_MSC_VER) && (_MSC_VER >= 1200)
+
+#include <boost/asio/detail/push_options.hpp>
+
+#include <boost/asio/detail/push_options.hpp>
+#include <boost/config.hpp>
+#include <boost/asio/detail/pop_options.hpp>
+
+#include <boost/asio/detail/socket_types.hpp>
+
+// This service is only supported on Win32 (NT4 and later).
+#if !defined(BOOST_ASIO_DISABLE_IOCP)
+#if defined(BOOST_WINDOWS) || defined(__CYGWIN__)
+#if defined(_WIN32_WINNT) && (_WIN32_WINNT >= 0x0400)
+#if !defined(UNDER_CE)
+
+// Define this to indicate that IOCP is supported on the target platform.
+#define BOOST_ASIO_HAS_IOCP 1
+
+namespace boost {
+namespace asio {
+namespace detail {
+
+class win_iocp_io_service;
+class win_iocp_overlapped_ptr;
+
+} // namespace detail
+} // namespace asio
+} // namespace boost
+
+#endif // !defined(UNDER_CE)
+#endif // defined(_WIN32_WINNT) && (_WIN32_WINNT >= 0x0400)
+#endif // defined(BOOST_WINDOWS) || defined(__CYGWIN__)
+#endif // !defined(BOOST_ASIO_DISABLE_IOCP)
+
+#include <boost/asio/detail/pop_options.hpp>
+
+#endif // BOOST_ASIO_DETAIL_WIN_IOCP_IO_SERVICE_FWD_HPP
diff --git a/3rdParty/Boost/boost/asio/detail/win_iocp_overlapped_ptr.hpp b/3rdParty/Boost/boost/asio/detail/win_iocp_overlapped_ptr.hpp
new file mode 100644
index 0000000..e8ab6b0
--- /dev/null
+++ b/3rdParty/Boost/boost/asio/detail/win_iocp_overlapped_ptr.hpp
@@ -0,0 +1,210 @@
+//
+// win_iocp_overlapped_ptr.hpp
+// ~~~~~~~~~~~~~~~~~~~~~~~~~~~
+//
+// Copyright (c) 2003-2008 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 BOOST_ASIO_DETAIL_WIN_IOCP_OVERLAPPED_PTR_HPP
+#define BOOST_ASIO_DETAIL_WIN_IOCP_OVERLAPPED_PTR_HPP
+
+#if defined(_MSC_VER) && (_MSC_VER >= 1200)
+# pragma once
+#endif // defined(_MSC_VER) && (_MSC_VER >= 1200)
+
+#include <boost/asio/detail/push_options.hpp>
+
+#include <boost/asio/detail/win_iocp_io_service_fwd.hpp>
+
+#if defined(BOOST_ASIO_HAS_IOCP)
+
+#include <boost/asio/detail/noncopyable.hpp>
+#include <boost/asio/detail/win_iocp_io_service.hpp>
+
+namespace boost {
+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)
+ {
+ }
+
+ // Construct an win_iocp_overlapped_ptr to contain the specified handler.
+ template <typename Handler>
+ explicit win_iocp_overlapped_ptr(
+ boost::asio::io_service& io_service, Handler handler)
+ : ptr_(0)
+ {
+ this->reset(io_service, 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;
+ }
+ }
+
+ // Reset to contain the specified handler, freeing any current OVERLAPPED
+ // object.
+ template <typename Handler>
+ void reset(boost::asio::io_service& io_service, Handler handler)
+ {
+ typedef overlapped_operation<Handler> value_type;
+ typedef handler_alloc_traits<Handler, value_type> alloc_traits;
+ raw_handler_ptr<alloc_traits> raw_ptr(handler);
+ handler_ptr<alloc_traits> ptr(raw_ptr, io_service.impl_, handler);
+ reset();
+ ptr_ = ptr.release();
+ }
+
+ // 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()
+ {
+ OVERLAPPED* tmp = ptr_;
+ ptr_ = 0;
+ return tmp;
+ }
+
+ // Post completion notification for overlapped operation. Releases ownership.
+ void complete(const boost::system::error_code& ec,
+ std::size_t bytes_transferred)
+ {
+ if (ptr_)
+ {
+ ptr_->ec_ = ec;
+ ptr_->io_service_.post_completion(ptr_, 0,
+ static_cast<DWORD>(bytes_transferred));
+ ptr_ = 0;
+ }
+ }
+
+private:
+ struct overlapped_operation_base
+ : public win_iocp_io_service::operation
+ {
+ overlapped_operation_base(win_iocp_io_service& io_service,
+ invoke_func_type invoke_func, destroy_func_type destroy_func)
+ : win_iocp_io_service::operation(io_service, invoke_func, destroy_func),
+ io_service_(io_service)
+ {
+ io_service_.work_started();
+ }
+
+ ~overlapped_operation_base()
+ {
+ io_service_.work_finished();
+ }
+
+ win_iocp_io_service& io_service_;
+ boost::system::error_code ec_;
+ };
+
+ template <typename Handler>
+ struct overlapped_operation
+ : public overlapped_operation_base
+ {
+ overlapped_operation(win_iocp_io_service& io_service,
+ Handler handler)
+ : overlapped_operation_base(io_service,
+ &overlapped_operation<Handler>::do_completion_impl,
+ &overlapped_operation<Handler>::destroy_impl),
+ handler_(handler)
+ {
+ }
+
+ private:
+ // Prevent copying and assignment.
+ overlapped_operation(const overlapped_operation&);
+ void operator=(const overlapped_operation&);
+
+ static void do_completion_impl(win_iocp_io_service::operation* op,
+ DWORD last_error, size_t bytes_transferred)
+ {
+ // Take ownership of the operation object.
+ typedef overlapped_operation<Handler> op_type;
+ op_type* handler_op(static_cast<op_type*>(op));
+ typedef handler_alloc_traits<Handler, op_type> alloc_traits;
+ handler_ptr<alloc_traits> ptr(handler_op->handler_, handler_op);
+
+ // Make a copy of the handler and error_code so that the memory can be
+ // deallocated before the upcall is made.
+ Handler handler(handler_op->handler_);
+ boost::system::error_code ec(handler_op->ec_);
+ if (last_error)
+ ec = boost::system::error_code(last_error,
+ boost::asio::error::get_system_category());
+
+ // Free the memory associated with the handler.
+ ptr.reset();
+
+ // Make the upcall.
+ boost_asio_handler_invoke_helpers::invoke(
+ bind_handler(handler, ec, bytes_transferred), &handler);
+ }
+
+ static void destroy_impl(win_iocp_io_service::operation* op)
+ {
+ // Take ownership of the operation object.
+ typedef overlapped_operation<Handler> op_type;
+ op_type* handler_op(static_cast<op_type*>(op));
+ typedef handler_alloc_traits<Handler, op_type> alloc_traits;
+ handler_ptr<alloc_traits> ptr(handler_op->handler_, handler_op);
+
+ // 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(handler_op->handler_);
+ (void)handler;
+
+ // Free the memory associated with the handler.
+ ptr.reset();
+ }
+
+ Handler handler_;
+ };
+
+ overlapped_operation_base* ptr_;
+};
+
+} // namespace detail
+} // namespace asio
+} // namespace boost
+
+#endif // defined(BOOST_ASIO_HAS_IOCP)
+
+#include <boost/asio/detail/pop_options.hpp>
+
+#endif // BOOST_ASIO_DETAIL_WIN_IOCP_OVERLAPPED_PTR_HPP
diff --git a/3rdParty/Boost/boost/asio/detail/win_iocp_serial_port_service.hpp b/3rdParty/Boost/boost/asio/detail/win_iocp_serial_port_service.hpp
new file mode 100644
index 0000000..57d56cf
--- /dev/null
+++ b/3rdParty/Boost/boost/asio/detail/win_iocp_serial_port_service.hpp
@@ -0,0 +1,294 @@
+//
+// win_iocp_serial_port_service.hpp
+// ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+//
+// Copyright (c) 2003-2008 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 BOOST_ASIO_DETAIL_WIN_IOCP_SERIAL_PORT_SERVICE_HPP
+#define BOOST_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 <boost/asio/detail/push_options.hpp>
+
+#include <boost/asio/detail/push_options.hpp>
+#include <cstring>
+#include <string>
+#include <boost/asio/detail/pop_options.hpp>
+
+#include <boost/asio/detail/win_iocp_io_service_fwd.hpp>
+
+#if defined(BOOST_ASIO_HAS_IOCP)
+
+#include <boost/asio/error.hpp>
+#include <boost/asio/io_service.hpp>
+#include <boost/asio/detail/win_iocp_handle_service.hpp>
+
+namespace boost {
+namespace asio {
+namespace detail {
+
+// Extend win_iocp_handle_service to provide serial port support.
+class win_iocp_serial_port_service
+ : public boost::asio::detail::service_base<win_iocp_serial_port_service>
+{
+public:
+ // The native type of a stream handle.
+ typedef win_iocp_handle_service::native_type native_type;
+
+ // The implementation type of the stream handle.
+ typedef win_iocp_handle_service::implementation_type implementation_type;
+
+ win_iocp_serial_port_service(boost::asio::io_service& io_service)
+ : boost::asio::detail::service_base<
+ win_iocp_serial_port_service>(io_service),
+ handle_service_(
+ boost::asio::use_service<win_iocp_handle_service>(io_service))
+ {
+ }
+
+ // Destroy all user-defined handler objects owned by the service.
+ void shutdown_service()
+ {
+ }
+
+ // Construct a new handle implementation.
+ void construct(implementation_type& impl)
+ {
+ handle_service_.construct(impl);
+ }
+
+ // Destroy a handle implementation.
+ void destroy(implementation_type& impl)
+ {
+ handle_service_.destroy(impl);
+ }
+
+ // Open the serial port using the specified device name.
+ boost::system::error_code open(implementation_type& impl,
+ const std::string& device, boost::system::error_code& ec)
+ {
+ if (is_open(impl))
+ {
+ ec = boost::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 = boost::system::error_code(last_error,
+ boost::asio::error::get_system_category());
+ return ec;
+ }
+
+ // Determine the initial serial port parameters.
+ using namespace std; // For memcpy.
+ ::DCB dcb;
+ memset(&dcb, 0, sizeof(DCB));
+ dcb.DCBlength = sizeof(DCB);
+ if (!::GetCommState(handle, &dcb))
+ {
+ DWORD last_error = ::GetLastError();
+ ::CloseHandle(handle);
+ ec = boost::system::error_code(last_error,
+ boost::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 = boost::system::error_code(last_error,
+ boost::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 = boost::system::error_code(last_error,
+ boost::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;
+ }
+
+ // Assign a native handle to a handle implementation.
+ boost::system::error_code assign(implementation_type& impl,
+ const native_type& native_handle, boost::system::error_code& ec)
+ {
+ return handle_service_.assign(impl, native_handle, ec);
+ }
+
+ // Determine whether the handle is open.
+ bool is_open(const implementation_type& impl) const
+ {
+ return handle_service_.is_open(impl);
+ }
+
+ // Destroy a handle implementation.
+ boost::system::error_code close(implementation_type& impl,
+ boost::system::error_code& ec)
+ {
+ return handle_service_.close(impl, ec);
+ }
+
+ // Get the native handle representation.
+ native_type native(implementation_type& impl)
+ {
+ return handle_service_.native(impl);
+ }
+
+ // Cancel all operations associated with the handle.
+ boost::system::error_code cancel(implementation_type& impl,
+ boost::system::error_code& ec)
+ {
+ return handle_service_.cancel(impl, ec);
+ }
+
+ // Set an option on the serial port.
+ template <typename SettableSerialPortOption>
+ boost::system::error_code set_option(implementation_type& impl,
+ const SettableSerialPortOption& option, boost::system::error_code& ec)
+ {
+ using namespace std; // For memcpy.
+
+ ::DCB dcb;
+ memset(&dcb, 0, sizeof(DCB));
+ dcb.DCBlength = sizeof(DCB);
+ if (!::GetCommState(handle_service_.native(impl), &dcb))
+ {
+ DWORD last_error = ::GetLastError();
+ ec = boost::system::error_code(last_error,
+ boost::asio::error::get_system_category());
+ return ec;
+ }
+
+ if (option.store(dcb, ec))
+ return ec;
+
+ if (!::SetCommState(handle_service_.native(impl), &dcb))
+ {
+ DWORD last_error = ::GetLastError();
+ ec = boost::system::error_code(last_error,
+ boost::asio::error::get_system_category());
+ return ec;
+ }
+
+ ec = boost::system::error_code();
+ return ec;
+ }
+
+ // Get an option from the serial port.
+ template <typename GettableSerialPortOption>
+ boost::system::error_code get_option(const implementation_type& impl,
+ GettableSerialPortOption& option, boost::system::error_code& ec) const
+ {
+ using namespace std; // For memcpy.
+
+ ::DCB dcb;
+ memset(&dcb, 0, sizeof(DCB));
+ dcb.DCBlength = sizeof(DCB);
+ if (!::GetCommState(handle_service_.native(impl), &dcb))
+ {
+ DWORD last_error = ::GetLastError();
+ ec = boost::system::error_code(last_error,
+ boost::asio::error::get_system_category());
+ return ec;
+ }
+
+ return option.load(dcb, ec);
+ }
+
+ // Send a break sequence to the serial port.
+ boost::system::error_code send_break(implementation_type&,
+ boost::system::error_code& ec)
+ {
+ ec = boost::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, boost::system::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, boost::system::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:
+ // The handle service used for initiating asynchronous operations.
+ win_iocp_handle_service& handle_service_;
+};
+
+} // namespace detail
+} // namespace asio
+} // namespace boost
+
+#endif // defined(BOOST_ASIO_HAS_IOCP)
+
+#include <boost/asio/detail/pop_options.hpp>
+
+#endif // BOOST_ASIO_DETAIL_WIN_IOCP_SERIAL_PORT_SERVICE_HPP
diff --git a/3rdParty/Boost/boost/asio/detail/win_iocp_socket_service.hpp b/3rdParty/Boost/boost/asio/detail/win_iocp_socket_service.hpp
new file mode 100644
index 0000000..5192612
--- /dev/null
+++ b/3rdParty/Boost/boost/asio/detail/win_iocp_socket_service.hpp
@@ -0,0 +1,2417 @@
+//
+// win_iocp_socket_service.hpp
+// ~~~~~~~~~~~~~~~~~~~~~~~~~~~
+//
+// Copyright (c) 2003-2008 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 BOOST_ASIO_DETAIL_WIN_IOCP_SOCKET_SERVICE_HPP
+#define BOOST_ASIO_DETAIL_WIN_IOCP_SOCKET_SERVICE_HPP
+
+#if defined(_MSC_VER) && (_MSC_VER >= 1200)
+# pragma once
+#endif // defined(_MSC_VER) && (_MSC_VER >= 1200)
+
+#include <boost/asio/detail/push_options.hpp>
+
+#include <boost/asio/detail/win_iocp_io_service_fwd.hpp>
+
+#if defined(BOOST_ASIO_HAS_IOCP)
+
+#include <boost/asio/detail/push_options.hpp>
+#include <cstring>
+#include <boost/shared_ptr.hpp>
+#include <boost/type_traits/is_same.hpp>
+#include <boost/weak_ptr.hpp>
+#include <boost/asio/detail/pop_options.hpp>
+
+#include <boost/asio/buffer.hpp>
+#include <boost/asio/error.hpp>
+#include <boost/asio/io_service.hpp>
+#include <boost/asio/socket_base.hpp>
+#include <boost/asio/detail/bind_handler.hpp>
+#include <boost/asio/detail/handler_alloc_helpers.hpp>
+#include <boost/asio/detail/handler_invoke_helpers.hpp>
+#include <boost/asio/detail/mutex.hpp>
+#include <boost/asio/detail/select_reactor.hpp>
+#include <boost/asio/detail/socket_holder.hpp>
+#include <boost/asio/detail/socket_ops.hpp>
+#include <boost/asio/detail/socket_types.hpp>
+#include <boost/asio/detail/win_iocp_io_service.hpp>
+
+namespace boost {
+namespace asio {
+namespace detail {
+
+template <typename Protocol>
+class win_iocp_socket_service
+ : public boost::asio::detail::service_base<win_iocp_socket_service<Protocol> >
+{
+public:
+ // The protocol type.
+ typedef Protocol protocol_type;
+
+ // The endpoint type.
+ typedef typename Protocol::endpoint endpoint_type;
+
+ // Base class for all operations.
+ typedef win_iocp_io_service::operation operation;
+
+ struct noop_deleter { void operator()(void*) {} };
+ typedef boost::shared_ptr<void> shared_cancel_token_type;
+ typedef boost::weak_ptr<void> weak_cancel_token_type;
+
+ // The native type of a socket.
+ class native_type
+ {
+ public:
+ native_type(socket_type s)
+ : socket_(s),
+ have_remote_endpoint_(false)
+ {
+ }
+
+ native_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_;
+ }
+
+ HANDLE as_handle() const
+ {
+ return reinterpret_cast<HANDLE>(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 type of the reactor used for connect operations.
+ typedef detail::select_reactor<true> reactor_type;
+
+ // The implementation type of the socket.
+ class implementation_type
+ {
+ public:
+ // Default constructor.
+ implementation_type()
+ : socket_(invalid_socket),
+ flags_(0),
+ cancel_token_(),
+ protocol_(endpoint_type().protocol()),
+ next_(0),
+ prev_(0)
+ {
+ }
+
+ private:
+ // Only this service will have access to the internal values.
+ friend class win_iocp_socket_service;
+
+ // The native socket representation.
+ native_type socket_;
+
+ enum
+ {
+ enable_connection_aborted = 1, // User wants connection_aborted errors.
+ close_might_block = 2, // User set linger option for blocking close.
+ user_set_non_blocking = 4 // The user wants a non-blocking socket.
+ };
+
+ // Flags indicating the current state of the socket.
+ unsigned char flags_;
+
+ // 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.
+ shared_cancel_token_type cancel_token_;
+
+ // The protocol associated with the socket.
+ protocol_type protocol_;
+
+ // Per-descriptor data used by the reactor.
+ reactor_type::per_descriptor_data reactor_data_;
+
+#if defined(BOOST_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(BOOST_ASIO_ENABLE_CANCELIO)
+
+ // Pointers to adjacent socket implementations in linked list.
+ implementation_type* next_;
+ implementation_type* prev_;
+ };
+
+ // The maximum number of buffers to support in a single operation.
+ enum { max_buffers = 64 < max_iov_len ? 64 : max_iov_len };
+
+ // Constructor.
+ win_iocp_socket_service(boost::asio::io_service& io_service)
+ : boost::asio::detail::service_base<
+ win_iocp_socket_service<Protocol> >(io_service),
+ iocp_service_(boost::asio::use_service<win_iocp_io_service>(io_service)),
+ reactor_(0),
+ mutex_(),
+ impl_list_(0)
+ {
+ }
+
+ // Destroy all user-defined handler objects owned by the service.
+ void shutdown_service()
+ {
+ // Close all implementations, causing all operations to complete.
+ boost::asio::detail::mutex::scoped_lock lock(mutex_);
+ implementation_type* impl = impl_list_;
+ while (impl)
+ {
+ boost::system::error_code ignored_ec;
+ close_for_destruction(*impl);
+ impl = impl->next_;
+ }
+ }
+
+ // Construct a new socket implementation.
+ void construct(implementation_type& impl)
+ {
+ impl.socket_ = invalid_socket;
+ impl.flags_ = 0;
+ impl.cancel_token_.reset();
+#if defined(BOOST_ASIO_ENABLE_CANCELIO)
+ impl.safe_cancellation_thread_id_ = 0;
+#endif // defined(BOOST_ASIO_ENABLE_CANCELIO)
+
+ // Insert implementation into linked list of all implementations.
+ boost::asio::detail::mutex::scoped_lock lock(mutex_);
+ impl.next_ = impl_list_;
+ impl.prev_ = 0;
+ if (impl_list_)
+ impl_list_->prev_ = &impl;
+ impl_list_ = &impl;
+ }
+
+ // Destroy a socket implementation.
+ void destroy(implementation_type& impl)
+ {
+ close_for_destruction(impl);
+
+ // Remove implementation from linked list of all implementations.
+ boost::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;
+ }
+
+ // Open a new socket implementation.
+ boost::system::error_code open(implementation_type& impl,
+ const protocol_type& protocol, boost::system::error_code& ec)
+ {
+ if (is_open(impl))
+ {
+ ec = boost::asio::error::already_open;
+ return ec;
+ }
+
+ socket_holder sock(socket_ops::socket(protocol.family(), protocol.type(),
+ protocol.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();
+ impl.flags_ = 0;
+ impl.cancel_token_.reset(static_cast<void*>(0), noop_deleter());
+ impl.protocol_ = protocol;
+ ec = boost::system::error_code();
+ return ec;
+ }
+
+ // Assign a native socket to a socket implementation.
+ boost::system::error_code assign(implementation_type& impl,
+ const protocol_type& protocol, const native_type& native_socket,
+ boost::system::error_code& ec)
+ {
+ if (is_open(impl))
+ {
+ ec = boost::asio::error::already_open;
+ return ec;
+ }
+
+ if (iocp_service_.register_handle(native_socket.as_handle(), ec))
+ return ec;
+
+ impl.socket_ = native_socket;
+ impl.flags_ = 0;
+ impl.cancel_token_.reset(static_cast<void*>(0), noop_deleter());
+ impl.protocol_ = protocol;
+ ec = boost::system::error_code();
+ return ec;
+ }
+
+ // Determine whether the socket is open.
+ bool is_open(const implementation_type& impl) const
+ {
+ return impl.socket_ != invalid_socket;
+ }
+
+ // Destroy a socket implementation.
+ boost::system::error_code close(implementation_type& impl,
+ boost::system::error_code& ec)
+ {
+ if (is_open(impl))
+ {
+ // 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.
+ reactor_type* reactor = static_cast<reactor_type*>(
+ interlocked_compare_exchange_pointer(
+ reinterpret_cast<void**>(&reactor_), 0, 0));
+ if (reactor)
+ reactor->close_descriptor(impl.socket_, impl.reactor_data_);
+
+ if (socket_ops::close(impl.socket_, ec) == socket_error_retval)
+ return ec;
+
+ impl.socket_ = invalid_socket;
+ impl.flags_ = 0;
+ impl.cancel_token_.reset();
+#if defined(BOOST_ASIO_ENABLE_CANCELIO)
+ impl.safe_cancellation_thread_id_ = 0;
+#endif // defined(BOOST_ASIO_ENABLE_CANCELIO)
+ }
+
+ ec = boost::system::error_code();
+ return ec;
+ }
+
+ // Get the native socket representation.
+ native_type native(implementation_type& impl)
+ {
+ return impl.socket_;
+ }
+
+ // Cancel all operations associated with the socket.
+ boost::system::error_code cancel(implementation_type& impl,
+ boost::system::error_code& ec)
+ {
+ if (!is_open(impl))
+ {
+ ec = boost::asio::error::bad_descriptor;
+ return ec;
+ }
+ else 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 = boost::system::error_code();
+ }
+ else
+ {
+ ec = boost::system::error_code(last_error,
+ boost::asio::error::get_system_category());
+ }
+ }
+ else
+ {
+ ec = boost::system::error_code();
+ }
+ }
+#if defined(BOOST_ASIO_ENABLE_CANCELIO)
+ else if (impl.safe_cancellation_thread_id_ == 0)
+ {
+ // No operations have been started, so there's nothing to cancel.
+ ec = boost::system::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 = boost::system::error_code(last_error,
+ boost::asio::error::get_system_category());
+ }
+ else
+ {
+ ec = boost::system::error_code();
+ }
+ }
+ else
+ {
+ // Asynchronous operations have been started from more than one thread,
+ // so cancellation is not safe.
+ ec = boost::asio::error::operation_not_supported;
+ }
+#else // defined(BOOST_ASIO_ENABLE_CANCELIO)
+ else
+ {
+ // Cancellation is not supported as CancelIo may not be used.
+ ec = boost::asio::error::operation_not_supported;
+ }
+#endif // defined(BOOST_ASIO_ENABLE_CANCELIO)
+
+ return ec;
+ }
+
+ // Determine whether the socket is at the out-of-band data mark.
+ bool at_mark(const implementation_type& impl,
+ boost::system::error_code& ec) const
+ {
+ if (!is_open(impl))
+ {
+ ec = boost::asio::error::bad_descriptor;
+ return false;
+ }
+
+ boost::asio::detail::ioctl_arg_type value = 0;
+ socket_ops::ioctl(impl.socket_, SIOCATMARK, &value, ec);
+ return ec ? false : value != 0;
+ }
+
+ // Determine the number of bytes available for reading.
+ std::size_t available(const implementation_type& impl,
+ boost::system::error_code& ec) const
+ {
+ if (!is_open(impl))
+ {
+ ec = boost::asio::error::bad_descriptor;
+ return 0;
+ }
+
+ boost::asio::detail::ioctl_arg_type value = 0;
+ socket_ops::ioctl(impl.socket_, FIONREAD, &value, ec);
+ return ec ? static_cast<std::size_t>(0) : static_cast<std::size_t>(value);
+ }
+
+ // Bind the socket to the specified local endpoint.
+ boost::system::error_code bind(implementation_type& impl,
+ const endpoint_type& endpoint, boost::system::error_code& ec)
+ {
+ if (!is_open(impl))
+ {
+ ec = boost::asio::error::bad_descriptor;
+ return ec;
+ }
+
+ socket_ops::bind(impl.socket_, endpoint.data(), endpoint.size(), ec);
+ return ec;
+ }
+
+ // Place the socket into the state where it will listen for new connections.
+ boost::system::error_code listen(implementation_type& impl, int backlog,
+ boost::system::error_code& ec)
+ {
+ if (!is_open(impl))
+ {
+ ec = boost::asio::error::bad_descriptor;
+ return ec;
+ }
+
+ socket_ops::listen(impl.socket_, backlog, ec);
+ return ec;
+ }
+
+ // Set a socket option.
+ template <typename Option>
+ boost::system::error_code set_option(implementation_type& impl,
+ const Option& option, boost::system::error_code& ec)
+ {
+ if (!is_open(impl))
+ {
+ ec = boost::asio::error::bad_descriptor;
+ return ec;
+ }
+
+ if (option.level(impl.protocol_) == custom_socket_option_level
+ && option.name(impl.protocol_) == enable_connection_aborted_option)
+ {
+ if (option.size(impl.protocol_) != sizeof(int))
+ {
+ ec = boost::asio::error::invalid_argument;
+ }
+ else
+ {
+ if (*reinterpret_cast<const int*>(option.data(impl.protocol_)))
+ impl.flags_ |= implementation_type::enable_connection_aborted;
+ else
+ impl.flags_ &= ~implementation_type::enable_connection_aborted;
+ ec = boost::system::error_code();
+ }
+ return ec;
+ }
+ else
+ {
+ if (option.level(impl.protocol_) == SOL_SOCKET
+ && option.name(impl.protocol_) == SO_LINGER)
+ {
+ const ::linger* linger_option =
+ reinterpret_cast<const ::linger*>(option.data(impl.protocol_));
+ if (linger_option->l_onoff != 0 && linger_option->l_linger != 0)
+ impl.flags_ |= implementation_type::close_might_block;
+ else
+ impl.flags_ &= ~implementation_type::close_might_block;
+ }
+
+ socket_ops::setsockopt(impl.socket_,
+ option.level(impl.protocol_), option.name(impl.protocol_),
+ option.data(impl.protocol_), option.size(impl.protocol_), ec);
+ return ec;
+ }
+ }
+
+ // Set a socket option.
+ template <typename Option>
+ boost::system::error_code get_option(const implementation_type& impl,
+ Option& option, boost::system::error_code& ec) const
+ {
+ if (!is_open(impl))
+ {
+ ec = boost::asio::error::bad_descriptor;
+ return ec;
+ }
+
+ if (option.level(impl.protocol_) == custom_socket_option_level
+ && option.name(impl.protocol_) == enable_connection_aborted_option)
+ {
+ if (option.size(impl.protocol_) != sizeof(int))
+ {
+ ec = boost::asio::error::invalid_argument;
+ }
+ else
+ {
+ int* target = reinterpret_cast<int*>(option.data(impl.protocol_));
+ if (impl.flags_ & implementation_type::enable_connection_aborted)
+ *target = 1;
+ else
+ *target = 0;
+ option.resize(impl.protocol_, sizeof(int));
+ ec = boost::system::error_code();
+ }
+ return ec;
+ }
+ else
+ {
+ size_t size = option.size(impl.protocol_);
+ socket_ops::getsockopt(impl.socket_,
+ option.level(impl.protocol_), option.name(impl.protocol_),
+ option.data(impl.protocol_), &size, ec);
+ if (!ec)
+ option.resize(impl.protocol_, size);
+ return ec;
+ }
+ }
+
+ // Perform an IO control command on the socket.
+ template <typename IO_Control_Command>
+ boost::system::error_code io_control(implementation_type& impl,
+ IO_Control_Command& command, boost::system::error_code& ec)
+ {
+ if (!is_open(impl))
+ {
+ ec = boost::asio::error::bad_descriptor;
+ return ec;
+ }
+
+ socket_ops::ioctl(impl.socket_, command.name(),
+ static_cast<ioctl_arg_type*>(command.data()), ec);
+
+ if (!ec && command.name() == static_cast<int>(FIONBIO))
+ {
+ if (*static_cast<ioctl_arg_type*>(command.data()))
+ impl.flags_ |= implementation_type::user_set_non_blocking;
+ else
+ impl.flags_ &= ~implementation_type::user_set_non_blocking;
+ }
+
+ return ec;
+ }
+
+ // Get the local endpoint.
+ endpoint_type local_endpoint(const implementation_type& impl,
+ boost::system::error_code& ec) const
+ {
+ if (!is_open(impl))
+ {
+ ec = boost::asio::error::bad_descriptor;
+ return endpoint_type();
+ }
+
+ endpoint_type endpoint;
+ std::size_t addr_len = endpoint.capacity();
+ if (socket_ops::getsockname(impl.socket_, endpoint.data(), &addr_len, ec))
+ return endpoint_type();
+ endpoint.resize(addr_len);
+ return endpoint;
+ }
+
+ // Get the remote endpoint.
+ endpoint_type remote_endpoint(const implementation_type& impl,
+ boost::system::error_code& ec) const
+ {
+ if (!is_open(impl))
+ {
+ ec = boost::asio::error::bad_descriptor;
+ return endpoint_type();
+ }
+
+ if (impl.socket_.have_remote_endpoint())
+ {
+ // Check if socket is still connected.
+ DWORD connect_time = 0;
+ size_t connect_time_len = sizeof(connect_time);
+ if (socket_ops::getsockopt(impl.socket_, SOL_SOCKET, SO_CONNECT_TIME,
+ &connect_time, &connect_time_len, ec) == socket_error_retval)
+ {
+ return endpoint_type();
+ }
+ if (connect_time == 0xFFFFFFFF)
+ {
+ ec = boost::asio::error::not_connected;
+ return endpoint_type();
+ }
+
+ ec = boost::system::error_code();
+ return impl.socket_.remote_endpoint();
+ }
+ else
+ {
+ endpoint_type endpoint;
+ std::size_t addr_len = endpoint.capacity();
+ if (socket_ops::getpeername(impl.socket_, endpoint.data(), &addr_len, ec))
+ return endpoint_type();
+ endpoint.resize(addr_len);
+ return endpoint;
+ }
+ }
+
+ /// Disable sends or receives on the socket.
+ boost::system::error_code shutdown(implementation_type& impl,
+ socket_base::shutdown_type what, boost::system::error_code& ec)
+ {
+ if (!is_open(impl))
+ {
+ ec = boost::asio::error::bad_descriptor;
+ return ec;
+ }
+
+ socket_ops::shutdown(impl.socket_, what, ec);
+ return ec;
+ }
+
+ // Send the given data to the peer. Returns the number of bytes sent.
+ template <typename ConstBufferSequence>
+ size_t send(implementation_type& impl, const ConstBufferSequence& buffers,
+ socket_base::message_flags flags, boost::system::error_code& ec)
+ {
+ if (!is_open(impl))
+ {
+ ec = boost::asio::error::bad_descriptor;
+ return 0;
+ }
+
+ // Copy buffers into WSABUF array.
+ ::WSABUF bufs[max_buffers];
+ typename ConstBufferSequence::const_iterator iter = buffers.begin();
+ typename ConstBufferSequence::const_iterator end = buffers.end();
+ DWORD i = 0;
+ size_t total_buffer_size = 0;
+ for (; iter != end && i < max_buffers; ++iter, ++i)
+ {
+ boost::asio::const_buffer buffer(*iter);
+ bufs[i].len = static_cast<u_long>(boost::asio::buffer_size(buffer));
+ bufs[i].buf = const_cast<char*>(
+ boost::asio::buffer_cast<const char*>(buffer));
+ total_buffer_size += boost::asio::buffer_size(buffer);
+ }
+
+ // A request to receive 0 bytes on a stream socket is a no-op.
+ if (impl.protocol_.type() == SOCK_STREAM && total_buffer_size == 0)
+ {
+ ec = boost::system::error_code();
+ return 0;
+ }
+
+ // Send the data.
+ DWORD bytes_transferred = 0;
+ int result = ::WSASend(impl.socket_, bufs,
+ i, &bytes_transferred, flags, 0, 0);
+ if (result != 0)
+ {
+ DWORD last_error = ::WSAGetLastError();
+ if (last_error == ERROR_NETNAME_DELETED)
+ last_error = WSAECONNRESET;
+ else if (last_error == ERROR_PORT_UNREACHABLE)
+ last_error = WSAECONNREFUSED;
+ ec = boost::system::error_code(last_error,
+ boost::asio::error::get_system_category());
+ return 0;
+ }
+
+ ec = boost::system::error_code();
+ return bytes_transferred;
+ }
+
+ // Wait until data can be sent without blocking.
+ size_t send(implementation_type& impl, const null_buffers&,
+ socket_base::message_flags, boost::system::error_code& ec)
+ {
+ if (!is_open(impl))
+ {
+ ec = boost::asio::error::bad_descriptor;
+ return 0;
+ }
+
+ // Wait for socket to become ready.
+ socket_ops::poll_write(impl.socket_, ec);
+
+ return 0;
+ }
+
+ template <typename ConstBufferSequence, typename Handler>
+ class send_operation
+ : public operation
+ {
+ public:
+ send_operation(win_iocp_io_service& io_service,
+ weak_cancel_token_type cancel_token,
+ const ConstBufferSequence& buffers, Handler handler)
+ : operation(io_service,
+ &send_operation<ConstBufferSequence, Handler>::do_completion_impl,
+ &send_operation<ConstBufferSequence, Handler>::destroy_impl),
+ work_(io_service.get_io_service()),
+ cancel_token_(cancel_token),
+ buffers_(buffers),
+ handler_(handler)
+ {
+ }
+
+ private:
+ static void do_completion_impl(operation* op,
+ DWORD last_error, size_t bytes_transferred)
+ {
+ // Take ownership of the operation object.
+ typedef send_operation<ConstBufferSequence, Handler> op_type;
+ op_type* handler_op(static_cast<op_type*>(op));
+ typedef handler_alloc_traits<Handler, op_type> alloc_traits;
+ handler_ptr<alloc_traits> ptr(handler_op->handler_, handler_op);
+
+#if defined(BOOST_ASIO_ENABLE_BUFFER_DEBUGGING)
+ // Check whether buffers are still valid.
+ typename ConstBufferSequence::const_iterator iter
+ = handler_op->buffers_.begin();
+ typename ConstBufferSequence::const_iterator end
+ = handler_op->buffers_.end();
+ while (iter != end)
+ {
+ boost::asio::const_buffer buffer(*iter);
+ boost::asio::buffer_cast<const char*>(buffer);
+ ++iter;
+ }
+#endif // defined(BOOST_ASIO_ENABLE_BUFFER_DEBUGGING)
+
+ // Map non-portable errors to their portable counterparts.
+ boost::system::error_code ec(last_error,
+ boost::asio::error::get_system_category());
+ if (ec.value() == ERROR_NETNAME_DELETED)
+ {
+ if (handler_op->cancel_token_.expired())
+ ec = boost::asio::error::operation_aborted;
+ else
+ ec = boost::asio::error::connection_reset;
+ }
+ else if (ec.value() == ERROR_PORT_UNREACHABLE)
+ {
+ ec = boost::asio::error::connection_refused;
+ }
+
+ // Make a copy of the handler so that the memory can be deallocated before
+ // the upcall is made.
+ Handler handler(handler_op->handler_);
+
+ // Free the memory associated with the handler.
+ ptr.reset();
+
+ // Call the handler.
+ boost_asio_handler_invoke_helpers::invoke(
+ detail::bind_handler(handler, ec, bytes_transferred), &handler);
+ }
+
+ static void destroy_impl(operation* op)
+ {
+ // Take ownership of the operation object.
+ typedef send_operation<ConstBufferSequence, Handler> op_type;
+ op_type* handler_op(static_cast<op_type*>(op));
+ typedef handler_alloc_traits<Handler, op_type> alloc_traits;
+ handler_ptr<alloc_traits> ptr(handler_op->handler_, handler_op);
+
+ // 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(handler_op->handler_);
+ (void)handler;
+
+ // Free the memory associated with the handler.
+ ptr.reset();
+ }
+
+ boost::asio::io_service::work work_;
+ weak_cancel_token_type cancel_token_;
+ ConstBufferSequence buffers_;
+ Handler handler_;
+ };
+
+ // 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& impl, const ConstBufferSequence& buffers,
+ socket_base::message_flags flags, Handler handler)
+ {
+ if (!is_open(impl))
+ {
+ this->get_io_service().post(bind_handler(handler,
+ boost::asio::error::bad_descriptor, 0));
+ return;
+ }
+
+#if defined(BOOST_ASIO_ENABLE_CANCELIO)
+ // Update the ID of the thread from which cancellation is safe.
+ 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);
+#endif // defined(BOOST_ASIO_ENABLE_CANCELIO)
+
+ // Allocate and construct an operation to wrap the handler.
+ typedef send_operation<ConstBufferSequence, Handler> value_type;
+ typedef handler_alloc_traits<Handler, value_type> alloc_traits;
+ raw_handler_ptr<alloc_traits> raw_ptr(handler);
+ handler_ptr<alloc_traits> ptr(raw_ptr, iocp_service_,
+ impl.cancel_token_, buffers, handler);
+
+ // Copy buffers into WSABUF array.
+ ::WSABUF bufs[max_buffers];
+ typename ConstBufferSequence::const_iterator iter = buffers.begin();
+ typename ConstBufferSequence::const_iterator end = buffers.end();
+ DWORD i = 0;
+ size_t total_buffer_size = 0;
+ for (; iter != end && i < max_buffers; ++iter, ++i)
+ {
+ boost::asio::const_buffer buffer(*iter);
+ bufs[i].len = static_cast<u_long>(boost::asio::buffer_size(buffer));
+ bufs[i].buf = const_cast<char*>(
+ boost::asio::buffer_cast<const char*>(buffer));
+ total_buffer_size += boost::asio::buffer_size(buffer);
+ }
+
+ // A request to receive 0 bytes on a stream socket is a no-op.
+ if (impl.protocol_.type() == SOCK_STREAM && total_buffer_size == 0)
+ {
+ boost::asio::io_service::work work(this->get_io_service());
+ ptr.reset();
+ boost::system::error_code error;
+ iocp_service_.post(bind_handler(handler, error, 0));
+ return;
+ }
+
+ // Send the data.
+ DWORD bytes_transferred = 0;
+ int result = ::WSASend(impl.socket_, bufs, i,
+ &bytes_transferred, flags, ptr.get(), 0);
+ DWORD last_error = ::WSAGetLastError();
+
+ // Check if the operation completed immediately.
+ if (result != 0 && last_error != WSA_IO_PENDING)
+ {
+ boost::asio::io_service::work work(this->get_io_service());
+ ptr.reset();
+ boost::system::error_code ec(last_error,
+ boost::asio::error::get_system_category());
+ iocp_service_.post(bind_handler(handler, ec, bytes_transferred));
+ }
+ else
+ {
+ ptr.release();
+ }
+ }
+
+ template <typename Handler>
+ class null_buffers_operation
+ {
+ public:
+ null_buffers_operation(boost::asio::io_service& io_service, Handler handler)
+ : work_(io_service),
+ handler_(handler)
+ {
+ }
+
+ bool perform(boost::system::error_code&,
+ std::size_t& bytes_transferred)
+ {
+ bytes_transferred = 0;
+ return true;
+ }
+
+ void complete(const boost::system::error_code& ec,
+ std::size_t bytes_transferred)
+ {
+ work_.get_io_service().post(bind_handler(
+ handler_, ec, bytes_transferred));
+ }
+
+ private:
+ boost::asio::io_service::work work_;
+ Handler handler_;
+ };
+
+ // Start an asynchronous wait until data can be sent without blocking.
+ template <typename Handler>
+ void async_send(implementation_type& impl, const null_buffers&,
+ socket_base::message_flags, Handler handler)
+ {
+ if (!is_open(impl))
+ {
+ this->get_io_service().post(bind_handler(handler,
+ boost::asio::error::bad_descriptor, 0));
+ }
+ else
+ {
+ // Check if the reactor was already obtained from the io_service.
+ reactor_type* reactor = static_cast<reactor_type*>(
+ interlocked_compare_exchange_pointer(
+ reinterpret_cast<void**>(&reactor_), 0, 0));
+ if (!reactor)
+ {
+ reactor = &(boost::asio::use_service<reactor_type>(
+ this->get_io_service()));
+ interlocked_exchange_pointer(
+ reinterpret_cast<void**>(&reactor_), reactor);
+ }
+
+ reactor->start_write_op(impl.socket_, impl.reactor_data_,
+ null_buffers_operation<Handler>(this->get_io_service(), handler),
+ false);
+ }
+ }
+
+ // Send a datagram to the specified endpoint. Returns the number of bytes
+ // sent.
+ template <typename ConstBufferSequence>
+ size_t send_to(implementation_type& impl, const ConstBufferSequence& buffers,
+ const endpoint_type& destination, socket_base::message_flags flags,
+ boost::system::error_code& ec)
+ {
+ if (!is_open(impl))
+ {
+ ec = boost::asio::error::bad_descriptor;
+ return 0;
+ }
+
+ // Copy buffers into WSABUF array.
+ ::WSABUF bufs[max_buffers];
+ typename ConstBufferSequence::const_iterator iter = buffers.begin();
+ typename ConstBufferSequence::const_iterator end = buffers.end();
+ DWORD i = 0;
+ for (; iter != end && i < max_buffers; ++iter, ++i)
+ {
+ boost::asio::const_buffer buffer(*iter);
+ bufs[i].len = static_cast<u_long>(boost::asio::buffer_size(buffer));
+ bufs[i].buf = const_cast<char*>(
+ boost::asio::buffer_cast<const char*>(buffer));
+ }
+
+ // Send the data.
+ DWORD bytes_transferred = 0;
+ int result = ::WSASendTo(impl.socket_, bufs, i, &bytes_transferred,
+ flags, destination.data(), static_cast<int>(destination.size()), 0, 0);
+ if (result != 0)
+ {
+ DWORD last_error = ::WSAGetLastError();
+ if (last_error == ERROR_PORT_UNREACHABLE)
+ last_error = WSAECONNREFUSED;
+ ec = boost::system::error_code(last_error,
+ boost::asio::error::get_system_category());
+ return 0;
+ }
+
+ ec = boost::system::error_code();
+ return bytes_transferred;
+ }
+
+ // Wait until data can be sent without blocking.
+ size_t send_to(implementation_type& impl, const null_buffers&,
+ socket_base::message_flags, const endpoint_type&,
+ boost::system::error_code& ec)
+ {
+ if (!is_open(impl))
+ {
+ ec = boost::asio::error::bad_descriptor;
+ return 0;
+ }
+
+ // Wait for socket to become ready.
+ socket_ops::poll_write(impl.socket_, ec);
+
+ return 0;
+ }
+
+ template <typename ConstBufferSequence, typename Handler>
+ class send_to_operation
+ : public operation
+ {
+ public:
+ send_to_operation(win_iocp_io_service& io_service,
+ const ConstBufferSequence& buffers, Handler handler)
+ : operation(io_service,
+ &send_to_operation<ConstBufferSequence, Handler>::do_completion_impl,
+ &send_to_operation<ConstBufferSequence, Handler>::destroy_impl),
+ work_(io_service.get_io_service()),
+ buffers_(buffers),
+ handler_(handler)
+ {
+ }
+
+ private:
+ static void do_completion_impl(operation* op,
+ DWORD last_error, size_t bytes_transferred)
+ {
+ // Take ownership of the operation object.
+ typedef send_to_operation<ConstBufferSequence, Handler> op_type;
+ op_type* handler_op(static_cast<op_type*>(op));
+ typedef handler_alloc_traits<Handler, op_type> alloc_traits;
+ handler_ptr<alloc_traits> ptr(handler_op->handler_, handler_op);
+
+#if defined(BOOST_ASIO_ENABLE_BUFFER_DEBUGGING)
+ // Check whether buffers are still valid.
+ typename ConstBufferSequence::const_iterator iter
+ = handler_op->buffers_.begin();
+ typename ConstBufferSequence::const_iterator end
+ = handler_op->buffers_.end();
+ while (iter != end)
+ {
+ boost::asio::const_buffer buffer(*iter);
+ boost::asio::buffer_cast<const char*>(buffer);
+ ++iter;
+ }
+#endif // defined(BOOST_ASIO_ENABLE_BUFFER_DEBUGGING)
+
+ // Map non-portable errors to their portable counterparts.
+ boost::system::error_code ec(last_error,
+ boost::asio::error::get_system_category());
+ if (ec.value() == ERROR_PORT_UNREACHABLE)
+ {
+ ec = boost::asio::error::connection_refused;
+ }
+
+ // Make a copy of the handler so that the memory can be deallocated before
+ // the upcall is made.
+ Handler handler(handler_op->handler_);
+
+ // Free the memory associated with the handler.
+ ptr.reset();
+
+ // Call the handler.
+ boost_asio_handler_invoke_helpers::invoke(
+ detail::bind_handler(handler, ec, bytes_transferred), &handler);
+ }
+
+ static void destroy_impl(operation* op)
+ {
+ // Take ownership of the operation object.
+ typedef send_to_operation<ConstBufferSequence, Handler> op_type;
+ op_type* handler_op(static_cast<op_type*>(op));
+ typedef handler_alloc_traits<Handler, op_type> alloc_traits;
+ handler_ptr<alloc_traits> ptr(handler_op->handler_, handler_op);
+
+ // 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(handler_op->handler_);
+ (void)handler;
+
+ // Free the memory associated with the handler.
+ ptr.reset();
+ }
+
+ boost::asio::io_service::work work_;
+ ConstBufferSequence buffers_;
+ Handler handler_;
+ };
+
+ // 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)
+ {
+ if (!is_open(impl))
+ {
+ this->get_io_service().post(bind_handler(handler,
+ boost::asio::error::bad_descriptor, 0));
+ return;
+ }
+
+#if defined(BOOST_ASIO_ENABLE_CANCELIO)
+ // Update the ID of the thread from which cancellation is safe.
+ 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);
+#endif // defined(BOOST_ASIO_ENABLE_CANCELIO)
+
+ // Allocate and construct an operation to wrap the handler.
+ typedef send_to_operation<ConstBufferSequence, Handler> value_type;
+ typedef handler_alloc_traits<Handler, value_type> alloc_traits;
+ raw_handler_ptr<alloc_traits> raw_ptr(handler);
+ handler_ptr<alloc_traits> ptr(raw_ptr, iocp_service_, buffers, handler);
+
+ // Copy buffers into WSABUF array.
+ ::WSABUF bufs[max_buffers];
+ typename ConstBufferSequence::const_iterator iter = buffers.begin();
+ typename ConstBufferSequence::const_iterator end = buffers.end();
+ DWORD i = 0;
+ for (; iter != end && i < max_buffers; ++iter, ++i)
+ {
+ boost::asio::const_buffer buffer(*iter);
+ bufs[i].len = static_cast<u_long>(boost::asio::buffer_size(buffer));
+ bufs[i].buf = const_cast<char*>(
+ boost::asio::buffer_cast<const char*>(buffer));
+ }
+
+ // Send the data.
+ DWORD bytes_transferred = 0;
+ int result = ::WSASendTo(impl.socket_, bufs, i, &bytes_transferred, flags,
+ destination.data(), static_cast<int>(destination.size()), ptr.get(), 0);
+ DWORD last_error = ::WSAGetLastError();
+
+ // Check if the operation completed immediately.
+ if (result != 0 && last_error != WSA_IO_PENDING)
+ {
+ boost::asio::io_service::work work(this->get_io_service());
+ ptr.reset();
+ boost::system::error_code ec(last_error,
+ boost::asio::error::get_system_category());
+ iocp_service_.post(bind_handler(handler, ec, bytes_transferred));
+ }
+ else
+ {
+ ptr.release();
+ }
+ }
+
+ // Start an asynchronous wait until data can be sent without blocking.
+ template <typename Handler>
+ void async_send_to(implementation_type& impl, const null_buffers&,
+ socket_base::message_flags, const endpoint_type&, Handler handler)
+ {
+ if (!is_open(impl))
+ {
+ this->get_io_service().post(bind_handler(handler,
+ boost::asio::error::bad_descriptor, 0));
+ }
+ else
+ {
+ // Check if the reactor was already obtained from the io_service.
+ reactor_type* reactor = static_cast<reactor_type*>(
+ interlocked_compare_exchange_pointer(
+ reinterpret_cast<void**>(&reactor_), 0, 0));
+ if (!reactor)
+ {
+ reactor = &(boost::asio::use_service<reactor_type>(
+ this->get_io_service()));
+ interlocked_exchange_pointer(
+ reinterpret_cast<void**>(&reactor_), reactor);
+ }
+
+ reactor->start_write_op(impl.socket_, impl.reactor_data_,
+ null_buffers_operation<Handler>(this->get_io_service(), handler),
+ false);
+ }
+ }
+
+ // Receive some data from the peer. Returns the number of bytes received.
+ template <typename MutableBufferSequence>
+ size_t receive(implementation_type& impl,
+ const MutableBufferSequence& buffers,
+ socket_base::message_flags flags, boost::system::error_code& ec)
+ {
+ if (!is_open(impl))
+ {
+ ec = boost::asio::error::bad_descriptor;
+ return 0;
+ }
+
+ // Copy buffers into WSABUF array.
+ ::WSABUF bufs[max_buffers];
+ typename MutableBufferSequence::const_iterator iter = buffers.begin();
+ typename MutableBufferSequence::const_iterator end = buffers.end();
+ DWORD i = 0;
+ size_t total_buffer_size = 0;
+ for (; iter != end && i < max_buffers; ++iter, ++i)
+ {
+ boost::asio::mutable_buffer buffer(*iter);
+ bufs[i].len = static_cast<u_long>(boost::asio::buffer_size(buffer));
+ bufs[i].buf = boost::asio::buffer_cast<char*>(buffer);
+ total_buffer_size += boost::asio::buffer_size(buffer);
+ }
+
+ // A request to receive 0 bytes on a stream socket is a no-op.
+ if (impl.protocol_.type() == SOCK_STREAM && total_buffer_size == 0)
+ {
+ ec = boost::system::error_code();
+ return 0;
+ }
+
+ // Receive some data.
+ DWORD bytes_transferred = 0;
+ DWORD recv_flags = flags;
+ int result = ::WSARecv(impl.socket_, bufs, i,
+ &bytes_transferred, &recv_flags, 0, 0);
+ if (result != 0)
+ {
+ DWORD last_error = ::WSAGetLastError();
+ if (last_error == ERROR_NETNAME_DELETED)
+ last_error = WSAECONNRESET;
+ else if (last_error == ERROR_PORT_UNREACHABLE)
+ last_error = WSAECONNREFUSED;
+ ec = boost::system::error_code(last_error,
+ boost::asio::error::get_system_category());
+ return 0;
+ }
+ if (bytes_transferred == 0 && impl.protocol_.type() == SOCK_STREAM)
+ {
+ ec = boost::asio::error::eof;
+ return 0;
+ }
+
+ ec = boost::system::error_code();
+ return bytes_transferred;
+ }
+
+ // Wait until data can be received without blocking.
+ size_t receive(implementation_type& impl, const null_buffers&,
+ socket_base::message_flags, boost::system::error_code& ec)
+ {
+ if (!is_open(impl))
+ {
+ ec = boost::asio::error::bad_descriptor;
+ return 0;
+ }
+
+ // Wait for socket to become ready.
+ socket_ops::poll_read(impl.socket_, ec);
+
+ return 0;
+ }
+
+ template <typename MutableBufferSequence, typename Handler>
+ class receive_operation
+ : public operation
+ {
+ public:
+ receive_operation(int protocol_type, win_iocp_io_service& io_service,
+ weak_cancel_token_type cancel_token,
+ const MutableBufferSequence& buffers, Handler handler)
+ : operation(io_service,
+ &receive_operation<
+ MutableBufferSequence, Handler>::do_completion_impl,
+ &receive_operation<
+ MutableBufferSequence, Handler>::destroy_impl),
+ protocol_type_(protocol_type),
+ work_(io_service.get_io_service()),
+ cancel_token_(cancel_token),
+ buffers_(buffers),
+ handler_(handler)
+ {
+ }
+
+ private:
+ static void do_completion_impl(operation* op,
+ DWORD last_error, size_t bytes_transferred)
+ {
+ // Take ownership of the operation object.
+ typedef receive_operation<MutableBufferSequence, Handler> op_type;
+ op_type* handler_op(static_cast<op_type*>(op));
+ typedef handler_alloc_traits<Handler, op_type> alloc_traits;
+ handler_ptr<alloc_traits> ptr(handler_op->handler_, handler_op);
+
+#if defined(BOOST_ASIO_ENABLE_BUFFER_DEBUGGING)
+ // Check whether buffers are still valid.
+ typename MutableBufferSequence::const_iterator iter
+ = handler_op->buffers_.begin();
+ typename MutableBufferSequence::const_iterator end
+ = handler_op->buffers_.end();
+ while (iter != end)
+ {
+ boost::asio::mutable_buffer buffer(*iter);
+ boost::asio::buffer_cast<char*>(buffer);
+ ++iter;
+ }
+#endif // defined(BOOST_ASIO_ENABLE_BUFFER_DEBUGGING)
+
+ // Map non-portable errors to their portable counterparts.
+ boost::system::error_code ec(last_error,
+ boost::asio::error::get_system_category());
+ if (ec.value() == ERROR_NETNAME_DELETED)
+ {
+ if (handler_op->cancel_token_.expired())
+ ec = boost::asio::error::operation_aborted;
+ else
+ ec = boost::asio::error::connection_reset;
+ }
+ else if (ec.value() == ERROR_PORT_UNREACHABLE)
+ {
+ ec = boost::asio::error::connection_refused;
+ }
+
+ // Check for connection closed.
+ else if (!ec && bytes_transferred == 0
+ && handler_op->protocol_type_ == SOCK_STREAM
+ && !boost::is_same<MutableBufferSequence, null_buffers>::value)
+ {
+ ec = boost::asio::error::eof;
+ }
+
+ // Make a copy of the handler so that the memory can be deallocated before
+ // the upcall is made.
+ Handler handler(handler_op->handler_);
+
+ // Free the memory associated with the handler.
+ ptr.reset();
+
+ // Call the handler.
+ boost_asio_handler_invoke_helpers::invoke(
+ detail::bind_handler(handler, ec, bytes_transferred), &handler);
+ }
+
+ static void destroy_impl(operation* op)
+ {
+ // Take ownership of the operation object.
+ typedef receive_operation<MutableBufferSequence, Handler> op_type;
+ op_type* handler_op(static_cast<op_type*>(op));
+ typedef handler_alloc_traits<Handler, op_type> alloc_traits;
+ handler_ptr<alloc_traits> ptr(handler_op->handler_, handler_op);
+
+ // 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(handler_op->handler_);
+ (void)handler;
+
+ // Free the memory associated with the handler.
+ ptr.reset();
+ }
+
+ int protocol_type_;
+ boost::asio::io_service::work work_;
+ weak_cancel_token_type cancel_token_;
+ MutableBufferSequence buffers_;
+ Handler handler_;
+ };
+
+ // 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& impl,
+ const MutableBufferSequence& buffers,
+ socket_base::message_flags flags, Handler handler)
+ {
+ if (!is_open(impl))
+ {
+ this->get_io_service().post(bind_handler(handler,
+ boost::asio::error::bad_descriptor, 0));
+ return;
+ }
+
+#if defined(BOOST_ASIO_ENABLE_CANCELIO)
+ // Update the ID of the thread from which cancellation is safe.
+ 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);
+#endif // defined(BOOST_ASIO_ENABLE_CANCELIO)
+
+ // Allocate and construct an operation to wrap the handler.
+ typedef receive_operation<MutableBufferSequence, Handler> value_type;
+ typedef handler_alloc_traits<Handler, value_type> alloc_traits;
+ raw_handler_ptr<alloc_traits> raw_ptr(handler);
+ int protocol_type = impl.protocol_.type();
+ handler_ptr<alloc_traits> ptr(raw_ptr, protocol_type,
+ iocp_service_, impl.cancel_token_, buffers, handler);
+
+ // Copy buffers into WSABUF array.
+ ::WSABUF bufs[max_buffers];
+ typename MutableBufferSequence::const_iterator iter = buffers.begin();
+ typename MutableBufferSequence::const_iterator end = buffers.end();
+ DWORD i = 0;
+ size_t total_buffer_size = 0;
+ for (; iter != end && i < max_buffers; ++iter, ++i)
+ {
+ boost::asio::mutable_buffer buffer(*iter);
+ bufs[i].len = static_cast<u_long>(boost::asio::buffer_size(buffer));
+ bufs[i].buf = boost::asio::buffer_cast<char*>(buffer);
+ total_buffer_size += boost::asio::buffer_size(buffer);
+ }
+
+ // A request to receive 0 bytes on a stream socket is a no-op.
+ if (impl.protocol_.type() == SOCK_STREAM && total_buffer_size == 0)
+ {
+ boost::asio::io_service::work work(this->get_io_service());
+ ptr.reset();
+ boost::system::error_code error;
+ iocp_service_.post(bind_handler(handler, error, 0));
+ return;
+ }
+
+ // Receive some data.
+ DWORD bytes_transferred = 0;
+ DWORD recv_flags = flags;
+ int result = ::WSARecv(impl.socket_, bufs, i,
+ &bytes_transferred, &recv_flags, ptr.get(), 0);
+ DWORD last_error = ::WSAGetLastError();
+ if (result != 0 && last_error != WSA_IO_PENDING)
+ {
+ boost::asio::io_service::work work(this->get_io_service());
+ ptr.reset();
+ boost::system::error_code ec(last_error,
+ boost::asio::error::get_system_category());
+ iocp_service_.post(bind_handler(handler, ec, bytes_transferred));
+ }
+ else
+ {
+ ptr.release();
+ }
+ }
+
+ // Wait until data can be received without blocking.
+ template <typename Handler>
+ void async_receive(implementation_type& impl, const null_buffers& buffers,
+ socket_base::message_flags flags, Handler handler)
+ {
+ if (!is_open(impl))
+ {
+ this->get_io_service().post(bind_handler(handler,
+ boost::asio::error::bad_descriptor, 0));
+ }
+ else if (impl.protocol_.type() == SOCK_STREAM)
+ {
+ // For stream sockets on Windows, we may issue a 0-byte overlapped
+ // WSARecv to wait until there is data available on the socket.
+
+#if defined(BOOST_ASIO_ENABLE_CANCELIO)
+ // Update the ID of the thread from which cancellation is safe.
+ 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);
+#endif // defined(BOOST_ASIO_ENABLE_CANCELIO)
+
+ // Allocate and construct an operation to wrap the handler.
+ typedef receive_operation<null_buffers, Handler> value_type;
+ typedef handler_alloc_traits<Handler, value_type> alloc_traits;
+ raw_handler_ptr<alloc_traits> raw_ptr(handler);
+ int protocol_type = impl.protocol_.type();
+ handler_ptr<alloc_traits> ptr(raw_ptr, protocol_type,
+ iocp_service_, impl.cancel_token_, buffers, handler);
+
+ // Issue a receive operation with an empty buffer.
+ ::WSABUF buf = { 0, 0 };
+ DWORD bytes_transferred = 0;
+ DWORD recv_flags = flags;
+ int result = ::WSARecv(impl.socket_, &buf, 1,
+ &bytes_transferred, &recv_flags, ptr.get(), 0);
+ DWORD last_error = ::WSAGetLastError();
+ if (result != 0 && last_error != WSA_IO_PENDING)
+ {
+ boost::asio::io_service::work work(this->get_io_service());
+ ptr.reset();
+ boost::system::error_code ec(last_error,
+ boost::asio::error::get_system_category());
+ iocp_service_.post(bind_handler(handler, ec, bytes_transferred));
+ }
+ else
+ {
+ ptr.release();
+ }
+ }
+ else
+ {
+ // Check if the reactor was already obtained from the io_service.
+ reactor_type* reactor = static_cast<reactor_type*>(
+ interlocked_compare_exchange_pointer(
+ reinterpret_cast<void**>(&reactor_), 0, 0));
+ if (!reactor)
+ {
+ reactor = &(boost::asio::use_service<reactor_type>(
+ this->get_io_service()));
+ interlocked_exchange_pointer(
+ reinterpret_cast<void**>(&reactor_), reactor);
+ }
+
+ if (flags & socket_base::message_out_of_band)
+ {
+ reactor->start_except_op(impl.socket_, impl.reactor_data_,
+ null_buffers_operation<Handler>(this->get_io_service(), handler));
+ }
+ else
+ {
+ reactor->start_read_op(impl.socket_, impl.reactor_data_,
+ null_buffers_operation<Handler>(this->get_io_service(), handler),
+ false);
+ }
+ }
+ }
+
+ // Receive a datagram with the endpoint of the sender. Returns the number of
+ // bytes received.
+ template <typename MutableBufferSequence>
+ size_t receive_from(implementation_type& impl,
+ const MutableBufferSequence& buffers,
+ endpoint_type& sender_endpoint, socket_base::message_flags flags,
+ boost::system::error_code& ec)
+ {
+ if (!is_open(impl))
+ {
+ ec = boost::asio::error::bad_descriptor;
+ return 0;
+ }
+
+ // Copy buffers into WSABUF array.
+ ::WSABUF bufs[max_buffers];
+ typename MutableBufferSequence::const_iterator iter = buffers.begin();
+ typename MutableBufferSequence::const_iterator end = buffers.end();
+ DWORD i = 0;
+ for (; iter != end && i < max_buffers; ++iter, ++i)
+ {
+ boost::asio::mutable_buffer buffer(*iter);
+ bufs[i].len = static_cast<u_long>(boost::asio::buffer_size(buffer));
+ bufs[i].buf = boost::asio::buffer_cast<char*>(buffer);
+ }
+
+ // Receive some data.
+ DWORD bytes_transferred = 0;
+ DWORD recv_flags = flags;
+ int endpoint_size = static_cast<int>(sender_endpoint.capacity());
+ int result = ::WSARecvFrom(impl.socket_, bufs, i, &bytes_transferred,
+ &recv_flags, sender_endpoint.data(), &endpoint_size, 0, 0);
+ if (result != 0)
+ {
+ DWORD last_error = ::WSAGetLastError();
+ if (last_error == ERROR_PORT_UNREACHABLE)
+ last_error = WSAECONNREFUSED;
+ ec = boost::system::error_code(last_error,
+ boost::asio::error::get_system_category());
+ return 0;
+ }
+ if (bytes_transferred == 0 && impl.protocol_.type() == SOCK_STREAM)
+ {
+ ec = boost::asio::error::eof;
+ return 0;
+ }
+
+ sender_endpoint.resize(static_cast<std::size_t>(endpoint_size));
+
+ ec = boost::system::error_code();
+ return bytes_transferred;
+ }
+
+ // Wait until data can be received without blocking.
+ size_t receive_from(implementation_type& impl,
+ const null_buffers&, endpoint_type& sender_endpoint,
+ socket_base::message_flags, boost::system::error_code& ec)
+ {
+ if (!is_open(impl))
+ {
+ ec = boost::asio::error::bad_descriptor;
+ return 0;
+ }
+
+ // Wait for socket to become ready.
+ socket_ops::poll_read(impl.socket_, ec);
+
+ // Reset endpoint since it can be given no sensible value at this time.
+ sender_endpoint = endpoint_type();
+
+ return 0;
+ }
+
+ template <typename MutableBufferSequence, typename Handler>
+ class receive_from_operation
+ : public operation
+ {
+ public:
+ receive_from_operation(int protocol_type, win_iocp_io_service& io_service,
+ endpoint_type& endpoint, const MutableBufferSequence& buffers,
+ Handler handler)
+ : operation(io_service,
+ &receive_from_operation<
+ MutableBufferSequence, Handler>::do_completion_impl,
+ &receive_from_operation<
+ MutableBufferSequence, Handler>::destroy_impl),
+ protocol_type_(protocol_type),
+ endpoint_(endpoint),
+ endpoint_size_(static_cast<int>(endpoint.capacity())),
+ work_(io_service.get_io_service()),
+ buffers_(buffers),
+ handler_(handler)
+ {
+ }
+
+ int& endpoint_size()
+ {
+ return endpoint_size_;
+ }
+
+ private:
+ static void do_completion_impl(operation* op,
+ DWORD last_error, size_t bytes_transferred)
+ {
+ // Take ownership of the operation object.
+ typedef receive_from_operation<MutableBufferSequence, Handler> op_type;
+ op_type* handler_op(static_cast<op_type*>(op));
+ typedef handler_alloc_traits<Handler, op_type> alloc_traits;
+ handler_ptr<alloc_traits> ptr(handler_op->handler_, handler_op);
+
+#if defined(BOOST_ASIO_ENABLE_BUFFER_DEBUGGING)
+ // Check whether buffers are still valid.
+ typename MutableBufferSequence::const_iterator iter
+ = handler_op->buffers_.begin();
+ typename MutableBufferSequence::const_iterator end
+ = handler_op->buffers_.end();
+ while (iter != end)
+ {
+ boost::asio::mutable_buffer buffer(*iter);
+ boost::asio::buffer_cast<char*>(buffer);
+ ++iter;
+ }
+#endif // defined(BOOST_ASIO_ENABLE_BUFFER_DEBUGGING)
+
+ // Map non-portable errors to their portable counterparts.
+ boost::system::error_code ec(last_error,
+ boost::asio::error::get_system_category());
+ if (ec.value() == ERROR_PORT_UNREACHABLE)
+ {
+ ec = boost::asio::error::connection_refused;
+ }
+
+ // Check for connection closed.
+ if (!ec && bytes_transferred == 0
+ && handler_op->protocol_type_ == SOCK_STREAM)
+ {
+ ec = boost::asio::error::eof;
+ }
+
+ // Record the size of the endpoint returned by the operation.
+ handler_op->endpoint_.resize(handler_op->endpoint_size_);
+
+ // Make a copy of the handler so that the memory can be deallocated before
+ // the upcall is made.
+ Handler handler(handler_op->handler_);
+
+ // Free the memory associated with the handler.
+ ptr.reset();
+
+ // Call the handler.
+ boost_asio_handler_invoke_helpers::invoke(
+ detail::bind_handler(handler, ec, bytes_transferred), &handler);
+ }
+
+ static void destroy_impl(operation* op)
+ {
+ // Take ownership of the operation object.
+ typedef receive_from_operation<MutableBufferSequence, Handler> op_type;
+ op_type* handler_op(static_cast<op_type*>(op));
+ typedef handler_alloc_traits<Handler, op_type> alloc_traits;
+ handler_ptr<alloc_traits> ptr(handler_op->handler_, handler_op);
+
+ // 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(handler_op->handler_);
+ (void)handler;
+
+ // Free the memory associated with the handler.
+ ptr.reset();
+ }
+
+ int protocol_type_;
+ endpoint_type& endpoint_;
+ int endpoint_size_;
+ boost::asio::io_service::work work_;
+ MutableBufferSequence buffers_;
+ Handler handler_;
+ };
+
+ // 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)
+ {
+ if (!is_open(impl))
+ {
+ this->get_io_service().post(bind_handler(handler,
+ boost::asio::error::bad_descriptor, 0));
+ return;
+ }
+
+#if defined(BOOST_ASIO_ENABLE_CANCELIO)
+ // Update the ID of the thread from which cancellation is safe.
+ 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);
+#endif // defined(BOOST_ASIO_ENABLE_CANCELIO)
+
+ // Allocate and construct an operation to wrap the handler.
+ typedef receive_from_operation<MutableBufferSequence, Handler> value_type;
+ typedef handler_alloc_traits<Handler, value_type> alloc_traits;
+ raw_handler_ptr<alloc_traits> raw_ptr(handler);
+ int protocol_type = impl.protocol_.type();
+ handler_ptr<alloc_traits> ptr(raw_ptr, protocol_type,
+ iocp_service_, sender_endp, buffers, handler);
+
+ // Copy buffers into WSABUF array.
+ ::WSABUF bufs[max_buffers];
+ typename MutableBufferSequence::const_iterator iter = buffers.begin();
+ typename MutableBufferSequence::const_iterator end = buffers.end();
+ DWORD i = 0;
+ for (; iter != end && i < max_buffers; ++iter, ++i)
+ {
+ boost::asio::mutable_buffer buffer(*iter);
+ bufs[i].len = static_cast<u_long>(boost::asio::buffer_size(buffer));
+ bufs[i].buf = boost::asio::buffer_cast<char*>(buffer);
+ }
+
+ // Receive some data.
+ DWORD bytes_transferred = 0;
+ DWORD recv_flags = flags;
+ int result = ::WSARecvFrom(impl.socket_, bufs, i, &bytes_transferred,
+ &recv_flags, sender_endp.data(), &ptr.get()->endpoint_size(),
+ ptr.get(), 0);
+ DWORD last_error = ::WSAGetLastError();
+ if (result != 0 && last_error != WSA_IO_PENDING)
+ {
+ boost::asio::io_service::work work(this->get_io_service());
+ ptr.reset();
+ boost::system::error_code ec(last_error,
+ boost::asio::error::get_system_category());
+ iocp_service_.post(bind_handler(handler, ec, bytes_transferred));
+ }
+ else
+ {
+ ptr.release();
+ }
+ }
+
+ // 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)
+ {
+ if (!is_open(impl))
+ {
+ this->get_io_service().post(bind_handler(handler,
+ boost::asio::error::bad_descriptor, 0));
+ }
+ else
+ {
+ // Check if the reactor was already obtained from the io_service.
+ reactor_type* reactor = static_cast<reactor_type*>(
+ interlocked_compare_exchange_pointer(
+ reinterpret_cast<void**>(&reactor_), 0, 0));
+ if (!reactor)
+ {
+ reactor = &(boost::asio::use_service<reactor_type>(
+ this->get_io_service()));
+ interlocked_exchange_pointer(
+ reinterpret_cast<void**>(&reactor_), reactor);
+ }
+
+ // Reset endpoint since it can be given no sensible value at this time.
+ sender_endpoint = endpoint_type();
+
+ if (flags & socket_base::message_out_of_band)
+ {
+ reactor->start_except_op(impl.socket_, impl.reactor_data_,
+ null_buffers_operation<Handler>(this->get_io_service(), handler));
+ }
+ else
+ {
+ reactor->start_read_op(impl.socket_, impl.reactor_data_,
+ null_buffers_operation<Handler>(this->get_io_service(), handler),
+ false);
+ }
+ }
+ }
+
+ // Accept a new connection.
+ template <typename Socket>
+ boost::system::error_code accept(implementation_type& impl, Socket& peer,
+ endpoint_type* peer_endpoint, boost::system::error_code& ec)
+ {
+ if (!is_open(impl))
+ {
+ ec = boost::asio::error::bad_descriptor;
+ return ec;
+ }
+
+ // We cannot accept a socket that is already open.
+ if (peer.is_open())
+ {
+ ec = boost::asio::error::already_open;
+ return ec;
+ }
+
+ for (;;)
+ {
+ socket_holder new_socket;
+ std::size_t addr_len = 0;
+ if (peer_endpoint)
+ {
+ addr_len = peer_endpoint->capacity();
+ new_socket.reset(socket_ops::accept(impl.socket_,
+ peer_endpoint->data(), &addr_len, ec));
+ }
+ else
+ {
+ new_socket.reset(socket_ops::accept(impl.socket_, 0, 0, ec));
+ }
+
+ if (ec)
+ {
+ if (ec == boost::asio::error::connection_aborted
+ && !(impl.flags_ & implementation_type::enable_connection_aborted))
+ {
+ // Retry accept operation.
+ continue;
+ }
+ else
+ {
+ return ec;
+ }
+ }
+
+ if (peer_endpoint)
+ peer_endpoint->resize(addr_len);
+
+ peer.assign(impl.protocol_, new_socket.get(), ec);
+ if (!ec)
+ new_socket.release();
+ return ec;
+ }
+ }
+
+ template <typename Socket, typename Handler>
+ class accept_operation
+ : public operation
+ {
+ public:
+ accept_operation(win_iocp_io_service& io_service,
+ socket_type socket, socket_type new_socket, Socket& peer,
+ const protocol_type& protocol, endpoint_type* peer_endpoint,
+ bool enable_connection_aborted, Handler handler)
+ : operation(io_service,
+ &accept_operation<Socket, Handler>::do_completion_impl,
+ &accept_operation<Socket, Handler>::destroy_impl),
+ io_service_(io_service),
+ socket_(socket),
+ new_socket_(new_socket),
+ peer_(peer),
+ protocol_(protocol),
+ peer_endpoint_(peer_endpoint),
+ work_(io_service.get_io_service()),
+ enable_connection_aborted_(enable_connection_aborted),
+ handler_(handler)
+ {
+ }
+
+ socket_type new_socket()
+ {
+ return new_socket_.get();
+ }
+
+ void* output_buffer()
+ {
+ return output_buffer_;
+ }
+
+ DWORD address_length()
+ {
+ return sizeof(sockaddr_storage_type) + 16;
+ }
+
+ private:
+ static void do_completion_impl(operation* op, DWORD last_error, size_t)
+ {
+ // Take ownership of the operation object.
+ typedef accept_operation<Socket, Handler> op_type;
+ op_type* handler_op(static_cast<op_type*>(op));
+ typedef handler_alloc_traits<Handler, op_type> alloc_traits;
+ handler_ptr<alloc_traits> ptr(handler_op->handler_, handler_op);
+
+ // Map Windows error ERROR_NETNAME_DELETED to connection_aborted.
+ if (last_error == ERROR_NETNAME_DELETED)
+ {
+ last_error = WSAECONNABORTED;
+ }
+
+ // Restart the accept operation if we got the connection_aborted error
+ // and the enable_connection_aborted socket option is not set.
+ if (last_error == WSAECONNABORTED
+ && !ptr.get()->enable_connection_aborted_)
+ {
+ // Reset OVERLAPPED structure.
+ ptr.get()->Internal = 0;
+ ptr.get()->InternalHigh = 0;
+ ptr.get()->Offset = 0;
+ ptr.get()->OffsetHigh = 0;
+ ptr.get()->hEvent = 0;
+
+ // Create a new socket for the next connection, since the AcceptEx call
+ // fails with WSAEINVAL if we try to reuse the same socket.
+ boost::system::error_code ec;
+ ptr.get()->new_socket_.reset();
+ ptr.get()->new_socket_.reset(socket_ops::socket(
+ ptr.get()->protocol_.family(), ptr.get()->protocol_.type(),
+ ptr.get()->protocol_.protocol(), ec));
+ if (ptr.get()->new_socket() != invalid_socket)
+ {
+ // Accept a connection.
+ DWORD bytes_read = 0;
+ BOOL result = ::AcceptEx(ptr.get()->socket_, ptr.get()->new_socket(),
+ ptr.get()->output_buffer(), 0, ptr.get()->address_length(),
+ ptr.get()->address_length(), &bytes_read, ptr.get());
+ last_error = ::WSAGetLastError();
+
+ // Check if the operation completed immediately.
+ if (!result && last_error != WSA_IO_PENDING)
+ {
+ if (last_error == ERROR_NETNAME_DELETED
+ || last_error == WSAECONNABORTED)
+ {
+ // Post this handler so that operation will be restarted again.
+ ptr.get()->io_service_.post_completion(ptr.get(), last_error, 0);
+ ptr.release();
+ return;
+ }
+ else
+ {
+ // Operation already complete. Continue with rest of this handler.
+ }
+ }
+ else
+ {
+ // Asynchronous operation has been successfully restarted.
+ ptr.release();
+ return;
+ }
+ }
+ }
+
+ // Get the address of the peer.
+ endpoint_type peer_endpoint;
+ if (last_error == 0)
+ {
+ LPSOCKADDR local_addr = 0;
+ int local_addr_length = 0;
+ LPSOCKADDR remote_addr = 0;
+ int remote_addr_length = 0;
+ GetAcceptExSockaddrs(handler_op->output_buffer(), 0,
+ handler_op->address_length(), handler_op->address_length(),
+ &local_addr, &local_addr_length, &remote_addr, &remote_addr_length);
+ if (static_cast<std::size_t>(remote_addr_length)
+ > peer_endpoint.capacity())
+ {
+ last_error = WSAEINVAL;
+ }
+ else
+ {
+ using namespace std; // For memcpy.
+ memcpy(peer_endpoint.data(), remote_addr, remote_addr_length);
+ peer_endpoint.resize(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.
+ if (last_error == 0)
+ {
+ SOCKET update_ctx_param = handler_op->socket_;
+ boost::system::error_code ec;
+ if (socket_ops::setsockopt(handler_op->new_socket_.get(),
+ SOL_SOCKET, SO_UPDATE_ACCEPT_CONTEXT,
+ &update_ctx_param, sizeof(SOCKET), ec) != 0)
+ {
+ last_error = ec.value();
+ }
+ }
+
+ // If the socket was successfully accepted, transfer ownership of the
+ // socket to the peer object.
+ if (last_error == 0)
+ {
+ boost::system::error_code ec;
+ handler_op->peer_.assign(handler_op->protocol_,
+ native_type(handler_op->new_socket_.get(), peer_endpoint), ec);
+ if (ec)
+ last_error = ec.value();
+ else
+ handler_op->new_socket_.release();
+ }
+
+ // Pass endpoint back to caller.
+ if (handler_op->peer_endpoint_)
+ *handler_op->peer_endpoint_ = peer_endpoint;
+
+ // Make a copy of the handler so that the memory can be deallocated before
+ // the upcall is made.
+ Handler handler(handler_op->handler_);
+
+ // Free the memory associated with the handler.
+ ptr.reset();
+
+ // Call the handler.
+ boost::system::error_code ec(last_error,
+ boost::asio::error::get_system_category());
+ boost_asio_handler_invoke_helpers::invoke(
+ detail::bind_handler(handler, ec), &handler);
+ }
+
+ static void destroy_impl(operation* op)
+ {
+ // Take ownership of the operation object.
+ typedef accept_operation<Socket, Handler> op_type;
+ op_type* handler_op(static_cast<op_type*>(op));
+ typedef handler_alloc_traits<Handler, op_type> alloc_traits;
+ handler_ptr<alloc_traits> ptr(handler_op->handler_, handler_op);
+
+ // 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(handler_op->handler_);
+ (void)handler;
+
+ // Free the memory associated with the handler.
+ ptr.reset();
+ }
+
+ win_iocp_io_service& io_service_;
+ socket_type socket_;
+ socket_holder new_socket_;
+ Socket& peer_;
+ protocol_type protocol_;
+ endpoint_type* peer_endpoint_;
+ boost::asio::io_service::work work_;
+ unsigned char output_buffer_[(sizeof(sockaddr_storage_type) + 16) * 2];
+ bool enable_connection_aborted_;
+ Handler handler_;
+ };
+
+ // 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)
+ {
+ // Check whether acceptor has been initialised.
+ if (!is_open(impl))
+ {
+ this->get_io_service().post(bind_handler(handler,
+ boost::asio::error::bad_descriptor));
+ return;
+ }
+
+ // Check that peer socket has not already been opened.
+ if (peer.is_open())
+ {
+ this->get_io_service().post(bind_handler(handler,
+ boost::asio::error::already_open));
+ return;
+ }
+
+#if defined(BOOST_ASIO_ENABLE_CANCELIO)
+ // Update the ID of the thread from which cancellation is safe.
+ 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);
+#endif // defined(BOOST_ASIO_ENABLE_CANCELIO)
+
+ // Create a new socket for the connection.
+ boost::system::error_code ec;
+ socket_holder sock(socket_ops::socket(impl.protocol_.family(),
+ impl.protocol_.type(), impl.protocol_.protocol(), ec));
+ if (sock.get() == invalid_socket)
+ {
+ this->get_io_service().post(bind_handler(handler, ec));
+ return;
+ }
+
+ // Allocate and construct an operation to wrap the handler.
+ typedef accept_operation<Socket, Handler> value_type;
+ typedef handler_alloc_traits<Handler, value_type> alloc_traits;
+ raw_handler_ptr<alloc_traits> raw_ptr(handler);
+ socket_type new_socket = sock.get();
+ bool enable_connection_aborted =
+ (impl.flags_ & implementation_type::enable_connection_aborted);
+ handler_ptr<alloc_traits> ptr(raw_ptr,
+ iocp_service_, impl.socket_, new_socket, peer, impl.protocol_,
+ peer_endpoint, enable_connection_aborted, handler);
+ sock.release();
+
+ // Accept a connection.
+ DWORD bytes_read = 0;
+ BOOL result = ::AcceptEx(impl.socket_, ptr.get()->new_socket(),
+ ptr.get()->output_buffer(), 0, ptr.get()->address_length(),
+ ptr.get()->address_length(), &bytes_read, ptr.get());
+ DWORD last_error = ::WSAGetLastError();
+
+ // Check if the operation completed immediately.
+ if (!result && last_error != WSA_IO_PENDING)
+ {
+ if (!enable_connection_aborted
+ && (last_error == ERROR_NETNAME_DELETED
+ || last_error == WSAECONNABORTED))
+ {
+ // Post handler so that operation will be restarted again. We do not
+ // perform the AcceptEx again here to avoid the possibility of starving
+ // other handlers.
+ iocp_service_.post_completion(ptr.get(), last_error, 0);
+ ptr.release();
+ }
+ else
+ {
+ boost::asio::io_service::work work(this->get_io_service());
+ ptr.reset();
+ boost::system::error_code ec(last_error,
+ boost::asio::error::get_system_category());
+ iocp_service_.post(bind_handler(handler, ec));
+ }
+ }
+ else
+ {
+ ptr.release();
+ }
+ }
+
+ // Connect the socket to the specified endpoint.
+ boost::system::error_code connect(implementation_type& impl,
+ const endpoint_type& peer_endpoint, boost::system::error_code& ec)
+ {
+ if (!is_open(impl))
+ {
+ ec = boost::asio::error::bad_descriptor;
+ return ec;
+ }
+
+ // Perform the connect operation.
+ socket_ops::connect(impl.socket_,
+ peer_endpoint.data(), peer_endpoint.size(), ec);
+ return ec;
+ }
+
+ template <typename Handler>
+ class connect_operation
+ {
+ public:
+ connect_operation(socket_type socket, bool user_set_non_blocking,
+ boost::asio::io_service& io_service, Handler handler)
+ : socket_(socket),
+ user_set_non_blocking_(user_set_non_blocking),
+ io_service_(io_service),
+ work_(io_service),
+ handler_(handler)
+ {
+ }
+
+ bool perform(boost::system::error_code& ec,
+ std::size_t& bytes_transferred)
+ {
+ bytes_transferred = 0;
+
+ // Check whether the operation was successful.
+ if (ec)
+ return true;
+
+ // Get the error code from the connect operation.
+ int connect_error = 0;
+ size_t connect_error_len = sizeof(connect_error);
+ if (socket_ops::getsockopt(socket_, SOL_SOCKET, SO_ERROR,
+ &connect_error, &connect_error_len, ec) == socket_error_retval)
+ return true;
+
+ // If connection failed then post the handler with the error code.
+ if (connect_error)
+ {
+ ec = boost::system::error_code(connect_error,
+ boost::asio::error::get_system_category());
+ return true;
+ }
+
+ // Revert socket to blocking mode unless the user requested otherwise.
+ if (!user_set_non_blocking_)
+ {
+ ioctl_arg_type non_blocking = 0;
+ if (socket_ops::ioctl(socket_, FIONBIO, &non_blocking, ec))
+ return true;
+ }
+
+ // Post the result of the successful connection operation.
+ ec = boost::system::error_code();
+ return true;
+ }
+
+ void complete(const boost::system::error_code& ec, std::size_t)
+ {
+ io_service_.post(bind_handler(handler_, ec));
+ }
+
+ private:
+ socket_type socket_;
+ bool user_set_non_blocking_;
+ boost::asio::io_service& io_service_;
+ boost::asio::io_service::work work_;
+ Handler handler_;
+ };
+
+ // Start an asynchronous connect.
+ template <typename Handler>
+ void async_connect(implementation_type& impl,
+ const endpoint_type& peer_endpoint, Handler handler)
+ {
+ if (!is_open(impl))
+ {
+ this->get_io_service().post(bind_handler(handler,
+ boost::asio::error::bad_descriptor));
+ return;
+ }
+
+#if defined(BOOST_ASIO_ENABLE_CANCELIO)
+ // Update the ID of the thread from which cancellation is safe.
+ 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);
+#endif // defined(BOOST_ASIO_ENABLE_CANCELIO)
+
+ // Check if the reactor was already obtained from the io_service.
+ reactor_type* reactor = static_cast<reactor_type*>(
+ interlocked_compare_exchange_pointer(
+ reinterpret_cast<void**>(&reactor_), 0, 0));
+ if (!reactor)
+ {
+ reactor = &(boost::asio::use_service<reactor_type>(
+ this->get_io_service()));
+ interlocked_exchange_pointer(
+ reinterpret_cast<void**>(&reactor_), reactor);
+ }
+
+ // Mark the socket as non-blocking so that the connection will take place
+ // asynchronously.
+ ioctl_arg_type non_blocking = 1;
+ boost::system::error_code ec;
+ if (socket_ops::ioctl(impl.socket_, FIONBIO, &non_blocking, ec))
+ {
+ this->get_io_service().post(bind_handler(handler, ec));
+ return;
+ }
+
+ // Start the connect operation.
+ if (socket_ops::connect(impl.socket_, peer_endpoint.data(),
+ peer_endpoint.size(), ec) == 0)
+ {
+ // Revert socket to blocking mode unless the user requested otherwise.
+ if (!(impl.flags_ & implementation_type::user_set_non_blocking))
+ {
+ non_blocking = 0;
+ socket_ops::ioctl(impl.socket_, FIONBIO, &non_blocking, ec);
+ }
+
+ // The connect operation has finished successfully so we need to post the
+ // handler immediately.
+ this->get_io_service().post(bind_handler(handler, ec));
+ }
+ else if (ec == boost::asio::error::in_progress
+ || ec == boost::asio::error::would_block)
+ {
+ // The connection is happening in the background, and we need to wait
+ // until the socket becomes writeable.
+ boost::shared_ptr<bool> completed(new bool(false));
+ reactor->start_connect_op(impl.socket_, impl.reactor_data_,
+ connect_operation<Handler>(
+ impl.socket_,
+ (impl.flags_ & implementation_type::user_set_non_blocking) != 0,
+ this->get_io_service(), handler));
+ }
+ else
+ {
+ // Revert socket to blocking mode unless the user requested otherwise.
+ if (!(impl.flags_ & implementation_type::user_set_non_blocking))
+ {
+ non_blocking = 0;
+ boost::system::error_code ignored_ec;
+ socket_ops::ioctl(impl.socket_, FIONBIO, &non_blocking, ignored_ec);
+ }
+
+ // The connect operation has failed, so post the handler immediately.
+ this->get_io_service().post(bind_handler(handler, ec));
+ }
+ }
+
+private:
+ // Helper function to close a socket when the associated object is being
+ // destroyed.
+ void close_for_destruction(implementation_type& impl)
+ {
+ if (is_open(impl))
+ {
+ // 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.
+ reactor_type* reactor = static_cast<reactor_type*>(
+ interlocked_compare_exchange_pointer(
+ reinterpret_cast<void**>(&reactor_), 0, 0));
+ if (reactor)
+ reactor->close_descriptor(impl.socket_, impl.reactor_data_);
+
+ // The socket destructor must not block. If the user has changed the
+ // linger option to block in the foreground, we will change it back to the
+ // default so that the closure is performed in the background.
+ if (impl.flags_ & implementation_type::close_might_block)
+ {
+ ::linger opt;
+ opt.l_onoff = 0;
+ opt.l_linger = 0;
+ boost::system::error_code ignored_ec;
+ socket_ops::setsockopt(impl.socket_,
+ SOL_SOCKET, SO_LINGER, &opt, sizeof(opt), ignored_ec);
+ }
+
+ boost::system::error_code ignored_ec;
+ socket_ops::close(impl.socket_, ignored_ec);
+ impl.socket_ = invalid_socket;
+ impl.flags_ = 0;
+ impl.cancel_token_.reset();
+#if defined(BOOST_ASIO_ENABLE_CANCELIO)
+ impl.safe_cancellation_thread_id_ = 0;
+#endif // defined(BOOST_ASIO_ENABLE_CANCELIO)
+ }
+ }
+
+ // Helper function to emulate InterlockedCompareExchangePointer functionality
+ // for:
+ // - very old Platform SDKs; and
+ // - platform SDKs where MSVC's /Wp64 option causes spurious warnings.
+ void* 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
+ }
+
+ // Helper function to emulate InterlockedExchangePointer functionality for:
+ // - very old Platform SDKs; and
+ // - platform SDKs where MSVC's /Wp64 option causes spurious warnings.
+ void* 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
+ }
+
+ // The IOCP service used for running asynchronous operations and dispatching
+ // handlers.
+ win_iocp_io_service& iocp_service_;
+
+ // The reactor used for performing connect operations. This object is created
+ // only if needed.
+ reactor_type* reactor_;
+
+ // Mutex to protect access to the linked list of implementations.
+ boost::asio::detail::mutex mutex_;
+
+ // The head of a linked list of all implementations.
+ implementation_type* impl_list_;
+};
+
+} // namespace detail
+} // namespace asio
+} // namespace boost
+
+#endif // defined(BOOST_ASIO_HAS_IOCP)
+
+#include <boost/asio/detail/pop_options.hpp>
+
+#endif // BOOST_ASIO_DETAIL_WIN_IOCP_SOCKET_SERVICE_HPP
diff --git a/3rdParty/Boost/boost/asio/detail/win_mutex.hpp b/3rdParty/Boost/boost/asio/detail/win_mutex.hpp
new file mode 100644
index 0000000..f5470c4
--- /dev/null
+++ b/3rdParty/Boost/boost/asio/detail/win_mutex.hpp
@@ -0,0 +1,151 @@
+//
+// win_mutex.hpp
+// ~~~~~~~~~~~~~
+//
+// Copyright (c) 2003-2008 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 BOOST_ASIO_DETAIL_WIN_MUTEX_HPP
+#define BOOST_ASIO_DETAIL_WIN_MUTEX_HPP
+
+#if defined(_MSC_VER) && (_MSC_VER >= 1200)
+# pragma once
+#endif // defined(_MSC_VER) && (_MSC_VER >= 1200)
+
+#include <boost/asio/detail/push_options.hpp>
+
+#include <boost/asio/detail/push_options.hpp>
+#include <boost/config.hpp>
+#include <boost/system/system_error.hpp>
+#include <boost/asio/detail/pop_options.hpp>
+
+#if defined(BOOST_WINDOWS)
+
+#include <boost/asio/error.hpp>
+#include <boost/asio/detail/noncopyable.hpp>
+#include <boost/asio/detail/socket_types.hpp>
+#include <boost/asio/detail/scoped_lock.hpp>
+
+#include <boost/asio/detail/push_options.hpp>
+#include <boost/throw_exception.hpp>
+#include <boost/asio/detail/pop_options.hpp>
+
+namespace boost {
+namespace asio {
+namespace detail {
+
+class win_mutex
+ : private noncopyable
+{
+public:
+ typedef boost::asio::detail::scoped_lock<win_mutex> scoped_lock;
+
+ // Constructor.
+ win_mutex()
+ {
+ int error = do_init();
+ if (error != 0)
+ {
+ boost::system::system_error e(
+ boost::system::error_code(error,
+ boost::asio::error::get_system_category()),
+ "mutex");
+ boost::throw_exception(e);
+ }
+ }
+
+ // Destructor.
+ ~win_mutex()
+ {
+ ::DeleteCriticalSection(&crit_section_);
+ }
+
+ // Lock the mutex.
+ void lock()
+ {
+ int error = do_lock();
+ if (error != 0)
+ {
+ boost::system::system_error e(
+ boost::system::error_code(error,
+ boost::asio::error::get_system_category()),
+ "mutex");
+ boost::throw_exception(e);
+ }
+ }
+
+ // 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.
+ int 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.
+ ::InitializeCriticalSection(&crit_section_);
+ return 0;
+#else
+ __try
+ {
+ ::InitializeCriticalSection(&crit_section_);
+ }
+ __except(GetExceptionCode() == STATUS_NO_MEMORY
+ ? EXCEPTION_EXECUTE_HANDLER : EXCEPTION_CONTINUE_SEARCH)
+ {
+ return ERROR_OUTOFMEMORY;
+ }
+
+ return 0;
+#endif
+ }
+
+ // Locking must be performed in a separate function to lock() since the
+ // compiler does not support the use of structured exceptions and C++
+ // exceptions in the same function.
+ int do_lock()
+ {
+#if defined(__MINGW32__)
+ // Not sure if MinGW supports structured exception handling, so for now
+ // we'll just call the Windows API and hope.
+ ::EnterCriticalSection(&crit_section_);
+ return 0;
+#else
+ __try
+ {
+ ::EnterCriticalSection(&crit_section_);
+ }
+ __except(GetExceptionCode() == STATUS_INVALID_HANDLE
+ || GetExceptionCode() == STATUS_NO_MEMORY
+ ? EXCEPTION_EXECUTE_HANDLER : EXCEPTION_CONTINUE_SEARCH)
+ {
+ if (GetExceptionCode() == STATUS_NO_MEMORY)
+ return ERROR_OUTOFMEMORY;
+ return ERROR_INVALID_HANDLE;
+ }
+
+ return 0;
+#endif
+ }
+
+ ::CRITICAL_SECTION crit_section_;
+};
+
+} // namespace detail
+} // namespace asio
+} // namespace boost
+
+#endif // defined(BOOST_WINDOWS)
+
+#include <boost/asio/detail/pop_options.hpp>
+
+#endif // BOOST_ASIO_DETAIL_WIN_MUTEX_HPP
diff --git a/3rdParty/Boost/boost/asio/detail/win_signal_blocker.hpp b/3rdParty/Boost/boost/asio/detail/win_signal_blocker.hpp
new file mode 100644
index 0000000..e9b4d37
--- /dev/null
+++ b/3rdParty/Boost/boost/asio/detail/win_signal_blocker.hpp
@@ -0,0 +1,69 @@
+//
+// win_signal_blocker.hpp
+// ~~~~~~~~~~~~~~~~~~~~~~
+//
+// Copyright (c) 2003-2008 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 BOOST_ASIO_DETAIL_WIN_SIGNAL_BLOCKER_HPP
+#define BOOST_ASIO_DETAIL_WIN_SIGNAL_BLOCKER_HPP
+
+#if defined(_MSC_VER) && (_MSC_VER >= 1200)
+# pragma once
+#endif // defined(_MSC_VER) && (_MSC_VER >= 1200)
+
+#include <boost/asio/detail/push_options.hpp>
+
+#include <boost/asio/detail/push_options.hpp>
+#include <boost/config.hpp>
+#include <boost/asio/detail/pop_options.hpp>
+
+#if defined(BOOST_WINDOWS) || defined(__CYGWIN__)
+
+#include <boost/asio/detail/noncopyable.hpp>
+
+namespace boost {
+namespace asio {
+namespace detail {
+
+class win_signal_blocker
+ : private noncopyable
+{
+public:
+ // Constructor blocks all signals for the calling thread.
+ win_signal_blocker()
+ {
+ // No-op.
+ }
+
+ // Destructor restores the previous signal mask.
+ ~win_signal_blocker()
+ {
+ // No-op.
+ }
+
+ // Block all signals for the calling thread.
+ void block()
+ {
+ // No-op.
+ }
+
+ // Restore the previous signal mask.
+ void unblock()
+ {
+ // No-op.
+ }
+};
+
+} // namespace detail
+} // namespace asio
+} // namespace boost
+
+#endif // defined(BOOST_WINDOWS) || defined(__CYGWIN__)
+
+#include <boost/asio/detail/pop_options.hpp>
+
+#endif // BOOST_ASIO_DETAIL_WIN_SIGNAL_BLOCKER_HPP
diff --git a/3rdParty/Boost/boost/asio/detail/win_thread.hpp b/3rdParty/Boost/boost/asio/detail/win_thread.hpp
new file mode 100644
index 0000000..c8058d8
--- /dev/null
+++ b/3rdParty/Boost/boost/asio/detail/win_thread.hpp
@@ -0,0 +1,234 @@
+//
+// win_thread.hpp
+// ~~~~~~~~~~~~~~
+//
+// Copyright (c) 2003-2008 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 BOOST_ASIO_DETAIL_WIN_THREAD_HPP
+#define BOOST_ASIO_DETAIL_WIN_THREAD_HPP
+
+#if defined(_MSC_VER) && (_MSC_VER >= 1200)
+# pragma once
+#endif // defined(_MSC_VER) && (_MSC_VER >= 1200)
+
+#include <boost/asio/detail/push_options.hpp>
+
+#include <boost/asio/detail/push_options.hpp>
+#include <boost/config.hpp>
+#include <boost/system/system_error.hpp>
+#include <boost/asio/detail/pop_options.hpp>
+
+#if defined(BOOST_WINDOWS) && !defined(UNDER_CE)
+
+#include <boost/asio/error.hpp>
+#include <boost/asio/detail/noncopyable.hpp>
+#include <boost/asio/detail/socket_types.hpp>
+
+#include <boost/asio/detail/push_options.hpp>
+#include <boost/throw_exception.hpp>
+#include <memory>
+#include <process.h>
+#include <boost/asio/detail/pop_options.hpp>
+
+namespace boost {
+namespace asio {
+namespace detail {
+
+unsigned int __stdcall win_thread_function(void* arg);
+
+#if (WINVER < 0x0500)
+void __stdcall apc_function(ULONG data);
+#else
+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)
+ : exit_event_(0)
+ {
+ std::auto_ptr<func_base> arg(new func<Function>(f));
+
+ ::HANDLE entry_event = 0;
+ arg->entry_event_ = entry_event = ::CreateEvent(0, true, false, 0);
+ if (!entry_event)
+ {
+ DWORD last_error = ::GetLastError();
+ boost::system::system_error e(
+ boost::system::error_code(last_error,
+ boost::asio::error::get_system_category()),
+ "thread.entry_event");
+ boost::throw_exception(e);
+ }
+
+ arg->exit_event_ = exit_event_ = ::CreateEvent(0, true, false, 0);
+ if (!exit_event_)
+ {
+ DWORD last_error = ::GetLastError();
+ ::CloseHandle(entry_event);
+ boost::system::system_error e(
+ boost::system::error_code(last_error,
+ boost::asio::error::get_system_category()),
+ "thread.exit_event");
+ boost::throw_exception(e);
+ }
+
+ unsigned int thread_id = 0;
+ thread_ = reinterpret_cast<HANDLE>(::_beginthreadex(0, 0,
+ win_thread_function, arg.get(), 0, &thread_id));
+ if (!thread_)
+ {
+ DWORD last_error = ::GetLastError();
+ if (entry_event)
+ ::CloseHandle(entry_event);
+ if (exit_event_)
+ ::CloseHandle(exit_event_);
+ boost::system::system_error e(
+ boost::system::error_code(last_error,
+ boost::asio::error::get_system_category()),
+ "thread");
+ boost::throw_exception(e);
+ }
+ arg.release();
+
+ if (entry_event)
+ {
+ ::WaitForSingleObject(entry_event, INFINITE);
+ ::CloseHandle(entry_event);
+ }
+ }
+
+ // Destructor.
+ ~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.
+ }
+
+ // Wait for the thread to exit.
+ void join()
+ {
+ ::WaitForSingleObject(exit_event_, INFINITE);
+ ::CloseHandle(exit_event_);
+ if (terminate_threads())
+ {
+ ::TerminateThread(thread_, 0);
+ }
+ else
+ {
+ ::QueueUserAPC(apc_function, thread_, 0);
+ ::WaitForSingleObject(thread_, INFINITE);
+ }
+ }
+
+private:
+ friend unsigned int __stdcall win_thread_function(void* arg);
+
+#if (WINVER < 0x0500)
+ friend void __stdcall apc_function(ULONG);
+#else
+ friend void __stdcall apc_function(ULONG_PTR);
+#endif
+
+ class func_base
+ {
+ public:
+ virtual ~func_base() {}
+ virtual void run() = 0;
+ ::HANDLE entry_event_;
+ ::HANDLE exit_event_;
+ };
+
+ template <typename Function>
+ class func
+ : public func_base
+ {
+ public:
+ func(Function f)
+ : f_(f)
+ {
+ }
+
+ virtual void run()
+ {
+ f_();
+ }
+
+ private:
+ Function f_;
+ };
+
+ ::HANDLE thread_;
+ ::HANDLE exit_event_;
+};
+
+inline unsigned int __stdcall win_thread_function(void* arg)
+{
+ std::auto_ptr<win_thread::func_base> func(
+ static_cast<win_thread::func_base*>(arg));
+
+ ::SetEvent(func->entry_event_);
+
+ func->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->exit_event_;
+ func.reset();
+ ::SetEvent(exit_event);
+ ::SleepEx(INFINITE, TRUE);
+
+ return 0;
+}
+
+#if (WINVER < 0x0500)
+inline void __stdcall apc_function(ULONG) {}
+#else
+inline void __stdcall apc_function(ULONG_PTR) {}
+#endif
+
+} // namespace detail
+} // namespace asio
+} // namespace boost
+
+#endif // defined(BOOST_WINDOWS) && !defined(UNDER_CE)
+
+#include <boost/asio/detail/pop_options.hpp>
+
+#endif // BOOST_ASIO_DETAIL_WIN_THREAD_HPP
diff --git a/3rdParty/Boost/boost/asio/detail/win_tss_ptr.hpp b/3rdParty/Boost/boost/asio/detail/win_tss_ptr.hpp
new file mode 100644
index 0000000..5c56454
--- /dev/null
+++ b/3rdParty/Boost/boost/asio/detail/win_tss_ptr.hpp
@@ -0,0 +1,97 @@
+//
+// win_tss_ptr.hpp
+// ~~~~~~~~~~~~~~~
+//
+// Copyright (c) 2003-2008 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 BOOST_ASIO_DETAIL_WIN_TSS_PTR_HPP
+#define BOOST_ASIO_DETAIL_WIN_TSS_PTR_HPP
+
+#if defined(_MSC_VER) && (_MSC_VER >= 1200)
+# pragma once
+#endif // defined(_MSC_VER) && (_MSC_VER >= 1200)
+
+#include <boost/asio/detail/push_options.hpp>
+
+#include <boost/asio/detail/push_options.hpp>
+#include <boost/config.hpp>
+#include <boost/system/system_error.hpp>
+#include <boost/asio/detail/pop_options.hpp>
+
+#if defined(BOOST_WINDOWS)
+
+#include <boost/asio/error.hpp>
+#include <boost/asio/detail/noncopyable.hpp>
+#include <boost/asio/detail/socket_types.hpp>
+
+#include <boost/asio/detail/push_options.hpp>
+#include <boost/throw_exception.hpp>
+#include <boost/asio/detail/pop_options.hpp>
+
+namespace boost {
+namespace asio {
+namespace detail {
+
+template <typename T>
+class win_tss_ptr
+ : private noncopyable
+{
+public:
+#if defined(UNDER_CE)
+ enum { out_of_indexes = 0xFFFFFFFF };
+#else
+ enum { out_of_indexes = TLS_OUT_OF_INDEXES };
+#endif
+
+ // Constructor.
+ win_tss_ptr()
+ {
+ tss_key_ = ::TlsAlloc();
+ if (tss_key_ == out_of_indexes)
+ {
+ DWORD last_error = ::GetLastError();
+ boost::system::system_error e(
+ boost::system::error_code(last_error,
+ boost::asio::error::get_system_category()),
+ "tss");
+ boost::throw_exception(e);
+ }
+ }
+
+ // 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
+} // namespace boost
+
+#endif // defined(BOOST_WINDOWS)
+
+#include <boost/asio/detail/pop_options.hpp>
+
+#endif // BOOST_ASIO_DETAIL_WIN_TSS_PTR_HPP
diff --git a/3rdParty/Boost/boost/asio/detail/wince_thread.hpp b/3rdParty/Boost/boost/asio/detail/wince_thread.hpp
new file mode 100644
index 0000000..7b24ec2
--- /dev/null
+++ b/3rdParty/Boost/boost/asio/detail/wince_thread.hpp
@@ -0,0 +1,126 @@
+//
+// wince_thread.hpp
+// ~~~~~~~~~~~~~~~~
+//
+// Copyright (c) 2003-2008 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 BOOST_ASIO_DETAIL_WINCE_THREAD_HPP
+#define BOOST_ASIO_DETAIL_WINCE_THREAD_HPP
+
+#if defined(_MSC_VER) && (_MSC_VER >= 1200)
+# pragma once
+#endif // defined(_MSC_VER) && (_MSC_VER >= 1200)
+
+#include <boost/asio/detail/push_options.hpp>
+
+#include <boost/asio/detail/push_options.hpp>
+#include <boost/config.hpp>
+#include <boost/system/system_error.hpp>
+#include <boost/asio/detail/pop_options.hpp>
+
+#if defined(BOOST_WINDOWS) && defined(UNDER_CE)
+
+#include <boost/asio/error.hpp>
+#include <boost/asio/detail/noncopyable.hpp>
+#include <boost/asio/detail/socket_types.hpp>
+
+#include <boost/asio/detail/push_options.hpp>
+#include <boost/throw_exception.hpp>
+#include <memory>
+#include <boost/asio/detail/pop_options.hpp>
+
+namespace boost {
+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)
+ {
+ std::auto_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();
+ boost::system::system_error e(
+ boost::system::error_code(last_error,
+ boost::asio::error::get_system_category()),
+ "thread");
+ boost::throw_exception(e);
+ }
+ arg.release();
+ }
+
+ // Destructor.
+ ~wince_thread()
+ {
+ ::CloseHandle(thread_);
+ }
+
+ // Wait for the thread to exit.
+ void join()
+ {
+ ::WaitForSingleObject(thread_, INFINITE);
+ }
+
+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)
+{
+ std::auto_ptr<wince_thread::func_base> func(
+ static_cast<wince_thread::func_base*>(arg));
+ func->run();
+ return 0;
+}
+
+} // namespace detail
+} // namespace asio
+} // namespace boost
+
+#endif // defined(BOOST_WINDOWS) && defined(UNDER_CE)
+
+#include <boost/asio/detail/pop_options.hpp>
+
+#endif // BOOST_ASIO_DETAIL_WINCE_THREAD_HPP
diff --git a/3rdParty/Boost/boost/asio/detail/winsock_init.hpp b/3rdParty/Boost/boost/asio/detail/winsock_init.hpp
new file mode 100644
index 0000000..827cf58
--- /dev/null
+++ b/3rdParty/Boost/boost/asio/detail/winsock_init.hpp
@@ -0,0 +1,122 @@
+//
+// winsock_init.hpp
+// ~~~~~~~~~~~~~~~~
+//
+// Copyright (c) 2003-2008 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 BOOST_ASIO_DETAIL_WINSOCK_INIT_HPP
+#define BOOST_ASIO_DETAIL_WINSOCK_INIT_HPP
+
+#if defined(_MSC_VER) && (_MSC_VER >= 1200)
+# pragma once
+#endif // defined(_MSC_VER) && (_MSC_VER >= 1200)
+
+#include <boost/asio/detail/push_options.hpp>
+
+#include <boost/asio/detail/push_options.hpp>
+#include <boost/config.hpp>
+#include <boost/system/system_error.hpp>
+#include <boost/asio/detail/pop_options.hpp>
+
+#if defined(BOOST_WINDOWS) || defined(__CYGWIN__)
+
+#include <boost/asio/detail/push_options.hpp>
+#include <boost/shared_ptr.hpp>
+#include <boost/throw_exception.hpp>
+#include <boost/asio/detail/pop_options.hpp>
+
+#include <boost/asio/error.hpp>
+#include <boost/asio/detail/noncopyable.hpp>
+#include <boost/asio/detail/socket_types.hpp>
+
+namespace boost {
+namespace asio {
+namespace detail {
+
+template <int Major = 2, int Minor = 0>
+class winsock_init
+ : private noncopyable
+{
+private:
+ // Structure to perform the actual initialisation.
+ struct do_init
+ {
+ do_init()
+ {
+ WSADATA wsa_data;
+ result_ = ::WSAStartup(MAKEWORD(Major, Minor), &wsa_data);
+ }
+
+ ~do_init()
+ {
+ ::WSACleanup();
+ }
+
+ int result() const
+ {
+ return result_;
+ }
+
+ // Helper function to manage a do_init singleton. The static instance of the
+ // winsock_init object ensures that this function is always called before
+ // main, and therefore before any other threads can get started. The do_init
+ // instance must be static in this function to ensure that it gets
+ // initialised before any other global objects try to use it.
+ static boost::shared_ptr<do_init> instance()
+ {
+ static boost::shared_ptr<do_init> init(new do_init);
+ return init;
+ }
+
+ private:
+ int result_;
+ };
+
+public:
+ // Constructor.
+ winsock_init()
+ : ref_(do_init::instance())
+ {
+ // Check whether winsock was successfully initialised. This check is not
+ // performed for the global instance since there will be nobody around to
+ // catch the exception.
+ if (this != &instance_ && ref_->result() != 0)
+ {
+ boost::system::system_error e(
+ boost::system::error_code(ref_->result(),
+ boost::asio::error::get_system_category()),
+ "winsock");
+ boost::throw_exception(e);
+ }
+ }
+
+ // Destructor.
+ ~winsock_init()
+ {
+ }
+
+private:
+ // Instance to force initialisation of winsock at global scope.
+ static winsock_init instance_;
+
+ // Reference to singleton do_init object to ensure that winsock does not get
+ // cleaned up until the last user has finished with it.
+ boost::shared_ptr<do_init> ref_;
+};
+
+template <int Major, int Minor>
+winsock_init<Major, Minor> winsock_init<Major, Minor>::instance_;
+
+} // namespace detail
+} // namespace asio
+} // namespace boost
+
+#endif // defined(BOOST_WINDOWS) || defined(__CYGWIN__)
+
+#include <boost/asio/detail/pop_options.hpp>
+
+#endif // BOOST_ASIO_DETAIL_WINSOCK_INIT_HPP
diff --git a/3rdParty/Boost/boost/asio/detail/wrapped_handler.hpp b/3rdParty/Boost/boost/asio/detail/wrapped_handler.hpp
new file mode 100644
index 0000000..64fc729
--- /dev/null
+++ b/3rdParty/Boost/boost/asio/detail/wrapped_handler.hpp
@@ -0,0 +1,211 @@
+//
+// wrapped_handler.hpp
+// ~~~~~~~~~~~~~~~~~~~
+//
+// Copyright (c) 2003-2008 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 BOOST_ASIO_DETAIL_WRAPPED_HANDLER_HPP
+#define BOOST_ASIO_DETAIL_WRAPPED_HANDLER_HPP
+
+#if defined(_MSC_VER) && (_MSC_VER >= 1200)
+# pragma once
+#endif // defined(_MSC_VER) && (_MSC_VER >= 1200)
+
+#include <boost/asio/detail/push_options.hpp>
+
+#include <boost/asio/detail/push_options.hpp>
+#include <boost/type_traits.hpp>
+#include <boost/asio/detail/pop_options.hpp>
+
+#include <boost/asio/detail/bind_handler.hpp>
+#include <boost/asio/detail/handler_alloc_helpers.hpp>
+#include <boost/asio/detail/handler_invoke_helpers.hpp>
+
+namespace boost {
+namespace asio {
+namespace detail {
+
+template <typename Dispatcher, typename Handler>
+class wrapped_handler
+{
+public:
+ typedef void result_type;
+
+ wrapped_handler(
+ typename boost::add_reference<Dispatcher>::type dispatcher,
+ Handler handler)
+ : dispatcher_(dispatcher),
+ handler_(handler)
+ {
+ }
+
+ void operator()()
+ {
+ dispatcher_.dispatch(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(const Handler& handler, const Context& context)
+ : handler_(handler),
+ context_(context)
+ {
+ }
+
+ void operator()()
+ {
+ handler_();
+ }
+
+ void operator()() const
+ {
+ handler_();
+ }
+
+//private:
+ Handler handler_;
+ Context context_;
+};
+
+template <typename Dispatcher, typename Handler>
+inline void* asio_handler_allocate(std::size_t size,
+ wrapped_handler<Dispatcher, Handler>* this_handler)
+{
+ return boost_asio_handler_alloc_helpers::allocate(
+ size, &this_handler->handler_);
+}
+
+template <typename Dispatcher, typename Handler>
+inline void asio_handler_deallocate(void* pointer, std::size_t size,
+ wrapped_handler<Dispatcher, Handler>* this_handler)
+{
+ boost_asio_handler_alloc_helpers::deallocate(
+ pointer, size, &this_handler->handler_);
+}
+
+template <typename Function, typename Dispatcher, typename Handler>
+inline void asio_handler_invoke(const Function& function,
+ wrapped_handler<Dispatcher, Handler>* 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 boost_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)
+{
+ boost_asio_handler_alloc_helpers::deallocate(
+ pointer, size, &this_handler->context_);
+}
+
+template <typename Function, typename Handler, typename Context>
+inline void asio_handler_invoke(const Function& function,
+ rewrapped_handler<Handler, Context>* this_handler)
+{
+ boost_asio_handler_invoke_helpers::invoke(
+ function, &this_handler->context_);
+}
+
+} // namespace detail
+} // namespace asio
+} // namespace boost
+
+#include <boost/asio/detail/pop_options.hpp>
+
+#endif // BOOST_ASIO_DETAIL_WRAPPED_HANDLER_HPP