Line data Source code
1 : //
2 : // Copyright (c) 2025 Vinnie Falco (vinnie dot falco at gmail dot com)
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/tcp_socket.hpp>
11 : #include <boost/corosio/detail/except.hpp>
12 : #include <boost/corosio/detail/platform.hpp>
13 :
14 : #if BOOST_COROSIO_HAS_IOCP
15 : #include "src/detail/iocp/sockets.hpp"
16 : #else
17 : // POSIX backends use the abstract socket_service interface
18 : #include "src/detail/socket_service.hpp"
19 : #endif
20 :
21 : namespace boost::corosio {
22 :
23 9683 : tcp_socket::
24 9683 : ~tcp_socket()
25 : {
26 9683 : close();
27 9683 : }
28 :
29 9503 : tcp_socket::
30 : tcp_socket(
31 9503 : capy::execution_context& ctx)
32 9503 : : io_stream(ctx)
33 : {
34 9503 : }
35 :
36 : void
37 4739 : tcp_socket::
38 : open()
39 : {
40 4739 : if (impl_)
41 0 : return;
42 :
43 : #if BOOST_COROSIO_HAS_IOCP
44 : auto& svc = ctx_->use_service<detail::win_sockets>();
45 : auto& wrapper = svc.create_impl();
46 : impl_ = &wrapper;
47 : std::error_code ec = svc.open_socket(*wrapper.get_internal());
48 : #else
49 : // POSIX backends use abstract socket_service for runtime polymorphism.
50 : // The concrete service (epoll_sockets or select_sockets) must be installed
51 : // by the context constructor before any socket operations.
52 4739 : auto* svc = ctx_->find_service<detail::socket_service>();
53 4739 : if (!svc)
54 0 : detail::throw_logic_error("tcp_socket::open: no socket service installed");
55 4739 : auto& wrapper = svc->create_impl();
56 4739 : impl_ = &wrapper;
57 4739 : std::error_code ec = svc->open_socket(wrapper);
58 : #endif
59 4739 : if (ec)
60 : {
61 0 : wrapper.release();
62 0 : impl_ = nullptr;
63 0 : detail::throw_system_error(ec, "tcp_socket::open");
64 : }
65 : }
66 :
67 : void
68 23870 : tcp_socket::
69 : close()
70 : {
71 23870 : if (!impl_)
72 14418 : return;
73 :
74 : // socket_impl has virtual release() method
75 9452 : impl_->release();
76 9452 : impl_ = nullptr;
77 : }
78 :
79 : void
80 190 : tcp_socket::
81 : cancel()
82 : {
83 190 : if (!impl_)
84 0 : return;
85 : #if BOOST_COROSIO_HAS_IOCP
86 : static_cast<detail::win_socket_impl*>(impl_)->get_internal()->cancel();
87 : #else
88 : // socket_impl has virtual cancel() method
89 190 : get().cancel();
90 : #endif
91 : }
92 :
93 : void
94 12 : tcp_socket::
95 : shutdown(shutdown_type what)
96 : {
97 12 : if (impl_)
98 6 : get().shutdown(what);
99 12 : }
100 :
101 : native_handle_type
102 0 : tcp_socket::
103 : native_handle() const noexcept
104 : {
105 0 : if (!impl_)
106 : {
107 : #if BOOST_COROSIO_HAS_IOCP
108 : return static_cast<native_handle_type>(~0ull); // INVALID_SOCKET
109 : #else
110 0 : return -1;
111 : #endif
112 : }
113 0 : return get().native_handle();
114 : }
115 :
116 : //------------------------------------------------------------------------------
117 : // Socket Options
118 : //------------------------------------------------------------------------------
119 :
120 : void
121 10 : tcp_socket::
122 : set_no_delay(bool value)
123 : {
124 10 : if (!impl_)
125 0 : detail::throw_logic_error("set_no_delay: socket not open");
126 10 : std::error_code ec = get().set_no_delay(value);
127 10 : if (ec)
128 0 : detail::throw_system_error(ec, "tcp_socket::set_no_delay");
129 10 : }
130 :
131 : bool
132 10 : tcp_socket::
133 : no_delay() const
134 : {
135 10 : if (!impl_)
136 0 : detail::throw_logic_error("no_delay: socket not open");
137 10 : std::error_code ec;
138 10 : bool result = get().no_delay(ec);
139 10 : if (ec)
140 0 : detail::throw_system_error(ec, "tcp_socket::no_delay");
141 10 : return result;
142 : }
143 :
144 : void
145 8 : tcp_socket::
146 : set_keep_alive(bool value)
147 : {
148 8 : if (!impl_)
149 0 : detail::throw_logic_error("set_keep_alive: socket not open");
150 8 : std::error_code ec = get().set_keep_alive(value);
151 8 : if (ec)
152 0 : detail::throw_system_error(ec, "tcp_socket::set_keep_alive");
153 8 : }
154 :
155 : bool
156 8 : tcp_socket::
157 : keep_alive() const
158 : {
159 8 : if (!impl_)
160 0 : detail::throw_logic_error("keep_alive: socket not open");
161 8 : std::error_code ec;
162 8 : bool result = get().keep_alive(ec);
163 8 : if (ec)
164 0 : detail::throw_system_error(ec, "tcp_socket::keep_alive");
165 8 : return result;
166 : }
167 :
168 : void
169 2 : tcp_socket::
170 : set_receive_buffer_size(int size)
171 : {
172 2 : if (!impl_)
173 0 : detail::throw_logic_error("set_receive_buffer_size: socket not open");
174 2 : std::error_code ec = get().set_receive_buffer_size(size);
175 2 : if (ec)
176 0 : detail::throw_system_error(ec, "tcp_socket::set_receive_buffer_size");
177 2 : }
178 :
179 : int
180 6 : tcp_socket::
181 : receive_buffer_size() const
182 : {
183 6 : if (!impl_)
184 0 : detail::throw_logic_error("receive_buffer_size: socket not open");
185 6 : std::error_code ec;
186 6 : int result = get().receive_buffer_size(ec);
187 6 : if (ec)
188 0 : detail::throw_system_error(ec, "tcp_socket::receive_buffer_size");
189 6 : return result;
190 : }
191 :
192 : void
193 2 : tcp_socket::
194 : set_send_buffer_size(int size)
195 : {
196 2 : if (!impl_)
197 0 : detail::throw_logic_error("set_send_buffer_size: socket not open");
198 2 : std::error_code ec = get().set_send_buffer_size(size);
199 2 : if (ec)
200 0 : detail::throw_system_error(ec, "tcp_socket::set_send_buffer_size");
201 2 : }
202 :
203 : int
204 6 : tcp_socket::
205 : send_buffer_size() const
206 : {
207 6 : if (!impl_)
208 0 : detail::throw_logic_error("send_buffer_size: socket not open");
209 6 : std::error_code ec;
210 6 : int result = get().send_buffer_size(ec);
211 6 : if (ec)
212 0 : detail::throw_system_error(ec, "tcp_socket::send_buffer_size");
213 6 : return result;
214 : }
215 :
216 : void
217 8 : tcp_socket::
218 : set_linger(bool enabled, int timeout)
219 : {
220 8 : if (!impl_)
221 0 : detail::throw_logic_error("set_linger: socket not open");
222 8 : std::error_code ec = get().set_linger(enabled, timeout);
223 8 : if (ec)
224 2 : detail::throw_system_error(ec, "tcp_socket::set_linger");
225 6 : }
226 :
227 : tcp_socket::linger_options
228 6 : tcp_socket::
229 : linger() const
230 : {
231 6 : if (!impl_)
232 0 : detail::throw_logic_error("linger: socket not open");
233 6 : std::error_code ec;
234 6 : linger_options result = get().linger(ec);
235 6 : if (ec)
236 0 : detail::throw_system_error(ec, "tcp_socket::linger");
237 6 : return result;
238 : }
239 :
240 : endpoint
241 42 : tcp_socket::
242 : local_endpoint() const noexcept
243 : {
244 42 : if (!impl_)
245 10 : return endpoint{};
246 32 : return get().local_endpoint();
247 : }
248 :
249 : endpoint
250 42 : tcp_socket::
251 : remote_endpoint() const noexcept
252 : {
253 42 : if (!impl_)
254 10 : return endpoint{};
255 32 : return get().remote_endpoint();
256 : }
257 :
258 : } // namespace boost::corosio
|