Skip to content

한국어 | English

Socket Index | Previous: PUB | Next: XPUB

Socket — SUB

What this chapter defines — the subscription behavior and public contract of a SUB socket.

1. SUB socket overview

SUB is a receive-only socket type that uses topic filtering to receive only subscribed messages. A topic is a sequence of classification bytes carried with a message, and SUB receives a message when its topic matches a registered subscription filter. SUB receives data only—PUB and XPUB publish it. Subscription management, such as registering and removing subscriptions, uses control-plane calls that configure and control the socket rather than the data plane that carries messages.

This document defines the SUB-specific contract: registering and removing subscription filters, filter matching rules, SUB-specific options (zlink_sub_option_t), the topic-and-payload receive function, and subscription inventory queries. These functions also apply to raw XSUB; XSUB defines XSUB-specific behavior.

The following documents own the related contracts.

Related contract Defining document
Common socket options (including RCVHWM and RCVBUF), lifetime, thread safety, and receive model Socket Common
Sockets that publish subscription messages and topic wire rules PUB, XPUB
Auto HWM budget calculation and admission Auto HWM
Message lifecycle and ownership Message

2. Subscriptions and filter matching

Subscriptions are managed by filter string.

  1. Registerzlink_set_subscription registers one filter as a subscription. The bytes before the terminating NUL form a byte prefix, and a message matches when its topic starts with those bytes. An empty string subscribes to every message. There is no wildcard syntax.
  2. Removezlink_unset_subscription removes a previously registered subscription using the same byte-prefix interpretation.
  3. Query — Read the number of subscribed topics through the read-only ZLINK_SUB_OPT_TOPICS_COUNT option, and read an individual filter by index through zlink_subscription_at.
  4. Receive — Receive the topic and complete payload record of a matching message through zlink_subscribe.

3. Automatic HWM defaults

Unless the application sets it directly, the context Auto HWM budget policy automatically calculates the byte limit (HWM) retained by the SUB receive queue.

SUB is classified as the recv_ingress role by the context Auto HWM policy. The active Auto HWM profile selects the Core memory-budget ratio and the per-role byte boundaries, and Core distributes that budget among unique physical directional queues. The default profile is balanced. If the user sets RCVHWM directly, that application direction is excluded from automatic distribution. RCVBUF is an OS socket-buffer option and is not changed by Auto HWM.

Auto HWM owns the exact budget-calculation and admission contract. Socket Common owns the RCVHWM and RCVBUF options themselves.

4. Receive flow state

DEALER and ROUTER report receive-flow state to peers that send to them. SUB 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 SUB socket and changes nothing.
  • The byte HWM, low water mark, and transport backpressure defined by Socket Common remain in effect.
  • A SUB 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.

Use these options with zlink_set_sub_option() / zlink_get_sub_option().

typedef enum zlink_sub_option_t
{
    ZLINK_SUB_OPT_TOPICS_COUNT = 0x3400  // Number of subscribed topics (int, read-only)
} zlink_sub_option_t;

6. Functions

Set a SUB/XSUB-specific socket option.

ZLINK_EXPORT zlink_config_result_t zlink_set_sub_option (void *handle_,
                           zlink_sub_option_t option_,
                           const void *optval_,
                           size_t optvallen_);

Configures a SUB/XSUB socket option. Use zlink_set_option() for common options shared across all socket types.

Returns: ZLINK_CONFIG_OK on success; otherwise a zlink_config_result_t value. zlink_errno() retains the detailed internal errno for diagnostics.

See also: zlink_get_sub_option, zlink_set_option


Get a SUB/XSUB-specific socket option.

ZLINK_EXPORT zlink_config_result_t zlink_get_sub_option (void *handle_,
                           zlink_sub_option_t option_,
                           void *optval_,
                           size_t *optvallen_);

Retrieves the current value of a SUB/XSUB socket option.

Returns: ZLINK_CONFIG_OK on success; otherwise a zlink_config_result_t value. zlink_errno() retains the detailed internal errno for diagnostics.

See also: zlink_set_sub_option


Subscribe to a topic filter.

ZLINK_EXPORT zlink_config_result_t zlink_set_subscription (void *handle_, const char *filter_);

Subscribes to messages matching filter_. filter_ is a NUL-terminated string and cannot contain an embedded NUL. The bytes before the terminating NUL form a byte-prefix filter, so a message matches when its topic starts with those bytes. An empty string subscribes to every message. There is no wildcard syntax; a trailing * is a literal byte.

Applicable types: raw SUB, raw XSUB.

Returns: ZLINK_CONFIG_OK on success; otherwise a zlink_config_result_t value. zlink_errno() retains the detailed internal errno for diagnostics.

Errors: EFAULT if handle_ is NULL. EINVAL if filter_ is NULL or the handle type does not support subscriptions.

See also: zlink_unset_subscription, zlink_subscribe


Unsubscribe from a topic filter.

ZLINK_EXPORT zlink_config_result_t zlink_unset_subscription (void *handle_, const char *filter_);

Removes a previously registered subscription. filter_ must be a NUL-terminated string without an embedded NUL. It uses the same byte-prefix interpretation as zlink_set_subscription(); the bytes before the terminating NUL must match a previously registered prefix.

Applicable types: raw SUB, raw XSUB.

Returns: ZLINK_CONFIG_OK on success; otherwise a zlink_config_result_t value. zlink_errno() retains the detailed internal errno for diagnostics.

Errors: EFAULT if handle_ is NULL. EINVAL if filter_ is NULL or the handle type does not support removing subscriptions.

See also: zlink_set_subscription


Receive the topic and complete payload record from a raw SUB or XSUB socket.

ZLINK_EXPORT zlink_recv_result_t zlink_subscribe (
  void *sub_,
  const zlink_routing_id_t **source_rid_out_,
  char *topic_id_buf_, size_t topic_id_capacity_, size_t *topic_id_len_out_,
  zlink_msg_t *parts_out_, size_t parts_capacity_, size_t *part_count_out_,
  zlink_recv_flags_t flags_);

topic_id_len_out_, parts_out_, and part_count_out_ are required. The array slots need not be initialized. source_rid_out_ is optional and always receives NULL for raw SUB and XSUB. On success, the function copies the binary topic bytes into the caller's buffer without a NUL byte and transfers the complete payload record into the array. The caller closes the leading *part_count_out_ slots exactly once with zlink_multipart_close.

If topic_id_capacity_ is smaller than the topic length (a zero-length topic succeeds with capacity 0), the function writes the required topic length to *topic_id_len_out_ and returns ZLINK_RECV_BUFFER_TOO_SMALL with ENOBUFS. Core keeps that message's topic and payload internally, leaves parts_out_ and every output other than topic_id_len_out_ unchanged, and does not transfer ownership of the slots. Calling again with a sufficient buffer returns the same retained message. If capacity is greater than zero but topic_id_buf_ is NULL, the function returns ZLINK_RECV_INVALID_HANDLE with EFAULT before inspecting or consuming the queue and leaves every output and parts_out_ unchanged.

If parts_capacity_ is smaller than the payload part count, the record is not consumed, the needed count is written to *part_count_out_, and the call returns ZLINK_RECV_BUFFER_TOO_SMALL with ENOBUFS. Other outputs and array slots are unchanged; retrying with a large enough array receives the same record. Applicable types are raw SUB and raw XSUB.


Retrieve the subscription filter at a given index.

ZLINK_EXPORT zlink_config_result_t zlink_subscription_at (void *handle_,
                           size_t index_,
                           char *filter_out_,
                           size_t *filter_len_inout_,
                           int *is_pattern_out_);

index_ is a zero-based index into a snapshot taken at query time and sorted in ascending lexicographic order by filter bytes, not registration order. On success, filter_out_ contains only the filter bytes and has no terminating NUL. This output is therefore not a C string. On entry, *filter_len_inout_ is the buffer size; on return, it is the filter length in bytes. is_pattern_out_ is an optional output and may be NULL. When provided, it reports whether the filter is a pattern subscription. All raw subscriptions are byte-prefix filters, so it receives 0.

If the buffer is too small, the function writes the required length to *filter_len_inout_ and returns ZLINK_CONFIG_BUFFER_TOO_SMALL with errno == ENOBUFS. It writes no partial data to filter_out_ and leaves *is_pattern_out_ unchanged. It does not consume or modify the subscription inventory, so the caller can retry the same index_ with a sufficient buffer.

Applicable types: raw SUB, raw XSUB.

Returns: ZLINK_CONFIG_OK on success; otherwise a zlink_config_result_t value. zlink_errno() retains the detailed internal errno for diagnostics.

Errors: ENOENT if the index is out of range. ENOBUFS if the buffer is too small. ENOTSUP if the handle type does not support subscription queries.

See also: zlink_set_subscription, zlink_get_sub_option

7. Implementation and contract test verification requirements

Verify the following through only the public surface: the subscription functions, SUB option set and get, zlink_subscribe results, return values, and errno. Each item maps to one unit test.

Subscription registration and removal

  • A filter registered through zlink_set_subscription matches by byte prefix—a message is received through zlink_subscribe when its topic begins with the filter bytes before the terminating NUL.
  • An empty-string filter subscribes to every message.
  • A filter with a trailing * matches * as a literal byte; it is not expanded as a wildcard.
  • zlink_unset_subscription removes the subscription whose previously registered prefix matches the filter bytes before the terminating NUL.
  • For zlink_set_subscription and zlink_unset_subscription, a NULL handle_ produces EFAULT; a NULL filter_ or a handle type that does not support subscription registration or removal produces EINVAL.

Subscription inventory queries

  • Reading the read-only ZLINK_SUB_OPT_TOPICS_COUNT through zlink_get_sub_option returns the number of subscribed topics as an int.
  • The zero-based index_ for zlink_subscription_at follows snapshot order sorted by filter bytes, not registration order. Each call takes a fresh snapshot, and that snapshot is not atomic with a ZLINK_SUB_OPT_TOPICS_COUNT query: if subscriptions change between the two calls, the same index_ may name a different filter or fail with ENOENT, so the caller serializes subscription changes while it reads the list.
  • On success, filter_out_ contains only the filter bytes and no terminating NUL. *filter_len_inout_ is that byte length, and filter_out_ is not a C string.
  • is_pattern_out_ is an optional output and may be NULL. When provided, it receives 0 because every raw subscription is a byte-prefix filter.
  • If the buffer is too small, the function writes the required length to *filter_len_inout_ and returns ZLINK_CONFIG_BUFFER_TOO_SMALL with ENOBUFS. It writes no partial data to filter_out_, leaves *is_pattern_out_ unchanged, and allows a retry of the same index_ with a sufficient buffer.
  • An out-of-range index produces ENOENT; a handle type that does not support subscription queries produces ENOTSUP.

Topic and payload-record receive

  • A successful zlink_subscribe copies the binary topic bytes into the caller's buffer without a NUL byte and fills the array with the complete payload record; the caller closes the leading *part_count_out_ slots exactly once with zlink_multipart_close.
  • On raw SUB and XSUB, source_rid_out_ always receives NULL.
  • If topic_id_capacity_ is smaller than the topic length (a zero-length topic succeeds with capacity 0), the function writes the required length to *topic_id_len_out_ and returns ZLINK_RECV_BUFFER_TOO_SMALL with ENOBUFS. Core retains that message's topic and payload internally, so a retry with a sufficient buffer receives the same message; parts_out_ and every output other than topic_id_len_out_ remain unchanged.
  • If parts_capacity_ is smaller than the payload part count, the call writes the needed count to *part_count_out_ and returns ZLINK_RECV_BUFFER_TOO_SMALL with ENOBUFS. The record and other outputs remain unchanged, and retrying with a large enough array receives the same record.
  • A record whose topic frame is not followed by a payload part (the topic frame lacks MORE) returns ZLINK_RECV_INTERNAL_ERROR with EPROTO.
  • If capacity is greater than zero but topic_id_buf_ is NULL, the function returns ZLINK_RECV_INVALID_HANDLE with EFAULT before inspecting or consuming the queue, and every output and parts_out_ remains unchanged.
  • All payload parts of a multipart message are returned in array order in one call, with no partial-record state.

Automatic HWM defaults

  • An application direction with an explicitly set RCVHWM is excluded from automatic distribution.
  • Auto HWM does not change RCVBUF.

Absence of receive flow state

  • Calling zlink_socket_set_receive_flow_state() on a SUB socket returns ZLINK_CONFIG_NOT_SUPPORTED with ENOTSUP and changes nothing.
  • A SUB 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.

Common return convention

  • The functions above that return zlink_config_result_t return ZLINK_CONFIG_OK on success and a zlink_config_result_t value on failure. zlink_errno() retains the detailed internal errno for diagnostics.

Auto HWM §5 owns verification of Auto HWM budget calculation and admission.

Socket Index | Previous: PUB | Next: XPUB