WPILibC++ 2027.0.0-alpha-4
Loading...
Searching...
No Matches
Tcp.hpp
Go to the documentation of this file.
1// Copyright (c) FIRST and other WPILib contributors.
2// Open Source Software; you can modify and/or share it under the terms of
3// the WPILib BSD license file in the root directory of this project.
4
5#pragma once
6
7#include <chrono>
8#include <functional>
9#include <memory>
10#include <string_view>
11#include <utility>
12
13#include <uv.h>
14
16
17namespace wpi::net::uv {
18
19class Loop;
20class TcpConnectReq;
21
22/**
23 * TCP handle.
24 * TCP handles are used to represent both TCP streams and servers.
25 */
26class Tcp final : public NetworkStreamImpl<Tcp, uv_tcp_t> {
27 struct private_init {};
28
29 public:
30 using Time = std::chrono::seconds;
31
32 explicit Tcp(const private_init&) {}
33 ~Tcp() noexcept override = default;
34
35 /**
36 * Create a TCP handle.
37 *
38 * @param loop Loop object where this handle runs.
39 * @param flags Flags
40 */
41 static std::shared_ptr<Tcp> Create(Loop& loop,
42 unsigned int flags = AF_UNSPEC);
43
44 /**
45 * Create a TCP handle.
46 *
47 * @param loop Loop object where this handle runs.
48 * @param flags Flags
49 */
50 static std::shared_ptr<Tcp> Create(const std::shared_ptr<Loop>& loop,
51 unsigned int flags = AF_UNSPEC) {
52 return Create(*loop, flags);
53 }
54
55 /**
56 * Reuse this handle. This closes the handle, and after the close completes,
57 * reinitializes it (identically to Create) and calls the provided callback.
58 * Unlike Close(), it does NOT emit the closed signal, however, IsClosing()
59 * will return true until the callback is called. This does nothing if
60 * IsClosing() is true (e.g. if Close() was called).
61 *
62 * @param flags Flags
63 * @param callback Callback
64 */
65 void Reuse(std::function<void()> callback, unsigned int flags = AF_UNSPEC);
66
67 /**
68 * Accept incoming connection.
69 *
70 * This call is used in conjunction with `Listen()` to accept incoming
71 * connections. Call this function after receiving a ListenEvent event to
72 * accept the connection.
73 * An error signal will be emitted in case of errors.
74 *
75 * When the connection signal is emitted it is guaranteed that this
76 * function will complete successfully the first time. If you attempt to use
77 * it more than once, it may fail.
78 * It is suggested to only call this function once per connection signal.
79 *
80 * @return The stream handle for the accepted connection, or nullptr on error.
81 */
82 std::shared_ptr<Tcp> Accept();
83
84 /**
85 * Accept incoming connection.
86 *
87 * This call is used in conjunction with `Listen()` to accept incoming
88 * connections. Call this function after receiving a connection signal to
89 * accept the connection.
90 * An error signal will be emitted in case of errors.
91 *
92 * When the connection signal is emitted it is guaranteed that this
93 * function will complete successfully the first time. If you attempt to use
94 * it more than once, it may fail.
95 * It is suggested to only call this function once per connection signal.
96 *
97 * @param client Client stream object.
98 * @return False on error.
99 */
100 bool Accept(const std::shared_ptr<Tcp>& client) {
101 return NetworkStream::Accept(client);
102 }
103
104 /**
105 * Open an existing file descriptor or SOCKET as a TCP handle.
106 *
107 * @note The passed file descriptor or SOCKET is not checked for its type, but
108 * it's required that it represents a valid stream socket.
109 *
110 * @param sock A valid socket handle (either a file descriptor or a SOCKET).
111 */
112 void Open(uv_os_sock_t sock) { Invoke(&uv_tcp_open, GetRaw(), sock); }
113
114 /**
115 * Enable no delay operation (turns off Nagle's algorithm).
116 * @param enable True to enable it, false otherwise.
117 * @return True in case of success, false otherwise.
118 */
119 bool SetNoDelay(bool enable) { return uv_tcp_nodelay(GetRaw(), enable) == 0; }
120
121 /**
122 * Enable/Disable TCP keep-alive.
123 * @param enable True to enable it, false otherwise.
124 * @param time Initial delay in seconds (use
125 * `std::chrono::duration<unsigned int>`).
126 * @return True in case of success, false otherwise.
127 */
128 bool SetKeepAlive(bool enable, Time time = Time{0}) {
129 return uv_tcp_keepalive(GetRaw(), enable,
130 static_cast<unsigned>(time.count())) == 0;
131 }
132
133 /**
134 * Enable/Disable simultaneous asynchronous accept requests.
135 *
136 * Enable/Disable simultaneous asynchronous accept requests that are
137 * queued by the operating system when listening for new TCP
138 * connections.
139 * This setting is used to tune a TCP server for the desired performance.
140 * Having simultaneous accepts can significantly improve the rate of
141 * accepting connections (which is why it is enabled by default) but may
142 * lead to uneven load distribution in multi-process setups.
143 *
144 * @param enable True to enable it, false otherwise.
145 * @return True in case of success, false otherwise.
146 */
147 bool SetSimultaneousAccepts(bool enable) {
148 return uv_tcp_simultaneous_accepts(GetRaw(), enable) == 0;
149 }
150
151 /**
152 * Bind the handle to an IPv4 or IPv6 address and port.
153 *
154 * A successful call to this function does not guarantee that the call to
155 * `Listen()` or `Connect()` will work properly.
156 * An error signal can be emitted because of either this function or the
157 * ones mentioned above.
158 *
159 * @param addr Initialized `sockaddr_in` or `sockaddr_in6` data structure.
160 * @param flags Optional additional flags.
161 */
162 void Bind(const sockaddr& addr, unsigned int flags = 0) {
163 Invoke(&uv_tcp_bind, GetRaw(), &addr, flags);
164 }
165
166 void Bind(const sockaddr_in& addr, unsigned int flags = 0) {
167 Bind(reinterpret_cast<const sockaddr&>(addr), flags);
168 }
169
170 void Bind(const sockaddr_in6& addr, unsigned int flags = 0) {
171 Bind(reinterpret_cast<const sockaddr&>(addr), flags);
172 }
173
174 /**
175 * Bind the handle to an IPv4 address and port.
176 *
177 * A successful call to this function does not guarantee that the call to
178 * `Listen()` or `Connect()` will work properly.
179 * An error signal can be emitted because of either this function or the
180 * ones mentioned above.
181 *
182 * Available flags are:
183 *
184 * @param ip The address to which to bind.
185 * @param port The port to which to bind.
186 * @param flags Optional additional flags.
187 */
188 void Bind(std::string_view ip, unsigned int port, unsigned int flags = 0);
189
190 /**
191 * Bind the handle to an IPv6 address and port.
192 *
193 * A successful call to this function does not guarantee that the call to
194 * `Listen()` or `Connect()` will work properly.
195 * An error signal can be emitted because of either this function or the
196 * ones mentioned above.
197 *
198 * Available flags are:
199 *
200 * @param ip The address to which to bind.
201 * @param port The port to which to bind.
202 * @param flags Optional additional flags.
203 */
204 void Bind6(std::string_view ip, unsigned int port, unsigned int flags = 0);
205
206 /**
207 * Get the current address to which the handle is bound.
208 * @return The address (will be zeroed if an error occurred).
209 */
210 sockaddr_storage GetSock();
211
212 /**
213 * Get the address of the peer connected to the handle.
214 * @return The address (will be zeroed if an error occurred).
215 */
216 sockaddr_storage GetPeer();
217
218 /**
219 * Establish an IPv4 or IPv6 TCP connection.
220 *
221 * On Windows if the addr is initialized to point to an unspecified address
222 * (`0.0.0.0` or `::`) it will be changed to point to localhost. This is
223 * done to match the behavior of Linux systems.
224 *
225 * The connected signal is emitted on the request when the connection has been
226 * established.
227 * The error signal is emitted on the request in case of errors during the
228 * connection.
229 *
230 * @param addr Initialized `sockaddr_in` or `sockaddr_in6` data structure.
231 * @param req connection request
232 */
233 void Connect(const sockaddr& addr, const std::shared_ptr<TcpConnectReq>& req);
234
235 void Connect(const sockaddr_in& addr,
236 const std::shared_ptr<TcpConnectReq>& req) {
237 Connect(reinterpret_cast<const sockaddr&>(addr), req);
238 }
239
240 void Connect(const sockaddr_in6& addr,
241 const std::shared_ptr<TcpConnectReq>& req) {
242 Connect(reinterpret_cast<const sockaddr&>(addr), req);
243 }
244
245 /**
246 * Establish an IPv4 or IPv6 TCP connection.
247 *
248 * On Windows if the addr is initialized to point to an unspecified address
249 * (`0.0.0.0` or `::`) it will be changed to point to localhost. This is
250 * done to match the behavior of Linux systems.
251 *
252 * The callback is called when the connection has been established. Errors
253 * are reported to the stream error handler.
254 *
255 * @param addr Initialized `sockaddr_in` or `sockaddr_in6` data structure.
256 * @param callback Callback function to call when connection established
257 */
258 void Connect(const sockaddr& addr, std::function<void()> callback);
259
260 void Connect(const sockaddr_in& addr, std::function<void()> callback) {
261 Connect(reinterpret_cast<const sockaddr&>(addr), std::move(callback));
262 }
263
264 void Connect(const sockaddr_in6& addr, std::function<void()> callback) {
265 Connect(reinterpret_cast<const sockaddr&>(addr), std::move(callback));
266 }
267
268 /**
269 * Establish an IPv4 TCP connection.
270 *
271 * On Windows if the addr is initialized to point to an unspecified address
272 * (`0.0.0.0` or `::`) it will be changed to point to localhost. This is
273 * done to match the behavior of Linux systems.
274 *
275 * The connected signal is emitted on the request when the connection has been
276 * established.
277 * The error signal is emitted on the request in case of errors during the
278 * connection.
279 *
280 * @param ip The address to which to connect to.
281 * @param port The port to which to connect to.
282 * @param req connection request
283 */
284 void Connect(std::string_view ip, unsigned int port,
285 const std::shared_ptr<TcpConnectReq>& req);
286
287 /**
288 * Establish an IPv4 TCP connection.
289 *
290 * On Windows if the addr is initialized to point to an unspecified address
291 * (`0.0.0.0` or `::`) it will be changed to point to localhost. This is
292 * done to match the behavior of Linux systems.
293 *
294 * The callback is called when the connection has been established. Errors
295 * are reported to the stream error handler.
296 *
297 * @param ip The address to which to connect to.
298 * @param port The port to which to connect to.
299 * @param callback Callback function to call when connection established
300 */
301 void Connect(std::string_view ip, unsigned int port,
302 std::function<void()> callback);
303
304 /**
305 * Establish an IPv6 TCP connection.
306 *
307 * On Windows if the addr is initialized to point to an unspecified address
308 * (`0.0.0.0` or `::`) it will be changed to point to localhost. This is
309 * done to match the behavior of Linux systems.
310 *
311 * The connected signal is emitted on the request when the connection has been
312 * established.
313 * The error signal is emitted on the request in case of errors during the
314 * connection.
315 *
316 * @param ip The address to which to connect to.
317 * @param port The port to which to connect to.
318 * @param req connection request
319 */
320 void Connect6(std::string_view ip, unsigned int port,
321 const std::shared_ptr<TcpConnectReq>& req);
322
323 /**
324 * Establish an IPv6 TCP connection.
325 *
326 * On Windows if the addr is initialized to point to an unspecified address
327 * (`0.0.0.0` or `::`) it will be changed to point to localhost. This is
328 * done to match the behavior of Linux systems.
329 *
330 * The callback is called when the connection has been established. Errors
331 * are reported to the stream error handler.
332 *
333 * @param ip The address to which to connect to.
334 * @param port The port to which to connect to.
335 * @param callback Callback function to call when connection established
336 */
337 void Connect6(std::string_view ip, unsigned int port,
338 std::function<void()> callback);
339
340 /**
341 * Resets a TCP connection by sending a RST packet. This is accomplished by
342 * setting the SO_LINGER socket option with a linger interval of zero and then
343 * calling Close(). Due to some platform inconsistencies, mixing of
344 * Shutdown() and CloseReset() calls is not allowed.
345 */
347
348 private:
349 Tcp* DoAccept() override;
350
351 struct ReuseData {
352 std::function<void()> callback;
353 unsigned int flags;
354 };
355 std::unique_ptr<ReuseData> m_reuseData;
356};
357
358/**
359 * TCP connection request.
360 */
361class TcpConnectReq : public ConnectReq {
362 public:
363 Tcp& GetStream() const {
364 return *static_cast<Tcp*>(&ConnectReq::GetStream());
365 }
366};
367
368} // namespace wpi::net::uv
NetworkStream & GetStream() const
Definition NetworkStream.hpp:27
bool Invoke(F &&f, Args &&... args) const
Definition Handle.hpp:265
Event loop.
Definition Loop.hpp:35
virtual NetworkStream * DoAccept()=0
std::shared_ptr< NetworkStream > Accept()
Accept incoming connection.
Definition NetworkStream.hpp:90
uv_tcp_t * GetRaw() const noexcept
Definition NetworkStream.hpp:141
NetworkStreamImpl()
Definition NetworkStream.hpp:146
TCP connection request.
Definition Tcp.hpp:361
Tcp & GetStream() const
Definition Tcp.hpp:363
TCP handle.
Definition Tcp.hpp:26
sockaddr_storage GetPeer()
Get the address of the peer connected to the handle.
void Connect(const sockaddr_in6 &addr, const std::shared_ptr< TcpConnectReq > &req)
Definition Tcp.hpp:240
void Bind(const sockaddr &addr, unsigned int flags=0)
Bind the handle to an IPv4 or IPv6 address and port.
Definition Tcp.hpp:162
void Connect6(std::string_view ip, unsigned int port, const std::shared_ptr< TcpConnectReq > &req)
Establish an IPv6 TCP connection.
void Connect(const sockaddr &addr, std::function< void()> callback)
Establish an IPv4 or IPv6 TCP connection.
void Connect(const sockaddr &addr, const std::shared_ptr< TcpConnectReq > &req)
Establish an IPv4 or IPv6 TCP connection.
void Connect6(std::string_view ip, unsigned int port, std::function< void()> callback)
Establish an IPv6 TCP connection.
sockaddr_storage GetSock()
Get the current address to which the handle is bound.
bool SetSimultaneousAccepts(bool enable)
Enable/Disable simultaneous asynchronous accept requests.
Definition Tcp.hpp:147
static std::shared_ptr< Tcp > Create(Loop &loop, unsigned int flags=AF_UNSPEC)
Create a TCP handle.
void Bind(std::string_view ip, unsigned int port, unsigned int flags=0)
Bind the handle to an IPv4 address and port.
bool SetNoDelay(bool enable)
Enable no delay operation (turns off Nagle's algorithm).
Definition Tcp.hpp:119
void Reuse(std::function< void()> callback, unsigned int flags=AF_UNSPEC)
Reuse this handle.
void CloseReset()
Resets a TCP connection by sending a RST packet.
bool Accept(const std::shared_ptr< Tcp > &client)
Accept incoming connection.
Definition Tcp.hpp:100
void Connect(std::string_view ip, unsigned int port, std::function< void()> callback)
Establish an IPv4 TCP connection.
void Open(uv_os_sock_t sock)
Open an existing file descriptor or SOCKET as a TCP handle.
Definition Tcp.hpp:112
void Connect(std::string_view ip, unsigned int port, const std::shared_ptr< TcpConnectReq > &req)
Establish an IPv4 TCP connection.
std::shared_ptr< Tcp > Accept()
Accept incoming connection.
~Tcp() noexcept override=default
void Connect(const sockaddr_in6 &addr, std::function< void()> callback)
Definition Tcp.hpp:264
void Connect(const sockaddr_in &addr, const std::shared_ptr< TcpConnectReq > &req)
Definition Tcp.hpp:235
void Connect(const sockaddr_in &addr, std::function< void()> callback)
Definition Tcp.hpp:260
void Bind(const sockaddr_in &addr, unsigned int flags=0)
Definition Tcp.hpp:166
bool SetKeepAlive(bool enable, Time time=Time{0})
Enable/Disable TCP keep-alive.
Definition Tcp.hpp:128
void Bind6(std::string_view ip, unsigned int port, unsigned int flags=0)
Bind the handle to an IPv6 address and port.
Tcp(const private_init &)
Definition Tcp.hpp:32
void Bind(const sockaddr_in6 &addr, unsigned int flags=0)
Definition Tcp.hpp:170
std::chrono::seconds Time
Definition Tcp.hpp:30
Definition StringMap.hpp:773
Definition Prepare.hpp:14
flags
Definition http_parser.hpp:206
UV_EXTERN int uv_tcp_keepalive(uv_tcp_t *handle, int enable, unsigned int delay)
UV_EXTERN int uv_tcp_open(uv_tcp_t *handle, uv_os_sock_t sock)
UV_EXTERN int uv_tcp_nodelay(uv_tcp_t *handle, int enable)
UV_EXTERN int uv_tcp_bind(uv_tcp_t *handle, const struct sockaddr *addr, unsigned int flags)
UV_EXTERN int uv_tcp_simultaneous_accepts(uv_tcp_t *handle, int enable)