627 lines
		
	
	
		
			16 KiB
		
	
	
	
		
			Plaintext
		
	
	
	
		
		
			
		
	
	
			627 lines
		
	
	
		
			16 KiB
		
	
	
	
		
			Plaintext
		
	
	
	
|  | // | ||
|  | // 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 |