한국어 | English
Socket Index | Previous: ROUTER | Next: Protocol Overview
Socket — STREAM¶
What this chapter defines — the public contract for exposing raw TCP connections through a STREAM socket and for result/errno.
1. STREAM overview¶
STREAM is a socket that exchanges raw bytes with external peers without zlink framing. It assigns a 4-byte routing ID—a byte sequence that identifies one connection—to each connection. Before bind or connect, the application selects a receive mode; it selects a peer by routing ID when sending and reads the source routing ID from receive results.
STREAM does not interpret application payloads or higher-level protocol semantics. This document defines the generic raw STREAM public contract in ZLink Core for C API and binding developers who send and receive byte records or fixed-framing packets over routed TCP or WS connections.
The following documents own the related contracts.
| Related contract | Defining document |
|---|---|
| Socket creation and close, common options, send wait tokens and completion, and thread safety | Socket Common |
| Wire format for bytes carried without ZMP framing | RAW (STREAM) Protocol Details |
| Result values and errno mapping | Errors |
2. Creation, bind, and options¶
ZLINK_EXPORT void *zlink_socket (void *context_, zlink_socket_type_t type_);
ZLINK_EXPORT zlink_bind_result_t zlink_bind (void *s_, const char *addr_);
ZLINK_EXPORT zlink_connect_result_t zlink_connect (void *s_, const char *addr_);
ZLINK_EXPORT zlink_close_result_t zlink_close (void *s_);
typedef enum zlink_stream_option_t
{
ZLINK_STREAM_OPT_NOTIFY = 0x3501, // RAW-mode connect/disconnect notification records (int 0|1)
ZLINK_STREAM_OPT_RECV_MODE = 0x3502 // zlink_stream_recv_mode_t, set before first bind/connect
} zlink_stream_option_t;
typedef enum zlink_stream_recv_mode_t {
ZLINK_STREAM_RECV_MODE_UNSPECIFIED = 0, // Initial value; bind/connect is not allowed
ZLINK_STREAM_RECV_MODE_RAW = 1, // Use zlink_recv()
ZLINK_STREAM_RECV_MODE_PACKET = 2 // Use zlink_stream_recv_packet()
} zlink_stream_recv_mode_t;
ZLINK_EXPORT zlink_config_result_t zlink_set_stream_option (
void *handle_, zlink_stream_option_t option_,
const void *optval_, size_t optvallen_);
ZLINK_EXPORT zlink_config_result_t zlink_get_stream_option (
void *handle_, zlink_stream_option_t option_,
void *optval_, size_t *optvallen_);
Create a STREAM socket with zlink_socket(context_, ZLINK_SOCKET_STREAM). The receive mode defaults
to UNSPECIFIED. The setter accepts only the exact enum size and RAW or PACKET.
UNSPECIFIED, unknown values, and size mismatches return ZLINK_CONFIG_INVALID_ARGUMENT with
EINVAL. The getter returns the initial UNSPECIFIED value.
ZLINK_STREAM_OPT_NOTIFY value 1 exposes client connect and disconnect notifications as
zero-length data records, whose source routing IDs identify the affected
clients. The default is 0, and it is used only in RAW mode.
Bind without selecting a mode fails with ZLINK_BIND_INVALID_ARGUMENT and EINVAL without endpoint
side effects; connect fails with ZLINK_CONNECT_INVALID_ARGUMENT and EINVAL without side effects.
A failed bind or connect does not freeze the mode. After the first successful bind or connect, the
mode setter and NOTIFY setter fail with ZLINK_CONFIG_INVALID_STATE and EBUSY, even when setting
the existing value.
PACKET and NOTIFY=1 cannot be combined. Whichever setter would create that combination fails with
ZLINK_CONFIG_NOT_SUPPORTED and ENOTSUP, preserving the prior state. Setting and getting
NOTIFY=0 is allowed in PACKET mode.
Common HWM, timeout, linger, TLS, and buffer options
use zlink_set_option() and zlink_get_option(). Socket Common
owns the contract for each option.
3. Receive modes¶
One STREAM handle explicitly selects one of the following modes before bind or connect.
| When to use it | Receive mode | Activation | Delivery form |
|---|---|---|---|
| The application handles a framing-free raw byte stream directly | RAW | Set ZLINK_STREAM_RECV_MODE_RAW |
Receive raw byte records with zlink_recv() |
An application protocol with header + body framing needs packet-sized delivery |
PACKET | Set ZLINK_STREAM_RECV_MODE_PACKET |
Receive header/body packets with zlink_stream_recv_packet() |
RAW permits only zlink_recv(), and PACKET permits only
zlink_stream_recv_packet(). The other receive family returns
ZLINK_RECV_NOT_SUPPORTED with ENOTSUP. Receive mode does not change
ZLINK_POLLOUT or the send contract.
4. Routed send¶
ZLINK_EXPORT zlink_submit_result_t zlink_send_rid (
void *s_, const zlink_routing_id_t *target_rid_,
zlink_msg_t *parts_, size_t part_count_, zlink_send_flags_t flags_,
void *user_context_, zlink_completion_id_t *completion_id_out_);
target_rid_ is a valid four-byte logical routing ID assigned by STREAM to a connection.
A STREAM send permits only part_count_ == 1. Any other count returns
ZLINK_SUBMIT_NOT_SUPPORTED, errno == ENOTSUP, and completion ID 0; it consumes every input
slot without transmitting it. Every call leaves every input slot empty and initialized on both
success and failure.
A send-call boundary does not guarantee a matching receive boundary at the peer. Application message boundaries come from wire framing. The header and body returned by PACKET receive form one packet under §6.
NONE snapshots SNDTIMEO and waits for local queue admission of the same RID. A DONTWAIT call makes exactly one admission attempt. If admitted immediately, it has ID
0 and no completion. If HWM or byte credit prevents admission, or the connection exists but is
not ready yet, it returns ZLINK_SUBMIT_BACKPRESSURED with EAGAIN and a nonzero wait token
bound to that RID, and Core does not retain the payload. If no connection matches target_rid_,
the result is ZLINK_SUBMIT_NOT_CONNECTED immediately with no token. When the same RID gains
write credit (peer drain, or attachment of a not-yet-ready pipe), Core produces exactly one
ZLINK_COMPLETION_WRITABLE record for that token with send_result == ZLINK_SEND_ADMITTED and
peer_rid set to the submitted RID. Credit on another RID does not wake this token. The caller
resubmits its retained record to the same RID with DONTWAIT. Explicitly removing that RID with
zlink_disconnect_rid() ends the token with a WRITABLE record carrying ZLINK_SEND_TERMINAL and
ENOENT. A physical disconnect ends the RID's token with a WRITABLE record carrying
ZLINK_SEND_TERMINAL and ENOTCONN. Reconnection uses a new RID. Socket close or context
termination ends the token internally and delivers no record
(§7). After ID 0, Core does not replay the application payload.
Socket Common owns detailed ownership, result, and
errno rules.
With multiple clients connected to a STREAM socket, ZLINK_POLLOUT is
aggregate readiness for the socket; it neither reserves credit for a specific
target_rid_ nor identifies that routing ID in the event. The original target
can therefore return EAGAIN again even after another writable client raised
the event. The precise per-target signal is the ZLINK_COMPLETION_WRITABLE
record identified by peer_rid; while an unread WRITABLE record exists,
ZLINK_POLLOUT and ZLINK_POLLCOMPLETION are level-held. That record is
received through zlink_completion_recv().
Routed sending of one zero-length part to a valid target_rid_ requests
termination of that peer connection instead of sending a byte record. Success
also consumes this input slot.
If the connection cannot be found, the function returns
ZLINK_SUBMIT_NOT_CONNECTED. See the errno map
for the complete result mapping.
5. Raw receive¶
ZLINK_EXPORT zlink_recv_result_t zlink_recv (
void *s_,
const zlink_routing_id_t **source_rid_out_,
zlink_msg_t *parts_out_,
size_t parts_capacity_,
size_t *part_count_out_,
zlink_recv_flags_t flags_);
parts_out_ and part_count_out_ are required. source_rid_out_ is optional. On success, it receives a
Core-owned borrowed view—a reference for temporarily reading memory owned by
Core—of the source client's routing ID. Copy this view before entry to the next
data-recv API on the same socket if it must remain valid after that receive.
Each RAW receive record has one part. On success, *part_count_out_ == 1 and ownership of the first
slot transfers to the caller, which releases it with zlink_multipart_close(). Failure does not
transfer ownership. If parts_capacity_ < 1, the call does not consume the record and returns the
needed count 1 with ZLINK_RECV_BUFFER_TOO_SMALL and ENOBUFS. A
ZLINK_RECV_FLAGS_DONTWAIT call with no data returns ZLINK_RECV_NO_DATA with EAGAIN.
Timeout and termination for NONE, and output invariance, follow the data-recv contract in
Socket Common.
6. Packet receive and framing¶
PACKET mode serves application protocols that place header + body framing on the raw STREAM byte
pipe. STREAM completes packets from each peer byte stream into a bounded receive queue, and the
application pulls them.
ZLINK_EXPORT zlink_recv_result_t zlink_stream_recv_packet(
void *stream_,
const zlink_routing_id_t **source_rid_out_,
zlink_msg_t *header_out_,
zlink_msg_t *body_out_,
zlink_recv_flags_t flags_);
6.1 Wire framing¶
Packet mode assembles the following frame in order on each client byte stream.
+----------------+----------------+----------------+---------------+
| header_size:u16| body_size:u32 | header bytes | body bytes |
+----------------+----------------+----------------+---------------+
| big endian | big endian | exact length | exact length |
+----------------+----------------+----------------+---------------+
header_sizeis a 2-byte big-endian unsigned 16-bit length.body_sizeis a 4-byte big-endian unsigned 32-bit length.- Both payload lengths may be
0. A packet withheader_size == 0 && body_size == 0is returned as two valid zero-lengthzlink_msg_tvalues. - When the complete six-byte prefix has been read, Core snapshots
ZLINK_OPT_MAXMSGSIZE. If it is positive,header_size,body_size, and their overflow-safe sum must each be within the limit. Zero and negative values are unlimited.
6.2 Output and ownership¶
source_rid_out_ is optional. header_out_ and body_out_ are required, distinct pointers, and
both messages must be initialized and empty before the call. A NULL required output returns
ZLINK_RECV_INVALID_HANDLE with EFAULT; aliased or non-empty messages return
ZLINK_RECV_INVALID_STATE with EINVAL.
Successful receive transfers the source-RID borrowed view and ownership of header and body to the
caller, which closes each message exactly once or moves it to another owner. A 0 + 0 packet still
returns two valid zero-length messages. NO_DATA and every failure leave the source pointer and both
messages unchanged. The RID view remains valid until entry to the next data-recv API on the same
socket or close; poller wait, completion recv, monitor recv, and data recv on another socket do not
invalidate it.
NONE snapshots RCVTIMEO on entry. DONTWAIT and timeout return ZLINK_RECV_NO_DATA with EAGAIN.
A blocking PACKET receive observes context termination at the start of every receive turn:
whether waiting or draining a ready packet backlog, observing termination returns
ZLINK_RECV_TERMINATED with ETERM; socket shutdown returns ZLINK_RECV_INVALID_STATE with
ESHUTDOWN.
6.3 Queue and malformed framing¶
STREAM treats the following conditions as malformed and closes the affected connection.
header_size,body_size, orheader_size + body_sizeexceeds a positive configuredmaxmsgsize.- The length fields have started to arrive, but the peer closes or resets before the full packet arrives—that is, a mid-length or mid-payload close.
The STREAM monitor exposes this condition as a disconnect event for that
source_rid. An incomplete packet is not placed in the application queue, and the decoder state is
discarded with the connection. Other peers' decoders and queues are unaffected.
ZLINK_POLLIN is ready only while at least one complete packet exists. Packet order for one source
RID is preserved; packets from different sources are returned in Core receive-queue admission order.
The queue follows RCVHWM; when full, Core stops pipe reads and propagates backpressure. It neither
silently drops packets nor creates a separate unbounded queue.
7. Completion and thread safety¶
When a STREAM send returns a nonzero wait token, exactly one ZLINK_COMPLETION_WRITABLE record
for that token is received through zlink_completion_recv(): ZLINK_SEND_ADMITTED when the same
RID gains write credit, or ZLINK_SEND_TERMINAL when the RID is explicitly removed with
zlink_disconnect_rid(). Socket close ends the token internally and delivers no record, so a result that
is needed is received before close. Its peer_rid preserves the logical RID snapshot
specified at submit; it does not change to a physical connection identity after reconnect. Socket Common
owns completion draining, reservation bounds, and close.
Public socket-handle thread safety and close behavior follow
Socket Common. The same zlink_msg_t cannot be used
concurrently from multiple threads.
8. Receive flow state¶
STREAM is not a socket type that supports receive flow. zlink_socket_set_receive_flow_state() returns
ZLINK_CONFIG_NOT_SUPPORTED with errno == ENOTSUP for a STREAM socket and
changes nothing. The byte HWM, low water mark, and transport backpressure
described above remain in effect. A STREAM socket monitor does not set
ZLINK_MONITOR_STATUS_DETAIL_FLOW_STATE and does not emit
ZLINK_EVENT_SEND_FLOW_PAUSED, ZLINK_EVENT_SEND_FLOW_RESUMED, or
ZLINK_EVENT_FLOW_STATE_STALE.
9. Peer routing ID and connection termination¶
The public routing ID for STREAM is the 4-byte connection ID that Core assigns
to each connection. Connections accepted through zlink_bind() and connections
created through zlink_connect() both receive their ID from the local socket. Passing this ID to zlink_disconnect_rid() requests
termination of that connection. A routing ID that is not 4 bytes fails as an
invalid argument. Socket Common owns the contract for
zlink_disconnect_rid() itself; §10 Internals explains how
the ID is found internally.
10. Internals¶
Contract ownership for this section — §1–§9 of this document own the public STREAM socket contract. This section explains the internal optimization structure of the WS/WSS path, the packet assembly implementation, and runtime defaults.
WS/WSS path¶
The STREAM socket supports RAW communication with external clients such as web browsers and game clients that connect without a ZMP (zlink Message Protocol) handshake. It supports tcp, tls, ws, and wss transports, with a particular focus on performance optimization of the WS/WSS path.
| Component | File | Role |
|---|---|---|
| stream_t | src/runtime/sockets/stream/stream.cpp | STREAM socket logic |
| raw_encoder_t | src/runtime/protocol/raw_encoder.cpp | passthrough encoding (no framing) |
| raw_decoder_t | src/runtime/protocol/raw_decoder.cpp | passthrough decoding (byte span -> msg_t) |
| asio_raw_engine_t | src/runtime/engine/asio/asio_raw_engine.cpp | RAW I/O engine |
| ws_transport_t | src/runtime/transports/ws/ | WebSocket transport |
| wss_transport_t | src/runtime/transports/tls/ | WebSocket + TLS transport |
%%{init: {'sequence': {'actorFontSize': '18px', 'messageFontSize': '18px', 'noteFontSize': '18px', 'boxMargin': 8, 'width': 140}, 'themeVariables': {'fontSize': '18px'}}}%%
sequenceDiagram
participant App as Application
participant SS as Stream Socket
participant Eng as Engine
participant Tr as Transport
App->>SS: zlink_send_rid(rid, data)
SS->>Eng: pipe_t::write()
Eng->>Tr: raw_encode (passthrough bytes, no framing)
Tr->>Tr: ws::write
WS/WSS has the following performance characteristics.
- Read path — Data is copied from the Beast read buffer (
message_buffer) into the outgoingmsg_t(one copy at delivery). - Write path — The
msg_tpayload is passed directly to the Beast write buffer (no intermediate copy). - Beast write buffer — The default is 64KB. A WS write sends one supplied
buffer as a single binary frame (one
async_write). STREAM is a raw protocol with no header to gather, so it does not use gather writes — whether a connection may gather is decided once, when the connection is created, by the fast-path policy from the protocol's and the transport's capabilities. - Frame fragmentation —
auto_fragment(false). One logical message maps to one WebSocket frame.
The design trade-offs are as follows.
- Speculative write is not supported because WebSocket is frame-based.
- Gather write: the WS/WSS transports advertise the capability through
supports_gather_write(), but STREAM's raw protocol has no header to gather, so STREAM connections do not gather. Gathering is enabled only for sockets on the ZMP protocol, together with the transport capability. - TLS/WSS has encryption overhead.
Packet assembly implementation¶
This is the per-connection accumulator that implements packet receive in
§6. Incoming bytes pass through the packet
state of each connection (pipe), pipe_t::_stream_packet_state. The receive engine
accesses this state through pipe_->stream_packet_state().
wire bytes (arbitrary fragmentation)
|
v
+-------------------------+
| pipe packet state |
| stage: prefix_stage |
| header_stage |
| body_stage |
+-------------------------+
|
v
bounded packet receive queue
The length fields are parsed first. Once both header_size and body_size are
known, subsequently arriving bytes accumulate in the header and body buffers
of that connection's packet state. When a packet completes, those accumulation
buffers are moved into freshly initialized zlink_msg_t header and body values
and placed in the receive queue. This zero-copy move transfers ownership without
copying the data. zlink_stream_recv_packet() transfers ownership of a queued
record to the caller outputs.
STREAM performs decoding internally instead of requiring each application to do so for the following reasons.
- One fewer copy. The application does not need to touch an assembled contiguous buffer and then split it again. The accumulation buffers are moved into the header and body messages with zero-copy semantics.
- Ordering guarantee. The decoder and receive queue enforce per-
source_ridserialization, so the caller does not need separate reordering logic on top of raw byte delivery.
Current STREAM runtime defaults¶
STREAM uses a common default performance profile across transports. For common socket defaults outside STREAM, see the internals section of Socket Common.
The following values are internal STREAM defaults.
- read drain: enabled
- speculative write: enabled by default on the STREAM/TCP path
- RX slab buffering: enabled
- speculative write byte budget:
2097152 - read drain max loops:
64 - read drain max bytes:
1048576
Socket and listener defaults are as follows.
- backlog:
65536 sndhwm/rcvhwm: per-physical-queue applied HWM produced by water-filling the Core memory budget within the STREAM role lower and upper boundssndbuf/rcvbuf: default-1, leaving OS buffer defaults and TCP autotuning in control- accept concurrency (STREAM only): default
4, maximum128 - session scheduler (STREAM): default
rr
Adaptive read/write targets and speculative reads¶
A STREAM connection keeps its own target — the number of bytes one kernel read or write should move — and that value changes only on what the connection observed. The rules in this section are an internal heuristic that applies inside the Core I/O thread and change no public contract such as part ownership, queue bounds or ordering. The multiplier and the number of observations are a record of the current implementation, not a contract, and may change as long as the public behaviour does not.
Initial value and maximum. The initial target starts from the batch size or 4,096 bytes,
is capped by the internal initial limit, and is capped again by
ZLINK_OPT_RCVBUF for reads, ZLINK_OPT_SNDBUF for writes and by ZLINK_OPT_MAXMSGSIZE for both
when those are smaller; the floor is 1. The maximum starts at the initial value and rises to a
larger positive RCVBUF for reads or SNDBUF for writes, capped by MAXMSGSIZE. If that socket
buffer option is not larger than the initial value, the maximum stays at the initial value, so a
connection that set no buffer option keeps its initial target.
Growth and shrink. When the previous read filled everything it asked for, the target doubles immediately, clamped to the maximum. One full read decides it; no consecutive observation is required. A read that did not fill the request leaves the target unchanged, and the decoder has no shrink rule. The encoder doubles the same way when a prepared batch fills the current target, and on a transport with message boundaries it returns to the initial value when a batch fills less than half of the current target. A decoder resize takes effect right after the read that caused it; an encoder resize takes effect at the next output-preparation boundary so it never rewrites a buffer that is already prepared.
Speculative reads and the bounded drain. Only when the previous read filled its request does
the engine issue the next read inline in the same callback. The repetition is bounded to 64 reads
per callback turn and to less than 1 MiB read in that turn, and it stops on a short read, EAGAIN,
an error, termination, or a read already outstanding. Where it stops, the asynchronous read is
re-armed if the conditions still hold. Only one asynchronous read exists per connection at a time;
that fact is held in state owned by the I/O thread so two are never armed together.
Peer routing ID disconnect implementation¶
zlink_disconnect_rid() interprets the 4-byte routing ID as a uint32_t,
finds the pipe in the STREAM routing map, and requests termination. §9
owns the public behavior.
11. Implementation and contract-test verification requirements¶
Verify the following through the public surface only: STREAM function calls, completion pull, return results and errno values, and monitor events. Each item maps to one test.
Creation, bind/connect, and receive mode
- Bind and connect in the default
UNSPECIFIEDstate fail without side effects asZLINK_BIND_INVALID_ARGUMENTwithEINVALandZLINK_CONNECT_INVALID_ARGUMENTwithEINVAL, respectively. - Selecting RAW before bind or connect succeeds and permits only
zlink_recv(); PACKET recv returnsZLINK_RECV_NOT_SUPPORTEDwithENOTSUP. - Selecting PACKET before bind or connect succeeds and permits only
zlink_stream_recv_packet(); raw recv returnsZLINK_RECV_NOT_SUPPORTEDwithENOTSUP. - A failed bind or connect does not freeze the mode. After the first successful bind or connect, the
mode and NOTIFY setters return
ZLINK_CONFIG_INVALID_STATEwithEBUSY, even for the same value. - Whichever setter would combine PACKET with
NOTIFY=1returnsZLINK_CONFIG_NOT_SUPPORTEDwithENOTSUPand preserves the previous state. - With
NOTIFY=1in RAW, connect and disconnect are returned as zero-length DATA records with source RIDs. PACKET observes connection state and RID through monitor pull.
Routed send
- If
part_count_ != 1, the call returnsZLINK_SUBMIT_NOT_SUPPORTEDwithENOTSUPand ID0, consumes every input slot, and transmits no bytes. - Sending one zero-length part to a valid target routing ID requests peer connection termination.
- Success and failure both consume every input slot and leave it empty and initialized.
NONEsnapshotsSNDTIMEO, waits for same-logical-RID local admission, and finishes with ID0and no completion.- A
DONTWAITcall admitted immediately has ID0and no completion. If it is refused because of HWM, credit, or a connection that is not ready, it returnsZLINK_SUBMIT_BACKPRESSUREDwithEAGAINand a nonzero wait token for that RID, and the payload is not retained. - When the same RID gains write credit, exactly one
ZLINK_COMPLETION_WRITABLErecord (ZLINK_SEND_ADMITTED,peer_ridset to the submitted RID) is returned for that token, and credit on another RID does not wake it.ZLINK_POLLOUTis level-held until it is read. - Removing the RID with
zlink_disconnect_rid()ends that RID's token with a WRITABLE record carryingZLINK_SEND_TERMINALandENOENT. - A wait token is bound only to the same logical RID; after reconnect, that RID's pipe attach
publishes the WRITABLE record, and after ID
0Core does not replay the payload. - If the connection cannot be found, the result is
ZLINK_SUBMIT_NOT_CONNECTEDimmediately with ID0and no token.
Raw receive
- On success,
*part_count_out_ == 1and ownership of the first slot transfers to the caller, which releases it withzlink_multipart_close(). Failure does not transfer ownership. - If
parts_capacity_ < 1, the call returns the needed count1andZLINK_RECV_BUFFER_TOO_SMALLwithENOBUFSwithout consuming the record. - DONTWAIT or a
NONEtimeout with no data returnsZLINK_RECV_NO_DATAwithEAGAIN. - The borrowed view from
source_rid_out_remains valid until entry to the next data recv on the same socket or close; poller, completion, and monitor recv and data recv on another socket do not invalidate it.
Packet receive
- A packet with
header_size == 0 && body_size == 0succeeds with two initialized zero-length messages. - Even when the six-byte prefix is split across raw reads, exactly one header/body pair is returned
after the complete packet, and
ZLINK_POLLINis not ready before completion. - A NULL required output returns
ZLINK_RECV_INVALID_HANDLEwithEFAULT; aliased or non-empty outputs returnZLINK_RECV_INVALID_STATEwithEINVAL, preserving the queued packet and outputs. - Packets from the same
source_ridare returned in arrival order; packets from different sources are returned in Core receive-queue admission order. - At
RCVHWM, Core stops pipe reads and propagates backpressure without dropping packets. - Size checks apply only when
maxmsgsizeis positive (the default-1is unbounded). From the snapshot taken when the complete prefix arrives, a size declaration in whichheader_size,body_size, or their overflow-safe sum exceeds the limit, as well as a mid-length or mid-payload close, is malformed: the connection closes and the monitor exposes a disconnect event for thatsource_rid. No incomplete packet enters the application queue.
Completion
- The WRITABLE record of a nonzero wait token is returned exactly once on an open socket
(
ZLINK_SEND_TERMINALon explicit RID removal; no record is returned after close) and preserves inpeer_ridthe logical RID snapshot specified at submit; it does not change to a physical connection identity after reconnect. ZLINK_POLLCOMPLETIONis non-consuming level readiness. Draining withzlink_completion_recv(DONTWAIT)throughNO_DATAclears it.
Receive flow state and monitor
zlink_socket_set_receive_flow_state()fails withZLINK_CONFIG_NOT_SUPPORTEDanderrno == ENOTSUPand changes nothing.- A STREAM monitor does not set
ZLINK_MONITOR_STATUS_DETAIL_FLOW_STATEand does not emitZLINK_EVENT_SEND_FLOW_PAUSED,ZLINK_EVENT_SEND_FLOW_RESUMED, orZLINK_EVENT_FLOW_STATE_STALE.
Connection termination
- Calling
zlink_disconnect_rid()with a 4-byte routing ID requests termination of that connection; a routing ID that is not 4 bytes fails as an invalid argument.