src/corosio/src/local_socket_pair.cpp

61.0% Lines (25/41) 100.0% List of functions (3/3)
local_socket_pair.cpp
f(x) Functions (3)
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 #include <boost/corosio/local_socket_pair.hpp>
11 #include <boost/corosio/io_context.hpp>
12 #include <boost/corosio/detail/platform.hpp>
13
14 #if BOOST_COROSIO_POSIX
15
16 #include <stdexcept>
17 #include <system_error>
18 #include <utility>
19
20 #include <fcntl.h>
21 #include <sys/socket.h>
22 #include <unistd.h>
23
24 namespace boost::corosio {
25
26 namespace {
27
28 #ifndef SOCK_NONBLOCK
29 // Only needed on platforms lacking SOCK_NONBLOCK/SOCK_CLOEXEC (e.g. older BSDs).
30 // On Linux/glibc SOCK_NONBLOCK is always defined, so omitting this definition
31 // avoids a -Wunused-function diagnostic.
32 //
33 // Returns 0 on success or errno on failure. Caller owns fd on error.
34 int
35 make_nonblock_cloexec(int fd)
36 {
37 int fl = ::fcntl(fd, F_GETFL, 0);
38 if (fl == -1)
39 return errno;
40 if (::fcntl(fd, F_SETFL, fl | O_NONBLOCK) == -1)
41 return errno;
42 if (::fcntl(fd, F_SETFD, FD_CLOEXEC) == -1)
43 return errno;
44 return 0;
45 }
46 #endif
47
48 void
49 16x create_pair(int type, int fds[2])
50 {
51 16x int flags = type;
52 #ifdef SOCK_NONBLOCK
53 16x flags |= SOCK_NONBLOCK | SOCK_CLOEXEC;
54 #endif
55 16x if (::socketpair(AF_UNIX, flags, 0, fds) != 0)
56 throw std::system_error(
57 std::error_code(errno, std::system_category()),
58 "socketpair");
59 #ifndef SOCK_NONBLOCK
60 int err = make_nonblock_cloexec(fds[0]);
61 if (err == 0)
62 err = make_nonblock_cloexec(fds[1]);
63 if (err != 0)
64 {
65 ::close(fds[0]);
66 ::close(fds[1]);
67 throw std::system_error(
68 std::error_code(err, std::system_category()),
69 "socketpair (fcntl setup)");
70 }
71 #endif
72 16x }
73
74 } // namespace
75
76 std::pair<local_stream_socket, local_stream_socket>
77 8x make_local_stream_pair(io_context& ctx)
78 {
79 int fds[2];
80 8x create_pair(SOCK_STREAM, fds);
81
82 try
83 {
84 8x local_stream_socket s1(ctx);
85 8x local_stream_socket s2(ctx);
86
87 8x s1.assign(fds[0]);
88 8x fds[0] = -1;
89 8x s2.assign(fds[1]);
90 8x fds[1] = -1;
91
92 16x return {std::move(s1), std::move(s2)};
93 8x }
94 catch (...)
95 {
96 if (fds[0] >= 0)
97 ::close(fds[0]);
98 if (fds[1] >= 0)
99 ::close(fds[1]);
100 throw;
101 }
102 }
103
104 std::pair<local_datagram_socket, local_datagram_socket>
105 8x make_local_datagram_pair(io_context& ctx)
106 {
107 int fds[2];
108 8x create_pair(SOCK_DGRAM, fds);
109
110 try
111 {
112 8x local_datagram_socket s1(ctx);
113 8x local_datagram_socket s2(ctx);
114
115 8x s1.assign(fds[0]);
116 8x fds[0] = -1;
117 8x s2.assign(fds[1]);
118 8x fds[1] = -1;
119
120 16x return {std::move(s1), std::move(s2)};
121 8x }
122 catch (...)
123 {
124 if (fds[0] >= 0)
125 ::close(fds[0]);
126 if (fds[1] >= 0)
127 ::close(fds[1]);
128 throw;
129 }
130 }
131
132 } // namespace boost::corosio
133
134 #endif // BOOST_COROSIO_POSIX
135