Imported Upstream version 1.72.0
[platform/upstream/boost.git] / boost / asio / detail / impl / winrt_ssocket_service_base.ipp
1 //
2 // detail/impl/winrt_ssocket_service_base.ipp
3 // ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
4 //
5 // Copyright (c) 2003-2019 Christopher M. Kohlhoff (chris at kohlhoff dot com)
6 //
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)
9 //
10
11 #ifndef BOOST_ASIO_DETAIL_IMPL_WINRT_SSOCKET_SERVICE_BASE_IPP
12 #define BOOST_ASIO_DETAIL_IMPL_WINRT_SSOCKET_SERVICE_BASE_IPP
13
14 #if defined(_MSC_VER) && (_MSC_VER >= 1200)
15 # pragma once
16 #endif // defined(_MSC_VER) && (_MSC_VER >= 1200)
17
18 #include <boost/asio/detail/config.hpp>
19
20 #if defined(BOOST_ASIO_WINDOWS_RUNTIME)
21
22 #include <cstring>
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>
26
27 #include <boost/asio/detail/push_options.hpp>
28
29 namespace boost {
30 namespace asio {
31 namespace detail {
32
33 winrt_ssocket_service_base::winrt_ssocket_service_base(
34     execution_context& context)
35   : scheduler_(use_service<scheduler_impl>(context)),
36     async_manager_(use_service<winrt_async_manager>(context)),
37     mutex_(),
38     impl_list_(0)
39 {
40 }
41
42 void winrt_ssocket_service_base::base_shutdown()
43 {
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_;
47   while (impl)
48   {
49     boost::system::error_code ignored_ec;
50     close(*impl, ignored_ec);
51     impl = impl->next_;
52   }
53 }
54
55 void winrt_ssocket_service_base::construct(
56     winrt_ssocket_service_base::base_implementation_type& impl)
57 {
58   // Insert implementation into linked list of all implementations.
59   boost::asio::detail::mutex::scoped_lock lock(mutex_);
60   impl.next_ = impl_list_;
61   impl.prev_ = 0;
62   if (impl_list_)
63     impl_list_->prev_ = &impl;
64   impl_list_ = &impl;
65 }
66
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)
70   BOOST_ASIO_NOEXCEPT
71 {
72   impl.socket_ = other_impl.socket_;
73   other_impl.socket_ = nullptr;
74
75   // Insert implementation into linked list of all implementations.
76   boost::asio::detail::mutex::scoped_lock lock(mutex_);
77   impl.next_ = impl_list_;
78   impl.prev_ = 0;
79   if (impl_list_)
80     impl_list_->prev_ = &impl;
81   impl_list_ = &impl;
82 }
83
84 void winrt_ssocket_service_base::base_move_assign(
85     winrt_ssocket_service_base::base_implementation_type& impl,
86     winrt_ssocket_service_base& other_service,
87     winrt_ssocket_service_base::base_implementation_type& other_impl)
88 {
89   boost::system::error_code ignored_ec;
90   close(impl, ignored_ec);
91
92   if (this != &other_service)
93   {
94     // Remove implementation from linked list of all implementations.
95     boost::asio::detail::mutex::scoped_lock lock(mutex_);
96     if (impl_list_ == &impl)
97       impl_list_ = impl.next_;
98     if (impl.prev_)
99       impl.prev_->next_ = impl.next_;
100     if (impl.next_)
101       impl.next_->prev_= impl.prev_;
102     impl.next_ = 0;
103     impl.prev_ = 0;
104   }
105
106   impl.socket_ = other_impl.socket_;
107   other_impl.socket_ = nullptr;
108
109   if (this != &other_service)
110   {
111     // Insert implementation into linked list of all implementations.
112     boost::asio::detail::mutex::scoped_lock lock(other_service.mutex_);
113     impl.next_ = other_service.impl_list_;
114     impl.prev_ = 0;
115     if (other_service.impl_list_)
116       other_service.impl_list_->prev_ = &impl;
117     other_service.impl_list_ = &impl;
118   }
119 }
120
121 void winrt_ssocket_service_base::destroy(
122     winrt_ssocket_service_base::base_implementation_type& impl)
123 {
124   boost::system::error_code ignored_ec;
125   close(impl, ignored_ec);
126
127   // Remove implementation from linked list of all implementations.
128   boost::asio::detail::mutex::scoped_lock lock(mutex_);
129   if (impl_list_ == &impl)
130     impl_list_ = impl.next_;
131   if (impl.prev_)
132     impl.prev_->next_ = impl.next_;
133   if (impl.next_)
134     impl.next_->prev_= impl.prev_;
135   impl.next_ = 0;
136   impl.prev_ = 0;
137 }
138
139 boost::system::error_code winrt_ssocket_service_base::close(
140     winrt_ssocket_service_base::base_implementation_type& impl,
141     boost::system::error_code& ec)
142 {
143   if (impl.socket_)
144   {
145     delete impl.socket_;
146     impl.socket_ = nullptr;
147   }
148
149   ec = boost::system::error_code();
150   return ec;
151 }
152
153 winrt_ssocket_service_base::native_handle_type
154 winrt_ssocket_service_base::release(
155     winrt_ssocket_service_base::base_implementation_type& impl,
156     boost::system::error_code& ec)
157 {
158   if (!is_open(impl))
159     return nullptr;
160
161   cancel(impl, ec);
162   if (ec)
163     return nullptr;
164
165   native_handle_type tmp = impl.socket_;
166   impl.socket_ = nullptr;
167   return tmp;
168 }
169
170 std::size_t winrt_ssocket_service_base::do_get_endpoint(
171     const base_implementation_type& impl, bool local,
172     void* addr, std::size_t addr_len, boost::system::error_code& ec) const
173 {
174   if (!is_open(impl))
175   {
176     ec = boost::asio::error::bad_descriptor;
177     return addr_len;
178   }
179
180   try
181   {
182     std::string addr_string = winrt_utils::string(local
183         ? impl.socket_->Information->LocalAddress->CanonicalName
184         : impl.socket_->Information->RemoteAddress->CanonicalName);
185     unsigned short port = winrt_utils::integer(local
186         ? impl.socket_->Information->LocalPort
187         : impl.socket_->Information->RemotePort);
188     unsigned long scope = 0;
189
190     switch (reinterpret_cast<const socket_addr_type*>(addr)->sa_family)
191     {
192     case BOOST_ASIO_OS_DEF(AF_INET):
193       if (addr_len < sizeof(sockaddr_in4_type))
194       {
195         ec = boost::asio::error::invalid_argument;
196         return addr_len;
197       }
198       else
199       {
200         socket_ops::inet_pton(BOOST_ASIO_OS_DEF(AF_INET), addr_string.c_str(),
201             &reinterpret_cast<sockaddr_in4_type*>(addr)->sin_addr, &scope, ec);
202         reinterpret_cast<sockaddr_in4_type*>(addr)->sin_port
203           = socket_ops::host_to_network_short(port);
204         ec = boost::system::error_code();
205         return sizeof(sockaddr_in4_type);
206       }
207     case BOOST_ASIO_OS_DEF(AF_INET6):
208       if (addr_len < sizeof(sockaddr_in6_type))
209       {
210         ec = boost::asio::error::invalid_argument;
211         return addr_len;
212       }
213       else
214       {
215         socket_ops::inet_pton(BOOST_ASIO_OS_DEF(AF_INET6), addr_string.c_str(),
216             &reinterpret_cast<sockaddr_in6_type*>(addr)->sin6_addr, &scope, ec);
217         reinterpret_cast<sockaddr_in6_type*>(addr)->sin6_port
218           = socket_ops::host_to_network_short(port);
219         ec = boost::system::error_code();
220         return sizeof(sockaddr_in6_type);
221       }
222     default:
223       ec = boost::asio::error::address_family_not_supported;
224       return addr_len;
225     }
226   }
227   catch (Platform::Exception^ e)
228   {
229     ec = boost::system::error_code(e->HResult,
230         boost::system::system_category());
231     return addr_len;
232   }
233 }
234
235 boost::system::error_code winrt_ssocket_service_base::do_set_option(
236     winrt_ssocket_service_base::base_implementation_type& impl,
237     int level, int optname, const void* optval,
238     std::size_t optlen, boost::system::error_code& ec)
239 {
240   if (!is_open(impl))
241   {
242     ec = boost::asio::error::bad_descriptor;
243     return ec;
244   }
245
246   try
247   {
248     if (level == BOOST_ASIO_OS_DEF(SOL_SOCKET)
249         && optname == BOOST_ASIO_OS_DEF(SO_KEEPALIVE))
250     {
251       if (optlen == sizeof(int))
252       {
253         int value = 0;
254         std::memcpy(&value, optval, optlen);
255         impl.socket_->Control->KeepAlive = !!value;
256         ec = boost::system::error_code();
257       }
258       else
259       {
260         ec = boost::asio::error::invalid_argument;
261       }
262     }
263     else if (level == BOOST_ASIO_OS_DEF(IPPROTO_TCP)
264         && optname == BOOST_ASIO_OS_DEF(TCP_NODELAY))
265     {
266       if (optlen == sizeof(int))
267       {
268         int value = 0;
269         std::memcpy(&value, optval, optlen);
270         impl.socket_->Control->NoDelay = !!value;
271         ec = boost::system::error_code();
272       }
273       else
274       {
275         ec = boost::asio::error::invalid_argument;
276       }
277     }
278     else
279     {
280       ec = boost::asio::error::invalid_argument;
281     }
282   }
283   catch (Platform::Exception^ e)
284   {
285     ec = boost::system::error_code(e->HResult,
286         boost::system::system_category());
287   }
288
289   return ec;
290 }
291
292 void winrt_ssocket_service_base::do_get_option(
293     const winrt_ssocket_service_base::base_implementation_type& impl,
294     int level, int optname, void* optval,
295     std::size_t* optlen, boost::system::error_code& ec) const
296 {
297   if (!is_open(impl))
298   {
299     ec = boost::asio::error::bad_descriptor;
300     return;
301   }
302
303   try
304   {
305     if (level == BOOST_ASIO_OS_DEF(SOL_SOCKET)
306         && optname == BOOST_ASIO_OS_DEF(SO_KEEPALIVE))
307     {
308       if (*optlen >= sizeof(int))
309       {
310         int value = impl.socket_->Control->KeepAlive ? 1 : 0;
311         std::memcpy(optval, &value, sizeof(int));
312         *optlen = sizeof(int);
313         ec = boost::system::error_code();
314       }
315       else
316       {
317         ec = boost::asio::error::invalid_argument;
318       }
319     }
320     else if (level == BOOST_ASIO_OS_DEF(IPPROTO_TCP)
321         && optname == BOOST_ASIO_OS_DEF(TCP_NODELAY))
322     {
323       if (*optlen >= sizeof(int))
324       {
325         int value = impl.socket_->Control->NoDelay ? 1 : 0;
326         std::memcpy(optval, &value, sizeof(int));
327         *optlen = sizeof(int);
328         ec = boost::system::error_code();
329       }
330       else
331       {
332         ec = boost::asio::error::invalid_argument;
333       }
334     }
335     else
336     {
337       ec = boost::asio::error::invalid_argument;
338     }
339   }
340   catch (Platform::Exception^ e)
341   {
342     ec = boost::system::error_code(e->HResult,
343         boost::system::system_category());
344   }
345 }
346
347 boost::system::error_code winrt_ssocket_service_base::do_connect(
348     winrt_ssocket_service_base::base_implementation_type& impl,
349     const void* addr, boost::system::error_code& ec)
350 {
351   if (!is_open(impl))
352   {
353     ec = boost::asio::error::bad_descriptor;
354     return ec;
355   }
356
357   char addr_string[max_addr_v6_str_len];
358   unsigned short port;
359   switch (reinterpret_cast<const socket_addr_type*>(addr)->sa_family)
360   {
361   case BOOST_ASIO_OS_DEF(AF_INET):
362     socket_ops::inet_ntop(BOOST_ASIO_OS_DEF(AF_INET),
363         &reinterpret_cast<const sockaddr_in4_type*>(addr)->sin_addr,
364         addr_string, sizeof(addr_string), 0, ec);
365     port = socket_ops::network_to_host_short(
366         reinterpret_cast<const sockaddr_in4_type*>(addr)->sin_port);
367     break;
368   case BOOST_ASIO_OS_DEF(AF_INET6):
369     socket_ops::inet_ntop(BOOST_ASIO_OS_DEF(AF_INET6),
370         &reinterpret_cast<const sockaddr_in6_type*>(addr)->sin6_addr,
371         addr_string, sizeof(addr_string), 0, ec);
372     port = socket_ops::network_to_host_short(
373         reinterpret_cast<const sockaddr_in6_type*>(addr)->sin6_port);
374     break;
375   default:
376     ec = boost::asio::error::address_family_not_supported;
377     return ec;
378   }
379
380   if (!ec) try
381   {
382     async_manager_.sync(impl.socket_->ConnectAsync(
383           ref new Windows::Networking::HostName(
384             winrt_utils::string(addr_string)),
385           winrt_utils::string(port)), ec);
386   }
387   catch (Platform::Exception^ e)
388   {
389     ec = boost::system::error_code(e->HResult,
390         boost::system::system_category());
391   }
392
393   return ec;
394 }
395
396 void winrt_ssocket_service_base::start_connect_op(
397     winrt_ssocket_service_base::base_implementation_type& impl,
398     const void* addr, winrt_async_op<void>* op, bool is_continuation)
399 {
400   if (!is_open(impl))
401   {
402     op->ec_ = boost::asio::error::bad_descriptor;
403     scheduler_.post_immediate_completion(op, is_continuation);
404     return;
405   }
406
407   char addr_string[max_addr_v6_str_len];
408   unsigned short port = 0;
409   switch (reinterpret_cast<const socket_addr_type*>(addr)->sa_family)
410   {
411   case BOOST_ASIO_OS_DEF(AF_INET):
412     socket_ops::inet_ntop(BOOST_ASIO_OS_DEF(AF_INET),
413         &reinterpret_cast<const sockaddr_in4_type*>(addr)->sin_addr,
414         addr_string, sizeof(addr_string), 0, op->ec_);
415     port = socket_ops::network_to_host_short(
416         reinterpret_cast<const sockaddr_in4_type*>(addr)->sin_port);
417     break;
418   case BOOST_ASIO_OS_DEF(AF_INET6):
419     socket_ops::inet_ntop(BOOST_ASIO_OS_DEF(AF_INET6),
420         &reinterpret_cast<const sockaddr_in6_type*>(addr)->sin6_addr,
421         addr_string, sizeof(addr_string), 0, op->ec_);
422     port = socket_ops::network_to_host_short(
423         reinterpret_cast<const sockaddr_in6_type*>(addr)->sin6_port);
424     break;
425   default:
426     op->ec_ = boost::asio::error::address_family_not_supported;
427     break;
428   }
429
430   if (op->ec_)
431   {
432     scheduler_.post_immediate_completion(op, is_continuation);
433     return;
434   }
435
436   try
437   {
438     async_manager_.async(impl.socket_->ConnectAsync(
439           ref new Windows::Networking::HostName(
440             winrt_utils::string(addr_string)),
441           winrt_utils::string(port)), op);
442   }
443   catch (Platform::Exception^ e)
444   {
445     op->ec_ = boost::system::error_code(
446         e->HResult, boost::system::system_category());
447     scheduler_.post_immediate_completion(op, is_continuation);
448   }
449 }
450
451 std::size_t winrt_ssocket_service_base::do_send(
452     winrt_ssocket_service_base::base_implementation_type& impl,
453     const boost::asio::const_buffer& data,
454     socket_base::message_flags flags, boost::system::error_code& ec)
455 {
456   if (flags)
457   {
458     ec = boost::asio::error::operation_not_supported;
459     return 0;
460   }
461
462   if (!is_open(impl))
463   {
464     ec = boost::asio::error::bad_descriptor;
465     return 0;
466   }
467
468   try
469   {
470     buffer_sequence_adapter<boost::asio::const_buffer,
471       boost::asio::const_buffer> bufs(boost::asio::buffer(data));
472
473     if (bufs.all_empty())
474     {
475       ec = boost::system::error_code();
476       return 0;
477     }
478
479     return async_manager_.sync(
480         impl.socket_->OutputStream->WriteAsync(bufs.buffers()[0]), ec);
481   }
482   catch (Platform::Exception^ e)
483   {
484     ec = boost::system::error_code(e->HResult,
485         boost::system::system_category());
486     return 0;
487   }
488 }
489
490 void winrt_ssocket_service_base::start_send_op(
491       winrt_ssocket_service_base::base_implementation_type& impl,
492       const boost::asio::const_buffer& data, socket_base::message_flags flags,
493       winrt_async_op<unsigned int>* op, bool is_continuation)
494 {
495   if (flags)
496   {
497     op->ec_ = boost::asio::error::operation_not_supported;
498     scheduler_.post_immediate_completion(op, is_continuation);
499     return;
500   }
501
502   if (!is_open(impl))
503   {
504     op->ec_ = boost::asio::error::bad_descriptor;
505     scheduler_.post_immediate_completion(op, is_continuation);
506     return;
507   }
508
509   try
510   {
511     buffer_sequence_adapter<boost::asio::const_buffer,
512         boost::asio::const_buffer> bufs(boost::asio::buffer(data));
513
514     if (bufs.all_empty())
515     {
516       scheduler_.post_immediate_completion(op, is_continuation);
517       return;
518     }
519
520     async_manager_.async(
521         impl.socket_->OutputStream->WriteAsync(bufs.buffers()[0]), op);
522   }
523   catch (Platform::Exception^ e)
524   {
525     op->ec_ = boost::system::error_code(e->HResult,
526         boost::system::system_category());
527     scheduler_.post_immediate_completion(op, is_continuation);
528   }
529 }
530
531 std::size_t winrt_ssocket_service_base::do_receive(
532     winrt_ssocket_service_base::base_implementation_type& impl,
533     const boost::asio::mutable_buffer& data,
534     socket_base::message_flags flags, boost::system::error_code& ec)
535 {
536   if (flags)
537   {
538     ec = boost::asio::error::operation_not_supported;
539     return 0;
540   }
541
542   if (!is_open(impl))
543   {
544     ec = boost::asio::error::bad_descriptor;
545     return 0;
546   }
547
548   try
549   {
550     buffer_sequence_adapter<boost::asio::mutable_buffer,
551         boost::asio::mutable_buffer> bufs(boost::asio::buffer(data));
552
553     if (bufs.all_empty())
554     {
555       ec = boost::system::error_code();
556       return 0;
557     }
558
559     async_manager_.sync(
560         impl.socket_->InputStream->ReadAsync(
561           bufs.buffers()[0], bufs.buffers()[0]->Capacity,
562           Windows::Storage::Streams::InputStreamOptions::Partial), ec);
563
564     std::size_t bytes_transferred = bufs.buffers()[0]->Length;
565     if (bytes_transferred == 0 && !ec)
566     {
567       ec = boost::asio::error::eof;
568     }
569
570     return bytes_transferred;
571   }
572   catch (Platform::Exception^ e)
573   {
574     ec = boost::system::error_code(e->HResult,
575         boost::system::system_category());
576     return 0;
577   }
578 }
579
580 void winrt_ssocket_service_base::start_receive_op(
581       winrt_ssocket_service_base::base_implementation_type& impl,
582       const boost::asio::mutable_buffer& data, socket_base::message_flags flags,
583       winrt_async_op<Windows::Storage::Streams::IBuffer^>* op,
584       bool is_continuation)
585 {
586   if (flags)
587   {
588     op->ec_ = boost::asio::error::operation_not_supported;
589     scheduler_.post_immediate_completion(op, is_continuation);
590     return;
591   }
592
593   if (!is_open(impl))
594   {
595     op->ec_ = boost::asio::error::bad_descriptor;
596     scheduler_.post_immediate_completion(op, is_continuation);
597     return;
598   }
599
600   try
601   {
602     buffer_sequence_adapter<boost::asio::mutable_buffer,
603         boost::asio::mutable_buffer> bufs(boost::asio::buffer(data));
604
605     if (bufs.all_empty())
606     {
607       scheduler_.post_immediate_completion(op, is_continuation);
608       return;
609     }
610
611     async_manager_.async(
612         impl.socket_->InputStream->ReadAsync(
613           bufs.buffers()[0], bufs.buffers()[0]->Capacity,
614           Windows::Storage::Streams::InputStreamOptions::Partial), op);
615   }
616   catch (Platform::Exception^ e)
617   {
618     op->ec_ = boost::system::error_code(e->HResult,
619         boost::system::system_category());
620     scheduler_.post_immediate_completion(op, is_continuation);
621   }
622 }
623
624 } // namespace detail
625 } // namespace asio
626 } // namespace boost
627
628 #include <boost/asio/detail/pop_options.hpp>
629
630 #endif // defined(BOOST_ASIO_WINDOWS_RUNTIME)
631
632 #endif // BOOST_ASIO_DETAIL_IMPL_WINRT_SSOCKET_SERVICE_BASE_IPP