Source
stdlib/socket/socket.hpp
1
// Copyright (c) 2026 BigBrain LLC. MIT-licensed (see LICENSE).2
// Original work; see ACKNOWLEDGMENTS.md for the open-source ideas we build upon.3
#pragma once5
/**6
* @file socket.hpp7
* @brief cheatah `socket` — a small wrapper around BSD/POSIX TCP sockets,8
* in the spirit of Python's `socket`. `import socket` to use it.9
*10
* The recommended API is the owning `socket::Conn` / `socket::Listener` guards (from11
* `socket.open(host, port)` / `socket.serve(host, port, backlog)`), which close their fd at12
* scope exit. A **flat, file-descriptor-based** API is also available for hand-built servers:13
* pass the integer fd from `socket()` / `tcp_listen()` / `accept()` to the other calls (an14
* unclosed fd there is a resource leak — prefer the guards). IPv4 + TCP only; host names are15
* resolved with `getaddrinfo` (so `"localhost"`, `"127.0.0.1"`, and DNS names all work).16
* Errors are a negative return (or empty string for `recv`); `last_error()` gives the `errno` text.17
*18
* `import socket` includes this header AND links `libcheatah_socket`. Unit tests:19
* `stdlib/tests/socket_test.cpp`; the suite runs under AddressSanitizer (the20
* `asan` preset) and Valgrind (`security/run-valgrind.sh`) on every QA-gate run.21
*22
* @note Every call is a thin wrapper over one or two syscalls. Only `recv` and23
* `last_error` allocate (their returned `std::string`, plus `recv`'s reused24
* per-thread scratch buffer); the fd/status calls return a `long long` and do25
* not allocate (the resolver's transient `getaddrinfo` list is freed in-call).26
*/27
#include <string>29
namespace cheatah::socket {31
// ---- high-level convenience (what a server/client usually wants) ----33
/**34
* Create a TCP socket bound to @p host:@p port and put it in the listening state (sets35
* `SO_REUSEADDR`).36
*37
* Performs socket()/set_reuseaddr/bind/listen in one shot; on any failure it closes the38
* partially-created socket and returns -1, so the caller never leaks an fd. On success the39
* returned fd is owned by the caller and must be passed to close() when done.40
* @param host interface to bind ("127.0.0.1", "0.0.0.0", …).41
* @param port TCP port (0 = let the OS pick — read it back with local_port()).42
* @param backlog pending-connection queue length.43
* @return the listening fd, or -1 on error.44
* @complexity O(1) + resolution (a few syscalls).45
* @alloc none (the resolver's transient `getaddrinfo` list is freed before returning).46
* @test CheatahSocket.Loopback47
* @crtest SocketCompileRun.TcpListen48
* @systest StdlibE2E.Socket49
*/50
long long tcp_listen(const std::string& host, long long port, long long backlog);52
/**53
* Create a TCP socket and connect it to @p host:@p port.54
*55
* The host is resolved via `getaddrinfo`, so names, "localhost", and dotted IPs all work; the56
* connect blocks until the handshake completes or fails. On failure the socket is closed and57
* -1 is returned; on success the caller owns the connected fd and must close() it.58
* @param host destination host (name or IP).59
* @param port destination port.60
* @return the connected fd, or -1 on error.61
* @complexity O(1) + DNS resolution.62
* @alloc none (the resolver's transient `getaddrinfo` list is freed before returning).63
* @concurrency blocks until the TCP handshake completes or fails.64
* @test CheatahSocket.Loopback65
* @crtest SocketCompileRun.TcpConnect66
* @systest StdlibE2E.Socket67
*/68
long long tcp_connect(const std::string& host, long long port);70
// ---- per-connection I/O ----72
/**73
* Accept one pending connection.74
*75
* Blocks until a client connects, then returns a new fd for that one connection (the listening76
* fd stays open for further accepts). The returned client fd is owned by the caller and must be77
* closed separately; the peer address is discarded.78
* @param fd a listening fd.79
* @return the connected client fd, or -1 on error.80
* @complexity O(1) syscall (blocks until a client arrives).81
* @alloc none.82
* @concurrency blocks the calling thread until a client connects.83
* @test CheatahSocket.Loopback84
* @crtest SocketCompileRun.Accept85
* @systest StdlibE2E.Socket86
*/87
long long accept(long long fd);89
/**90
* Receive up to @p bufsize bytes.91
*92
* Blocks for one `recv` and returns whatever bytes arrive (possibly fewer than @p bufsize); the93
* result is binary-safe, so a returned string may contain embedded NULs and its length is the94
* true byte count. A clean EOF (peer closed) and an error both yield "", so check last_error()95
* to tell them apart; @p bufsize <= 0 also returns "" without touching the socket.96
* @param fd a connected fd.97
* @param bufsize maximum bytes to read.98
* @return the bytes read (binary-safe), or "" on EOF/error.99
* @complexity O(@p bufsize).100
* @alloc allocates the returned string (and grows a reused per-thread scratch buffer101
* up to @p bufsize on first use).102
* @concurrency blocks until data, EOF, or the set_timeout() deadline; a shutdown() from103
* another thread wakes it with EOF.104
* @test CheatahSocket.Loopback105
* @crtest SocketCompileRun.Recv106
* @systest StdlibE2E.Socket107
*/108
std::string recv(long long fd, long long bufsize);110
/**111
* Send some of @p data (one `send`).112
*113
* Issues a single `send`, which may transmit fewer bytes than supplied (a partial send); the114
* caller is responsible for re-sending the remainder, or use sendall() to loop automatically.115
* @param fd a connected fd.116
* @param data bytes to send.117
* @return bytes actually sent, or -1 on error.118
* @complexity O(n).119
* @alloc none (`MSG_NOSIGNAL`, so a broken pipe never raises `SIGPIPE`).120
* @test CheatahSocket.Sendall121
* @crtest SocketCompileRun.Send122
* @systest StdlibE2E.Socket123
*/124
long long send(long long fd, const std::string& data);126
/**127
* Send @p data in full, looping until all bytes are written.128
*129
* Repeatedly calls `send` on the unsent remainder until every byte is written, so unlike send()130
* there are no partial sends to handle; it aborts with -1 the moment a `send` returns <= 0131
* (error or peer hang-up), in which case some bytes may already have been transmitted.132
* @param fd a connected fd.133
* @param data bytes to send.134
* @return 0 on success, -1 on error.135
* @complexity O(n).136
* @alloc none.137
* @concurrency may block while the peer's receive window is full; bounded per `send`138
* by the set_timeout() send deadline.139
* @test CheatahSocket.Sendall140
* @crtest SocketCompileRun.Sendall141
* @systest StdlibE2E.Socket142
*/143
long long sendall(long long fd, const std::string& data);145
/**146
* Close a socket.147
*148
* Releases the fd back to the OS; after this the fd is invalid and must not be reused. Closing an149
* already-closed or never-opened fd fails with -1 (EBADF), which is how the BadFd test exercises150
* the error path.151
* @param fd the fd to close.152
* @return 0 on success, -1 on error.153
* @complexity O(1) syscall.154
* @alloc none.155
* @test CheatahSocket.BadFd156
* @crtest SocketCompileRun.Close157
* @systest StdlibE2E.Socket158
*/159
long long close(long long fd);161
/**162
* Half-close @p fd in both directions (::shutdown SHUT_RDWR) WITHOUT releasing it.163
* A blocking recv() on another thread returns immediately (EOF) — the safe way to164
* wake a reader for a clean shutdown. The fd is still owned by the caller and must165
* be close()d afterwards.166
* @param fd the fd to half-close.167
* @return 0 on success, -1 on error.168
* @complexity O(1) syscall.169
* @alloc none.170
* @concurrency safe to call from another thread while a recv() on @p fd blocks — waking171
* that reader is exactly what it is for.172
* @test CheatahSocket.TimeoutThenShutdown173
*/174
long long shutdown(long long fd);176
// ---- low-level BSD primitives (for clients/servers built by hand) ----178
/**179
* Create an IPv4 TCP socket.180
*181
* Allocates an unbound, unconnected AF_INET/SOCK_STREAM fd; you must follow up with bind()+listen()182
* or connect() before it can carry data, and close() it when done.183
* @return the new fd, or -1 on error.184
* @complexity O(1).185
* @alloc none.186
* @test CheatahSocket.ListenLowLevel187
* @crtest SocketCompileRun.Socket188
* @systest StdlibE2E.Socket189
*/190
long long socket();192
/**193
* Enable `SO_REUSEADDR` on @p fd.194
*195
* Lets a subsequent bind() reuse a local address still lingering in TIME_WAIT, so a restarted196
* server can re-listen on the same port immediately; call it before bind().197
* @warning `SO_REUSEADDR` trades TIME_WAIT protection for restartability: by skipping the198
* kernel's cooldown, delayed segments from a previous connection on the same199
* address can in principle reach the new socket.200
* @param fd the socket.201
* @return 0 on success, -1 on error.202
* @complexity O(1).203
* @alloc none.204
* @test CheatahSocket.ListenLowLevel205
* @crtest SocketCompileRun.SetReuseaddr206
* @systest StdlibE2E.Socket207
*/208
long long set_reuseaddr(long long fd);210
/**211
* Bind @p fd to @p host:@p port.212
*213
* Resolves @p host via `getaddrinfo` and assigns the resulting local address to the socket; a214
* resolution failure returns -1 with errno set to EADDRNOTAVAIL (see the ResolveFailure test).215
* @param fd the socket.216
* @param host interface to bind.217
* @param port TCP port (0 = OS-assigned).218
* @return 0 on success, -1 on error.219
* @complexity O(1) + resolution.220
* @alloc none (the resolver's transient `getaddrinfo` list is freed before returning).221
* @test CheatahSocket.ListenLowLevel, CheatahSocket.ResolveFailure222
* @crtest SocketCompileRun.Bind223
* @systest StdlibE2E.Socket224
*/225
long long bind(long long fd, const std::string& host, long long port);227
/**228
* Mark @p fd as a passive (listening) socket.229
*230
* Switches an already-bound socket into the listening state so accept() can pull connections from231
* it; @p backlog caps how many fully-established connections may queue before new ones are refused.232
* @param fd the socket.233
* @param backlog queue length.234
* @return 0 on success, -1 on error.235
* @complexity O(1).236
* @alloc none.237
* @test CheatahSocket.ListenLowLevel238
* @crtest SocketCompileRun.Listen239
* @systest StdlibE2E.Socket240
*/241
long long listen(long long fd, long long backlog);243
/**244
* Connect @p fd to @p host:@p port.245
*246
* Resolves @p host and blocks until the TCP handshake succeeds or fails; a refused connection247
* returns -1 with errno ECONNREFUSED (see the ConnectRefused test). Unlike tcp_connect() it does248
* not close the fd on failure — the caller still owns @p fd.249
* @param fd the socket.250
* @param host destination.251
* @param port destination port.252
* @return 0 on success, -1 on error.253
* @complexity O(1) + DNS.254
* @alloc none (the resolver's transient `getaddrinfo` list is freed before returning).255
* @concurrency blocks until the TCP handshake completes or fails.256
* @test CheatahSocket.ConnectRefused257
* @crtest SocketCompileRun.Connect258
* @systest StdlibE2E.Socket259
*/260
long long connect(long long fd, const std::string& host, long long port);262
/**263
* The local TCP port @p fd is bound to (useful after binding to port 0).264
*265
* Reads the address actually assigned via `getsockname` and returns its port in host byte order;266
* this is the way to discover the ephemeral port the OS chose when you bound to port 0.267
* @param fd a bound socket.268
* @return the port, or -1 on error.269
* @complexity O(1) syscall.270
* @alloc none.271
* @test CheatahSocket.Loopback272
* @crtest SocketCompileRun.LocalPort273
* @systest StdlibE2E.Socket274
*/275
long long local_port(long long fd);277
/**278
* Bound both blocking directions of @p fd by @p timeout_ms (SO_RCVTIMEO + SO_SNDTIMEO), so a279
* silent peer cannot hang a recv/send forever. A recv that times out returns "" (check280
* last_error() to distinguish from EOF). @p timeout_ms <= 0 clears the timeouts (block forever).281
*282
* @param fd a socket.283
* @param timeout_ms the per-operation bound in milliseconds.284
* @return 0 on success, -1 on error.285
* @complexity O(1) (two setsockopt calls).286
* @alloc none.287
* @test CheatahSocket.TimeoutThenShutdown288
*/289
long long set_timeout(long long fd, long long timeout_ms);291
/**292
* @brief A UDP socket — the DATAGRAM face beside the stream one. Unbound until @ref bind; a293
* client that only sends needs no bind (the kernel picks a port on the first @ref sendto).294
*295
* What a datagram is for: data whose NEXT packet supersedes this one — a presence pose, a live296
* drag, a simulation snapshot. It may be dropped, duplicated or reordered by the network and the297
* receiver must be written for that (newest-wins by stamp); nothing here acks, retries or orders.298
* Everything that must arrive rides TCP (@ref tcp_connect).299
*300
* @return the socket fd, or -1 (@ref last_error says why).301
* @complexity O(1).302
* @alloc none.303
* @test CheatahSocket.UdpLoopback304
* @crtest SocketCompileRun.UdpLoopback305
* @systest StdlibE2E.Socket306
*/307
long long udp_socket();309
/**310
* @brief Send one datagram to @p host:@p port (an IPv4 literal or a name; resolved per call, so311
* cache the address yourself on a hot path). The whole of @p data is one packet: keep it312
* under the path MTU (1200 bytes is safe on the public internet, 65507 the absolute cap).313
* @param fd a socket from @ref udp_socket.314
* @param host destination host.315
* @param port destination port.316
* @param data the packet.317
* @return bytes sent (== data.size()), or -1.318
* @complexity O(len) + the kernel's copy.319
* @alloc none (the resolve is on the stack).320
* @test CheatahSocket.UdpLoopback321
* @crtest SocketCompileRun.UdpLoopback322
* @systest StdlibE2E.Socket323
*/324
long long sendto(long long fd, const std::string& host, long long port, const std::string& data);326
/**327
* @brief Receive one datagram: at most @p bufsize bytes of it (the rest of a larger packet is328
* DISCARDED — the datagram contract), with the sender's address in @p out_host / @p out_port.329
* Blocks until a packet arrives, or until @ref set_timeout's window passes (an empty string,330
* @p out_port 0).331
* @param fd a socket from @ref udp_socket, bound with @ref bind.332
* @param bufsize the most bytes to take.333
* @param out_host the sender's address, dotted (empty on timeout/error).334
* @param out_port the sender's port (0 on timeout/error).335
* @return the packet's bytes, or empty.336
* @complexity O(bufsize) worst case.337
* @alloc the returned string (the receive buffer is a reused per-thread scratch).338
* @test CheatahSocket.UdpLoopback339
* @crtest SocketCompileRun.UdpLoopback340
* @systest StdlibE2E.Socket341
*/342
std::string recvfrom(long long fd, long long bufsize, std::string& out_host, long long& out_port);344
/**345
* The message for the current `errno`.346
*347
* Returns the human-readable text for the thread's current `errno`; call it right after a function348
* reports failure (a -1 return, or "" from recv), since any later syscall may overwrite `errno`.349
* @return `strerror(errno)`.350
* @complexity O(1).351
* @alloc allocates the returned string.352
* @test CheatahSocket.ConnectRefused353
* @crtest SocketCompileRun.LastError354
* @systest StdlibE2E.Socket355
*/356
std::string last_error();358
// ---- owning RAII connections (the `with`-friendly, leak-proof API) ----360
/**361
* @brief An owning TCP connection — a socket fd whose destructor closes it.362
*363
* The RAII counterpart to the fd-based calls above, and the C++/cheatah analog of a364
* Python socket used in a `with` block. A `Conn` owns exactly one fd; when it is365
* destroyed (scope exit, including a `return`/`break`/exception out of a `with` body)366
* or explicitly close()d, the fd is released — so a connection opened with367
* `with socket.open(host, port) as c { … }` cannot leak. Move-only: copying would give368
* two owners of one fd and double-close it, so the copy operations are deleted and a369
* moved-from `Conn` is left closed.370
*/371
class Conn {372
public:373
/**374
* Construct a closed connection (owns no fd).375
* @complexity O(1).376
* @alloc none.377
* @test CheatahSocket.ConnDefaultIsClosed378
*/379
Conn() = default;380
/**381
* Adopt an already-connected fd (e.g. from tcp_connect()/accept()); the `Conn` now owns it.382
* @param fd a connected fd to take ownership of (-1 for a closed connection).383
* @complexity O(1).384
* @alloc none.385
* @test CheatahSocket.ConnGuardClosesOnScopeExit386
*/387
explicit Conn(long long fd) : fd_(fd) {}388
Conn(const Conn&) = delete;389
Conn& operator=(const Conn&) = delete;390
/**391
* Move-construct, taking over @p other's fd (the moved-from `Conn` becomes closed).392
* @param other the connection to move from.393
* @complexity O(1).394
* @alloc none.395
* @test CheatahSocket.ConnMoveTransfersOwnership396
*/397
Conn(Conn&& other) noexcept : fd_(other.fd_) { other.fd_ = -1; }398
/**399
* Move-assign, closing this fd first, then taking over @p other's (which becomes closed).400
* @param other the connection to move from.401
* @return reference to this connection.402
* @complexity O(1).403
* @alloc none.404
* @test CheatahSocket.ConnMoveTransfersOwnership405
*/406
Conn& operator=(Conn&& other) noexcept;407
/**408
* Close the fd if still open.409
* @complexity O(1) syscall.410
* @alloc none.411
* @test CheatahSocket.ConnGuardClosesOnScopeExit412
*/413
~Conn();415
/**416
* Is a connection open?417
* @return true iff this owns an open fd.418
* @complexity O(1).419
* @alloc none.420
* @test CheatahSocket.ConnDefaultIsClosed421
*/422
bool is_open() const { return fd_ >= 0; }423
/**424
* The raw fd, for the low-level calls or to hand to tls.open(conn.fd(), …).425
* @return the owned fd, or -1 when closed.426
* @complexity O(1).427
* @alloc none.428
* @test CheatahSocket.ConnGuardClosesOnScopeExit429
*/430
long long fd() const { return fd_; }431
/**432
* Send some of @p data (one send(); see the free send()).433
* @param data bytes to send.434
* @return bytes actually sent, or -1 on error.435
* @complexity O(n).436
* @alloc none.437
* @test CheatahSocket.ConnLoopback438
*/439
long long send(const std::string& data) const;440
/**441
* Send @p data in full, looping until every byte is written (see the free sendall()).442
* @param data bytes to send.443
* @return 0 on success, -1 on error.444
* @complexity O(n).445
* @alloc none.446
* @test CheatahSocket.ConnLoopback447
*/448
long long sendall(const std::string& data) const;449
/**450
* Receive up to @p bufsize bytes (see the free recv()).451
* @param bufsize maximum bytes to read.452
* @return the bytes read (binary-safe), or "" on EOF/error.453
* @complexity O(@p bufsize).454
* @alloc allocates the returned string (plus the free recv()'s reused per-thread455
* scratch buffer on growth).456
* @concurrency blocks until data, EOF, or the set_timeout() deadline.457
* @test CheatahSocket.ConnLoopback458
*/459
std::string recv(long long bufsize) const;460
/**461
* Bound both blocking directions by @p timeout_ms (see the free set_timeout()).462
* @param timeout_ms per-operation bound in milliseconds (<= 0 clears it).463
* @return 0 on success, -1 on error.464
* @complexity O(1).465
* @alloc none.466
* @test CheatahSocket.ConnLoopback467
*/468
long long set_timeout(long long timeout_ms) const;469
/**470
* The local TCP port this fd is bound to (see the free local_port()).471
* @return the port, or -1 on error.472
* @complexity O(1) syscall.473
* @alloc none.474
* @test CheatahSocket.ConnLoopback475
*/476
long long local_port() const;477
/**478
* Half-close both directions WITHOUT releasing the fd (see the free shutdown()) — wakes a479
* blocked reader for a clean shutdown; still call close() (or let the destructor) afterward.480
* @return 0 on success, -1 on error.481
* @complexity O(1) syscall.482
* @alloc none.483
* @test CheatahSocket.ConnLoopback484
*/485
long long shutdown() const;486
/**487
* Close the fd now (idempotent — the destructor will not close it again).488
* @return 0 on success, -1 if already closed or on error.489
* @complexity O(1) syscall.490
* @alloc none.491
* @test CheatahSocket.ConnGuardClosesOnScopeExit492
*/493
long long close();495
private:496
long long fd_ = -1;497
};499
/**500
* @brief An owning listening socket; accept() yields owning Conn clients; the destructor closes it.501
*502
* The server-side RAII guard: `with socket.serve(host, port, backlog) as server { … }` keeps the503
* listening fd for the block and closes it on exit. Each accept() returns an owning Conn, so a504
* whole server loop leaks neither the listener nor its clients. Move-only, like Conn.505
*/506
class Listener {507
public:508
/**509
* Construct a closed listener (owns no fd).510
* @complexity O(1).511
* @alloc none.512
* @test CheatahSocket.ListenerDefaultIsClosed513
*/514
Listener() = default;515
/**516
* Adopt an already-listening fd (e.g. from tcp_listen()); the `Listener` now owns it.517
* @param fd a listening fd to take ownership of (-1 for a closed listener).518
* @complexity O(1).519
* @alloc none.520
* @test CheatahSocket.ListenerLoopback521
*/522
explicit Listener(long long fd) : fd_(fd) {}523
Listener(const Listener&) = delete;524
Listener& operator=(const Listener&) = delete;525
/**526
* Move-construct, taking over @p other's fd (the moved-from `Listener` becomes closed).527
* @param other the listener to move from.528
* @complexity O(1).529
* @alloc none.530
* @test CheatahSocket.ListenerLoopback531
*/532
Listener(Listener&& other) noexcept : fd_(other.fd_) { other.fd_ = -1; }533
/**534
* Move-assign, closing this fd first, then taking over @p other's (which becomes closed).535
* @param other the listener to move from.536
* @return reference to this listener.537
* @complexity O(1).538
* @alloc none.539
* @test CheatahSocket.ListenerLoopback540
*/541
Listener& operator=(Listener&& other) noexcept;542
/**543
* Close the listening fd if still open.544
* @complexity O(1) syscall.545
* @alloc none.546
* @test CheatahSocket.ListenerLoopback547
*/548
~Listener();550
/**551
* Is the listener open?552
* @return true iff this owns an open listening fd.553
* @complexity O(1).554
* @alloc none.555
* @test CheatahSocket.ListenerDefaultIsClosed556
*/557
bool is_open() const { return fd_ >= 0; }558
/**559
* The raw listening fd.560
* @return the owned fd, or -1 when closed.561
* @complexity O(1).562
* @alloc none.563
* @test CheatahSocket.ListenerLoopback564
*/565
long long fd() const { return fd_; }566
/**567
* Accept one pending connection, returned as an owning Conn (the listener stays open).568
* @return an owning Conn for the client (its is_open() is false on error).569
* @complexity O(1) syscall (blocks until a client arrives).570
* @alloc none.571
* @concurrency blocks the calling thread until a client connects.572
* @test CheatahSocket.ConnLoopback573
*/574
Conn accept() const;575
/**576
* The local TCP port this listener is bound to (useful after binding to port 0).577
* @return the port, or -1 on error.578
* @complexity O(1) syscall.579
* @alloc none.580
* @test CheatahSocket.ListenerLoopback581
*/582
long long local_port() const;583
/**584
* Close the listening fd now (idempotent — the destructor will not close it again).585
* @return 0 on success, -1 if already closed or on error.586
* @complexity O(1) syscall.587
* @alloc none.588
* @test CheatahSocket.ListenerLoopback589
*/590
long long close();592
private:593
long long fd_ = -1;594
};596
/**597
* Open a client TCP connection to @p host:@p port and return it as an owning Conn (the598
* RAII, `with`-friendly form of tcp_connect()).599
* @param host destination host (name or IP).600
* @param port destination port.601
* @return an owning Conn; on failure its is_open() is false (see last_error()).602
* @complexity O(1) + DNS resolution.603
* @alloc none beyond the Conn itself.604
* @concurrency blocks until the TCP handshake completes or fails.605
* @test CheatahSocket.ConnLoopback606
*/607
Conn open(const std::string& host, long long port);609
/**610
* Create a listening server socket bound to @p host:@p port and return it as an owning611
* Listener (the RAII, `with`-friendly form of tcp_listen()).612
* @param host interface to bind ("127.0.0.1", "0.0.0.0", …).613
* @param port TCP port (0 = let the OS pick — read it back with Listener::local_port()).614
* @param backlog pending-connection queue length.615
* @return an owning Listener; on failure its is_open() is false (see last_error()).616
* @complexity O(1) + resolution (a few syscalls).617
* @alloc none beyond the Listener itself.618
* @test CheatahSocket.ListenerLoopback619
*/620
Listener serve(const std::string& host, long long port, long long backlog);622
} // namespace cheatah::socket