win_iocp_socket_service_base.ipp 24 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801
  1. //
  2. // detail/impl/win_iocp_socket_service_base.ipp
  3. // ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
  4. //
  5. // Copyright (c) 2003-2018 Christopher M. Kohlhoff (chris at kohlhoff dot com)
  6. //
  7. // Distributed under the Boost Software License, Version 1.0. (See accompanying
  8. // file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt)
  9. //
  10. #ifndef BOOST_ASIO_DETAIL_IMPL_WIN_IOCP_SOCKET_SERVICE_BASE_IPP
  11. #define BOOST_ASIO_DETAIL_IMPL_WIN_IOCP_SOCKET_SERVICE_BASE_IPP
  12. #if defined(_MSC_VER) && (_MSC_VER >= 1200)
  13. # pragma once
  14. #endif // defined(_MSC_VER) && (_MSC_VER >= 1200)
  15. #include <boost/asio/detail/config.hpp>
  16. #if defined(BOOST_ASIO_HAS_IOCP)
  17. #include <boost/asio/detail/win_iocp_socket_service_base.hpp>
  18. #include <boost/asio/detail/push_options.hpp>
  19. namespace boost {
  20. namespace asio {
  21. namespace detail {
  22. win_iocp_socket_service_base::win_iocp_socket_service_base(
  23. boost::asio::io_context& io_context)
  24. : io_context_(io_context),
  25. iocp_service_(use_service<win_iocp_io_context>(io_context)),
  26. reactor_(0),
  27. connect_ex_(0),
  28. nt_set_info_(0),
  29. mutex_(),
  30. impl_list_(0)
  31. {
  32. }
  33. void win_iocp_socket_service_base::base_shutdown()
  34. {
  35. // Close all implementations, causing all operations to complete.
  36. boost::asio::detail::mutex::scoped_lock lock(mutex_);
  37. base_implementation_type* impl = impl_list_;
  38. while (impl)
  39. {
  40. close_for_destruction(*impl);
  41. impl = impl->next_;
  42. }
  43. }
  44. void win_iocp_socket_service_base::construct(
  45. win_iocp_socket_service_base::base_implementation_type& impl)
  46. {
  47. impl.socket_ = invalid_socket;
  48. impl.state_ = 0;
  49. impl.cancel_token_.reset();
  50. #if defined(BOOST_ASIO_ENABLE_CANCELIO)
  51. impl.safe_cancellation_thread_id_ = 0;
  52. #endif // defined(BOOST_ASIO_ENABLE_CANCELIO)
  53. // Insert implementation into linked list of all implementations.
  54. boost::asio::detail::mutex::scoped_lock lock(mutex_);
  55. impl.next_ = impl_list_;
  56. impl.prev_ = 0;
  57. if (impl_list_)
  58. impl_list_->prev_ = &impl;
  59. impl_list_ = &impl;
  60. }
  61. void win_iocp_socket_service_base::base_move_construct(
  62. win_iocp_socket_service_base::base_implementation_type& impl,
  63. win_iocp_socket_service_base::base_implementation_type& other_impl)
  64. {
  65. impl.socket_ = other_impl.socket_;
  66. other_impl.socket_ = invalid_socket;
  67. impl.state_ = other_impl.state_;
  68. other_impl.state_ = 0;
  69. impl.cancel_token_ = other_impl.cancel_token_;
  70. other_impl.cancel_token_.reset();
  71. #if defined(BOOST_ASIO_ENABLE_CANCELIO)
  72. impl.safe_cancellation_thread_id_ = other_impl.safe_cancellation_thread_id_;
  73. other_impl.safe_cancellation_thread_id_ = 0;
  74. #endif // defined(BOOST_ASIO_ENABLE_CANCELIO)
  75. // Insert implementation into linked list of all implementations.
  76. boost::asio::detail::mutex::scoped_lock lock(mutex_);
  77. impl.next_ = impl_list_;
  78. impl.prev_ = 0;
  79. if (impl_list_)
  80. impl_list_->prev_ = &impl;
  81. impl_list_ = &impl;
  82. }
  83. void win_iocp_socket_service_base::base_move_assign(
  84. win_iocp_socket_service_base::base_implementation_type& impl,
  85. win_iocp_socket_service_base& other_service,
  86. win_iocp_socket_service_base::base_implementation_type& other_impl)
  87. {
  88. close_for_destruction(impl);
  89. if (this != &other_service)
  90. {
  91. // Remove implementation from linked list of all implementations.
  92. boost::asio::detail::mutex::scoped_lock lock(mutex_);
  93. if (impl_list_ == &impl)
  94. impl_list_ = impl.next_;
  95. if (impl.prev_)
  96. impl.prev_->next_ = impl.next_;
  97. if (impl.next_)
  98. impl.next_->prev_= impl.prev_;
  99. impl.next_ = 0;
  100. impl.prev_ = 0;
  101. }
  102. impl.socket_ = other_impl.socket_;
  103. other_impl.socket_ = invalid_socket;
  104. impl.state_ = other_impl.state_;
  105. other_impl.state_ = 0;
  106. impl.cancel_token_ = other_impl.cancel_token_;
  107. other_impl.cancel_token_.reset();
  108. #if defined(BOOST_ASIO_ENABLE_CANCELIO)
  109. impl.safe_cancellation_thread_id_ = other_impl.safe_cancellation_thread_id_;
  110. other_impl.safe_cancellation_thread_id_ = 0;
  111. #endif // defined(BOOST_ASIO_ENABLE_CANCELIO)
  112. if (this != &other_service)
  113. {
  114. // Insert implementation into linked list of all implementations.
  115. boost::asio::detail::mutex::scoped_lock lock(other_service.mutex_);
  116. impl.next_ = other_service.impl_list_;
  117. impl.prev_ = 0;
  118. if (other_service.impl_list_)
  119. other_service.impl_list_->prev_ = &impl;
  120. other_service.impl_list_ = &impl;
  121. }
  122. }
  123. void win_iocp_socket_service_base::destroy(
  124. win_iocp_socket_service_base::base_implementation_type& impl)
  125. {
  126. close_for_destruction(impl);
  127. // Remove implementation from linked list of all implementations.
  128. boost::asio::detail::mutex::scoped_lock lock(mutex_);
  129. if (impl_list_ == &impl)
  130. impl_list_ = impl.next_;
  131. if (impl.prev_)
  132. impl.prev_->next_ = impl.next_;
  133. if (impl.next_)
  134. impl.next_->prev_= impl.prev_;
  135. impl.next_ = 0;
  136. impl.prev_ = 0;
  137. }
  138. boost::system::error_code win_iocp_socket_service_base::close(
  139. win_iocp_socket_service_base::base_implementation_type& impl,
  140. boost::system::error_code& ec)
  141. {
  142. if (is_open(impl))
  143. {
  144. BOOST_ASIO_HANDLER_OPERATION((iocp_service_.context(),
  145. "socket", &impl, impl.socket_, "close"));
  146. // Check if the reactor was created, in which case we need to close the
  147. // socket on the reactor as well to cancel any operations that might be
  148. // running there.
  149. select_reactor* r = static_cast<select_reactor*>(
  150. interlocked_compare_exchange_pointer(
  151. reinterpret_cast<void**>(&reactor_), 0, 0));
  152. if (r)
  153. r->deregister_descriptor(impl.socket_, impl.reactor_data_, true);
  154. socket_ops::close(impl.socket_, impl.state_, false, ec);
  155. if (r)
  156. r->cleanup_descriptor_data(impl.reactor_data_);
  157. }
  158. else
  159. {
  160. ec = boost::system::error_code();
  161. }
  162. impl.socket_ = invalid_socket;
  163. impl.state_ = 0;
  164. impl.cancel_token_.reset();
  165. #if defined(BOOST_ASIO_ENABLE_CANCELIO)
  166. impl.safe_cancellation_thread_id_ = 0;
  167. #endif // defined(BOOST_ASIO_ENABLE_CANCELIO)
  168. return ec;
  169. }
  170. socket_type win_iocp_socket_service_base::release(
  171. win_iocp_socket_service_base::base_implementation_type& impl,
  172. boost::system::error_code& ec)
  173. {
  174. if (!is_open(impl))
  175. return invalid_socket;
  176. cancel(impl, ec);
  177. if (ec)
  178. return invalid_socket;
  179. nt_set_info_fn fn = get_nt_set_info();
  180. if (fn == 0)
  181. {
  182. ec = boost::asio::error::operation_not_supported;
  183. return invalid_socket;
  184. }
  185. HANDLE sock_as_handle = reinterpret_cast<HANDLE>(impl.socket_);
  186. ULONG_PTR iosb[2] = { 0, 0 };
  187. void* info[2] = { 0, 0 };
  188. if (fn(sock_as_handle, iosb, &info, sizeof(info),
  189. 61 /* FileReplaceCompletionInformation */))
  190. {
  191. ec = boost::asio::error::operation_not_supported;
  192. return invalid_socket;
  193. }
  194. socket_type tmp = impl.socket_;
  195. impl.socket_ = invalid_socket;
  196. return tmp;
  197. }
  198. boost::system::error_code win_iocp_socket_service_base::cancel(
  199. win_iocp_socket_service_base::base_implementation_type& impl,
  200. boost::system::error_code& ec)
  201. {
  202. if (!is_open(impl))
  203. {
  204. ec = boost::asio::error::bad_descriptor;
  205. return ec;
  206. }
  207. BOOST_ASIO_HANDLER_OPERATION((iocp_service_.context(),
  208. "socket", &impl, impl.socket_, "cancel"));
  209. if (FARPROC cancel_io_ex_ptr = ::GetProcAddress(
  210. ::GetModuleHandleA("KERNEL32"), "CancelIoEx"))
  211. {
  212. // The version of Windows supports cancellation from any thread.
  213. typedef BOOL (WINAPI* cancel_io_ex_t)(HANDLE, LPOVERLAPPED);
  214. cancel_io_ex_t cancel_io_ex = (cancel_io_ex_t)cancel_io_ex_ptr;
  215. socket_type sock = impl.socket_;
  216. HANDLE sock_as_handle = reinterpret_cast<HANDLE>(sock);
  217. if (!cancel_io_ex(sock_as_handle, 0))
  218. {
  219. DWORD last_error = ::GetLastError();
  220. if (last_error == ERROR_NOT_FOUND)
  221. {
  222. // ERROR_NOT_FOUND means that there were no operations to be
  223. // cancelled. We swallow this error to match the behaviour on other
  224. // platforms.
  225. ec = boost::system::error_code();
  226. }
  227. else
  228. {
  229. ec = boost::system::error_code(last_error,
  230. boost::asio::error::get_system_category());
  231. }
  232. }
  233. else
  234. {
  235. ec = boost::system::error_code();
  236. }
  237. }
  238. #if defined(BOOST_ASIO_ENABLE_CANCELIO)
  239. else if (impl.safe_cancellation_thread_id_ == 0)
  240. {
  241. // No operations have been started, so there's nothing to cancel.
  242. ec = boost::system::error_code();
  243. }
  244. else if (impl.safe_cancellation_thread_id_ == ::GetCurrentThreadId())
  245. {
  246. // Asynchronous operations have been started from the current thread only,
  247. // so it is safe to try to cancel them using CancelIo.
  248. socket_type sock = impl.socket_;
  249. HANDLE sock_as_handle = reinterpret_cast<HANDLE>(sock);
  250. if (!::CancelIo(sock_as_handle))
  251. {
  252. DWORD last_error = ::GetLastError();
  253. ec = boost::system::error_code(last_error,
  254. boost::asio::error::get_system_category());
  255. }
  256. else
  257. {
  258. ec = boost::system::error_code();
  259. }
  260. }
  261. else
  262. {
  263. // Asynchronous operations have been started from more than one thread,
  264. // so cancellation is not safe.
  265. ec = boost::asio::error::operation_not_supported;
  266. }
  267. #else // defined(BOOST_ASIO_ENABLE_CANCELIO)
  268. else
  269. {
  270. // Cancellation is not supported as CancelIo may not be used.
  271. ec = boost::asio::error::operation_not_supported;
  272. }
  273. #endif // defined(BOOST_ASIO_ENABLE_CANCELIO)
  274. // Cancel any operations started via the reactor.
  275. if (!ec)
  276. {
  277. select_reactor* r = static_cast<select_reactor*>(
  278. interlocked_compare_exchange_pointer(
  279. reinterpret_cast<void**>(&reactor_), 0, 0));
  280. if (r)
  281. r->cancel_ops(impl.socket_, impl.reactor_data_);
  282. }
  283. return ec;
  284. }
  285. boost::system::error_code win_iocp_socket_service_base::do_open(
  286. win_iocp_socket_service_base::base_implementation_type& impl,
  287. int family, int type, int protocol, boost::system::error_code& ec)
  288. {
  289. if (is_open(impl))
  290. {
  291. ec = boost::asio::error::already_open;
  292. return ec;
  293. }
  294. socket_holder sock(socket_ops::socket(family, type, protocol, ec));
  295. if (sock.get() == invalid_socket)
  296. return ec;
  297. HANDLE sock_as_handle = reinterpret_cast<HANDLE>(sock.get());
  298. if (iocp_service_.register_handle(sock_as_handle, ec))
  299. return ec;
  300. impl.socket_ = sock.release();
  301. switch (type)
  302. {
  303. case SOCK_STREAM: impl.state_ = socket_ops::stream_oriented; break;
  304. case SOCK_DGRAM: impl.state_ = socket_ops::datagram_oriented; break;
  305. default: impl.state_ = 0; break;
  306. }
  307. impl.cancel_token_.reset(static_cast<void*>(0), socket_ops::noop_deleter());
  308. ec = boost::system::error_code();
  309. return ec;
  310. }
  311. boost::system::error_code win_iocp_socket_service_base::do_assign(
  312. win_iocp_socket_service_base::base_implementation_type& impl,
  313. int type, socket_type native_socket, boost::system::error_code& ec)
  314. {
  315. if (is_open(impl))
  316. {
  317. ec = boost::asio::error::already_open;
  318. return ec;
  319. }
  320. HANDLE sock_as_handle = reinterpret_cast<HANDLE>(native_socket);
  321. if (iocp_service_.register_handle(sock_as_handle, ec))
  322. return ec;
  323. impl.socket_ = native_socket;
  324. switch (type)
  325. {
  326. case SOCK_STREAM: impl.state_ = socket_ops::stream_oriented; break;
  327. case SOCK_DGRAM: impl.state_ = socket_ops::datagram_oriented; break;
  328. default: impl.state_ = 0; break;
  329. }
  330. impl.cancel_token_.reset(static_cast<void*>(0), socket_ops::noop_deleter());
  331. ec = boost::system::error_code();
  332. return ec;
  333. }
  334. void win_iocp_socket_service_base::start_send_op(
  335. win_iocp_socket_service_base::base_implementation_type& impl,
  336. WSABUF* buffers, std::size_t buffer_count,
  337. socket_base::message_flags flags, bool noop, operation* op)
  338. {
  339. update_cancellation_thread_id(impl);
  340. iocp_service_.work_started();
  341. if (noop)
  342. iocp_service_.on_completion(op);
  343. else if (!is_open(impl))
  344. iocp_service_.on_completion(op, boost::asio::error::bad_descriptor);
  345. else
  346. {
  347. DWORD bytes_transferred = 0;
  348. int result = ::WSASend(impl.socket_, buffers,
  349. static_cast<DWORD>(buffer_count), &bytes_transferred, flags, op, 0);
  350. DWORD last_error = ::WSAGetLastError();
  351. if (last_error == ERROR_PORT_UNREACHABLE)
  352. last_error = WSAECONNREFUSED;
  353. if (result != 0 && last_error != WSA_IO_PENDING)
  354. iocp_service_.on_completion(op, last_error, bytes_transferred);
  355. else
  356. iocp_service_.on_pending(op);
  357. }
  358. }
  359. void win_iocp_socket_service_base::start_send_to_op(
  360. win_iocp_socket_service_base::base_implementation_type& impl,
  361. WSABUF* buffers, std::size_t buffer_count,
  362. const socket_addr_type* addr, int addrlen,
  363. socket_base::message_flags flags, operation* op)
  364. {
  365. update_cancellation_thread_id(impl);
  366. iocp_service_.work_started();
  367. if (!is_open(impl))
  368. iocp_service_.on_completion(op, boost::asio::error::bad_descriptor);
  369. else
  370. {
  371. DWORD bytes_transferred = 0;
  372. int result = ::WSASendTo(impl.socket_, buffers,
  373. static_cast<DWORD>(buffer_count),
  374. &bytes_transferred, flags, addr, addrlen, op, 0);
  375. DWORD last_error = ::WSAGetLastError();
  376. if (last_error == ERROR_PORT_UNREACHABLE)
  377. last_error = WSAECONNREFUSED;
  378. if (result != 0 && last_error != WSA_IO_PENDING)
  379. iocp_service_.on_completion(op, last_error, bytes_transferred);
  380. else
  381. iocp_service_.on_pending(op);
  382. }
  383. }
  384. void win_iocp_socket_service_base::start_receive_op(
  385. win_iocp_socket_service_base::base_implementation_type& impl,
  386. WSABUF* buffers, std::size_t buffer_count,
  387. socket_base::message_flags flags, bool noop, operation* op)
  388. {
  389. update_cancellation_thread_id(impl);
  390. iocp_service_.work_started();
  391. if (noop)
  392. iocp_service_.on_completion(op);
  393. else if (!is_open(impl))
  394. iocp_service_.on_completion(op, boost::asio::error::bad_descriptor);
  395. else
  396. {
  397. DWORD bytes_transferred = 0;
  398. DWORD recv_flags = flags;
  399. int result = ::WSARecv(impl.socket_, buffers,
  400. static_cast<DWORD>(buffer_count),
  401. &bytes_transferred, &recv_flags, op, 0);
  402. DWORD last_error = ::WSAGetLastError();
  403. if (last_error == ERROR_NETNAME_DELETED)
  404. last_error = WSAECONNRESET;
  405. else if (last_error == ERROR_PORT_UNREACHABLE)
  406. last_error = WSAECONNREFUSED;
  407. if (result != 0 && last_error != WSA_IO_PENDING)
  408. iocp_service_.on_completion(op, last_error, bytes_transferred);
  409. else
  410. iocp_service_.on_pending(op);
  411. }
  412. }
  413. void win_iocp_socket_service_base::start_null_buffers_receive_op(
  414. win_iocp_socket_service_base::base_implementation_type& impl,
  415. socket_base::message_flags flags, reactor_op* op)
  416. {
  417. if ((impl.state_ & socket_ops::stream_oriented) != 0)
  418. {
  419. // For stream sockets on Windows, we may issue a 0-byte overlapped
  420. // WSARecv to wait until there is data available on the socket.
  421. ::WSABUF buf = { 0, 0 };
  422. start_receive_op(impl, &buf, 1, flags, false, op);
  423. }
  424. else
  425. {
  426. start_reactor_op(impl,
  427. (flags & socket_base::message_out_of_band)
  428. ? select_reactor::except_op : select_reactor::read_op,
  429. op);
  430. }
  431. }
  432. void win_iocp_socket_service_base::start_receive_from_op(
  433. win_iocp_socket_service_base::base_implementation_type& impl,
  434. WSABUF* buffers, std::size_t buffer_count, socket_addr_type* addr,
  435. socket_base::message_flags flags, int* addrlen, operation* op)
  436. {
  437. update_cancellation_thread_id(impl);
  438. iocp_service_.work_started();
  439. if (!is_open(impl))
  440. iocp_service_.on_completion(op, boost::asio::error::bad_descriptor);
  441. else
  442. {
  443. DWORD bytes_transferred = 0;
  444. DWORD recv_flags = flags;
  445. int result = ::WSARecvFrom(impl.socket_, buffers,
  446. static_cast<DWORD>(buffer_count),
  447. &bytes_transferred, &recv_flags, addr, addrlen, op, 0);
  448. DWORD last_error = ::WSAGetLastError();
  449. if (last_error == ERROR_PORT_UNREACHABLE)
  450. last_error = WSAECONNREFUSED;
  451. if (result != 0 && last_error != WSA_IO_PENDING)
  452. iocp_service_.on_completion(op, last_error, bytes_transferred);
  453. else
  454. iocp_service_.on_pending(op);
  455. }
  456. }
  457. void win_iocp_socket_service_base::start_accept_op(
  458. win_iocp_socket_service_base::base_implementation_type& impl,
  459. bool peer_is_open, socket_holder& new_socket, int family, int type,
  460. int protocol, void* output_buffer, DWORD address_length, operation* op)
  461. {
  462. update_cancellation_thread_id(impl);
  463. iocp_service_.work_started();
  464. if (!is_open(impl))
  465. iocp_service_.on_completion(op, boost::asio::error::bad_descriptor);
  466. else if (peer_is_open)
  467. iocp_service_.on_completion(op, boost::asio::error::already_open);
  468. else
  469. {
  470. boost::system::error_code ec;
  471. new_socket.reset(socket_ops::socket(family, type, protocol, ec));
  472. if (new_socket.get() == invalid_socket)
  473. iocp_service_.on_completion(op, ec);
  474. else
  475. {
  476. DWORD bytes_read = 0;
  477. BOOL result = ::AcceptEx(impl.socket_, new_socket.get(), output_buffer,
  478. 0, address_length, address_length, &bytes_read, op);
  479. DWORD last_error = ::WSAGetLastError();
  480. if (!result && last_error != WSA_IO_PENDING)
  481. iocp_service_.on_completion(op, last_error);
  482. else
  483. iocp_service_.on_pending(op);
  484. }
  485. }
  486. }
  487. void win_iocp_socket_service_base::restart_accept_op(
  488. socket_type s, socket_holder& new_socket, int family, int type,
  489. int protocol, void* output_buffer, DWORD address_length, operation* op)
  490. {
  491. new_socket.reset();
  492. iocp_service_.work_started();
  493. boost::system::error_code ec;
  494. new_socket.reset(socket_ops::socket(family, type, protocol, ec));
  495. if (new_socket.get() == invalid_socket)
  496. iocp_service_.on_completion(op, ec);
  497. else
  498. {
  499. DWORD bytes_read = 0;
  500. BOOL result = ::AcceptEx(s, new_socket.get(), output_buffer,
  501. 0, address_length, address_length, &bytes_read, op);
  502. DWORD last_error = ::WSAGetLastError();
  503. if (!result && last_error != WSA_IO_PENDING)
  504. iocp_service_.on_completion(op, last_error);
  505. else
  506. iocp_service_.on_pending(op);
  507. }
  508. }
  509. void win_iocp_socket_service_base::start_reactor_op(
  510. win_iocp_socket_service_base::base_implementation_type& impl,
  511. int op_type, reactor_op* op)
  512. {
  513. select_reactor& r = get_reactor();
  514. update_cancellation_thread_id(impl);
  515. if (is_open(impl))
  516. {
  517. r.start_op(op_type, impl.socket_, impl.reactor_data_, op, false, false);
  518. return;
  519. }
  520. else
  521. op->ec_ = boost::asio::error::bad_descriptor;
  522. iocp_service_.post_immediate_completion(op, false);
  523. }
  524. void win_iocp_socket_service_base::start_connect_op(
  525. win_iocp_socket_service_base::base_implementation_type& impl,
  526. int family, int type, const socket_addr_type* addr,
  527. std::size_t addrlen, win_iocp_socket_connect_op_base* op)
  528. {
  529. // If ConnectEx is available, use that.
  530. if (family == BOOST_ASIO_OS_DEF(AF_INET)
  531. || family == BOOST_ASIO_OS_DEF(AF_INET6))
  532. {
  533. if (connect_ex_fn connect_ex = get_connect_ex(impl, type))
  534. {
  535. union address_union
  536. {
  537. socket_addr_type base;
  538. sockaddr_in4_type v4;
  539. sockaddr_in6_type v6;
  540. } a;
  541. using namespace std; // For memset.
  542. memset(&a, 0, sizeof(a));
  543. a.base.sa_family = family;
  544. socket_ops::bind(impl.socket_, &a.base,
  545. family == BOOST_ASIO_OS_DEF(AF_INET)
  546. ? sizeof(a.v4) : sizeof(a.v6), op->ec_);
  547. if (op->ec_ && op->ec_ != boost::asio::error::invalid_argument)
  548. {
  549. iocp_service_.post_immediate_completion(op, false);
  550. return;
  551. }
  552. op->connect_ex_ = true;
  553. update_cancellation_thread_id(impl);
  554. iocp_service_.work_started();
  555. BOOL result = connect_ex(impl.socket_,
  556. addr, static_cast<int>(addrlen), 0, 0, 0, op);
  557. DWORD last_error = ::WSAGetLastError();
  558. if (!result && last_error != WSA_IO_PENDING)
  559. iocp_service_.on_completion(op, last_error);
  560. else
  561. iocp_service_.on_pending(op);
  562. return;
  563. }
  564. }
  565. // Otherwise, fall back to a reactor-based implementation.
  566. select_reactor& r = get_reactor();
  567. update_cancellation_thread_id(impl);
  568. if ((impl.state_ & socket_ops::non_blocking) != 0
  569. || socket_ops::set_internal_non_blocking(
  570. impl.socket_, impl.state_, true, op->ec_))
  571. {
  572. if (socket_ops::connect(impl.socket_, addr, addrlen, op->ec_) != 0)
  573. {
  574. if (op->ec_ == boost::asio::error::in_progress
  575. || op->ec_ == boost::asio::error::would_block)
  576. {
  577. op->ec_ = boost::system::error_code();
  578. r.start_op(select_reactor::connect_op, impl.socket_,
  579. impl.reactor_data_, op, false, false);
  580. return;
  581. }
  582. }
  583. }
  584. r.post_immediate_completion(op, false);
  585. }
  586. void win_iocp_socket_service_base::close_for_destruction(
  587. win_iocp_socket_service_base::base_implementation_type& impl)
  588. {
  589. if (is_open(impl))
  590. {
  591. BOOST_ASIO_HANDLER_OPERATION((iocp_service_.context(),
  592. "socket", &impl, impl.socket_, "close"));
  593. // Check if the reactor was created, in which case we need to close the
  594. // socket on the reactor as well to cancel any operations that might be
  595. // running there.
  596. select_reactor* r = static_cast<select_reactor*>(
  597. interlocked_compare_exchange_pointer(
  598. reinterpret_cast<void**>(&reactor_), 0, 0));
  599. if (r)
  600. r->deregister_descriptor(impl.socket_, impl.reactor_data_, true);
  601. boost::system::error_code ignored_ec;
  602. socket_ops::close(impl.socket_, impl.state_, true, ignored_ec);
  603. if (r)
  604. r->cleanup_descriptor_data(impl.reactor_data_);
  605. }
  606. impl.socket_ = invalid_socket;
  607. impl.state_ = 0;
  608. impl.cancel_token_.reset();
  609. #if defined(BOOST_ASIO_ENABLE_CANCELIO)
  610. impl.safe_cancellation_thread_id_ = 0;
  611. #endif // defined(BOOST_ASIO_ENABLE_CANCELIO)
  612. }
  613. void win_iocp_socket_service_base::update_cancellation_thread_id(
  614. win_iocp_socket_service_base::base_implementation_type& impl)
  615. {
  616. #if defined(BOOST_ASIO_ENABLE_CANCELIO)
  617. if (impl.safe_cancellation_thread_id_ == 0)
  618. impl.safe_cancellation_thread_id_ = ::GetCurrentThreadId();
  619. else if (impl.safe_cancellation_thread_id_ != ::GetCurrentThreadId())
  620. impl.safe_cancellation_thread_id_ = ~DWORD(0);
  621. #else // defined(BOOST_ASIO_ENABLE_CANCELIO)
  622. (void)impl;
  623. #endif // defined(BOOST_ASIO_ENABLE_CANCELIO)
  624. }
  625. select_reactor& win_iocp_socket_service_base::get_reactor()
  626. {
  627. select_reactor* r = static_cast<select_reactor*>(
  628. interlocked_compare_exchange_pointer(
  629. reinterpret_cast<void**>(&reactor_), 0, 0));
  630. if (!r)
  631. {
  632. r = &(use_service<select_reactor>(io_context_));
  633. interlocked_exchange_pointer(reinterpret_cast<void**>(&reactor_), r);
  634. }
  635. return *r;
  636. }
  637. win_iocp_socket_service_base::connect_ex_fn
  638. win_iocp_socket_service_base::get_connect_ex(
  639. win_iocp_socket_service_base::base_implementation_type& impl, int type)
  640. {
  641. #if defined(BOOST_ASIO_DISABLE_CONNECTEX)
  642. (void)impl;
  643. (void)type;
  644. return 0;
  645. #else // defined(BOOST_ASIO_DISABLE_CONNECTEX)
  646. if (type != BOOST_ASIO_OS_DEF(SOCK_STREAM)
  647. && type != BOOST_ASIO_OS_DEF(SOCK_SEQPACKET))
  648. return 0;
  649. void* ptr = interlocked_compare_exchange_pointer(&connect_ex_, 0, 0);
  650. if (!ptr)
  651. {
  652. GUID guid = { 0x25a207b9, 0xddf3, 0x4660,
  653. { 0x8e, 0xe9, 0x76, 0xe5, 0x8c, 0x74, 0x06, 0x3e } };
  654. DWORD bytes = 0;
  655. if (::WSAIoctl(impl.socket_, SIO_GET_EXTENSION_FUNCTION_POINTER,
  656. &guid, sizeof(guid), &ptr, sizeof(ptr), &bytes, 0, 0) != 0)
  657. {
  658. // Set connect_ex_ to a special value to indicate that ConnectEx is
  659. // unavailable. That way we won't bother trying to look it up again.
  660. ptr = this;
  661. }
  662. interlocked_exchange_pointer(&connect_ex_, ptr);
  663. }
  664. return reinterpret_cast<connect_ex_fn>(ptr == this ? 0 : ptr);
  665. #endif // defined(BOOST_ASIO_DISABLE_CONNECTEX)
  666. }
  667. win_iocp_socket_service_base::nt_set_info_fn
  668. win_iocp_socket_service_base::get_nt_set_info()
  669. {
  670. void* ptr = interlocked_compare_exchange_pointer(&nt_set_info_, 0, 0);
  671. if (!ptr)
  672. {
  673. if (HMODULE h = ::GetModuleHandleA("NTDLL.DLL"))
  674. ptr = reinterpret_cast<void*>(GetProcAddress(h, "NtSetInformationFile"));
  675. // On failure, set nt_set_info_ to a special value to indicate that the
  676. // NtSetInformationFile function is unavailable. That way we won't bother
  677. // trying to look it up again.
  678. interlocked_exchange_pointer(&nt_set_info_, ptr ? ptr : this);
  679. }
  680. return reinterpret_cast<nt_set_info_fn>(ptr == this ? 0 : ptr);
  681. }
  682. void* win_iocp_socket_service_base::interlocked_compare_exchange_pointer(
  683. void** dest, void* exch, void* cmp)
  684. {
  685. #if defined(_M_IX86)
  686. return reinterpret_cast<void*>(InterlockedCompareExchange(
  687. reinterpret_cast<PLONG>(dest), reinterpret_cast<LONG>(exch),
  688. reinterpret_cast<LONG>(cmp)));
  689. #else
  690. return InterlockedCompareExchangePointer(dest, exch, cmp);
  691. #endif
  692. }
  693. void* win_iocp_socket_service_base::interlocked_exchange_pointer(
  694. void** dest, void* val)
  695. {
  696. #if defined(_M_IX86)
  697. return reinterpret_cast<void*>(InterlockedExchange(
  698. reinterpret_cast<PLONG>(dest), reinterpret_cast<LONG>(val)));
  699. #else
  700. return InterlockedExchangePointer(dest, val);
  701. #endif
  702. }
  703. } // namespace detail
  704. } // namespace asio
  705. } // namespace boost
  706. #include <boost/asio/detail/pop_options.hpp>
  707. #endif // defined(BOOST_ASIO_HAS_IOCP)
  708. #endif // BOOST_ASIO_DETAIL_IMPL_WIN_IOCP_SOCKET_SERVICE_BASE_IPP