winrt_ssocket_service_base.ipp 17 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631
  1. //
  2. // detail/impl/winrt_ssocket_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_WINRT_SSOCKET_SERVICE_BASE_IPP
  11. #define BOOST_ASIO_DETAIL_IMPL_WINRT_SSOCKET_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_WINDOWS_RUNTIME)
  17. #include <cstring>
  18. #include <boost/asio/detail/winrt_ssocket_service_base.hpp>
  19. #include <boost/asio/detail/winrt_async_op.hpp>
  20. #include <boost/asio/detail/winrt_utils.hpp>
  21. #include <boost/asio/detail/push_options.hpp>
  22. namespace boost {
  23. namespace asio {
  24. namespace detail {
  25. winrt_ssocket_service_base::winrt_ssocket_service_base(
  26. boost::asio::io_context& io_context)
  27. : io_context_(use_service<io_context_impl>(io_context)),
  28. async_manager_(use_service<winrt_async_manager>(io_context)),
  29. mutex_(),
  30. impl_list_(0)
  31. {
  32. }
  33. void winrt_ssocket_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. boost::system::error_code ignored_ec;
  41. close(*impl, ignored_ec);
  42. impl = impl->next_;
  43. }
  44. }
  45. void winrt_ssocket_service_base::construct(
  46. winrt_ssocket_service_base::base_implementation_type& impl)
  47. {
  48. // Insert implementation into linked list of all implementations.
  49. boost::asio::detail::mutex::scoped_lock lock(mutex_);
  50. impl.next_ = impl_list_;
  51. impl.prev_ = 0;
  52. if (impl_list_)
  53. impl_list_->prev_ = &impl;
  54. impl_list_ = &impl;
  55. }
  56. void winrt_ssocket_service_base::base_move_construct(
  57. winrt_ssocket_service_base::base_implementation_type& impl,
  58. winrt_ssocket_service_base::base_implementation_type& other_impl)
  59. {
  60. impl.socket_ = other_impl.socket_;
  61. other_impl.socket_ = nullptr;
  62. // Insert implementation into linked list of all implementations.
  63. boost::asio::detail::mutex::scoped_lock lock(mutex_);
  64. impl.next_ = impl_list_;
  65. impl.prev_ = 0;
  66. if (impl_list_)
  67. impl_list_->prev_ = &impl;
  68. impl_list_ = &impl;
  69. }
  70. void winrt_ssocket_service_base::base_move_assign(
  71. winrt_ssocket_service_base::base_implementation_type& impl,
  72. winrt_ssocket_service_base& other_service,
  73. winrt_ssocket_service_base::base_implementation_type& other_impl)
  74. {
  75. boost::system::error_code ignored_ec;
  76. close(impl, ignored_ec);
  77. if (this != &other_service)
  78. {
  79. // Remove implementation from linked list of all implementations.
  80. boost::asio::detail::mutex::scoped_lock lock(mutex_);
  81. if (impl_list_ == &impl)
  82. impl_list_ = impl.next_;
  83. if (impl.prev_)
  84. impl.prev_->next_ = impl.next_;
  85. if (impl.next_)
  86. impl.next_->prev_= impl.prev_;
  87. impl.next_ = 0;
  88. impl.prev_ = 0;
  89. }
  90. impl.socket_ = other_impl.socket_;
  91. other_impl.socket_ = nullptr;
  92. if (this != &other_service)
  93. {
  94. // Insert implementation into linked list of all implementations.
  95. boost::asio::detail::mutex::scoped_lock lock(other_service.mutex_);
  96. impl.next_ = other_service.impl_list_;
  97. impl.prev_ = 0;
  98. if (other_service.impl_list_)
  99. other_service.impl_list_->prev_ = &impl;
  100. other_service.impl_list_ = &impl;
  101. }
  102. }
  103. void winrt_ssocket_service_base::destroy(
  104. winrt_ssocket_service_base::base_implementation_type& impl)
  105. {
  106. boost::system::error_code ignored_ec;
  107. close(impl, ignored_ec);
  108. // Remove implementation from linked list of all implementations.
  109. boost::asio::detail::mutex::scoped_lock lock(mutex_);
  110. if (impl_list_ == &impl)
  111. impl_list_ = impl.next_;
  112. if (impl.prev_)
  113. impl.prev_->next_ = impl.next_;
  114. if (impl.next_)
  115. impl.next_->prev_= impl.prev_;
  116. impl.next_ = 0;
  117. impl.prev_ = 0;
  118. }
  119. boost::system::error_code winrt_ssocket_service_base::close(
  120. winrt_ssocket_service_base::base_implementation_type& impl,
  121. boost::system::error_code& ec)
  122. {
  123. if (impl.socket_)
  124. {
  125. delete impl.socket_;
  126. impl.socket_ = nullptr;
  127. }
  128. ec = boost::system::error_code();
  129. return ec;
  130. }
  131. winrt_ssocket_service_base::native_handle_type
  132. winrt_ssocket_service_base::release(
  133. winrt_ssocket_service_base::base_implementation_type& impl,
  134. boost::system::error_code& ec)
  135. {
  136. if (!is_open(impl))
  137. return nullptr;
  138. cancel(impl, ec);
  139. if (ec)
  140. return nullptr;
  141. native_handle_type tmp = impl.socket_;
  142. impl.socket_ = nullptr;
  143. return tmp;
  144. }
  145. std::size_t winrt_ssocket_service_base::do_get_endpoint(
  146. const base_implementation_type& impl, bool local,
  147. void* addr, std::size_t addr_len, boost::system::error_code& ec) const
  148. {
  149. if (!is_open(impl))
  150. {
  151. ec = boost::asio::error::bad_descriptor;
  152. return addr_len;
  153. }
  154. try
  155. {
  156. std::string addr_string = winrt_utils::string(local
  157. ? impl.socket_->Information->LocalAddress->CanonicalName
  158. : impl.socket_->Information->RemoteAddress->CanonicalName);
  159. unsigned short port = winrt_utils::integer(local
  160. ? impl.socket_->Information->LocalPort
  161. : impl.socket_->Information->RemotePort);
  162. unsigned long scope = 0;
  163. switch (reinterpret_cast<const socket_addr_type*>(addr)->sa_family)
  164. {
  165. case BOOST_ASIO_OS_DEF(AF_INET):
  166. if (addr_len < sizeof(sockaddr_in4_type))
  167. {
  168. ec = boost::asio::error::invalid_argument;
  169. return addr_len;
  170. }
  171. else
  172. {
  173. socket_ops::inet_pton(BOOST_ASIO_OS_DEF(AF_INET), addr_string.c_str(),
  174. &reinterpret_cast<sockaddr_in4_type*>(addr)->sin_addr, &scope, ec);
  175. reinterpret_cast<sockaddr_in4_type*>(addr)->sin_port
  176. = socket_ops::host_to_network_short(port);
  177. ec = boost::system::error_code();
  178. return sizeof(sockaddr_in4_type);
  179. }
  180. case BOOST_ASIO_OS_DEF(AF_INET6):
  181. if (addr_len < sizeof(sockaddr_in6_type))
  182. {
  183. ec = boost::asio::error::invalid_argument;
  184. return addr_len;
  185. }
  186. else
  187. {
  188. socket_ops::inet_pton(BOOST_ASIO_OS_DEF(AF_INET6), addr_string.c_str(),
  189. &reinterpret_cast<sockaddr_in6_type*>(addr)->sin6_addr, &scope, ec);
  190. reinterpret_cast<sockaddr_in6_type*>(addr)->sin6_port
  191. = socket_ops::host_to_network_short(port);
  192. ec = boost::system::error_code();
  193. return sizeof(sockaddr_in6_type);
  194. }
  195. default:
  196. ec = boost::asio::error::address_family_not_supported;
  197. return addr_len;
  198. }
  199. }
  200. catch (Platform::Exception^ e)
  201. {
  202. ec = boost::system::error_code(e->HResult,
  203. boost::system::system_category());
  204. return addr_len;
  205. }
  206. }
  207. boost::system::error_code winrt_ssocket_service_base::do_set_option(
  208. winrt_ssocket_service_base::base_implementation_type& impl,
  209. int level, int optname, const void* optval,
  210. std::size_t optlen, boost::system::error_code& ec)
  211. {
  212. if (!is_open(impl))
  213. {
  214. ec = boost::asio::error::bad_descriptor;
  215. return ec;
  216. }
  217. try
  218. {
  219. if (level == BOOST_ASIO_OS_DEF(SOL_SOCKET)
  220. && optname == BOOST_ASIO_OS_DEF(SO_KEEPALIVE))
  221. {
  222. if (optlen == sizeof(int))
  223. {
  224. int value = 0;
  225. std::memcpy(&value, optval, optlen);
  226. impl.socket_->Control->KeepAlive = !!value;
  227. ec = boost::system::error_code();
  228. }
  229. else
  230. {
  231. ec = boost::asio::error::invalid_argument;
  232. }
  233. }
  234. else if (level == BOOST_ASIO_OS_DEF(IPPROTO_TCP)
  235. && optname == BOOST_ASIO_OS_DEF(TCP_NODELAY))
  236. {
  237. if (optlen == sizeof(int))
  238. {
  239. int value = 0;
  240. std::memcpy(&value, optval, optlen);
  241. impl.socket_->Control->NoDelay = !!value;
  242. ec = boost::system::error_code();
  243. }
  244. else
  245. {
  246. ec = boost::asio::error::invalid_argument;
  247. }
  248. }
  249. else
  250. {
  251. ec = boost::asio::error::invalid_argument;
  252. }
  253. }
  254. catch (Platform::Exception^ e)
  255. {
  256. ec = boost::system::error_code(e->HResult,
  257. boost::system::system_category());
  258. }
  259. return ec;
  260. }
  261. void winrt_ssocket_service_base::do_get_option(
  262. const winrt_ssocket_service_base::base_implementation_type& impl,
  263. int level, int optname, void* optval,
  264. std::size_t* optlen, boost::system::error_code& ec) const
  265. {
  266. if (!is_open(impl))
  267. {
  268. ec = boost::asio::error::bad_descriptor;
  269. return;
  270. }
  271. try
  272. {
  273. if (level == BOOST_ASIO_OS_DEF(SOL_SOCKET)
  274. && optname == BOOST_ASIO_OS_DEF(SO_KEEPALIVE))
  275. {
  276. if (*optlen >= sizeof(int))
  277. {
  278. int value = impl.socket_->Control->KeepAlive ? 1 : 0;
  279. std::memcpy(optval, &value, sizeof(int));
  280. *optlen = sizeof(int);
  281. ec = boost::system::error_code();
  282. }
  283. else
  284. {
  285. ec = boost::asio::error::invalid_argument;
  286. }
  287. }
  288. else if (level == BOOST_ASIO_OS_DEF(IPPROTO_TCP)
  289. && optname == BOOST_ASIO_OS_DEF(TCP_NODELAY))
  290. {
  291. if (*optlen >= sizeof(int))
  292. {
  293. int value = impl.socket_->Control->NoDelay ? 1 : 0;
  294. std::memcpy(optval, &value, sizeof(int));
  295. *optlen = sizeof(int);
  296. ec = boost::system::error_code();
  297. }
  298. else
  299. {
  300. ec = boost::asio::error::invalid_argument;
  301. }
  302. }
  303. else
  304. {
  305. ec = boost::asio::error::invalid_argument;
  306. }
  307. }
  308. catch (Platform::Exception^ e)
  309. {
  310. ec = boost::system::error_code(e->HResult,
  311. boost::system::system_category());
  312. }
  313. }
  314. boost::system::error_code winrt_ssocket_service_base::do_connect(
  315. winrt_ssocket_service_base::base_implementation_type& impl,
  316. const void* addr, boost::system::error_code& ec)
  317. {
  318. if (!is_open(impl))
  319. {
  320. ec = boost::asio::error::bad_descriptor;
  321. return ec;
  322. }
  323. char addr_string[max_addr_v6_str_len];
  324. unsigned short port;
  325. switch (reinterpret_cast<const socket_addr_type*>(addr)->sa_family)
  326. {
  327. case BOOST_ASIO_OS_DEF(AF_INET):
  328. socket_ops::inet_ntop(BOOST_ASIO_OS_DEF(AF_INET),
  329. &reinterpret_cast<const sockaddr_in4_type*>(addr)->sin_addr,
  330. addr_string, sizeof(addr_string), 0, ec);
  331. port = socket_ops::network_to_host_short(
  332. reinterpret_cast<const sockaddr_in4_type*>(addr)->sin_port);
  333. break;
  334. case BOOST_ASIO_OS_DEF(AF_INET6):
  335. socket_ops::inet_ntop(BOOST_ASIO_OS_DEF(AF_INET6),
  336. &reinterpret_cast<const sockaddr_in6_type*>(addr)->sin6_addr,
  337. addr_string, sizeof(addr_string), 0, ec);
  338. port = socket_ops::network_to_host_short(
  339. reinterpret_cast<const sockaddr_in6_type*>(addr)->sin6_port);
  340. break;
  341. default:
  342. ec = boost::asio::error::address_family_not_supported;
  343. return ec;
  344. }
  345. if (!ec) try
  346. {
  347. async_manager_.sync(impl.socket_->ConnectAsync(
  348. ref new Windows::Networking::HostName(
  349. winrt_utils::string(addr_string)),
  350. winrt_utils::string(port)), ec);
  351. }
  352. catch (Platform::Exception^ e)
  353. {
  354. ec = boost::system::error_code(e->HResult,
  355. boost::system::system_category());
  356. }
  357. return ec;
  358. }
  359. void winrt_ssocket_service_base::start_connect_op(
  360. winrt_ssocket_service_base::base_implementation_type& impl,
  361. const void* addr, winrt_async_op<void>* op, bool is_continuation)
  362. {
  363. if (!is_open(impl))
  364. {
  365. op->ec_ = boost::asio::error::bad_descriptor;
  366. io_context_.post_immediate_completion(op, is_continuation);
  367. return;
  368. }
  369. char addr_string[max_addr_v6_str_len];
  370. unsigned short port = 0;
  371. switch (reinterpret_cast<const socket_addr_type*>(addr)->sa_family)
  372. {
  373. case BOOST_ASIO_OS_DEF(AF_INET):
  374. socket_ops::inet_ntop(BOOST_ASIO_OS_DEF(AF_INET),
  375. &reinterpret_cast<const sockaddr_in4_type*>(addr)->sin_addr,
  376. addr_string, sizeof(addr_string), 0, op->ec_);
  377. port = socket_ops::network_to_host_short(
  378. reinterpret_cast<const sockaddr_in4_type*>(addr)->sin_port);
  379. break;
  380. case BOOST_ASIO_OS_DEF(AF_INET6):
  381. socket_ops::inet_ntop(BOOST_ASIO_OS_DEF(AF_INET6),
  382. &reinterpret_cast<const sockaddr_in6_type*>(addr)->sin6_addr,
  383. addr_string, sizeof(addr_string), 0, op->ec_);
  384. port = socket_ops::network_to_host_short(
  385. reinterpret_cast<const sockaddr_in6_type*>(addr)->sin6_port);
  386. break;
  387. default:
  388. op->ec_ = boost::asio::error::address_family_not_supported;
  389. break;
  390. }
  391. if (op->ec_)
  392. {
  393. io_context_.post_immediate_completion(op, is_continuation);
  394. return;
  395. }
  396. try
  397. {
  398. async_manager_.async(impl.socket_->ConnectAsync(
  399. ref new Windows::Networking::HostName(
  400. winrt_utils::string(addr_string)),
  401. winrt_utils::string(port)), op);
  402. }
  403. catch (Platform::Exception^ e)
  404. {
  405. op->ec_ = boost::system::error_code(
  406. e->HResult, boost::system::system_category());
  407. io_context_.post_immediate_completion(op, is_continuation);
  408. }
  409. }
  410. std::size_t winrt_ssocket_service_base::do_send(
  411. winrt_ssocket_service_base::base_implementation_type& impl,
  412. const boost::asio::const_buffer& data,
  413. socket_base::message_flags flags, boost::system::error_code& ec)
  414. {
  415. if (flags)
  416. {
  417. ec = boost::asio::error::operation_not_supported;
  418. return 0;
  419. }
  420. if (!is_open(impl))
  421. {
  422. ec = boost::asio::error::bad_descriptor;
  423. return 0;
  424. }
  425. try
  426. {
  427. buffer_sequence_adapter<boost::asio::const_buffer,
  428. boost::asio::const_buffer> bufs(boost::asio::buffer(data));
  429. if (bufs.all_empty())
  430. {
  431. ec = boost::system::error_code();
  432. return 0;
  433. }
  434. return async_manager_.sync(
  435. impl.socket_->OutputStream->WriteAsync(bufs.buffers()[0]), ec);
  436. }
  437. catch (Platform::Exception^ e)
  438. {
  439. ec = boost::system::error_code(e->HResult,
  440. boost::system::system_category());
  441. return 0;
  442. }
  443. }
  444. void winrt_ssocket_service_base::start_send_op(
  445. winrt_ssocket_service_base::base_implementation_type& impl,
  446. const boost::asio::const_buffer& data, socket_base::message_flags flags,
  447. winrt_async_op<unsigned int>* op, bool is_continuation)
  448. {
  449. if (flags)
  450. {
  451. op->ec_ = boost::asio::error::operation_not_supported;
  452. io_context_.post_immediate_completion(op, is_continuation);
  453. return;
  454. }
  455. if (!is_open(impl))
  456. {
  457. op->ec_ = boost::asio::error::bad_descriptor;
  458. io_context_.post_immediate_completion(op, is_continuation);
  459. return;
  460. }
  461. try
  462. {
  463. buffer_sequence_adapter<boost::asio::const_buffer,
  464. boost::asio::const_buffer> bufs(boost::asio::buffer(data));
  465. if (bufs.all_empty())
  466. {
  467. io_context_.post_immediate_completion(op, is_continuation);
  468. return;
  469. }
  470. async_manager_.async(
  471. impl.socket_->OutputStream->WriteAsync(bufs.buffers()[0]), op);
  472. }
  473. catch (Platform::Exception^ e)
  474. {
  475. op->ec_ = boost::system::error_code(e->HResult,
  476. boost::system::system_category());
  477. io_context_.post_immediate_completion(op, is_continuation);
  478. }
  479. }
  480. std::size_t winrt_ssocket_service_base::do_receive(
  481. winrt_ssocket_service_base::base_implementation_type& impl,
  482. const boost::asio::mutable_buffer& data,
  483. socket_base::message_flags flags, boost::system::error_code& ec)
  484. {
  485. if (flags)
  486. {
  487. ec = boost::asio::error::operation_not_supported;
  488. return 0;
  489. }
  490. if (!is_open(impl))
  491. {
  492. ec = boost::asio::error::bad_descriptor;
  493. return 0;
  494. }
  495. try
  496. {
  497. buffer_sequence_adapter<boost::asio::mutable_buffer,
  498. boost::asio::mutable_buffer> bufs(boost::asio::buffer(data));
  499. if (bufs.all_empty())
  500. {
  501. ec = boost::system::error_code();
  502. return 0;
  503. }
  504. async_manager_.sync(
  505. impl.socket_->InputStream->ReadAsync(
  506. bufs.buffers()[0], bufs.buffers()[0]->Capacity,
  507. Windows::Storage::Streams::InputStreamOptions::Partial), ec);
  508. std::size_t bytes_transferred = bufs.buffers()[0]->Length;
  509. if (bytes_transferred == 0 && !ec)
  510. {
  511. ec = boost::asio::error::eof;
  512. }
  513. return bytes_transferred;
  514. }
  515. catch (Platform::Exception^ e)
  516. {
  517. ec = boost::system::error_code(e->HResult,
  518. boost::system::system_category());
  519. return 0;
  520. }
  521. }
  522. void winrt_ssocket_service_base::start_receive_op(
  523. winrt_ssocket_service_base::base_implementation_type& impl,
  524. const boost::asio::mutable_buffer& data, socket_base::message_flags flags,
  525. winrt_async_op<Windows::Storage::Streams::IBuffer^>* op,
  526. bool is_continuation)
  527. {
  528. if (flags)
  529. {
  530. op->ec_ = boost::asio::error::operation_not_supported;
  531. io_context_.post_immediate_completion(op, is_continuation);
  532. return;
  533. }
  534. if (!is_open(impl))
  535. {
  536. op->ec_ = boost::asio::error::bad_descriptor;
  537. io_context_.post_immediate_completion(op, is_continuation);
  538. return;
  539. }
  540. try
  541. {
  542. buffer_sequence_adapter<boost::asio::mutable_buffer,
  543. boost::asio::mutable_buffer> bufs(boost::asio::buffer(data));
  544. if (bufs.all_empty())
  545. {
  546. io_context_.post_immediate_completion(op, is_continuation);
  547. return;
  548. }
  549. async_manager_.async(
  550. impl.socket_->InputStream->ReadAsync(
  551. bufs.buffers()[0], bufs.buffers()[0]->Capacity,
  552. Windows::Storage::Streams::InputStreamOptions::Partial), op);
  553. }
  554. catch (Platform::Exception^ e)
  555. {
  556. op->ec_ = boost::system::error_code(e->HResult,
  557. boost::system::system_category());
  558. io_context_.post_immediate_completion(op, is_continuation);
  559. }
  560. }
  561. } // namespace detail
  562. } // namespace asio
  563. } // namespace boost
  564. #include <boost/asio/detail/pop_options.hpp>
  565. #endif // defined(BOOST_ASIO_WINDOWS_RUNTIME)
  566. #endif // BOOST_ASIO_DETAIL_IMPL_WINRT_SSOCKET_SERVICE_BASE_IPP