Back to home page

EIC code displayed by LXR

 
 

    


File indexing completed on 2025-01-18 09:28:36

0001 //
0002 // detail/impl/winrt_ssocket_service_base.ipp
0003 // ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
0004 //
0005 // Copyright (c) 2003-2023 Christopher M. Kohlhoff (chris at kohlhoff dot com)
0006 //
0007 // Distributed under the Boost Software License, Version 1.0. (See accompanying
0008 // file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt)
0009 //
0010 
0011 #ifndef BOOST_ASIO_DETAIL_IMPL_WINRT_SSOCKET_SERVICE_BASE_IPP
0012 #define BOOST_ASIO_DETAIL_IMPL_WINRT_SSOCKET_SERVICE_BASE_IPP
0013 
0014 #if defined(_MSC_VER) && (_MSC_VER >= 1200)
0015 # pragma once
0016 #endif // defined(_MSC_VER) && (_MSC_VER >= 1200)
0017 
0018 #include <boost/asio/detail/config.hpp>
0019 
0020 #if defined(BOOST_ASIO_WINDOWS_RUNTIME)
0021 
0022 #include <cstring>
0023 #include <boost/asio/detail/winrt_ssocket_service_base.hpp>
0024 #include <boost/asio/detail/winrt_async_op.hpp>
0025 #include <boost/asio/detail/winrt_utils.hpp>
0026 
0027 #include <boost/asio/detail/push_options.hpp>
0028 
0029 namespace boost {
0030 namespace asio {
0031 namespace detail {
0032 
0033 winrt_ssocket_service_base::winrt_ssocket_service_base(
0034     execution_context& context)
0035   : scheduler_(use_service<scheduler_impl>(context)),
0036     async_manager_(use_service<winrt_async_manager>(context)),
0037     mutex_(),
0038     impl_list_(0)
0039 {
0040 }
0041 
0042 void winrt_ssocket_service_base::base_shutdown()
0043 {
0044   // Close all implementations, causing all operations to complete.
0045   boost::asio::detail::mutex::scoped_lock lock(mutex_);
0046   base_implementation_type* impl = impl_list_;
0047   while (impl)
0048   {
0049     boost::system::error_code ignored_ec;
0050     close(*impl, ignored_ec);
0051     impl = impl->next_;
0052   }
0053 }
0054 
0055 void winrt_ssocket_service_base::construct(
0056     winrt_ssocket_service_base::base_implementation_type& impl)
0057 {
0058   // Insert implementation into linked list of all implementations.
0059   boost::asio::detail::mutex::scoped_lock lock(mutex_);
0060   impl.next_ = impl_list_;
0061   impl.prev_ = 0;
0062   if (impl_list_)
0063     impl_list_->prev_ = &impl;
0064   impl_list_ = &impl;
0065 }
0066 
0067 void winrt_ssocket_service_base::base_move_construct(
0068     winrt_ssocket_service_base::base_implementation_type& impl,
0069     winrt_ssocket_service_base::base_implementation_type& other_impl)
0070   noexcept
0071 {
0072   impl.socket_ = other_impl.socket_;
0073   other_impl.socket_ = nullptr;
0074 
0075   // Insert implementation into linked list of all implementations.
0076   boost::asio::detail::mutex::scoped_lock lock(mutex_);
0077   impl.next_ = impl_list_;
0078   impl.prev_ = 0;
0079   if (impl_list_)
0080     impl_list_->prev_ = &impl;
0081   impl_list_ = &impl;
0082 }
0083 
0084 void winrt_ssocket_service_base::base_move_assign(
0085     winrt_ssocket_service_base::base_implementation_type& impl,
0086     winrt_ssocket_service_base& other_service,
0087     winrt_ssocket_service_base::base_implementation_type& other_impl)
0088 {
0089   boost::system::error_code ignored_ec;
0090   close(impl, ignored_ec);
0091 
0092   if (this != &other_service)
0093   {
0094     // Remove implementation from linked list of all implementations.
0095     boost::asio::detail::mutex::scoped_lock lock(mutex_);
0096     if (impl_list_ == &impl)
0097       impl_list_ = impl.next_;
0098     if (impl.prev_)
0099       impl.prev_->next_ = impl.next_;
0100     if (impl.next_)
0101       impl.next_->prev_= impl.prev_;
0102     impl.next_ = 0;
0103     impl.prev_ = 0;
0104   }
0105 
0106   impl.socket_ = other_impl.socket_;
0107   other_impl.socket_ = nullptr;
0108 
0109   if (this != &other_service)
0110   {
0111     // Insert implementation into linked list of all implementations.
0112     boost::asio::detail::mutex::scoped_lock lock(other_service.mutex_);
0113     impl.next_ = other_service.impl_list_;
0114     impl.prev_ = 0;
0115     if (other_service.impl_list_)
0116       other_service.impl_list_->prev_ = &impl;
0117     other_service.impl_list_ = &impl;
0118   }
0119 }
0120 
0121 void winrt_ssocket_service_base::destroy(
0122     winrt_ssocket_service_base::base_implementation_type& impl)
0123 {
0124   boost::system::error_code ignored_ec;
0125   close(impl, ignored_ec);
0126 
0127   // Remove implementation from linked list of all implementations.
0128   boost::asio::detail::mutex::scoped_lock lock(mutex_);
0129   if (impl_list_ == &impl)
0130     impl_list_ = impl.next_;
0131   if (impl.prev_)
0132     impl.prev_->next_ = impl.next_;
0133   if (impl.next_)
0134     impl.next_->prev_= impl.prev_;
0135   impl.next_ = 0;
0136   impl.prev_ = 0;
0137 }
0138 
0139 boost::system::error_code winrt_ssocket_service_base::close(
0140     winrt_ssocket_service_base::base_implementation_type& impl,
0141     boost::system::error_code& ec)
0142 {
0143   delete impl.socket_;
0144   impl.socket_ = nullptr;
0145   ec = boost::system::error_code();
0146   return ec;
0147 }
0148 
0149 winrt_ssocket_service_base::native_handle_type
0150 winrt_ssocket_service_base::release(
0151     winrt_ssocket_service_base::base_implementation_type& impl,
0152     boost::system::error_code& ec)
0153 {
0154   if (!is_open(impl))
0155     return nullptr;
0156 
0157   cancel(impl, ec);
0158   if (ec)
0159     return nullptr;
0160 
0161   native_handle_type tmp = impl.socket_;
0162   impl.socket_ = nullptr;
0163   return tmp;
0164 }
0165 
0166 std::size_t winrt_ssocket_service_base::do_get_endpoint(
0167     const base_implementation_type& impl, bool local,
0168     void* addr, std::size_t addr_len, boost::system::error_code& ec) const
0169 {
0170   if (!is_open(impl))
0171   {
0172     ec = boost::asio::error::bad_descriptor;
0173     return addr_len;
0174   }
0175 
0176   try
0177   {
0178     std::string addr_string = winrt_utils::string(local
0179         ? impl.socket_->Information->LocalAddress->CanonicalName
0180         : impl.socket_->Information->RemoteAddress->CanonicalName);
0181     unsigned short port = winrt_utils::integer(local
0182         ? impl.socket_->Information->LocalPort
0183         : impl.socket_->Information->RemotePort);
0184     unsigned long scope = 0;
0185 
0186     switch (static_cast<const socket_addr_type*>(addr)->sa_family)
0187     {
0188     case BOOST_ASIO_OS_DEF(AF_INET):
0189       if (addr_len < sizeof(sockaddr_in4_type))
0190       {
0191         ec = boost::asio::error::invalid_argument;
0192         return addr_len;
0193       }
0194       else
0195       {
0196         socket_ops::inet_pton(BOOST_ASIO_OS_DEF(AF_INET), addr_string.c_str(),
0197             &reinterpret_cast<sockaddr_in4_type*>(addr)->sin_addr, &scope, ec);
0198         reinterpret_cast<sockaddr_in4_type*>(addr)->sin_port
0199           = socket_ops::host_to_network_short(port);
0200         ec = boost::system::error_code();
0201         return sizeof(sockaddr_in4_type);
0202       }
0203     case BOOST_ASIO_OS_DEF(AF_INET6):
0204       if (addr_len < sizeof(sockaddr_in6_type))
0205       {
0206         ec = boost::asio::error::invalid_argument;
0207         return addr_len;
0208       }
0209       else
0210       {
0211         socket_ops::inet_pton(BOOST_ASIO_OS_DEF(AF_INET6), addr_string.c_str(),
0212             &reinterpret_cast<sockaddr_in6_type*>(addr)->sin6_addr, &scope, ec);
0213         reinterpret_cast<sockaddr_in6_type*>(addr)->sin6_port
0214           = socket_ops::host_to_network_short(port);
0215         ec = boost::system::error_code();
0216         return sizeof(sockaddr_in6_type);
0217       }
0218     default:
0219       ec = boost::asio::error::address_family_not_supported;
0220       return addr_len;
0221     }
0222   }
0223   catch (Platform::Exception^ e)
0224   {
0225     ec = boost::system::error_code(e->HResult,
0226         boost::system::system_category());
0227     return addr_len;
0228   }
0229 }
0230 
0231 boost::system::error_code winrt_ssocket_service_base::do_set_option(
0232     winrt_ssocket_service_base::base_implementation_type& impl,
0233     int level, int optname, const void* optval,
0234     std::size_t optlen, boost::system::error_code& ec)
0235 {
0236   if (!is_open(impl))
0237   {
0238     ec = boost::asio::error::bad_descriptor;
0239     return ec;
0240   }
0241 
0242   try
0243   {
0244     if (level == BOOST_ASIO_OS_DEF(SOL_SOCKET)
0245         && optname == BOOST_ASIO_OS_DEF(SO_KEEPALIVE))
0246     {
0247       if (optlen == sizeof(int))
0248       {
0249         int value = 0;
0250         std::memcpy(&value, optval, optlen);
0251         impl.socket_->Control->KeepAlive = !!value;
0252         ec = boost::system::error_code();
0253       }
0254       else
0255       {
0256         ec = boost::asio::error::invalid_argument;
0257       }
0258     }
0259     else if (level == BOOST_ASIO_OS_DEF(IPPROTO_TCP)
0260         && optname == BOOST_ASIO_OS_DEF(TCP_NODELAY))
0261     {
0262       if (optlen == sizeof(int))
0263       {
0264         int value = 0;
0265         std::memcpy(&value, optval, optlen);
0266         impl.socket_->Control->NoDelay = !!value;
0267         ec = boost::system::error_code();
0268       }
0269       else
0270       {
0271         ec = boost::asio::error::invalid_argument;
0272       }
0273     }
0274     else
0275     {
0276       ec = boost::asio::error::invalid_argument;
0277     }
0278   }
0279   catch (Platform::Exception^ e)
0280   {
0281     ec = boost::system::error_code(e->HResult,
0282         boost::system::system_category());
0283   }
0284 
0285   return ec;
0286 }
0287 
0288 void winrt_ssocket_service_base::do_get_option(
0289     const winrt_ssocket_service_base::base_implementation_type& impl,
0290     int level, int optname, void* optval,
0291     std::size_t* optlen, boost::system::error_code& ec) const
0292 {
0293   if (!is_open(impl))
0294   {
0295     ec = boost::asio::error::bad_descriptor;
0296     return;
0297   }
0298 
0299   try
0300   {
0301     if (level == BOOST_ASIO_OS_DEF(SOL_SOCKET)
0302         && optname == BOOST_ASIO_OS_DEF(SO_KEEPALIVE))
0303     {
0304       if (*optlen >= sizeof(int))
0305       {
0306         int value = impl.socket_->Control->KeepAlive ? 1 : 0;
0307         std::memcpy(optval, &value, sizeof(int));
0308         *optlen = sizeof(int);
0309         ec = boost::system::error_code();
0310       }
0311       else
0312       {
0313         ec = boost::asio::error::invalid_argument;
0314       }
0315     }
0316     else if (level == BOOST_ASIO_OS_DEF(IPPROTO_TCP)
0317         && optname == BOOST_ASIO_OS_DEF(TCP_NODELAY))
0318     {
0319       if (*optlen >= sizeof(int))
0320       {
0321         int value = impl.socket_->Control->NoDelay ? 1 : 0;
0322         std::memcpy(optval, &value, sizeof(int));
0323         *optlen = sizeof(int);
0324         ec = boost::system::error_code();
0325       }
0326       else
0327       {
0328         ec = boost::asio::error::invalid_argument;
0329       }
0330     }
0331     else
0332     {
0333       ec = boost::asio::error::invalid_argument;
0334     }
0335   }
0336   catch (Platform::Exception^ e)
0337   {
0338     ec = boost::system::error_code(e->HResult,
0339         boost::system::system_category());
0340   }
0341 }
0342 
0343 boost::system::error_code winrt_ssocket_service_base::do_connect(
0344     winrt_ssocket_service_base::base_implementation_type& impl,
0345     const void* addr, boost::system::error_code& ec)
0346 {
0347   if (!is_open(impl))
0348   {
0349     ec = boost::asio::error::bad_descriptor;
0350     return ec;
0351   }
0352 
0353   char addr_string[max_addr_v6_str_len];
0354   unsigned short port;
0355   switch (static_cast<const socket_addr_type*>(addr)->sa_family)
0356   {
0357   case BOOST_ASIO_OS_DEF(AF_INET):
0358     socket_ops::inet_ntop(BOOST_ASIO_OS_DEF(AF_INET),
0359         &reinterpret_cast<const sockaddr_in4_type*>(addr)->sin_addr,
0360         addr_string, sizeof(addr_string), 0, ec);
0361     port = socket_ops::network_to_host_short(
0362         reinterpret_cast<const sockaddr_in4_type*>(addr)->sin_port);
0363     break;
0364   case BOOST_ASIO_OS_DEF(AF_INET6):
0365     socket_ops::inet_ntop(BOOST_ASIO_OS_DEF(AF_INET6),
0366         &reinterpret_cast<const sockaddr_in6_type*>(addr)->sin6_addr,
0367         addr_string, sizeof(addr_string), 0, ec);
0368     port = socket_ops::network_to_host_short(
0369         reinterpret_cast<const sockaddr_in6_type*>(addr)->sin6_port);
0370     break;
0371   default:
0372     ec = boost::asio::error::address_family_not_supported;
0373     return ec;
0374   }
0375 
0376   if (!ec) try
0377   {
0378     async_manager_.sync(impl.socket_->ConnectAsync(
0379           ref new Windows::Networking::HostName(
0380             winrt_utils::string(addr_string)),
0381           winrt_utils::string(port)), ec);
0382   }
0383   catch (Platform::Exception^ e)
0384   {
0385     ec = boost::system::error_code(e->HResult,
0386         boost::system::system_category());
0387   }
0388 
0389   return ec;
0390 }
0391 
0392 void winrt_ssocket_service_base::start_connect_op(
0393     winrt_ssocket_service_base::base_implementation_type& impl,
0394     const void* addr, winrt_async_op<void>* op, bool is_continuation)
0395 {
0396   if (!is_open(impl))
0397   {
0398     op->ec_ = boost::asio::error::bad_descriptor;
0399     scheduler_.post_immediate_completion(op, is_continuation);
0400     return;
0401   }
0402 
0403   char addr_string[max_addr_v6_str_len];
0404   unsigned short port = 0;
0405   switch (static_cast<const socket_addr_type*>(addr)->sa_family)
0406   {
0407   case BOOST_ASIO_OS_DEF(AF_INET):
0408     socket_ops::inet_ntop(BOOST_ASIO_OS_DEF(AF_INET),
0409         &reinterpret_cast<const sockaddr_in4_type*>(addr)->sin_addr,
0410         addr_string, sizeof(addr_string), 0, op->ec_);
0411     port = socket_ops::network_to_host_short(
0412         reinterpret_cast<const sockaddr_in4_type*>(addr)->sin_port);
0413     break;
0414   case BOOST_ASIO_OS_DEF(AF_INET6):
0415     socket_ops::inet_ntop(BOOST_ASIO_OS_DEF(AF_INET6),
0416         &reinterpret_cast<const sockaddr_in6_type*>(addr)->sin6_addr,
0417         addr_string, sizeof(addr_string), 0, op->ec_);
0418     port = socket_ops::network_to_host_short(
0419         reinterpret_cast<const sockaddr_in6_type*>(addr)->sin6_port);
0420     break;
0421   default:
0422     op->ec_ = boost::asio::error::address_family_not_supported;
0423     break;
0424   }
0425 
0426   if (op->ec_)
0427   {
0428     scheduler_.post_immediate_completion(op, is_continuation);
0429     return;
0430   }
0431 
0432   try
0433   {
0434     async_manager_.async(impl.socket_->ConnectAsync(
0435           ref new Windows::Networking::HostName(
0436             winrt_utils::string(addr_string)),
0437           winrt_utils::string(port)), op);
0438   }
0439   catch (Platform::Exception^ e)
0440   {
0441     op->ec_ = boost::system::error_code(
0442         e->HResult, boost::system::system_category());
0443     scheduler_.post_immediate_completion(op, is_continuation);
0444   }
0445 }
0446 
0447 std::size_t winrt_ssocket_service_base::do_send(
0448     winrt_ssocket_service_base::base_implementation_type& impl,
0449     const boost::asio::const_buffer& data,
0450     socket_base::message_flags flags, boost::system::error_code& ec)
0451 {
0452   if (flags)
0453   {
0454     ec = boost::asio::error::operation_not_supported;
0455     return 0;
0456   }
0457 
0458   if (!is_open(impl))
0459   {
0460     ec = boost::asio::error::bad_descriptor;
0461     return 0;
0462   }
0463 
0464   try
0465   {
0466     buffer_sequence_adapter<boost::asio::const_buffer,
0467       boost::asio::const_buffer> bufs(boost::asio::buffer(data));
0468 
0469     if (bufs.all_empty())
0470     {
0471       ec = boost::system::error_code();
0472       return 0;
0473     }
0474 
0475     return async_manager_.sync(
0476         impl.socket_->OutputStream->WriteAsync(bufs.buffers()[0]), ec);
0477   }
0478   catch (Platform::Exception^ e)
0479   {
0480     ec = boost::system::error_code(e->HResult,
0481         boost::system::system_category());
0482     return 0;
0483   }
0484 }
0485 
0486 void winrt_ssocket_service_base::start_send_op(
0487       winrt_ssocket_service_base::base_implementation_type& impl,
0488       const boost::asio::const_buffer& data, socket_base::message_flags flags,
0489       winrt_async_op<unsigned int>* op, bool is_continuation)
0490 {
0491   if (flags)
0492   {
0493     op->ec_ = boost::asio::error::operation_not_supported;
0494     scheduler_.post_immediate_completion(op, is_continuation);
0495     return;
0496   }
0497 
0498   if (!is_open(impl))
0499   {
0500     op->ec_ = boost::asio::error::bad_descriptor;
0501     scheduler_.post_immediate_completion(op, is_continuation);
0502     return;
0503   }
0504 
0505   try
0506   {
0507     buffer_sequence_adapter<boost::asio::const_buffer,
0508         boost::asio::const_buffer> bufs(boost::asio::buffer(data));
0509 
0510     if (bufs.all_empty())
0511     {
0512       scheduler_.post_immediate_completion(op, is_continuation);
0513       return;
0514     }
0515 
0516     async_manager_.async(
0517         impl.socket_->OutputStream->WriteAsync(bufs.buffers()[0]), op);
0518   }
0519   catch (Platform::Exception^ e)
0520   {
0521     op->ec_ = boost::system::error_code(e->HResult,
0522         boost::system::system_category());
0523     scheduler_.post_immediate_completion(op, is_continuation);
0524   }
0525 }
0526 
0527 std::size_t winrt_ssocket_service_base::do_receive(
0528     winrt_ssocket_service_base::base_implementation_type& impl,
0529     const boost::asio::mutable_buffer& data,
0530     socket_base::message_flags flags, boost::system::error_code& ec)
0531 {
0532   if (flags)
0533   {
0534     ec = boost::asio::error::operation_not_supported;
0535     return 0;
0536   }
0537 
0538   if (!is_open(impl))
0539   {
0540     ec = boost::asio::error::bad_descriptor;
0541     return 0;
0542   }
0543 
0544   try
0545   {
0546     buffer_sequence_adapter<boost::asio::mutable_buffer,
0547         boost::asio::mutable_buffer> bufs(boost::asio::buffer(data));
0548 
0549     if (bufs.all_empty())
0550     {
0551       ec = boost::system::error_code();
0552       return 0;
0553     }
0554 
0555     async_manager_.sync(
0556         impl.socket_->InputStream->ReadAsync(
0557           bufs.buffers()[0], bufs.buffers()[0]->Capacity,
0558           Windows::Storage::Streams::InputStreamOptions::Partial), ec);
0559 
0560     std::size_t bytes_transferred = bufs.buffers()[0]->Length;
0561     if (bytes_transferred == 0 && !ec)
0562     {
0563       ec = boost::asio::error::eof;
0564     }
0565 
0566     return bytes_transferred;
0567   }
0568   catch (Platform::Exception^ e)
0569   {
0570     ec = boost::system::error_code(e->HResult,
0571         boost::system::system_category());
0572     return 0;
0573   }
0574 }
0575 
0576 void winrt_ssocket_service_base::start_receive_op(
0577       winrt_ssocket_service_base::base_implementation_type& impl,
0578       const boost::asio::mutable_buffer& data, socket_base::message_flags flags,
0579       winrt_async_op<Windows::Storage::Streams::IBuffer^>* op,
0580       bool is_continuation)
0581 {
0582   if (flags)
0583   {
0584     op->ec_ = boost::asio::error::operation_not_supported;
0585     scheduler_.post_immediate_completion(op, is_continuation);
0586     return;
0587   }
0588 
0589   if (!is_open(impl))
0590   {
0591     op->ec_ = boost::asio::error::bad_descriptor;
0592     scheduler_.post_immediate_completion(op, is_continuation);
0593     return;
0594   }
0595 
0596   try
0597   {
0598     buffer_sequence_adapter<boost::asio::mutable_buffer,
0599         boost::asio::mutable_buffer> bufs(boost::asio::buffer(data));
0600 
0601     if (bufs.all_empty())
0602     {
0603       scheduler_.post_immediate_completion(op, is_continuation);
0604       return;
0605     }
0606 
0607     async_manager_.async(
0608         impl.socket_->InputStream->ReadAsync(
0609           bufs.buffers()[0], bufs.buffers()[0]->Capacity,
0610           Windows::Storage::Streams::InputStreamOptions::Partial), op);
0611   }
0612   catch (Platform::Exception^ e)
0613   {
0614     op->ec_ = boost::system::error_code(e->HResult,
0615         boost::system::system_category());
0616     scheduler_.post_immediate_completion(op, is_continuation);
0617   }
0618 }
0619 
0620 } // namespace detail
0621 } // namespace asio
0622 } // namespace boost
0623 
0624 #include <boost/asio/detail/pop_options.hpp>
0625 
0626 #endif // defined(BOOST_ASIO_WINDOWS_RUNTIME)
0627 
0628 #endif // BOOST_ASIO_DETAIL_IMPL_WINRT_SSOCKET_SERVICE_BASE_IPP