2 // win_iocp_socket_service.hpp
3 // ~~~~~~~~~~~~~~~~~~~~~~~~~~~
5 // Copyright (c) 2003-2008 Christopher M. Kohlhoff (chris at kohlhoff dot com)
7 // Distributed under the Boost Software License, Version 1.0. (See accompanying
8 // file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt)
11 #ifndef BOOST_ASIO_DETAIL_WIN_IOCP_SOCKET_SERVICE_HPP
12 #define BOOST_ASIO_DETAIL_WIN_IOCP_SOCKET_SERVICE_HPP
14 #if defined(_MSC_VER) && (_MSC_VER >= 1200)
16 #endif // defined(_MSC_VER) && (_MSC_VER >= 1200)
18 #include <boost/asio/detail/push_options.hpp>
20 #include <boost/asio/detail/win_iocp_io_service_fwd.hpp>
22 #if defined(BOOST_ASIO_HAS_IOCP)
24 #include <boost/asio/detail/push_options.hpp>
26 #include <boost/shared_ptr.hpp>
27 #include <boost/type_traits/is_same.hpp>
28 #include <boost/weak_ptr.hpp>
29 #include <boost/asio/detail/pop_options.hpp>
31 #include <boost/asio/buffer.hpp>
32 #include <boost/asio/error.hpp>
33 #include <boost/asio/io_service.hpp>
34 #include <boost/asio/socket_base.hpp>
35 #include <boost/asio/detail/bind_handler.hpp>
36 #include <boost/asio/detail/handler_alloc_helpers.hpp>
37 #include <boost/asio/detail/handler_invoke_helpers.hpp>
38 #include <boost/asio/detail/mutex.hpp>
39 #include <boost/asio/detail/select_reactor.hpp>
40 #include <boost/asio/detail/socket_holder.hpp>
41 #include <boost/asio/detail/socket_ops.hpp>
42 #include <boost/asio/detail/socket_types.hpp>
43 #include <boost/asio/detail/win_iocp_io_service.hpp>
49 template <typename Protocol
>
50 class win_iocp_socket_service
51 : public boost::asio::detail::service_base
<win_iocp_socket_service
<Protocol
> >
55 typedef Protocol protocol_type
;
58 typedef typename
Protocol::endpoint endpoint_type
;
60 // Base class for all operations.
61 typedef win_iocp_io_service::operation operation
;
63 struct noop_deleter
{ void operator()(void*) {} };
64 typedef boost::shared_ptr
<void> shared_cancel_token_type
;
65 typedef boost::weak_ptr
<void> weak_cancel_token_type
;
67 // The native type of a socket.
71 native_type(socket_type s
)
73 have_remote_endpoint_(false)
77 native_type(socket_type s
, const endpoint_type
& ep
)
79 have_remote_endpoint_(true),
84 void operator=(socket_type s
)
87 have_remote_endpoint_
= false;
88 remote_endpoint_
= endpoint_type();
91 operator socket_type() const
96 HANDLE
as_handle() const
98 return reinterpret_cast<HANDLE
>(socket_
);
101 bool have_remote_endpoint() const
103 return have_remote_endpoint_
;
106 endpoint_type
remote_endpoint() const
108 return remote_endpoint_
;
113 bool have_remote_endpoint_
;
114 endpoint_type remote_endpoint_
;
117 // The type of the reactor used for connect operations.
118 typedef detail::select_reactor
<true> reactor_type
;
120 // The implementation type of the socket.
121 class implementation_type
124 // Default constructor.
125 implementation_type()
126 : socket_(invalid_socket
),
129 protocol_(endpoint_type().protocol()),
136 // Only this service will have access to the internal values.
137 friend class win_iocp_socket_service
;
139 // The native socket representation.
144 enable_connection_aborted
= 1, // User wants connection_aborted errors.
145 close_might_block
= 2, // User set linger option for blocking close.
146 user_set_non_blocking
= 4 // The user wants a non-blocking socket.
149 // Flags indicating the current state of the socket.
150 unsigned char flags_
;
152 // We use a shared pointer as a cancellation token here to work around the
153 // broken Windows support for cancellation. MSDN says that when you call
154 // closesocket any outstanding WSARecv or WSASend operations will complete
155 // with the error ERROR_OPERATION_ABORTED. In practice they complete with
156 // ERROR_NETNAME_DELETED, which means you can't tell the difference between
157 // a local cancellation and the socket being hard-closed by the peer.
158 shared_cancel_token_type cancel_token_
;
160 // The protocol associated with the socket.
161 protocol_type protocol_
;
163 // Per-descriptor data used by the reactor.
164 reactor_type::per_descriptor_data reactor_data_
;
166 #if defined(BOOST_ASIO_ENABLE_CANCELIO)
167 // The ID of the thread from which it is safe to cancel asynchronous
168 // operations. 0 means no asynchronous operations have been started yet.
169 // ~0 means asynchronous operations have been started from more than one
170 // thread, and cancellation is not supported for the socket.
171 DWORD safe_cancellation_thread_id_
;
172 #endif // defined(BOOST_ASIO_ENABLE_CANCELIO)
174 // Pointers to adjacent socket implementations in linked list.
175 implementation_type
* next_
;
176 implementation_type
* prev_
;
179 // The maximum number of buffers to support in a single operation.
180 enum { max_buffers
= 64 < max_iov_len
? 64 : max_iov_len
};
183 win_iocp_socket_service(boost::asio::io_service
& io_service
)
184 : boost::asio::detail::service_base
<
185 win_iocp_socket_service
<Protocol
> >(io_service
),
186 iocp_service_(boost::asio::use_service
<win_iocp_io_service
>(io_service
)),
193 // Destroy all user-defined handler objects owned by the service.
194 void shutdown_service()
196 // Close all implementations, causing all operations to complete.
197 boost::asio::detail::mutex::scoped_lock
lock(mutex_
);
198 implementation_type
* impl
= impl_list_
;
201 boost::system::error_code ignored_ec
;
202 close_for_destruction(*impl
);
207 // Construct a new socket implementation.
208 void construct(implementation_type
& impl
)
210 impl
.socket_
= invalid_socket
;
212 impl
.cancel_token_
.reset();
213 #if defined(BOOST_ASIO_ENABLE_CANCELIO)
214 impl
.safe_cancellation_thread_id_
= 0;
215 #endif // defined(BOOST_ASIO_ENABLE_CANCELIO)
217 // Insert implementation into linked list of all implementations.
218 boost::asio::detail::mutex::scoped_lock
lock(mutex_
);
219 impl
.next_
= impl_list_
;
222 impl_list_
->prev_
= &impl
;
226 // Destroy a socket implementation.
227 void destroy(implementation_type
& impl
)
229 close_for_destruction(impl
);
231 // Remove implementation from linked list of all implementations.
232 boost::asio::detail::mutex::scoped_lock
lock(mutex_
);
233 if (impl_list_
== &impl
)
234 impl_list_
= impl
.next_
;
236 impl
.prev_
->next_
= impl
.next_
;
238 impl
.next_
->prev_
= impl
.prev_
;
243 // Open a new socket implementation.
244 boost::system::error_code
open(implementation_type
& impl
,
245 const protocol_type
& protocol
, boost::system::error_code
& ec
)
249 ec
= boost::asio::error::already_open
;
253 socket_holder
sock(socket_ops::socket(protocol
.family(), protocol
.type(),
254 protocol
.protocol(), ec
));
255 if (sock
.get() == invalid_socket
)
258 HANDLE sock_as_handle
= reinterpret_cast<HANDLE
>(sock
.get());
259 if (iocp_service_
.register_handle(sock_as_handle
, ec
))
262 impl
.socket_
= sock
.release();
264 impl
.cancel_token_
.reset(static_cast<void*>(0), noop_deleter());
265 impl
.protocol_
= protocol
;
266 ec
= boost::system::error_code();
270 // Assign a native socket to a socket implementation.
271 boost::system::error_code
assign(implementation_type
& impl
,
272 const protocol_type
& protocol
, const native_type
& native_socket
,
273 boost::system::error_code
& ec
)
277 ec
= boost::asio::error::already_open
;
281 if (iocp_service_
.register_handle(native_socket
.as_handle(), ec
))
284 impl
.socket_
= native_socket
;
286 impl
.cancel_token_
.reset(static_cast<void*>(0), noop_deleter());
287 impl
.protocol_
= protocol
;
288 ec
= boost::system::error_code();
292 // Determine whether the socket is open.
293 bool is_open(const implementation_type
& impl
) const
295 return impl
.socket_
!= invalid_socket
;
298 // Destroy a socket implementation.
299 boost::system::error_code
close(implementation_type
& impl
,
300 boost::system::error_code
& ec
)
304 // Check if the reactor was created, in which case we need to close the
305 // socket on the reactor as well to cancel any operations that might be
307 reactor_type
* reactor
= static_cast<reactor_type
*>(
308 interlocked_compare_exchange_pointer(
309 reinterpret_cast<void**>(&reactor_
), 0, 0));
311 reactor
->close_descriptor(impl
.socket_
, impl
.reactor_data_
);
313 if (socket_ops::close(impl
.socket_
, ec
) == socket_error_retval
)
316 impl
.socket_
= invalid_socket
;
318 impl
.cancel_token_
.reset();
319 #if defined(BOOST_ASIO_ENABLE_CANCELIO)
320 impl
.safe_cancellation_thread_id_
= 0;
321 #endif // defined(BOOST_ASIO_ENABLE_CANCELIO)
324 ec
= boost::system::error_code();
328 // Get the native socket representation.
329 native_type
native(implementation_type
& impl
)
334 // Cancel all operations associated with the socket.
335 boost::system::error_code
cancel(implementation_type
& impl
,
336 boost::system::error_code
& ec
)
340 ec
= boost::asio::error::bad_descriptor
;
343 else if (FARPROC cancel_io_ex_ptr
= ::GetProcAddress(
344 ::GetModuleHandleA("KERNEL32"), "CancelIoEx"))
346 // The version of Windows supports cancellation from any thread.
347 typedef BOOL (WINAPI
* cancel_io_ex_t
)(HANDLE
, LPOVERLAPPED
);
348 cancel_io_ex_t cancel_io_ex
= (cancel_io_ex_t
)cancel_io_ex_ptr
;
349 socket_type sock
= impl
.socket_
;
350 HANDLE sock_as_handle
= reinterpret_cast<HANDLE
>(sock
);
351 if (!cancel_io_ex(sock_as_handle
, 0))
353 DWORD last_error
= ::GetLastError();
354 if (last_error
== ERROR_NOT_FOUND
)
356 // ERROR_NOT_FOUND means that there were no operations to be
357 // cancelled. We swallow this error to match the behaviour on other
359 ec
= boost::system::error_code();
363 ec
= boost::system::error_code(last_error
,
364 boost::asio::error::get_system_category());
369 ec
= boost::system::error_code();
372 #if defined(BOOST_ASIO_ENABLE_CANCELIO)
373 else if (impl
.safe_cancellation_thread_id_
== 0)
375 // No operations have been started, so there's nothing to cancel.
376 ec
= boost::system::error_code();
378 else if (impl
.safe_cancellation_thread_id_
== ::GetCurrentThreadId())
380 // Asynchronous operations have been started from the current thread only,
381 // so it is safe to try to cancel them using CancelIo.
382 socket_type sock
= impl
.socket_
;
383 HANDLE sock_as_handle
= reinterpret_cast<HANDLE
>(sock
);
384 if (!::CancelIo(sock_as_handle
))
386 DWORD last_error
= ::GetLastError();
387 ec
= boost::system::error_code(last_error
,
388 boost::asio::error::get_system_category());
392 ec
= boost::system::error_code();
397 // Asynchronous operations have been started from more than one thread,
398 // so cancellation is not safe.
399 ec
= boost::asio::error::operation_not_supported
;
401 #else // defined(BOOST_ASIO_ENABLE_CANCELIO)
404 // Cancellation is not supported as CancelIo may not be used.
405 ec
= boost::asio::error::operation_not_supported
;
407 #endif // defined(BOOST_ASIO_ENABLE_CANCELIO)
412 // Determine whether the socket is at the out-of-band data mark.
413 bool at_mark(const implementation_type
& impl
,
414 boost::system::error_code
& ec
) const
418 ec
= boost::asio::error::bad_descriptor
;
422 boost::asio::detail::ioctl_arg_type value
= 0;
423 socket_ops::ioctl(impl
.socket_
, SIOCATMARK
, &value
, ec
);
424 return ec
? false : value
!= 0;
427 // Determine the number of bytes available for reading.
428 std::size_t available(const implementation_type
& impl
,
429 boost::system::error_code
& ec
) const
433 ec
= boost::asio::error::bad_descriptor
;
437 boost::asio::detail::ioctl_arg_type value
= 0;
438 socket_ops::ioctl(impl
.socket_
, FIONREAD
, &value
, ec
);
439 return ec
? static_cast<std::size_t>(0) : static_cast<std::size_t>(value
);
442 // Bind the socket to the specified local endpoint.
443 boost::system::error_code
bind(implementation_type
& impl
,
444 const endpoint_type
& endpoint
, boost::system::error_code
& ec
)
448 ec
= boost::asio::error::bad_descriptor
;
452 socket_ops::bind(impl
.socket_
, endpoint
.data(), endpoint
.size(), ec
);
456 // Place the socket into the state where it will listen for new connections.
457 boost::system::error_code
listen(implementation_type
& impl
, int backlog
,
458 boost::system::error_code
& ec
)
462 ec
= boost::asio::error::bad_descriptor
;
466 socket_ops::listen(impl
.socket_
, backlog
, ec
);
470 // Set a socket option.
471 template <typename Option
>
472 boost::system::error_code
set_option(implementation_type
& impl
,
473 const Option
& option
, boost::system::error_code
& ec
)
477 ec
= boost::asio::error::bad_descriptor
;
481 if (option
.level(impl
.protocol_
) == custom_socket_option_level
482 && option
.name(impl
.protocol_
) == enable_connection_aborted_option
)
484 if (option
.size(impl
.protocol_
) != sizeof(int))
486 ec
= boost::asio::error::invalid_argument
;
490 if (*reinterpret_cast<const int*>(option
.data(impl
.protocol_
)))
491 impl
.flags_
|= implementation_type::enable_connection_aborted
;
493 impl
.flags_
&= ~implementation_type::enable_connection_aborted
;
494 ec
= boost::system::error_code();
500 if (option
.level(impl
.protocol_
) == SOL_SOCKET
501 && option
.name(impl
.protocol_
) == SO_LINGER
)
503 const ::linger
* linger_option
=
504 reinterpret_cast<const ::linger
*>(option
.data(impl
.protocol_
));
505 if (linger_option
->l_onoff
!= 0 && linger_option
->l_linger
!= 0)
506 impl
.flags_
|= implementation_type::close_might_block
;
508 impl
.flags_
&= ~implementation_type::close_might_block
;
511 socket_ops::setsockopt(impl
.socket_
,
512 option
.level(impl
.protocol_
), option
.name(impl
.protocol_
),
513 option
.data(impl
.protocol_
), option
.size(impl
.protocol_
), ec
);
518 // Set a socket option.
519 template <typename Option
>
520 boost::system::error_code
get_option(const implementation_type
& impl
,
521 Option
& option
, boost::system::error_code
& ec
) const
525 ec
= boost::asio::error::bad_descriptor
;
529 if (option
.level(impl
.protocol_
) == custom_socket_option_level
530 && option
.name(impl
.protocol_
) == enable_connection_aborted_option
)
532 if (option
.size(impl
.protocol_
) != sizeof(int))
534 ec
= boost::asio::error::invalid_argument
;
538 int* target
= reinterpret_cast<int*>(option
.data(impl
.protocol_
));
539 if (impl
.flags_
& implementation_type::enable_connection_aborted
)
543 option
.resize(impl
.protocol_
, sizeof(int));
544 ec
= boost::system::error_code();
550 size_t size
= option
.size(impl
.protocol_
);
551 socket_ops::getsockopt(impl
.socket_
,
552 option
.level(impl
.protocol_
), option
.name(impl
.protocol_
),
553 option
.data(impl
.protocol_
), &size
, ec
);
555 option
.resize(impl
.protocol_
, size
);
560 // Perform an IO control command on the socket.
561 template <typename IO_Control_Command
>
562 boost::system::error_code
io_control(implementation_type
& impl
,
563 IO_Control_Command
& command
, boost::system::error_code
& ec
)
567 ec
= boost::asio::error::bad_descriptor
;
571 socket_ops::ioctl(impl
.socket_
, command
.name(),
572 static_cast<ioctl_arg_type
*>(command
.data()), ec
);
574 if (!ec
&& command
.name() == static_cast<int>(FIONBIO
))
576 if (*static_cast<ioctl_arg_type
*>(command
.data()))
577 impl
.flags_
|= implementation_type::user_set_non_blocking
;
579 impl
.flags_
&= ~implementation_type::user_set_non_blocking
;
585 // Get the local endpoint.
586 endpoint_type
local_endpoint(const implementation_type
& impl
,
587 boost::system::error_code
& ec
) const
591 ec
= boost::asio::error::bad_descriptor
;
592 return endpoint_type();
595 endpoint_type endpoint
;
596 std::size_t addr_len
= endpoint
.capacity();
597 if (socket_ops::getsockname(impl
.socket_
, endpoint
.data(), &addr_len
, ec
))
598 return endpoint_type();
599 endpoint
.resize(addr_len
);
603 // Get the remote endpoint.
604 endpoint_type
remote_endpoint(const implementation_type
& impl
,
605 boost::system::error_code
& ec
) const
609 ec
= boost::asio::error::bad_descriptor
;
610 return endpoint_type();
613 if (impl
.socket_
.have_remote_endpoint())
615 // Check if socket is still connected.
616 DWORD connect_time
= 0;
617 size_t connect_time_len
= sizeof(connect_time
);
618 if (socket_ops::getsockopt(impl
.socket_
, SOL_SOCKET
, SO_CONNECT_TIME
,
619 &connect_time
, &connect_time_len
, ec
) == socket_error_retval
)
621 return endpoint_type();
623 if (connect_time
== 0xFFFFFFFF)
625 ec
= boost::asio::error::not_connected
;
626 return endpoint_type();
629 ec
= boost::system::error_code();
630 return impl
.socket_
.remote_endpoint();
634 endpoint_type endpoint
;
635 std::size_t addr_len
= endpoint
.capacity();
636 if (socket_ops::getpeername(impl
.socket_
, endpoint
.data(), &addr_len
, ec
))
637 return endpoint_type();
638 endpoint
.resize(addr_len
);
643 /// Disable sends or receives on the socket.
644 boost::system::error_code
shutdown(implementation_type
& impl
,
645 socket_base::shutdown_type what
, boost::system::error_code
& ec
)
649 ec
= boost::asio::error::bad_descriptor
;
653 socket_ops::shutdown(impl
.socket_
, what
, ec
);
657 // Send the given data to the peer. Returns the number of bytes sent.
658 template <typename ConstBufferSequence
>
659 size_t send(implementation_type
& impl
, const ConstBufferSequence
& buffers
,
660 socket_base::message_flags flags
, boost::system::error_code
& ec
)
664 ec
= boost::asio::error::bad_descriptor
;
668 // Copy buffers into WSABUF array.
669 ::WSABUF bufs
[max_buffers
];
670 typename
ConstBufferSequence::const_iterator iter
= buffers
.begin();
671 typename
ConstBufferSequence::const_iterator end
= buffers
.end();
673 size_t total_buffer_size
= 0;
674 for (; iter
!= end
&& i
< max_buffers
; ++iter
, ++i
)
676 boost::asio::const_buffer
buffer(*iter
);
677 bufs
[i
].len
= static_cast<u_long
>(boost::asio::buffer_size(buffer
));
678 bufs
[i
].buf
= const_cast<char*>(
679 boost::asio::buffer_cast
<const char*>(buffer
));
680 total_buffer_size
+= boost::asio::buffer_size(buffer
);
683 // A request to receive 0 bytes on a stream socket is a no-op.
684 if (impl
.protocol_
.type() == SOCK_STREAM
&& total_buffer_size
== 0)
686 ec
= boost::system::error_code();
691 DWORD bytes_transferred
= 0;
692 int result
= ::WSASend(impl
.socket_
, bufs
,
693 i
, &bytes_transferred
, flags
, 0, 0);
696 DWORD last_error
= ::WSAGetLastError();
697 if (last_error
== ERROR_NETNAME_DELETED
)
698 last_error
= WSAECONNRESET
;
699 else if (last_error
== ERROR_PORT_UNREACHABLE
)
700 last_error
= WSAECONNREFUSED
;
701 ec
= boost::system::error_code(last_error
,
702 boost::asio::error::get_system_category());
706 ec
= boost::system::error_code();
707 return bytes_transferred
;
710 // Wait until data can be sent without blocking.
711 size_t send(implementation_type
& impl
, const null_buffers
&,
712 socket_base::message_flags
, boost::system::error_code
& ec
)
716 ec
= boost::asio::error::bad_descriptor
;
720 // Wait for socket to become ready.
721 socket_ops::poll_write(impl
.socket_
, ec
);
726 template <typename ConstBufferSequence
, typename Handler
>
731 send_operation(win_iocp_io_service
& io_service
,
732 weak_cancel_token_type cancel_token
,
733 const ConstBufferSequence
& buffers
, Handler handler
)
734 : operation(io_service
,
735 &send_operation
<ConstBufferSequence
, Handler
>::do_completion_impl
,
736 &send_operation
<ConstBufferSequence
, Handler
>::destroy_impl
),
737 work_(io_service
.get_io_service()),
738 cancel_token_(cancel_token
),
745 static void do_completion_impl(operation
* op
,
746 DWORD last_error
, size_t bytes_transferred
)
748 // Take ownership of the operation object.
749 typedef send_operation
<ConstBufferSequence
, Handler
> op_type
;
750 op_type
* handler_op(static_cast<op_type
*>(op
));
751 typedef handler_alloc_traits
<Handler
, op_type
> alloc_traits
;
752 handler_ptr
<alloc_traits
> ptr(handler_op
->handler_
, handler_op
);
754 #if defined(BOOST_ASIO_ENABLE_BUFFER_DEBUGGING)
755 // Check whether buffers are still valid.
756 typename
ConstBufferSequence::const_iterator iter
757 = handler_op
->buffers_
.begin();
758 typename
ConstBufferSequence::const_iterator end
759 = handler_op
->buffers_
.end();
762 boost::asio::const_buffer
buffer(*iter
);
763 boost::asio::buffer_cast
<const char*>(buffer
);
766 #endif // defined(BOOST_ASIO_ENABLE_BUFFER_DEBUGGING)
768 // Map non-portable errors to their portable counterparts.
769 boost::system::error_code
ec(last_error
,
770 boost::asio::error::get_system_category());
771 if (ec
.value() == ERROR_NETNAME_DELETED
)
773 if (handler_op
->cancel_token_
.expired())
774 ec
= boost::asio::error::operation_aborted
;
776 ec
= boost::asio::error::connection_reset
;
778 else if (ec
.value() == ERROR_PORT_UNREACHABLE
)
780 ec
= boost::asio::error::connection_refused
;
783 // Make a copy of the handler so that the memory can be deallocated before
784 // the upcall is made.
785 Handler
handler(handler_op
->handler_
);
787 // Free the memory associated with the handler.
791 boost_asio_handler_invoke_helpers::invoke(
792 detail::bind_handler(handler
, ec
, bytes_transferred
), &handler
);
795 static void destroy_impl(operation
* op
)
797 // Take ownership of the operation object.
798 typedef send_operation
<ConstBufferSequence
, Handler
> op_type
;
799 op_type
* handler_op(static_cast<op_type
*>(op
));
800 typedef handler_alloc_traits
<Handler
, op_type
> alloc_traits
;
801 handler_ptr
<alloc_traits
> ptr(handler_op
->handler_
, handler_op
);
803 // A sub-object of the handler may be the true owner of the memory
804 // associated with the handler. Consequently, a local copy of the handler
805 // is required to ensure that any owning sub-object remains valid until
806 // after we have deallocated the memory here.
807 Handler
handler(handler_op
->handler_
);
810 // Free the memory associated with the handler.
814 boost::asio::io_service::work work_
;
815 weak_cancel_token_type cancel_token_
;
816 ConstBufferSequence buffers_
;
820 // Start an asynchronous send. The data being sent must be valid for the
821 // lifetime of the asynchronous operation.
822 template <typename ConstBufferSequence
, typename Handler
>
823 void async_send(implementation_type
& impl
, const ConstBufferSequence
& buffers
,
824 socket_base::message_flags flags
, Handler handler
)
828 this->get_io_service().post(bind_handler(handler
,
829 boost::asio::error::bad_descriptor
, 0));
833 #if defined(BOOST_ASIO_ENABLE_CANCELIO)
834 // Update the ID of the thread from which cancellation is safe.
835 if (impl
.safe_cancellation_thread_id_
== 0)
836 impl
.safe_cancellation_thread_id_
= ::GetCurrentThreadId();
837 else if (impl
.safe_cancellation_thread_id_
!= ::GetCurrentThreadId())
838 impl
.safe_cancellation_thread_id_
= ~DWORD(0);
839 #endif // defined(BOOST_ASIO_ENABLE_CANCELIO)
841 // Allocate and construct an operation to wrap the handler.
842 typedef send_operation
<ConstBufferSequence
, Handler
> value_type
;
843 typedef handler_alloc_traits
<Handler
, value_type
> alloc_traits
;
844 raw_handler_ptr
<alloc_traits
> raw_ptr(handler
);
845 handler_ptr
<alloc_traits
> ptr(raw_ptr
, iocp_service_
,
846 impl
.cancel_token_
, buffers
, handler
);
848 // Copy buffers into WSABUF array.
849 ::WSABUF bufs
[max_buffers
];
850 typename
ConstBufferSequence::const_iterator iter
= buffers
.begin();
851 typename
ConstBufferSequence::const_iterator end
= buffers
.end();
853 size_t total_buffer_size
= 0;
854 for (; iter
!= end
&& i
< max_buffers
; ++iter
, ++i
)
856 boost::asio::const_buffer
buffer(*iter
);
857 bufs
[i
].len
= static_cast<u_long
>(boost::asio::buffer_size(buffer
));
858 bufs
[i
].buf
= const_cast<char*>(
859 boost::asio::buffer_cast
<const char*>(buffer
));
860 total_buffer_size
+= boost::asio::buffer_size(buffer
);
863 // A request to receive 0 bytes on a stream socket is a no-op.
864 if (impl
.protocol_
.type() == SOCK_STREAM
&& total_buffer_size
== 0)
866 boost::asio::io_service::work
work(this->get_io_service());
868 boost::system::error_code error
;
869 iocp_service_
.post(bind_handler(handler
, error
, 0));
874 DWORD bytes_transferred
= 0;
875 int result
= ::WSASend(impl
.socket_
, bufs
, i
,
876 &bytes_transferred
, flags
, ptr
.get(), 0);
877 DWORD last_error
= ::WSAGetLastError();
879 // Check if the operation completed immediately.
880 if (result
!= 0 && last_error
!= WSA_IO_PENDING
)
882 boost::asio::io_service::work
work(this->get_io_service());
884 boost::system::error_code
ec(last_error
,
885 boost::asio::error::get_system_category());
886 iocp_service_
.post(bind_handler(handler
, ec
, bytes_transferred
));
894 template <typename Handler
>
895 class null_buffers_operation
898 null_buffers_operation(boost::asio::io_service
& io_service
, Handler handler
)
904 bool perform(boost::system::error_code
&,
905 std::size_t& bytes_transferred
)
907 bytes_transferred
= 0;
911 void complete(const boost::system::error_code
& ec
,
912 std::size_t bytes_transferred
)
914 work_
.get_io_service().post(bind_handler(
915 handler_
, ec
, bytes_transferred
));
919 boost::asio::io_service::work work_
;
923 // Start an asynchronous wait until data can be sent without blocking.
924 template <typename Handler
>
925 void async_send(implementation_type
& impl
, const null_buffers
&,
926 socket_base::message_flags
, Handler handler
)
930 this->get_io_service().post(bind_handler(handler
,
931 boost::asio::error::bad_descriptor
, 0));
935 // Check if the reactor was already obtained from the io_service.
936 reactor_type
* reactor
= static_cast<reactor_type
*>(
937 interlocked_compare_exchange_pointer(
938 reinterpret_cast<void**>(&reactor_
), 0, 0));
941 reactor
= &(boost::asio::use_service
<reactor_type
>(
942 this->get_io_service()));
943 interlocked_exchange_pointer(
944 reinterpret_cast<void**>(&reactor_
), reactor
);
947 reactor
->start_write_op(impl
.socket_
, impl
.reactor_data_
,
948 null_buffers_operation
<Handler
>(this->get_io_service(), handler
),
953 // Send a datagram to the specified endpoint. Returns the number of bytes
955 template <typename ConstBufferSequence
>
956 size_t send_to(implementation_type
& impl
, const ConstBufferSequence
& buffers
,
957 const endpoint_type
& destination
, socket_base::message_flags flags
,
958 boost::system::error_code
& ec
)
962 ec
= boost::asio::error::bad_descriptor
;
966 // Copy buffers into WSABUF array.
967 ::WSABUF bufs
[max_buffers
];
968 typename
ConstBufferSequence::const_iterator iter
= buffers
.begin();
969 typename
ConstBufferSequence::const_iterator end
= buffers
.end();
971 for (; iter
!= end
&& i
< max_buffers
; ++iter
, ++i
)
973 boost::asio::const_buffer
buffer(*iter
);
974 bufs
[i
].len
= static_cast<u_long
>(boost::asio::buffer_size(buffer
));
975 bufs
[i
].buf
= const_cast<char*>(
976 boost::asio::buffer_cast
<const char*>(buffer
));
980 DWORD bytes_transferred
= 0;
981 int result
= ::WSASendTo(impl
.socket_
, bufs
, i
, &bytes_transferred
,
982 flags
, destination
.data(), static_cast<int>(destination
.size()), 0, 0);
985 DWORD last_error
= ::WSAGetLastError();
986 if (last_error
== ERROR_PORT_UNREACHABLE
)
987 last_error
= WSAECONNREFUSED
;
988 ec
= boost::system::error_code(last_error
,
989 boost::asio::error::get_system_category());
993 ec
= boost::system::error_code();
994 return bytes_transferred
;
997 // Wait until data can be sent without blocking.
998 size_t send_to(implementation_type
& impl
, const null_buffers
&,
999 socket_base::message_flags
, const endpoint_type
&,
1000 boost::system::error_code
& ec
)
1004 ec
= boost::asio::error::bad_descriptor
;
1008 // Wait for socket to become ready.
1009 socket_ops::poll_write(impl
.socket_
, ec
);
1014 template <typename ConstBufferSequence
, typename Handler
>
1015 class send_to_operation
1019 send_to_operation(win_iocp_io_service
& io_service
,
1020 const ConstBufferSequence
& buffers
, Handler handler
)
1021 : operation(io_service
,
1022 &send_to_operation
<ConstBufferSequence
, Handler
>::do_completion_impl
,
1023 &send_to_operation
<ConstBufferSequence
, Handler
>::destroy_impl
),
1024 work_(io_service
.get_io_service()),
1031 static void do_completion_impl(operation
* op
,
1032 DWORD last_error
, size_t bytes_transferred
)
1034 // Take ownership of the operation object.
1035 typedef send_to_operation
<ConstBufferSequence
, Handler
> op_type
;
1036 op_type
* handler_op(static_cast<op_type
*>(op
));
1037 typedef handler_alloc_traits
<Handler
, op_type
> alloc_traits
;
1038 handler_ptr
<alloc_traits
> ptr(handler_op
->handler_
, handler_op
);
1040 #if defined(BOOST_ASIO_ENABLE_BUFFER_DEBUGGING)
1041 // Check whether buffers are still valid.
1042 typename
ConstBufferSequence::const_iterator iter
1043 = handler_op
->buffers_
.begin();
1044 typename
ConstBufferSequence::const_iterator end
1045 = handler_op
->buffers_
.end();
1048 boost::asio::const_buffer
buffer(*iter
);
1049 boost::asio::buffer_cast
<const char*>(buffer
);
1052 #endif // defined(BOOST_ASIO_ENABLE_BUFFER_DEBUGGING)
1054 // Map non-portable errors to their portable counterparts.
1055 boost::system::error_code
ec(last_error
,
1056 boost::asio::error::get_system_category());
1057 if (ec
.value() == ERROR_PORT_UNREACHABLE
)
1059 ec
= boost::asio::error::connection_refused
;
1062 // Make a copy of the handler so that the memory can be deallocated before
1063 // the upcall is made.
1064 Handler
handler(handler_op
->handler_
);
1066 // Free the memory associated with the handler.
1069 // Call the handler.
1070 boost_asio_handler_invoke_helpers::invoke(
1071 detail::bind_handler(handler
, ec
, bytes_transferred
), &handler
);
1074 static void destroy_impl(operation
* op
)
1076 // Take ownership of the operation object.
1077 typedef send_to_operation
<ConstBufferSequence
, Handler
> op_type
;
1078 op_type
* handler_op(static_cast<op_type
*>(op
));
1079 typedef handler_alloc_traits
<Handler
, op_type
> alloc_traits
;
1080 handler_ptr
<alloc_traits
> ptr(handler_op
->handler_
, handler_op
);
1082 // A sub-object of the handler may be the true owner of the memory
1083 // associated with the handler. Consequently, a local copy of the handler
1084 // is required to ensure that any owning sub-object remains valid until
1085 // after we have deallocated the memory here.
1086 Handler
handler(handler_op
->handler_
);
1089 // Free the memory associated with the handler.
1093 boost::asio::io_service::work work_
;
1094 ConstBufferSequence buffers_
;
1098 // Start an asynchronous send. The data being sent must be valid for the
1099 // lifetime of the asynchronous operation.
1100 template <typename ConstBufferSequence
, typename Handler
>
1101 void async_send_to(implementation_type
& impl
,
1102 const ConstBufferSequence
& buffers
, const endpoint_type
& destination
,
1103 socket_base::message_flags flags
, Handler handler
)
1107 this->get_io_service().post(bind_handler(handler
,
1108 boost::asio::error::bad_descriptor
, 0));
1112 #if defined(BOOST_ASIO_ENABLE_CANCELIO)
1113 // Update the ID of the thread from which cancellation is safe.
1114 if (impl
.safe_cancellation_thread_id_
== 0)
1115 impl
.safe_cancellation_thread_id_
= ::GetCurrentThreadId();
1116 else if (impl
.safe_cancellation_thread_id_
!= ::GetCurrentThreadId())
1117 impl
.safe_cancellation_thread_id_
= ~DWORD(0);
1118 #endif // defined(BOOST_ASIO_ENABLE_CANCELIO)
1120 // Allocate and construct an operation to wrap the handler.
1121 typedef send_to_operation
<ConstBufferSequence
, Handler
> value_type
;
1122 typedef handler_alloc_traits
<Handler
, value_type
> alloc_traits
;
1123 raw_handler_ptr
<alloc_traits
> raw_ptr(handler
);
1124 handler_ptr
<alloc_traits
> ptr(raw_ptr
, iocp_service_
, buffers
, handler
);
1126 // Copy buffers into WSABUF array.
1127 ::WSABUF bufs
[max_buffers
];
1128 typename
ConstBufferSequence::const_iterator iter
= buffers
.begin();
1129 typename
ConstBufferSequence::const_iterator end
= buffers
.end();
1131 for (; iter
!= end
&& i
< max_buffers
; ++iter
, ++i
)
1133 boost::asio::const_buffer
buffer(*iter
);
1134 bufs
[i
].len
= static_cast<u_long
>(boost::asio::buffer_size(buffer
));
1135 bufs
[i
].buf
= const_cast<char*>(
1136 boost::asio::buffer_cast
<const char*>(buffer
));
1140 DWORD bytes_transferred
= 0;
1141 int result
= ::WSASendTo(impl
.socket_
, bufs
, i
, &bytes_transferred
, flags
,
1142 destination
.data(), static_cast<int>(destination
.size()), ptr
.get(), 0);
1143 DWORD last_error
= ::WSAGetLastError();
1145 // Check if the operation completed immediately.
1146 if (result
!= 0 && last_error
!= WSA_IO_PENDING
)
1148 boost::asio::io_service::work
work(this->get_io_service());
1150 boost::system::error_code
ec(last_error
,
1151 boost::asio::error::get_system_category());
1152 iocp_service_
.post(bind_handler(handler
, ec
, bytes_transferred
));
1160 // Start an asynchronous wait until data can be sent without blocking.
1161 template <typename Handler
>
1162 void async_send_to(implementation_type
& impl
, const null_buffers
&,
1163 socket_base::message_flags
, const endpoint_type
&, Handler handler
)
1167 this->get_io_service().post(bind_handler(handler
,
1168 boost::asio::error::bad_descriptor
, 0));
1172 // Check if the reactor was already obtained from the io_service.
1173 reactor_type
* reactor
= static_cast<reactor_type
*>(
1174 interlocked_compare_exchange_pointer(
1175 reinterpret_cast<void**>(&reactor_
), 0, 0));
1178 reactor
= &(boost::asio::use_service
<reactor_type
>(
1179 this->get_io_service()));
1180 interlocked_exchange_pointer(
1181 reinterpret_cast<void**>(&reactor_
), reactor
);
1184 reactor
->start_write_op(impl
.socket_
, impl
.reactor_data_
,
1185 null_buffers_operation
<Handler
>(this->get_io_service(), handler
),
1190 // Receive some data from the peer. Returns the number of bytes received.
1191 template <typename MutableBufferSequence
>
1192 size_t receive(implementation_type
& impl
,
1193 const MutableBufferSequence
& buffers
,
1194 socket_base::message_flags flags
, boost::system::error_code
& ec
)
1198 ec
= boost::asio::error::bad_descriptor
;
1202 // Copy buffers into WSABUF array.
1203 ::WSABUF bufs
[max_buffers
];
1204 typename
MutableBufferSequence::const_iterator iter
= buffers
.begin();
1205 typename
MutableBufferSequence::const_iterator end
= buffers
.end();
1207 size_t total_buffer_size
= 0;
1208 for (; iter
!= end
&& i
< max_buffers
; ++iter
, ++i
)
1210 boost::asio::mutable_buffer
buffer(*iter
);
1211 bufs
[i
].len
= static_cast<u_long
>(boost::asio::buffer_size(buffer
));
1212 bufs
[i
].buf
= boost::asio::buffer_cast
<char*>(buffer
);
1213 total_buffer_size
+= boost::asio::buffer_size(buffer
);
1216 // A request to receive 0 bytes on a stream socket is a no-op.
1217 if (impl
.protocol_
.type() == SOCK_STREAM
&& total_buffer_size
== 0)
1219 ec
= boost::system::error_code();
1223 // Receive some data.
1224 DWORD bytes_transferred
= 0;
1225 DWORD recv_flags
= flags
;
1226 int result
= ::WSARecv(impl
.socket_
, bufs
, i
,
1227 &bytes_transferred
, &recv_flags
, 0, 0);
1230 DWORD last_error
= ::WSAGetLastError();
1231 if (last_error
== ERROR_NETNAME_DELETED
)
1232 last_error
= WSAECONNRESET
;
1233 else if (last_error
== ERROR_PORT_UNREACHABLE
)
1234 last_error
= WSAECONNREFUSED
;
1235 ec
= boost::system::error_code(last_error
,
1236 boost::asio::error::get_system_category());
1239 if (bytes_transferred
== 0 && impl
.protocol_
.type() == SOCK_STREAM
)
1241 ec
= boost::asio::error::eof
;
1245 ec
= boost::system::error_code();
1246 return bytes_transferred
;
1249 // Wait until data can be received without blocking.
1250 size_t receive(implementation_type
& impl
, const null_buffers
&,
1251 socket_base::message_flags
, boost::system::error_code
& ec
)
1255 ec
= boost::asio::error::bad_descriptor
;
1259 // Wait for socket to become ready.
1260 socket_ops::poll_read(impl
.socket_
, ec
);
1265 template <typename MutableBufferSequence
, typename Handler
>
1266 class receive_operation
1270 receive_operation(int protocol_type
, win_iocp_io_service
& io_service
,
1271 weak_cancel_token_type cancel_token
,
1272 const MutableBufferSequence
& buffers
, Handler handler
)
1273 : operation(io_service
,
1275 MutableBufferSequence
, Handler
>::do_completion_impl
,
1277 MutableBufferSequence
, Handler
>::destroy_impl
),
1278 protocol_type_(protocol_type
),
1279 work_(io_service
.get_io_service()),
1280 cancel_token_(cancel_token
),
1287 static void do_completion_impl(operation
* op
,
1288 DWORD last_error
, size_t bytes_transferred
)
1290 // Take ownership of the operation object.
1291 typedef receive_operation
<MutableBufferSequence
, Handler
> op_type
;
1292 op_type
* handler_op(static_cast<op_type
*>(op
));
1293 typedef handler_alloc_traits
<Handler
, op_type
> alloc_traits
;
1294 handler_ptr
<alloc_traits
> ptr(handler_op
->handler_
, handler_op
);
1296 #if defined(BOOST_ASIO_ENABLE_BUFFER_DEBUGGING)
1297 // Check whether buffers are still valid.
1298 typename
MutableBufferSequence::const_iterator iter
1299 = handler_op
->buffers_
.begin();
1300 typename
MutableBufferSequence::const_iterator end
1301 = handler_op
->buffers_
.end();
1304 boost::asio::mutable_buffer
buffer(*iter
);
1305 boost::asio::buffer_cast
<char*>(buffer
);
1308 #endif // defined(BOOST_ASIO_ENABLE_BUFFER_DEBUGGING)
1310 // Map non-portable errors to their portable counterparts.
1311 boost::system::error_code
ec(last_error
,
1312 boost::asio::error::get_system_category());
1313 if (ec
.value() == ERROR_NETNAME_DELETED
)
1315 if (handler_op
->cancel_token_
.expired())
1316 ec
= boost::asio::error::operation_aborted
;
1318 ec
= boost::asio::error::connection_reset
;
1320 else if (ec
.value() == ERROR_PORT_UNREACHABLE
)
1322 ec
= boost::asio::error::connection_refused
;
1325 // Check for connection closed.
1326 else if (!ec
&& bytes_transferred
== 0
1327 && handler_op
->protocol_type_
== SOCK_STREAM
1328 && !boost::is_same
<MutableBufferSequence
, null_buffers
>::value
)
1330 ec
= boost::asio::error::eof
;
1333 // Make a copy of the handler so that the memory can be deallocated before
1334 // the upcall is made.
1335 Handler
handler(handler_op
->handler_
);
1337 // Free the memory associated with the handler.
1340 // Call the handler.
1341 boost_asio_handler_invoke_helpers::invoke(
1342 detail::bind_handler(handler
, ec
, bytes_transferred
), &handler
);
1345 static void destroy_impl(operation
* op
)
1347 // Take ownership of the operation object.
1348 typedef receive_operation
<MutableBufferSequence
, Handler
> op_type
;
1349 op_type
* handler_op(static_cast<op_type
*>(op
));
1350 typedef handler_alloc_traits
<Handler
, op_type
> alloc_traits
;
1351 handler_ptr
<alloc_traits
> ptr(handler_op
->handler_
, handler_op
);
1353 // A sub-object of the handler may be the true owner of the memory
1354 // associated with the handler. Consequently, a local copy of the handler
1355 // is required to ensure that any owning sub-object remains valid until
1356 // after we have deallocated the memory here.
1357 Handler
handler(handler_op
->handler_
);
1360 // Free the memory associated with the handler.
1365 boost::asio::io_service::work work_
;
1366 weak_cancel_token_type cancel_token_
;
1367 MutableBufferSequence buffers_
;
1371 // Start an asynchronous receive. The buffer for the data being received
1372 // must be valid for the lifetime of the asynchronous operation.
1373 template <typename MutableBufferSequence
, typename Handler
>
1374 void async_receive(implementation_type
& impl
,
1375 const MutableBufferSequence
& buffers
,
1376 socket_base::message_flags flags
, Handler handler
)
1380 this->get_io_service().post(bind_handler(handler
,
1381 boost::asio::error::bad_descriptor
, 0));
1385 #if defined(BOOST_ASIO_ENABLE_CANCELIO)
1386 // Update the ID of the thread from which cancellation is safe.
1387 if (impl
.safe_cancellation_thread_id_
== 0)
1388 impl
.safe_cancellation_thread_id_
= ::GetCurrentThreadId();
1389 else if (impl
.safe_cancellation_thread_id_
!= ::GetCurrentThreadId())
1390 impl
.safe_cancellation_thread_id_
= ~DWORD(0);
1391 #endif // defined(BOOST_ASIO_ENABLE_CANCELIO)
1393 // Allocate and construct an operation to wrap the handler.
1394 typedef receive_operation
<MutableBufferSequence
, Handler
> value_type
;
1395 typedef handler_alloc_traits
<Handler
, value_type
> alloc_traits
;
1396 raw_handler_ptr
<alloc_traits
> raw_ptr(handler
);
1397 int protocol_type
= impl
.protocol_
.type();
1398 handler_ptr
<alloc_traits
> ptr(raw_ptr
, protocol_type
,
1399 iocp_service_
, impl
.cancel_token_
, buffers
, handler
);
1401 // Copy buffers into WSABUF array.
1402 ::WSABUF bufs
[max_buffers
];
1403 typename
MutableBufferSequence::const_iterator iter
= buffers
.begin();
1404 typename
MutableBufferSequence::const_iterator end
= buffers
.end();
1406 size_t total_buffer_size
= 0;
1407 for (; iter
!= end
&& i
< max_buffers
; ++iter
, ++i
)
1409 boost::asio::mutable_buffer
buffer(*iter
);
1410 bufs
[i
].len
= static_cast<u_long
>(boost::asio::buffer_size(buffer
));
1411 bufs
[i
].buf
= boost::asio::buffer_cast
<char*>(buffer
);
1412 total_buffer_size
+= boost::asio::buffer_size(buffer
);
1415 // A request to receive 0 bytes on a stream socket is a no-op.
1416 if (impl
.protocol_
.type() == SOCK_STREAM
&& total_buffer_size
== 0)
1418 boost::asio::io_service::work
work(this->get_io_service());
1420 boost::system::error_code error
;
1421 iocp_service_
.post(bind_handler(handler
, error
, 0));
1425 // Receive some data.
1426 DWORD bytes_transferred
= 0;
1427 DWORD recv_flags
= flags
;
1428 int result
= ::WSARecv(impl
.socket_
, bufs
, i
,
1429 &bytes_transferred
, &recv_flags
, ptr
.get(), 0);
1430 DWORD last_error
= ::WSAGetLastError();
1431 if (result
!= 0 && last_error
!= WSA_IO_PENDING
)
1433 boost::asio::io_service::work
work(this->get_io_service());
1435 boost::system::error_code
ec(last_error
,
1436 boost::asio::error::get_system_category());
1437 iocp_service_
.post(bind_handler(handler
, ec
, bytes_transferred
));
1445 // Wait until data can be received without blocking.
1446 template <typename Handler
>
1447 void async_receive(implementation_type
& impl
, const null_buffers
& buffers
,
1448 socket_base::message_flags flags
, Handler handler
)
1452 this->get_io_service().post(bind_handler(handler
,
1453 boost::asio::error::bad_descriptor
, 0));
1455 else if (impl
.protocol_
.type() == SOCK_STREAM
)
1457 // For stream sockets on Windows, we may issue a 0-byte overlapped
1458 // WSARecv to wait until there is data available on the socket.
1460 #if defined(BOOST_ASIO_ENABLE_CANCELIO)
1461 // Update the ID of the thread from which cancellation is safe.
1462 if (impl
.safe_cancellation_thread_id_
== 0)
1463 impl
.safe_cancellation_thread_id_
= ::GetCurrentThreadId();
1464 else if (impl
.safe_cancellation_thread_id_
!= ::GetCurrentThreadId())
1465 impl
.safe_cancellation_thread_id_
= ~DWORD(0);
1466 #endif // defined(BOOST_ASIO_ENABLE_CANCELIO)
1468 // Allocate and construct an operation to wrap the handler.
1469 typedef receive_operation
<null_buffers
, Handler
> value_type
;
1470 typedef handler_alloc_traits
<Handler
, value_type
> alloc_traits
;
1471 raw_handler_ptr
<alloc_traits
> raw_ptr(handler
);
1472 int protocol_type
= impl
.protocol_
.type();
1473 handler_ptr
<alloc_traits
> ptr(raw_ptr
, protocol_type
,
1474 iocp_service_
, impl
.cancel_token_
, buffers
, handler
);
1476 // Issue a receive operation with an empty buffer.
1477 ::WSABUF buf
= { 0, 0 };
1478 DWORD bytes_transferred
= 0;
1479 DWORD recv_flags
= flags
;
1480 int result
= ::WSARecv(impl
.socket_
, &buf
, 1,
1481 &bytes_transferred
, &recv_flags
, ptr
.get(), 0);
1482 DWORD last_error
= ::WSAGetLastError();
1483 if (result
!= 0 && last_error
!= WSA_IO_PENDING
)
1485 boost::asio::io_service::work
work(this->get_io_service());
1487 boost::system::error_code
ec(last_error
,
1488 boost::asio::error::get_system_category());
1489 iocp_service_
.post(bind_handler(handler
, ec
, bytes_transferred
));
1498 // Check if the reactor was already obtained from the io_service.
1499 reactor_type
* reactor
= static_cast<reactor_type
*>(
1500 interlocked_compare_exchange_pointer(
1501 reinterpret_cast<void**>(&reactor_
), 0, 0));
1504 reactor
= &(boost::asio::use_service
<reactor_type
>(
1505 this->get_io_service()));
1506 interlocked_exchange_pointer(
1507 reinterpret_cast<void**>(&reactor_
), reactor
);
1510 if (flags
& socket_base::message_out_of_band
)
1512 reactor
->start_except_op(impl
.socket_
, impl
.reactor_data_
,
1513 null_buffers_operation
<Handler
>(this->get_io_service(), handler
));
1517 reactor
->start_read_op(impl
.socket_
, impl
.reactor_data_
,
1518 null_buffers_operation
<Handler
>(this->get_io_service(), handler
),
1524 // Receive a datagram with the endpoint of the sender. Returns the number of
1526 template <typename MutableBufferSequence
>
1527 size_t receive_from(implementation_type
& impl
,
1528 const MutableBufferSequence
& buffers
,
1529 endpoint_type
& sender_endpoint
, socket_base::message_flags flags
,
1530 boost::system::error_code
& ec
)
1534 ec
= boost::asio::error::bad_descriptor
;
1538 // Copy buffers into WSABUF array.
1539 ::WSABUF bufs
[max_buffers
];
1540 typename
MutableBufferSequence::const_iterator iter
= buffers
.begin();
1541 typename
MutableBufferSequence::const_iterator end
= buffers
.end();
1543 for (; iter
!= end
&& i
< max_buffers
; ++iter
, ++i
)
1545 boost::asio::mutable_buffer
buffer(*iter
);
1546 bufs
[i
].len
= static_cast<u_long
>(boost::asio::buffer_size(buffer
));
1547 bufs
[i
].buf
= boost::asio::buffer_cast
<char*>(buffer
);
1550 // Receive some data.
1551 DWORD bytes_transferred
= 0;
1552 DWORD recv_flags
= flags
;
1553 int endpoint_size
= static_cast<int>(sender_endpoint
.capacity());
1554 int result
= ::WSARecvFrom(impl
.socket_
, bufs
, i
, &bytes_transferred
,
1555 &recv_flags
, sender_endpoint
.data(), &endpoint_size
, 0, 0);
1558 DWORD last_error
= ::WSAGetLastError();
1559 if (last_error
== ERROR_PORT_UNREACHABLE
)
1560 last_error
= WSAECONNREFUSED
;
1561 ec
= boost::system::error_code(last_error
,
1562 boost::asio::error::get_system_category());
1565 if (bytes_transferred
== 0 && impl
.protocol_
.type() == SOCK_STREAM
)
1567 ec
= boost::asio::error::eof
;
1571 sender_endpoint
.resize(static_cast<std::size_t>(endpoint_size
));
1573 ec
= boost::system::error_code();
1574 return bytes_transferred
;
1577 // Wait until data can be received without blocking.
1578 size_t receive_from(implementation_type
& impl
,
1579 const null_buffers
&, endpoint_type
& sender_endpoint
,
1580 socket_base::message_flags
, boost::system::error_code
& ec
)
1584 ec
= boost::asio::error::bad_descriptor
;
1588 // Wait for socket to become ready.
1589 socket_ops::poll_read(impl
.socket_
, ec
);
1591 // Reset endpoint since it can be given no sensible value at this time.
1592 sender_endpoint
= endpoint_type();
1597 template <typename MutableBufferSequence
, typename Handler
>
1598 class receive_from_operation
1602 receive_from_operation(int protocol_type
, win_iocp_io_service
& io_service
,
1603 endpoint_type
& endpoint
, const MutableBufferSequence
& buffers
,
1605 : operation(io_service
,
1606 &receive_from_operation
<
1607 MutableBufferSequence
, Handler
>::do_completion_impl
,
1608 &receive_from_operation
<
1609 MutableBufferSequence
, Handler
>::destroy_impl
),
1610 protocol_type_(protocol_type
),
1611 endpoint_(endpoint
),
1612 endpoint_size_(static_cast<int>(endpoint
.capacity())),
1613 work_(io_service
.get_io_service()),
1619 int& endpoint_size()
1621 return endpoint_size_
;
1625 static void do_completion_impl(operation
* op
,
1626 DWORD last_error
, size_t bytes_transferred
)
1628 // Take ownership of the operation object.
1629 typedef receive_from_operation
<MutableBufferSequence
, Handler
> op_type
;
1630 op_type
* handler_op(static_cast<op_type
*>(op
));
1631 typedef handler_alloc_traits
<Handler
, op_type
> alloc_traits
;
1632 handler_ptr
<alloc_traits
> ptr(handler_op
->handler_
, handler_op
);
1634 #if defined(BOOST_ASIO_ENABLE_BUFFER_DEBUGGING)
1635 // Check whether buffers are still valid.
1636 typename
MutableBufferSequence::const_iterator iter
1637 = handler_op
->buffers_
.begin();
1638 typename
MutableBufferSequence::const_iterator end
1639 = handler_op
->buffers_
.end();
1642 boost::asio::mutable_buffer
buffer(*iter
);
1643 boost::asio::buffer_cast
<char*>(buffer
);
1646 #endif // defined(BOOST_ASIO_ENABLE_BUFFER_DEBUGGING)
1648 // Map non-portable errors to their portable counterparts.
1649 boost::system::error_code
ec(last_error
,
1650 boost::asio::error::get_system_category());
1651 if (ec
.value() == ERROR_PORT_UNREACHABLE
)
1653 ec
= boost::asio::error::connection_refused
;
1656 // Check for connection closed.
1657 if (!ec
&& bytes_transferred
== 0
1658 && handler_op
->protocol_type_
== SOCK_STREAM
)
1660 ec
= boost::asio::error::eof
;
1663 // Record the size of the endpoint returned by the operation.
1664 handler_op
->endpoint_
.resize(handler_op
->endpoint_size_
);
1666 // Make a copy of the handler so that the memory can be deallocated before
1667 // the upcall is made.
1668 Handler
handler(handler_op
->handler_
);
1670 // Free the memory associated with the handler.
1673 // Call the handler.
1674 boost_asio_handler_invoke_helpers::invoke(
1675 detail::bind_handler(handler
, ec
, bytes_transferred
), &handler
);
1678 static void destroy_impl(operation
* op
)
1680 // Take ownership of the operation object.
1681 typedef receive_from_operation
<MutableBufferSequence
, Handler
> op_type
;
1682 op_type
* handler_op(static_cast<op_type
*>(op
));
1683 typedef handler_alloc_traits
<Handler
, op_type
> alloc_traits
;
1684 handler_ptr
<alloc_traits
> ptr(handler_op
->handler_
, handler_op
);
1686 // A sub-object of the handler may be the true owner of the memory
1687 // associated with the handler. Consequently, a local copy of the handler
1688 // is required to ensure that any owning sub-object remains valid until
1689 // after we have deallocated the memory here.
1690 Handler
handler(handler_op
->handler_
);
1693 // Free the memory associated with the handler.
1698 endpoint_type
& endpoint_
;
1700 boost::asio::io_service::work work_
;
1701 MutableBufferSequence buffers_
;
1705 // Start an asynchronous receive. The buffer for the data being received and
1706 // the sender_endpoint object must both be valid for the lifetime of the
1707 // asynchronous operation.
1708 template <typename MutableBufferSequence
, typename Handler
>
1709 void async_receive_from(implementation_type
& impl
,
1710 const MutableBufferSequence
& buffers
, endpoint_type
& sender_endp
,
1711 socket_base::message_flags flags
, Handler handler
)
1715 this->get_io_service().post(bind_handler(handler
,
1716 boost::asio::error::bad_descriptor
, 0));
1720 #if defined(BOOST_ASIO_ENABLE_CANCELIO)
1721 // Update the ID of the thread from which cancellation is safe.
1722 if (impl
.safe_cancellation_thread_id_
== 0)
1723 impl
.safe_cancellation_thread_id_
= ::GetCurrentThreadId();
1724 else if (impl
.safe_cancellation_thread_id_
!= ::GetCurrentThreadId())
1725 impl
.safe_cancellation_thread_id_
= ~DWORD(0);
1726 #endif // defined(BOOST_ASIO_ENABLE_CANCELIO)
1728 // Allocate and construct an operation to wrap the handler.
1729 typedef receive_from_operation
<MutableBufferSequence
, Handler
> value_type
;
1730 typedef handler_alloc_traits
<Handler
, value_type
> alloc_traits
;
1731 raw_handler_ptr
<alloc_traits
> raw_ptr(handler
);
1732 int protocol_type
= impl
.protocol_
.type();
1733 handler_ptr
<alloc_traits
> ptr(raw_ptr
, protocol_type
,
1734 iocp_service_
, sender_endp
, buffers
, handler
);
1736 // Copy buffers into WSABUF array.
1737 ::WSABUF bufs
[max_buffers
];
1738 typename
MutableBufferSequence::const_iterator iter
= buffers
.begin();
1739 typename
MutableBufferSequence::const_iterator end
= buffers
.end();
1741 for (; iter
!= end
&& i
< max_buffers
; ++iter
, ++i
)
1743 boost::asio::mutable_buffer
buffer(*iter
);
1744 bufs
[i
].len
= static_cast<u_long
>(boost::asio::buffer_size(buffer
));
1745 bufs
[i
].buf
= boost::asio::buffer_cast
<char*>(buffer
);
1748 // Receive some data.
1749 DWORD bytes_transferred
= 0;
1750 DWORD recv_flags
= flags
;
1751 int result
= ::WSARecvFrom(impl
.socket_
, bufs
, i
, &bytes_transferred
,
1752 &recv_flags
, sender_endp
.data(), &ptr
.get()->endpoint_size(),
1754 DWORD last_error
= ::WSAGetLastError();
1755 if (result
!= 0 && last_error
!= WSA_IO_PENDING
)
1757 boost::asio::io_service::work
work(this->get_io_service());
1759 boost::system::error_code
ec(last_error
,
1760 boost::asio::error::get_system_category());
1761 iocp_service_
.post(bind_handler(handler
, ec
, bytes_transferred
));
1769 // Wait until data can be received without blocking.
1770 template <typename Handler
>
1771 void async_receive_from(implementation_type
& impl
,
1772 const null_buffers
&, endpoint_type
& sender_endpoint
,
1773 socket_base::message_flags flags
, Handler handler
)
1777 this->get_io_service().post(bind_handler(handler
,
1778 boost::asio::error::bad_descriptor
, 0));
1782 // Check if the reactor was already obtained from the io_service.
1783 reactor_type
* reactor
= static_cast<reactor_type
*>(
1784 interlocked_compare_exchange_pointer(
1785 reinterpret_cast<void**>(&reactor_
), 0, 0));
1788 reactor
= &(boost::asio::use_service
<reactor_type
>(
1789 this->get_io_service()));
1790 interlocked_exchange_pointer(
1791 reinterpret_cast<void**>(&reactor_
), reactor
);
1794 // Reset endpoint since it can be given no sensible value at this time.
1795 sender_endpoint
= endpoint_type();
1797 if (flags
& socket_base::message_out_of_band
)
1799 reactor
->start_except_op(impl
.socket_
, impl
.reactor_data_
,
1800 null_buffers_operation
<Handler
>(this->get_io_service(), handler
));
1804 reactor
->start_read_op(impl
.socket_
, impl
.reactor_data_
,
1805 null_buffers_operation
<Handler
>(this->get_io_service(), handler
),
1811 // Accept a new connection.
1812 template <typename Socket
>
1813 boost::system::error_code
accept(implementation_type
& impl
, Socket
& peer
,
1814 endpoint_type
* peer_endpoint
, boost::system::error_code
& ec
)
1818 ec
= boost::asio::error::bad_descriptor
;
1822 // We cannot accept a socket that is already open.
1825 ec
= boost::asio::error::already_open
;
1831 socket_holder new_socket
;
1832 std::size_t addr_len
= 0;
1835 addr_len
= peer_endpoint
->capacity();
1836 new_socket
.reset(socket_ops::accept(impl
.socket_
,
1837 peer_endpoint
->data(), &addr_len
, ec
));
1841 new_socket
.reset(socket_ops::accept(impl
.socket_
, 0, 0, ec
));
1846 if (ec
== boost::asio::error::connection_aborted
1847 && !(impl
.flags_
& implementation_type::enable_connection_aborted
))
1849 // Retry accept operation.
1859 peer_endpoint
->resize(addr_len
);
1861 peer
.assign(impl
.protocol_
, new_socket
.get(), ec
);
1863 new_socket
.release();
1868 template <typename Socket
, typename Handler
>
1869 class accept_operation
1873 accept_operation(win_iocp_io_service
& io_service
,
1874 socket_type socket
, socket_type new_socket
, Socket
& peer
,
1875 const protocol_type
& protocol
, endpoint_type
* peer_endpoint
,
1876 bool enable_connection_aborted
, Handler handler
)
1877 : operation(io_service
,
1878 &accept_operation
<Socket
, Handler
>::do_completion_impl
,
1879 &accept_operation
<Socket
, Handler
>::destroy_impl
),
1880 io_service_(io_service
),
1882 new_socket_(new_socket
),
1884 protocol_(protocol
),
1885 peer_endpoint_(peer_endpoint
),
1886 work_(io_service
.get_io_service()),
1887 enable_connection_aborted_(enable_connection_aborted
),
1892 socket_type
new_socket()
1894 return new_socket_
.get();
1897 void* output_buffer()
1899 return output_buffer_
;
1902 DWORD
address_length()
1904 return sizeof(sockaddr_storage_type
) + 16;
1908 static void do_completion_impl(operation
* op
, DWORD last_error
, size_t)
1910 // Take ownership of the operation object.
1911 typedef accept_operation
<Socket
, Handler
> op_type
;
1912 op_type
* handler_op(static_cast<op_type
*>(op
));
1913 typedef handler_alloc_traits
<Handler
, op_type
> alloc_traits
;
1914 handler_ptr
<alloc_traits
> ptr(handler_op
->handler_
, handler_op
);
1916 // Map Windows error ERROR_NETNAME_DELETED to connection_aborted.
1917 if (last_error
== ERROR_NETNAME_DELETED
)
1919 last_error
= WSAECONNABORTED
;
1922 // Restart the accept operation if we got the connection_aborted error
1923 // and the enable_connection_aborted socket option is not set.
1924 if (last_error
== WSAECONNABORTED
1925 && !ptr
.get()->enable_connection_aborted_
)
1927 // Reset OVERLAPPED structure.
1928 ptr
.get()->Internal
= 0;
1929 ptr
.get()->InternalHigh
= 0;
1930 ptr
.get()->Offset
= 0;
1931 ptr
.get()->OffsetHigh
= 0;
1932 ptr
.get()->hEvent
= 0;
1934 // Create a new socket for the next connection, since the AcceptEx call
1935 // fails with WSAEINVAL if we try to reuse the same socket.
1936 boost::system::error_code ec
;
1937 ptr
.get()->new_socket_
.reset();
1938 ptr
.get()->new_socket_
.reset(socket_ops::socket(
1939 ptr
.get()->protocol_
.family(), ptr
.get()->protocol_
.type(),
1940 ptr
.get()->protocol_
.protocol(), ec
));
1941 if (ptr
.get()->new_socket() != invalid_socket
)
1943 // Accept a connection.
1944 DWORD bytes_read
= 0;
1945 BOOL result
= ::AcceptEx(ptr
.get()->socket_
, ptr
.get()->new_socket(),
1946 ptr
.get()->output_buffer(), 0, ptr
.get()->address_length(),
1947 ptr
.get()->address_length(), &bytes_read
, ptr
.get());
1948 last_error
= ::WSAGetLastError();
1950 // Check if the operation completed immediately.
1951 if (!result
&& last_error
!= WSA_IO_PENDING
)
1953 if (last_error
== ERROR_NETNAME_DELETED
1954 || last_error
== WSAECONNABORTED
)
1956 // Post this handler so that operation will be restarted again.
1957 ptr
.get()->io_service_
.post_completion(ptr
.get(), last_error
, 0);
1963 // Operation already complete. Continue with rest of this handler.
1968 // Asynchronous operation has been successfully restarted.
1975 // Get the address of the peer.
1976 endpoint_type peer_endpoint
;
1977 if (last_error
== 0)
1979 LPSOCKADDR local_addr
= 0;
1980 int local_addr_length
= 0;
1981 LPSOCKADDR remote_addr
= 0;
1982 int remote_addr_length
= 0;
1983 GetAcceptExSockaddrs(handler_op
->output_buffer(), 0,
1984 handler_op
->address_length(), handler_op
->address_length(),
1985 &local_addr
, &local_addr_length
, &remote_addr
, &remote_addr_length
);
1986 if (static_cast<std::size_t>(remote_addr_length
)
1987 > peer_endpoint
.capacity())
1989 last_error
= WSAEINVAL
;
1993 using namespace std
; // For memcpy.
1994 memcpy(peer_endpoint
.data(), remote_addr
, remote_addr_length
);
1995 peer_endpoint
.resize(static_cast<std::size_t>(remote_addr_length
));
1999 // Need to set the SO_UPDATE_ACCEPT_CONTEXT option so that getsockname
2000 // and getpeername will work on the accepted socket.
2001 if (last_error
== 0)
2003 SOCKET update_ctx_param
= handler_op
->socket_
;
2004 boost::system::error_code ec
;
2005 if (socket_ops::setsockopt(handler_op
->new_socket_
.get(),
2006 SOL_SOCKET
, SO_UPDATE_ACCEPT_CONTEXT
,
2007 &update_ctx_param
, sizeof(SOCKET
), ec
) != 0)
2009 last_error
= ec
.value();
2013 // If the socket was successfully accepted, transfer ownership of the
2014 // socket to the peer object.
2015 if (last_error
== 0)
2017 boost::system::error_code ec
;
2018 handler_op
->peer_
.assign(handler_op
->protocol_
,
2019 native_type(handler_op
->new_socket_
.get(), peer_endpoint
), ec
);
2021 last_error
= ec
.value();
2023 handler_op
->new_socket_
.release();
2026 // Pass endpoint back to caller.
2027 if (handler_op
->peer_endpoint_
)
2028 *handler_op
->peer_endpoint_
= peer_endpoint
;
2030 // Make a copy of the handler so that the memory can be deallocated before
2031 // the upcall is made.
2032 Handler
handler(handler_op
->handler_
);
2034 // Free the memory associated with the handler.
2037 // Call the handler.
2038 boost::system::error_code
ec(last_error
,
2039 boost::asio::error::get_system_category());
2040 boost_asio_handler_invoke_helpers::invoke(
2041 detail::bind_handler(handler
, ec
), &handler
);
2044 static void destroy_impl(operation
* op
)
2046 // Take ownership of the operation object.
2047 typedef accept_operation
<Socket
, Handler
> op_type
;
2048 op_type
* handler_op(static_cast<op_type
*>(op
));
2049 typedef handler_alloc_traits
<Handler
, op_type
> alloc_traits
;
2050 handler_ptr
<alloc_traits
> ptr(handler_op
->handler_
, handler_op
);
2052 // A sub-object of the handler may be the true owner of the memory
2053 // associated with the handler. Consequently, a local copy of the handler
2054 // is required to ensure that any owning sub-object remains valid until
2055 // after we have deallocated the memory here.
2056 Handler
handler(handler_op
->handler_
);
2059 // Free the memory associated with the handler.
2063 win_iocp_io_service
& io_service_
;
2064 socket_type socket_
;
2065 socket_holder new_socket_
;
2067 protocol_type protocol_
;
2068 endpoint_type
* peer_endpoint_
;
2069 boost::asio::io_service::work work_
;
2070 unsigned char output_buffer_
[(sizeof(sockaddr_storage_type
) + 16) * 2];
2071 bool enable_connection_aborted_
;
2075 // Start an asynchronous accept. The peer and peer_endpoint objects
2076 // must be valid until the accept's handler is invoked.
2077 template <typename Socket
, typename Handler
>
2078 void async_accept(implementation_type
& impl
, Socket
& peer
,
2079 endpoint_type
* peer_endpoint
, Handler handler
)
2081 // Check whether acceptor has been initialised.
2084 this->get_io_service().post(bind_handler(handler
,
2085 boost::asio::error::bad_descriptor
));
2089 // Check that peer socket has not already been opened.
2092 this->get_io_service().post(bind_handler(handler
,
2093 boost::asio::error::already_open
));
2097 #if defined(BOOST_ASIO_ENABLE_CANCELIO)
2098 // Update the ID of the thread from which cancellation is safe.
2099 if (impl
.safe_cancellation_thread_id_
== 0)
2100 impl
.safe_cancellation_thread_id_
= ::GetCurrentThreadId();
2101 else if (impl
.safe_cancellation_thread_id_
!= ::GetCurrentThreadId())
2102 impl
.safe_cancellation_thread_id_
= ~DWORD(0);
2103 #endif // defined(BOOST_ASIO_ENABLE_CANCELIO)
2105 // Create a new socket for the connection.
2106 boost::system::error_code ec
;
2107 socket_holder
sock(socket_ops::socket(impl
.protocol_
.family(),
2108 impl
.protocol_
.type(), impl
.protocol_
.protocol(), ec
));
2109 if (sock
.get() == invalid_socket
)
2111 this->get_io_service().post(bind_handler(handler
, ec
));
2115 // Allocate and construct an operation to wrap the handler.
2116 typedef accept_operation
<Socket
, Handler
> value_type
;
2117 typedef handler_alloc_traits
<Handler
, value_type
> alloc_traits
;
2118 raw_handler_ptr
<alloc_traits
> raw_ptr(handler
);
2119 socket_type new_socket
= sock
.get();
2120 bool enable_connection_aborted
=
2121 (impl
.flags_
& implementation_type::enable_connection_aborted
);
2122 handler_ptr
<alloc_traits
> ptr(raw_ptr
,
2123 iocp_service_
, impl
.socket_
, new_socket
, peer
, impl
.protocol_
,
2124 peer_endpoint
, enable_connection_aborted
, handler
);
2127 // Accept a connection.
2128 DWORD bytes_read
= 0;
2129 BOOL result
= ::AcceptEx(impl
.socket_
, ptr
.get()->new_socket(),
2130 ptr
.get()->output_buffer(), 0, ptr
.get()->address_length(),
2131 ptr
.get()->address_length(), &bytes_read
, ptr
.get());
2132 DWORD last_error
= ::WSAGetLastError();
2134 // Check if the operation completed immediately.
2135 if (!result
&& last_error
!= WSA_IO_PENDING
)
2137 if (!enable_connection_aborted
2138 && (last_error
== ERROR_NETNAME_DELETED
2139 || last_error
== WSAECONNABORTED
))
2141 // Post handler so that operation will be restarted again. We do not
2142 // perform the AcceptEx again here to avoid the possibility of starving
2144 iocp_service_
.post_completion(ptr
.get(), last_error
, 0);
2149 boost::asio::io_service::work
work(this->get_io_service());
2151 boost::system::error_code
ec(last_error
,
2152 boost::asio::error::get_system_category());
2153 iocp_service_
.post(bind_handler(handler
, ec
));
2162 // Connect the socket to the specified endpoint.
2163 boost::system::error_code
connect(implementation_type
& impl
,
2164 const endpoint_type
& peer_endpoint
, boost::system::error_code
& ec
)
2168 ec
= boost::asio::error::bad_descriptor
;
2172 // Perform the connect operation.
2173 socket_ops::connect(impl
.socket_
,
2174 peer_endpoint
.data(), peer_endpoint
.size(), ec
);
2178 template <typename Handler
>
2179 class connect_operation
2182 connect_operation(socket_type socket
, bool user_set_non_blocking
,
2183 boost::asio::io_service
& io_service
, Handler handler
)
2185 user_set_non_blocking_(user_set_non_blocking
),
2186 io_service_(io_service
),
2192 bool perform(boost::system::error_code
& ec
,
2193 std::size_t& bytes_transferred
)
2195 bytes_transferred
= 0;
2197 // Check whether the operation was successful.
2201 // Get the error code from the connect operation.
2202 int connect_error
= 0;
2203 size_t connect_error_len
= sizeof(connect_error
);
2204 if (socket_ops::getsockopt(socket_
, SOL_SOCKET
, SO_ERROR
,
2205 &connect_error
, &connect_error_len
, ec
) == socket_error_retval
)
2208 // If connection failed then post the handler with the error code.
2211 ec
= boost::system::error_code(connect_error
,
2212 boost::asio::error::get_system_category());
2216 // Revert socket to blocking mode unless the user requested otherwise.
2217 if (!user_set_non_blocking_
)
2219 ioctl_arg_type non_blocking
= 0;
2220 if (socket_ops::ioctl(socket_
, FIONBIO
, &non_blocking
, ec
))
2224 // Post the result of the successful connection operation.
2225 ec
= boost::system::error_code();
2229 void complete(const boost::system::error_code
& ec
, std::size_t)
2231 io_service_
.post(bind_handler(handler_
, ec
));
2235 socket_type socket_
;
2236 bool user_set_non_blocking_
;
2237 boost::asio::io_service
& io_service_
;
2238 boost::asio::io_service::work work_
;
2242 // Start an asynchronous connect.
2243 template <typename Handler
>
2244 void async_connect(implementation_type
& impl
,
2245 const endpoint_type
& peer_endpoint
, Handler handler
)
2249 this->get_io_service().post(bind_handler(handler
,
2250 boost::asio::error::bad_descriptor
));
2254 #if defined(BOOST_ASIO_ENABLE_CANCELIO)
2255 // Update the ID of the thread from which cancellation is safe.
2256 if (impl
.safe_cancellation_thread_id_
== 0)
2257 impl
.safe_cancellation_thread_id_
= ::GetCurrentThreadId();
2258 else if (impl
.safe_cancellation_thread_id_
!= ::GetCurrentThreadId())
2259 impl
.safe_cancellation_thread_id_
= ~DWORD(0);
2260 #endif // defined(BOOST_ASIO_ENABLE_CANCELIO)
2262 // Check if the reactor was already obtained from the io_service.
2263 reactor_type
* reactor
= static_cast<reactor_type
*>(
2264 interlocked_compare_exchange_pointer(
2265 reinterpret_cast<void**>(&reactor_
), 0, 0));
2268 reactor
= &(boost::asio::use_service
<reactor_type
>(
2269 this->get_io_service()));
2270 interlocked_exchange_pointer(
2271 reinterpret_cast<void**>(&reactor_
), reactor
);
2274 // Mark the socket as non-blocking so that the connection will take place
2276 ioctl_arg_type non_blocking
= 1;
2277 boost::system::error_code ec
;
2278 if (socket_ops::ioctl(impl
.socket_
, FIONBIO
, &non_blocking
, ec
))
2280 this->get_io_service().post(bind_handler(handler
, ec
));
2284 // Start the connect operation.
2285 if (socket_ops::connect(impl
.socket_
, peer_endpoint
.data(),
2286 peer_endpoint
.size(), ec
) == 0)
2288 // Revert socket to blocking mode unless the user requested otherwise.
2289 if (!(impl
.flags_
& implementation_type::user_set_non_blocking
))
2292 socket_ops::ioctl(impl
.socket_
, FIONBIO
, &non_blocking
, ec
);
2295 // The connect operation has finished successfully so we need to post the
2296 // handler immediately.
2297 this->get_io_service().post(bind_handler(handler
, ec
));
2299 else if (ec
== boost::asio::error::in_progress
2300 || ec
== boost::asio::error::would_block
)
2302 // The connection is happening in the background, and we need to wait
2303 // until the socket becomes writeable.
2304 boost::shared_ptr
<bool> completed(new bool(false));
2305 reactor
->start_connect_op(impl
.socket_
, impl
.reactor_data_
,
2306 connect_operation
<Handler
>(
2308 (impl
.flags_
& implementation_type::user_set_non_blocking
) != 0,
2309 this->get_io_service(), handler
));
2313 // Revert socket to blocking mode unless the user requested otherwise.
2314 if (!(impl
.flags_
& implementation_type::user_set_non_blocking
))
2317 boost::system::error_code ignored_ec
;
2318 socket_ops::ioctl(impl
.socket_
, FIONBIO
, &non_blocking
, ignored_ec
);
2321 // The connect operation has failed, so post the handler immediately.
2322 this->get_io_service().post(bind_handler(handler
, ec
));
2327 // Helper function to close a socket when the associated object is being
2329 void close_for_destruction(implementation_type
& impl
)
2333 // Check if the reactor was created, in which case we need to close the
2334 // socket on the reactor as well to cancel any operations that might be
2336 reactor_type
* reactor
= static_cast<reactor_type
*>(
2337 interlocked_compare_exchange_pointer(
2338 reinterpret_cast<void**>(&reactor_
), 0, 0));
2340 reactor
->close_descriptor(impl
.socket_
, impl
.reactor_data_
);
2342 // The socket destructor must not block. If the user has changed the
2343 // linger option to block in the foreground, we will change it back to the
2344 // default so that the closure is performed in the background.
2345 if (impl
.flags_
& implementation_type::close_might_block
)
2350 boost::system::error_code ignored_ec
;
2351 socket_ops::setsockopt(impl
.socket_
,
2352 SOL_SOCKET
, SO_LINGER
, &opt
, sizeof(opt
), ignored_ec
);
2355 boost::system::error_code ignored_ec
;
2356 socket_ops::close(impl
.socket_
, ignored_ec
);
2357 impl
.socket_
= invalid_socket
;
2359 impl
.cancel_token_
.reset();
2360 #if defined(BOOST_ASIO_ENABLE_CANCELIO)
2361 impl
.safe_cancellation_thread_id_
= 0;
2362 #endif // defined(BOOST_ASIO_ENABLE_CANCELIO)
2366 // Helper function to emulate InterlockedCompareExchangePointer functionality
2368 // - very old Platform SDKs; and
2369 // - platform SDKs where MSVC's /Wp64 option causes spurious warnings.
2370 void* interlocked_compare_exchange_pointer(void** dest
, void* exch
, void* cmp
)
2372 #if defined(_M_IX86)
2373 return reinterpret_cast<void*>(InterlockedCompareExchange(
2374 reinterpret_cast<PLONG
>(dest
), reinterpret_cast<LONG
>(exch
),
2375 reinterpret_cast<LONG
>(cmp
)));
2377 return InterlockedCompareExchangePointer(dest
, exch
, cmp
);
2381 // Helper function to emulate InterlockedExchangePointer functionality for:
2382 // - very old Platform SDKs; and
2383 // - platform SDKs where MSVC's /Wp64 option causes spurious warnings.
2384 void* interlocked_exchange_pointer(void** dest
, void* val
)
2386 #if defined(_M_IX86)
2387 return reinterpret_cast<void*>(InterlockedExchange(
2388 reinterpret_cast<PLONG
>(dest
), reinterpret_cast<LONG
>(val
)));
2390 return InterlockedExchangePointer(dest
, val
);
2394 // The IOCP service used for running asynchronous operations and dispatching
2396 win_iocp_io_service
& iocp_service_
;
2398 // The reactor used for performing connect operations. This object is created
2400 reactor_type
* reactor_
;
2402 // Mutex to protect access to the linked list of implementations.
2403 boost::asio::detail::mutex mutex_
;
2405 // The head of a linked list of all implementations.
2406 implementation_type
* impl_list_
;
2409 } // namespace detail
2411 } // namespace boost
2413 #endif // defined(BOOST_ASIO_HAS_IOCP)
2415 #include <boost/asio/detail/pop_options.hpp>
2417 #endif // BOOST_ASIO_DETAIL_WIN_IOCP_SOCKET_SERVICE_HPP