627 lines
		
	
	
		
			16 KiB
		
	
	
	
		
			C++
		
	
	
	
			
		
		
	
	
			627 lines
		
	
	
		
			16 KiB
		
	
	
	
		
			C++
		
	
	
	
| //
 | |
| // detail/impl/winrt_ssocket_service_base.ipp
 | |
| // ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
 | |
| //
 | |
| // Copyright (c) 2003-2023 Christopher M. Kohlhoff (chris at kohlhoff dot com)
 | |
| //
 | |
| // Distributed under the Boost Software License, Version 1.0. (See accompanying
 | |
| // file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt)
 | |
| //
 | |
| 
 | |
| #ifndef ASIO_DETAIL_IMPL_WINRT_SSOCKET_SERVICE_BASE_IPP
 | |
| #define ASIO_DETAIL_IMPL_WINRT_SSOCKET_SERVICE_BASE_IPP
 | |
| 
 | |
| #if defined(_MSC_VER) && (_MSC_VER >= 1200)
 | |
| # pragma once
 | |
| #endif // defined(_MSC_VER) && (_MSC_VER >= 1200)
 | |
| 
 | |
| #include "asio/detail/config.hpp"
 | |
| 
 | |
| #if defined(ASIO_WINDOWS_RUNTIME)
 | |
| 
 | |
| #include <cstring>
 | |
| #include "asio/detail/winrt_ssocket_service_base.hpp"
 | |
| #include "asio/detail/winrt_async_op.hpp"
 | |
| #include "asio/detail/winrt_utils.hpp"
 | |
| 
 | |
| #include "asio/detail/push_options.hpp"
 | |
| 
 | |
| namespace asio {
 | |
| namespace detail {
 | |
| 
 | |
| winrt_ssocket_service_base::winrt_ssocket_service_base(
 | |
|     execution_context& context)
 | |
|   : scheduler_(use_service<scheduler_impl>(context)),
 | |
|     async_manager_(use_service<winrt_async_manager>(context)),
 | |
|     mutex_(),
 | |
|     impl_list_(0)
 | |
| {
 | |
| }
 | |
| 
 | |
| void winrt_ssocket_service_base::base_shutdown()
 | |
| {
 | |
|   // Close all implementations, causing all operations to complete.
 | |
|   asio::detail::mutex::scoped_lock lock(mutex_);
 | |
|   base_implementation_type* impl = impl_list_;
 | |
|   while (impl)
 | |
|   {
 | |
|     asio::error_code ignored_ec;
 | |
|     close(*impl, ignored_ec);
 | |
|     impl = impl->next_;
 | |
|   }
 | |
| }
 | |
| 
 | |
| void winrt_ssocket_service_base::construct(
 | |
|     winrt_ssocket_service_base::base_implementation_type& impl)
 | |
| {
 | |
|   // Insert implementation into linked list of all implementations.
 | |
|   asio::detail::mutex::scoped_lock lock(mutex_);
 | |
|   impl.next_ = impl_list_;
 | |
|   impl.prev_ = 0;
 | |
|   if (impl_list_)
 | |
|     impl_list_->prev_ = &impl;
 | |
|   impl_list_ = &impl;
 | |
| }
 | |
| 
 | |
| void winrt_ssocket_service_base::base_move_construct(
 | |
|     winrt_ssocket_service_base::base_implementation_type& impl,
 | |
|     winrt_ssocket_service_base::base_implementation_type& other_impl)
 | |
|   ASIO_NOEXCEPT
 | |
| {
 | |
|   impl.socket_ = other_impl.socket_;
 | |
|   other_impl.socket_ = nullptr;
 | |
| 
 | |
|   // Insert implementation into linked list of all implementations.
 | |
|   asio::detail::mutex::scoped_lock lock(mutex_);
 | |
|   impl.next_ = impl_list_;
 | |
|   impl.prev_ = 0;
 | |
|   if (impl_list_)
 | |
|     impl_list_->prev_ = &impl;
 | |
|   impl_list_ = &impl;
 | |
| }
 | |
| 
 | |
| void winrt_ssocket_service_base::base_move_assign(
 | |
|     winrt_ssocket_service_base::base_implementation_type& impl,
 | |
|     winrt_ssocket_service_base& other_service,
 | |
|     winrt_ssocket_service_base::base_implementation_type& other_impl)
 | |
| {
 | |
|   asio::error_code ignored_ec;
 | |
|   close(impl, ignored_ec);
 | |
| 
 | |
|   if (this != &other_service)
 | |
|   {
 | |
|     // Remove implementation from linked list of all implementations.
 | |
|     asio::detail::mutex::scoped_lock lock(mutex_);
 | |
|     if (impl_list_ == &impl)
 | |
|       impl_list_ = impl.next_;
 | |
|     if (impl.prev_)
 | |
|       impl.prev_->next_ = impl.next_;
 | |
|     if (impl.next_)
 | |
|       impl.next_->prev_= impl.prev_;
 | |
|     impl.next_ = 0;
 | |
|     impl.prev_ = 0;
 | |
|   }
 | |
| 
 | |
|   impl.socket_ = other_impl.socket_;
 | |
|   other_impl.socket_ = nullptr;
 | |
| 
 | |
|   if (this != &other_service)
 | |
|   {
 | |
|     // Insert implementation into linked list of all implementations.
 | |
|     asio::detail::mutex::scoped_lock lock(other_service.mutex_);
 | |
|     impl.next_ = other_service.impl_list_;
 | |
|     impl.prev_ = 0;
 | |
|     if (other_service.impl_list_)
 | |
|       other_service.impl_list_->prev_ = &impl;
 | |
|     other_service.impl_list_ = &impl;
 | |
|   }
 | |
| }
 | |
| 
 | |
| void winrt_ssocket_service_base::destroy(
 | |
|     winrt_ssocket_service_base::base_implementation_type& impl)
 | |
| {
 | |
|   asio::error_code ignored_ec;
 | |
|   close(impl, ignored_ec);
 | |
| 
 | |
|   // Remove implementation from linked list of all implementations.
 | |
|   asio::detail::mutex::scoped_lock lock(mutex_);
 | |
|   if (impl_list_ == &impl)
 | |
|     impl_list_ = impl.next_;
 | |
|   if (impl.prev_)
 | |
|     impl.prev_->next_ = impl.next_;
 | |
|   if (impl.next_)
 | |
|     impl.next_->prev_= impl.prev_;
 | |
|   impl.next_ = 0;
 | |
|   impl.prev_ = 0;
 | |
| }
 | |
| 
 | |
| asio::error_code winrt_ssocket_service_base::close(
 | |
|     winrt_ssocket_service_base::base_implementation_type& impl,
 | |
|     asio::error_code& ec)
 | |
| {
 | |
|   delete impl.socket_;
 | |
|   impl.socket_ = nullptr;
 | |
|   ec = asio::error_code();
 | |
|   return ec;
 | |
| }
 | |
| 
 | |
| winrt_ssocket_service_base::native_handle_type
 | |
| winrt_ssocket_service_base::release(
 | |
|     winrt_ssocket_service_base::base_implementation_type& impl,
 | |
|     asio::error_code& ec)
 | |
| {
 | |
|   if (!is_open(impl))
 | |
|     return nullptr;
 | |
| 
 | |
|   cancel(impl, ec);
 | |
|   if (ec)
 | |
|     return nullptr;
 | |
| 
 | |
|   native_handle_type tmp = impl.socket_;
 | |
|   impl.socket_ = nullptr;
 | |
|   return tmp;
 | |
| }
 | |
| 
 | |
| std::size_t winrt_ssocket_service_base::do_get_endpoint(
 | |
|     const base_implementation_type& impl, bool local,
 | |
|     void* addr, std::size_t addr_len, asio::error_code& ec) const
 | |
| {
 | |
|   if (!is_open(impl))
 | |
|   {
 | |
|     ec = asio::error::bad_descriptor;
 | |
|     return addr_len;
 | |
|   }
 | |
| 
 | |
|   try
 | |
|   {
 | |
|     std::string addr_string = winrt_utils::string(local
 | |
|         ? impl.socket_->Information->LocalAddress->CanonicalName
 | |
|         : impl.socket_->Information->RemoteAddress->CanonicalName);
 | |
|     unsigned short port = winrt_utils::integer(local
 | |
|         ? impl.socket_->Information->LocalPort
 | |
|         : impl.socket_->Information->RemotePort);
 | |
|     unsigned long scope = 0;
 | |
| 
 | |
|     switch (static_cast<const socket_addr_type*>(addr)->sa_family)
 | |
|     {
 | |
|     case ASIO_OS_DEF(AF_INET):
 | |
|       if (addr_len < sizeof(sockaddr_in4_type))
 | |
|       {
 | |
|         ec = asio::error::invalid_argument;
 | |
|         return addr_len;
 | |
|       }
 | |
|       else
 | |
|       {
 | |
|         socket_ops::inet_pton(ASIO_OS_DEF(AF_INET), addr_string.c_str(),
 | |
|             &reinterpret_cast<sockaddr_in4_type*>(addr)->sin_addr, &scope, ec);
 | |
|         reinterpret_cast<sockaddr_in4_type*>(addr)->sin_port
 | |
|           = socket_ops::host_to_network_short(port);
 | |
|         ec = asio::error_code();
 | |
|         return sizeof(sockaddr_in4_type);
 | |
|       }
 | |
|     case ASIO_OS_DEF(AF_INET6):
 | |
|       if (addr_len < sizeof(sockaddr_in6_type))
 | |
|       {
 | |
|         ec = asio::error::invalid_argument;
 | |
|         return addr_len;
 | |
|       }
 | |
|       else
 | |
|       {
 | |
|         socket_ops::inet_pton(ASIO_OS_DEF(AF_INET6), addr_string.c_str(),
 | |
|             &reinterpret_cast<sockaddr_in6_type*>(addr)->sin6_addr, &scope, ec);
 | |
|         reinterpret_cast<sockaddr_in6_type*>(addr)->sin6_port
 | |
|           = socket_ops::host_to_network_short(port);
 | |
|         ec = asio::error_code();
 | |
|         return sizeof(sockaddr_in6_type);
 | |
|       }
 | |
|     default:
 | |
|       ec = asio::error::address_family_not_supported;
 | |
|       return addr_len;
 | |
|     }
 | |
|   }
 | |
|   catch (Platform::Exception^ e)
 | |
|   {
 | |
|     ec = asio::error_code(e->HResult,
 | |
|         asio::system_category());
 | |
|     return addr_len;
 | |
|   }
 | |
| }
 | |
| 
 | |
| asio::error_code winrt_ssocket_service_base::do_set_option(
 | |
|     winrt_ssocket_service_base::base_implementation_type& impl,
 | |
|     int level, int optname, const void* optval,
 | |
|     std::size_t optlen, asio::error_code& ec)
 | |
| {
 | |
|   if (!is_open(impl))
 | |
|   {
 | |
|     ec = asio::error::bad_descriptor;
 | |
|     return ec;
 | |
|   }
 | |
| 
 | |
|   try
 | |
|   {
 | |
|     if (level == ASIO_OS_DEF(SOL_SOCKET)
 | |
|         && optname == ASIO_OS_DEF(SO_KEEPALIVE))
 | |
|     {
 | |
|       if (optlen == sizeof(int))
 | |
|       {
 | |
|         int value = 0;
 | |
|         std::memcpy(&value, optval, optlen);
 | |
|         impl.socket_->Control->KeepAlive = !!value;
 | |
|         ec = asio::error_code();
 | |
|       }
 | |
|       else
 | |
|       {
 | |
|         ec = asio::error::invalid_argument;
 | |
|       }
 | |
|     }
 | |
|     else if (level == ASIO_OS_DEF(IPPROTO_TCP)
 | |
|         && optname == ASIO_OS_DEF(TCP_NODELAY))
 | |
|     {
 | |
|       if (optlen == sizeof(int))
 | |
|       {
 | |
|         int value = 0;
 | |
|         std::memcpy(&value, optval, optlen);
 | |
|         impl.socket_->Control->NoDelay = !!value;
 | |
|         ec = asio::error_code();
 | |
|       }
 | |
|       else
 | |
|       {
 | |
|         ec = asio::error::invalid_argument;
 | |
|       }
 | |
|     }
 | |
|     else
 | |
|     {
 | |
|       ec = asio::error::invalid_argument;
 | |
|     }
 | |
|   }
 | |
|   catch (Platform::Exception^ e)
 | |
|   {
 | |
|     ec = asio::error_code(e->HResult,
 | |
|         asio::system_category());
 | |
|   }
 | |
| 
 | |
|   return ec;
 | |
| }
 | |
| 
 | |
| void winrt_ssocket_service_base::do_get_option(
 | |
|     const winrt_ssocket_service_base::base_implementation_type& impl,
 | |
|     int level, int optname, void* optval,
 | |
|     std::size_t* optlen, asio::error_code& ec) const
 | |
| {
 | |
|   if (!is_open(impl))
 | |
|   {
 | |
|     ec = asio::error::bad_descriptor;
 | |
|     return;
 | |
|   }
 | |
| 
 | |
|   try
 | |
|   {
 | |
|     if (level == ASIO_OS_DEF(SOL_SOCKET)
 | |
|         && optname == ASIO_OS_DEF(SO_KEEPALIVE))
 | |
|     {
 | |
|       if (*optlen >= sizeof(int))
 | |
|       {
 | |
|         int value = impl.socket_->Control->KeepAlive ? 1 : 0;
 | |
|         std::memcpy(optval, &value, sizeof(int));
 | |
|         *optlen = sizeof(int);
 | |
|         ec = asio::error_code();
 | |
|       }
 | |
|       else
 | |
|       {
 | |
|         ec = asio::error::invalid_argument;
 | |
|       }
 | |
|     }
 | |
|     else if (level == ASIO_OS_DEF(IPPROTO_TCP)
 | |
|         && optname == ASIO_OS_DEF(TCP_NODELAY))
 | |
|     {
 | |
|       if (*optlen >= sizeof(int))
 | |
|       {
 | |
|         int value = impl.socket_->Control->NoDelay ? 1 : 0;
 | |
|         std::memcpy(optval, &value, sizeof(int));
 | |
|         *optlen = sizeof(int);
 | |
|         ec = asio::error_code();
 | |
|       }
 | |
|       else
 | |
|       {
 | |
|         ec = asio::error::invalid_argument;
 | |
|       }
 | |
|     }
 | |
|     else
 | |
|     {
 | |
|       ec = asio::error::invalid_argument;
 | |
|     }
 | |
|   }
 | |
|   catch (Platform::Exception^ e)
 | |
|   {
 | |
|     ec = asio::error_code(e->HResult,
 | |
|         asio::system_category());
 | |
|   }
 | |
| }
 | |
| 
 | |
| asio::error_code winrt_ssocket_service_base::do_connect(
 | |
|     winrt_ssocket_service_base::base_implementation_type& impl,
 | |
|     const void* addr, asio::error_code& ec)
 | |
| {
 | |
|   if (!is_open(impl))
 | |
|   {
 | |
|     ec = asio::error::bad_descriptor;
 | |
|     return ec;
 | |
|   }
 | |
| 
 | |
|   char addr_string[max_addr_v6_str_len];
 | |
|   unsigned short port;
 | |
|   switch (static_cast<const socket_addr_type*>(addr)->sa_family)
 | |
|   {
 | |
|   case ASIO_OS_DEF(AF_INET):
 | |
|     socket_ops::inet_ntop(ASIO_OS_DEF(AF_INET),
 | |
|         &reinterpret_cast<const sockaddr_in4_type*>(addr)->sin_addr,
 | |
|         addr_string, sizeof(addr_string), 0, ec);
 | |
|     port = socket_ops::network_to_host_short(
 | |
|         reinterpret_cast<const sockaddr_in4_type*>(addr)->sin_port);
 | |
|     break;
 | |
|   case ASIO_OS_DEF(AF_INET6):
 | |
|     socket_ops::inet_ntop(ASIO_OS_DEF(AF_INET6),
 | |
|         &reinterpret_cast<const sockaddr_in6_type*>(addr)->sin6_addr,
 | |
|         addr_string, sizeof(addr_string), 0, ec);
 | |
|     port = socket_ops::network_to_host_short(
 | |
|         reinterpret_cast<const sockaddr_in6_type*>(addr)->sin6_port);
 | |
|     break;
 | |
|   default:
 | |
|     ec = asio::error::address_family_not_supported;
 | |
|     return ec;
 | |
|   }
 | |
| 
 | |
|   if (!ec) try
 | |
|   {
 | |
|     async_manager_.sync(impl.socket_->ConnectAsync(
 | |
|           ref new Windows::Networking::HostName(
 | |
|             winrt_utils::string(addr_string)),
 | |
|           winrt_utils::string(port)), ec);
 | |
|   }
 | |
|   catch (Platform::Exception^ e)
 | |
|   {
 | |
|     ec = asio::error_code(e->HResult,
 | |
|         asio::system_category());
 | |
|   }
 | |
| 
 | |
|   return ec;
 | |
| }
 | |
| 
 | |
| void winrt_ssocket_service_base::start_connect_op(
 | |
|     winrt_ssocket_service_base::base_implementation_type& impl,
 | |
|     const void* addr, winrt_async_op<void>* op, bool is_continuation)
 | |
| {
 | |
|   if (!is_open(impl))
 | |
|   {
 | |
|     op->ec_ = asio::error::bad_descriptor;
 | |
|     scheduler_.post_immediate_completion(op, is_continuation);
 | |
|     return;
 | |
|   }
 | |
| 
 | |
|   char addr_string[max_addr_v6_str_len];
 | |
|   unsigned short port = 0;
 | |
|   switch (static_cast<const socket_addr_type*>(addr)->sa_family)
 | |
|   {
 | |
|   case ASIO_OS_DEF(AF_INET):
 | |
|     socket_ops::inet_ntop(ASIO_OS_DEF(AF_INET),
 | |
|         &reinterpret_cast<const sockaddr_in4_type*>(addr)->sin_addr,
 | |
|         addr_string, sizeof(addr_string), 0, op->ec_);
 | |
|     port = socket_ops::network_to_host_short(
 | |
|         reinterpret_cast<const sockaddr_in4_type*>(addr)->sin_port);
 | |
|     break;
 | |
|   case ASIO_OS_DEF(AF_INET6):
 | |
|     socket_ops::inet_ntop(ASIO_OS_DEF(AF_INET6),
 | |
|         &reinterpret_cast<const sockaddr_in6_type*>(addr)->sin6_addr,
 | |
|         addr_string, sizeof(addr_string), 0, op->ec_);
 | |
|     port = socket_ops::network_to_host_short(
 | |
|         reinterpret_cast<const sockaddr_in6_type*>(addr)->sin6_port);
 | |
|     break;
 | |
|   default:
 | |
|     op->ec_ = asio::error::address_family_not_supported;
 | |
|     break;
 | |
|   }
 | |
| 
 | |
|   if (op->ec_)
 | |
|   {
 | |
|     scheduler_.post_immediate_completion(op, is_continuation);
 | |
|     return;
 | |
|   }
 | |
| 
 | |
|   try
 | |
|   {
 | |
|     async_manager_.async(impl.socket_->ConnectAsync(
 | |
|           ref new Windows::Networking::HostName(
 | |
|             winrt_utils::string(addr_string)),
 | |
|           winrt_utils::string(port)), op);
 | |
|   }
 | |
|   catch (Platform::Exception^ e)
 | |
|   {
 | |
|     op->ec_ = asio::error_code(
 | |
|         e->HResult, asio::system_category());
 | |
|     scheduler_.post_immediate_completion(op, is_continuation);
 | |
|   }
 | |
| }
 | |
| 
 | |
| std::size_t winrt_ssocket_service_base::do_send(
 | |
|     winrt_ssocket_service_base::base_implementation_type& impl,
 | |
|     const asio::const_buffer& data,
 | |
|     socket_base::message_flags flags, asio::error_code& ec)
 | |
| {
 | |
|   if (flags)
 | |
|   {
 | |
|     ec = asio::error::operation_not_supported;
 | |
|     return 0;
 | |
|   }
 | |
| 
 | |
|   if (!is_open(impl))
 | |
|   {
 | |
|     ec = asio::error::bad_descriptor;
 | |
|     return 0;
 | |
|   }
 | |
| 
 | |
|   try
 | |
|   {
 | |
|     buffer_sequence_adapter<asio::const_buffer,
 | |
|       asio::const_buffer> bufs(asio::buffer(data));
 | |
| 
 | |
|     if (bufs.all_empty())
 | |
|     {
 | |
|       ec = asio::error_code();
 | |
|       return 0;
 | |
|     }
 | |
| 
 | |
|     return async_manager_.sync(
 | |
|         impl.socket_->OutputStream->WriteAsync(bufs.buffers()[0]), ec);
 | |
|   }
 | |
|   catch (Platform::Exception^ e)
 | |
|   {
 | |
|     ec = asio::error_code(e->HResult,
 | |
|         asio::system_category());
 | |
|     return 0;
 | |
|   }
 | |
| }
 | |
| 
 | |
| void winrt_ssocket_service_base::start_send_op(
 | |
|       winrt_ssocket_service_base::base_implementation_type& impl,
 | |
|       const asio::const_buffer& data, socket_base::message_flags flags,
 | |
|       winrt_async_op<unsigned int>* op, bool is_continuation)
 | |
| {
 | |
|   if (flags)
 | |
|   {
 | |
|     op->ec_ = asio::error::operation_not_supported;
 | |
|     scheduler_.post_immediate_completion(op, is_continuation);
 | |
|     return;
 | |
|   }
 | |
| 
 | |
|   if (!is_open(impl))
 | |
|   {
 | |
|     op->ec_ = asio::error::bad_descriptor;
 | |
|     scheduler_.post_immediate_completion(op, is_continuation);
 | |
|     return;
 | |
|   }
 | |
| 
 | |
|   try
 | |
|   {
 | |
|     buffer_sequence_adapter<asio::const_buffer,
 | |
|         asio::const_buffer> bufs(asio::buffer(data));
 | |
| 
 | |
|     if (bufs.all_empty())
 | |
|     {
 | |
|       scheduler_.post_immediate_completion(op, is_continuation);
 | |
|       return;
 | |
|     }
 | |
| 
 | |
|     async_manager_.async(
 | |
|         impl.socket_->OutputStream->WriteAsync(bufs.buffers()[0]), op);
 | |
|   }
 | |
|   catch (Platform::Exception^ e)
 | |
|   {
 | |
|     op->ec_ = asio::error_code(e->HResult,
 | |
|         asio::system_category());
 | |
|     scheduler_.post_immediate_completion(op, is_continuation);
 | |
|   }
 | |
| }
 | |
| 
 | |
| std::size_t winrt_ssocket_service_base::do_receive(
 | |
|     winrt_ssocket_service_base::base_implementation_type& impl,
 | |
|     const asio::mutable_buffer& data,
 | |
|     socket_base::message_flags flags, asio::error_code& ec)
 | |
| {
 | |
|   if (flags)
 | |
|   {
 | |
|     ec = asio::error::operation_not_supported;
 | |
|     return 0;
 | |
|   }
 | |
| 
 | |
|   if (!is_open(impl))
 | |
|   {
 | |
|     ec = asio::error::bad_descriptor;
 | |
|     return 0;
 | |
|   }
 | |
| 
 | |
|   try
 | |
|   {
 | |
|     buffer_sequence_adapter<asio::mutable_buffer,
 | |
|         asio::mutable_buffer> bufs(asio::buffer(data));
 | |
| 
 | |
|     if (bufs.all_empty())
 | |
|     {
 | |
|       ec = asio::error_code();
 | |
|       return 0;
 | |
|     }
 | |
| 
 | |
|     async_manager_.sync(
 | |
|         impl.socket_->InputStream->ReadAsync(
 | |
|           bufs.buffers()[0], bufs.buffers()[0]->Capacity,
 | |
|           Windows::Storage::Streams::InputStreamOptions::Partial), ec);
 | |
| 
 | |
|     std::size_t bytes_transferred = bufs.buffers()[0]->Length;
 | |
|     if (bytes_transferred == 0 && !ec)
 | |
|     {
 | |
|       ec = asio::error::eof;
 | |
|     }
 | |
| 
 | |
|     return bytes_transferred;
 | |
|   }
 | |
|   catch (Platform::Exception^ e)
 | |
|   {
 | |
|     ec = asio::error_code(e->HResult,
 | |
|         asio::system_category());
 | |
|     return 0;
 | |
|   }
 | |
| }
 | |
| 
 | |
| void winrt_ssocket_service_base::start_receive_op(
 | |
|       winrt_ssocket_service_base::base_implementation_type& impl,
 | |
|       const asio::mutable_buffer& data, socket_base::message_flags flags,
 | |
|       winrt_async_op<Windows::Storage::Streams::IBuffer^>* op,
 | |
|       bool is_continuation)
 | |
| {
 | |
|   if (flags)
 | |
|   {
 | |
|     op->ec_ = asio::error::operation_not_supported;
 | |
|     scheduler_.post_immediate_completion(op, is_continuation);
 | |
|     return;
 | |
|   }
 | |
| 
 | |
|   if (!is_open(impl))
 | |
|   {
 | |
|     op->ec_ = asio::error::bad_descriptor;
 | |
|     scheduler_.post_immediate_completion(op, is_continuation);
 | |
|     return;
 | |
|   }
 | |
| 
 | |
|   try
 | |
|   {
 | |
|     buffer_sequence_adapter<asio::mutable_buffer,
 | |
|         asio::mutable_buffer> bufs(asio::buffer(data));
 | |
| 
 | |
|     if (bufs.all_empty())
 | |
|     {
 | |
|       scheduler_.post_immediate_completion(op, is_continuation);
 | |
|       return;
 | |
|     }
 | |
| 
 | |
|     async_manager_.async(
 | |
|         impl.socket_->InputStream->ReadAsync(
 | |
|           bufs.buffers()[0], bufs.buffers()[0]->Capacity,
 | |
|           Windows::Storage::Streams::InputStreamOptions::Partial), op);
 | |
|   }
 | |
|   catch (Platform::Exception^ e)
 | |
|   {
 | |
|     op->ec_ = asio::error_code(e->HResult,
 | |
|         asio::system_category());
 | |
|     scheduler_.post_immediate_completion(op, is_continuation);
 | |
|   }
 | |
| }
 | |
| 
 | |
| } // namespace detail
 | |
| } // namespace asio
 | |
| 
 | |
| #include "asio/detail/pop_options.hpp"
 | |
| 
 | |
| #endif // defined(ASIO_WINDOWS_RUNTIME)
 | |
| 
 | |
| #endif // ASIO_DETAIL_IMPL_WINRT_SSOCKET_SERVICE_BASE_IPP
 |