1 //
2 // basic_seq_packet_socket.hpp
3 // ~~~~~~~~~~~~~~~~~~~~~~~~~~~
4 //
5 // Copyright (c) 2003-2018 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 ASIO_BASIC_SEQ_PACKET_SOCKET_HPP
12 #define ASIO_BASIC_SEQ_PACKET_SOCKET_HPP
13 
14 #if defined(_MSC_VER) && (_MSC_VER >= 1200)
15 # pragma once
16 #endif // defined(_MSC_VER) && (_MSC_VER >= 1200)
17 
18 #include "asio/detail/config.hpp"
19 #include <cstddef>
20 #include "asio/basic_socket.hpp"
21 #include "asio/detail/handler_type_requirements.hpp"
22 #include "asio/detail/throw_error.hpp"
23 #include "asio/error.hpp"
24 
25 #if defined(ASIO_ENABLE_OLD_SERVICES)
26 # include "asio/seq_packet_socket_service.hpp"
27 #endif // defined(ASIO_ENABLE_OLD_SERVICES)
28 
29 #include "asio/detail/push_options.hpp"
30 
31 namespace asio {
32 
33 /// Provides sequenced packet socket functionality.
34 /**
35  * The basic_seq_packet_socket class template provides asynchronous and blocking
36  * sequenced packet socket functionality.
37  *
38  * @par Thread Safety
39  * @e Distinct @e objects: Safe.@n
40  * @e Shared @e objects: Unsafe.
41  */
42 template <typename Protocol
43     ASIO_SVC_TPARAM_DEF1(= seq_packet_socket_service<Protocol>)>
44 class basic_seq_packet_socket
45   : public basic_socket<Protocol ASIO_SVC_TARG>
46 {
47 public:
48   /// The native representation of a socket.
49 #if defined(GENERATING_DOCUMENTATION)
50   typedef implementation_defined native_handle_type;
51 #else
52   typedef typename basic_socket<
53     Protocol ASIO_SVC_TARG>::native_handle_type native_handle_type;
54 #endif
55 
56   /// The protocol type.
57   typedef Protocol protocol_type;
58 
59   /// The endpoint type.
60   typedef typename Protocol::endpoint endpoint_type;
61 
62   /// Construct a basic_seq_packet_socket without opening it.
63   /**
64    * This constructor creates a sequenced packet socket without opening it. The
65    * socket needs to be opened and then connected or accepted before data can
66    * be sent or received on it.
67    *
68    * @param io_context The io_context object that the sequenced packet socket
69    * will use to dispatch handlers for any asynchronous operations performed on
70    * the socket.
71    */
basic_seq_packet_socket(asio::io_context & io_context)72   explicit basic_seq_packet_socket(asio::io_context& io_context)
73     : basic_socket<Protocol ASIO_SVC_TARG>(io_context)
74   {
75   }
76 
77   /// Construct and open a basic_seq_packet_socket.
78   /**
79    * This constructor creates and opens a sequenced_packet socket. The socket
80    * needs to be connected or accepted before data can be sent or received on
81    * it.
82    *
83    * @param io_context The io_context object that the sequenced packet socket
84    * will use to dispatch handlers for any asynchronous operations performed on
85    * the socket.
86    *
87    * @param protocol An object specifying protocol parameters to be used.
88    *
89    * @throws asio::system_error Thrown on failure.
90    */
basic_seq_packet_socket(asio::io_context & io_context,const protocol_type & protocol)91   basic_seq_packet_socket(asio::io_context& io_context,
92       const protocol_type& protocol)
93     : basic_socket<Protocol ASIO_SVC_TARG>(io_context, protocol)
94   {
95   }
96 
97   /// Construct a basic_seq_packet_socket, opening it and binding it to the
98   /// given local endpoint.
99   /**
100    * This constructor creates a sequenced packet socket and automatically opens
101    * it bound to the specified endpoint on the local machine. The protocol used
102    * is the protocol associated with the given endpoint.
103    *
104    * @param io_context The io_context object that the sequenced packet socket
105    * will use to dispatch handlers for any asynchronous operations performed on
106    * the socket.
107    *
108    * @param endpoint An endpoint on the local machine to which the sequenced
109    * packet socket will be bound.
110    *
111    * @throws asio::system_error Thrown on failure.
112    */
basic_seq_packet_socket(asio::io_context & io_context,const endpoint_type & endpoint)113   basic_seq_packet_socket(asio::io_context& io_context,
114       const endpoint_type& endpoint)
115     : basic_socket<Protocol ASIO_SVC_TARG>(io_context, endpoint)
116   {
117   }
118 
119   /// Construct a basic_seq_packet_socket on an existing native socket.
120   /**
121    * This constructor creates a sequenced packet socket object to hold an
122    * existing native socket.
123    *
124    * @param io_context The io_context object that the sequenced packet socket
125    * will use to dispatch handlers for any asynchronous operations performed on
126    * the socket.
127    *
128    * @param protocol An object specifying protocol parameters to be used.
129    *
130    * @param native_socket The new underlying socket implementation.
131    *
132    * @throws asio::system_error Thrown on failure.
133    */
basic_seq_packet_socket(asio::io_context & io_context,const protocol_type & protocol,const native_handle_type & native_socket)134   basic_seq_packet_socket(asio::io_context& io_context,
135       const protocol_type& protocol, const native_handle_type& native_socket)
136     : basic_socket<Protocol ASIO_SVC_TARG>(
137         io_context, protocol, native_socket)
138   {
139   }
140 
141 #if defined(ASIO_HAS_MOVE) || defined(GENERATING_DOCUMENTATION)
142   /// Move-construct a basic_seq_packet_socket from another.
143   /**
144    * This constructor moves a sequenced packet socket from one object to
145    * another.
146    *
147    * @param other The other basic_seq_packet_socket object from which the move
148    * will occur.
149    *
150    * @note Following the move, the moved-from object is in the same state as if
151    * constructed using the @c basic_seq_packet_socket(io_context&) constructor.
152    */
basic_seq_packet_socket(basic_seq_packet_socket && other)153   basic_seq_packet_socket(basic_seq_packet_socket&& other)
154     : basic_socket<Protocol ASIO_SVC_TARG>(std::move(other))
155   {
156   }
157 
158   /// Move-assign a basic_seq_packet_socket from another.
159   /**
160    * This assignment operator moves a sequenced packet socket from one object to
161    * another.
162    *
163    * @param other The other basic_seq_packet_socket object from which the move
164    * will occur.
165    *
166    * @note Following the move, the moved-from object is in the same state as if
167    * constructed using the @c basic_seq_packet_socket(io_context&) constructor.
168    */
operator =(basic_seq_packet_socket && other)169   basic_seq_packet_socket& operator=(basic_seq_packet_socket&& other)
170   {
171     basic_socket<Protocol ASIO_SVC_TARG>::operator=(std::move(other));
172     return *this;
173   }
174 
175   /// Move-construct a basic_seq_packet_socket from a socket of another protocol
176   /// type.
177   /**
178    * This constructor moves a sequenced packet socket from one object to
179    * another.
180    *
181    * @param other The other basic_seq_packet_socket object from which the move
182    * will occur.
183    *
184    * @note Following the move, the moved-from object is in the same state as if
185    * constructed using the @c basic_seq_packet_socket(io_context&) constructor.
186    */
187   template <typename Protocol1 ASIO_SVC_TPARAM1>
basic_seq_packet_socket(basic_seq_packet_socket<Protocol1 ASIO_SVC_TARG1> && other,typename enable_if<is_convertible<Protocol1,Protocol>::value>::type * =0)188   basic_seq_packet_socket(
189       basic_seq_packet_socket<Protocol1 ASIO_SVC_TARG1>&& other,
190       typename enable_if<is_convertible<Protocol1, Protocol>::value>::type* = 0)
191     : basic_socket<Protocol ASIO_SVC_TARG>(std::move(other))
192   {
193   }
194 
195   /// Move-assign a basic_seq_packet_socket from a socket of another protocol
196   /// type.
197   /**
198    * This assignment operator moves a sequenced packet socket from one object to
199    * another.
200    *
201    * @param other The other basic_seq_packet_socket object from which the move
202    * will occur.
203    *
204    * @note Following the move, the moved-from object is in the same state as if
205    * constructed using the @c basic_seq_packet_socket(io_context&) constructor.
206    */
207   template <typename Protocol1 ASIO_SVC_TPARAM1>
208   typename enable_if<is_convertible<Protocol1, Protocol>::value,
operator =(basic_seq_packet_socket<Protocol1 ASIO_SVC_TARG1> && other)209       basic_seq_packet_socket>::type& operator=(
210         basic_seq_packet_socket<Protocol1 ASIO_SVC_TARG1>&& other)
211   {
212     basic_socket<Protocol ASIO_SVC_TARG>::operator=(std::move(other));
213     return *this;
214   }
215 #endif // defined(ASIO_HAS_MOVE) || defined(GENERATING_DOCUMENTATION)
216 
217   /// Destroys the socket.
218   /**
219    * This function destroys the socket, cancelling any outstanding asynchronous
220    * operations associated with the socket as if by calling @c cancel.
221    */
~basic_seq_packet_socket()222   ~basic_seq_packet_socket()
223   {
224   }
225 
226   /// Send some data on the socket.
227   /**
228    * This function is used to send data on the sequenced packet socket. The
229    * function call will block until the data has been sent successfully, or an
230    * until error occurs.
231    *
232    * @param buffers One or more data buffers to be sent on the socket.
233    *
234    * @param flags Flags specifying how the send call is to be made.
235    *
236    * @returns The number of bytes sent.
237    *
238    * @throws asio::system_error Thrown on failure.
239    *
240    * @par Example
241    * To send a single data buffer use the @ref buffer function as follows:
242    * @code
243    * socket.send(asio::buffer(data, size), 0);
244    * @endcode
245    * See the @ref buffer documentation for information on sending multiple
246    * buffers in one go, and how to use it with arrays, boost::array or
247    * std::vector.
248    */
249   template <typename ConstBufferSequence>
send(const ConstBufferSequence & buffers,socket_base::message_flags flags)250   std::size_t send(const ConstBufferSequence& buffers,
251       socket_base::message_flags flags)
252   {
253     asio::error_code ec;
254     std::size_t s = this->get_service().send(
255         this->get_implementation(), buffers, flags, ec);
256     asio::detail::throw_error(ec, "send");
257     return s;
258   }
259 
260   /// Send some data on the socket.
261   /**
262    * This function is used to send data on the sequenced packet socket. The
263    * function call will block the data has been sent successfully, or an until
264    * error occurs.
265    *
266    * @param buffers One or more data buffers to be sent on the socket.
267    *
268    * @param flags Flags specifying how the send call is to be made.
269    *
270    * @param ec Set to indicate what error occurred, if any.
271    *
272    * @returns The number of bytes sent. Returns 0 if an error occurred.
273    *
274    * @note The send operation may not transmit all of the data to the peer.
275    * Consider using the @ref write function if you need to ensure that all data
276    * is written before the blocking operation completes.
277    */
278   template <typename ConstBufferSequence>
send(const ConstBufferSequence & buffers,socket_base::message_flags flags,asio::error_code & ec)279   std::size_t send(const ConstBufferSequence& buffers,
280       socket_base::message_flags flags, asio::error_code& ec)
281   {
282     return this->get_service().send(
283         this->get_implementation(), buffers, flags, ec);
284   }
285 
286   /// Start an asynchronous send.
287   /**
288    * This function is used to asynchronously send data on the sequenced packet
289    * socket. The function call always returns immediately.
290    *
291    * @param buffers One or more data buffers to be sent on the socket. Although
292    * the buffers object may be copied as necessary, ownership of the underlying
293    * memory blocks is retained by the caller, which must guarantee that they
294    * remain valid until the handler is called.
295    *
296    * @param flags Flags specifying how the send call is to be made.
297    *
298    * @param handler The handler to be called when the send operation completes.
299    * Copies will be made of the handler as required. The function signature of
300    * the handler must be:
301    * @code void handler(
302    *   const asio::error_code& error, // Result of operation.
303    *   std::size_t bytes_transferred           // Number of bytes sent.
304    * ); @endcode
305    * Regardless of whether the asynchronous operation completes immediately or
306    * not, the handler will not be invoked from within this function. Invocation
307    * of the handler will be performed in a manner equivalent to using
308    * asio::io_context::post().
309    *
310    * @par Example
311    * To send a single data buffer use the @ref buffer function as follows:
312    * @code
313    * socket.async_send(asio::buffer(data, size), 0, handler);
314    * @endcode
315    * See the @ref buffer documentation for information on sending multiple
316    * buffers in one go, and how to use it with arrays, boost::array or
317    * std::vector.
318    */
319   template <typename ConstBufferSequence, typename WriteHandler>
ASIO_INITFN_RESULT_TYPE(WriteHandler,void (asio::error_code,std::size_t))320   ASIO_INITFN_RESULT_TYPE(WriteHandler,
321       void (asio::error_code, std::size_t))
322   async_send(const ConstBufferSequence& buffers,
323       socket_base::message_flags flags,
324       ASIO_MOVE_ARG(WriteHandler) handler)
325   {
326     // If you get an error on the following line it means that your handler does
327     // not meet the documented type requirements for a WriteHandler.
328     ASIO_WRITE_HANDLER_CHECK(WriteHandler, handler) type_check;
329 
330 #if defined(ASIO_ENABLE_OLD_SERVICES)
331     return this->get_service().async_send(this->get_implementation(),
332         buffers, flags, ASIO_MOVE_CAST(WriteHandler)(handler));
333 #else // defined(ASIO_ENABLE_OLD_SERVICES)
334     async_completion<WriteHandler,
335       void (asio::error_code, std::size_t)> init(handler);
336 
337     this->get_service().async_send(this->get_implementation(),
338         buffers, flags, init.completion_handler);
339 
340     return init.result.get();
341 #endif // defined(ASIO_ENABLE_OLD_SERVICES)
342   }
343 
344   /// Receive some data on the socket.
345   /**
346    * This function is used to receive data on the sequenced packet socket. The
347    * function call will block until data has been received successfully, or
348    * until an error occurs.
349    *
350    * @param buffers One or more buffers into which the data will be received.
351    *
352    * @param out_flags After the receive call completes, contains flags
353    * associated with the received data. For example, if the
354    * socket_base::message_end_of_record bit is set then the received data marks
355    * the end of a record.
356    *
357    * @returns The number of bytes received.
358    *
359    * @throws asio::system_error Thrown on failure. An error code of
360    * asio::error::eof indicates that the connection was closed by the
361    * peer.
362    *
363    * @par Example
364    * To receive into a single data buffer use the @ref buffer function as
365    * follows:
366    * @code
367    * socket.receive(asio::buffer(data, size), out_flags);
368    * @endcode
369    * See the @ref buffer documentation for information on receiving into
370    * multiple buffers in one go, and how to use it with arrays, boost::array or
371    * std::vector.
372    */
373   template <typename MutableBufferSequence>
receive(const MutableBufferSequence & buffers,socket_base::message_flags & out_flags)374   std::size_t receive(const MutableBufferSequence& buffers,
375       socket_base::message_flags& out_flags)
376   {
377     asio::error_code ec;
378 #if defined(ASIO_ENABLE_OLD_SERVICES)
379     std::size_t s = this->get_service().receive(
380         this->get_implementation(), buffers, 0, out_flags, ec);
381 #else // defined(ASIO_ENABLE_OLD_SERVICES)
382     std::size_t s = this->get_service().receive_with_flags(
383         this->get_implementation(), buffers, 0, out_flags, ec);
384 #endif // defined(ASIO_ENABLE_OLD_SERVICES)
385     asio::detail::throw_error(ec, "receive");
386     return s;
387   }
388 
389   /// Receive some data on the socket.
390   /**
391    * This function is used to receive data on the sequenced packet socket. The
392    * function call will block until data has been received successfully, or
393    * until an error occurs.
394    *
395    * @param buffers One or more buffers into which the data will be received.
396    *
397    * @param in_flags Flags specifying how the receive call is to be made.
398    *
399    * @param out_flags After the receive call completes, contains flags
400    * associated with the received data. For example, if the
401    * socket_base::message_end_of_record bit is set then the received data marks
402    * the end of a record.
403    *
404    * @returns The number of bytes received.
405    *
406    * @throws asio::system_error Thrown on failure. An error code of
407    * asio::error::eof indicates that the connection was closed by the
408    * peer.
409    *
410    * @note The receive operation may not receive all of the requested number of
411    * bytes. Consider using the @ref read function if you need to ensure that the
412    * requested amount of data is read before the blocking operation completes.
413    *
414    * @par Example
415    * To receive into a single data buffer use the @ref buffer function as
416    * follows:
417    * @code
418    * socket.receive(asio::buffer(data, size), 0, out_flags);
419    * @endcode
420    * See the @ref buffer documentation for information on receiving into
421    * multiple buffers in one go, and how to use it with arrays, boost::array or
422    * std::vector.
423    */
424   template <typename MutableBufferSequence>
receive(const MutableBufferSequence & buffers,socket_base::message_flags in_flags,socket_base::message_flags & out_flags)425   std::size_t receive(const MutableBufferSequence& buffers,
426       socket_base::message_flags in_flags,
427       socket_base::message_flags& out_flags)
428   {
429     asio::error_code ec;
430 #if defined(ASIO_ENABLE_OLD_SERVICES)
431     std::size_t s = this->get_service().receive(
432         this->get_implementation(), buffers, in_flags, out_flags, ec);
433 #else // defined(ASIO_ENABLE_OLD_SERVICES)
434     std::size_t s = this->get_service().receive_with_flags(
435         this->get_implementation(), buffers, in_flags, out_flags, ec);
436 #endif // defined(ASIO_ENABLE_OLD_SERVICES)
437     asio::detail::throw_error(ec, "receive");
438     return s;
439   }
440 
441   /// Receive some data on a connected socket.
442   /**
443    * This function is used to receive data on the sequenced packet socket. The
444    * function call will block until data has been received successfully, or
445    * until an error occurs.
446    *
447    * @param buffers One or more buffers into which the data will be received.
448    *
449    * @param in_flags Flags specifying how the receive call is to be made.
450    *
451    * @param out_flags After the receive call completes, contains flags
452    * associated with the received data. For example, if the
453    * socket_base::message_end_of_record bit is set then the received data marks
454    * the end of a record.
455    *
456    * @param ec Set to indicate what error occurred, if any.
457    *
458    * @returns The number of bytes received. Returns 0 if an error occurred.
459    *
460    * @note The receive operation may not receive all of the requested number of
461    * bytes. Consider using the @ref read function if you need to ensure that the
462    * requested amount of data is read before the blocking operation completes.
463    */
464   template <typename MutableBufferSequence>
receive(const MutableBufferSequence & buffers,socket_base::message_flags in_flags,socket_base::message_flags & out_flags,asio::error_code & ec)465   std::size_t receive(const MutableBufferSequence& buffers,
466       socket_base::message_flags in_flags,
467       socket_base::message_flags& out_flags, asio::error_code& ec)
468   {
469 #if defined(ASIO_ENABLE_OLD_SERVICES)
470     return this->get_service().receive(this->get_implementation(),
471         buffers, in_flags, out_flags, ec);
472 #else // defined(ASIO_ENABLE_OLD_SERVICES)
473     return this->get_service().receive_with_flags(this->get_implementation(),
474         buffers, in_flags, out_flags, ec);
475 #endif // defined(ASIO_ENABLE_OLD_SERVICES)
476   }
477 
478   /// Start an asynchronous receive.
479   /**
480    * This function is used to asynchronously receive data from the sequenced
481    * packet socket. The function call always returns immediately.
482    *
483    * @param buffers One or more buffers into which the data will be received.
484    * Although the buffers object may be copied as necessary, ownership of the
485    * underlying memory blocks is retained by the caller, which must guarantee
486    * that they remain valid until the handler is called.
487    *
488    * @param out_flags Once the asynchronous operation completes, contains flags
489    * associated with the received data. For example, if the
490    * socket_base::message_end_of_record bit is set then the received data marks
491    * the end of a record. The caller must guarantee that the referenced
492    * variable remains valid until the handler is called.
493    *
494    * @param handler The handler to be called when the receive operation
495    * completes. Copies will be made of the handler as required. The function
496    * signature of the handler must be:
497    * @code void handler(
498    *   const asio::error_code& error, // Result of operation.
499    *   std::size_t bytes_transferred           // Number of bytes received.
500    * ); @endcode
501    * Regardless of whether the asynchronous operation completes immediately or
502    * not, the handler will not be invoked from within this function. Invocation
503    * of the handler will be performed in a manner equivalent to using
504    * asio::io_context::post().
505    *
506    * @par Example
507    * To receive into a single data buffer use the @ref buffer function as
508    * follows:
509    * @code
510    * socket.async_receive(asio::buffer(data, size), out_flags, handler);
511    * @endcode
512    * See the @ref buffer documentation for information on receiving into
513    * multiple buffers in one go, and how to use it with arrays, boost::array or
514    * std::vector.
515    */
516   template <typename MutableBufferSequence, typename ReadHandler>
ASIO_INITFN_RESULT_TYPE(ReadHandler,void (asio::error_code,std::size_t))517   ASIO_INITFN_RESULT_TYPE(ReadHandler,
518       void (asio::error_code, std::size_t))
519   async_receive(const MutableBufferSequence& buffers,
520       socket_base::message_flags& out_flags,
521       ASIO_MOVE_ARG(ReadHandler) handler)
522   {
523     // If you get an error on the following line it means that your handler does
524     // not meet the documented type requirements for a ReadHandler.
525     ASIO_READ_HANDLER_CHECK(ReadHandler, handler) type_check;
526 
527 #if defined(ASIO_ENABLE_OLD_SERVICES)
528     return this->get_service().async_receive(
529         this->get_implementation(), buffers, 0, out_flags,
530         ASIO_MOVE_CAST(ReadHandler)(handler));
531 #else // defined(ASIO_ENABLE_OLD_SERVICES)
532     async_completion<ReadHandler,
533       void (asio::error_code, std::size_t)> init(handler);
534 
535     this->get_service().async_receive_with_flags(
536         this->get_implementation(), buffers, 0, out_flags,
537         init.completion_handler);
538 
539     return init.result.get();
540 #endif // defined(ASIO_ENABLE_OLD_SERVICES)
541   }
542 
543   /// Start an asynchronous receive.
544   /**
545    * This function is used to asynchronously receive data from the sequenced
546    * data socket. The function call always returns immediately.
547    *
548    * @param buffers One or more buffers into which the data will be received.
549    * Although the buffers object may be copied as necessary, ownership of the
550    * underlying memory blocks is retained by the caller, which must guarantee
551    * that they remain valid until the handler is called.
552    *
553    * @param in_flags Flags specifying how the receive call is to be made.
554    *
555    * @param out_flags Once the asynchronous operation completes, contains flags
556    * associated with the received data. For example, if the
557    * socket_base::message_end_of_record bit is set then the received data marks
558    * the end of a record. The caller must guarantee that the referenced
559    * variable remains valid until the handler is called.
560    *
561    * @param handler The handler to be called when the receive operation
562    * completes. Copies will be made of the handler as required. The function
563    * signature of the handler must be:
564    * @code void handler(
565    *   const asio::error_code& error, // Result of operation.
566    *   std::size_t bytes_transferred           // Number of bytes received.
567    * ); @endcode
568    * Regardless of whether the asynchronous operation completes immediately or
569    * not, the handler will not be invoked from within this function. Invocation
570    * of the handler will be performed in a manner equivalent to using
571    * asio::io_context::post().
572    *
573    * @par Example
574    * To receive into a single data buffer use the @ref buffer function as
575    * follows:
576    * @code
577    * socket.async_receive(
578    *     asio::buffer(data, size),
579    *     0, out_flags, handler);
580    * @endcode
581    * See the @ref buffer documentation for information on receiving into
582    * multiple buffers in one go, and how to use it with arrays, boost::array or
583    * std::vector.
584    */
585   template <typename MutableBufferSequence, typename ReadHandler>
ASIO_INITFN_RESULT_TYPE(ReadHandler,void (asio::error_code,std::size_t))586   ASIO_INITFN_RESULT_TYPE(ReadHandler,
587       void (asio::error_code, std::size_t))
588   async_receive(const MutableBufferSequence& buffers,
589       socket_base::message_flags in_flags,
590       socket_base::message_flags& out_flags,
591       ASIO_MOVE_ARG(ReadHandler) handler)
592   {
593     // If you get an error on the following line it means that your handler does
594     // not meet the documented type requirements for a ReadHandler.
595     ASIO_READ_HANDLER_CHECK(ReadHandler, handler) type_check;
596 
597 #if defined(ASIO_ENABLE_OLD_SERVICES)
598     return this->get_service().async_receive(
599         this->get_implementation(), buffers, in_flags, out_flags,
600         ASIO_MOVE_CAST(ReadHandler)(handler));
601 #else // defined(ASIO_ENABLE_OLD_SERVICES)
602     async_completion<ReadHandler,
603       void (asio::error_code, std::size_t)> init(handler);
604 
605     this->get_service().async_receive_with_flags(
606         this->get_implementation(), buffers, in_flags, out_flags,
607         init.completion_handler);
608 
609     return init.result.get();
610 #endif // defined(ASIO_ENABLE_OLD_SERVICES)
611   }
612 };
613 
614 } // namespace asio
615 
616 #include "asio/detail/pop_options.hpp"
617 
618 #endif // ASIO_BASIC_SEQ_PACKET_SOCKET_HPP
619