src/corosio/src/tcp_socket.cpp

77.2% Lines (88/114) 94.7% Functions (18/19) 58.6% Branches (34/58)
src/corosio/src/tcp_socket.cpp
Line Branch TLA Hits Source Code
1 //
2 // Copyright (c) 2025 Vinnie Falco ([email protected])
3 // Copyright (c) 2026 Steve Gerbino
4 //
5 // Distributed under the Boost Software License, Version 1.0. (See accompanying
6 // file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt)
7 //
8 // Official repository: https://github.com/cppalliance/corosio
9 //
10
11 #include <boost/corosio/tcp_socket.hpp>
12 #include <boost/corosio/detail/except.hpp>
13 #include <boost/corosio/detail/platform.hpp>
14
15 #if BOOST_COROSIO_HAS_IOCP
16 #include <boost/corosio/native/detail/iocp/win_acceptor_service.hpp>
17 #else
18 #include <boost/corosio/detail/socket_service.hpp>
19 #endif
20
21 namespace boost::corosio {
22
23 4778 tcp_socket::~tcp_socket()
24 {
25 4778 close();
26 4778 }
27
28 2489 tcp_socket::tcp_socket(capy::execution_context& ctx)
29 #if BOOST_COROSIO_HAS_IOCP
30
1/1
✓ Branch 2 → 3 taken 2489 times.
2489 : io_object(create_handle<detail::win_sockets>(ctx))
31 #else
32 : io_object(create_handle<detail::socket_service>(ctx))
33 #endif
34 {
35 2489 }
36
37 void
38 1215 tcp_socket::open()
39 {
40
1/2
✗ Branch 3 → 4 not taken.
✓ Branch 3 → 5 taken 1215 times.
1215 if (is_open())
41 return;
42 #if BOOST_COROSIO_HAS_IOCP
43 1215 auto& svc = static_cast<detail::win_sockets&>(h_.service());
44 1215 auto& wrapper = static_cast<tcp_socket::implementation&>(*h_.get());
45
1/1
✓ Branch 8 → 9 taken 1215 times.
1215 std::error_code ec = svc.open_socket(
46 1215 *static_cast<detail::win_socket&>(wrapper).get_internal());
47 #else
48 auto& svc = static_cast<detail::socket_service&>(h_.service());
49 std::error_code ec =
50 svc.open_socket(static_cast<tcp_socket::implementation&>(*h_.get()));
51 #endif
52
1/2
✗ Branch 10 → 11 not taken.
✓ Branch 10 → 12 taken 1215 times.
1215 if (ec)
53 detail::throw_system_error(ec, "tcp_socket::open");
54 }
55
56 void
57 7263 tcp_socket::close()
58 {
59
2/2
✓ Branch 3 → 4 taken 4847 times.
✓ Branch 3 → 5 taken 2416 times.
7263 if (!is_open())
60 4847 return;
61 2416 h_.service().close(h_);
62 }
63
64 void
65 2107 tcp_socket::cancel()
66 {
67
1/2
✗ Branch 3 → 4 not taken.
✓ Branch 3 → 5 taken 2107 times.
2107 if (!is_open())
68 return;
69 2107 get().cancel();
70 }
71
72 void
73 6 tcp_socket::shutdown(shutdown_type what)
74 {
75
2/2
✓ Branch 3 → 4 taken 3 times.
✓ Branch 3 → 7 taken 3 times.
6 if (is_open())
76 {
77 // Best-effort: errors like ENOTCONN are expected and unhelpful
78 3 [[maybe_unused]] auto ec = get().shutdown(what);
79 }
80 6 }
81
82 native_handle_type
83 tcp_socket::native_handle() const noexcept
84 {
85 if (!is_open())
86 {
87 #if BOOST_COROSIO_HAS_IOCP
88 return static_cast<native_handle_type>(~0ull); // INVALID_SOCKET
89 #else
90 return -1;
91 #endif
92 }
93 return get().native_handle();
94 }
95
96 void
97 5 tcp_socket::set_no_delay(bool value)
98 {
99
1/2
✗ Branch 3 → 4 not taken.
✓ Branch 3 → 5 taken 5 times.
5 if (!is_open())
100 detail::throw_logic_error("set_no_delay: socket not open");
101 5 std::error_code ec = get().set_no_delay(value);
102
1/2
✗ Branch 8 → 9 not taken.
✓ Branch 8 → 10 taken 5 times.
5 if (ec)
103 detail::throw_system_error(ec, "tcp_socket::set_no_delay");
104 5 }
105
106 bool
107 5 tcp_socket::no_delay() const
108 {
109
1/2
✗ Branch 3 → 4 not taken.
✓ Branch 3 → 5 taken 5 times.
5 if (!is_open())
110 detail::throw_logic_error("no_delay: socket not open");
111 5 std::error_code ec;
112 5 bool result = get().no_delay(ec);
113
1/2
✗ Branch 9 → 10 not taken.
✓ Branch 9 → 11 taken 5 times.
5 if (ec)
114 detail::throw_system_error(ec, "tcp_socket::no_delay");
115 5 return result;
116 }
117
118 void
119 4 tcp_socket::set_keep_alive(bool value)
120 {
121
1/2
✗ Branch 3 → 4 not taken.
✓ Branch 3 → 5 taken 4 times.
4 if (!is_open())
122 detail::throw_logic_error("set_keep_alive: socket not open");
123 4 std::error_code ec = get().set_keep_alive(value);
124
1/2
✗ Branch 8 → 9 not taken.
✓ Branch 8 → 10 taken 4 times.
4 if (ec)
125 detail::throw_system_error(ec, "tcp_socket::set_keep_alive");
126 4 }
127
128 bool
129 4 tcp_socket::keep_alive() const
130 {
131
1/2
✗ Branch 3 → 4 not taken.
✓ Branch 3 → 5 taken 4 times.
4 if (!is_open())
132 detail::throw_logic_error("keep_alive: socket not open");
133 4 std::error_code ec;
134 4 bool result = get().keep_alive(ec);
135
1/2
✗ Branch 9 → 10 not taken.
✓ Branch 9 → 11 taken 4 times.
4 if (ec)
136 detail::throw_system_error(ec, "tcp_socket::keep_alive");
137 4 return result;
138 }
139
140 void
141 1 tcp_socket::set_receive_buffer_size(int size)
142 {
143
1/2
✗ Branch 3 → 4 not taken.
✓ Branch 3 → 5 taken 1 time.
1 if (!is_open())
144 detail::throw_logic_error("set_receive_buffer_size: socket not open");
145 1 std::error_code ec = get().set_receive_buffer_size(size);
146
1/2
✗ Branch 8 → 9 not taken.
✓ Branch 8 → 10 taken 1 time.
1 if (ec)
147 detail::throw_system_error(ec, "tcp_socket::set_receive_buffer_size");
148 1 }
149
150 int
151 3 tcp_socket::receive_buffer_size() const
152 {
153
1/2
✗ Branch 3 → 4 not taken.
✓ Branch 3 → 5 taken 3 times.
3 if (!is_open())
154 detail::throw_logic_error("receive_buffer_size: socket not open");
155 3 std::error_code ec;
156 3 int result = get().receive_buffer_size(ec);
157
1/2
✗ Branch 9 → 10 not taken.
✓ Branch 9 → 11 taken 3 times.
3 if (ec)
158 detail::throw_system_error(ec, "tcp_socket::receive_buffer_size");
159 3 return result;
160 }
161
162 void
163 1 tcp_socket::set_send_buffer_size(int size)
164 {
165
1/2
✗ Branch 3 → 4 not taken.
✓ Branch 3 → 5 taken 1 time.
1 if (!is_open())
166 detail::throw_logic_error("set_send_buffer_size: socket not open");
167 1 std::error_code ec = get().set_send_buffer_size(size);
168
1/2
✗ Branch 8 → 9 not taken.
✓ Branch 8 → 10 taken 1 time.
1 if (ec)
169 detail::throw_system_error(ec, "tcp_socket::set_send_buffer_size");
170 1 }
171
172 int
173 3 tcp_socket::send_buffer_size() const
174 {
175
1/2
✗ Branch 3 → 4 not taken.
✓ Branch 3 → 5 taken 3 times.
3 if (!is_open())
176 detail::throw_logic_error("send_buffer_size: socket not open");
177 3 std::error_code ec;
178 3 int result = get().send_buffer_size(ec);
179
1/2
✗ Branch 9 → 10 not taken.
✓ Branch 9 → 11 taken 3 times.
3 if (ec)
180 detail::throw_system_error(ec, "tcp_socket::send_buffer_size");
181 3 return result;
182 }
183
184 void
185 2102 tcp_socket::set_linger(bool enabled, int timeout)
186 {
187
1/2
✗ Branch 3 → 4 not taken.
✓ Branch 3 → 5 taken 2102 times.
2102 if (!is_open())
188 detail::throw_logic_error("set_linger: socket not open");
189 2102 std::error_code ec = get().set_linger(enabled, timeout);
190
2/2
✓ Branch 8 → 9 taken 1 time.
✓ Branch 8 → 10 taken 2101 times.
2102 if (ec)
191 1 detail::throw_system_error(ec, "tcp_socket::set_linger");
192 2101 }
193
194 tcp_socket::linger_options
195 3 tcp_socket::linger() const
196 {
197
1/2
✗ Branch 3 → 4 not taken.
✓ Branch 3 → 5 taken 3 times.
3 if (!is_open())
198 detail::throw_logic_error("linger: socket not open");
199 3 std::error_code ec;
200 3 linger_options result = get().linger(ec);
201
1/2
✗ Branch 9 → 10 not taken.
✓ Branch 9 → 11 taken 3 times.
3 if (ec)
202 detail::throw_system_error(ec, "tcp_socket::linger");
203 3 return result;
204 }
205
206 endpoint
207 21 tcp_socket::local_endpoint() const noexcept
208 {
209
2/2
✓ Branch 3 → 4 taken 5 times.
✓ Branch 3 → 5 taken 16 times.
21 if (!is_open())
210 5 return endpoint{};
211 16 return get().local_endpoint();
212 }
213
214 endpoint
215 21 tcp_socket::remote_endpoint() const noexcept
216 {
217
2/2
✓ Branch 3 → 4 taken 5 times.
✓ Branch 3 → 5 taken 16 times.
21 if (!is_open())
218 5 return endpoint{};
219 16 return get().remote_endpoint();
220 }
221
222 } // namespace boost::corosio
223