include/boost/corosio/local_datagram_socket.hpp

92.2% Lines (47/51) 100.0% List of functions (19/19)
local_datagram_socket.hpp
f(x) Functions (19)
Function Calls Lines Blocks
boost::corosio::local_datagram_socket::send_to_awaitable::send_to_awaitable(boost::corosio::local_datagram_socket&, boost::corosio::buffer_param, boost::corosio::local_endpoint, int) :286 6x 100.0% 100.0% boost::corosio::local_datagram_socket::send_to_awaitable::dispatch(std::__n4861::coroutine_handle<void>, boost::capy::executor_ref) const :291 6x 100.0% 80.0% boost::corosio::local_datagram_socket::recv_from_awaitable::recv_from_awaitable(boost::corosio::local_datagram_socket&, boost::corosio::buffer_param, boost::corosio::local_endpoint&, int) :312 8x 100.0% 100.0% boost::corosio::local_datagram_socket::recv_from_awaitable::dispatch(std::__n4861::coroutine_handle<void>, boost::capy::executor_ref) const :317 8x 100.0% 80.0% boost::corosio::local_datagram_socket::send_awaitable::send_awaitable(boost::corosio::local_datagram_socket&, boost::corosio::buffer_param, int) :361 8x 100.0% 100.0% boost::corosio::local_datagram_socket::send_awaitable::dispatch(std::__n4861::coroutine_handle<void>, boost::capy::executor_ref) const :366 8x 100.0% 80.0% boost::corosio::local_datagram_socket::recv_awaitable::recv_awaitable(boost::corosio::local_datagram_socket&, boost::corosio::buffer_param, int) :386 10x 100.0% 100.0% boost::corosio::local_datagram_socket::recv_awaitable::dispatch(std::__n4861::coroutine_handle<void>, boost::capy::executor_ref) const :391 10x 100.0% 80.0% boost::corosio::local_datagram_socket::local_datagram_socket(boost::corosio::local_datagram_socket&&) :433 14x 100.0% 100.0% boost::corosio::local_datagram_socket::is_open() const :484 142x 100.0% 100.0% auto boost::corosio::local_datagram_socket::send_to<boost::capy::const_buffer>(boost::capy::const_buffer const&, boost::corosio::local_endpoint, boost::corosio::message_flags) :549 6x 75.0% 86.0% auto boost::corosio::local_datagram_socket::send_to<boost::capy::const_buffer>(boost::capy::const_buffer const&, boost::corosio::local_endpoint) :562 6x 100.0% 100.0% auto boost::corosio::local_datagram_socket::recv_from<boost::capy::mutable_buffer>(boost::capy::mutable_buffer const&, boost::corosio::local_endpoint&, boost::corosio::message_flags) :589 8x 75.0% 86.0% auto boost::corosio::local_datagram_socket::recv_from<boost::capy::mutable_buffer>(boost::capy::mutable_buffer const&, boost::corosio::local_endpoint&) :602 6x 100.0% 100.0% auto boost::corosio::local_datagram_socket::send<boost::capy::const_buffer>(boost::capy::const_buffer const&, boost::corosio::message_flags) :623 8x 75.0% 86.0% auto boost::corosio::local_datagram_socket::send<boost::capy::const_buffer>(boost::capy::const_buffer const&) :633 8x 100.0% 100.0% auto boost::corosio::local_datagram_socket::recv<boost::capy::mutable_buffer>(boost::capy::mutable_buffer const&, boost::corosio::message_flags) :654 10x 75.0% 86.0% auto boost::corosio::local_datagram_socket::recv<boost::capy::mutable_buffer>(boost::capy::mutable_buffer const&) :664 8x 100.0% 100.0% boost::corosio::local_datagram_socket::get() const :808 158x 100.0% 100.0%
Line TLA Hits Source Code
1 //
2 // Copyright (c) 2026 Michael Vandeberg
3 //
4 // Distributed under the Boost Software License, Version 1.0. (See accompanying
5 // file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt)
6 //
7 // Official repository: https://github.com/cppalliance/corosio
8 //
9
10 #ifndef BOOST_COROSIO_LOCAL_DATAGRAM_SOCKET_HPP
11 #define BOOST_COROSIO_LOCAL_DATAGRAM_SOCKET_HPP
12
13 #include <boost/corosio/detail/config.hpp>
14 #include <boost/corosio/detail/platform.hpp>
15 #include <boost/corosio/detail/except.hpp>
16 #include <boost/corosio/detail/native_handle.hpp>
17 #include <boost/corosio/detail/op_base.hpp>
18 #include <boost/corosio/io/io_object.hpp>
19 #include <boost/capy/io_result.hpp>
20 #include <boost/corosio/detail/buffer_param.hpp>
21 #include <boost/corosio/local_endpoint.hpp>
22 #include <boost/corosio/local_datagram.hpp>
23 #include <boost/corosio/message_flags.hpp>
24 #include <boost/corosio/shutdown_type.hpp>
25 #include <boost/capy/ex/executor_ref.hpp>
26 #include <boost/capy/ex/execution_context.hpp>
27 #include <boost/capy/ex/io_env.hpp>
28 #include <boost/capy/concept/executor.hpp>
29
30 #include <system_error>
31
32 #include <concepts>
33 #include <coroutine>
34 #include <cstddef>
35 #include <stop_token>
36 #include <type_traits>
37
38 namespace boost::corosio {
39
40 /** An asynchronous Unix datagram socket for coroutine I/O.
41
42 This class provides asynchronous Unix domain datagram socket
43 operations that return awaitable types. Each operation
44 participates in the affine awaitable protocol, ensuring
45 coroutines resume on the correct executor.
46
47 Supports two modes of operation:
48
49 @li **Connectionless:** each send_to() specifies a destination
50 endpoint, and each recv_from() captures the source. The
51 socket must be opened (and optionally bound) before I/O.
52
53 @li **Connected:** call connect() to set a default peer,
54 then use send()/recv() without endpoint arguments. The
55 kernel filters incoming datagrams to those from the
56 connected peer.
57
58 @par Cancellation
59 All asynchronous operations support cancellation through
60 `std::stop_token` via the affine protocol, or explicitly
61 through cancel(). Cancelled operations complete with
62 `capy::cond::canceled`. Datagram sends and receives are
63 atomic — there is no partial progress on cancellation.
64
65 @par Thread Safety
66 Distinct objects: Safe.@n
67 Shared objects: Unsafe. A socket must not have concurrent
68 operations of the same type (e.g., two simultaneous
69 recv_from). One send and one recv may be in flight
70 simultaneously. Note that recv and recv_from share the
71 same internal read slot, so they must not overlap; likewise
72 send and send_to share the write slot.
73
74 @par Example
75 @code
76 // Connectionless
77 local_datagram_socket sender(ioc);
78 sender.open();
79 sender.bind(local_endpoint("/tmp/sender.sock"));
80 auto [ec, n] = co_await sender.send_to(
81 capy::const_buffer("hello", 5),
82 local_endpoint("/tmp/receiver.sock"));
83
84 // Connected
85 local_datagram_socket sock(ioc);
86 co_await sock.connect(local_endpoint("/tmp/peer.sock"));
87 auto [ec2, n2] = co_await sock.send(
88 capy::const_buffer("hi", 2));
89 @endcode
90 */
91 class BOOST_COROSIO_DECL local_datagram_socket : public io_object
92 {
93 public:
94 /// The shutdown direction type used by shutdown().
95 using shutdown_type = corosio::shutdown_type;
96 using enum corosio::shutdown_type;
97
98 /** Define backend hooks for local datagram socket operations.
99
100 Platform backends (epoll, kqueue, select) derive from this
101 to implement datagram I/O, connection, and option management.
102 */
103 struct implementation : io_object::implementation
104 {
105 /** Initiate an asynchronous send_to operation.
106
107 @param h Coroutine handle to resume on completion.
108 @param ex Executor for dispatching the completion.
109 @param buf The buffer data to send.
110 @param dest The destination endpoint.
111 @param token Stop token for cancellation.
112 @param ec Output error code.
113 @param bytes_out Output bytes transferred.
114
115 @return Coroutine handle to resume immediately.
116 */
117 virtual std::coroutine_handle<> send_to(
118 std::coroutine_handle<> h,
119 capy::executor_ref ex,
120 buffer_param buf,
121 corosio::local_endpoint dest,
122 int flags,
123 std::stop_token token,
124 std::error_code* ec,
125 std::size_t* bytes_out) = 0;
126
127 /** Initiate an asynchronous recv_from operation.
128
129 @param h Coroutine handle to resume on completion.
130 @param ex Executor for dispatching the completion.
131 @param buf The buffer to receive into.
132 @param source Output endpoint for the sender's address.
133 @param token Stop token for cancellation.
134 @param ec Output error code.
135 @param bytes_out Output bytes transferred.
136
137 @return Coroutine handle to resume immediately.
138 */
139 virtual std::coroutine_handle<> recv_from(
140 std::coroutine_handle<> h,
141 capy::executor_ref ex,
142 buffer_param buf,
143 corosio::local_endpoint* source,
144 int flags,
145 std::stop_token token,
146 std::error_code* ec,
147 std::size_t* bytes_out) = 0;
148
149 /** Initiate an asynchronous connect to set the default peer.
150
151 @param h Coroutine handle to resume on completion.
152 @param ex Executor for dispatching the completion.
153 @param ep The remote endpoint to connect to.
154 @param token Stop token for cancellation.
155 @param ec Output error code.
156
157 @return Coroutine handle to resume immediately.
158 */
159 virtual std::coroutine_handle<> connect(
160 std::coroutine_handle<> h,
161 capy::executor_ref ex,
162 corosio::local_endpoint ep,
163 std::stop_token token,
164 std::error_code* ec) = 0;
165
166 /** Initiate an asynchronous connected send operation.
167
168 @param h Coroutine handle to resume on completion.
169 @param ex Executor for dispatching the completion.
170 @param buf The buffer data to send.
171 @param token Stop token for cancellation.
172 @param ec Output error code.
173 @param bytes_out Output bytes transferred.
174
175 @return Coroutine handle to resume immediately.
176 */
177 virtual std::coroutine_handle<> send(
178 std::coroutine_handle<> h,
179 capy::executor_ref ex,
180 buffer_param buf,
181 int flags,
182 std::stop_token token,
183 std::error_code* ec,
184 std::size_t* bytes_out) = 0;
185
186 /** Initiate an asynchronous connected recv operation.
187
188 @param h Coroutine handle to resume on completion.
189 @param ex Executor for dispatching the completion.
190 @param buf The buffer to receive into.
191 @param flags Message flags (e.g. MSG_PEEK).
192 @param token Stop token for cancellation.
193 @param ec Output error code.
194 @param bytes_out Output bytes transferred.
195
196 @return Coroutine handle to resume immediately.
197 */
198 virtual std::coroutine_handle<> recv(
199 std::coroutine_handle<> h,
200 capy::executor_ref ex,
201 buffer_param buf,
202 int flags,
203 std::stop_token token,
204 std::error_code* ec,
205 std::size_t* bytes_out) = 0;
206
207 /// Shut down part or all of the socket.
208 virtual std::error_code shutdown(shutdown_type what) noexcept = 0;
209
210 /// Return the platform socket descriptor.
211 virtual native_handle_type native_handle() const noexcept = 0;
212
213 /** Release ownership of the socket descriptor.
214
215 The implementation deregisters from the reactor and cancels
216 pending operations. The caller takes ownership of the
217 returned descriptor.
218
219 @return The native handle, or an invalid sentinel if
220 not open.
221 */
222 virtual native_handle_type release_socket() noexcept = 0;
223
224 /** Request cancellation of pending asynchronous operations.
225
226 All outstanding operations complete with operation_canceled
227 error. Check ec == cond::canceled for portable comparison.
228 */
229 virtual void cancel() noexcept = 0;
230
231 /** Set a socket option.
232
233 @param level The protocol level (e.g. SOL_SOCKET).
234 @param optname The option name.
235 @param data Pointer to the option value.
236 @param size Size of the option value in bytes.
237 @return Error code on failure, empty on success.
238 */
239 virtual std::error_code set_option(
240 int level,
241 int optname,
242 void const* data,
243 std::size_t size) noexcept = 0;
244
245 /** Get a socket option.
246
247 @param level The protocol level (e.g. SOL_SOCKET).
248 @param optname The option name.
249 @param data Pointer to receive the option value.
250 @param size On entry, the size of the buffer. On exit,
251 the size of the option value.
252 @return Error code on failure, empty on success.
253 */
254 virtual std::error_code
255 get_option(int level, int optname, void* data, std::size_t* size)
256 const noexcept = 0;
257
258 /// Return the cached local endpoint.
259 virtual corosio::local_endpoint local_endpoint() const noexcept = 0;
260
261 /// Return the cached remote endpoint (connected mode).
262 virtual corosio::local_endpoint remote_endpoint() const noexcept = 0;
263
264 /** Bind the socket to a local endpoint.
265
266 @param ep The local endpoint to bind to.
267 @return Error code on failure, empty on success.
268 */
269 virtual std::error_code
270 bind(corosio::local_endpoint ep) noexcept = 0;
271 };
272
273 /** Represent the awaitable returned by @ref send_to.
274
275 Captures the destination endpoint and buffer, then dispatches
276 to the backend implementation on suspension.
277 */
278 struct send_to_awaitable
279 : detail::bytes_op_base<send_to_awaitable>
280 {
281 local_datagram_socket& s_;
282 buffer_param buf_;
283 corosio::local_endpoint dest_;
284 int flags_;
285
286 6x send_to_awaitable(
287 local_datagram_socket& s, buffer_param buf,
288 corosio::local_endpoint dest, int flags = 0) noexcept
289 6x : s_(s), buf_(buf), dest_(dest), flags_(flags) {}
290
291 6x std::coroutine_handle<> dispatch(
292 std::coroutine_handle<> h, capy::executor_ref ex) const
293 {
294 12x return s_.get().send_to(
295 12x h, ex, buf_, dest_, flags_, token_, &ec_, &bytes_);
296 }
297 };
298
299 /** Represent the awaitable returned by @ref recv_from.
300
301 Captures the source endpoint reference and buffer, then
302 dispatches to the backend implementation on suspension.
303 */
304 struct recv_from_awaitable
305 : detail::bytes_op_base<recv_from_awaitable>
306 {
307 local_datagram_socket& s_;
308 buffer_param buf_;
309 corosio::local_endpoint& source_;
310 int flags_;
311
312 8x recv_from_awaitable(
313 local_datagram_socket& s, buffer_param buf,
314 corosio::local_endpoint& source, int flags = 0) noexcept
315 8x : s_(s), buf_(buf), source_(source), flags_(flags) {}
316
317 8x std::coroutine_handle<> dispatch(
318 std::coroutine_handle<> h, capy::executor_ref ex) const
319 {
320 16x return s_.get().recv_from(
321 16x h, ex, buf_, &source_, flags_, token_, &ec_, &bytes_);
322 }
323 };
324
325 /** Represent the awaitable returned by @ref connect.
326
327 Captures the target endpoint, then dispatches to the
328 backend implementation on suspension.
329 */
330 struct connect_awaitable
331 : detail::void_op_base<connect_awaitable>
332 {
333 local_datagram_socket& s_;
334 corosio::local_endpoint endpoint_;
335
336 connect_awaitable(
337 local_datagram_socket& s,
338 corosio::local_endpoint ep) noexcept
339 : s_(s), endpoint_(ep) {}
340
341 std::coroutine_handle<> dispatch(
342 std::coroutine_handle<> h, capy::executor_ref ex) const
343 {
344 return s_.get().connect(
345 h, ex, endpoint_, token_, &ec_);
346 }
347 };
348
349 /** Represent the awaitable returned by @ref send.
350
351 Captures the buffer, then dispatches to the backend
352 implementation on suspension. Requires a prior connect().
353 */
354 struct send_awaitable
355 : detail::bytes_op_base<send_awaitable>
356 {
357 local_datagram_socket& s_;
358 buffer_param buf_;
359 int flags_;
360
361 8x send_awaitable(
362 local_datagram_socket& s, buffer_param buf,
363 int flags = 0) noexcept
364 8x : s_(s), buf_(buf), flags_(flags) {}
365
366 8x std::coroutine_handle<> dispatch(
367 std::coroutine_handle<> h, capy::executor_ref ex) const
368 {
369 16x return s_.get().send(
370 16x h, ex, buf_, flags_, token_, &ec_, &bytes_);
371 }
372 };
373
374 /** Represent the awaitable returned by @ref recv.
375
376 Captures the buffer, then dispatches to the backend
377 implementation on suspension. Requires a prior connect().
378 */
379 struct recv_awaitable
380 : detail::bytes_op_base<recv_awaitable>
381 {
382 local_datagram_socket& s_;
383 buffer_param buf_;
384 int flags_;
385
386 10x recv_awaitable(
387 local_datagram_socket& s, buffer_param buf,
388 int flags = 0) noexcept
389 10x : s_(s), buf_(buf), flags_(flags) {}
390
391 10x std::coroutine_handle<> dispatch(
392 std::coroutine_handle<> h, capy::executor_ref ex) const
393 {
394 20x return s_.get().recv(
395 20x h, ex, buf_, flags_, token_, &ec_, &bytes_);
396 }
397 };
398
399 public:
400 /** Destructor.
401
402 Closes the socket if open, cancelling any pending operations.
403 */
404 ~local_datagram_socket() override;
405
406 /** Construct a socket from an execution context.
407
408 @param ctx The execution context that will own this socket.
409 */
410 explicit local_datagram_socket(capy::execution_context& ctx);
411
412 /** Construct a socket from an executor.
413
414 The socket is associated with the executor's context.
415
416 @param ex The executor whose context will own the socket.
417 */
418 template<class Ex>
419 requires(
420 !std::same_as<std::remove_cvref_t<Ex>, local_datagram_socket>) &&
421 capy::Executor<Ex>
422 explicit local_datagram_socket(Ex const& ex)
423 : local_datagram_socket(ex.context())
424 {
425 }
426
427 /** Move constructor.
428
429 Transfers ownership of the socket resources.
430
431 @param other The socket to move from.
432 */
433 14x local_datagram_socket(local_datagram_socket&& other) noexcept
434 14x : io_object(std::move(other))
435 {
436 14x }
437
438 /** Move assignment operator.
439
440 Closes any existing socket and transfers ownership.
441
442 @param other The socket to move from.
443 @return Reference to this socket.
444 */
445 local_datagram_socket& operator=(local_datagram_socket&& other) noexcept
446 {
447 if (this != &other)
448 {
449 close();
450 io_object::operator=(std::move(other));
451 }
452 return *this;
453 }
454
455 local_datagram_socket(local_datagram_socket const&) = delete;
456 local_datagram_socket& operator=(local_datagram_socket const&) = delete;
457
458 /** Open the socket.
459
460 Creates a Unix datagram socket and associates it with
461 the platform reactor.
462
463 @param proto The protocol. Defaults to local_datagram{}.
464
465 @throws std::system_error on failure.
466 */
467 void open(local_datagram proto = {});
468
469 /** Close the socket.
470
471 Cancels any pending asynchronous operations and releases
472 the underlying file descriptor. Has no effect if the
473 socket is not open.
474
475 @post is_open() == false
476 */
477 void close();
478
479 /** Check if the socket is open.
480
481 @return `true` if the socket holds a valid file descriptor,
482 `false` otherwise.
483 */
484 142x bool is_open() const noexcept
485 {
486 #if BOOST_COROSIO_HAS_IOCP && !defined(BOOST_COROSIO_MRDOCS)
487 return h_ && get().native_handle() != ~native_handle_type(0);
488 #else
489 142x return h_ && get().native_handle() >= 0;
490 #endif
491 }
492
493 /** Bind the socket to a local endpoint.
494
495 Associates the socket with a local address (filesystem path).
496 Required before calling recv_from in connectionless mode.
497
498 @param ep The local endpoint to bind to.
499
500 @return Error code on failure, empty on success.
501
502 @throws std::logic_error if the socket is not open.
503 */
504 std::error_code bind(corosio::local_endpoint ep);
505
506 /** Initiate an asynchronous connect to set the default peer.
507
508 If the socket is not already open, it is opened automatically.
509 After successful completion, send()/recv() may be used
510 without specifying an endpoint.
511
512 @param ep The remote endpoint to connect to.
513
514 @par Cancellation
515 Supports cancellation via the awaitable's stop_token or by
516 calling cancel(). On cancellation, yields
517 `capy::cond::canceled`.
518
519 @return An awaitable that completes with io_result<>.
520
521 @throws std::system_error if the socket needs to be opened
522 and the open fails.
523 */
524 auto connect(corosio::local_endpoint ep)
525 {
526 if (!is_open())
527 open();
528 return connect_awaitable(*this, ep);
529 }
530
531 /** Send a datagram to the specified destination.
532
533 Completes when the entire datagram has been accepted
534 by the kernel. The bytes_transferred value equals the
535 datagram size on success.
536
537 @param buf The buffer containing data to send.
538 @param dest The destination endpoint.
539
540 @par Cancellation
541 Supports cancellation via stop_token or cancel().
542
543 @return An awaitable that completes with
544 io_result<std::size_t>.
545
546 @throws std::logic_error if the socket is not open.
547 */
548 template<capy::ConstBufferSequence Buffers>
549 6x auto send_to(
550 Buffers const& buf,
551 corosio::local_endpoint dest,
552 corosio::message_flags flags)
553 {
554 6x if (!is_open())
555 detail::throw_logic_error("send_to: socket not open");
556 return send_to_awaitable(
557 6x *this, buf, dest, static_cast<int>(flags));
558 }
559
560 /// @overload
561 template<capy::ConstBufferSequence Buffers>
562 6x auto send_to(Buffers const& buf, corosio::local_endpoint dest)
563 {
564 6x return send_to(buf, dest, corosio::message_flags::none);
565 }
566
567 /** Receive a datagram and capture the sender's endpoint.
568
569 Completes when one datagram has been received. The
570 bytes_transferred value is the number of bytes copied
571 into the buffer. If the buffer is smaller than the
572 datagram, excess bytes are discarded (datagram
573 semantics).
574
575 @param buf The buffer to receive data into.
576 @param source Reference to an endpoint that will be set to
577 the sender's address on successful completion.
578 @param flags Message flags (e.g. message_flags::peek).
579
580 @par Cancellation
581 Supports cancellation via stop_token or cancel().
582
583 @return An awaitable that completes with
584 io_result<std::size_t>.
585
586 @throws std::logic_error if the socket is not open.
587 */
588 template<capy::MutableBufferSequence Buffers>
589 8x auto recv_from(
590 Buffers const& buf,
591 corosio::local_endpoint& source,
592 corosio::message_flags flags)
593 {
594 8x if (!is_open())
595 detail::throw_logic_error("recv_from: socket not open");
596 return recv_from_awaitable(
597 8x *this, buf, source, static_cast<int>(flags));
598 }
599
600 /// @overload
601 template<capy::MutableBufferSequence Buffers>
602 6x auto recv_from(Buffers const& buf, corosio::local_endpoint& source)
603 {
604 6x return recv_from(buf, source, corosio::message_flags::none);
605 }
606
607 /** Send a datagram to the connected peer.
608
609 @pre connect() has been called successfully.
610
611 @param buf The buffer containing data to send.
612 @param flags Message flags.
613
614 @par Cancellation
615 Supports cancellation via stop_token or cancel().
616
617 @return An awaitable that completes with
618 io_result<std::size_t>.
619
620 @throws std::logic_error if the socket is not open.
621 */
622 template<capy::ConstBufferSequence Buffers>
623 8x auto send(Buffers const& buf, corosio::message_flags flags)
624 {
625 8x if (!is_open())
626 detail::throw_logic_error("send: socket not open");
627 return send_awaitable(
628 8x *this, buf, static_cast<int>(flags));
629 }
630
631 /// @overload
632 template<capy::ConstBufferSequence Buffers>
633 8x auto send(Buffers const& buf)
634 {
635 8x return send(buf, corosio::message_flags::none);
636 }
637
638 /** Receive a datagram from the connected peer.
639
640 @pre connect() has been called successfully.
641
642 @param buf The buffer to receive data into.
643 @param flags Message flags (e.g. message_flags::peek).
644
645 @par Cancellation
646 Supports cancellation via stop_token or cancel().
647
648 @return An awaitable that completes with
649 io_result<std::size_t>.
650
651 @throws std::logic_error if the socket is not open.
652 */
653 template<capy::MutableBufferSequence Buffers>
654 10x auto recv(Buffers const& buf, corosio::message_flags flags)
655 {
656 10x if (!is_open())
657 detail::throw_logic_error("recv: socket not open");
658 return recv_awaitable(
659 10x *this, buf, static_cast<int>(flags));
660 }
661
662 /// @overload
663 template<capy::MutableBufferSequence Buffers>
664 8x auto recv(Buffers const& buf)
665 {
666 8x return recv(buf, corosio::message_flags::none);
667 }
668
669 /** Cancel any pending asynchronous operations.
670
671 All outstanding operations complete with
672 errc::operation_canceled. Check ec == cond::canceled
673 for portable comparison.
674 */
675 void cancel();
676
677 /** Get the native socket handle.
678
679 @return The native socket handle, or -1 if not open.
680 */
681 native_handle_type native_handle() const noexcept;
682
683 /** Release ownership of the native socket handle.
684
685 Deregisters the socket from the reactor and cancels pending
686 operations without closing the fd. The caller takes ownership
687 of the returned descriptor.
688
689 @return The native handle, or -1 if not open.
690
691 @throws std::logic_error if the socket is not open.
692 */
693 native_handle_type release();
694
695 /** Query the number of bytes available for reading.
696
697 @return The number of bytes that can be read without blocking.
698
699 @throws std::logic_error if the socket is not open.
700 @throws std::system_error on ioctl failure.
701 */
702 std::size_t available() const;
703
704 /** Shut down part or all of the socket.
705
706 @param what Which direction to shut down.
707
708 @throws std::system_error on failure.
709 */
710 void shutdown(shutdown_type what);
711
712 /** Shut down part or all of the socket (non-throwing).
713
714 @param what Which direction to shut down.
715 @param ec Set to the error code on failure.
716 */
717 void shutdown(shutdown_type what, std::error_code& ec) noexcept;
718
719 /** Set a socket option.
720
721 @tparam Option A socket option type that provides static
722 `level()` and `name()` members, and `data()` / `size()`
723 accessors for the option value.
724
725 @param opt The option to set.
726
727 @throws std::logic_error if the socket is not open.
728 @throws std::system_error on failure.
729 */
730 template<class Option>
731 void set_option(Option const& opt)
732 {
733 if (!is_open())
734 detail::throw_logic_error("set_option: socket not open");
735 std::error_code ec = get().set_option(
736 Option::level(), Option::name(), opt.data(), opt.size());
737 if (ec)
738 detail::throw_system_error(
739 ec, "local_datagram_socket::set_option");
740 }
741
742 /** Get a socket option.
743
744 @tparam Option A socket option type that provides static
745 `level()` and `name()` members, `data()` / `size()`
746 accessors, and a `resize()` member.
747
748 @return The current option value.
749
750 @throws std::logic_error if the socket is not open.
751 @throws std::system_error on failure.
752 */
753 template<class Option>
754 Option get_option() const
755 {
756 if (!is_open())
757 detail::throw_logic_error("get_option: socket not open");
758 Option opt{};
759 std::size_t sz = opt.size();
760 std::error_code ec =
761 get().get_option(Option::level(), Option::name(), opt.data(), &sz);
762 if (ec)
763 detail::throw_system_error(
764 ec, "local_datagram_socket::get_option");
765 opt.resize(sz);
766 return opt;
767 }
768
769 /** Assign an existing file descriptor to this socket.
770
771 The socket must not already be open. The fd is adopted
772 and registered with the platform reactor.
773
774 @param fd The file descriptor to adopt.
775
776 @throws std::system_error on failure.
777 */
778 void assign(native_handle_type fd);
779
780 /** Get the local endpoint of the socket.
781
782 @return The local endpoint, or a default endpoint if not bound.
783 */
784 corosio::local_endpoint local_endpoint() const noexcept;
785
786 /** Get the remote endpoint of the socket.
787
788 Returns the address of the connected peer.
789
790 @return The remote endpoint, or a default endpoint if
791 not connected.
792 */
793 corosio::local_endpoint remote_endpoint() const noexcept;
794
795 protected:
796 /// Default-construct (for derived types).
797 local_datagram_socket() noexcept = default;
798
799 /// Construct from a pre-built handle.
800 explicit local_datagram_socket(handle h) noexcept
801 : io_object(std::move(h))
802 {
803 }
804
805 private:
806 void open_for_family(int family, int type, int protocol);
807
808 158x inline implementation& get() const noexcept
809 {
810 158x return *static_cast<implementation*>(h_.get());
811 }
812 };
813
814 } // namespace boost::corosio
815
816 #endif // BOOST_COROSIO_LOCAL_DATAGRAM_SOCKET_HPP
817