src/corosio/src/local_stream_acceptor.cpp

67.3% Lines (35/52) 66.7% List of functions (6/9)
local_stream_acceptor.cpp
f(x) Functions (9)
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/detail/platform.hpp>
11
12 #if BOOST_COROSIO_POSIX
13
14 #include <boost/corosio/local_stream_acceptor.hpp>
15 #include <boost/corosio/detail/except.hpp>
16 #include <boost/corosio/detail/local_stream_acceptor_service.hpp>
17
18 #include <cstring>
19
20 #include <sys/stat.h>
21 #include <unistd.h>
22
23 namespace boost::corosio {
24
25 12x local_stream_acceptor::~local_stream_acceptor()
26 {
27 12x close();
28 12x }
29
30 12x local_stream_acceptor::local_stream_acceptor(capy::execution_context& ctx)
31 12x : io_object(create_handle<detail::local_stream_acceptor_service>(ctx))
32 12x , ctx_(ctx)
33 {
34 12x }
35
36 void
37 12x local_stream_acceptor::open(local_stream proto)
38 {
39 12x if (is_open())
40 return;
41 auto& svc =
42 12x static_cast<detail::local_stream_acceptor_service&>(h_.service());
43 24x auto ec = svc.open_acceptor_socket(
44 12x static_cast<local_stream_acceptor::implementation&>(*h_.get()),
45 proto.family(), proto.type(), proto.protocol());
46 12x if (ec)
47 detail::throw_system_error(ec, "local_stream_acceptor::open");
48 }
49
50 std::error_code
51 12x local_stream_acceptor::bind(corosio::local_endpoint ep, bind_option opt)
52 {
53 12x if (!is_open())
54 detail::throw_logic_error("bind: acceptor not open");
55
56 16x if (opt == bind_option::unlink_existing &&
57 12x !ep.empty() && !ep.is_abstract())
58 {
59 4x auto p = ep.path();
60 // path() is not null-terminated for the fixed buffer,
61 // so copy to a local array for syscalls.
62 char buf[local_endpoint::max_path_length + 1];
63 4x std::memcpy(buf, p.data(), p.size());
64 4x buf[p.size()] = '\0';
65
66 // Only remove the path if it actually points to a socket
67 // file. Use lstat (NOT stat) so a symlink at the path is
68 // left alone — otherwise this option could be abused via
69 // symlink races to delete arbitrary files. Any lstat
70 // failure (ENOENT or otherwise) is treated as "nothing to
71 // remove" and we let bind() handle whatever's actually
72 // there.
73 struct stat st;
74 4x if (::lstat(buf, &st) == 0 && S_ISSOCK(st.st_mode))
75 2x ::unlink(buf);
76 }
77
78 auto& svc =
79 12x static_cast<detail::local_stream_acceptor_service&>(h_.service());
80 12x return svc.bind_acceptor(
81 12x static_cast<local_stream_acceptor::implementation&>(*h_.get()),
82 12x ep);
83 }
84
85 std::error_code
86 4x local_stream_acceptor::listen(int backlog)
87 {
88 4x if (!is_open())
89 detail::throw_logic_error("listen: acceptor not open");
90 auto& svc =
91 4x static_cast<detail::local_stream_acceptor_service&>(h_.service());
92 4x return svc.listen_acceptor(
93 4x static_cast<local_stream_acceptor::implementation&>(*h_.get()),
94 4x backlog);
95 }
96
97 void
98 12x local_stream_acceptor::close()
99 {
100 12x if (!is_open())
101 return;
102 12x h_.service().close(h_);
103 }
104
105 native_handle_type
106 local_stream_acceptor::release()
107 {
108 if (!is_open())
109 detail::throw_logic_error("release: acceptor not open");
110 return get().release_socket();
111 }
112
113 void
114 local_stream_acceptor::cancel()
115 {
116 if (!is_open())
117 return;
118 get().cancel();
119 }
120
121 local_endpoint
122 local_stream_acceptor::local_endpoint() const noexcept
123 {
124 if (!is_open())
125 return corosio::local_endpoint{};
126 return get().local_endpoint();
127 }
128
129 } // namespace boost::corosio
130
131 #endif // BOOST_COROSIO_POSIX
132