2 // detail/impl/winrt_ssocket_service_base.ipp
3 // ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
5 // Copyright (c) 2003-2017 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 boost::asio::io_context& io_context)
35 : io_context_(use_service<io_context_impl>(io_context)),
36 async_manager_(use_service<winrt_async_manager>(io_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)
71 impl.socket_ = other_impl.socket_;
72 other_impl.socket_ = nullptr;
74 // Insert implementation into linked list of all implementations.
75 boost::asio::detail::mutex::scoped_lock lock(mutex_);
76 impl.next_ = impl_list_;
79 impl_list_->prev_ = &impl;
83 void winrt_ssocket_service_base::base_move_assign(
84 winrt_ssocket_service_base::base_implementation_type& impl,
85 winrt_ssocket_service_base& other_service,
86 winrt_ssocket_service_base::base_implementation_type& other_impl)
88 boost::system::error_code ignored_ec;
89 close(impl, ignored_ec);
91 if (this != &other_service)
93 // Remove implementation from linked list of all implementations.
94 boost::asio::detail::mutex::scoped_lock lock(mutex_);
95 if (impl_list_ == &impl)
96 impl_list_ = impl.next_;
98 impl.prev_->next_ = impl.next_;
100 impl.next_->prev_= impl.prev_;
105 impl.socket_ = other_impl.socket_;
106 other_impl.socket_ = nullptr;
108 if (this != &other_service)
110 // Insert implementation into linked list of all implementations.
111 boost::asio::detail::mutex::scoped_lock lock(other_service.mutex_);
112 impl.next_ = other_service.impl_list_;
114 if (other_service.impl_list_)
115 other_service.impl_list_->prev_ = &impl;
116 other_service.impl_list_ = &impl;
120 void winrt_ssocket_service_base::destroy(
121 winrt_ssocket_service_base::base_implementation_type& impl)
123 boost::system::error_code ignored_ec;
124 close(impl, ignored_ec);
126 // Remove implementation from linked list of all implementations.
127 boost::asio::detail::mutex::scoped_lock lock(mutex_);
128 if (impl_list_ == &impl)
129 impl_list_ = impl.next_;
131 impl.prev_->next_ = impl.next_;
133 impl.next_->prev_= impl.prev_;
138 boost::system::error_code winrt_ssocket_service_base::close(
139 winrt_ssocket_service_base::base_implementation_type& impl,
140 boost::system::error_code& ec)
145 impl.socket_ = nullptr;
148 ec = boost::system::error_code();
152 winrt_ssocket_service_base::native_handle_type
153 winrt_ssocket_service_base::release(
154 winrt_ssocket_service_base::base_implementation_type& impl,
155 boost::system::error_code& ec)
164 native_handle_type tmp = impl.socket_;
165 impl.socket_ = nullptr;
169 std::size_t winrt_ssocket_service_base::do_get_endpoint(
170 const base_implementation_type& impl, bool local,
171 void* addr, std::size_t addr_len, boost::system::error_code& ec) const
175 ec = boost::asio::error::bad_descriptor;
181 std::string addr_string = winrt_utils::string(local
182 ? impl.socket_->Information->LocalAddress->CanonicalName
183 : impl.socket_->Information->RemoteAddress->CanonicalName);
184 unsigned short port = winrt_utils::integer(local
185 ? impl.socket_->Information->LocalPort
186 : impl.socket_->Information->RemotePort);
187 unsigned long scope = 0;
189 switch (reinterpret_cast<const socket_addr_type*>(addr)->sa_family)
191 case BOOST_ASIO_OS_DEF(AF_INET):
192 if (addr_len < sizeof(sockaddr_in4_type))
194 ec = boost::asio::error::invalid_argument;
199 socket_ops::inet_pton(BOOST_ASIO_OS_DEF(AF_INET), addr_string.c_str(),
200 &reinterpret_cast<sockaddr_in4_type*>(addr)->sin_addr, &scope, ec);
201 reinterpret_cast<sockaddr_in4_type*>(addr)->sin_port
202 = socket_ops::host_to_network_short(port);
203 ec = boost::system::error_code();
204 return sizeof(sockaddr_in4_type);
206 case BOOST_ASIO_OS_DEF(AF_INET6):
207 if (addr_len < sizeof(sockaddr_in6_type))
209 ec = boost::asio::error::invalid_argument;
214 socket_ops::inet_pton(BOOST_ASIO_OS_DEF(AF_INET6), addr_string.c_str(),
215 &reinterpret_cast<sockaddr_in6_type*>(addr)->sin6_addr, &scope, ec);
216 reinterpret_cast<sockaddr_in6_type*>(addr)->sin6_port
217 = socket_ops::host_to_network_short(port);
218 ec = boost::system::error_code();
219 return sizeof(sockaddr_in6_type);
222 ec = boost::asio::error::address_family_not_supported;
226 catch (Platform::Exception^ e)
228 ec = boost::system::error_code(e->HResult,
229 boost::system::system_category());
234 boost::system::error_code winrt_ssocket_service_base::do_set_option(
235 winrt_ssocket_service_base::base_implementation_type& impl,
236 int level, int optname, const void* optval,
237 std::size_t optlen, boost::system::error_code& ec)
241 ec = boost::asio::error::bad_descriptor;
247 if (level == BOOST_ASIO_OS_DEF(SOL_SOCKET)
248 && optname == BOOST_ASIO_OS_DEF(SO_KEEPALIVE))
250 if (optlen == sizeof(int))
253 std::memcpy(&value, optval, optlen);
254 impl.socket_->Control->KeepAlive = !!value;
255 ec = boost::system::error_code();
259 ec = boost::asio::error::invalid_argument;
262 else if (level == BOOST_ASIO_OS_DEF(IPPROTO_TCP)
263 && optname == BOOST_ASIO_OS_DEF(TCP_NODELAY))
265 if (optlen == sizeof(int))
268 std::memcpy(&value, optval, optlen);
269 impl.socket_->Control->NoDelay = !!value;
270 ec = boost::system::error_code();
274 ec = boost::asio::error::invalid_argument;
279 ec = boost::asio::error::invalid_argument;
282 catch (Platform::Exception^ e)
284 ec = boost::system::error_code(e->HResult,
285 boost::system::system_category());
291 void winrt_ssocket_service_base::do_get_option(
292 const winrt_ssocket_service_base::base_implementation_type& impl,
293 int level, int optname, void* optval,
294 std::size_t* optlen, boost::system::error_code& ec) const
298 ec = boost::asio::error::bad_descriptor;
304 if (level == BOOST_ASIO_OS_DEF(SOL_SOCKET)
305 && optname == BOOST_ASIO_OS_DEF(SO_KEEPALIVE))
307 if (*optlen >= sizeof(int))
309 int value = impl.socket_->Control->KeepAlive ? 1 : 0;
310 std::memcpy(optval, &value, sizeof(int));
311 *optlen = sizeof(int);
312 ec = boost::system::error_code();
316 ec = boost::asio::error::invalid_argument;
319 else if (level == BOOST_ASIO_OS_DEF(IPPROTO_TCP)
320 && optname == BOOST_ASIO_OS_DEF(TCP_NODELAY))
322 if (*optlen >= sizeof(int))
324 int value = impl.socket_->Control->NoDelay ? 1 : 0;
325 std::memcpy(optval, &value, sizeof(int));
326 *optlen = sizeof(int);
327 ec = boost::system::error_code();
331 ec = boost::asio::error::invalid_argument;
336 ec = boost::asio::error::invalid_argument;
339 catch (Platform::Exception^ e)
341 ec = boost::system::error_code(e->HResult,
342 boost::system::system_category());
346 boost::system::error_code winrt_ssocket_service_base::do_connect(
347 winrt_ssocket_service_base::base_implementation_type& impl,
348 const void* addr, boost::system::error_code& ec)
352 ec = boost::asio::error::bad_descriptor;
356 char addr_string[max_addr_v6_str_len];
358 switch (reinterpret_cast<const socket_addr_type*>(addr)->sa_family)
360 case BOOST_ASIO_OS_DEF(AF_INET):
361 socket_ops::inet_ntop(BOOST_ASIO_OS_DEF(AF_INET),
362 &reinterpret_cast<const sockaddr_in4_type*>(addr)->sin_addr,
363 addr_string, sizeof(addr_string), 0, ec);
364 port = socket_ops::network_to_host_short(
365 reinterpret_cast<const sockaddr_in4_type*>(addr)->sin_port);
367 case BOOST_ASIO_OS_DEF(AF_INET6):
368 socket_ops::inet_ntop(BOOST_ASIO_OS_DEF(AF_INET6),
369 &reinterpret_cast<const sockaddr_in6_type*>(addr)->sin6_addr,
370 addr_string, sizeof(addr_string), 0, ec);
371 port = socket_ops::network_to_host_short(
372 reinterpret_cast<const sockaddr_in6_type*>(addr)->sin6_port);
375 ec = boost::asio::error::address_family_not_supported;
381 async_manager_.sync(impl.socket_->ConnectAsync(
382 ref new Windows::Networking::HostName(
383 winrt_utils::string(addr_string)),
384 winrt_utils::string(port)), ec);
386 catch (Platform::Exception^ e)
388 ec = boost::system::error_code(e->HResult,
389 boost::system::system_category());
395 void winrt_ssocket_service_base::start_connect_op(
396 winrt_ssocket_service_base::base_implementation_type& impl,
397 const void* addr, winrt_async_op<void>* op, bool is_continuation)
401 op->ec_ = boost::asio::error::bad_descriptor;
402 io_context_.post_immediate_completion(op, is_continuation);
406 char addr_string[max_addr_v6_str_len];
407 unsigned short port = 0;
408 switch (reinterpret_cast<const socket_addr_type*>(addr)->sa_family)
410 case BOOST_ASIO_OS_DEF(AF_INET):
411 socket_ops::inet_ntop(BOOST_ASIO_OS_DEF(AF_INET),
412 &reinterpret_cast<const sockaddr_in4_type*>(addr)->sin_addr,
413 addr_string, sizeof(addr_string), 0, op->ec_);
414 port = socket_ops::network_to_host_short(
415 reinterpret_cast<const sockaddr_in4_type*>(addr)->sin_port);
417 case BOOST_ASIO_OS_DEF(AF_INET6):
418 socket_ops::inet_ntop(BOOST_ASIO_OS_DEF(AF_INET6),
419 &reinterpret_cast<const sockaddr_in6_type*>(addr)->sin6_addr,
420 addr_string, sizeof(addr_string), 0, op->ec_);
421 port = socket_ops::network_to_host_short(
422 reinterpret_cast<const sockaddr_in6_type*>(addr)->sin6_port);
425 op->ec_ = boost::asio::error::address_family_not_supported;
431 io_context_.post_immediate_completion(op, is_continuation);
437 async_manager_.async(impl.socket_->ConnectAsync(
438 ref new Windows::Networking::HostName(
439 winrt_utils::string(addr_string)),
440 winrt_utils::string(port)), op);
442 catch (Platform::Exception^ e)
444 op->ec_ = boost::system::error_code(
445 e->HResult, boost::system::system_category());
446 io_context_.post_immediate_completion(op, is_continuation);
450 std::size_t winrt_ssocket_service_base::do_send(
451 winrt_ssocket_service_base::base_implementation_type& impl,
452 const boost::asio::const_buffer& data,
453 socket_base::message_flags flags, boost::system::error_code& ec)
457 ec = boost::asio::error::operation_not_supported;
463 ec = boost::asio::error::bad_descriptor;
469 buffer_sequence_adapter<boost::asio::const_buffer,
470 boost::asio::const_buffer> bufs(boost::asio::buffer(data));
472 if (bufs.all_empty())
474 ec = boost::system::error_code();
478 return async_manager_.sync(
479 impl.socket_->OutputStream->WriteAsync(bufs.buffers()[0]), ec);
481 catch (Platform::Exception^ e)
483 ec = boost::system::error_code(e->HResult,
484 boost::system::system_category());
489 void winrt_ssocket_service_base::start_send_op(
490 winrt_ssocket_service_base::base_implementation_type& impl,
491 const boost::asio::const_buffer& data, socket_base::message_flags flags,
492 winrt_async_op<unsigned int>* op, bool is_continuation)
496 op->ec_ = boost::asio::error::operation_not_supported;
497 io_context_.post_immediate_completion(op, is_continuation);
503 op->ec_ = boost::asio::error::bad_descriptor;
504 io_context_.post_immediate_completion(op, is_continuation);
510 buffer_sequence_adapter<boost::asio::const_buffer,
511 boost::asio::const_buffer> bufs(boost::asio::buffer(data));
513 if (bufs.all_empty())
515 io_context_.post_immediate_completion(op, is_continuation);
519 async_manager_.async(
520 impl.socket_->OutputStream->WriteAsync(bufs.buffers()[0]), op);
522 catch (Platform::Exception^ e)
524 op->ec_ = boost::system::error_code(e->HResult,
525 boost::system::system_category());
526 io_context_.post_immediate_completion(op, is_continuation);
530 std::size_t winrt_ssocket_service_base::do_receive(
531 winrt_ssocket_service_base::base_implementation_type& impl,
532 const boost::asio::mutable_buffer& data,
533 socket_base::message_flags flags, boost::system::error_code& ec)
537 ec = boost::asio::error::operation_not_supported;
543 ec = boost::asio::error::bad_descriptor;
549 buffer_sequence_adapter<boost::asio::mutable_buffer,
550 boost::asio::mutable_buffer> bufs(boost::asio::buffer(data));
552 if (bufs.all_empty())
554 ec = boost::system::error_code();
559 impl.socket_->InputStream->ReadAsync(
560 bufs.buffers()[0], bufs.buffers()[0]->Capacity,
561 Windows::Storage::Streams::InputStreamOptions::Partial), ec);
563 std::size_t bytes_transferred = bufs.buffers()[0]->Length;
564 if (bytes_transferred == 0 && !ec)
566 ec = boost::asio::error::eof;
569 return bytes_transferred;
571 catch (Platform::Exception^ e)
573 ec = boost::system::error_code(e->HResult,
574 boost::system::system_category());
579 void winrt_ssocket_service_base::start_receive_op(
580 winrt_ssocket_service_base::base_implementation_type& impl,
581 const boost::asio::mutable_buffer& data, socket_base::message_flags flags,
582 winrt_async_op<Windows::Storage::Streams::IBuffer^>* op,
583 bool is_continuation)
587 op->ec_ = boost::asio::error::operation_not_supported;
588 io_context_.post_immediate_completion(op, is_continuation);
594 op->ec_ = boost::asio::error::bad_descriptor;
595 io_context_.post_immediate_completion(op, is_continuation);
601 buffer_sequence_adapter<boost::asio::mutable_buffer,
602 boost::asio::mutable_buffer> bufs(boost::asio::buffer(data));
604 if (bufs.all_empty())
606 io_context_.post_immediate_completion(op, is_continuation);
610 async_manager_.async(
611 impl.socket_->InputStream->ReadAsync(
612 bufs.buffers()[0], bufs.buffers()[0]->Capacity,
613 Windows::Storage::Streams::InputStreamOptions::Partial), op);
615 catch (Platform::Exception^ e)
617 op->ec_ = boost::system::error_code(e->HResult,
618 boost::system::system_category());
619 io_context_.post_immediate_completion(op, is_continuation);
623 } // namespace detail
627 #include <boost/asio/detail/pop_options.hpp>
629 #endif // defined(BOOST_ASIO_WINDOWS_RUNTIME)
631 #endif // BOOST_ASIO_DETAIL_IMPL_WINRT_SSOCKET_SERVICE_BASE_IPP