Imported Upstream version 1.64.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-2017 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     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)),
37     mutex_(),
38     impl_list_(0)
39 {
40 }
41
42 void winrt_ssocket_service_base::shutdown_service()
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 {
71   impl.socket_ = other_impl.socket_;
72   other_impl.socket_ = nullptr;
73
74   // Insert implementation into linked list of all implementations.
75   boost::asio::detail::mutex::scoped_lock lock(mutex_);
76   impl.next_ = impl_list_;
77   impl.prev_ = 0;
78   if (impl_list_)
79     impl_list_->prev_ = &impl;
80   impl_list_ = &impl;
81 }
82
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)
87 {
88   boost::system::error_code ignored_ec;
89   close(impl, ignored_ec);
90
91   if (this != &other_service)
92   {
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_;
97     if (impl.prev_)
98       impl.prev_->next_ = impl.next_;
99     if (impl.next_)
100       impl.next_->prev_= impl.prev_;
101     impl.next_ = 0;
102     impl.prev_ = 0;
103   }
104
105   impl.socket_ = other_impl.socket_;
106   other_impl.socket_ = nullptr;
107
108   if (this != &other_service)
109   {
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_;
113     impl.prev_ = 0;
114     if (other_service.impl_list_)
115       other_service.impl_list_->prev_ = &impl;
116     other_service.impl_list_ = &impl;
117   }
118 }
119
120 void winrt_ssocket_service_base::destroy(
121     winrt_ssocket_service_base::base_implementation_type& impl)
122 {
123   boost::system::error_code ignored_ec;
124   close(impl, ignored_ec);
125
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_;
130   if (impl.prev_)
131     impl.prev_->next_ = impl.next_;
132   if (impl.next_)
133     impl.next_->prev_= impl.prev_;
134   impl.next_ = 0;
135   impl.prev_ = 0;
136 }
137
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)
141 {
142   if (impl.socket_)
143   {
144     delete impl.socket_;
145     impl.socket_ = nullptr;
146   }
147
148   ec = boost::system::error_code();
149   return ec;
150 }
151
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
155 {
156   if (!is_open(impl))
157   {
158     ec = boost::asio::error::bad_descriptor;
159     return addr_len;
160   }
161
162   try
163   {
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;
171
172     switch (reinterpret_cast<const socket_addr_type*>(addr)->sa_family)
173     {
174     case BOOST_ASIO_OS_DEF(AF_INET):
175       if (addr_len < sizeof(sockaddr_in4_type))
176       {
177         ec = boost::asio::error::invalid_argument;
178         return addr_len;
179       }
180       else
181       {
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);
188       }
189     case BOOST_ASIO_OS_DEF(AF_INET6):
190       if (addr_len < sizeof(sockaddr_in6_type))
191       {
192         ec = boost::asio::error::invalid_argument;
193         return addr_len;
194       }
195       else
196       {
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);
203       }
204     default:
205       ec = boost::asio::error::address_family_not_supported;
206       return addr_len;
207     }
208   }
209   catch (Platform::Exception^ e)
210   {
211     ec = boost::system::error_code(e->HResult,
212         boost::system::system_category());
213     return addr_len;
214   }
215 }
216
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)
221 {
222   if (!is_open(impl))
223   {
224     ec = boost::asio::error::bad_descriptor;
225     return ec;
226   }
227
228   try
229   {
230     if (level == BOOST_ASIO_OS_DEF(SOL_SOCKET)
231         && optname == BOOST_ASIO_OS_DEF(SO_KEEPALIVE))
232     {
233       if (optlen == sizeof(int))
234       {
235         int value = 0;
236         std::memcpy(&value, optval, optlen);
237         impl.socket_->Control->KeepAlive = !!value;
238         ec = boost::system::error_code();
239       }
240       else
241       {
242         ec = boost::asio::error::invalid_argument;
243       }
244     }
245     else if (level == BOOST_ASIO_OS_DEF(IPPROTO_TCP)
246         && optname == BOOST_ASIO_OS_DEF(TCP_NODELAY))
247     {
248       if (optlen == sizeof(int))
249       {
250         int value = 0;
251         std::memcpy(&value, optval, optlen);
252         impl.socket_->Control->NoDelay = !!value;
253         ec = boost::system::error_code();
254       }
255       else
256       {
257         ec = boost::asio::error::invalid_argument;
258       }
259     }
260     else
261     {
262       ec = boost::asio::error::invalid_argument;
263     }
264   }
265   catch (Platform::Exception^ e)
266   {
267     ec = boost::system::error_code(e->HResult,
268         boost::system::system_category());
269   }
270
271   return ec;
272 }
273
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
278 {
279   if (!is_open(impl))
280   {
281     ec = boost::asio::error::bad_descriptor;
282     return;
283   }
284
285   try
286   {
287     if (level == BOOST_ASIO_OS_DEF(SOL_SOCKET)
288         && optname == BOOST_ASIO_OS_DEF(SO_KEEPALIVE))
289     {
290       if (*optlen >= sizeof(int))
291       {
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();
296       }
297       else
298       {
299         ec = boost::asio::error::invalid_argument;
300       }
301     }
302     else if (level == BOOST_ASIO_OS_DEF(IPPROTO_TCP)
303         && optname == BOOST_ASIO_OS_DEF(TCP_NODELAY))
304     {
305       if (*optlen >= sizeof(int))
306       {
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();
311       }
312       else
313       {
314         ec = boost::asio::error::invalid_argument;
315       }
316     }
317     else
318     {
319       ec = boost::asio::error::invalid_argument;
320     }
321   }
322   catch (Platform::Exception^ e)
323   {
324     ec = boost::system::error_code(e->HResult,
325         boost::system::system_category());
326   }
327 }
328
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)
332 {
333   if (!is_open(impl))
334   {
335     ec = boost::asio::error::bad_descriptor;
336     return ec;
337   }
338
339   char addr_string[max_addr_v6_str_len];
340   unsigned short port;
341   switch (reinterpret_cast<const socket_addr_type*>(addr)->sa_family)
342   {
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);
349     break;
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);
356     break;
357   default:
358     ec = boost::asio::error::address_family_not_supported;
359     return ec;
360   }
361
362   if (!ec) try
363   {
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);
368   }
369   catch (Platform::Exception^ e)
370   {
371     ec = boost::system::error_code(e->HResult,
372         boost::system::system_category());
373   }
374
375   return ec;
376 }
377
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)
381 {
382   if (!is_open(impl))
383   {
384     op->ec_ = boost::asio::error::bad_descriptor;
385     io_service_.post_immediate_completion(op, is_continuation);
386     return;
387   }
388
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)
392   {
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);
399     break;
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);
406     break;
407   default:
408     op->ec_ = boost::asio::error::address_family_not_supported;
409     break;
410   }
411
412   if (op->ec_)
413   {
414     io_service_.post_immediate_completion(op, is_continuation);
415     return;
416   }
417
418   try
419   {
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);
424   }
425   catch (Platform::Exception^ e)
426   {
427     op->ec_ = boost::system::error_code(
428         e->HResult, boost::system::system_category());
429     io_service_.post_immediate_completion(op, is_continuation);
430   }
431 }
432
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)
437 {
438   if (flags)
439   {
440     ec = boost::asio::error::operation_not_supported;
441     return 0;
442   }
443
444   if (!is_open(impl))
445   {
446     ec = boost::asio::error::bad_descriptor;
447     return 0;
448   }
449
450   try
451   {
452     buffer_sequence_adapter<boost::asio::const_buffer,
453       boost::asio::const_buffers_1> bufs(boost::asio::buffer(data));
454
455     if (bufs.all_empty())
456     {
457       ec = boost::system::error_code();
458       return 0;
459     }
460
461     return async_manager_.sync(
462         impl.socket_->OutputStream->WriteAsync(bufs.buffers()[0]), ec);
463   }
464   catch (Platform::Exception^ e)
465   {
466     ec = boost::system::error_code(e->HResult,
467         boost::system::system_category());
468     return 0;
469   }
470 }
471
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)
476 {
477   if (flags)
478   {
479     op->ec_ = boost::asio::error::operation_not_supported;
480     io_service_.post_immediate_completion(op, is_continuation);
481     return;
482   }
483
484   if (!is_open(impl))
485   {
486     op->ec_ = boost::asio::error::bad_descriptor;
487     io_service_.post_immediate_completion(op, is_continuation);
488     return;
489   }
490
491   try
492   {
493     buffer_sequence_adapter<boost::asio::const_buffer,
494         boost::asio::const_buffers_1> bufs(boost::asio::buffer(data));
495
496     if (bufs.all_empty())
497     {
498       io_service_.post_immediate_completion(op, is_continuation);
499       return;
500     }
501
502     async_manager_.async(
503         impl.socket_->OutputStream->WriteAsync(bufs.buffers()[0]), op);
504   }
505   catch (Platform::Exception^ e)
506   {
507     op->ec_ = boost::system::error_code(e->HResult,
508         boost::system::system_category());
509     io_service_.post_immediate_completion(op, is_continuation);
510   }
511 }
512
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)
517 {
518   if (flags)
519   {
520     ec = boost::asio::error::operation_not_supported;
521     return 0;
522   }
523
524   if (!is_open(impl))
525   {
526     ec = boost::asio::error::bad_descriptor;
527     return 0;
528   }
529
530   try
531   {
532     buffer_sequence_adapter<boost::asio::mutable_buffer,
533         boost::asio::mutable_buffers_1> bufs(boost::asio::buffer(data));
534
535     if (bufs.all_empty())
536     {
537       ec = boost::system::error_code();
538       return 0;
539     }
540
541     async_manager_.sync(
542         impl.socket_->InputStream->ReadAsync(
543           bufs.buffers()[0], bufs.buffers()[0]->Capacity,
544           Windows::Storage::Streams::InputStreamOptions::Partial), ec);
545
546     std::size_t bytes_transferred = bufs.buffers()[0]->Length;
547     if (bytes_transferred == 0 && !ec)
548     {
549       ec = boost::asio::error::eof;
550     }
551
552     return bytes_transferred;
553   }
554   catch (Platform::Exception^ e)
555   {
556     ec = boost::system::error_code(e->HResult,
557         boost::system::system_category());
558     return 0;
559   }
560 }
561
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)
567 {
568   if (flags)
569   {
570     op->ec_ = boost::asio::error::operation_not_supported;
571     io_service_.post_immediate_completion(op, is_continuation);
572     return;
573   }
574
575   if (!is_open(impl))
576   {
577     op->ec_ = boost::asio::error::bad_descriptor;
578     io_service_.post_immediate_completion(op, is_continuation);
579     return;
580   }
581
582   try
583   {
584     buffer_sequence_adapter<boost::asio::mutable_buffer,
585         boost::asio::mutable_buffers_1> bufs(boost::asio::buffer(data));
586
587     if (bufs.all_empty())
588     {
589       io_service_.post_immediate_completion(op, is_continuation);
590       return;
591     }
592
593     async_manager_.async(
594         impl.socket_->InputStream->ReadAsync(
595           bufs.buffers()[0], bufs.buffers()[0]->Capacity,
596           Windows::Storage::Streams::InputStreamOptions::Partial), op);
597   }
598   catch (Platform::Exception^ e)
599   {
600     op->ec_ = boost::system::error_code(e->HResult,
601         boost::system::system_category());
602     io_service_.post_immediate_completion(op, is_continuation);
603   }
604 }
605
606 } // namespace detail
607 } // namespace asio
608 } // namespace boost
609
610 #include <boost/asio/detail/pop_options.hpp>
611
612 #endif // defined(BOOST_ASIO_WINDOWS_RUNTIME)
613
614 #endif // BOOST_ASIO_DETAIL_IMPL_WINRT_SSOCKET_SERVICE_BASE_IPP