src/corosio/src/tcp_socket.cpp

76.8% Lines (86/112) 94.7% Functions (18/19)
src/corosio/src/tcp_socket.cpp
Line Hits Source Code
1 //
2 // Copyright (c) 2025 Vinnie Falco (vinnie.falco@gmail.com)
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 "src/detail/iocp/sockets.hpp"
17 #else
18 #include "src/detail/socket_service.hpp"
19 #endif
20
21 namespace boost::corosio {
22
23 17006 tcp_socket::~tcp_socket()
24 {
25 17006 close();
26 17006 }
27
28 16826 tcp_socket::tcp_socket(capy::execution_context& ctx)
29 #if BOOST_COROSIO_HAS_IOCP
30 : io_stream(create_handle<detail::win_sockets>(ctx))
31 #else
32 16826 : io_stream(create_handle<detail::socket_service>(ctx))
33 #endif
34 {
35 16826 }
36
37 void
38 8400 tcp_socket::open()
39 {
40 8400 if (is_open())
41 return;
42 #if BOOST_COROSIO_HAS_IOCP
43 auto& svc = static_cast<detail::win_sockets&>(h_.service());
44 auto& wrapper = static_cast<tcp_socket::implementation&>(*h_.get());
45 std::error_code ec = svc.open_socket(
46 *static_cast<detail::win_socket_impl&>(wrapper).get_internal());
47 #else
48 8400 auto& svc = static_cast<detail::socket_service&>(h_.service());
49 std::error_code ec =
50 8400 svc.open_socket(static_cast<tcp_socket::implementation&>(*h_.get()));
51 #endif
52 8400 if (ec)
53 detail::throw_system_error(ec, "tcp_socket::open");
54 }
55
56 void
57 33803 tcp_socket::close()
58 {
59 33803 if (!is_open())
60 17028 return;
61 16775 h_.service().close(h_);
62 }
63
64 void
65 364 tcp_socket::cancel()
66 {
67 364 if (!is_open())
68 return;
69 364 get().cancel();
70 }
71
72 void
73 12 tcp_socket::shutdown(shutdown_type what)
74 {
75 12 if (is_open())
76 {
77 // Best-effort: errors like ENOTCONN are expected and unhelpful
78 6 [[maybe_unused]] auto ec = get().shutdown(what);
79 }
80 12 }
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 10 tcp_socket::set_no_delay(bool value)
98 {
99 10 if (!is_open())
100 detail::throw_logic_error("set_no_delay: socket not open");
101 10 std::error_code ec = get().set_no_delay(value);
102 10 if (ec)
103 detail::throw_system_error(ec, "tcp_socket::set_no_delay");
104 10 }
105
106 bool
107 10 tcp_socket::no_delay() const
108 {
109 10 if (!is_open())
110 detail::throw_logic_error("no_delay: socket not open");
111 10 std::error_code ec;
112 10 bool result = get().no_delay(ec);
113 10 if (ec)
114 detail::throw_system_error(ec, "tcp_socket::no_delay");
115 10 return result;
116 }
117
118 void
119 8 tcp_socket::set_keep_alive(bool value)
120 {
121 8 if (!is_open())
122 detail::throw_logic_error("set_keep_alive: socket not open");
123 8 std::error_code ec = get().set_keep_alive(value);
124 8 if (ec)
125 detail::throw_system_error(ec, "tcp_socket::set_keep_alive");
126 8 }
127
128 bool
129 8 tcp_socket::keep_alive() const
130 {
131 8 if (!is_open())
132 detail::throw_logic_error("keep_alive: socket not open");
133 8 std::error_code ec;
134 8 bool result = get().keep_alive(ec);
135 8 if (ec)
136 detail::throw_system_error(ec, "tcp_socket::keep_alive");
137 8 return result;
138 }
139
140 void
141 2 tcp_socket::set_receive_buffer_size(int size)
142 {
143 2 if (!is_open())
144 detail::throw_logic_error("set_receive_buffer_size: socket not open");
145 2 std::error_code ec = get().set_receive_buffer_size(size);
146 2 if (ec)
147 detail::throw_system_error(ec, "tcp_socket::set_receive_buffer_size");
148 2 }
149
150 int
151 6 tcp_socket::receive_buffer_size() const
152 {
153 6 if (!is_open())
154 detail::throw_logic_error("receive_buffer_size: socket not open");
155 6 std::error_code ec;
156 6 int result = get().receive_buffer_size(ec);
157 6 if (ec)
158 detail::throw_system_error(ec, "tcp_socket::receive_buffer_size");
159 6 return result;
160 }
161
162 void
163 2 tcp_socket::set_send_buffer_size(int size)
164 {
165 2 if (!is_open())
166 detail::throw_logic_error("set_send_buffer_size: socket not open");
167 2 std::error_code ec = get().set_send_buffer_size(size);
168 2 if (ec)
169 detail::throw_system_error(ec, "tcp_socket::set_send_buffer_size");
170 2 }
171
172 int
173 6 tcp_socket::send_buffer_size() const
174 {
175 6 if (!is_open())
176 detail::throw_logic_error("send_buffer_size: socket not open");
177 6 std::error_code ec;
178 6 int result = get().send_buffer_size(ec);
179 6 if (ec)
180 detail::throw_system_error(ec, "tcp_socket::send_buffer_size");
181 6 return result;
182 }
183
184 void
185 12 tcp_socket::set_linger(bool enabled, int timeout)
186 {
187 12 if (!is_open())
188 detail::throw_logic_error("set_linger: socket not open");
189 12 std::error_code ec = get().set_linger(enabled, timeout);
190 12 if (ec)
191 2 detail::throw_system_error(ec, "tcp_socket::set_linger");
192 10 }
193
194 tcp_socket::linger_options
195 6 tcp_socket::linger() const
196 {
197 6 if (!is_open())
198 detail::throw_logic_error("linger: socket not open");
199 6 std::error_code ec;
200 6 linger_options result = get().linger(ec);
201 6 if (ec)
202 detail::throw_system_error(ec, "tcp_socket::linger");
203 6 return result;
204 }
205
206 endpoint
207 42 tcp_socket::local_endpoint() const noexcept
208 {
209 42 if (!is_open())
210 10 return endpoint{};
211 32 return get().local_endpoint();
212 }
213
214 endpoint
215 42 tcp_socket::remote_endpoint() const noexcept
216 {
217 42 if (!is_open())
218 10 return endpoint{};
219 32 return get().remote_endpoint();
220 }
221
222 } // namespace boost::corosio
223