File indexing completed on 2025-01-18 09:28:36
0001
0002
0003
0004
0005
0006
0007
0008
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
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
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
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
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
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
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
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 }
0621 }
0622 }
0623
0624 #include <boost/asio/detail/pop_options.hpp>
0625
0626 #endif
0627
0628 #endif