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