2 // detail/impl/winrt_ssocket_service_base.ipp
3 // ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
5 // Copyright (c) 2003-2019 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_IMPL_WINRT_SSOCKET_SERVICE_BASE_IPP
12 #define BOOST_ASIO_DETAIL_IMPL_WINRT_SSOCKET_SERVICE_BASE_IPP
14 #if defined(_MSC_VER) && (_MSC_VER >= 1200)
16 #endif // defined(_MSC_VER) && (_MSC_VER >= 1200)
18 #include <boost/asio/detail/config.hpp>
20 #if defined(BOOST_ASIO_WINDOWS_RUNTIME)
23 #include <boost/asio/detail/winrt_ssocket_service_base.hpp>
24 #include <boost/asio/detail/winrt_async_op.hpp>
25 #include <boost/asio/detail/winrt_utils.hpp>
27 #include <boost/asio/detail/push_options.hpp>
33 winrt_ssocket_service_base::winrt_ssocket_service_base(
34 execution_context& context)
35 : scheduler_(use_service<scheduler_impl>(context)),
36 async_manager_(use_service<winrt_async_manager>(context)),
42 void winrt_ssocket_service_base::base_shutdown()
44 // Close all implementations, causing all operations to complete.
45 boost::asio::detail::mutex::scoped_lock lock(mutex_);
46 base_implementation_type* impl = impl_list_;
49 boost::system::error_code ignored_ec;
50 close(*impl, ignored_ec);
55 void winrt_ssocket_service_base::construct(
56 winrt_ssocket_service_base::base_implementation_type& impl)
58 // Insert implementation into linked list of all implementations.
59 boost::asio::detail::mutex::scoped_lock lock(mutex_);
60 impl.next_ = impl_list_;
63 impl_list_->prev_ = &impl;
67 void winrt_ssocket_service_base::base_move_construct(
68 winrt_ssocket_service_base::base_implementation_type& impl,
69 winrt_ssocket_service_base::base_implementation_type& other_impl)
72 impl.socket_ = other_impl.socket_;
73 other_impl.socket_ = nullptr;
75 // Insert implementation into linked list of all implementations.
76 boost::asio::detail::mutex::scoped_lock lock(mutex_);
77 impl.next_ = impl_list_;
80 impl_list_->prev_ = &impl;
84 void winrt_ssocket_service_base::base_move_assign(
85 winrt_ssocket_service_base::base_implementation_type& impl,
86 winrt_ssocket_service_base& other_service,
87 winrt_ssocket_service_base::base_implementation_type& other_impl)
89 boost::system::error_code ignored_ec;
90 close(impl, ignored_ec);
92 if (this != &other_service)
94 // Remove implementation from linked list of all implementations.
95 boost::asio::detail::mutex::scoped_lock lock(mutex_);
96 if (impl_list_ == &impl)
97 impl_list_ = impl.next_;
99 impl.prev_->next_ = impl.next_;
101 impl.next_->prev_= impl.prev_;
106 impl.socket_ = other_impl.socket_;
107 other_impl.socket_ = nullptr;
109 if (this != &other_service)
111 // Insert implementation into linked list of all implementations.
112 boost::asio::detail::mutex::scoped_lock lock(other_service.mutex_);
113 impl.next_ = other_service.impl_list_;
115 if (other_service.impl_list_)
116 other_service.impl_list_->prev_ = &impl;
117 other_service.impl_list_ = &impl;
121 void winrt_ssocket_service_base::destroy(
122 winrt_ssocket_service_base::base_implementation_type& impl)
124 boost::system::error_code ignored_ec;
125 close(impl, ignored_ec);
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_;
132 impl.prev_->next_ = impl.next_;
134 impl.next_->prev_= impl.prev_;
139 boost::system::error_code winrt_ssocket_service_base::close(
140 winrt_ssocket_service_base::base_implementation_type& impl,
141 boost::system::error_code& ec)
146 impl.socket_ = nullptr;
149 ec = boost::system::error_code();
153 winrt_ssocket_service_base::native_handle_type
154 winrt_ssocket_service_base::release(
155 winrt_ssocket_service_base::base_implementation_type& impl,
156 boost::system::error_code& ec)
165 native_handle_type tmp = impl.socket_;
166 impl.socket_ = nullptr;
170 std::size_t winrt_ssocket_service_base::do_get_endpoint(
171 const base_implementation_type& impl, bool local,
172 void* addr, std::size_t addr_len, boost::system::error_code& ec) const
176 ec = boost::asio::error::bad_descriptor;
182 std::string addr_string = winrt_utils::string(local
183 ? impl.socket_->Information->LocalAddress->CanonicalName
184 : impl.socket_->Information->RemoteAddress->CanonicalName);
185 unsigned short port = winrt_utils::integer(local
186 ? impl.socket_->Information->LocalPort
187 : impl.socket_->Information->RemotePort);
188 unsigned long scope = 0;
190 switch (reinterpret_cast<const socket_addr_type*>(addr)->sa_family)
192 case BOOST_ASIO_OS_DEF(AF_INET):
193 if (addr_len < sizeof(sockaddr_in4_type))
195 ec = boost::asio::error::invalid_argument;
200 socket_ops::inet_pton(BOOST_ASIO_OS_DEF(AF_INET), addr_string.c_str(),
201 &reinterpret_cast<sockaddr_in4_type*>(addr)->sin_addr, &scope, ec);
202 reinterpret_cast<sockaddr_in4_type*>(addr)->sin_port
203 = socket_ops::host_to_network_short(port);
204 ec = boost::system::error_code();
205 return sizeof(sockaddr_in4_type);
207 case BOOST_ASIO_OS_DEF(AF_INET6):
208 if (addr_len < sizeof(sockaddr_in6_type))
210 ec = boost::asio::error::invalid_argument;
215 socket_ops::inet_pton(BOOST_ASIO_OS_DEF(AF_INET6), addr_string.c_str(),
216 &reinterpret_cast<sockaddr_in6_type*>(addr)->sin6_addr, &scope, ec);
217 reinterpret_cast<sockaddr_in6_type*>(addr)->sin6_port
218 = socket_ops::host_to_network_short(port);
219 ec = boost::system::error_code();
220 return sizeof(sockaddr_in6_type);
223 ec = boost::asio::error::address_family_not_supported;
227 catch (Platform::Exception^ e)
229 ec = boost::system::error_code(e->HResult,
230 boost::system::system_category());
235 boost::system::error_code winrt_ssocket_service_base::do_set_option(
236 winrt_ssocket_service_base::base_implementation_type& impl,
237 int level, int optname, const void* optval,
238 std::size_t optlen, boost::system::error_code& ec)
242 ec = boost::asio::error::bad_descriptor;
248 if (level == BOOST_ASIO_OS_DEF(SOL_SOCKET)
249 && optname == BOOST_ASIO_OS_DEF(SO_KEEPALIVE))
251 if (optlen == sizeof(int))
254 std::memcpy(&value, optval, optlen);
255 impl.socket_->Control->KeepAlive = !!value;
256 ec = boost::system::error_code();
260 ec = boost::asio::error::invalid_argument;
263 else if (level == BOOST_ASIO_OS_DEF(IPPROTO_TCP)
264 && optname == BOOST_ASIO_OS_DEF(TCP_NODELAY))
266 if (optlen == sizeof(int))
269 std::memcpy(&value, optval, optlen);
270 impl.socket_->Control->NoDelay = !!value;
271 ec = boost::system::error_code();
275 ec = boost::asio::error::invalid_argument;
280 ec = boost::asio::error::invalid_argument;
283 catch (Platform::Exception^ e)
285 ec = boost::system::error_code(e->HResult,
286 boost::system::system_category());
292 void winrt_ssocket_service_base::do_get_option(
293 const winrt_ssocket_service_base::base_implementation_type& impl,
294 int level, int optname, void* optval,
295 std::size_t* optlen, boost::system::error_code& ec) const
299 ec = boost::asio::error::bad_descriptor;
305 if (level == BOOST_ASIO_OS_DEF(SOL_SOCKET)
306 && optname == BOOST_ASIO_OS_DEF(SO_KEEPALIVE))
308 if (*optlen >= sizeof(int))
310 int value = impl.socket_->Control->KeepAlive ? 1 : 0;
311 std::memcpy(optval, &value, sizeof(int));
312 *optlen = sizeof(int);
313 ec = boost::system::error_code();
317 ec = boost::asio::error::invalid_argument;
320 else if (level == BOOST_ASIO_OS_DEF(IPPROTO_TCP)
321 && optname == BOOST_ASIO_OS_DEF(TCP_NODELAY))
323 if (*optlen >= sizeof(int))
325 int value = impl.socket_->Control->NoDelay ? 1 : 0;
326 std::memcpy(optval, &value, sizeof(int));
327 *optlen = sizeof(int);
328 ec = boost::system::error_code();
332 ec = boost::asio::error::invalid_argument;
337 ec = boost::asio::error::invalid_argument;
340 catch (Platform::Exception^ e)
342 ec = boost::system::error_code(e->HResult,
343 boost::system::system_category());
347 boost::system::error_code winrt_ssocket_service_base::do_connect(
348 winrt_ssocket_service_base::base_implementation_type& impl,
349 const void* addr, boost::system::error_code& ec)
353 ec = boost::asio::error::bad_descriptor;
357 char addr_string[max_addr_v6_str_len];
359 switch (reinterpret_cast<const socket_addr_type*>(addr)->sa_family)
361 case BOOST_ASIO_OS_DEF(AF_INET):
362 socket_ops::inet_ntop(BOOST_ASIO_OS_DEF(AF_INET),
363 &reinterpret_cast<const sockaddr_in4_type*>(addr)->sin_addr,
364 addr_string, sizeof(addr_string), 0, ec);
365 port = socket_ops::network_to_host_short(
366 reinterpret_cast<const sockaddr_in4_type*>(addr)->sin_port);
368 case BOOST_ASIO_OS_DEF(AF_INET6):
369 socket_ops::inet_ntop(BOOST_ASIO_OS_DEF(AF_INET6),
370 &reinterpret_cast<const sockaddr_in6_type*>(addr)->sin6_addr,
371 addr_string, sizeof(addr_string), 0, ec);
372 port = socket_ops::network_to_host_short(
373 reinterpret_cast<const sockaddr_in6_type*>(addr)->sin6_port);
376 ec = boost::asio::error::address_family_not_supported;
382 async_manager_.sync(impl.socket_->ConnectAsync(
383 ref new Windows::Networking::HostName(
384 winrt_utils::string(addr_string)),
385 winrt_utils::string(port)), ec);
387 catch (Platform::Exception^ e)
389 ec = boost::system::error_code(e->HResult,
390 boost::system::system_category());
396 void winrt_ssocket_service_base::start_connect_op(
397 winrt_ssocket_service_base::base_implementation_type& impl,
398 const void* addr, winrt_async_op<void>* op, bool is_continuation)
402 op->ec_ = boost::asio::error::bad_descriptor;
403 scheduler_.post_immediate_completion(op, is_continuation);
407 char addr_string[max_addr_v6_str_len];
408 unsigned short port = 0;
409 switch (reinterpret_cast<const socket_addr_type*>(addr)->sa_family)
411 case BOOST_ASIO_OS_DEF(AF_INET):
412 socket_ops::inet_ntop(BOOST_ASIO_OS_DEF(AF_INET),
413 &reinterpret_cast<const sockaddr_in4_type*>(addr)->sin_addr,
414 addr_string, sizeof(addr_string), 0, op->ec_);
415 port = socket_ops::network_to_host_short(
416 reinterpret_cast<const sockaddr_in4_type*>(addr)->sin_port);
418 case BOOST_ASIO_OS_DEF(AF_INET6):
419 socket_ops::inet_ntop(BOOST_ASIO_OS_DEF(AF_INET6),
420 &reinterpret_cast<const sockaddr_in6_type*>(addr)->sin6_addr,
421 addr_string, sizeof(addr_string), 0, op->ec_);
422 port = socket_ops::network_to_host_short(
423 reinterpret_cast<const sockaddr_in6_type*>(addr)->sin6_port);
426 op->ec_ = boost::asio::error::address_family_not_supported;
432 scheduler_.post_immediate_completion(op, is_continuation);
438 async_manager_.async(impl.socket_->ConnectAsync(
439 ref new Windows::Networking::HostName(
440 winrt_utils::string(addr_string)),
441 winrt_utils::string(port)), op);
443 catch (Platform::Exception^ e)
445 op->ec_ = boost::system::error_code(
446 e->HResult, boost::system::system_category());
447 scheduler_.post_immediate_completion(op, is_continuation);
451 std::size_t winrt_ssocket_service_base::do_send(
452 winrt_ssocket_service_base::base_implementation_type& impl,
453 const boost::asio::const_buffer& data,
454 socket_base::message_flags flags, boost::system::error_code& ec)
458 ec = boost::asio::error::operation_not_supported;
464 ec = boost::asio::error::bad_descriptor;
470 buffer_sequence_adapter<boost::asio::const_buffer,
471 boost::asio::const_buffer> bufs(boost::asio::buffer(data));
473 if (bufs.all_empty())
475 ec = boost::system::error_code();
479 return async_manager_.sync(
480 impl.socket_->OutputStream->WriteAsync(bufs.buffers()[0]), ec);
482 catch (Platform::Exception^ e)
484 ec = boost::system::error_code(e->HResult,
485 boost::system::system_category());
490 void winrt_ssocket_service_base::start_send_op(
491 winrt_ssocket_service_base::base_implementation_type& impl,
492 const boost::asio::const_buffer& data, socket_base::message_flags flags,
493 winrt_async_op<unsigned int>* op, bool is_continuation)
497 op->ec_ = boost::asio::error::operation_not_supported;
498 scheduler_.post_immediate_completion(op, is_continuation);
504 op->ec_ = boost::asio::error::bad_descriptor;
505 scheduler_.post_immediate_completion(op, is_continuation);
511 buffer_sequence_adapter<boost::asio::const_buffer,
512 boost::asio::const_buffer> bufs(boost::asio::buffer(data));
514 if (bufs.all_empty())
516 scheduler_.post_immediate_completion(op, is_continuation);
520 async_manager_.async(
521 impl.socket_->OutputStream->WriteAsync(bufs.buffers()[0]), op);
523 catch (Platform::Exception^ e)
525 op->ec_ = boost::system::error_code(e->HResult,
526 boost::system::system_category());
527 scheduler_.post_immediate_completion(op, is_continuation);
531 std::size_t winrt_ssocket_service_base::do_receive(
532 winrt_ssocket_service_base::base_implementation_type& impl,
533 const boost::asio::mutable_buffer& data,
534 socket_base::message_flags flags, boost::system::error_code& ec)
538 ec = boost::asio::error::operation_not_supported;
544 ec = boost::asio::error::bad_descriptor;
550 buffer_sequence_adapter<boost::asio::mutable_buffer,
551 boost::asio::mutable_buffer> bufs(boost::asio::buffer(data));
553 if (bufs.all_empty())
555 ec = boost::system::error_code();
560 impl.socket_->InputStream->ReadAsync(
561 bufs.buffers()[0], bufs.buffers()[0]->Capacity,
562 Windows::Storage::Streams::InputStreamOptions::Partial), ec);
564 std::size_t bytes_transferred = bufs.buffers()[0]->Length;
565 if (bytes_transferred == 0 && !ec)
567 ec = boost::asio::error::eof;
570 return bytes_transferred;
572 catch (Platform::Exception^ e)
574 ec = boost::system::error_code(e->HResult,
575 boost::system::system_category());
580 void winrt_ssocket_service_base::start_receive_op(
581 winrt_ssocket_service_base::base_implementation_type& impl,
582 const boost::asio::mutable_buffer& data, socket_base::message_flags flags,
583 winrt_async_op<Windows::Storage::Streams::IBuffer^>* op,
584 bool is_continuation)
588 op->ec_ = boost::asio::error::operation_not_supported;
589 scheduler_.post_immediate_completion(op, is_continuation);
595 op->ec_ = boost::asio::error::bad_descriptor;
596 scheduler_.post_immediate_completion(op, is_continuation);
602 buffer_sequence_adapter<boost::asio::mutable_buffer,
603 boost::asio::mutable_buffer> bufs(boost::asio::buffer(data));
605 if (bufs.all_empty())
607 scheduler_.post_immediate_completion(op, is_continuation);
611 async_manager_.async(
612 impl.socket_->InputStream->ReadAsync(
613 bufs.buffers()[0], bufs.buffers()[0]->Capacity,
614 Windows::Storage::Streams::InputStreamOptions::Partial), op);
616 catch (Platform::Exception^ e)
618 op->ec_ = boost::system::error_code(e->HResult,
619 boost::system::system_category());
620 scheduler_.post_immediate_completion(op, is_continuation);
624 } // namespace detail
628 #include <boost/asio/detail/pop_options.hpp>
630 #endif // defined(BOOST_ASIO_WINDOWS_RUNTIME)
632 #endif // BOOST_ASIO_DETAIL_IMPL_WINRT_SSOCKET_SERVICE_BASE_IPP