CX Framework
Cross-platform C utility framework
Loading...
Searching...
No Matches
socket.h
Go to the documentation of this file.
1
6
7#pragma once
8// This header file is auto-generated!
9// Do not make changes to this file or they will be overwritten.
10// clang-format off
11#include <cx/obj.h>
12#include <cx/struct.h>
13#include <cx/net/queue.h>
14#include <cx/net/filter.h>
15#include <cx/net/net_shared.h>
16#include <cx/buffer/bufchain.h>
17#include <cx/buffer/bufring.h>
18#include <cx/thread.h>
19
20CX_C_BEGIN
21
22typedef struct NetFlow NetFlow;
23typedef struct NetFlow_WeakRef NetFlow_WeakRef;
24typedef struct NetSocket NetSocket;
25typedef struct NetSocket_WeakRef NetSocket_WeakRef;
27saDeclarePtr(NetSocket_WeakRef);
28#define _sti_NetSocket _sti_object
29#define SType_NetSocket NetSocket*
30#define STStorageType_NetSocket NetSocket*
31#define STypeArg_NetSocket(type, val) stgeneric(object, (ObjInst*)objInstCheckClass(NetSocket, val))
32#define STypeArgPtr_NetSocket(type, val) (stgeneric*)objInstCheckClassPtr(NetSocket, val)
33#define STypeCheckedArg_NetSocket(type, val) stType(type), stArg(type, val)
34#define STypeCheckedPtrArg_NetSocket(type, val) stType(type), stArgPtr(type, val)
35
36
46typedef bool (*socketRecvCB)(NetSocket* sock, NetMessage* msg, void* ctx);
47
48typedef struct NetSocket_ClassIf {
49 ObjIface* _implements;
50 ObjIface* _parent;
51 size_t _size;
52
53 size_t (*recv)(_In_ void* self, _Out_ uint8* buf, size_t bufsz, _Out_opt_ NetAddr* src, flags_t flags);
54 bool (*recvMsgs)(_In_ void* self, socketRecvCB cb, _In_opt_ void* ctx);
55 bool (*send)(_In_ void* self, _In_ const uint8* data, size_t len, _In_opt_ const NetAddr* dest, flags_t flags);
56 bool (*connect)(_In_ void* self, _In_ strref host, uint16 port);
57 bool (*bind)(_In_ void* self, const NetAddr* addr);
58 // backlog 0 means use a platform-specific default
59 bool (*listen)(_In_ void* self, int backlog);
60 bool (*close)(_In_ void* self);
61} NetSocket_ClassIf;
62extern NetSocket_ClassIf NetSocket_ClassIf_tmpl;
63
67typedef struct NetSocket {
68 union {
69 NetSocket_ClassIf* _;
70 void* _is_NetSocket;
71 void* _is_ObjInst;
72 };
73 ObjClassInfo* _clsinfo;
74 atomic(uintptr) _ref;
75 atomic(ptr) _weakref;
76
77 Weak(NetQueue)* queue;
85 atomic(uint32) state;
86 atomic(bool) canSend;
87 // An accepted socket the application has not been handed yet. While it is set, no worker
88 // delivers anything of this socket's to the application: NET_Accepted travels on the
89 // *listener's* flow, so nothing orders it against events on the accepted socket's own flows,
90 // and a QUIC connection has streams opening on flows of their own the moment its handshake
91 // finishes. Without this, the NET_FlowOpen for a peer's first stream can be delivered before
92 // the application has seen the connection, and it goes to the handlers the socket inherited
93 // from the listener rather than the ones the application installs when it does. Cleared once
94 // NET_Accepted has been delivered, which is also when those flows are put back on the
95 // runqueue.
96 // // A QUIC connection's control flow still runs while this is set, because it is what answers
97 // the handshake that raises the accept -- but only as far as its first application-facing
98 // message, which waits like everything else. See drainFlow().
99 atomic(uint32) awaitingAccept;
106 uint32 mru;
118 NetSocketBufs bufs;
125 size_t sendHigh;
132 size_t sendLow;
156 Weak(ObjInst)* handlerWeak;
164 hashtable flows;
174 // Hook that takes arriving datagrams instead of the flow table, or NULL for the normal path.
175 // Installed by cxquic on the UDP endpoint socket behind a QUIC connection or listener; nothing
176 // else installs one. See NetDatagramRouteFn and _setRoute().
177 // // Written only under flowLock, which the ingest path holds just long enough to copy the hook
178 // and turn the weak context into a reference. `route` alone is also read without it, as a hint
179 // of whether to take the lock at all.
180 NetDatagramRouteFn route;
181 Weak(ObjInst)* routeCtx;
182 // Who installed the hook, compared and never dereferenced -- the weak reference above cannot
183 // answer that once its object is being destroyed, which is one of the times it is asked.
184 void* routeOwner;
189 sa_NetFilter filters;
198 sa_NetAddr connQueue;
212 atomic(uint32) connectGen;
217} NetSocket;
218extern ObjClassInfo NetSocket_clsinfo;
219#define NetSocket(inst) objInstCheckClass(NetSocket, inst)
220#define NetSocketNone ((NetSocket*)NULL)
221
222typedef struct NetSocket_WeakRef {
223 union {
224 ObjInst* _inst;
225 void* _is_NetSocket_WeakRef;
226 void* _is_ObjInst_WeakRef;
227 };
228 atomic(uintptr) _ref;
229 RWLock _lock;
230} NetSocket_WeakRef;
231#define NetSocket_WeakRef(inst) objWeakRefCheckClass(NetSocket, inst)
232
233bool NetSocket_sendEx(_In_ NetSocket* self, _In_ const uint8* data, size_t len, _In_ const NetAddr* dest, _In_opt_ const NetPktInfo* info, flags_t flags);
252#define netsocketSendEx(self, data, len, dest, info, flags) NetSocket_sendEx(NetSocket(self), data, len, dest, info, flags)
253
254bool NetSocket_setRecvInfo(_In_ NetSocket* self, bool enable);
266#define netsocketSetRecvInfo(self, enable) NetSocket_setRecvInfo(NetSocket(self), enable)
267
268bool NetSocket_setDontFragment(_In_ NetSocket* self, bool enable);
279#define netsocketSetDontFragment(self, enable) NetSocket_setDontFragment(NetSocket(self), enable)
280
281void NetSocket_setHandlers(_In_ NetSocket* self, _In_opt_ const NetHandlers* handlers, _In_opt_ void* ctx);
291#define netsocketSetHandlers(self, handlers, ctx) NetSocket_setHandlers(NetSocket(self), handlers, ctx)
292
293void NetSocket_setHandlersObj(_In_ NetSocket* self, _In_opt_ const NetHandlers* handlers, _In_opt_ ObjInst* ctx);
302#define netsocketSetHandlersObj(self, handlers, ctx) NetSocket_setHandlersObj(NetSocket(self), handlers, ObjInst(ctx))
303
304bool NetSocket_addFilter(_In_ NetSocket* self, _In_ NetFilter* filter);
330#define netsocketAddFilter(self, filter) NetSocket_addFilter(NetSocket(self), NetFilter(filter))
331
332void NetSocket_removeFilters(_In_ NetSocket* self);
340#define netsocketRemoveFilters(self) NetSocket_removeFilters(NetSocket(self))
341
342bool NetSocket__wantWrite(_In_ NetSocket* self);
343// bool netsocket_wantWrite(NetSocket* self);
344//
345// -----------------------------------------------------------------------------------------
346// PRIVATE IMPLEMENTATION DETAILS
347// // Everything below this point is internal plumbing between the net module's own translation
348// units and the platform backends. It is not a stable API and carries no compatibility
349// promise -- signatures and semantics change whenever the implementation needs them to.
350// -----------------------------------------------------------------------------------------
351// Send path (dataplane.c)
352// // The send logic is backend-independent and lives on the base socket; only the syscall differs
353// and it is hidden behind netSockSendv/netSockSendTo. A readiness backend watches sockets that
354// have queued data for write-readiness and flushes them from its ingest loop.
355// True when the socket has outbound data queued and should be watched for write-readiness. A
356// hint read without the send lock -- a stale value costs at most one empty flush or one poll
357// cycle.
358#define netsocket_wantWrite(self) NetSocket__wantWrite(NetSocket(self))
359
360void NetSocket__flushSend(_In_ NetSocket* self, _In_opt_ NetQueue* q);
361// void netsocket_flushSend(NetSocket* self, NetQueue* q);
362//
363// Flush as much queued outbound data as the OS will currently accept, updating canSend and
364// firing NET_SendReady on the flow when the backlog drains back below the low watermark.
365// Called by the backend on write-readiness; `q` may be NULL if the socket has no queue
366// (nothing to deliver on).
367#define netsocket_flushSend(self, q) NetSocket__flushSend(NetSocket(self), NetQueue(q))
368
369void NetSocket__sendError(_In_ NetSocket* self, _In_opt_ NetQueue* q, NetErrorCode err, _In_ NetAddr* peer);
370// void netsocket_sendError(NetSocket* self, NetQueue* q, NetErrorCode err, NetAddr* peer);
371//
372// Report a fatal error from the async send path: the call that queued the bytes already
373// returned success, so an event is the only way the application can hear about the loss.
374// Delivers NET_Error through the affected flow like everything else -- on a worker, ordered. A
375// stream's byte stream is broken by bytes vanishing from the middle of it, so its flow is
376// closed behind the event: NET_Error lands first carrying the code, and NET_FlowClosed
377// (NCR_Error) follows. A datagram error cost only the one datagram, so the peer's flow (`peer`
378// is the failed datagram's destination; ignored for streams) hears NET_Error and stays open --
379// and since sending alone never creates a flow, an error for a peer that has no flow has
380// nobody to tell and is dropped. Do not call with sendLock held.
381#define netsocket_sendError(self, q, err, peer) NetSocket__sendError(NetSocket(self), NetQueue(q), err, peer)
382
383void NetSocket__connectResult(_In_ NetSocket* self, NetErrorCode err);
384// void netsocket_connectResult(NetSocket* self, NetErrorCode err);
385//
386// Connect (connect.c)
387// Report the outcome of the in-flight connect attempt and advance the state machine: on
388// success the socket goes NS_Connected and its NET_Connection event is queued; on failure the
389// next resolved address is tried, or a failing NET_Connection is delivered when the list is
390// exhausted. Claims the per-attempt transition by cancelling connectTimer, so the backend
391// completion and the attempt's own timeout cannot both advance it. Safe to call from either;
392// the loser is a no-op.
393#define netsocket_connectResult(self, err) NetSocket__connectResult(NetSocket(self), err)
394
395bool NetSocket__readinessConnect(_In_ NetSocket* self, _Inout_ NetQueue* q, _In_ const NetAddr* addr);
396// bool netsocket_readinessConnect(NetSocket* self, NetQueue* q, const NetAddr* addr);
397//
398// Shared readiness-backend connectBegin body: reset the handle to the address's family, issue
399// a non-blocking connect(), and drive the immediate outcome through netsocket_connectResult().
400// A pending connect is left for the select loop to complete on writability/except. Returns
401// true once the attempt has been initiated (the state machine has been advanced or is now
402// pending).
403#define netsocket_readinessConnect(self, q, addr) NetSocket__readinessConnect(NetSocket(self), NetQueue(q), addr)
404
405void NetSocket__connectCancel(_In_ NetSocket* self);
406// void netsocket_connectCancel(NetSocket* self);
407//
408// Abort an in-flight connect when the socket is being closed. Claims the current attempt the
409// same way the backend completion and the timeout do; if won, drops the connect's resources
410// without starting a new attempt or delivering an event. A no-op if there is no armed attempt
411// -- either nothing is connecting, or the completion/timeout already finished it, or the
412// connect is still resolving (that window is handled in the resolver callback, which checks
413// NS_Closed).
414#define netsocket_connectCancel(self) NetSocket__connectCancel(NetSocket(self))
415
416void NetSocket__accepted(_In_ NetSocket* self, _Inout_ NetSocket* newSock, _In_opt_ const NetAddr* peer);
417// void netsocket_accepted(NetSocket* self, NetSocket* newSock, const NetAddr* peer);
418//
419// Accept and listen (socket.c)
420// Deliver a freshly accepted connection. `newSock` arrives owning one reference (the platform
421// factory's), which this call takes: with NQ_AutoAccept the socket is first added to the
422// listener's queue (which acquires its own reference), then an NMSG_Accept carrying the socket
423// is queued on the listener's flow so NET_Accepted runs on a worker, ordered. If the listener
424// has no queue or flow to deliver on, the socket is dropped (released, closing its handle).
425// Called by both backends once they have pulled a connection off the backlog and wrapped it in
426// a platform NetSocket. `peer` is the remote address, or NULL if it could not be determined.
427#define netsocket_accepted(self, newSock, peer) NetSocket__accepted(NetSocket(self), NetSocket(newSock), peer)
428
429void NetSocket__listenArm(_In_ NetSocket* self);
430// void netsocket_listenArm(NetSocket* self);
431//
432// Kick the backend into servicing a socket that has just started listening. Resolves the
433// socket's queue and calls its acceptArm hook (select wakes its loop to read-watch the
434// listener; IOCP posts the initial AcceptEx batch). A no-op if the socket is not yet on a
435// queue -- the backend's addSocket picks up an already-listening socket instead. Called by the
436// platform listen() once the socket is in NS_Listening.
437#define netsocket_listenArm(self) NetSocket__listenArm(NetSocket(self))
438
439void NetSocket__setRoute(_In_ NetSocket* self, _In_ NetDatagramRouteFn fn, _In_ ObjInst* ctx);
440// void netsocket_setRoute(NetSocket* self, NetDatagramRouteFn fn, ObjInst* ctx);
441//
442// Install a datagram route hook, replacing whatever was installed before. `ctx` is held weakly
443// and passed to the hook as a reference for the length of each call, so a datagram that
444// arrives after it is gone is dropped instead of routed to freed memory.
445#define netsocket_setRoute(self, fn, ctx) NetSocket__setRoute(NetSocket(self), fn, ObjInst(ctx))
446
447bool NetSocket__clearRoute(_In_ NetSocket* self, _In_ ObjInst* owner);
448// bool netsocket_clearRoute(NetSocket* self, ObjInst* owner);
449//
450// Remove the route hook, but only if `owner` is what installed it. Returns true if it did.
451// Safe to call from `owner`'s destroy, when it can no longer be referenced.
452#define netsocket_clearRoute(self, owner) NetSocket__clearRoute(NetSocket(self), ObjInst(owner))
453
454void NetSocket__dropFlow(_In_ NetSocket* self, _Inout_ NetFlow* flow);
455// void netsocket_dropFlow(NetSocket* self, NetFlow* flow);
456//
457// Flow table (flow.c)
458// Remove a flow from this socket's table, releasing the socket's reference. Called once the
459// terminal event has been delivered.
460#define netsocket_dropFlow(self, flow) NetSocket__dropFlow(NetSocket(self), NetFlow(flow))
461
462void NetSocket__closeFlows(_In_ NetSocket* self, NetCloseReason reason);
463// void netsocket_closeFlows(NetSocket* self, NetCloseReason reason);
464//
465// Close every flow on this socket with the given reason.
466#define netsocket_closeFlows(self, reason) NetSocket__closeFlows(NetSocket(self), reason)
467
488#define netsocketRecv(self, buf, bufsz, src, flags) (self)->_->recv(NetSocket(self), buf, bufsz, src, flags)
510#define netsocketRecvMsgs(self, cb, ctx) (self)->_->recvMsgs(NetSocket(self), cb, ctx)
543#define netsocketSend(self, data, len, dest, flags) (self)->_->send(NetSocket(self), data, len, dest, flags)
562#define netsocketConnect(self, host, port) (self)->_->connect(NetSocket(self), host, port)
563// bool netsocketBind(NetSocket* self, const NetAddr* addr);
564#define netsocketBind(self, addr) (self)->_->bind(NetSocket(self), addr)
565// bool netsocketListen(NetSocket* self, int backlog);
566//
567// backlog 0 means use a platform-specific default
568#define netsocketListen(self, backlog) (self)->_->listen(NetSocket(self), backlog)
581#define netsocketClose(self) (self)->_->close(NetSocket(self))
582
583CX_C_END
Buffer chain implementation for efficient streaming I/O.
Ring buffer implementation for efficient streaming I/O.
#define saDeclarePtr(name)
Definition sarray.h:100
bool(* socketRecvCB)(NetSocket *sock, NetMessage *msg, void *ctx)
Definition socket.h:46
NetCloseReason
Definition net_shared.h:166
intptr NetSockHandle
Platform-neutral OS socket handle: a Windows SOCKET or a Unix file descriptor.
Definition net_shared.h:17
NetConnectPref
Definition net_shared.h:40
uint64 NetTimerId
Handle to an armed timer, unique for the lifetime of its queue.
Definition net_shared.h:210
NetErrorCode
Network error codes.
Definition net_shared.h:243
NetSocketType
Socket types.
Definition net_shared.h:134
#define Weak(clsname)
Definition objclass.h:162
CX Struct System - Introspectable, serializable POD structures in C.
Threading system aggregated header.
CX Object System - Object-oriented programming in C.
Definition mutex.h:60
Socket-level factory for per-flow filters.
Definition filter.h:184
A single ordering domain: one connection, or one datagram peer.
Definition flow.h:116
Set of event handlers, registered per flow, per socket, or queue-wide.
Definition net_shared.h:678
A received packet, as delivered to a handler.
Definition net_shared.h:361
Per-datagram information the IP layer carries alongside the payload.
Definition net_shared.h:328
NetQueue manages one or more sockets and a thread pool of workers.
Definition queue.h:79
Mutex connectLock
Serializes the connect-advance transition; see connectTimer.
Definition socket.h:216
NetSockHandle handle
Platform-neutral OS handle, set by the platform factory.
Definition socket.h:84
atomic(bool) canSend
Send buffer empty; can send immediately.
bool sendPending
A completion backend has an overlapped send in flight for this socket.
Definition socket.h:148
uint32 mru
Definition socket.h:106
NetHandlers * handlers
Per-socket handler overrides, optional.
Definition socket.h:152
size_t sendLow
NET_SendReady fires when the queue drains below this.
Definition socket.h:132
sa_NetAddr connQueue
List of fallback addresses to try to connect to if pending connect fails.
Definition socket.h:198
NetSocketType type
Definition socket.h:78
void * handlerCtx
Definition socket.h:153
NetTimerId connectTimer
Timer arming the in-flight connect attempt's deadline, or 0 when none is armed.
Definition socket.h:207
hashtable flows
Flows keyed by peer address (datagram) or stream id (QUIC). Not used by stream sockets.
Definition socket.h:164
bool recvInfo
The OS is reporting per-datagram IP information; see setRecvInfo()
Definition socket.h:111
NetAddr local
Local end, filled in by bind()
Definition socket.h:104
NetSocketBufs bufs
Type-specific send/receive buffers; which arm is live depends on type
Definition socket.h:118
atomic(uint32) state
See NetSocketState enum.
Weak(ObjInst) *handlerWeak
Context passed to per-socket handlers, set by setHandlersObj() – NULL when handlerCtx is in use inste...
Mutex recvLock
Exclusive access to the socket's receive buffer.
Definition socket.h:119
bool sendBlocked
A send returned false at the high watermark and is waiting for NET_SendReady.
Definition socket.h:141
Mutex sendLock
Definition socket.h:120
size_t sendQueued
Bytes waiting in the datagram send queue, guarded by sendLock.
Definition socket.h:136
atomic(uint32) connectGen
Attempt generation, bumped once per connect attempt.
RWLock handlerLock
Guards handlers/handlerCtx/handlerWeak against a concurrent setHandlers()/setHandlersObj()
Definition socket.h:157
size_t sendHigh
Send fails over this many bytes queued.
Definition socket.h:125
Weak(NetQueue) *queue
NetQueue this socket is registered to (may be NULL)
NetAddr remote
Remote address (for connected sockets only)
Definition socket.h:105
int32 connectIdx
Definition socket.h:199
RWLock flowLock
Definition socket.h:165
sa_NetFilter filters
Filters attached to this socket, ordered application -> wire, or empty for none.
Definition socket.h:189
NetFlow * flow
Stream: the single flow for this connection. QUIC: the connection control flow. Not used by datagram ...
Definition socket.h:173
NetConnectPref connectPref
Per-socket address-family preference override; NCP_Default inherits the queue's setting when the sock...
Definition socket.h:192