한국어 | English
Core Spec Index | Previous: Polling | Next: Utilities
Monitoring¶
What this chapter defines — The public contract for subscribing to socket events through a separate channel with the
zlink_socket_monitor_*APIs.
1. Monitoring Overview¶
The zlink raw socket monitor is an observability tool that subscribes to connection, transport, protocol, and socket-lifecycle changes on a socket through a separate event channel. A socket monitor provides bind, accept, connect, disconnect, handshake, protocol-error, and close events. A monitor only observes state; it does not change routing or queue state.
This document defines the public contract for opening a monitor, consuming events, querying a status snapshot, and closing the monitor. Its audience is developers who map this contract to the C API and each language binding.
The following documents own the related contracts.
| Related contract | Defining document |
|---|---|
| Socket event-family catalog and receive-flow event occurrence conditions | Events |
| Exclusion of monitor queues from Auto HWM planning and their aggregation in context budget snapshots | Auto HWM |
| Mapping between each result value and errno | Errors |
2. Monitor Lifecycle and Consumption Modes¶
A monitor proceeds through open → event consumption → close.
- open —
zlink_socket_monitor_openopens a monitor on the target socket. Theeventsmask in the open options selects the events to receive.events == 0selects no events, whileEVENT_ALLselects every bit. - consumption — The caller retrieves events directly with
zlink_socket_monitor_recv. - status —
zlink_monitor_statusfills a current-state snapshot (§6). - close —
zlink_monitor_closecloses the monitor.
Recv and close must follow the single-consumer rule for the same event queue. The caller is responsible for serializing these operations. Core neither detects nor serializes concurrent consumption by recv and close.
The event addresses and the routing ID—the byte sequence that identifies a peer—are values inside the caller-owned output structure.
%%{init: {'sequence': {'actorFontSize': '18px', 'messageFontSize': '18px', 'noteFontSize': '18px', 'boxMargin': 8, 'width': 140}, 'themeVariables': {'fontSize': '18px'}}}%%
sequenceDiagram
participant App as Application
participant Mon as Monitor
participant S as Raw socket
App->>Mon: zlink_socket_monitor_open(socket, options)
S-->>Mon: Record events in state-transition commit order
App->>Mon: zlink_socket_monitor_recv(&event_out, flags)
Mon-->>App: Write event to caller-owned structure
App->>Mon: zlink_monitor_status(&status_out)
App->>Mon: zlink_monitor_close(&monitor)
3. Event Interpretation¶
3.1 Connection and Lane Identification¶
connection_id is a diagnostic and correlation value that identifies one physical
transport attempt in the current process. It cannot be used as a send target or reconnect
fence. transport_lane classifies the physical connection. Every physical event for
DEALER-DEALER and DEALER-ROUTER has the Application value, and only the separate
ROUTER-ROUTER Completion connection can have the Completion value. Other transports also
have the Application value.
CONNECTION_READY aggregates count 1 for DEALER-DEALER and DEALER-ROUTER and count 2
for ROUTER-ROUTER as one logical peer. It therefore emits exactly one ready edge and counts
the peer only once in value. Learning the routing ID at different times on the two
ROUTER-ROUTER lanes does not split the peer into two ready transports, and readiness of only
one lane does not increase the count.
3.2 value and flags¶
Each event defines value as follows.
| Event | value |
|---|---|
CONNECTED, LISTENING, ACCEPTED, CLOSED |
The OS transport descriptor converted to uint64_t |
CONNECT_RETRIED |
The interval (ms) until the next reconnect attempt |
CONNECT_DELAYED, BIND_FAILED, ACCEPT_FAILED, CLOSE_FAILED, HANDSHAKE_FAILED_NO_DETAIL |
The errno for that failure |
MONITOR_STOPPED |
0 |
DISCONNECTED |
A zlink_disconnect_reason_t value |
HANDSHAKE_FAILED_PROTOCOL |
A zlink_protocol_error_t value |
HANDSHAKE_FAILED_AUTH |
EACCES for TLS verification or client-certificate failure |
PEER_WEIGHT_CHANGED |
The new 0..10000 weight |
CONNECTION_READY |
The current count of ready logical peers for this monitor source |
| Receive-flow events | Receive-flow table below |
Because the value of CONNECTION_READY is the current count of ready logical peers, use
ZLINK_MONITOR_EVENT_FLAG_CONNECTION_READY_EDGE in flags to identify the instant when
the count increases. A ready-count event without this flag is a count snapshot, not the
ready edge of a new connection.
ZLINK_MONITOR_EVENT_FLAG_SEND_FLOW_WRITABLE and
ZLINK_MONITOR_EVENT_FLAG_FLOW_STATE_STALE_EPOCH apply only to the three receive-flow
events (ZLINK_EVENT_SEND_FLOW_PAUSED, ZLINK_EVENT_SEND_FLOW_RESUMED, and
ZLINK_EVENT_FLOW_STATE_STALE).
Events defines occurrence conditions and event bits. Receive-flow field values are as follows.
| Event | value |
flags |
Other fields |
|---|---|---|---|
ZLINK_EVENT_SEND_FLOW_PAUSED |
flow epoch of the applied state | none | routing_id, connection_id, and Application transport_lane of the paused peer |
ZLINK_EVENT_SEND_FLOW_RESUMED |
flow epoch of the applied state | ZLINK_MONITOR_EVENT_FLAG_SEND_FLOW_WRITABLE if clearing the remote pause makes the pipe actually writable |
same as PAUSED |
ZLINK_EVENT_FLOW_STATE_STALE |
received flow epoch | ZLINK_MONITOR_EVENT_FLAG_FLOW_STATE_STALE_EPOCH |
routing_id, connection_id, and Application transport_lane of the peer |
Auxiliary identifier (ZLINK_ prefix) |
Value | Meaning |
|---|---|---|
DISCONNECT_REASON_UNKNOWN |
0 |
Termination not classified by another public reason |
DISCONNECT_REASON_HANDSHAKE_FAILED |
3 |
Handshake failure |
DISCONNECT_REASON_TRANSPORT_ERROR |
4 |
Transport error |
DISCONNECT_REASON_CTX_TERM |
5 |
Context termination |
PROTOCOL_ERROR_ZMP_MALFORMED_COMMAND_HELLO |
0x10000013 |
Malformed HELLO |
PROTOCOL_ERROR_ZMP_MALFORMED_COMMAND_READY |
0x10000016 |
Malformed READY metadata or paired-lane topology |
MONITOR_TRANSPORT_LANE_APPLICATION |
0 |
Application connection |
MONITOR_TRANSPORT_LANE_COMPLETION |
1 |
Separate Completion connection |
MONITOR_EVENT_FLAG_CONNECTION_READY_EDGE |
1u << 0 |
Logical peer transitions from not-ready to ready |
MONITOR_EVENT_FLAG_SEND_FLOW_WRITABLE |
1u << 1 |
No other cause blocks the pipe after RESUMED |
MONITOR_EVENT_FLAG_FLOW_STATE_STALE_EPOCH |
1u << 3 |
Epoch did not advance within the same generation |
4. Ordering, Overflow, and Thread Safety¶
Within one monitor, Core queues events in the order in which it commits state transitions. No wall-clock order is guaranteed across different connection I/O threads.
The monitor queue is bounded and lossy. When the queue is full, it discards the newly arriving record regardless of event type and retains records already in the queue. It does not aggregate events or preferentially retain specific event types, and it exposes no public counter or status field for the number of discarded records. A delayed monitor consumer does not block raw socket submission.
The thread rule follows the single-consumer rule in §2: the caller serializes recv and close so that one consumer uses the event queue. Core does not contractually detect or serialize concurrent calls on the caller's behalf.
5. Monitor Queue Byte Budget¶
monitor_hwm_bytes is the single byte budget applied to both the monitor source worker and
the internal monitor PAIR. An HWM limits the bytes retained in a
queue. A positive value is used unchanged as the exact SNDHWM, RCVHWM, and worker admission
limit. 0 is not unlimited; it selects the Core default byte value computed by
checkedMultiply(4096, sizeof(socket_monitor_internal_event_t) + sizeof(zlink_msg_t)).
The worker also makes admission decisions from the actual accounted bytes of a record, not from an event count, and applies the same one-oversize-record-on-empty rule.
Monitor queues are excluded from application Auto HWM water-filling. A context budget snapshot counts each unique physical ypipe direction of the internal monitor PAIR once and does not add the reader and writer endpoint options twice. Auto HWM owns this relationship.
6. Status Snapshot¶
6.1 ABI Version and Layout¶
In the status structure filled by zlink_monitor_status,
abi_version is ZLINK_MONITOR_STATUS_ABI_VERSION, and struct_size is the full byte size
of the returned ABI version. These values diagnose the current layout returned by Core;
they are neither caller inputs nor compatibility-negotiation values. A raw socket monitor
status has source_kind set to ZLINK_MONITOR_SOURCE_SOCKET.
The current ABI version is 4 and includes snd_pending_bytes, rcv_pending_bytes, and
five receive-flow fields. Older layouts are not accepted as compatibility layouts. Core
provides neither caller size/version negotiation nor a parallel versioned entry point.
6.2 Detail Bits and Valid Fields¶
detail_flags identifies which optional status fields are valid. Each detail bit makes
the following fields valid. A field belongs to only one bit, and all fields in a row are
zero when that bit is absent.
| detail bit | valid fields |
|---|---|
ZLINK_MONITOR_STATUS_DETAIL_SND_PENDING_MSGS |
snd_pending_msgs, snd_pending_bytes |
ZLINK_MONITOR_STATUS_DETAIL_RCV_PENDING_MSGS |
rcv_pending_msgs, rcv_pending_bytes |
ZLINK_MONITOR_STATUS_DETAIL_AUTO_HWM_BUDGET |
auto_hwm_enabled, auto_hwm_profile, auto_hwm_role, auto_hwm_policy_class, auto_hwm_planned_sndhwm_bytes, auto_hwm_planned_rcvhwm_bytes, auto_hwm_last_recalc_ms, auto_hwm_last_recalc_reason, auto_hwm_send_blocked_ratio_ppm, auto_hwm_deferred_sndhwm_bytes, auto_hwm_deferred_rcvhwm_bytes, auto_hwm_deferred_sndhwm_valid, auto_hwm_deferred_rcvhwm_valid |
ZLINK_MONITOR_STATUS_DETAIL_AUTO_HWM_BUFFERS |
auto_hwm_applied_sndhwm_bytes, auto_hwm_applied_rcvhwm_bytes, auto_hwm_effective_sndbuf, auto_hwm_effective_rcvbuf, snd_bytes_in_flight, rcv_bytes_in_flight, minimum_core_message_charge_bytes, oversize_message_admission_count, oversize_message_admission_max_bytes |
ZLINK_MONITOR_STATUS_DETAIL_FLOW_STATE |
flow_paused_connections, flow_pause_applied_total, flow_resume_applied_total, flow_state_stale_total, flow_pause_duration_ms |
6.3 Byte and Pending Diagnostic Fields¶
The planned fields report the result of the current automatic policy. The applied fields
report the byte HWM that the socket actually uses, including manual overrides. A deferred
value is valid only when the corresponding _valid field is nonzero.
snd_bytes_in_flight and rcv_bytes_in_flight are directional pipe totals at snapshot
time. snd_pending_bytes and rcv_pending_bytes report
the same send and receive in-flight totals, respectively. Some sources estimate the
receive total and count. Pending message fields remain counts, and pending byte fields use
the same byte unit as admission accounting, but the diagnostic values themselves are not
used as admission inputs. The minimum-charge and oversize fields make it possible to
diagnose byte-accounting results without querying the allocator for every message.
The pipe-total field group consists of snd_pending_msgs, rcv_pending_msgs,
snd_pending_bytes, rcv_pending_bytes, snd_bytes_in_flight, and
rcv_bytes_in_flight. Core reads this group under one lock, so the group is internally
consistent. Auto HWM fields and the flow counters in
§6.4 may be read at different times. Therefore,
cross-consistency among the pipe-total field group, Auto HWM fields, and flow counters is
not guaranteed.
auto_hwm_send_blocked_ratio_ppm is the fraction, in parts per million, of the socket's
first send-admission attempts in the measurement epoch that were blocked by an application
pipe HWM. Retries after the same submission wakes are not counted again. Transport I/O
waits, the ROUTER-ROUTER completion lane, and context-aggregate usage are excluded.
The context Auto HWM snapshot uses ABI v1. DEALER-ROUTER reply bytes are included in
core_queue_accounted_bytes, current_accounted_bytes, and, when applicable,
provisional_accounted_bytes, peak_accounted_bytes, and total_messaging_accounted_bytes.
They are not included in completion_current_accounted_bytes,
completion_peak_accounted_bytes, completion_pending_message_count, or
active_completion_directional_queue_count. Auto HWM owns the
declarations and exact accounting for these fields.
6.4 Receive-Flow Statistics¶
ZLINK_MONITOR_STATUS_DETAIL_FLOW_STATE is set for DEALER and ROUTER sockets that support
receive flow. This includes DEALER-DEALER and DEALER-ROUTER, which have no separate
completion lane. For other socket types, the bit
is absent and all five fields are zero. These fields report the receive-flow state that the
socket observes on its peers. The declaration comments in
§7.5 define the exact increment and decrement rules for each field.
The three counters (flow_pause_applied_total, flow_resume_applied_total, and
flow_state_stale_total) increase monotonically over the lifetime of the socket. No public
call resets or rebases these values, and zlink_ctx_reset_auto_hwm_budget_metrics does not
change them. Snapshot consistency between these flow counters and other field groups
follows the boundary in §6.3.
7. Types and Constants¶
7.1 Event Mask¶
ZLINK_SOCKET_MONITOR_EVENT_* names are the canonical event-mask names;
ZLINK_EVENT_* are shorter names with the same numeric values.
typedef uint32_t zlink_socket_monitor_event_mask_t; // Event-selection mask in open options
typedef enum zlink_socket_monitor_event_e {
ZLINK_SOCKET_MONITOR_EVENT_CONNECTED = 1u << 0,
ZLINK_SOCKET_MONITOR_EVENT_CONNECT_DELAYED = 1u << 1,
ZLINK_SOCKET_MONITOR_EVENT_CONNECT_RETRIED = 1u << 2,
ZLINK_SOCKET_MONITOR_EVENT_LISTENING = 1u << 3,
ZLINK_SOCKET_MONITOR_EVENT_BIND_FAILED = 1u << 4,
ZLINK_SOCKET_MONITOR_EVENT_ACCEPTED = 1u << 5,
ZLINK_SOCKET_MONITOR_EVENT_ACCEPT_FAILED = 1u << 6,
ZLINK_SOCKET_MONITOR_EVENT_CLOSED = 1u << 7,
ZLINK_SOCKET_MONITOR_EVENT_CLOSE_FAILED = 1u << 8,
ZLINK_SOCKET_MONITOR_EVENT_DISCONNECTED = 1u << 9,
ZLINK_SOCKET_MONITOR_EVENT_MONITOR_STOPPED = 1u << 10,
ZLINK_SOCKET_MONITOR_EVENT_HANDSHAKE_FAILED_NO_DETAIL = 1u << 11,
ZLINK_SOCKET_MONITOR_EVENT_CONNECTION_READY = 1u << 12,
ZLINK_SOCKET_MONITOR_EVENT_HANDSHAKE_FAILED_PROTOCOL = 1u << 13,
ZLINK_SOCKET_MONITOR_EVENT_HANDSHAKE_FAILED_AUTH = 1u << 14,
ZLINK_SOCKET_MONITOR_EVENT_PEER_WEIGHT_CHANGED = 1u << 15,
ZLINK_SOCKET_MONITOR_EVENT_SEND_FLOW_PAUSED = 1u << 16, // Events owns the emission condition
ZLINK_SOCKET_MONITOR_EVENT_SEND_FLOW_RESUMED = 1u << 17, // Events owns the emission condition
ZLINK_SOCKET_MONITOR_EVENT_FLOW_STATE_STALE = 1u << 18, // Events owns the emission condition
ZLINK_SOCKET_MONITOR_EVENT_ALL = 0x7FFFFu, // Select every bit (0..18)
/* ZLINK_EVENT_* are shorter names with the same numeric values. */
ZLINK_EVENT_CONNECTED = ZLINK_SOCKET_MONITOR_EVENT_CONNECTED,
ZLINK_EVENT_CONNECT_DELAYED = ZLINK_SOCKET_MONITOR_EVENT_CONNECT_DELAYED,
ZLINK_EVENT_CONNECT_RETRIED = ZLINK_SOCKET_MONITOR_EVENT_CONNECT_RETRIED,
ZLINK_EVENT_LISTENING = ZLINK_SOCKET_MONITOR_EVENT_LISTENING,
ZLINK_EVENT_BIND_FAILED = ZLINK_SOCKET_MONITOR_EVENT_BIND_FAILED,
ZLINK_EVENT_ACCEPTED = ZLINK_SOCKET_MONITOR_EVENT_ACCEPTED,
ZLINK_EVENT_ACCEPT_FAILED = ZLINK_SOCKET_MONITOR_EVENT_ACCEPT_FAILED,
ZLINK_EVENT_CLOSED = ZLINK_SOCKET_MONITOR_EVENT_CLOSED,
ZLINK_EVENT_CLOSE_FAILED = ZLINK_SOCKET_MONITOR_EVENT_CLOSE_FAILED,
ZLINK_EVENT_DISCONNECTED = ZLINK_SOCKET_MONITOR_EVENT_DISCONNECTED,
ZLINK_EVENT_MONITOR_STOPPED = ZLINK_SOCKET_MONITOR_EVENT_MONITOR_STOPPED,
ZLINK_EVENT_HANDSHAKE_FAILED_NO_DETAIL =
ZLINK_SOCKET_MONITOR_EVENT_HANDSHAKE_FAILED_NO_DETAIL,
ZLINK_EVENT_CONNECTION_READY = ZLINK_SOCKET_MONITOR_EVENT_CONNECTION_READY,
ZLINK_EVENT_HANDSHAKE_FAILED_PROTOCOL =
ZLINK_SOCKET_MONITOR_EVENT_HANDSHAKE_FAILED_PROTOCOL,
ZLINK_EVENT_HANDSHAKE_FAILED_AUTH =
ZLINK_SOCKET_MONITOR_EVENT_HANDSHAKE_FAILED_AUTH,
ZLINK_EVENT_PEER_WEIGHT_CHANGED =
ZLINK_SOCKET_MONITOR_EVENT_PEER_WEIGHT_CHANGED,
ZLINK_EVENT_SEND_FLOW_PAUSED =
ZLINK_SOCKET_MONITOR_EVENT_SEND_FLOW_PAUSED,
ZLINK_EVENT_SEND_FLOW_RESUMED =
ZLINK_SOCKET_MONITOR_EVENT_SEND_FLOW_RESUMED,
ZLINK_EVENT_FLOW_STATE_STALE =
ZLINK_SOCKET_MONITOR_EVENT_FLOW_STATE_STALE,
ZLINK_EVENT_ALL = ZLINK_SOCKET_MONITOR_EVENT_ALL
} zlink_socket_monitor_event_e;
7.2 Event Record¶
typedef struct zlink_monitor_event_t {
uint64_t event; // ZLINK_SOCKET_MONITOR_EVENT_* value
uint64_t value; // Event-specific additional value (§3.2)
zlink_routing_id_t routing_id; // Routing ID for the event
char local_addr[256]; // Local address for the event
char remote_addr[256]; // Remote address for the event
uint64_t connection_id; // Physical transport-attempt ID in the current process (§3.1)
uint32_t transport_lane; // zlink_monitor_transport_lane_t value
uint32_t flags; // ZLINK_MONITOR_EVENT_FLAG_* bits
} zlink_monitor_event_t;
typedef enum zlink_monitor_transport_lane_e {
ZLINK_MONITOR_TRANSPORT_LANE_APPLICATION = 0, // Application lane; default for unpaired transports
ZLINK_MONITOR_TRANSPORT_LANE_COMPLETION = 1 // Completion lane
} zlink_monitor_transport_lane_t;
#define ZLINK_MONITOR_EVENT_FLAG_CONNECTION_READY_EDGE (1u << 0) // Ready edge that increased the count (§3.2)
#define ZLINK_MONITOR_EVENT_FLAG_SEND_FLOW_WRITABLE (1u << 1) // Receive-flow event only; see §3.2
#define ZLINK_MONITOR_EVENT_FLAG_FLOW_STATE_STALE_EPOCH (1u << 3) // Receive-flow event only; see §3.2
typedef zlink_monitor_event_t zlink_socket_monitor_event_t;
7.3 Enums Used by value¶
The ZLINK_DISCONNECT_* macros are ABI-preserving aliases for the corresponding
ZLINK_DISCONNECT_REASON_* enum values.
typedef enum zlink_disconnect_reason_t { // Value of a DISCONNECTED event (§3.2)
ZLINK_DISCONNECT_REASON_UNKNOWN = 0,
ZLINK_DISCONNECT_REASON_HANDSHAKE_FAILED = 3,
ZLINK_DISCONNECT_REASON_TRANSPORT_ERROR = 4,
ZLINK_DISCONNECT_REASON_CTX_TERM = 5
} zlink_disconnect_reason_t;
#define ZLINK_DISCONNECT_UNKNOWN ZLINK_DISCONNECT_REASON_UNKNOWN
#define ZLINK_DISCONNECT_HANDSHAKE_FAILED ZLINK_DISCONNECT_REASON_HANDSHAKE_FAILED
#define ZLINK_DISCONNECT_TRANSPORT_ERROR ZLINK_DISCONNECT_REASON_TRANSPORT_ERROR
#define ZLINK_DISCONNECT_CTX_TERM ZLINK_DISCONNECT_REASON_CTX_TERM
typedef enum zlink_protocol_error_t { // Value of a HANDSHAKE_FAILED_PROTOCOL event (§3.2)
ZLINK_PROTOCOL_ERROR_ZMP_MALFORMED_COMMAND_HELLO = 0x10000013,
ZLINK_PROTOCOL_ERROR_ZMP_MALFORMED_COMMAND_READY = 0x10000016
} zlink_protocol_error_t;
7.4 Open Options¶
typedef struct zlink_socket_monitor_open_options_t {
zlink_socket_monitor_event_mask_t events; // Event bits to receive; 0=none, EVENT_ALL=every bit (§2)
uint64_t monitor_hwm_bytes; // Single monitor-queue byte budget; 0=Core default (§5)
} zlink_socket_monitor_open_options_t;
7.5 Status Structure¶
#define ZLINK_MONITOR_STATUS_ABI_VERSION 4u // ABI version of the current status layout (§6.1)
typedef enum zlink_monitor_source_kind_t {
ZLINK_MONITOR_SOURCE_SOCKET = 1 // source_kind for a raw socket monitor
} zlink_monitor_source_kind_t;
typedef uint32_t zlink_monitor_state_mask_t;
typedef enum zlink_monitor_state_flag_e {
ZLINK_MONITOR_STATE_READY = 1u << 0,
ZLINK_MONITOR_STATE_BOUND_READY = 1u << 1,
ZLINK_MONITOR_STATE_CLOSED = 1u << 3
} zlink_monitor_state_flag_e;
typedef uint32_t zlink_monitor_status_detail_mask_t;
typedef enum zlink_monitor_status_detail_flag_e { // See the §6.2 table for fields valid under each bit
ZLINK_MONITOR_STATUS_DETAIL_SND_PENDING_MSGS = 1u << 1,
ZLINK_MONITOR_STATUS_DETAIL_RCV_PENDING_MSGS = 1u << 2,
ZLINK_MONITOR_STATUS_DETAIL_AUTO_HWM_BUDGET = 1u << 3,
ZLINK_MONITOR_STATUS_DETAIL_AUTO_HWM_BUFFERS = 1u << 4,
ZLINK_MONITOR_STATUS_DETAIL_FLOW_STATE = 1u << 5 // Only for DEALER and ROUTER, which support receive flow (§6.4)
} zlink_monitor_status_detail_flag_e;
typedef enum zlink_auto_hwm_recalc_reason_t { // Values for auto_hwm_last_recalc_reason
ZLINK_AUTO_HWM_RECALC_REASON_NONE = 0,
ZLINK_AUTO_HWM_RECALC_REASON_INITIAL = 1,
ZLINK_AUTO_HWM_RECALC_REASON_ROLE_CHANGE = 2,
ZLINK_AUTO_HWM_RECALC_REASON_POLICY_TOGGLE = 3,
ZLINK_AUTO_HWM_RECALC_REASON_REFRESH = 4,
ZLINK_AUTO_HWM_RECALC_REASON_DEFERRED_SHRINK = 5
} zlink_auto_hwm_recalc_reason_t;
typedef struct zlink_monitor_status_t {
uint32_t abi_version; // ABI version of the current layout returned by Core (diagnostic, §6.1)
uint32_t struct_size; // Full byte size of the returned ABI version
zlink_monitor_source_kind_t source_kind; // ZLINK_MONITOR_SOURCE_SOCKET for raw socket monitors
zlink_monitor_state_mask_t state_flags; // ZLINK_MONITOR_STATE_* bits
zlink_monitor_status_detail_mask_t detail_flags; // Groups of valid optional fields (§6.2)
uint64_t snd_pending_msgs; // Pending messages in the send direction (count)
uint64_t rcv_pending_msgs; // Pending messages in the receive direction (count; estimated for some sources)
uint64_t snd_pending_bytes; // Send in-flight byte total (§6.3)
uint64_t rcv_pending_bytes; // Receive in-flight byte total (§6.3)
uint32_t auto_hwm_enabled;
uint32_t auto_hwm_profile;
uint32_t auto_hwm_role;
uint32_t auto_hwm_policy_class;
uint64_t auto_hwm_planned_sndhwm_bytes; // planned: result of the current automatic policy (§6.3)
uint64_t auto_hwm_planned_rcvhwm_bytes;
uint64_t auto_hwm_applied_sndhwm_bytes; // applied: byte HWM actually used, including manual overrides (§6.3)
uint64_t auto_hwm_applied_rcvhwm_bytes;
int32_t auto_hwm_effective_sndbuf;
int32_t auto_hwm_effective_rcvbuf;
uint64_t auto_hwm_last_recalc_ms;
uint32_t auto_hwm_last_recalc_reason; // zlink_auto_hwm_recalc_reason_t value
uint32_t auto_hwm_send_blocked_ratio_ppm; // First send attempts blocked by HWM (ppm, §6.3)
uint64_t auto_hwm_deferred_sndhwm_bytes; // deferred: valid only when the matching _valid field is nonzero (§6.3)
uint64_t auto_hwm_deferred_rcvhwm_bytes;
uint32_t auto_hwm_deferred_sndhwm_valid;
uint32_t auto_hwm_deferred_rcvhwm_valid;
uint64_t snd_bytes_in_flight; // Directional send-pipe total at snapshot time
uint64_t rcv_bytes_in_flight; // Directional receive-pipe total at snapshot time
uint64_t minimum_core_message_charge_bytes; // Byte-accounting diagnostic (§6.3)
uint64_t oversize_message_admission_count; // Byte-accounting diagnostic (§6.3)
uint64_t oversize_message_admission_max_bytes;
/* Five receive-flow fields appended in version 4 (ZLINK_MONITOR_STATUS_DETAIL_FLOW_STATE, §6.4) */
uint64_t flow_paused_connections; // gauge: application pipes currently seen as remote-PAUSED.
// Increment by 1 for each applied PAUSED transition; decrement by 1
// for the matching RUNNING transition or when a PAUSED pipe terminates
uint64_t flow_pause_applied_total; // counter: PAUSED transitions actually applied since socket creation.
// Do not count stale, duplicate, or same-state frames
uint64_t flow_resume_applied_total; // counter: RUNNING transitions actually applied under the same rule.
// Do not count a pipe that terminates while PAUSED as a resume
uint64_t flow_state_stale_total; // counter: flow-state frames ignored as stale or duplicate
uint64_t flow_pause_duration_ms; // Length of the most recently completed PAUSED interval (ms); 0 if none.
// A pause ended by pipe termination also records its duration
} zlink_monitor_status_t;
8. Functions¶
The errno map owns the mapping between each result value and errno.
zlink_socket_monitor_open¶
Opens a raw socket monitor on the target socket.
ZLINK_EXPORT void *zlink_socket_monitor_open(
void *socket,
const zlink_socket_monitor_open_options_t *options);
The events mask in options selects the events to receive
(§2), and monitor_hwm_bytes sets the
monitor queue's byte budget (§5). This function, the open
options, and the status-structure layout follow §6.1: Core
does not add caller size/version negotiation or a parallel versioned entry point.
A socket can have one open monitor. A second open returns NULL with EBUSY while
preserving the existing handle and its event consumption.
Returns: A monitor handle on success; NULL on failure, with errno set.
Errors: If an HWM range or calculation or an allocation prevents monitor creation,
the function fails with NULL and errno. Core does not add a separate RESOURCE_LIMIT
configuration result or binding error type.
See also: zlink_monitor_close, zlink_monitor_status
zlink_socket_monitor_recv¶
Receives one event into a caller-owned structure (recv mode).
ZLINK_EXPORT zlink_recv_result_t zlink_socket_monitor_recv(
void *monitor,
zlink_socket_monitor_event_t *event_out,
zlink_recv_flags_t flags);
This function writes the complete current zlink_socket_monitor_event_t layout.
The caller must provide an output buffer sized for the current layout. Core does not
provide a separate receive entry point for the previous event prefix or a version-
negotiation path. The received event's addresses and routing ID are values inside the
caller-owned output structure.
Returns: A zlink_recv_result_t value.
Thread safety: Recv and close follow the single-consumer rule for the same event queue (§2).
See also: zlink_monitor_status, zlink_monitor_close
zlink_monitor_status¶
Queries the monitor's current status snapshot.
ZLINK_EXPORT zlink_config_result_t zlink_monitor_status(
void *monitor,
zlink_monitor_status_t *status_out);
This function fills status_out according to §6. abi_version and
struct_size diagnose the current layout returned by Core and are not caller inputs.
Optional fields absent from detail_flags are zero. The pipe-total field group is internally
consistent, and cross-consistency with the Auto HWM fields and flow counters is not guaranteed
(§6.3 owns the consistency scope and its mechanism).
If the source socket is closed first, the monitor handle stays valid until it is closed, but this
function returns ZLINK_CONFIG_NOT_SUPPORTED/ENOTSUP — the caller drains the remaining events
and then closes the monitor separately.
Returns: A zlink_config_result_t value.
See also: zlink_socket_monitor_open, zlink_ctx_get_auto_hwm_budget_snapshot
zlink_monitor_close¶
Closes the monitor.
Returns: A zlink_close_result_t value.
Thread safety: Recv and close follow the single-consumer rule for the same event queue (§2).
See also: zlink_socket_monitor_open
9. Implementation and Contract-Test Verification Requirements¶
Verify the following through the public surface only: the zlink_socket_monitor_* and
zlink_monitor_* functions, open options, event structure, status snapshot, return values,
and errno. Each item maps to one test.
Open and pull consumption
- A monitor opened with
events == 0receives no events, while one opened withEVENT_ALLreceives events for every bit. - If an HWM range or calculation or an allocation prevents monitor creation,
zlink_socket_monitor_openreturnsNULLand sets errno. No separateRESOURCE_LIMITconfiguration result or binding error type is observable. - A DONTWAIT call to
zlink_socket_monitor_recvwith no available event returnsZLINK_RECV_NO_DATAand leaves the event output unchanged. - The caller is responsible for single-consumer serialization of recv and close. Core neither detects nor serializes concurrent consumption by these two operations.
Event delivery and ordering
- Events from one monitor are ordered by the order in which Core commits state transitions. No wall-clock order is guaranteed across different connection I/O threads.
- When the monitor queue is full, it discards the newly arriving record regardless of event type and retains existing queue records. It does not aggregate events or preferentially retain event types, and it does not expose the discard count through a public counter or status field.
- A delayed monitor consumer does not block raw socket submission.
Event contents
- The
valueofDISCONNECTEDis azlink_disconnect_reason_tvalue, thevalueofHANDSHAKE_FAILED_PROTOCOLis azlink_protocol_error_tvalue, thevalueofPEER_WEIGHT_CHANGEDis the new0..10000weight, and thevalueof another failure event is the errno for that failure. - A malformed HELLO reports
ZLINK_PROTOCOL_ERROR_ZMP_MALFORMED_COMMAND_HELLO. A READY protocol error as defined by 01-zmp (missing, wrong-length, or wrong-valueZlink-Lane-CountorZlink-Lane, a count mismatch, lane1on count1, a duplicate or missing lane on count2, or a socket type orRouting-Idmismatch) reports aHANDSHAKE_FAILED_PROTOCOLevent whosevalueisZLINK_PROTOCOL_ERROR_ZMP_MALFORMED_COMMAND_READYbefore that physical connection'sDISCONNECTED. Neither case producesCONNECTION_READYor application payload. - When count
1for DEALER-DEALER or DEALER-ROUTER or count2for ROUTER-ROUTER becomes ready as one logical peer, theCONNECTION_READYready edge (ZLINK_MONITOR_EVENT_FLAG_CONNECTION_READY_EDGE) occurs exactly once and contributes exactly once to the count invalue. A ready-count event without the edge flag is a count snapshot. - Every physical event for DEALER-DEALER and DEALER-ROUTER has the Application value in
transport_lane; only a ROUTER-ROUTER Completion physical event reports Completion. connection_idis a diagnostic and correlation value; no public API uses it to select a send or reply target. A REQUEST completion does not return theconnection_idof the physical connection the request was admitted on or the reply was received on either (nor is a request guaranteed to use the same physical connection as its reply).CLOSEDreports that a TCP/IPC/WS/TLS connect attempt (connecter) or a listener closed the OS transport handle it owns. The end of an established connection is reported, for every transport, by a singleDISCONNECTED; a furtherCLOSEDfor that connection is not guaranteed (aCLOSEDobserved after a server close belongs to the failed new attempt of the automatic reconnect and carries the sameconnection_idas itsCONNECT_DELAYED). An inproc peer detach is reported asDISCONNECTEDand emits noCLOSED. While the connect intent remains, automatic reconnection continues afterDISCONNECTED.- When the peer of an established physical connection terminates,
DISCONNECTEDis observed once on the monitor even while no application DATA receive is in progress and received records remain queued (it doesn't depend on the receive drain).
Event-data ownership
zlink_socket_monitor_recvwrites the complete current layout to a caller-owned output structure, and the event addresses and routing ID are values inside that structure.
Status snapshot
- A raw socket monitor status has
source_kindset toZLINK_MONITOR_SOURCE_SOCKET,abi_versionset toZLINK_MONITOR_STATUS_ABI_VERSION, andstruct_sizeset to the full byte size of the returned ABI version. - Every optional field whose bit is absent from
detail_flagsis zero. ZLINK_MONITOR_STATUS_DETAIL_FLOW_STATEis set on DEALER-DEALER and DEALER-ROUTER count1sockets and ROUTER-ROUTER count2sockets. For other socket types, the bit is absent and all five flow fields are zero.- The Auto HWM snapshot uses ABI v1 with its defined field layout. Controlled DEALER-ROUTER
reply bytes appear only in Application accounting fields and
total_messaging_accounted_bytes, not in Completion current, peak, pending, or direction counts. - The three flow counters increase monotonically over the socket lifetime and do not change
when
zlink_ctx_reset_auto_hwm_budget_metricsis called. - The snapshot's pipe-total field group is internally consistent (for example, the in-flight totals match the sum over pipes), and no same-instant guarantee exists between it and the Auto HWM fields or flow counters.
Monitor queue budget
- A positive
monitor_hwm_bytesis used unchanged as the exact SNDHWM, RCVHWM, and worker admission limit.0is not unlimited; it selects the default byte value computed by Core (§5). - The worker makes admission decisions from the actual accounted bytes of each record, not from an event count, and applies the same one-oversize-record-on-empty rule.
- Auto HWM owns verification of monitor-queue exclusion from Auto HWM planning and context budget snapshot aggregation.