Handlers are a plain struct of function pointers, set with designated initializers:
.flowClosed = onFlowClosed,
};
Set of event handlers, registered per flow, per socket, or queue-wide.
NetEventCB recv
NET_DataReceived: stream data or a complete datagram.
Register the same struct at the flow, socket, or queue level. A NULL entry falls through to the next level, resolved separately for each event type:
flow handlers -> socket handlers -> queue-wide handlers
The ctx registered alongside whichever level supplied the handler arrives on NetEvent.ctx, so the queue-wide set is a good place for logging and error handling while sockets and flows override only the events they care about.
◆ NetConnectPrepCB
| typedef void(* NetConnectPrepCB) (NetSocket *sock, void *ctx) |
Called with a socket that is about to dial, before the connect starts
The socket is finished: it is on its queue, its handlers and filters are installed, and it has a flow to deliver on – but nothing has been sent, so no event can have been raised for it yet. A caller that has to know the socket before its first event arrives learns it here rather than from the return value, which comes back too late for that: the connect may complete on another thread while the call that started it is still returning.
The reference belongs to the dial, so keep one (objAcquire) if the socket is stored anywhere.
- Parameters
-
| sock | Socket about to connect |
| ctx | Context registered alongside the callback |
Example:
static void publishSock(
NetSocket* sock,
void* ctx)
{
MyDial* d = (MyDial*)ctx;
}
}
Definition at line 714 of file net_shared.h.
◆ NetEventCB
| typedef void(* NetEventCB) (NetEvent *event) |
The callback type for a network event handler. The handler is called on the thread that generated the event, which is usually the queue's worker thread. The handler must not block or perform long-running work, since that would stall the queue's dispatch loop.
Definition at line 675 of file net_shared.h.
◆ NetEventType
Network event types.
Each type describes a different kind of event that can be delivered to a handler. The event-specific data for each type lives in the matching arm of NetEvent's union.
| Enumerator |
|---|
| NET_Connection | A connection attempt resolved.
Delivered when netsocketConnect() reaches a terminal state: established, or failed once
every resolved address has been tried. NetEvent.conn.state carries the resulting state
and NetEvent.conn.err the failure cause (NERR_None on success). On success this is
always ordered ahead of any NET_DataReceived from the new connection.
|
| NET_FilterNotify | A filter raised an out-of-band notification.
The channel a filter uses to tell the application about a milestone -- most commonly
NFN_Secured, the "secure channel is up, you may send now" edge for a TLS/DTLS session.
NetEvent.filter.notify carries which one (a NetFilterNotify: a built-in code or an
application-defined one at NFN_AppCustom+). It is never inferred from filter state: the
filter raises it itself with netflowfilterNotify(), and the data-plane driver delivers it -- so
a non-security filter (compression, framing) never triggers it merely by establishing.
NET_Connection still fires at the transport level when the socket connects; an NFN_Secured
notification is the higher, secure-channel-ready edge layered on top of it, ordered ahead of
the first NET_DataReceived carrying decoded application data.
|
| NET_Accepted | A listening socket accepted an incoming connection.
The new socket arrives in NetEvent.accept.newSocket, already connected. It is only
guaranteed to live until the handler returns -- call objAcquire() to keep it. Under
NQ_AutoAccept the queue has already registered it and begun servicing receives;
otherwise the handler adds it to a queue itself.
|
| NET_DataReceived | Data arrived on a socket.
For a datagram socket: one event per datagram, delivered whole as NetEvent.recv.msg.
For a stream socket: bytes were appended to the socket's receive ring -- recv.msg is
NULL, and the handler drains the ring with netsocketRecv() or netsocketRecvMsgs().
For a QUIC stream (NST_Quic): recv.msg is NULL and the handler takes the bytes from the
flow with netquicRecv(), which is also what reopens that stream's receive window.
For a QUIC datagram flow (netquicOpenDatagram()): one event per datagram, delivered whole
as recv.msg the way a datagram socket does.
NetEvent.recv.bytes is what this event delivered; NetEvent.recv.total is everything
currently pending.
|
| NET_SendReady | The send backlog drained; sending can resume.
Fires as a real edge, only after a netsocketSend() was refused with more than sendHigh
bytes already queued: once the backlog drains back below sendLow, this event says the
socket is accepting data again.
@note Currently delivered only for stream sockets.
|
| NET_Error | An error surfaced asynchronously on the socket.
Reports a failure with no call left to return it from: data that was accepted into the
send buffer failed when the backend later flushed it. NetEvent.error.err carries the
cause. On a stream socket this is followed by NET_FlowClosed (NCR_Error), since bytes
lost mid-stream break it; a datagram socket stays open, having dropped only the one
datagram. Errors that happen synchronously are reported on the failing call's return
instead, without this event.
|
| NET_FlowOpen | A flow was created for a new peer.
Fires once for every datagram flow that comes into being, whether the queue auto-created
it for an arriving packet or the application admitted the peer with
netqueuePromoteFlow(). Delivered through the new flow's own queue, ordered ahead of its
first NET_DataReceived, which makes it the natural place to set up session state on
flow->user and register flow-level handlers with netflowSetHandlers(). Pairs with
NET_FlowClosed: every open is eventually matched by exactly one close.
@note Datagram sockets only. A stream socket's session start is NET_Connection or
NET_Accepted; its single flow exists from socket creation. See @ref net_flow.
|
| NET_FlowRefused | A packet arrived from a source with no flow, and none could be created.
The queue is at its flow cap with nothing reclaimable (see maxflows, noReclaim, and
reclaimMinIdle in NetQueueConfig). Delivered with the raw packet in NetEvent.refused.msg,
without allocating anything -- this is what keeps a spoofed-source flood from forcing
unbounded allocation. The application validates the packet and calls
netqueuePromoteFlow() to admit the peer, which may exceed the cap by one.
@note Datagram sockets only, and unlike other events this one is delivered inline on the
ingest thread, not a worker -- there is no flow to order it behind.
|
| NET_FlowClosed | A flow is being torn down; release any state hanging off flow->user.
Delivered as a terminal event on the flow's own queue, so it is ordered after every
packet already queued for that flow. Fires exactly once for every flow the application
has seen, on every close cause; the cause is carried in NetEvent.closed.reason.
|
| NET_Timer | A timer armed on this flow reached its deadline.
Delivered on the flow's own queue like a packet, so it is ordered behind everything
already pending for that flow and runs on a worker -- never inline on whichever thread
noticed the deadline. NetEvent.timer.id says which timer fired, so one handler can serve
several. A one-shot timer is spent by the time the handler runs; an NTF_Repeat timer has
already been re-armed and keeps the same id.
A timer never fires after its flow's NET_FlowClosed: teardown cancels everything the flow
still had armed.
|
Definition at line 495 of file net_shared.h.