2 // detail/impl/winrt_ssocket_service_base.ipp
3 // ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
5 // Copyright (c) 2003-2016 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_service& io_service)
35 : io_service_(use_service<io_service_impl>(io_service)),
36 async_manager_(use_service<winrt_async_manager>(io_service)),
42 void winrt_ssocket_service_base::shutdown_service()
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 std::size_t winrt_ssocket_service_base::do_get_endpoint(
153 const base_implementation_type& impl, bool local,
154 void* addr, std::size_t addr_len, boost::system::error_code& ec) const
158 ec = boost::asio::error::bad_descriptor;
164 std::string addr_string = winrt_utils::string(local
165 ? impl.socket_->Information->LocalAddress->CanonicalName
166 : impl.socket_->Information->RemoteAddress->CanonicalName);
167 unsigned short port = winrt_utils::integer(local
168 ? impl.socket_->Information->LocalPort
169 : impl.socket_->Information->RemotePort);
170 unsigned long scope = 0;
172 switch (reinterpret_cast<const socket_addr_type*>(addr)->sa_family)
174 case BOOST_ASIO_OS_DEF(AF_INET):
175 if (addr_len < sizeof(sockaddr_in4_type))
177 ec = boost::asio::error::invalid_argument;
182 socket_ops::inet_pton(BOOST_ASIO_OS_DEF(AF_INET), addr_string.c_str(),
183 &reinterpret_cast<sockaddr_in4_type*>(addr)->sin_addr, &scope, ec);
184 reinterpret_cast<sockaddr_in4_type*>(addr)->sin_port
185 = socket_ops::host_to_network_short(port);
186 ec = boost::system::error_code();
187 return sizeof(sockaddr_in4_type);
189 case BOOST_ASIO_OS_DEF(AF_INET6):
190 if (addr_len < sizeof(sockaddr_in6_type))
192 ec = boost::asio::error::invalid_argument;
197 socket_ops::inet_pton(BOOST_ASIO_OS_DEF(AF_INET6), addr_string.c_str(),
198 &reinterpret_cast<sockaddr_in6_type*>(addr)->sin6_addr, &scope, ec);
199 reinterpret_cast<sockaddr_in6_type*>(addr)->sin6_port
200 = socket_ops::host_to_network_short(port);
201 ec = boost::system::error_code();
202 return sizeof(sockaddr_in6_type);
205 ec = boost::asio::error::address_family_not_supported;
209 catch (Platform::Exception^ e)
211 ec = boost::system::error_code(e->HResult,
212 boost::system::system_category());
217 boost::system::error_code winrt_ssocket_service_base::do_set_option(
218 winrt_ssocket_service_base::base_implementation_type& impl,
219 int level, int optname, const void* optval,
220 std::size_t optlen, boost::system::error_code& ec)
224 ec = boost::asio::error::bad_descriptor;
230 if (level == BOOST_ASIO_OS_DEF(SOL_SOCKET)
231 && optname == BOOST_ASIO_OS_DEF(SO_KEEPALIVE))
233 if (optlen == sizeof(int))
236 std::memcpy(&value, optval, optlen);
237 impl.socket_->Control->KeepAlive = !!value;
238 ec = boost::system::error_code();
242 ec = boost::asio::error::invalid_argument;
245 else if (level == BOOST_ASIO_OS_DEF(IPPROTO_TCP)
246 && optname == BOOST_ASIO_OS_DEF(TCP_NODELAY))
248 if (optlen == sizeof(int))
251 std::memcpy(&value, optval, optlen);
252 impl.socket_->Control->NoDelay = !!value;
253 ec = boost::system::error_code();
257 ec = boost::asio::error::invalid_argument;
262 ec = boost::asio::error::invalid_argument;
265 catch (Platform::Exception^ e)
267 ec = boost::system::error_code(e->HResult,
268 boost::system::system_category());
274 void winrt_ssocket_service_base::do_get_option(
275 const winrt_ssocket_service_base::base_implementation_type& impl,
276 int level, int optname, void* optval,
277 std::size_t* optlen, boost::system::error_code& ec) const
281 ec = boost::asio::error::bad_descriptor;
287 if (level == BOOST_ASIO_OS_DEF(SOL_SOCKET)
288 && optname == BOOST_ASIO_OS_DEF(SO_KEEPALIVE))
290 if (*optlen >= sizeof(int))
292 int value = impl.socket_->Control->KeepAlive ? 1 : 0;
293 std::memcpy(optval, &value, sizeof(int));
294 *optlen = sizeof(int);
295 ec = boost::system::error_code();
299 ec = boost::asio::error::invalid_argument;
302 else if (level == BOOST_ASIO_OS_DEF(IPPROTO_TCP)
303 && optname == BOOST_ASIO_OS_DEF(TCP_NODELAY))
305 if (*optlen >= sizeof(int))
307 int value = impl.socket_->Control->NoDelay ? 1 : 0;
308 std::memcpy(optval, &value, sizeof(int));
309 *optlen = sizeof(int);
310 ec = boost::system::error_code();
314 ec = boost::asio::error::invalid_argument;
319 ec = boost::asio::error::invalid_argument;
322 catch (Platform::Exception^ e)
324 ec = boost::system::error_code(e->HResult,
325 boost::system::system_category());
329 boost::system::error_code winrt_ssocket_service_base::do_connect(
330 winrt_ssocket_service_base::base_implementation_type& impl,
331 const void* addr, boost::system::error_code& ec)
335 ec = boost::asio::error::bad_descriptor;
339 char addr_string[max_addr_v6_str_len];
341 switch (reinterpret_cast<const socket_addr_type*>(addr)->sa_family)
343 case BOOST_ASIO_OS_DEF(AF_INET):
344 socket_ops::inet_ntop(BOOST_ASIO_OS_DEF(AF_INET),
345 &reinterpret_cast<const sockaddr_in4_type*>(addr)->sin_addr,
346 addr_string, sizeof(addr_string), 0, ec);
347 port = socket_ops::network_to_host_short(
348 reinterpret_cast<const sockaddr_in4_type*>(addr)->sin_port);
350 case BOOST_ASIO_OS_DEF(AF_INET6):
351 socket_ops::inet_ntop(BOOST_ASIO_OS_DEF(AF_INET6),
352 &reinterpret_cast<const sockaddr_in6_type*>(addr)->sin6_addr,
353 addr_string, sizeof(addr_string), 0, ec);
354 port = socket_ops::network_to_host_short(
355 reinterpret_cast<const sockaddr_in6_type*>(addr)->sin6_port);
358 ec = boost::asio::error::address_family_not_supported;
364 async_manager_.sync(impl.socket_->ConnectAsync(
365 ref new Windows::Networking::HostName(
366 winrt_utils::string(addr_string)),
367 winrt_utils::string(port)), ec);
369 catch (Platform::Exception^ e)
371 ec = boost::system::error_code(e->HResult,
372 boost::system::system_category());
378 void winrt_ssocket_service_base::start_connect_op(
379 winrt_ssocket_service_base::base_implementation_type& impl,
380 const void* addr, winrt_async_op<void>* op, bool is_continuation)
384 op->ec_ = boost::asio::error::bad_descriptor;
385 io_service_.post_immediate_completion(op, is_continuation);
389 char addr_string[max_addr_v6_str_len];
390 unsigned short port = 0;
391 switch (reinterpret_cast<const socket_addr_type*>(addr)->sa_family)
393 case BOOST_ASIO_OS_DEF(AF_INET):
394 socket_ops::inet_ntop(BOOST_ASIO_OS_DEF(AF_INET),
395 &reinterpret_cast<const sockaddr_in4_type*>(addr)->sin_addr,
396 addr_string, sizeof(addr_string), 0, op->ec_);
397 port = socket_ops::network_to_host_short(
398 reinterpret_cast<const sockaddr_in4_type*>(addr)->sin_port);
400 case BOOST_ASIO_OS_DEF(AF_INET6):
401 socket_ops::inet_ntop(BOOST_ASIO_OS_DEF(AF_INET6),
402 &reinterpret_cast<const sockaddr_in6_type*>(addr)->sin6_addr,
403 addr_string, sizeof(addr_string), 0, op->ec_);
404 port = socket_ops::network_to_host_short(
405 reinterpret_cast<const sockaddr_in6_type*>(addr)->sin6_port);
408 op->ec_ = boost::asio::error::address_family_not_supported;
414 io_service_.post_immediate_completion(op, is_continuation);
420 async_manager_.async(impl.socket_->ConnectAsync(
421 ref new Windows::Networking::HostName(
422 winrt_utils::string(addr_string)),
423 winrt_utils::string(port)), op);
425 catch (Platform::Exception^ e)
427 op->ec_ = boost::system::error_code(
428 e->HResult, boost::system::system_category());
429 io_service_.post_immediate_completion(op, is_continuation);
433 std::size_t winrt_ssocket_service_base::do_send(
434 winrt_ssocket_service_base::base_implementation_type& impl,
435 const boost::asio::const_buffer& data,
436 socket_base::message_flags flags, boost::system::error_code& ec)
440 ec = boost::asio::error::operation_not_supported;
446 ec = boost::asio::error::bad_descriptor;
452 buffer_sequence_adapter<boost::asio::const_buffer,
453 boost::asio::const_buffers_1> bufs(boost::asio::buffer(data));
455 if (bufs.all_empty())
457 ec = boost::system::error_code();
461 return async_manager_.sync(
462 impl.socket_->OutputStream->WriteAsync(bufs.buffers()[0]), ec);
464 catch (Platform::Exception^ e)
466 ec = boost::system::error_code(e->HResult,
467 boost::system::system_category());
472 void winrt_ssocket_service_base::start_send_op(
473 winrt_ssocket_service_base::base_implementation_type& impl,
474 const boost::asio::const_buffer& data, socket_base::message_flags flags,
475 winrt_async_op<unsigned int>* op, bool is_continuation)
479 op->ec_ = boost::asio::error::operation_not_supported;
480 io_service_.post_immediate_completion(op, is_continuation);
486 op->ec_ = boost::asio::error::bad_descriptor;
487 io_service_.post_immediate_completion(op, is_continuation);
493 buffer_sequence_adapter<boost::asio::const_buffer,
494 boost::asio::const_buffers_1> bufs(boost::asio::buffer(data));
496 if (bufs.all_empty())
498 io_service_.post_immediate_completion(op, is_continuation);
502 async_manager_.async(
503 impl.socket_->OutputStream->WriteAsync(bufs.buffers()[0]), op);
505 catch (Platform::Exception^ e)
507 op->ec_ = boost::system::error_code(e->HResult,
508 boost::system::system_category());
509 io_service_.post_immediate_completion(op, is_continuation);
513 std::size_t winrt_ssocket_service_base::do_receive(
514 winrt_ssocket_service_base::base_implementation_type& impl,
515 const boost::asio::mutable_buffer& data,
516 socket_base::message_flags flags, boost::system::error_code& ec)
520 ec = boost::asio::error::operation_not_supported;
526 ec = boost::asio::error::bad_descriptor;
532 buffer_sequence_adapter<boost::asio::mutable_buffer,
533 boost::asio::mutable_buffers_1> bufs(boost::asio::buffer(data));
535 if (bufs.all_empty())
537 ec = boost::system::error_code();
542 impl.socket_->InputStream->ReadAsync(
543 bufs.buffers()[0], bufs.buffers()[0]->Capacity,
544 Windows::Storage::Streams::InputStreamOptions::Partial), ec);
546 std::size_t bytes_transferred = bufs.buffers()[0]->Length;
547 if (bytes_transferred == 0 && !ec)
549 ec = boost::asio::error::eof;
552 return bytes_transferred;
554 catch (Platform::Exception^ e)
556 ec = boost::system::error_code(e->HResult,
557 boost::system::system_category());
562 void winrt_ssocket_service_base::start_receive_op(
563 winrt_ssocket_service_base::base_implementation_type& impl,
564 const boost::asio::mutable_buffer& data, socket_base::message_flags flags,
565 winrt_async_op<Windows::Storage::Streams::IBuffer^>* op,
566 bool is_continuation)
570 op->ec_ = boost::asio::error::operation_not_supported;
571 io_service_.post_immediate_completion(op, is_continuation);
577 op->ec_ = boost::asio::error::bad_descriptor;
578 io_service_.post_immediate_completion(op, is_continuation);
584 buffer_sequence_adapter<boost::asio::mutable_buffer,
585 boost::asio::mutable_buffers_1> bufs(boost::asio::buffer(data));
587 if (bufs.all_empty())
589 io_service_.post_immediate_completion(op, is_continuation);
593 async_manager_.async(
594 impl.socket_->InputStream->ReadAsync(
595 bufs.buffers()[0], bufs.buffers()[0]->Capacity,
596 Windows::Storage::Streams::InputStreamOptions::Partial), op);
598 catch (Platform::Exception^ e)
600 op->ec_ = boost::system::error_code(e->HResult,
601 boost::system::system_category());
602 io_service_.post_immediate_completion(op, is_continuation);
606 } // namespace detail
610 #include <boost/asio/detail/pop_options.hpp>
612 #endif // defined(BOOST_ASIO_WINDOWS_RUNTIME)
614 #endif // BOOST_ASIO_DETAIL_IMPL_WINRT_SSOCKET_SERVICE_BASE_IPP