group2 0.1.0
CSE 125 Group 2
Loading...
Searching...
No Matches
Server.hpp
Go to the documentation of this file.
1
3
4#pragma once
5
16#include "network/ShotEvent.hpp"
22
23#include <SDL3/SDL_stdinc.h>
24
25#include <SDL3_net/SDL_net.h>
26#include <atomic>
27#include <deque>
28#include <entt/entity/entity.hpp>
29#include <memory>
30#include <mutex>
31#include <shared_mutex>
32#include <span>
33#include <string_view>
34#include <thread>
35#include <vector>
36
41class Server
42{
43public:
51 bool init(const char* addr,
52 Uint16 port,
53 const TransportConfig& transport = {},
54 const GlobalDiscoveryConfig& discovery = {});
55
57 void shutdown();
58
65 void poll() {}
66
69 bool isEmpty();
70
74
81 void drainEvents(std::vector<Event>& out);
82
85 bool notifyPlayerClientId(ClientId clientId, entt::entity playerEntity);
86
88 void broadcastRegistry(const Registry& registry);
89
91 void broadcastParticleEvents(const std::vector<NetParticleEvent>& events);
92
94 void broadcastLobbyUpdate(const LobbyUpdateEvent& event);
95
98 int getClientCount();
99
101 uint32_t globalDirectoryServerId() const noexcept;
102
109 uint16_t getClientRttMs(ClientId clientId);
110
126 {
128 uint16_t rttMs;
134 };
135 void snapshotClientNetStates(std::vector<ClientNetState>& out);
136
139
142
144 void broadcastKillEvents(const std::vector<NetKillEvent>& events);
145
147 void broadcastTextChat(ClientId sender, std::string_view message);
148
150 bool sendVoiceFrameToClient(ClientId recipient,
151 ClientId speaker,
152 std::uint16_t sequence,
153 std::uint8_t frameMs,
154 std::span<const std::uint8_t> opus);
155
157 bool sendVoiceFrameToClients(std::span<const ClientId> recipients,
158 ClientId speaker,
159 std::uint16_t sequence,
160 std::uint8_t frameMs,
161 std::span<const std::uint8_t> opus);
162
168 bool sendToClient(const ClientId& clientId, const void* data, int len);
169
172 bool sendLobbyStateToClient(ClientId clientId, const std::vector<LobbyPlayer>& players);
173
175 bool sendMatchConfigToClient(ClientId clientId, const MatchConfig& config);
176
181 void broadcastRosterEventExcept(ClientId excluded, const PlayerRosterEvent& event);
182
184 void setMaxPlayers(int maxPlayers);
185
187 void setAdvertiseServer(bool enabled);
188
197 void flushAllOutbound();
198
200 using ClientConnectedCallback = std::function<void(ClientId)>;
202 using ClientDisconnectedCallback = std::function<void(ClientId)>;
207
210 uint16_t listeningPort() const;
211
212 void broadcastMatchConfig(const MatchConfig& config);
213
214private:
217
225 {
229
237
247
255 std::uint64_t connectionId = 0;
256
263
269
275
287 {
288 uint16_t sequence;
290 std::shared_ptr<const std::vector<uint8_t>> framed;
291 };
292 std::deque<PendingReliableEvent> reliableQueue;
293
304 uint16_t lastReportedRttMs = 0;
305
329
344
346 std::uint8_t chatMessagesInWindow = 0;
348 std::uint8_t voiceFramesInWindow = 0;
349 };
350
355 void handleMessage(Connection& client, const void* data, Uint32 len);
356
360
372 void disconnectClient(Connection& conn);
373
375 void readClients();
376
379
384 bool enqueueTo(const ClientId& clientId, uint8_t replaceKey, const void* data, int len);
385
388 void enqueueBroadcast(uint8_t replaceKey, const void* data, int len);
389
399 void enqueueReliableEvent(const void* data, int len);
400
405 void enqueueReliableEventExcept(std::span<const ClientId> excluded, const void* data, int len);
406
415 void networkLoop();
416
424 void
425 handleUdpUnreliable(std::uint64_t connId, const net::UdpEndpointAddr& from, const uint8_t* payload, uint32_t len);
426 void
427 handleSessionPayload(std::uint64_t connId, net::ChannelId channel, const std::uint8_t* payload, std::uint32_t len);
428 void handleVoiceFrame(Connection& conn, const std::uint8_t* payload, std::uint32_t len);
429 void handleDirectoryEvent(const std::vector<std::uint8_t>& payload, const net::UdpEndpointAddr& from);
430 void sendDirectoryHeartbeat(Uint64 nowMs);
431
432 NET_Server* server = nullptr;
433
434 std::unordered_map<ClientId, Connection> clients;
436
438
439 // ── Phase 3d: UDP sidecar ─────────────────────────────────────────────
440 //
441 // Bound during init() to the same port as the TCP listener (different
442 // protocol = different socket; OS demuxes). The network thread polls
443 // both. Server-assigned 32-bit connection IDs let us match an
444 // incoming UDP datagram to a TCP-established Connection — the IDs
445 // are minted on TCP accept and shipped to the client in the
446 // ASSIGN_CLIENT_ID packet so it can stamp them on outbound UDP.
452 std::atomic<std::uint32_t> directoryServerId_{0};
454 std::uint32_t nextChatServerSeq_ = 0;
455 std::atomic<int> maxPlayers_{128};
456 std::atomic<bool> advertiseServer_{true};
457 bool usingUdpSession_ = false;
458 Uint16 listenPort_ = 0;
459 std::unordered_map<std::uint64_t, ClientId> connIdToClient_;
460
461 // ── Stage 3b: dedicated network thread ────────────────────────────────
462 //
463 // The mutex protects every member above (clients map, eventQueue,
464 // nextClientId, NET_Server*) — both the game thread (enqueueTo /
465 // enqueueBroadcast / dequeueEvent / notifyPlayerClientId) and the
466 // network thread (acceptClients / readClients / flushAllOutbound) hold
467 // it during state mutation. Lock holds are kept short (one phase at a
468 // time) so the game thread isn't starved.
469 // PR-6 (server-perf): shared_mutex so read-mostly paths
470 // (enqueueBroadcast iterating clients, flushAllOutbound's phase 1
471 // snapshot, readClients's per-client poll, UDP receive) can take
472 // shared locks and run concurrently. Writers (acceptClients,
473 // disconnect-application, reliable-queue mutation) take unique.
474 std::shared_mutex stateMutex_;
475 std::thread networkThread_;
476 std::atomic<bool> shouldStop_{false};
477
478 // ── PR-2 (server-perf): deferred snapshot fanout ──────────────────────
479 //
480 // `broadcastRegistry` no longer does the per-client send loop on the
481 // game thread. Instead it serializes the snapshot once, wraps the
482 // bytes in `shared_ptr<const ...>`, and stores both the unframed
483 // payload (for the UDP path's per-fragment send loop) and the
484 // length-prefixed framed bytes (for the TCP fallback's enqueue) in
485 // these slots. The network thread picks them up at the start of its
486 // next cycle and runs the fanout there.
487 //
488 // Why two buffers: the UDP path expects the raw payload (the
489 // PacketHeader is added per-fragment); the TCP path expects the
490 // 4-byte length prefix already prepended (it goes straight into
491 // OutboundQueue → NET_WriteToStreamSocket). Pre-PR-2 the framing was
492 // done per client; now it's once per snapshot and shared.
493 //
494 // Both pointers protected by stateMutex_; the network thread
495 // exchanges to nullptr atomically under the lock so a fresh snapshot
496 // arriving mid-cycle replaces the old one without races.
497 std::shared_ptr<const std::vector<uint8_t>> pendingSnapshotPayload_;
498 std::shared_ptr<const std::vector<uint8_t>> pendingSnapshotFramed_;
499
500 // ── PR-10 (server-perf): snapshot delta encoding state ────────────────
501 //
502 // `prevSnapshotRaw_` is the *unprefixed* `registry_serialization::
503 // serialize()` output from the previous broadcastRegistry call —
504 // i.e. NOT the wire-prefixed form, just the entt-snapshot bytes.
505 // We diff the next call's serialize() against this; if the patch
506 // is at least 25% smaller than a full payload AND the size matches
507 // (entity count unchanged), we ship a DELTA packet referencing
508 // `prevSnapshotTick_`. Clients drop the DELTA if their last-applied
509 // tick != `prevSnapshotTick_` — they wait for the next FULL.
510 //
511 // `snapshotCounter_` increments each broadcastRegistry call. Every
512 // `k_keyframeInterval`-th call is forced to FULL regardless of
513 // delta size, so clients that fell behind one delta still resync
514 // within ≤ 500 ms (at 32 Hz × 16 = 500 ms).
515 //
516 // PR-14 (loss resilience): `keyframeRaw_` / `keyframeTick_` now
517 // hold the most recent FULL keyframe, NOT the immediately previous
518 // snapshot. Every delta within a keyframe window is encoded
519 // against the same fixed baseline, so a single dropped delta no
520 // longer cascades — the next-arriving delta still decodes against
521 // the keyframe the client holds. The keyframe is replaced only
522 // when a new FULL is sent (forced by `k_keyframeInterval` or
523 // size-change fallback). `snapshotCounter_` tracks the absolute
524 // snapshot number for tick stamping and keyframe scheduling.
525 //
526 // All three fields are touched only on the game thread inside
527 // broadcastRegistry — no synchronisation needed.
528 std::vector<uint8_t> keyframeRaw_;
529 std::uint32_t keyframeTick_ = 0;
530 std::uint32_t snapshotCounter_ = 0;
531
532 // ── PR-4 (server-perf): atomic-published read snapshots ───────────────
533 //
534 // Pre-PR-4 the game-thread query path (snapshotClientRtts,
535 // getClientCount, broadcastMatchStatus's getClientCount) acquired
536 // `stateMutex_` once per call and competed with the network thread's
537 // long-running readClients() pass. At 200+ bots that lock-wait was
538 // the dominant tick-time spike (50 ms p99 on lagcompTargets, 25 ms
539 // on match) — see §9 of docs/server-perf-design.md.
540 //
541 // PR-4 publishes both a per-client RTT snapshot and a client-count
542 // gauge atomically from the network thread. The game thread reads
543 // them lock-free. Trade-offs:
544 // - Snapshot is at most one network-thread cycle (~1 ms) stale.
545 // For lag-comp's RTT/2 rewind window that's negligible.
546 // - PR-30 (cross-platform): we use the C++11 free-function API
547 // `std::atomic_load_explicit(&shared_ptr, …)` /
548 // `std::atomic_store_explicit(&shared_ptr, …)` rather than the
549 // C++20 `std::atomic<std::shared_ptr<T>>` partial specialization.
550 // Reason: libstdc++ 12+ ships the C++20 specialization, but
551 // Apple's libc++ (through Xcode 16 / libc++ 19) does NOT.
552 // The free-function API is deprecated in C++20 but remains
553 // available through C++23 across all stdlibs we ship to, and
554 // lowers to the same lock-free atomic ops on x86/ARM. Local
555 // pragma suppression in `Server.cpp` silences the deprecation
556 // warnings at the call sites.
563 {
564 std::vector<ClientNetState> entries;
565 };
566 std::shared_ptr<const ClientRttSnapshot> rttSnapshotAtomic_;
567 std::atomic<std::uint32_t> clientCountAtomic_{0};
568};
Bounded text-chat packet helpers shared by client, server, and tests.
Network client identifier component for multiplayer entities.
Thread-safe event queue for passing network events to the game loop.
Shared lobby data types exchanged between server and clients.
Shared definitions for match status and state synchronization between server and clients.
Length-prefixed message framing layer over a TCP stream socket.
Network configuration loaded from config.toml at startup.
Per-client outbound message queue with replace-on-stale semantics.
Player status manager for things like life state and healing.
Shared ECS registry type alias for the game engine.
entt::registry Registry
Shared ECS registry type alias.
Definition Registry.hpp:11
Wire-format particle effect event broadcast from server to all clients.
Thin wrapper over SDL3_net's NET_DatagramSocket.
UDP-first session transport with handshake, reliability, and relay routing.
Bounded Opus voice-frame packet helpers.
Thread-safe FIFO queue of gameplay events awaiting processing each tick.
Definition EventQueue.hpp:23
A single gameplay event produced by network input processing.
Definition Event.hpp:47
Length-prefixed framing layer over a TCP stream socket.
Definition MessageStream.hpp:29
Per-connection outbound message queue.
Definition OutboundQueue.hpp:85
TCP stream socket — receives client packets and echoes them back.
Definition Server.hpp:42
void broadcastParticleEvents(const std::vector< NetParticleEvent > &events)
Broadcast particle events to all clients for effect replication.
Definition Server.cpp:1687
ClientId acceptClients()
Accept up to one new client connection per call.
Definition Server.cpp:1127
void broadcastTextChat(ClientId sender, std::string_view message)
Broadcast a sanitized all-chat message from one client.
Definition Server.cpp:1818
net::UdpEndpointAddr directoryAddr_
Definition Server.hpp:451
bool isEmpty()
Check whether the event queue is empty.
Definition Server.cpp:1497
std::vector< uint8_t > keyframeRaw_
Definition Server.hpp:528
void broadcastMatchConfig(const MatchConfig &config)
Definition Server.cpp:1918
bool sendVoiceFrameToClient(ClientId recipient, ClientId speaker, std::uint16_t sequence, std::uint8_t frameMs, std::span< const std::uint8_t > opus)
Send one proximity-routed voice frame to a specific listener.
Definition Server.cpp:1826
std::uint32_t nextChatServerSeq_
Definition Server.hpp:454
Event dequeueEvent()
Remove and return the next event from the queue.
Definition Server.cpp:1505
void handleMessage(Connection &client, const void *data, Uint32 len)
Dispatch a single decoded message from a client.
Definition Server.cpp:1257
std::shared_ptr< const std::vector< uint8_t > > pendingSnapshotPayload_
Definition Server.hpp:497
std::atomic< std::uint32_t > clientCountAtomic_
Definition Server.hpp:567
bool sendMatchConfigToClient(ClientId clientId, const MatchConfig &config)
Unicast the current match settings to a single client.
Definition Server.cpp:1926
ClientId getNextClientId()
Generate next unique client ID.
Definition Server.cpp:1490
bool sendLobbyStateToClient(ClientId clientId, const std::vector< LobbyPlayer > &players)
Unicast a full lobby snapshot to a single client.
Definition Server.cpp:1865
void disconnectClient(Connection &conn)
Disconnect a client and clean up resources.
Definition Server.cpp:1179
void shutdown()
Close the socket and release resources.
Definition Server.cpp:160
std::shared_mutex stateMutex_
Definition Server.hpp:474
void readClients()
Read and process pending messages from all connected clients.
Definition Server.cpp:1192
std::uint32_t keyframeTick_
Definition Server.hpp:529
bool sendToClient(const ClientId &clientId, const void *data, int len)
PR-20: unicast a serialized SHOT_DEBUG_REPORT (or any other already-framed payload) to a single clien...
Definition Server.cpp:1784
uint16_t listeningPort() const
Get the actual port the server is listening on.
Definition Server.cpp:1913
net::UdpEndpoint udpEndpoint_
Definition Server.hpp:447
std::atomic< bool > advertiseServer_
Runtime global-directory heartbeat toggle.
Definition Server.hpp:456
void handleDirectoryEvent(const std::vector< std::uint8_t > &payload, const net::UdpEndpointAddr &from)
Definition Server.cpp:686
std::atomic< int > maxPlayers_
Definition Server.hpp:455
net::UdpSessionTransport session_
Definition Server.hpp:448
void broadcastRosterEventExcept(ClientId excluded, const PlayerRosterEvent &event)
Broadcast an in-match join/leave event to all clients except excluded.
Definition Server.cpp:1934
void resetAppliedInputTicks()
Reset per-connection input deduplication for a new match session.
Definition Server.cpp:1775
void broadcastLobbyUpdate(const LobbyUpdateEvent &event)
Broadcast lobby status updates to clients.
Definition Server.cpp:1884
std::unordered_map< std::uint64_t, ClientId > connIdToClient_
UDP connection-id → ClientId lookup.
Definition Server.hpp:459
bool init(const char *addr, Uint16 port, const TransportConfig &transport={}, const GlobalDiscoveryConfig &discovery={})
Bind a TCP socket to the given address and port.
Definition Server.cpp:60
ClientConnectedCallback clientConnectedFn_
Fired by acceptClients() when a new client is accepted.
Definition Server.hpp:215
std::unordered_map< ClientId, Connection > clients
Currently connected clients.
Definition Server.hpp:434
void broadcastKillEvents(const std::vector< NetKillEvent > &events)
Broadcast kill events to clients for kill feed updates.
Definition Server.cpp:1798
void snapshotClientNetStates(std::vector< ClientNetState > &out)
Definition Server.cpp:1731
std::function< void(ClientId)> ClientDisconnectedCallback
Invoked on the network thread immediately after a client is disconnected.
Definition Server.hpp:202
Uint16 listenPort_
Definition Server.hpp:458
std::atomic< bool > shouldStop_
Definition Server.hpp:476
std::thread networkThread_
Definition Server.hpp:475
void enqueueReliableEventExcept(std::span< const ClientId > excluded, const void *data, int len)
Enqueue reliable event for all clients except those in excluded.
Definition Server.cpp:412
void handleSessionPayload(std::uint64_t connId, net::ChannelId channel, const std::uint8_t *payload, std::uint32_t len)
Definition Server.cpp:618
uint16_t getClientRttMs(ClientId clientId)
Phase 6: get this client's most-recently-reported smoothed RTT.
Definition Server.cpp:1719
EventQueue eventQueue
Incoming events awaiting processing.
Definition Server.hpp:435
void enqueueReliableEvent(const void *data, int len)
Phase 3d-5: enqueue a reliable event for all clients.
Definition Server.cpp:407
void flushAllOutbound()
Drain every connection's outbound queue to its socket.
Definition Server.cpp:274
void networkLoop()
Network-thread main loop body.
Definition Server.cpp:779
void setAdvertiseServer(bool enabled)
Enable or disable global directory heartbeats at runtime.
Definition Server.cpp:774
void enqueueBroadcast(uint8_t replaceKey, const void *data, int len)
Enqueue raw data for all currently-connected clients.
Definition Server.cpp:243
void handleVoiceFrame(Connection &conn, const std::uint8_t *payload, std::uint32_t len)
Definition Server.cpp:661
void drainEvents(std::vector< Event > &out)
PR-2b (server-perf): drain every queued event in FIFO order into out under a single mutex acquisition...
Definition Server.cpp:1510
TransportConfig transportConfig_
Definition Server.hpp:449
int getClientCount()
Get the number of currently connected clients.
Definition Server.cpp:1704
std::atomic< std::uint32_t > directoryServerId_
Definition Server.hpp:452
std::shared_ptr< const std::vector< uint8_t > > pendingSnapshotFramed_
Definition Server.hpp:498
void poll()
No-op since stage 3b moved I/O onto a dedicated network thread.
Definition Server.hpp:65
Uint64 lastDirectoryHeartbeatMs_
Definition Server.hpp:453
void sendDirectoryHeartbeat(Uint64 nowMs)
Definition Server.cpp:744
GlobalDiscoveryConfig discoveryConfig_
Definition Server.hpp:450
ClientDisconnectedCallback clientDisconnectedFn_
Fired by disconnectClient() when a client drops.
Definition Server.hpp:216
ClientId nextClientId
Counter for assigning client IDs.
Definition Server.hpp:437
bool enqueueTo(const ClientId &clientId, uint8_t replaceKey, const void *data, int len)
Enqueue raw data for one client.
Definition Server.cpp:218
void setMaxPlayers(int maxPlayers)
Update the authoritative client admission cap.
Definition Server.cpp:768
void broadcastMatchStatus(MatchStatePacket packet)
Broadcast match status updates to clients.
Definition Server.cpp:1789
bool notifyPlayerClientId(ClientId clientId, entt::entity playerEntity)
Update client with new entity id.
Definition Server.cpp:1516
std::shared_ptr< const ClientRttSnapshot > rttSnapshotAtomic_
Definition Server.hpp:566
std::function< void(ClientId)> ClientConnectedCallback
Invoked on the network thread immediately after a new client is accepted.
Definition Server.hpp:200
bool usingUdpSession_
Definition Server.hpp:457
uint32_t globalDirectoryServerId() const noexcept
Directory-assigned global server id, or 0 before registration succeeds.
Definition Server.cpp:1714
std::uint32_t snapshotCounter_
Definition Server.hpp:530
void broadcastRegistry(const Registry &registry)
Broadcast the full registry state to all clients.
Definition Server.cpp:1559
void onClientDisconnected(ClientDisconnectedCallback fn)
Register a callback fired whenever a client disconnects.
Definition Server.hpp:206
bool sendVoiceFrameToClients(std::span< const ClientId > recipients, ClientId speaker, std::uint16_t sequence, std::uint8_t frameMs, std::span< const std::uint8_t > opus)
Send one proximity-routed voice frame to multiple listeners.
Definition Server.cpp:1836
void onClientConnected(ClientConnectedCallback fn)
Register a callback fired whenever a client connects.
Definition Server.hpp:204
void handleUdpUnreliable(std::uint64_t connId, const net::UdpEndpointAddr &from, const uint8_t *payload, uint32_t len)
Dispatch a UDP datagram received with channel == Unreliable.
Definition Server.cpp:479
Wraps a NET_DatagramSocket with header-prefixed I/O.
Definition UdpEndpoint.hpp:109
Definition UdpSessionTransport.hpp:26
ChannelId
Per-channel reliability + ordering semantics.
Definition PacketHeader.hpp:48
Definition LagCompMath.hpp:10
Associates an entity with a connected network client.
Definition ClientId.hpp:10
Global server browser / directory-service settings.
Definition NetworkConfig.hpp:121
Incremental lobby change event broadcast to all connected clients.
Definition LobbyStatus.hpp:34
Definition MatchConfig.hpp:4
Definition MatchStatus.hpp:17
Server-authored join/leave notification for in-progress matches.
Definition RosterEvent.hpp:20
PR-2b (server-perf): bulk-snapshot every connected client's last-reported network state in one (mostl...
Definition Server.hpp:126
uint16_t rttMs
Definition Server.hpp:128
ClientId id
Definition Server.hpp:127
uint8_t interpDelaySnapshots
Definition Server.hpp:129
uint16_t interpDelayMs
PR-31: client's measured render delay in ms (EMA-derived).
Definition Server.hpp:133
Atomic-published snapshot of every connected client's network state.
Definition Server.hpp:563
std::vector< ClientNetState > entries
Definition Server.hpp:564
Phase 3d-5: pending reliable events, each scheduled for remainingSends more cycles.
Definition Server.hpp:287
std::shared_ptr< const std::vector< uint8_t > > framed
[PacketType][rest] payload bytes (shared).
Definition Server.hpp:290
uint16_t sequence
Per-channel send sequence.
Definition Server.hpp:288
uint8_t remainingSends
Decremented each send; popped at 0.
Definition Server.hpp:289
Per-client connection state.
Definition Server.hpp:225
bool pendingInitialization
True if waiting for Game to initialize player entity.
Definition Server.hpp:228
uint16_t lastReportedInterpDelayMs
PR-31: client's most-recent self-reported render delay in milliseconds, computed client-side as inter...
Definition Server.hpp:343
std::deque< PendingReliableEvent > reliableQueue
Definition Server.hpp:292
uint16_t reliableNextSequence
Phase 3d-5: per-client outgoing sequence for the reliable event stream over UDP.
Definition Server.hpp:274
Uint64 voiceWindowStartMs
Definition Server.hpp:347
uint16_t lastReportedRttMs
Phase 6: client's most-recent self-reported smoothed RTT in milliseconds.
Definition Server.hpp:304
std::uint8_t chatMessagesInWindow
Definition Server.hpp:346
uint32_t lastAppliedInputTick
Highest InputSnapshot.tick this client has had applied to the simulation.
Definition Server.hpp:236
std::uint8_t voiceFramesInWindow
Definition Server.hpp:348
Uint64 chatWindowStartMs
Definition Server.hpp:345
OutboundQueue outbound
Per-client userspace outbound queue (Phase 3a).
Definition Server.hpp:246
net::UdpEndpointAddr udpAddr
Phase 3d: source address of the most-recent UDP packet from this client.
Definition Server.hpp:262
uint8_t lastReportedInterpDelaySnapshots
PR-12: client's most-recent self-reported render-delay in snapshots (i.e.
Definition Server.hpp:328
uint16_t udpSnapshotSequence
Phase 3d-4: per-client outgoing sequence for the Unreliable channel's snapshot stream.
Definition Server.hpp:268
std::uint64_t connectionId
Phase 3d: server-assigned UDP connection ID.
Definition Server.hpp:255
ClientId clientId
Unique identifier assigned on accept.
Definition Server.hpp:227
MessageStream msgStream
Framed message stream for this client.
Definition Server.hpp:226
Phase 3d: per-feature toggles for the UDP transport rollout.
Definition NetworkConfig.hpp:63
A UDP datagram address (server's view of a remote peer).
Definition UdpEndpoint.hpp:49