summaryrefslogtreecommitdiff
path: root/docs/reference
diff options
context:
space:
mode:
authorGarrett D'Amore <garrett@damore.org>2024-03-30 14:36:35 -0700
committerGarrett D'Amore <garrett@damore.org>2024-03-30 14:36:35 -0700
commitd38c90f0b429df3c13fb13f87481b73465d2eae5 (patch)
tree29b19caf79f82f9de3268333ceb8ffb3a45e973a /docs/reference
parentf1a8d00adad337d7e7ef24b936a3f046f80370dd (diff)
downloadnng-d38c90f0b429df3c13fb13f87481b73465d2eae5.tar.gz
nng-d38c90f0b429df3c13fb13f87481b73465d2eae5.tar.bz2
nng-d38c90f0b429df3c13fb13f87481b73465d2eae5.zip
Reorganization in progress.
Diffstat (limited to 'docs/reference')
-rw-r--r--docs/reference/book.toml24
-rw-r--r--docs/reference/src/SUMMARY.md17
-rw-r--r--docs/reference/src/api/socket/nng_pub_open.md2
-rw-r--r--docs/reference/src/proto/bus.md (renamed from docs/reference/src/protocols/bus.md)13
-rw-r--r--docs/reference/src/proto/index.md27
-rw-r--r--docs/reference/src/proto/pair.md100
-rw-r--r--docs/reference/src/proto/pub.md (renamed from docs/reference/src/protocols/pub.md)4
-rw-r--r--docs/reference/src/proto/pull.md39
-rw-r--r--docs/reference/src/proto/push.md54
-rw-r--r--docs/reference/src/proto/rep.md (renamed from docs/reference/src/protocols/rep.md)15
-rw-r--r--docs/reference/src/proto/req.md138
-rw-r--r--docs/reference/src/proto/respondent.md62
-rw-r--r--docs/reference/src/proto/sub.md70
-rw-r--r--docs/reference/src/proto/surveyor.md124
-rw-r--r--docs/reference/src/protocols/index.md1
-rw-r--r--docs/reference/src/refs.md50
-rw-r--r--docs/reference/src/transports/tcp.md8
17 files changed, 721 insertions, 27 deletions
diff --git a/docs/reference/book.toml b/docs/reference/book.toml
index 3a24d1f6..d6c1cff6 100644
--- a/docs/reference/book.toml
+++ b/docs/reference/book.toml
@@ -12,4 +12,28 @@ fold.level = 1
[preprocessor.indexing]
+[preprocessor.indexing.see_instead]
+
+# "*PULL* protocol" = "protocol, *PULL*"
+
+#"protocol, PUB" = "PUB"
+# "_PAIR_&zwj;" = "protocol, _PAIR_"
+
+[preprocessor.indexing.nest_under]
+# hacks to allow us to also place some entries underneath
+"*BUS*" = "protocol"
+"*PAIR*" = "protocol"
+"*PULL*" = "protocol"
+"*PUSH*" = "protocol"
+"*REQ*" = "protocol"
+"*REP*" = "protocol"
+"*PUB*" = "protocol"
+"*SUB*" = "protocol"
+"*SURVEYOR*" = "protocol"
+"*RESPONDENT*" = "protocol"
+
+"*tcp*" = "transport"
+
+"`tcp://`" = "URI"
+
[preprocessor.alerts]
diff --git a/docs/reference/src/SUMMARY.md b/docs/reference/src/SUMMARY.md
index 98d70ad7..99924f3d 100644
--- a/docs/reference/src/SUMMARY.md
+++ b/docs/reference/src/SUMMARY.md
@@ -6,11 +6,18 @@
- [RAW mode](./overview/raw.md)
-- [Protocols](./protocols/index.md)
-
- - [BUS](protocols/bus.md)
- - [PUB](protocols/pub.md)
- - [REP](protocols/rep.md)
+- [Protocols](./proto/index.md)
+
+ - [BUS](proto/bus.md)
+ - [PAIR](proto/pair.md)
+ - [PUB](proto/pub.md)
+ - [PULL](proto/pull.md)
+ - [PUSH](proto/push.md)
+ - [REP](proto/rep.md)
+ - [REQ](proto/req.md)
+ - [RESPONDENT](proto/respondent.md)
+ - [SUB](proto/sub.md)
+ - [SURVEYOR](proto/surveyor.md)
- [Transports](./transports/index.md)
diff --git a/docs/reference/src/api/socket/nng_pub_open.md b/docs/reference/src/api/socket/nng_pub_open.md
index cfbbb91e..18321896 100644
--- a/docs/reference/src/api/socket/nng_pub_open.md
+++ b/docs/reference/src/api/socket/nng_pub_open.md
@@ -2,7 +2,7 @@
## NAME
-nng_pub_open --- create _PUB_ socket
+nng*pub_open --- create \_PUB* socket
## SYNOPSIS
diff --git a/docs/reference/src/protocols/bus.md b/docs/reference/src/proto/bus.md
index 8583ed65..c68d9218 100644
--- a/docs/reference/src/protocols/bus.md
+++ b/docs/reference/src/proto/bus.md
@@ -1,7 +1,6 @@
# BUS Protocol
-{{hi:protocol, _BUS_}}
-The {{i:_BUS_ protocol}} provides for building mesh networks where
+The {{i:*BUS* protocol}}{{hi:*BUS*}} provides for building mesh networks where
every peer is connected to every other peer.
In this protocol, each message sent by a node is sent to every one of
its directly connected peers.
@@ -29,7 +28,7 @@ message cannot be delivered for any reason it is discarded.
## Socket Operations
-The [`nng_bus0_open()`](../api/nng_bus_open.md) functions create a bus socket.
+The [`nng_bus0_open()`][nng_bus_open] functions create a bus socket.
This socket may be used to send and receive messages.
Sending messages will attempt to deliver to each directly connected peer.
@@ -44,15 +43,17 @@ The _BUS_ protocol has no protocol-specific options.
## Protocol Headers
-When using a _BUS_ socket in [raw mode](../overview/raw.md), received messages will
-contain the incoming [pipe](../api/nng_pipe.md) ID as the sole element in the header.
+When using a _BUS_ socket in [raw mode][raw], received messages will
+contain the incoming [pipe][pipe] ID as the sole element in the header.
If a message containing such a header is sent using a raw _BUS_ socket, then,
the message will be delivered to all connected pipes _except_ the one
identified in the header.
-This behavior is intended for use with [device](../api/nng_device.md)
+This behavior is intended for use with [device][device]
configurations consisting of just a single socket.
Such configurations are useful in the creation of rebroadcasters, and this
capability prevents a message from being routed back to its source.
If no header is present, then a message is sent to all connected pipes.
When using normal (cooked mode) _BUS_ sockets, no message headers are present.
+
+{{#include ../refs.md}}
diff --git a/docs/reference/src/proto/index.md b/docs/reference/src/proto/index.md
new file mode 100644
index 00000000..d131c78f
--- /dev/null
+++ b/docs/reference/src/proto/index.md
@@ -0,0 +1,27 @@
+# Protocols
+
+{{hi:protocol}}
+The Scalability Protocols are a principally a collection of common networking
+patterns found in applications.
+
+The following patterns are included:
+
+## Request/Reply
+
+The {{i:request/reply pattern}} is made up of the [_REQ_][req] and [_REP_][rep] protocols.
+This most often used when implementing RPC-like services, where
+a given request is matched by a single reply.
+
+## Pipeline
+
+The {{i:pipeline pattern}} is made up of the [_PUSH_][push] and [_PULL_][pull]
+protocols.
+
+In this pattern communication is {{i:half-duplex}}, in that one side sends
+data and another side receives.
+
+This pattern is also characterized by its ability to solve distribution
+problems, and the fact that it has {{i:back-pressure}}, providing a measure
+of {{i:flow control}} to data production and consumption.
+
+{{#include ../refs.md}}
diff --git a/docs/reference/src/proto/pair.md b/docs/reference/src/proto/pair.md
new file mode 100644
index 00000000..5a7a92e4
--- /dev/null
+++ b/docs/reference/src/proto/pair.md
@@ -0,0 +1,100 @@
+# PAIR protocol
+
+The {{i:*PAIR* protocol}}{{hi:*PAIR*}} implements a peer-to-peer pattern, where
+relationships between peers are one-to-one.
+
+### Socket Operations
+
+The [`nng_pair_open()`][nng_pair_open] functions create a _PAIR_ socket.
+
+Normally, this pattern will block when attempting to send a message if
+no peer is able to receive the message.
+
+> [!NOTE]
+> Even though this mode may appear to be reliable, because back-pressure
+> prevents discarding messages most of the time, there are topologies involving
+> where messages may be discarded.
+> Applications that require reliable delivery semantics should consider using
+> [_REQ_][req] sockets, or implement their own acknowledgment layer on top of _PAIR_ sockets.
+
+### Protocol Versions
+
+Version 0 is the legacy version of this protocol.
+It lacks any header
+information, and is suitable when building simple one-to-one topologies.
+
+> [!TIP]
+> Use version 0 if you need to communicate with other implementations,
+> including the legacy [libnanomsg][nanomsg] library or
+> [mangos][mangos].
+
+Version 1 of the protocol offers improved protection against loops when
+used with [devices][device].
+
+### Polyamorous Mode
+
+> [!NOTE]
+> Polyamorous mode is deprecated, and support for it will likely
+> be removed in a future release, when a suitable mesh protocol is
+> available.
+> In the meantime, applications are encouraged to look to other patterns.
+
+Normally pair sockets are for one-to-one communication, and a given peer
+will reject new connections if it already has an active connection to another
+peer.
+
+_Polyamorous_{{hi:polyamorous mode}} changes this, to allow a socket to communicate with
+multiple directly-connected peers.
+This mode is enabled by opening a socket using
+[`nng_pair1_open_poly()`][nng_pair_open].
+
+> [!TIP]
+> Polyamorous mode is only available when using pair version 1.
+
+In polyamorous mode a socket can support many one-to-one connections.
+In this mode, the application must
+choose the remote peer to receive an outgoing message by setting the
+[`nng_pipe`][pipe] to use for the outgoing message using
+[`nng_msg_set_pipe()`][nng_msg_set_pipe].
+
+If no remote peer is specified by the sender, then the protocol will select
+any available connected peer.
+
+Most often the value of the outgoing pipe will be obtained from an incoming
+message using [`nng_msg_get_pipe()`][nng_msg_get_pipe],
+such as when replying to an incoming message.
+
+> [!NOTE]
+> Directed send _only_ works with directly connected peers.
+> It will not function across [device][device] proxies.
+
+In order to prevent head-of-line blocking, if the peer on the given pipe
+is not able to receive (or the pipe is no longer available, such as if the
+peer has disconnected), then the message will be discarded with no notification
+to the sender.
+
+### Protocol Options
+
+The following protocol-specific options are available.
+
+- [`NNG_OPT_MAXTTL`][NNG_OPT_MAXTTL]:
+ (`int`, version 1 only). Maximum time-to-live.
+
+- `NNG_OPT_PAIR1_POLY`:
+ (`bool`, version 1 only) This option is no longer supported.
+ Formerly it was used to configure _polyamorous_ mode, but that mode
+ is now established by using the `nng_pair1_open_poly()` function.
+
+### Protocol Headers
+
+Version 0 of the pair protocol has no protocol-specific headers.
+
+Version 1 of the pair protocol uses a single 32-bit unsigned value. The
+low-order (big-endian) byte of this value contains a "hop" count, and is
+used in conjunction with the
+[`NNG_OPT_MAXTTL`][NNG_OPT_MAXTTL] option to guard against
+device forwarding loops.
+This value is initialized to 1, and incremented each time the message is
+received by a new node.
+
+{{#include ../refs.md}}
diff --git a/docs/reference/src/protocols/pub.md b/docs/reference/src/proto/pub.md
index bd49b1d3..faa42e57 100644
--- a/docs/reference/src/protocols/pub.md
+++ b/docs/reference/src/proto/pub.md
@@ -1,6 +1,6 @@
# PUB Protocol
-The {{i:_PUB_ protocol}}{{hi:protocol, _PUB_} is one half of a {{i:publisher}}/subscriber pattern.
+The {{i:*PUB* protocol}}{{hi:*PUB*}} is one half of a {{i:publisher}}/subscriber pattern.
In this pattern, a publisher sends data, which is broadcast to all
subscribers.
The subscribing applications only see the data to which
@@ -22,7 +22,7 @@ Applications should construct their messages accordingly.
## Socket Operations
-The [`nng_pub0_open()`](../api/nng_pub_open.md) functions create a publisher socket.
+The [`nng_pub0_open()`][nng_pub_open] functions create a publisher socket.
This socket may be used to send messages, but is unable to receive them.
Attempts to receive messages will result in `NNG_ENOTSUP`.
diff --git a/docs/reference/src/proto/pull.md b/docs/reference/src/proto/pull.md
new file mode 100644
index 00000000..5aeeb9e6
--- /dev/null
+++ b/docs/reference/src/proto/pull.md
@@ -0,0 +1,39 @@
+# PULL protocol
+
+The {{i:*PULL* protocol}}{{hi:*PULL*}} is one half of a
+{{i:pipeline pattern}}.
+The other half is the [_PUSH_][push] protocol.
+
+In the pipeline pattern, pushers distribute messages to pullers.
+Each message sent
+by a pusher will be sent to one of its peer pullers,
+chosen in a round-robin fashion
+from the set of connected peers available for receiving.
+This property makes this pattern useful in {{i:load-balancing}} scenarios.
+
+### Socket Operations
+
+The [`nng_pull0_open()`][nng_pull_open] functions create a
+_PULL_ socket.
+This socket may be used to receive messages, but is unable to send them.
+Attempts to send messages will result in `NNG_ENOTSUP`.
+
+When receiving messages, the _PULL_ protocol accepts messages as
+they arrive from peers.
+If two peers both have a message ready, the
+order in which messages are handled is undefined.
+
+### Protocol Versions
+
+Only version 0 of this protocol is supported.
+(At the time of writing, no other versions of this protocol have been defined.)
+
+### Protocol Options
+
+The _PULL_ protocol has no protocol-specific options.
+
+### Protocol Headers
+
+The _PULL_ protocol has no protocol-specific headers.
+
+{{#include ../refs.md}}
diff --git a/docs/reference/src/proto/push.md b/docs/reference/src/proto/push.md
new file mode 100644
index 00000000..a22a73b5
--- /dev/null
+++ b/docs/reference/src/proto/push.md
@@ -0,0 +1,54 @@
+# PUSH protocol
+
+## DESCRIPTION
+
+The {{i:*PUSH* protocol}}{{hi:*PUSH*}} is one half of a {{i:pipeline pattern}}.
+The other side is the [_PULL_][pull] protocol.
+
+In the pipeline pattern, pushers distribute messages to pullers.
+Each message sent by a pusher will be sent to one of its peer pullers,
+chosen in a round-robin fashion
+from the set of connected peers available for receiving.
+This property makes this pattern useful in {{i:load-balancing}} scenarios.
+
+### Socket Operations
+
+The [`nng_push0_open()`][nng_push_open] call creates a _PUSH_ socket.
+This socket may be used to send messages, but is unable to receive them.
+Attempts to receive messages will result in `NNG_ENOTSUP`.
+
+Send operations will observe flow control (back-pressure), so that
+only peers capable of accepting a message will be considered.
+If no peer is available to receive a message, then the send operation will
+wait until one is available, or the operation times out.
+
+> [!NOTE]
+> Although the pipeline protocol honors flow control, and attempts
+> to avoid dropping messages, no guarantee of delivery is made.
+> Furthermore, as there is no capability for message acknowledgment,
+> applications that need reliable delivery are encouraged to consider the
+> [_REQ_][req] protocol instead.
+
+### Protocol Versions
+
+Only version 0 of this protocol is supported.
+(At the time of writing, no other versions of this protocol have been defined.)
+
+### Protocol Options
+
+- [`NNG_OPT_SENDBUF`][NNG_OPT_SENDBUF]:
+ (`int`, 0 - 8192)
+ Normally this is set to zero, indicating that send operations are unbuffered.
+ In unbuffered operation, send operations will wait until a suitable peer is available to receive the message.
+ If this is set to a positive value (up to 8192), then an intermediate buffer is
+ provided for the socket with the specified depth (in messages).
+
+> [!NOTE]
+> Transport layer buffering may occur in addition to any socket
+> buffer determined by this option.
+
+### Protocol Headers
+
+The _PUSH_ protocol has no protocol-specific headers.
+
+{{#include ../refs.md}}
diff --git a/docs/reference/src/protocols/rep.md b/docs/reference/src/proto/rep.md
index cb602e47..d34e2fca 100644
--- a/docs/reference/src/protocols/rep.md
+++ b/docs/reference/src/proto/rep.md
@@ -1,7 +1,6 @@
# REP Protocol
-{{hi:protocol, _REP_}}
-The {{i:_REP_ protocol}} is one half of a {{i:request/reply pattern}}.
+The {{i:*REP* protocol}}{{hi:*REP*}} is one half of a {{i:request/reply pattern}}.
In this pattern, a requester sends a message to one replier, who
is expected to reply.
The request is resent if no reply arrives,
@@ -13,11 +12,11 @@ until a reply is received or the request times out.
> a reply is received.
The _REP_ protocol is the replier side, and the
-[_REP_](req.md) protocol is the requester side.
+[_REP_][req] protocol is the requester side.
## Socket Operations
-The [`nng_rep0_open()`](nng_rep_open.md) functions create a replier socket.
+The [`nng_rep0_open()`][nng_rep_open] functions create a replier socket.
This socket may be used to receive messages (requests), and then to send
replies.
@@ -29,11 +28,11 @@ was previously received.
Likewise, only one receive operation may be pending at a time.
Any additional concurrent receive operations will result in `NNG_ESTATE`.
-[Raw](../overview/raw.md) mode sockets ignore all these restrictions.
+[Raw mode][raw] sockets ignore all these restrictions.
## Context Operations
-This protocol supports the creation of [contexts](../api/nng_ctx.md) for concurrent use cases using [`nng_ctx_open()`](../api/nng_ctx_open.md).
+This protocol supports the creation of [contexts][context] for concurrent use cases using [`nng_ctx_open()`][nng_ctx_open].
Each context may have at most one outstanding request, and operates
independently of the others.
@@ -53,4 +52,6 @@ The _REP_ protocol has no protocol-specific options.
## Protocol Headers
The _REP_ protocol uses a {{ii:backtrace}} in the header.
-This is more fully documented in the [_REQ_](req.md) chapter.
+This is more fully documented in the [_REQ_][req] chapter.
+
+{{#include ../refs.md}}
diff --git a/docs/reference/src/proto/req.md b/docs/reference/src/proto/req.md
new file mode 100644
index 00000000..f6c1f994
--- /dev/null
+++ b/docs/reference/src/proto/req.md
@@ -0,0 +1,138 @@
+# REQ protocol
+
+The {{i:*REQ* protocol}}{{hi:*REQ*}} is one half of a {{i:request/reply pattern}}.
+In this pattern, a requester sends a message to one replier, who
+is expected to reply.
+The request is resent if no reply arrives,
+until a reply is received or the request times out.
+
+> [!TIP]
+> This protocol is useful in setting up RPC-like services.
+> It is also "reliable", in that a the requester will keep retrying until
+> a reply is received.
+
+> [!NOTE]
+> Because requests are resent, it is important that they be {{i:idempotent}}
+> to ensure predictable and repeatable behavior even in the face of duplicated
+> requests, which can occur (for example if a reply message is lost for
+> some reason.)
+
+{{hi: load-balancing}}
+The requester generally only has one outstanding request at a time unless
+in [raw mode][raw],
+and it will generally attempt to spread work requests to different peer repliers.
+
+> [!TIP]
+> This property, when combined with a [device][device]
+> can help provide a degree of load-balancing.
+
+The _REQ_ protocol is the requester side, and the [_REP_][rep] protocol
+is the replier side.
+
+### Socket Operations
+
+The [`nng_req0_open()`][nng_req_open] functions create a _REQ_ socket.
+This socket may be used to send messages (requests), and then to receive replies.
+
+Generally a reply can only be received after sending a request.
+(Attempts to receive a message will result in `NNG_ESTATE` if there is no
+outstanding request.)
+
+Furthermore, only a single receive operation may be pending at a time.
+Attempts to post more receive operations concurrently will result in
+`NNG_ESTATE`.
+
+Requests may be canceled by sending a different request.
+This will cause the requester to discard any reply from the earlier request,
+but it will not stop a replier
+from processing a request it has already received or terminate a request
+that has already been placed on the wire.
+
+[Raw mode][raw] sockets ignore all these restrictions.
+
+### Context Operations
+
+This protocol supports the creation of [contexts][context] for concurrent
+use cases using [`nng_ctx_open()`][nng_ctx_open].
+
+The `NNG_OPT_REQ_RESENDTIME` value may be configured differently
+on contexts created this way.
+
+Each context may have at most one outstanding request, and operates
+independently from the others.
+
+The restrictions for order of operations with sockets apply equally
+well for contexts, except that each context will be treated as if it were
+a separate socket.
+
+### Protocol Versions
+
+Only version 0 of this protocol is supported.
+(At the time of writing, no other versions of this protocol have been defined.)
+
+### Protocol Options
+
+The following protocol-specific option is available.
+
+- {{i:`NNG_OPT_REQ_RESENDTIME`}}: \
+ ([`nng_duration`][duration]) \
+ When a new request is started, a timer of this duration is also started.
+ If no reply is received before this timer expires, then the request will
+ be resent. \
+ \
+ Requests are also automatically resent if the peer to whom
+ the original request was sent disconnects. \
+ \
+ Resending may be deferred up to the value of the `NNG_OPT_RESENDTICK` parameter. \
+ \
+ If the value is set to [`NNG_DURATION_INFINITE`][duration], then resends are disabled
+ altogether. This should be used when the request is not idemptoent.
+
+- {{i:`NNG_OPT_REQ_RESENDTICK`}}: \
+ ([`nng_duration`][duration]) \
+ This is the granularity of the clock that is used to check for resending.
+ The default is a second. Setting this to a higher rate will allow for
+ more timely resending to occur, but may incur significant additional
+ overhead when the socket has many outstanding requests (contexts). \
+ \
+ When there are no requests outstanding that have a resend set, then
+ the clock does not tick at all. \
+ \
+ This option is shared for all contexts on a socket, and is only available for the socket itself.
+
+### Protocol Headers
+
+This protocol uses a {{ii:backtrace}} in the header.
+This form uses a stack of 32-bit big-endian identifiers.
+There _must_ be at least one identifier, the **request ID**, which will be the
+last element in the array, and _must_ have the most significant bit set.
+
+There may be additional **peer ID**s preceding the request ID.
+These will be distinguishable from the request ID by having their most
+significant bit clear.
+
+When a request message is received by a forwarding node (such as a [device][device]),
+the forwarding node prepends a
+32-bit peer ID (which _must_ have the most significant bit clear),
+which is the forwarder's way of identifying the directly connected
+peer from which it received the message.
+(This peer ID, except for the
+most significant bit, has meaning only to the forwarding node itself.)
+
+It may help to think of prepending a peer ID as pushing a peer ID onto the
+front of the stack of headers for the message.
+(It will use the peer ID
+it popped from the front to determine the next intermediate destination
+for the reply.)
+
+When a reply message is created, it is created using the same headers
+that the request contained.
+
+A forwarding node can pop the peer ID it originally pushed on the
+message, stripping it from the front of the message as it does so.
+
+When the reply finally arrives back at the initiating requester, it
+should have only a single element in the message, which will be the
+request ID it originally used for the request.
+
+{{#include ../refs.md}}
diff --git a/docs/reference/src/proto/respondent.md b/docs/reference/src/proto/respondent.md
new file mode 100644
index 00000000..e3f14eba
--- /dev/null
+++ b/docs/reference/src/proto/respondent.md
@@ -0,0 +1,62 @@
+# RESPONDENT protocol
+
+The {{i:*RESPONDENT* protocol}}{{hi:*RESPONDENT*}} is one half of a {{i:survey pattern}}.
+In this pattern, a surveyor sends a survey, which is broadcast to all
+peer respondents.
+The respondents then have a chance to reply (but are not obliged to reply).
+The survey itself is a timed event, so that responses
+received after the survey has finished are discarded.
+
+> [!TIP]
+> This protocol is useful in solving voting problems, such as leader
+> election in cluster configurations, as well as certain kinds of service
+> discovery problems.
+
+The _RESPONDENT_ protocol is the respondent side, and the
+[_SURVEYOR_][surveyor] protocol is the surveyor side.
+
+### Socket Operations
+
+The [`nng_respondent0_open()`][nng_respondent_open] functions create a
+respondent socket.
+This socket may be used to receive messages, and then to send replies.
+A reply can only be sent after receiving a survey, and generally the
+reply will be sent to surveyor from whom the last survey was received.
+
+Respondents may discard a survey by simply not replying to it.
+
+[Raw mode][raw] sockets ignore all these restrictions.
+
+### Context Operations
+
+This protocol supports the creation of [contexts][context] for concurrent
+use cases using [`nng_ctx_open()`][nng_ctx_open].
+
+Incoming surveys will be routed to and received by only one context.
+Additional surveys may be received by other contexts in parallel.
+Replies made using a context will be returned to the the surveyor that
+issued the survey most recently received by that context.
+The restrictions for order of operations with sockets apply equally
+well for contexts, except that each context will be treated as if it were
+a separate socket.
+
+### Protocol Versions
+
+Only version 0 of this protocol is supported.
+At the time of writing, no other versions of this protocol have been defined. [^1]
+
+[^1]:
+ An earlier and incompatible version of the protocol was used in older
+ pre-releases of [nanomsg][nanomsg], but was not released in any
+ production version.
+
+### Protocol Options
+
+The _respondent_ protocol has no protocol-specific options.
+
+### Protocol Headers
+
+The _RESPONDENT_ protocol uses a {{ii:backtrace}} in the header.
+This is more fully documented in the [_SURVEYOR_][surveyor] manual.
+
+{{#include ../refs.md}}
diff --git a/docs/reference/src/proto/sub.md b/docs/reference/src/proto/sub.md
new file mode 100644
index 00000000..c87db7e8
--- /dev/null
+++ b/docs/reference/src/proto/sub.md
@@ -0,0 +1,70 @@
+# SUB protocol
+
+The {{i:*SUB* protocol}}{{hi:*SUB*}} is one half of a publisher/{{i:subscriber}} pattern.
+In this pattern, a publisher sends data, which is broadcast to all subscribers.
+The subscribing applications only see the data to which they have subscribed.
+
+The _SUB_ protocol is the subscriber side, and the
+[_PUB_][pub] protocol is the publisher side.
+
+> [!NOTE]
+> The publisher delivers all messages to all subscribers.
+> The subscribers maintain their own subscriptions, and filter them locally.
+> Thus, this pattern should not be used in an attempt to
+> reduce bandwidth consumption.
+
+The topics that subscribers subscribe to is compared to the leading bytes of
+the message body.
+Applications should construct their messages accordingly.
+
+### Socket Operations
+
+The [`nng_sub0_open()`][nng_sub_open] functions create a _SUB_ socket.
+This socket may be used to receive messages, but is unable to send them.
+Attempts to send messages will result in `NNG_ENOTSUP`.
+
+### Protocol Versions
+
+Only version 0 of this protocol is supported.
+(At the time of writing, no other versions of this protocol have been defined.)
+
+### Protocol Options
+
+The following protocol-specific options are available.
+
+- {{i:`NNG_OPT_SUB_SUBSCRIBE`}}{{hi:subscribe}}: \
+ \
+ This option registers a topic that the subscriber is interested in.
+ The option is write-only, and takes an array of bytes, of arbitrary size.
+ Each incoming message is checked against the list of subscribed topics.
+ If the body begins with the entire set of bytes in the topic, then the
+ message is accepted. If no topic matches, then the message is
+ discarded. \
+ \
+ This option is a byte array. Thus if you use
+ [`nng_socket_set_string()`][nng_socket_set] the `NUL` terminator byte will
+ be included in the topic.
+ If that isn't desired, consider using
+ [`nng_socket_set()`][nng_socket_set] and using `strlen()` of the topic
+ as the topic size. \
+ \
+ To receive all messages, an empty topic (zero length) can be used.
+
+- {{i:`NNG_OPT_SUB_UNSUBSCRIBE`}}: \
+ \
+ This option, also read-only, removes a topic from the subscription list.
+ Note that if the topic was not previously subscribed to with
+ `NNG_OPT_SUB_SUBSCRIBE` then an `NNG_ENOENT` error will result.
+
+- {{i:`NNG_OPT_SUB_PREFNEW`}}: \
+ (`bool`) \
+ \
+ This read/write option specifies the behavior of the subscriber when the queue is full.
+ When `true` (the default), the subscriber will make room in the queue by removing the oldest message.
+ When `false`, the subscriber will reject messages if the message queue does not have room.
+
+### Protocol Headers
+
+The _SUB_ protocol has no protocol-specific headers.
+
+{{#include ../refs.md}}
diff --git a/docs/reference/src/proto/surveyor.md b/docs/reference/src/proto/surveyor.md
new file mode 100644
index 00000000..91be9228
--- /dev/null
+++ b/docs/reference/src/proto/surveyor.md
@@ -0,0 +1,124 @@
+# SURVEYOR protocol
+
+The {{i:*SURVEYOR* protocol}}{{hi:*SURVEYOR*}} is one half of a {{i:survey pattern}}.
+In this pattern, a surveyor sends a survey, which is broadcast to all
+peer respondents.
+The respondents then have a chance, but are not obliged, to reply.
+The survey itself is a timed event, so that responses
+received after the survey has finished are discarded.
+
+> [!TIP]
+> This protocol is useful in solving {{i:voting}} problems, such as
+> {{i:leader election}} in cluster configurations,
+> as well as certain kinds of {{i:service discovery}} problems.
+
+The _SURVEYOR_ protocol is the surveyor side, and the
+[_RESPONDENT_][respondent] protocol is the respondent side.
+
+### Socket Operations
+
+The [`nng_surveyor0_open()`][nng_surveyor_open]
+functions create a surveyor socket.
+This socket may be used to send messages (surveys), and then to receive replies.
+A reply can only be received after sending a survey.
+A surveyor can normally expect to receive at most one reply from each responder.
+(Messages can be duplicated in some topologies,
+so there is no guarantee of this.)
+
+Attempts to receive on a socket with no outstanding survey will result
+in `NNG_ESTATE`.
+If the survey times out while the surveyor is waiting
+for replies, then the result will be `NNG_ETIMEDOUT`.
+
+Only one survey can be outstanding at a time; sending another survey will
+cancel the prior one, and any responses from respondents from the prior
+survey that arrive after this will be discarded.
+
+[Raw mode][raw] sockets ignore all these restrictions.
+
+### Context Operations
+
+This protocol supports the creation of [contexts][context] for concurrent
+use cases using [`nng_ctx_open()`][nng_ctx_open].
+
+Each context can initiate its own surveys, and it will receive only
+responses to its own outstanding surveys.
+Other contexts on the same socket may have overlapping surveys
+operating at the same time.
+
+Each of these may have their own timeouts established with
+`NNG_OPT_SURVEYOR_SURVEYTIME`.
+
+Additionally, sending a survey on a context will only cancel an outstanding
+survey on the same context.
+
+> [!NOTE]
+> Due to the best-effort nature of this protocol, if too may contexts
+> are attempting to perform surveys simultaneously, it is possible for either
+> individual outgoing surveys or incoming responses to be lost.
+
+### Protocol Versions
+
+Only version 0 of this protocol is supported.
+At the time of writing, no other versions of this protocol have been defined. [^1]
+
+[^1]:
+ An earlier and incompatible version of the protocol was used in older
+ pre-releases of [nanomsg][nanomsg], but was not released in any production
+ version.
+
+### Protocol Options
+
+The following protocol-specific option is available.
+
+- {{i:`NNG_OPT_SURVEYOR_SURVEYTIME`}}: \
+ ([`nng_duration`][duration]) \
+ \
+ When a new survey is started, a timer of this duration is started.
+ Any responses arriving this time will be discarded.
+ Attempts to receive
+ after the timer expires with no other surveys started will result in
+ `NNG_ESTATE`.\
+ \
+ If a receive is pending when this timer expires, it will result in
+ `NNG_ETIMEDOUT`.
+
+### Protocol Headers
+
+{{hi:backtrace}}
+This form uses a stack of 32-bit big-endian identifiers.
+There _must_ be at least one identifier, the **survey ID**, which will be the
+last element in the array, and _must_ have the most significant bit set.
+
+There may be additional **peer ID**s preceding the survey ID.
+These will be distinguishable from the survey ID by having their most
+significant bit clear.
+
+When a survey message is received by a forwarding node (such as a
+[device][device]),
+the forwarding node prepends a
+32-bit peer ID (which _must_ have the most significant bit clear),
+which is the forwarder's way of identifying the directly connected
+peer from which it received the message.
+(This peer ID, except for the
+most significant bit, has meaning only to the forwarding node itself.)
+
+It may help to think of prepending a peer ID as pushing a peer ID onto the
+front of the stack of headers for the message.
+(It will use the peer ID
+it popped from the front to determine the next intermediate destination
+for the response.)
+
+When a response message is created, it is created using the same headers
+that the survey contained.
+
+A forwarding node can pop the peer ID it originally pushed on the
+message, stripping it from the front of the message as it does so.
+
+When the response finally arrives back at the initiating surveyor, it
+should have only a single element in the message, which will be the
+survey ID it originally used for the request.
+
+More detail can be found in the [sp-surveyor-01 RFC][survey_rfc] document.
+
+{{#include ../refs.md}}
diff --git a/docs/reference/src/protocols/index.md b/docs/reference/src/protocols/index.md
deleted file mode 100644
index 8d9f7317..00000000
--- a/docs/reference/src/protocols/index.md
+++ /dev/null
@@ -1 +0,0 @@
-# Protocols
diff --git a/docs/reference/src/refs.md b/docs/reference/src/refs.md
new file mode 100644
index 00000000..d1201354
--- /dev/null
+++ b/docs/reference/src/refs.md
@@ -0,0 +1,50 @@
+<!-- Concepts -->
+
+[context]: ../overview/context.md
+[device]: ../overview/device.md
+[duration]: ../overview/duration.md
+[msg]: ../overview/msg.md
+[pipe]: ../overview/pipe.md
+[raw]: ../overview/raw.md
+[url]: ../overview/url.md
+
+<!-- Protocols -->
+
+[bus]: ../proto/bus.md
+[pair]: ../proto/pair.md
+[pub]: ../proto/pub.md
+[pull]: ../proto/pull.md
+[push]: ../proto/push.md
+[req]: ../proto/req.md
+[rep]: ../proto/rep.md
+[respondent]: ../proto/respondent.md
+[sub]: ../proto/sub.md
+[surveyor]: ../proto/surveyor.md
+
+<!-- API -->
+
+[nng_bus_open]: ../api/nng_bus_open.md
+[nng_ctx_open]: ../api/nng_ctx_open.md
+[nng_msg_get_pipe]: ../api/nng_msg_get_pipe.md
+[nng_msg_set_pipe]: ../api/nng_msg_set_pipe.md
+[nng_pair_open]: ../api/nng_pair_open.md
+[nng_pub_open]: ../api/nng_pub_open.md
+[nng_pull_open]: ../api/nng_pull_open.md
+[nng_push_open]: ../api/nng_push_open.md
+[nng_rep_open]: ../api/nng_rep_open.md
+[nng_req_open]: ../api/nng_req_open.md
+[nng_respondent_open]: ../api/nng_respondent_open.md
+[nng_socket_set]: ../api/nng_socket_set.md
+[nng_surveyor_open]: ../api/nng_surveyor_open.md
+[nng_sub_open]: ../api/nng_sub_open.md
+
+<!-- Options -->
+
+[NNG_OPT_MAXTTL]: ../opts/nng_opt_max_ttl.md
+[NNG_OPT_SENDBUF]: ../opts/nng_opt_sendbuf.md
+
+<!-- External -->
+
+[mangos]: http://github.com/nanomsg/mangos
+[nanomsg]: http://github.com/nanomsg/nanomsg
+[survey_rfc]: https://github.com/nanomsg/nanomsg/blob/master/rfc/sp-surveyor-01.txt
diff --git a/docs/reference/src/transports/tcp.md b/docs/reference/src/transports/tcp.md
index 1e05e7b7..a710ea23 100644
--- a/docs/reference/src/transports/tcp.md
+++ b/docs/reference/src/transports/tcp.md
@@ -1,17 +1,15 @@
# TCP transport
-{{hi: transport, _tcp_}}
-The {{i:_tcp_ transport}} provides communication support between
+The {{i:*tcp* transport}}{{hi:*tcp*}} provides communication support between
sockets across a {{i:TCP/IP}} network.
Both IPv4 and IPv6 are supported when the underlying platform also supports it.
## URI Format
-{{hi:URI, `tcp://`}}
-This transport uses URIs using the scheme `tcp://`, followed by
+This transport uses URIs using the scheme {{i:`tcp://`}}, followed by
an IP address or hostname, followed by a colon and finally a
-TCP port number.{{hi:port number, TCP}}
+TCP {{i:port number}}.
For example, to contact port 80 on the localhost either of the following URIs
could be used: `tcp://127.0.0.1:80` or `tcp://localhost:80`.