Overview

RAW mode

Most applications will use sockets in normal, or cooked, mode. This mode provides the full semantics of the protocol. For example, REQ sockets will automatically match a reply to a request, and resend requests periodically if no reply was received.

There are situations, such as with proxies, where it is desirable to bypass these semantics and simply pass messages to and from the socket with no extra semantic handling. This is possible using raw mode sockets.

Raw mode sockets are generally constructed with a different function, such as nng_req0_open_raw(). Using these sockets, the application can simply send and receive messages, and is responsible for supplying any additional socket semantics. Typically this means that the application will need to inspect message headers on incoming messages, and supply them on outgoing messages.

tip

The nng_device() function only works with raw mode sockets, but as it only forwards the messages, no additional application processing is needed.

Protocols

The Scalability Protocols are a principally a collection of common networking patterns found in applications.

The following patterns are included:

Request/Reply

The request/reply pattern is made up of the REQ and REP protocols. This most often used when implementing RPC-like services, where a given request is matched by a single reply.

Pipeline

The pipeline pattern is made up of the PUSH and PULL protocols.

In this pattern communication is 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 back-pressure, providing a measure of flow control to data production and consumption.

BUS Protocol

The BUS protocol 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.

tip

Messages are only sent to directly connected peers. This means that in the event that a peer is connected indirectly, it will not receive messages. When using this protocol to build mesh networks, it is therefore important that a fully-connected mesh network be constructed.

All message delivery in this pattern is best-effort, which means that peers may not receive messages. Furthermore, delivery may occur to some, all, or none of the directly connected peers. (Messages are not delivered when peer nodes are unable to receive.) Hence, send operations will never block; instead if the message cannot be delivered for any reason it is discarded.

tip

In order to minimize the likelihood of message loss, this protocol should not be used for high throughput communications. Furthermore, the more traffic in aggregate that occurs across the topology, the more likely that message loss is to occur.

Socket Operations

The nng_bus0_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.

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 BUS protocol has no protocol-specific options.

Protocol Headers

When using a BUS socket in raw mode, received messages will contain the incoming 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 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.

PAIR protocol

The PAIR protocol implements a peer-to-peer pattern, where relationships between peers are one-to-one.

Socket Operations

The 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 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 library or mangos.

Version 1 of the protocol offers improved protection against loops when used with devices.

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 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().

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 to use for the outgoing message using 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(), such as when replying to an incoming message.

note

Directed send only works with directly connected peers. It will not function across 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: (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 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.

PUB Protocol

The PUB protocol is one half of a 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 they have subscribed.

The PUB protocol is the publisher side, and the SUB protocol is the subscriber side.

note

In this implementation, 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 just the first part of the message body. Applications should construct their messages accordingly.

Socket Operations

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.

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 PUB protocol has no protocol-specific options.

Protocol Headers

The PUB protocol has no protocol-specific headers.

PULL protocol

The PULL protocol is one half of a pipeline pattern. The other half is the 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 load-balancing scenarios.

Socket Operations

The nng_pull0_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.

PUSH protocol

DESCRIPTION

The PUSH protocol is one half of a pipeline pattern. The other side is the 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 load-balancing scenarios.

Socket Operations

The nng_push0_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 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: (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.

REP Protocol

The REP protocol is one half of a 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 requester will keep retrying until a reply is received.

The REP protocol is the replier side, and the REP protocol is the requester side.

Socket Operations

The nng_rep0_open() functions create a replier socket. This socket may be used to receive messages (requests), and then to send replies.

Generally a reply can only be sent after receiving a request.

Send operations will result in NNG_ESTATE if no corresponding request 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 mode sockets ignore all these restrictions.

Context Operations

This protocol supports the creation of contexts for concurrent use cases using nng_ctx_open().

Each context may have at most one outstanding request, and operates independently of 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 REP protocol has no protocol-specific options.

Protocol Headers

The REP protocol uses a backtrace in the header. This is more fully documented in the REQ chapter.

REQ protocol

The REQ protocol is one half of a 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 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.)

The requester generally only has one outstanding request at a time unless in raw mode, and it will generally attempt to spread work requests to different peer repliers.

tip

This property, when combined with a device can help provide a degree of load-balancing.

The REQ protocol is the requester side, and the REP protocol is the replier side.

Socket Operations

The nng_req0_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 sockets ignore all these restrictions.

Context Operations

This protocol supports the creation of contexts for concurrent use cases using 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.

  • NNG_OPT_REQ_RESENDTIME:
    (nng_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, then resends are disabled altogether. This should be used when the request is not idemptoent.

  • NNG_OPT_REQ_RESENDTICK:
    (nng_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 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 IDs 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), 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.

RESPONDENT protocol

The RESPONDENT protocol is one half of a 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 protocol is the surveyor side.

Socket Operations

The nng_respondent0_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 sockets ignore all these restrictions.

Context Operations

This protocol supports the creation of contexts for concurrent use cases using 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, 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 backtrace in the header. This is more fully documented in the SURVEYOR manual.

SUB protocol

The SUB protocol is one half of a 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 they have subscribed.

The SUB protocol is the subscriber side, and the 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() 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.

  • NNG_OPT_SUB_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() the NUL terminator byte will be included in the topic. If that isn’t desired, consider using 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.

  • 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.

  • 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.

SURVEYOR protocol

The SURVEYOR protocol is one half of a 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 voting problems, such as leader election in cluster configurations, as well as certain kinds of service discovery problems.

The SURVEYOR protocol is the surveyor side, and the RESPONDENT protocol is the respondent side.

Socket Operations

The nng_surveyor0_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 sockets ignore all these restrictions.

Context Operations

This protocol supports the creation of contexts for concurrent use cases using 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, but was not released in any production version.

Protocol Options

The following protocol-specific option is available.

  • NNG_OPT_SURVEYOR_SURVEYTIME:
    (nng_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

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 IDs 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), 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 document.

Transports

This chapter provides information about the various transports that NNG supports. Transports may be thought of as different underlying communications technologies, such as TCP, Websockets, and so forth.

INPROC

The inproc transport provides intra-process communication within a single process.

TCP

The tcp transport provides communication over TCP/IP networks.

IPC Transport

DESCRIPTION

The ipc transport provides communication support between sockets within different processes on the same host. For POSIX platforms, this is implemented using UNIX domain sockets. For Windows, this is implemented using Windows named pipes. Other platforms may have different implementation strategies.

URI Formats

Traditional Names

This transport uses URIs using the scheme ipc://, followed by a path name in the file system where the socket or named pipe should be created.

tip

On Windows, all names are prefixed by \\.\pipe\ and do not reside in the normal file system. On POSIX platforms, the path is taken literally, and is relative to the current directory, unless it begins with /, in which case it is relative to the root directory.

note

When using relative paths on POSIX systems, the address used and returned in properties like NNG_OPT_LOCADDR and NNG_OPT_URL will also be relative. Consequently, they will only be interpreted the same by processes that have the same working directory. To ensure maximum portability and safety, absolute paths are recommended whenever possible.

note

If compatibility with legacy nanomsg applications is required, then path names must not be longer than 122 bytes, including the final NUL byte. This is because legacy versions of nanomsg cannot express URLs longer than 128 bytes, including the ipc:// prefix.

UNIX Aliases

The unix:// scheme is an alias for ipc:// and can be used inter-changeably, but only on POSIX systems.1

1

The purpose of this scheme is to support a future transport making use of AF_UNIX on Windows systems, at which time it will be necessary to discriminate between the Named Pipes and the AF_UNIX based transports.

Abstract Names

On Linux, this transport also can support abstract sockets. Abstract sockets use a URI-encoded name after the abstract:// scheme, which allows arbitrary values to be conveyed in the path, including embedded NUL bytes. For example, the name "a\0b" would be represented as abstract://a%00b.

tip

An empty name may be used with a listener to request “auto bind” be used to select a name. In this case the system will allocate a free name. The name assigned may be retrieved using NNG_OPT_LOCADDR.

Abstract names do not include the leading NUL byte used in the low-level socket address.

Abstract sockets do not have any representation in the file system, and are automatically freed by the system when no longer in use.

Abstract sockets ignore socket permissions, but it is still possible to determine the credentials of the peer with NNG_OPT_PEER_UID, and similar options.2

2

This property makes it important that names be chosen randomly to prevent unauthorized access, or that checks against the peer credentials are made, or ideally, both.

Socket Address

When using an nng_sockaddr structure, the actual structure is of type nng_sockaddr_ipc, except for abstract sockets, which use nng_sockaddr_abstract.

Transport Options

The following transport options are supported by this transport, where supported by the underlying platform.

INPROC Transport

The inproc transport{{intra-process}} provides communication support between sockets within the same process. This may be used as an alternative to slower transports when data must be moved within the same process.

This transport tries hard to avoid copying data, and thus is very light-weight.

URI Format

This transport uses URIs using the scheme inproc://, followed by an arbitrary string of text, terminated by a NUL byte.

Multiple URIs can be used within the same application, and they will not interfere with one another.

Two applications may also use the same URI without interfering with each other, and they will be unable to communicate with each other using that URI.

Socket Address

When using an nng_sockaddr structure, the actual structure is of type nng_sockaddr_inproc.

Transport Options

The inproc transport has no special options.

note

While inproc accepts the option [NNG_OPT_RECVMAXSZ] for compatibility, the value of the option is ignored with no enforcement. As inproc peers are in the same address space, they are implicitly trusted, so the protection afforded by NNG_OPT_RECVMAXSZ is unnecessary.

Mixing Implementations

When mixing the NNG library with other implementations of these protocols in the same process (such as the mangos or libnanomsg implementations), it will not be possible to utilize the inproc transport to communicate across this boundary.

This limitation also extends to using different instances of the NNG library within the same process.

TCP transport

The tcp transport provides communication support between sockets across a TCP/IP network.

Both IPv4 and IPv6 are supported when the underlying platform also supports it.

URI Format

This transport uses URIs using the scheme tcp://, followed by an IP address or hostname, followed by a colon and finally a TCP 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.

A URI may be restricted to IPv6 using the scheme tcp6://, and may be restricted to IPv4 using the scheme tcp4://.

note

Specifying tcp6:// may not prevent IPv4 hosts from being used with IPv4-in-IPv6 addresses, particularly when using a wildcard hostname with listeners. The details of this varies across operating systems.

note

Both tcp6:// and tcp4:// are specific to NNG, and might not be understood by other implementations.

tip

We recommend using either numeric IP addresses, or names that are specific to either IPv4 or IPv6 to prevent confusion and surprises.

When specifying IPv6 addresses, the address must be enclosed in square brackets ([]) to avoid confusion with the final colon separating the port.

For example, the same port 80 on the IPv6 loopback address (::1) would be specified as tcp://[::1]:80.

The special value of 0 (INADDR_ANY) can be used for a listener to indicate that it should listen on all interfaces on the host. A short-hand for this form is to either omit the address, or specify the asterisk (*) character. For example, the following three URIs are all equivalent, and could be used to listen to port 9999 on the host:

  1. tcp://0.0.0.0:9999
  2. tcp://*:9999
  3. tcp://:9999

The entire URI must be less than NNG_MAXADDRLEN bytes long.

Socket Address

When using an nng_sockaddr structure, the actual structure is either of type nng_sockaddr_in (for IPv4) or nng_sockaddr_in6 (for IPv6).

Transport Options

The following transport options are supported by this transport, where supported by the underlying platform.

BSD Socket Transport (Experimental)

The socket transport supports communication between peers across arbitrary BSD sockets, such as those that are created with nng_socket_pair().

This transport only supports listeners, using [nng_listener_create()][nng_listener_create].

note

Attempts to create dialers using this transport will result in NNG_ENOTSUP.

The socket file descriptor is passed to the listener using the NNG_OPT_SOCKET_FD option (as an integer). Setting this option will cause the listener to create a pipe backed by the file descriptor.

The protocol between peers using this transport is compatible with the protocol used for the tcp transport, but this is an implementation detail and subject to change without notice.1

1

Specifically it is not compatible with the ipc transport.

note

This transport is experimental, and at present is only supported on POSIX platforms.2

2

Windows lacks a suitable socketpair() equivalent function we could use.

Registration

No special action is necessary to register this transport.

URI Format

This transport uses the URL socket://, without further qualification.

Socket Address

The socket address will be of family NNG_AF_UNSPEC. There are no further socket details available.

Transport Options

The following transport option is available:

  • NNG_OPT_SOCKET_FD:
    (int)

    This is a write-only option, that may be set multiple times on a listener. Each time this is set, the listener will create a pipe backed by the given file descriptor passed as an argument.

Additionally, the following options may be supported on pipes when the platform supports them:

API Reference

This chapter documents the functions and data structures that make up the NNG programming interface.

note

Interfaces not documented here are not considered public or stable, and they may be removed or altered in incompatible ways at any time.

We have organized the reference material along general functional areas. They are:

Messages

Messages in Scalability Protocols are the fundamental unit of transmission and reception, as these protocols are fundamentally message-oriented.

Message object

An nng_msg represents a single message sent between Scalability Protocols peers.

Messages have a body, containing the application supplied payload, and a header, containing protocol specific routing and similar related information.

tip

Only applications using raw mode need to access the message header.

Creating, Destroying and Using

Messages are allocated using nng_msg_alloc(), and are deallocated using nng_msg_free().

In addition there are other functions used to access message contents, including adding data to either the beginning or end of the message, automatic data conversion, and removing data from the beginning or end.

Performance Considerations

While there are convenience wrappers for sending and receiving arrays of bytes, using message objects directly when possible will give better performance by reducing data copies and needless allocations.

These functions are designed to try to avoid copying message contents by making use of scratch areas at the beginning and end of the message. These scratch areas, the “headroom” and “tailroom”, are automatically included when allocating a message.

Direct Use Forbidden

The nng_msg structure is opaque, and applications should never try to rely on the size of it, nor access internal members directly. This insulates the application from changes in subsequent NNG versions that would affect the binary representation of the nng_msg itself.

Examples

Example 1: Preparing a message for use

    #include <nng/nng.h>

    nng_msg *m;
    if (nng_msg_alloc(&m, strlen("content") + 1) != 0) {
       // handle error
    }
    strcpy(nng_msg_body(m), "content");

Example 2: Preallocating message content

    if (nng_msg_alloc(&m, 1024) != 0) {
        // handle error
    }
    while ((val64 = next_datum()) != 0) P
        if (nng_msg_append_u64(m, val64) != 0) {
            // handle error
        }
    }

See Also

nng_aio_get_msg, nng_aio_set_msg, nng_msg_alloc, nng_msg_append, nng_msg_body, nng_msg_capacity, nng_msg_dup, nng_msg_free, nng_msg_header, nng_msg_header_append, nng_msg_header_chop, nng_msg_header_clear, nng_msg_header_insert, nng_msg_header_len, nng_msg_header_trim, nng_msg_insert, nng_msg_len, nng_msg_reserve, nng_msg_realloc, nng_msg_set_pipe, nng_msg_trim, nng_recvmsg, nng_sendmsg

nng_msg_alloc

NAME

nng_msg_alloc — allocate a message

SYNOPSIS

#include <nng/nng.h>

int nng_msg_alloc(nng_msg **msgp, size_t size);

DESCRIPTION

The nng_msg_alloc() function allocates a new message with body length size and stores the result in msgp. Messages allocated with this function contain a body and optionally a header. They are used with receive and transmit functions.

RETURN VALUES

This function returns 0 on success, and non-zero otherwise.

ERRORS

  • NNG_ENOMEM: Insufficient free memory exists to allocate a message.

SEE ALSO

nng_msg_free, nng_msg_body, nng_msg_dup, nng_msg_header, nng_msg_header_len, nng_msg_len, nng_msg_capacity, nng_msg_reserve, nng_msg_realloc

nng_msg_append

NAME

nng_msg_append — append to message body

SYNOPSIS

#include <nng/nng.h>

int nng_msg_append(nng_msg *msg, const void *val, size_t size);
int nng_msg_append_u16(nng_msg *msg, uint16_t val16);
int nng_msg_append_u32(nng_msg *msg, uint32_t val32);
int nng_msg_append_u64(nng_msg *msg, uint64_t val64);

DESCRIPTION

The nng_msg_append() family of functions appends data to the end of the body of message msg, reallocating it if necessary. The first function appends size bytes, copying them from val. The remaining functions append the value specified (such as val32) in network-byte order (big-endian).

RETURN VALUES

These functions return 0 on success, and non-zero otherwise.

ERRORS

  • NNG_ENOMEM: Insufficient free memory exists.

SEE ALSO

nng_msg_alloc, nng_msg_body, nng_msg_capacity, nng_msg_chop, nng_msg_clear, nng_msg_free, nng_msg_insert, [nng_msg_len][nng_msg_len.md], nng_msg_reserve, nng_msg_realloc, nng_msg_trim

nng_msg_body

NAME

nng_msg_body — return message body

SYNOPSIS

#include <nng/nng.h>

void *nng_msg_body(nng_msg *msg);

DESCRIPTION

The nng_msg_body() function returns a pointer to the start of the body content of the message msg.

note

The value returned by this is invalidated by a call to any of the functions that modify the message itself. Such functions are nng_msg_free(), nng_msg_realloc(), any of the nng_msg_trim(), nng_msg_chop(), nng_msg_append(), or nng_msg_insert() variants.

RETURN VALUES

Pointer to start of message body.

SEE ALSO

nng_msg_alloc, nng_msg_append, nng_msg_capacity, nng_msg_chop, nng_msg_clear, nng_msg_free, nng_msg_insert, nng_msg_len, nng_msg_reserve, nng_msg_realloc, nng_msg_trim

nng_msg_capacity

NAME

nng_msg_capacity — return message body length

SYNOPSIS

#include <nng/nng.h>

size_t nng_msg_capacity(nng_msg *msg);

DESCRIPTION

The nng_msg_capacity() returns the storage allocated for the body of message msg. The capacity includes the current contents of the message and free space after it. The message body may grow to capacity without performing any further allocations.

RETURN VALUES

Allocated capacity for message body.

SEE ALSO

nng_msg_alloc, nng_msg_realloc, nng_msg_reserve nng_msg_body

nng_msg_chop

NAME

nng_msg_chop — remove data from end of message body

SYNOPSIS

#include <nng/nng.h>

int nng_msg_chop(nng_msg *msg, size_t size);
int nng_msg_chop_u16(nng_msg *msg, uint16_t *val16);
int nng_msg_chop_u32(nng_msg *msg, uint32_t *val32);
int nng_msg_chop_u64(nng_msg *msg, uint64_t *val64);

DESCRIPTION

The nng_msg_chop() family of functions removes data from the end of the body of message msg. The first function removes size bytes. The remaining functions remove 2, 4, or 8 bytes, and stores them in the value (such as val32), after converting them from network-byte order (big-endian) to native byte order.

RETURN VALUES

These functions return 0 on success, and non-zero otherwise.

ERRORS

  • NNG_EINVAL: The message body is too short to remove the requested data.

SEE ALSO

nng_msg_alloc, nng_msg_append, nng_msg_body, nng_msg_capacity, nng_msg_clear, nng_msg_free, nng_msg_insert, nng_msg_len, nng_msg_reserve, nng_msg_realloc, nng_msg_trim

nng_msg_clear

NAME

nng_msg_clear — clear message body content

SYNOPSIS

#include <nng/nng.h>

void nng_msg_clear(nng_msg *msg);

DESCRIPTION

The nng_msg_clear() function resets the body length of message msg to zero.

SEE ALSO

nng_msg_alloc, nng_msg_capacity, nng_msg_reserve

nng_msg_dup

NAME

nng_msg_dup — duplicate a message

SYNOPSIS

#include <nng/nng.h>

int nng_msg_dup(nng_msg **dup, nng_msg_t *orig);

DESCRIPTION

The nng_msg_dup() makes a duplicate of the original message orig, and saves the result in the location pointed by dup. The actual message body and header content is copied, but the duplicate may contain a different amount of unused space than the original message.

RETURN VALUES

This function returns 0 on success, and non-zero otherwise.

ERRORS

  • NNG_ENOMEM: Insufficient free memory exists to duplicate a message.

SEE ALSO

nng_msg_alloc, nng_msg_free

nng_msg_free

NAME

nng_msg_free — free a message

SYNOPSIS

#include <nng/nng.h>

void nng_msg_free(nng_msg *msg);

DESCRIPTION

The nng_msg_free() function deallocates the message msg entirely.

SEE ALSO

nng_msg_alloc, nng_msg_realloc

nng_msg_get_pipe

NAME

nng_msg_get_pipe — get pipe for message

SYNOPSIS

#include <nng/nng.h>

nng_pipe nng_msg_get_pipe(nng_msg *msg);

DESCRIPTION

The nng_msg_get_pipe() returns the nng_pipe object associated with message msg. On receive, this is the pipe from which a message was received. On transmit, this would be the pipe that the message should be delivered to, if a specific peer is required.

note

Not all protocols support overriding the destination pipe.

The most usual use case for this is to obtain information about the peer from which the message was received. This can be used to provide different behaviors for different peers, such as a higher level of authentication for peers located on an untrusted network. The [nng_pipe_get()][nng_pipe_get] function is useful in this situation.

RETURN VALUES

This function returns the pipe associated with this message, which will be a positive value. If the pipe is non-positive, then that indicates that no specific pipe is associated with the message.

SEE ALSO

nng_msg_alloc, nng_msg_set_pipe, [nng_pipe_get][nng_pipe_get]

nng_msg_header

NAME

nng_msg_header — return message header

SYNOPSIS

#include <nng/nng.h>

void *nng_msg_header(nng_msg *msg);

DESCRIPTION

The nng_msg_header() function returns a pointer to the start of the header content of the message msg.

note

The message header contains protocol-specific header content. Most applications should not need to access this content, but it is available for raw mode sockets.

note

The value returned by this is invalidated by a call to any of the functions that modify the message or the header content.

RETURN VALUES

Pointer to start of message header.

SEE ALSO

nng_msg_alloc, nng_msg_body, nng_msg_free, nng_msg_header_append, nng_msg_header_chop, nng_msg_header_insert nng_msg_header_len, nng_msg_header_trim

nng_msg_header_append

NAME

nng_msg_header_append — append to message header

SYNOPSIS

#include <nng/nng.h>

int nng_msg_header_append(nng_msg *msg, const void *val, size_t size);
int nng_msg_header_append_u16(nng_msg *msg, uint16_t val16);
int nng_msg_header_append_u32(nng_msg *msg, uint32_t val32);
int nng_msg_header_append_u64(nng_msg *msg, uint64_t val64);

DESCRIPTION

The nng_msg_header_append() family of functions appends data to the end of the header of message msg, reallocating it if necessary. The first function appends size bytes, copying them from val.

The remaining functions append the value (such as val32) in network-byte order (big-endian).

RETURN VALUES

These functions return 0 on success, and non-zero otherwise.

ERRORS

  • NNG_ENOMEM: Insufficient free memory exists.

SEE ALSO

nng_msg_header, nng_msg_header_chop, nng_msg_header_insert nng_msg_header_len, nng_msg_header_trim

nng_msg_header_chop

NAME

nng_msg_header_chop — remove data from end of message header

SYNOPSIS

#include <nng/nng.h>

int nng_msg_header_chop(nng_msg *msg, size_t size);
int nng_msg_header_chop_u16(nng_msg *msg, uint16_t *val16);
int nng_msg_header_chop_u32(nng_msg *msg, uint32_t *val32);
int nng_msg_header_chop_u64(nng_msg *msg, uint64_t *val64);

DESCRIPTION

The nng_msg_header_chop() family of functions removes data from the end of the header of message msg. The first function removes size bytes. The remaining functions remove 2, 4, or 8 bytes, and stores them in the value (such as val32), after converting them from network-byte order (big-endian) to native byte order.

RETURN VALUES

These function return 0 on success, and non-zero otherwise.

ERRORS

  • NNG_EINVAL: The message header is too short to remove the requested data.

SEE ALSO

nng_msg_header, nng_msg_header_append, nng_msg_header_insert nng_msg_header_len, nng_msg_header_trim

nng_msg_header_clear

NAME

nng_msg_header_clear — clear message header

SYNOPSIS

#include <nng/nng.h>

void nng_msg_header_clear(nng_msg *msg);

DESCRIPTION

The nng_msg_clear() function resets the header length of messaage msg to zero.

SEE ALSO

nng_msg_header, nng_msg_header_len

nng_msg_header_insert

NAME

nng_msg_header_insert — prepend to message header

SYNOPSIS

#include <nng/nng.h>

int nng_msg_header_insert(nng_msg *msg, const void *val, size_t size);
int nng_msg_header_insert_u16(nng_msg *msg, uint16_t val16);
int nng_msg_header_insert_u32(nng_msg *msg, uint32_t val32);
int nng_msg_header_insert_u64(nng_msg *msg, uint64_t val64);

DESCRIPTION

The nng_msg_header_insert() family of functions prepends data to the front of the headers of message msg, reallocating if necessary. The first function prepends size bytes, copying them from val. The remaining functions prepend the specified value (such as val32) in network-byte order (big-endian).

RETURN VALUES

These functions return 0 on success, and non-zero otherwise.

ERRORS

  • NNG_ENOMEM: Insufficient free memory exists.

SEE ALSO

nng_msg_header, nng_msg_header_append nng_msg_header_chop, nng_msg_header_len, nng_msg_header_trim

nng_msg_header_len

NAME

nng_msg_header_len — return message header length

SYNOPSIS

#include <nng/nng.h>

size_t nng_msg_header_len(nng_msg *msg);

DESCRIPTION

The nng_msg_header_len() returns the length of the header of message msg.

RETURN VALUES

Length of message header.

SEE ALSO

nng_msg_header

nng_msg_header_trim

NAME

nng_msg_header_trim — remove data from start of message header

SYNOPSIS

#include <nng/nng.h>

int nng_msg_header_trim(nng_msg *msg, size_t size);
int nng_msg_header_trim_u16(nng_msg *msg, uint16_t *val16);
int nng_msg_header_trim_u32(nng_msg *msg, uint32_t *val32);
int nng_msg_header_trim_u64(nng_msg *msg, uint64_t *val64);

DESCRIPTION

The nng_msg_header_trim() family of functions remove data from the start of the header of message msg. The first function removes size bytes. The remaining functions removes 2, 4, or 8 bytes, and stores them in the value (such as val32), after converting them from network-byte order (big-endian) to native byte order.

RETURN VALUES

This function returns 0 on success, and non-zero otherwise.

ERRORS

  • NNG_EINVAL: The message header is too short to remove the requested data.

SEE ALSO

nng_msg_header, nng_msg_header_append, nng_msg_header_chop nng_msg_header_insert nng_msg_header_len,

nng_msg_insert

NAME

nng_msg_insert — prepend to message body

SYNOPSIS

#include <nng/nng.h>

int nng_msg_insert(nng_msg *msg, const void *val, size_t size);
int nng_msg_insert_u16(nng_msg *msg, uint16_t val16);
int nng_msg_insert_u32(nng_msg *msg, uint32_t val32);
int nng_msg_insert_u64(nng_msg *msg, uint64_t val64);

DESCRIPTION

The nng_msg_insert() family of functions prepends data to the front of the body of message msg, reallocating it if necessary. The first function prepends size bytes, copying them from val. The remaining functions prepend the specified value (such as val32) in network-byte order (big-endian).

tip

These functions make use of space pre-allocated in front of the message body if available, so they can often avoid performing any reallocation. Applications should use these instead of reallocating and copying message content themselves, in order to benefit from this capability.

RETURN VALUES

These functions return 0 on success, and non-zero otherwise.

ERRORS

  • NNG_ENOMEM: Insufficient free memory exists.

SEE ALSO

nng_msg_alloc, nng_msg_append, nng_msg_body, nng_msg_capacity, nng_msg_chop, nng_msg_clear, nng_msg_free, nng_msg_insert, nng_msg_len, nng_msg_reserve, nng_msg_realloc, nng_msg_trim

nng_msg_len

NAME

nng_msg_len — return message body length

SYNOPSIS

#include <nng/nng.h>

size_t nng_msg_len(nng_msg *msg);

DESCRIPTION

The nng_msg_len() returns the length of the body of message msg.

RETURN VALUES

Length of message body.

SEE ALSO

nng_msg_alloc, nng_msg_body

nng_msg_realloc(3)

NAME

nng_msg_realloc — reallocate a message

SYNOPSIS

#include <nng/nng.h>

int nng_msg_realloc(nng_msg *msg, size_t size);

DESCRIPTION

The nng_msg_realloc() function re-allocates a [message][] so that it has a body of length size. This message attempts to avoid extra allocations, and will reuse the existing memory when possible.

TIP: nng_msg_realloc is suitable for creating space for direct writing of data. When appending many small pieces of data to a message using nng_msg_append(), allocations may be reduced by first using nng_msg_reserve() to create sufficient space. In any case, reallocating or appending to a message is guaranteed to succeed if the resulting body length is less than nng_msg_capacity().

note

Pointers to message body and header content obtained prior to this function must not be in use, as the underlying memory used for the message may have changed, particularly if the message size is increasing.

RETURN VALUES

This function returns 0 on success, and non-zero otherwise.

ERRORS

  • NNG_ENOMEM: Insufficient free memory exists to reallocate a message.

SEE ALSO

nng_msg_alloc, nng_msg_reserve, nng_msg_append, nng_msg_body, nng_msg_chop, nng_msg_free, nng_msg_insert, nng_msg_len, nng_msg_trim

nng_msg_reserve

NAME

nng_msg_reserve — reserve storage for a message

SYNOPSIS

#include <nng/nng.h>

int nng_msg_reserve(nng_msg *msg, size_t capacity);

DESCRIPTION

The nng_msg_reserve() function ensures a message has allocated enough storage to accommodate a body of the given length. This message attempts to avoid extra allocations, and will reuse the existing memory when possible.

tip

Using this message before nng_msg_append() will prevent additional memory allocations until the message’s length exceeds the alotted capacity.

important

Pointers to message body and header content obtained prior to this function must not be in use, as the underlying memory used for the message may have changed, particularly if the message capacity is increasing.

RETURN VALUES

This function returns 0 on success, and non-zero otherwise.

ERRORS

  • NNG_ENOMEM: Insufficient free memory exists to reallocate a message.

SEE ALSO

nng_msg_alloc, nng_msg_append, nng_msg_capacity, nng_msg_insert, nng_msg_len

nng_msg_set_pipe

NAME

nng_msg_set_pipe — set pipe for message

SYNOPSIS

#include <nng/nng.h>

void nng_msg_set_pipe(nng_msg *msg, nng_pipe p);

DESCRIPTION

The nng_msg_set_pipe() sets the pipe associated with message m to p. This is most often useful when used with protocols that support directing a message to a specific peer. For example the PAIR version 1 protocol can do this when NNG_OPT_PAIR1_POLY mode is set.

note

Not all protocols support overriding the destination pipe.

SEE ALSO

nng_msg_alloc, nng_msg_get_pipe

nng_msg_trim

NAME

nng_msg_trim — remove data from start of message body

SYNOPSIS

#include <nng/nng.h>

int nng_msg_trim(nng_msg *msg, size_t size);
int nng_msg_trim_u16(nng_msg *msg, uint16_t *val16);
int nng_msg_trim_u32(nng_msg *msg, uint32_t *val32);
int nng_msg_trim_u64(nng_msg *msg, uint64_t *val64);

DESCRIPTION

The nng_msg_trim() family of functions removes data from the start of the body of message msg. The first function removes size bytes. The remaining functions remove 2, 4, or 8 bytes, and stores them in the value (such as val32), after converting them from network-byte order (big-endian) to native byte order.

RETURN VALUES

These functions return 0 on success, and non-zero otherwise.

ERRORS

  • NNG_EINVAL: The message body is too short to remove the requested data.

SEE ALSO

nng_msg_alloc, nng_msg_append, nng_msg_body, nng_msg_capacity, nng_msg_chop nng_msg_clear, nng_msg_free, nng_msg_insert, nng_msg_len, nng_msg_reserve, nng_msg_realloc

Sockets

See Also

nng_bus_open, nng_close, nng_pair_open, nng_pub_open, nng_sub_open, nng_surveyor_open

nng_bus_open

NAME

nng_bus_open — create BUS socket

SYNOPSIS

#include <nng/nng.h>
#include <nng/protocol/bus0/bus.h>

int nng_bus0_open(nng_socket *s);

int nng_bus0_open_raw(nng_socket *s);

DESCRIPTION

The nng_bus0_open() function creates a BUS version 0 socket and returns it at the location pointed to by s.

The nng_bus0_open_raw() function creates a BUS version 0 socket in raw mode, and returns it at the location pointed to by s.

RETURN VALUES

These functions return 0 on success, and non-zero otherwise.

ERRORS

  • NNG_ENOMEM: Insufficient memory is available.
  • NNG_ENOTSUP: The protocol is not supported.

SEE ALSO

BUS protocol, RAW mode

nng_close

NAME

nng_close — close socket

SYNOPSIS

#include <nng/nng.h>

int nng_close(nng_socket s);

DESCRIPTION

The nng_close() function closes the socket s. Messages that have been submitted for sending may be flushed or delivered, depending upon the transport.

Further attempts to use the socket after this call returns will result in NNG_ECLOSED. Threads waiting for operations on the socket when this call is executed may also return with an NNG_ECLOSED result.

note

Closing the socket while data is in transmission will likely lead to loss of that data. There is no automatic linger or flush to ensure that the socket send buffers have completely transmitted. It is recommended to wait a brief period after calling nng_send() or similar functions, before calling this function.

RETURN VALUES

This function returns 0 on success, and non-zero otherwise.

ERRORS

  • NNG_ECLOSED: The socket s is already closed or was never opened.

nng_device

NAME

nng_device - message forwarding device

SYNOPSIS

#include <nng/nng.h>

int nng_device(nng_socket s1, nng_socket s2);

void nng_device_aio(nng_aio *aio, nng_socket s1, nng_socket s2);

DESCRIPTION

The nng_device() and nng_device_aio() functions forward messages received from one socket s1 to another socket s2, and vice versa.

These functions are used to create forwarders, which can be used to create complex network topologies to provide for improved horizontal scalability, reliability, and isolation.

Only raw mode sockets may be used with this function. These can be created using _raw forms of the various socket constructors, such as nng_req0_open_raw().

The nng_device() function does not return until one of the sockets is closed. The nng_device_aio() function returns immediately, and operates completely in the background.

Reflectors

One of the sockets passed may be an unopened socket initialized with the NNG_SOCKET_INITIALIZER special value. If this is the case, then the other socket must be valid, and must use a protocol that is bidirectional and can peer with itself (such as PAIR or BUS). In this case the device acts as a reflector or loop-back device, where messages received from the valid socket are merely returned to the sender.

Forwarders

When both sockets are valid, then the result is a forwarder or proxy. In this case sockets s1 and s2 must be compatible with each other, which is to say that they should represent the opposite halves of a two protocol pattern, or both be the same protocol for a single protocol pattern. For example, if s1 is a PUB socket, then s2 must be a SUB socket. Or, if s1 is a BUS socket, then s2 must also be a BUS socket.

Operation

The nng_device() function moves messages between the provided sockets.

When a protocol has a backtrace style header, routing information is present in the header of received messages, and is copied to the header of the output bound message. The underlying raw mode protocols supply the necessary header adjustments to add or remove routing headers as needed. This allows replies to be returned to requesters, and responses to be routed back to surveyors.

The caller of these functions is required to close the sockets when the device is stopped.

Additionally, some protocols have a maximum time-to-live to protect against forwarding loops and especially amplification loops. In these cases, the default limit (usually 8), ensures that messages will self-terminate when they have passed through too many forwarders, protecting the network from unlimited message amplification that can arise through misconfiguration. This is controlled via the NNG_OPT_MAXTTL option.

note

Not all protocols have support for guarding against forwarding loops, and even for those that do, forwarding loops can be extremely detrimental to network performance.

note

Devices (forwarders and reflectors) act in best-effort delivery mode only. If a message is received from one socket that cannot be accepted by the other (due to back-pressure or other issues), then the message is discarded.

tip

Use the request/reply pattern, which includes automatic retries by the requester, if reliable delivery is needed.

RETURN VALUES

This function continues running, and only returns an appropriate error when one occurs, or if one of the sockets is closed.

ERRORS

  • NNG_ECLOSED: At least one of the sockets is not open.
  • NNG_ENOMEM: Insufficient memory is available.
  • NNG_EINVAL: The sockets are not compatible, or are both invalid.

SEE ALSO

Sockets, Raw mode

nng_pair_open

NAME

nng_pair_open — create PAIR socket

SYNOPSIS

Version 0

#include <nng/protocol/pair0/pair.h>

int nng_pair0_open(nng_socket *s);

int nng_pair0_open_raw(nng_socket *s);

Version 1

#include <nng/protocol/pair1/pair.h>

int nng_pair1_open(nng_socket *s);

int nng_pair1_open_raw(nng_socket *s);

int nng_pair1_open_poly(nng_socktet *s);

DESCRIPTION

The nng_pair0_open() and nng_pair1_open() functions create a PAIR version 0 or version 1 socket and return it at the location pointed to by s.

The nng_pair0_open_raw() and nng_pair1_open_raw() functions create a PAIR version 0 or version 1 socket in raw mode and return it at the location pointed to by s.

The nng_pair1_open_poly() function opens a pair version 1 socket in polyamorous mode.

note

Polyamorous mode is deprecated and should not be used in new applications. The nng_pair1_open_poly() function will likely be removed in a future release.

RETURN VALUES

These functions returns 0 on success, and non-zero otherwise.

ERRORS

  • NNG_ENOMEM:: Insufficient memory is available.
  • NNG_ENOTSUP:: The protocol is not supported.

SEE ALSO

Sockets, PAIR Protocol

nng_pub_open

NAME

nng_pub_open — create PUB socket

SYNOPSIS

#include <nng/nng.h>
#include <nng/protocol/pubsub0/pub.h>

int nng_pub0_open(nng_socket *s);

int nng_pub0_open_raw(nng_socket *s);

DESCRIPTION

The nng_pub0_open() function creates a PUB version 0 socket and returns it at the location pointed to by s.

The nng_pub0_open_raw() function creates a PUB version 0 socket in raw mode and returns it at the location pointed to by s.

RETURN VALUES

These functions return 0 on success, and non-zero otherwise.

ERRORS

  • NNG_ENOMEM: Insufficient memory is available.
  • NNG_ENOTSUP: The protocol is not supported.

SEE ALSO

Sockets PUB Protocol, SUB Protocol

nng_pull_open

NAME

nng_pull_open — create PULL socket

SYNOPSIS

#include <nng/nng.h>
#include <nng/protocol/pipeline0/pull.h>

int nng_pull0_open(nng_socket *s);

int nng_pull0_open_raw(nng_socket *s);

DESCRIPTION

The nng_pull0_open() function creates a PULL version 0 socket and returns it at the location pointed to by s.

The nng_pull0_open_raw() function creates a PULL version 0 socket in raw mode and returns it at the location pointed to by s.

RETURN VALUES

These functions return 0 on success, and non-zero otherwise.

ERRORS

  • NNG_ENOMEM: Insufficient memory is available.
  • NNG_ENOTSUP: The protocol is not supported.

SEE ALSO

Sockets, PULL Protocol, PUSH Protocol

nng_push_open

NAME

nng_push_open — create PUSH socket

SYNOPSIS

#include <nng/nng.h>
#include <nng/protocol/pipeline0/push.h>

int nng_push0_open(nng_socket *s);

int nng_push0_open_raw(nng_socket *s);

DESCRIPTION

The nng_push0_open() function creates a PUSH version 0 socket and returns it at the location pointed to by s.

The nng_push0_open_raw() function creates a PUSH version 0 socket in raw mode and returns it at the location pointed to by s.

RETURN VALUES

These functions return 0 on success, and non-zero otherwise.

ERRORS

  • NNG_ENOMEM: Insufficient memory is available.
  • NNG_ENOTSUP: The protocol is not supported.

SEE ALSO

Sockets, PULL Protocol, PUSH Protocol

nng_respondent_open

NAME

nng_respondent_open — create RESPONDENT socket

SYNOPSIS

#include <nng/nng.h>
#include <nng/protocol/survey0/respond.h>

int nng_respondent0_open(nng_socket *s);

int nng_respondent0_open_raw(nng_socket *s);

DESCRIPTION

The nng_respondent0_open() function creates a RESPONDENT version 0 socket and returns it at the location pointed to by s.

The nng_respondent0_open_raw() function creates a RESPONDENT version 0 socket in raw mode and returns it at the location pointed to by s.

RETURN VALUES

These functions return 0 on success, and non-zero otherwise.

ERRORS

  • NNG_ENOMEM: Insufficient memory is available.
  • NNG_ENOTSUP: The protocol is not supported.

SEE ALSO

Sockets, RESPONDENT Protocol, SURVEYOR Protocol

nng_recv

NAME

nng_recv — recv data

SYNOPSIS

#include <nng/nng.h>

int nng_recv(nng_socket s, void *data, size_t *sizep, int flags);

DESCRIPTION

The nng_recv() receives a message from the socket s, obtaining its body content.

The flags is a bit mask that may contain any of the following values:

  • NNG_FLAG_NONBLOCK:
    The function returns immediately, even if no message is available. Without this flag, the function will wait until a message is received by the socket s, or any configured timer expires.

  • NNG_FLAG_ALLOC:
    If this flag is present, then a zero-copy mode is used. In this case the caller must set the value of data to the location of another pointer (of type void *), and the sizep pointer must be set to a location to receive the size of the message body. The function will then allocate a message buffer (as if by nng_alloc()), fill it with the message body, and store it at the address referenced by data, and update the size referenced by sizep. The caller is responsible for disposing of the received buffer either by the nng_free() function or passing the message (also with the NNG_FLAG_ALLOC flag) in a call to nng_send().

If the special flag NNG_FLAG_ALLOC (see above) is not specified, then the caller must set data to a buffer to receive the message body content, and must store the size of that buffer at the location pointed to by sizep. When the function returns, if it is successful, the size at sizep will be updated with the actual message body length copied into data.

note

The semantics of what receiving a message means vary from protocol to protocol, so examination of the protocol documentation is encouraged. Furthermore, some protocols may not support receiving data at all, or may require other conditions be met before they can receive.

tip

The NNG_FLAG_ALLOC flag can be used to reduce data copies, thereby increasing performance, particularly if the buffer is reused to send a response using the same flag. However, the nng_recvmsg() function is even better in this regard, and should be preferred over this function when possible.

RETURN VALUES

This function returns 0 on success, and non-zero otherwise.

ERRORS

  • NNG_EAGAIN: The operation would block, but NNG_FLAG_NONBLOCK was specified.
  • NNG_ECLOSED: The socket s is not open.
  • NNG_EINVAL: An invalid set of flags was specified.
  • NNG_EMSGSIZE: The received message did not fit in the size provided.
  • NNG_ENOMEM: Insufficient memory is available.
  • NNG_ENOTSUP: The protocol for socket s does not support receiving.
  • NNG_ESTATE: The socket s cannot receive data in this state.
  • NNG_ETIMEDOUT: The operation timed out.

SEE ALSO

nng_alloc, nng_free, nng_recvmsg, nng_send

nng_recv_aio

NAME

nng_recv_aio — receive message asynchronously

SYNOPSIS

#include <nng/nng.h>

void nng_recv_aio(nng_socket s, nng_aio *aio);

DESCRIPTION

The nng_recv_aio() function receives a message using the socket s asynchronously.

When a message is successfully received by the socket, it is stored in the aio by an internal call equivalent to nng_aio_set_msg(), then the completion callback on the aio is executed. In this case, nng_aio_result() will return zero. The callback function is responsible for retrieving the message and disposing of it appropriately.

important

Failing to dispose of successfully received messages will leak the memory associated with it.

If for some reason the asynchronous receive cannot be completed successfully (including by being canceled or timing out), then the callback will still be executed, but nng_aio_result() will be non-zero.

note

The semantics of what receiving a message means varies from protocol to protocol, so examination of the protocol documentation is encouraged. Furthermore, some protocols may not support receiving or may require other conditions be met before receiving messages.

ERRORS

  • NNG_ECANCELED: The operation was aborted.
  • NNG_ECLOSED: The socket s is not open.
  • NNG_ENOMEM: Insufficient memory is available.
  • NNG_ENOTSUP: The protocol for socket s does not support receiving.
  • NNG_ESTATE: The socket s cannot receive data in this state.
  • NNG_ETIMEDOUT: The receive timeout expired.

SEE ALSO

Messages, Sockets, Asynchronous I/O, nng_aio_get_msg, nng_msg_alloc

nng_recvmsg

NAME

nng_recvmsg — receive a message

SYNOPSIS

#include <nng/nng.h>

int nng_recvmsg(nng_socket s, nng_msg **msgp, int flags);

DESCRIPTION

The nng_recvmsg() receives a message on socket s, storing the received message at the location pointed to by msgp.

This function gives access to the message structure, and thus may offer more functionality than the simpler nng_recv() function.1 2

1

It is also more efficient.

2

An asynchronous form of this function is available as nng_recv_aio().

The flags may contain the following value:

  • NNG_FLAG_NONBLOCK:
    The function returns immediately, even if no message is available. Without this flag, the function will wait until a message is received by the socket s, or any configured timer expires.

After successfully receiving a message, the caller is responsible for disposing of it when it is no longer needed.

important

Failing to dispose of the message will leak the memory associated with it.

note

The semantics of what receiving a message means vary from protocol to protocol, so examination of the protocol documentation is encouraged. Furthermore, some protocols do not support receiving data at all, or may require other conditions be met before receiving messages.

RETURN VALUES

This function returns 0 on success, and non-zero otherwise.

ERRORS

  • NNG_EAGAIN: The operation would block, but NNG_FLAG_NONBLOCK was specified.
  • NNG_ECLOSED: The socket s is not open.
  • NNG_EINVAL: An invalid set of flags was specified.
  • NNG_ENOMEM: Insufficient memory is available.
  • NNG_ENOTSUP: The protocol for socket s does not support receiving.
  • NNG_ESTATE: The socket s cannot receive data in this state.
  • NNG_ETIMEDOUT: The operation timed out.

SEE ALSO

Messages, Sockets, nng_msg_free, nng_recv, nng_sendmsg

nng_rep_open

NAME

nng_rep_open — create REP socket

SYNOPSIS

#include <nng/nng.h>
#include <nng/protocol/reqrep0/rep.h>

int nng_rep0_open(nng_socket *s);

int nng_rep0_open_raw(nng_socket *);

DESCRIPTION

The nng_rep0_open() function creates a REP version 0 socket and returns it at the location pointed to by s.

The nng_rep0_open_raw() function creates a REP version 0 socket in raw mode and returns it at the location pointed to by s.

RETURN VALUES

These functions return 0 on success, and non-zero otherwise.

ERRORS

  • NNG_ENOMEM: Insufficient memory is available.
  • NNG_ENOTSUP: The protocol is not supported.

SEE ALSO

Sockets, REP Protocol, REQ Protocol

nng_req_open

NAME

nng_req_open — create req socket

SYNOPSIS

#include <nng/nng.h>
#include <nng/protocol/reqrep0/req.h>

int nng_req0_open(nng_socket *s);

int nng_req0_open_raw(nng_socket *s);

DESCRIPTION

The nng_req0_open() function creates a REQ version 0 socket and returns it at the location pointed to by s.

The nng_req0_open_raw() function creates a REQ version 0 socket in raw mode and returns it at the location pointed to by s.

RETURN VALUES

These functions return 0 on success, and non-zero otherwise.

ERRORS

  • NNG_ENOMEM: Insufficient memory is available.
  • NNG_ENOTSUP: The protocol is not supported.

SEE ALSO

Sockets, REP Protocol, REQ Protocol

nng_send

NAME

nng_send — send data

SYNOPSIS

#include <nng/nng.h>

int nng_send(nng_socket s, void *data, size_t size, int flags);

DESCRIPTION

The nng_send() function sends a message containing the data of length size using the socket s.

note

The semantics of what sending a message means vary from protocol to protocol, so examination of the protocol documentation is encouraged. For example, on PUB sockets the data is broadcast, so that any peers who have a suitable subscription will be able to receive it. Furthermore, some protocols may not support sending data or may require other conditions. For example, REP sockets cannot normally send data until they have first received a request.)

The flags may contain either of (or neither of) the following values:

  • NNG_FLAG_NONBLOCK:
    The function returns immediately, regardless of whether the socket is able to accept the data or not. If the socket is unable to accept the data (such as if backpressure exists because the peers are consuming messages too slowly, or no peer is present), then the function will return with NNG_EAGAIN. If this flag is not specified, then the function will block if such a condition exists.

  • NNG_FLAG_ALLOC:
    The data was allocated using nng_alloc(), or was obtained from a call to nng_recv() with the NNG_FLAG_ALLOC flag. If this function returns success, then the data is “owned” by the function, and it will assume responsibility for calling nng_free() when it is no longer needed. In the absence of this flag, the data is copied by the implementation before the function returns to the caller.

tip

The NNG_FLAG_ALLOC flag can be used to reduce data copies, thereby increasing performance. However, the nng_sendmsg() function is even better in this regard, and should be preferred over this function when possible.

note

Regardless of the presence or absence of NNG_FLAG_NONBLOCK, there may be queues between the sender and the receiver. Furthermore, there is no guarantee that the message has actually been delivered. Finally, with some protocols, the semantic is implicitly NNG_FLAG_NONBLOCK, such as with PUB sockets, which are best-effort delivery only.

important

When using NNG_FLAG_ALLOC, it is important that the value of size match the actual allocated size of the data. Using an incorrect size results in unspecified behavior, which may include heap corruption, program crashes, or teleportation of the program’s author to an alternate universe.

RETURN VALUES

This function returns 0 on success, and non-zero otherwise.

ERRORS

  • NNG_EAGAIN: The operation would block, but NNG_FLAG_NONBLOCK was specified.
  • NNG_ECLOSED: The socket s is not open.
  • NNG_EINVAL: An invalid set of flags was specified.
  • NNG_EMSGSIZE: The value of size is too large.
  • NNG_ENOMEM: Insufficient memory is available.
  • NNG_ENOTSUP: The protocol for socket s does not support sending.
  • NNG_ESTATE: The socket s cannot send data in this state.
  • NNG_ETIMEDOUT: The operation timed out.

SEE ALSO

Sockets, nng_alloc, nng_free, nng_recv, nng_send_aio, nng_sendmsg

nng_send_aio

NAME

nng_send_aio — send message asynchronously

SYNOPSIS

#include <nng/nng.h>

void nng_send_aio(nng_socket s, nng_aio *aio);

DESCRIPTION

The nng_send_aio() sends a message using the socket s asynchronously.

The message to send must have previously been set on the aio using the nng_aio_set_msg() function. The function assumes ownership of the message.

If the message was successfully queued for delivery to the socket, then the aio will complete1, and nng_aio_result() will return zero. In this case the socket will dispose of the message when it is finished with it.

1

This does not indicate that the message was actually delivered, as it may still be buffered in the sending socket, buffered in the receiving socket, or in flight over physical media.

If the operation fails for any reason (including cancellation or timeout), then the aio callback will be executed and nng_aio_result() will return a non-zero error status.

In this case, the callback has a responsibility to retrieve the message from the aio with nng_aio_get_msg() and dispose of it appropriately. 2 (This may include retrying the send operation on the same or a different socket, or deallocating the message with nng_msg_free().)

2

Failure to do so will leak the memory associated with the message.

note

The semantics of what sending a message means varies from protocol to protocol, so examination of the protocol documentation is encouraged. Furthermore, some protocols may not support sending, or may only permit sending when other conditions are met.

RETURN VALUES

None. (The operation completes asynchronously.)

ERRORS

  • NNG_ECANCELED: The operation was aborted.
  • NNG_ECLOSED: The socket s is not open.
  • NNG_EMSGSIZE: The message is too large.
  • NNG_ENOMEM: Insufficient memory is available.
  • NNG_ENOTSUP: The protocol for socket s does not support sending.
  • NNG_ESTATE: The socket s cannot send data in this state.
  • NNG_ETIMEDOUT: The send timeout expired.

SEE ALSO

Asynchronous I/O, Messages, Sockets, nng_aio_get_msg, nng_aio_set_msg, nng_msg_alloc

nng_sendmsg

NAME

nng_sendmsg — send message

SYNOPSIS

#include <nng/nng.h>

int nng_sendmsg(nng_socket s, nng_msg *msg, int flags);

DESCRIPTION

The nng_sendmsg() sends message msg using the socket s.

If the function returns zero, indicating it has accepted the message for delivery, then the msg is owned by the socket s, and the caller must not make any further use of it. The socket will free the message when it is finished.

If the function returns non-zero, then it is the caller’s responsibility to dispose of the msg, which may include freeing it, sending it to another socket, or simply trying again later.

tip

Using this function gives access to the message structure, and may offer more functionality than the simpler nng_send() function. 1 2

1

It is also more efficient.

2

An asynchronous form of this function is available as nng_send_aio().

note

The semantics of what sending a message means vary from protocol to protocol, so examination of the protocol documentation is encouraged. Furthermore, some protocols may not support sending messages or may require other conditions be met first before sending messages.

The flags may contain the following value:

  • NNG_FLAG_NONBLOCK: The function returns immediately, regardless of whether the socket is able to accept the data or not. If the socket is unable to accept the data (such as if back-pressure exists because the peers are consuming messages too slowly, or no peer is present), then the function will return with NNG_EAGAIN. If this flag is not specified, then the function will block if such a condition exists.

note

Regardless of the presence or absence of NNG_FLAG_NONBLOCK, there may be queues between the sender and the receiver. Furthermore, there is no guarantee that the message has actually been delivered. Finally, with some protocols, the semantic is implicitly NNG_FLAG_NONBLOCK, such as with PUB sockets, which are best-effort delivery only.

RETURN VALUES

This function returns 0 on success, and non-zero otherwise.

ERRORS

  • NNG_EAGAIN: The operation would block, but NNG_FLAG_NONBLOCK was specified.
  • NNG_ECLOSED: The socket s is not open.
  • NNG_EINVAL: An invalid set of flags was specified.
  • NNG_EMSGSIZE: The value of size is too large.
  • NNG_ENOMEM: Insufficient memory is available.
  • NNG_ENOTSUP: The protocol for socket s does not support sending.
  • NNG_ESTATE: The socket s cannot send data in this state.
  • NNG_ETIMEDOUT: The operation timed out.

SEE ALSO

Messages, Sockets, nng_msg_alloc, nng_recvmsg, nng_send

nng_sub_open

NAME

nng_sub_open - create SUB socket

SYNOPSIS

#include <nng/nng.h>
#include <nng/protocol/pubsub0/sub.h>

int nng_sub0_open(nng_socket *s);

int nng_sub0_open_raw(nng_socket *s);

DESCRIPTION

The nng_sub0_open() function creates a SUB version 0 socket and returns it at the location pointed to by s.

The nng_sub0_open_raw() function creates a SUB version 0 socket in raw mode and returns it at the location pointed to by s.

RETURN VALUES

These functions return 0 on success, and non-zero otherwise.

ERRORS

  • NNG_ENOMEM: Insufficient memory is available.
  • NNG_ENOTSUP: The protocol is not supported.

SEE ALSO

Sockets, PUB Protocol, SUB Protocol

nng_surveyor_open

NAME

nng_surveyor_open — create SURVEYOR socket

SYNOPSIS

#include <nng/nng.h>
#include <nng/protocol/survey0/survey.h>

int nng_surveyor0_open(nng_socket *s);

int nng_surveyor0_open_raw(nng_socket *s);

DESCRIPTION

The nng_surveyor0_open() function creates a SURVEYOR version 0 socket and returns it at the location pointed to by s.

The nng_surveyor0_open_raw() function creates a SURVEYOR version 0 socket in raw mode and returns it at the location pointed to by s.

RETURN VALUES

These functions return 0 on success, and non-zero otherwise.

ERRORS

  • NNG_ENOMEM: Insufficient memory is available.
  • NNG_ENOTSUP: The protocol is not supported.

SEE ALSO

Sockets, RESPONDENT Protocol, SURVEYOR Protocol

nng_ctx

NAME

nng_ctx — protocol context

SYNOPSIS

#include <nng/nng.h>

typedef struct nng_ctx_s nng_ctx

DESCRIPTION

An nng_ctx is a handle to an underlying context object, which keeps the protocol state for some stateful protocols. The purpose of a separate context object is to permit applications to share a single socket, with its various underlying [dialers][nng_dialer], [listeners][nng_listener], [pipes][nng_pipe], while still benefiting from separate state tracking.

For example, a REQ context will contain the request ID of any sent request, a timer to retry the request on failure, and so forth. A separate context on the same socket can have similar data, but corresponding to a completely different request.

note

The nng_ctx structure is always passed by value (both for input parameters and return values), and should be treated opaquely. Passing structures this way gives the compiler a chance to perform accurate type checks in functions passing values of this type.

All contexts share the same socket, and so some options, as well as the underlying transport details, will be common to all contexts on that socket.

Protocols that make use of contexts will also have a default context that is used when the socket global operations are used. Operations using the global context will generally not interfere with any other contexts, except that certain socket options may affect socket global behavior.

Historically, applications wanting to use a stateful protocol concurrently would have to resort to raw mode sockets, which bypasses much of the various protocol handling, leaving it to up to the application to do so. Contexts make it possible to still benefit from advanced protocol handling, including timeouts, retries, and matching requests to responses, while doing so concurrently.

tip

Contexts are an excellent mechanism to use when building concurrent applications, and should be used in lieu of raw mode sockets when possible.

Caveats

Not every protocol supports separate contexts. See the protocol-specific documentation for further details about whether contexts are supported, and details about what options are supported for contexts.

Use of file descriptor polling (with descriptors obtained using the NNG_OPT_RECVFD or NNG_OPT_SENDFD options) while contexts are in use on the same socket is not supported, and may lead to unpredictable behavior. These asynchronous methods should not be mixed on the same socket.

Raw mode sockets do not support contexts, since there is generally no state tracked for them, and thus contexts make no sense.

Initialization

A context may be initialized using the macro NNG_CTX_INITIALIZER before it is opened, to prevent confusion with valid open contexts.

Example

The following program fragment demonstrates the use of contexts to implement a concurrent REP service that simply echos messages back to the sender.

struct echo_context {
    nng_ctx ctx;
    nng_aio *aio;
    enum { INIT, RECV, SEND } state;
};

void
echo(void *arg)
{
    struct echo_context *ec = arg;

    switch (ec->state) {
    case INIT:
        ec->state = RECV;
        nng_ctx_recv(ec->ctx, ec->aio);
        return;
    case RECV:
        if (nng_aio_result(ec->aio) != 0) {
            // ... handle error
        }
        // We reuse the message on the ec->aio
        ec->state = SEND;
        nng_ctx_send(ec->ctx, ec->aio);
        return;
    case SEND:
        if (nng_aio_result(ec->aio) != 0) {
            // ... handle error
        }
        ec->state = RECV;
        nng_ctx_recv(ec->ctx, ec->aio);
        return;
    }
}

Given the above fragment, the following example shows setting up the service. It assumes that the [socket][nng_socket] has already been created and any transports set up as well with functions such as [nng_dial()][nng_dial] or nng_listen().

#define CONCURRENCY 1024

echo_context ecs[CONCURRENCY];

void
start_echo_service(nng_socket rep_socket)
{
    for (int i = 0; i < CONCURRENCY; i++) {
        // error checks elided for clarity
        nng_ctx_open(ec[i].ctx, rep_socket)
        nng_aio_alloc(ec[i].aio, echo, &e[i]);
        ec[i].state = INIT;
        echo(&ec[i]); // start it running
    }
}

SEE ALSO

nng_ctx_close, nng_ctx_open, nng_ctx_get, nng_ctx_id nng_ctx_recv, nng_ctx_recvmsg, nng_ctx_send, nng_ctx_sendmsg, nng_ctx_set, [nng_dialer][nng_dialer], [nng_listener][nng_listener], nng_socket, [nng_options][nng_options]

nng_ctx_close

NAME

nng_ctx_close — close context

SYNOPSIS

#include <nng/nng.h>

int nng_ctx_close(nng_ctx ctx);

DESCRIPTION

The nng_ctx_close() function closes the context ctx. Messages that have been submitted for sending may be flushed or delivered, depending upon the transport.

Further attempts to use the context after this call returns will result in NNG_ECLOSED. Threads waiting for operations on the context when this call is executed may also return with an NNG_ECLOSED result.

note

Closing the socket associated with ctx (using nng_close()) also closes this context.

RETURN VALUES

This function returns 0 on success, and non-zero otherwise.

ERRORS

  • NNG_ECLOSED: The context ctx is already closed or was never opened.

SEE ALSO

nng_close, nng_ctx_open

nng_ctx_get

NAME

nng_ctx_get — get context option

SYNOPSIS

#include <nng/nng.h>

int nng_ctx_get(nng_ctx ctx, const char *opt, void *val, size_t *valszp);

int nng_ctx_get_bool(nng_ctx ctx, const char *opt, bool *bvalp);

int nng_ctx_get_int(nng_ctx ctx, const char *opt, int *ivalp);

int nng_ctx_get_ms(nng_ctx ctx, const char *opt, nng_duration *durp);

int nng_ctx_get_size(nng_ctx ctx, const char *opt, size_t *zp);

int nng_ctx_get_string(nng_ctx ctx, const char *opt, char **strp);

int nng_ctx_get_uint64(nng_ctx ctx, const char *opt, uint64_t *u64p);

DESCRIPTION

The nng_ctx_get() functions are used to retrieve option values for the context ctx. The actual options that may be retrieved in this way vary. A number of them are documented in [nng_options][options].

note

Context options are protocol specific. The details will be documented with the protocol.

Forms

In all of these forms, the option opt is retrieved from the context ctx. The forms vary based on the type of the option they take.

The details of the type, size, and semantics of the option will depend on the actual option, and will be documented with the option itself.

  • nng_ctx_get():
    This function is untyped and can be used to retrieve the value of any option. The caller must store a pointer to a buffer to receive the value in val, and the size of the buffer shall be stored at the location referenced by valszp.

    When the function returns, the actual size of the data copied (or that would have been copied if sufficient space were present) is stored at the location referenced by valszp. If the caller’s buffer is not large enough to hold the entire object, then the copy is truncated. Therefore the caller should check for truncation by verifying that the returned size in valszp does not exceed the original buffer size.

    It is acceptable to pass NULL for val if the value in valszp is zero. This can be used to determine the size of the buffer needed to receive the object.

  • nng_ctx_get_bool():
    This function is for options which take a Boolean (bool). The value will be stored at ivalp.

  • nng_ctx_get_int():
    This function is for options which take an integer (int). The value will be stored at ivalp.

  • nng_ctx_get_ms():
    This function is used to retrieve time durations (such as timeouts), stored in durp as a number of milliseconds. (The special value NNG_DURATION_INFINITE means an infinite amount of time, and the special value NNG_DURATION_DEFAULT means a context-specific default.)

  • nng_ctx_get_size():
    This function is used to retrieve a size into the pointer zp, typically for buffer sizes, message maximum sizes, and similar options.

  • nng_ctx_get_string():
    This function is used to retrieve a string into strp. This string is created from the source using nng_strdup() and consequently must be freed by the caller using nng_strfree() when it is no longer needed.

  • nng_ctx_get_uint64():
    This function is used to retrieve a 64-bit unsigned value into the value referenced by u64p. This is typically used for options related to identifiers, network numbers, and similar.

RETURN VALUES

These functions return 0 on success, and non-zero otherwise.

ERRORS

  • NNG_EBADTYPE: Incorrect type for option.
  • NNG_ECLOSED: Parameter s does not refer to an open socket.
  • NNG_EINVAL: Size of destination val too small for object.
  • NNG_ENOMEM: Insufficient memory exists.
  • NNG_ENOTSUP: The option opt is not supported.
  • NNG_EWRITEONLY: The option opt is write-only.

SEE ALSO

nng_ctx_set, nng_strdup, nng_strfree, [nng_duration][nng_duration], [nng_options][options]

nng_ctx_getopt

NAME

nng_ctx_getopt — get context option (deprecated)

SYNOPSIS

#include <nng/nng.h>

int nng_ctx_getopt(nng_ctx ctx, const char *opt, void *val, size_t *valszp);

int nng_ctx_getopt_bool(nng_ctx ctx, const char *opt, bool *bvalp);

int nng_ctx_getopt_int(nng_ctx ctx, const char *opt, int *ivalp);

int nng_ctx_getopt_ms(nng_ctx ctx, const char *opt, nng_duration *durp);

int nng_ctx_getopt_size(nng_ctx ctx, const char *opt, size_t *zp);

int nng_ctx_getopt_string(nng_ctx ctx, const char *opt, char **strp);

int nng_ctx_getopt_uint64(nng_ctx ctx, const char *opt, uint64_t *u64p);

DESCRIPTION

important

These functions are deprecated. Please see nng_ctx_get. They may not be present if the library was built with NNG_ELIDE_DEPRECATED. They may also be removed entirely in a future version of NNG.

The nng_ctx_getopt() functions are used to retrieve option values for the context ctx. The actual options that may be retrieved in this way vary.

note

Context options are protocol specific. The details will be documented with the protocol.

Forms

In all of these forms, the option opt is retrieved from the context ctx. The forms vary based on the type of the option they take.

The details of the type, size, and semantics of the option will depend on the actual option, and will be documented with the option itself.

  • nng_ctx_getopt():
    This function is untyped and can be used to retrieve the value of any option. The caller must store a pointer to a buffer to receive the value in val, and the size of the buffer shall be stored at the location referenced by valszp.

    When the function returns, the actual size of the data copied (or that would have been copied if sufficient space were present) is stored at the location referenced by valszp. If the caller’s buffer is not large enough to hold the entire object, then the copy is truncated. Therefore the caller should check for truncation by verifying that the returned size in valszp does not exceed the original buffer size.

    It is acceptable to pass NULL for val if the value in valszp is zero. This can be used to determine the size of the buffer needed to receive the object.

  • nng_ctx_getopt_bool():
    This function is for options which take a Boolean (bool). The value will be stored at ivalp.

  • nng_ctx_getopt_int():
    This function is for options which take an integer (int). The value will be stored at ivalp.

  • nng_ctx_getopt_ms():
    This function is used to retrieve time [durations][nng_duration] (such as timeouts), stored in durp as a number of milliseconds. (The special value NNG_DURATION_INFINITE means an infinite amount of time, and the special value NNG_DURATION_DEFAULT means a context-specific default.)

  • nng_ctx_getopt_size():
    This function is used to retrieve a size into the pointer zp, typically for buffer sizes, message maximum sizes, and similar options.

  • nng_ctx_getopt_string():
    This function is used to retrieve a string into strp. This string is created from the source using nng_strdup() and consequently must be freed by the caller using nng_strfree() when it is no longer needed.

  • nng_ctx_getopt_uint64():
    This function is used to retrieve a 64-bit unsigned value into the value referenced by u64p. This is typically used for options related to identifiers, network numbers, and similar.

RETURN VALUES

These functions return 0 on success, and non-zero otherwise.

ERRORS

  • NNG_EBADTYPE: Incorrect type for option.
  • NNG_ECLOSED: Parameter s does not refer to an open socket.
  • NNG_EINVAL: Size of destination val too small for object.
  • NNG_ENOMEM: Insufficient memory exists.
  • NNG_ENOTSUP: The option opt is not supported.
  • NNG_EWRITEONLY: The option opt is write-only.

SEE ALSO

nng_strdup, nng_strfree, nng_duration, [nng_options][options]

nng_ctx_id

NAME

nng_ctx_id — return numeric context identifier

SYNOPSIS

#include <nng/nng.h>

int nng_ctx_id(nng_ctx c);

DESCRIPTION

The nng_ctx_id() function returns a positive identifier for the context c, if it is valid. Otherwise it returns -1.

note

A context is considered valid if it was ever opened with nng_ctx_open() function. Contexts that are allocated on the stack or statically should be initialized with the macro NNG_CTX_INITIALIZER to ensure that they cannot be confused with a valid context before they are opened.

RETURN VALUES

This function returns the positive value for the context identifier, or -1 if the context is invalid.

nng_ctx_open

NAME

nng_ctx_open — create context

SYNOPSIS

#include <nng/nng.h>

int nng_ctx_open(nng_ctx *ctxp, nng_socket s);

DESCRIPTION

The nng_ctx_open() function creates a separate context to be used with the socket s, and returns it at the location pointed by ctxp.

note

Not every protocol supports creation of separate contexts.

Contexts allow the independent and concurrent use of stateful operations using the same socket. For example, two different contexts created on a REP socket can each receive requests, and send replies to them, without any regard to or interference with each other.

tip

Using contexts is an excellent way to write simpler concurrent applications, while retaining the benefits of the protocol-specific advanced processing, avoiding the need to bypass that with raw mode sockets.

note

Use of contexts with raw mode sockets is nonsensical, and not supported.

RETURN VALUES

This function returns 0 on success, and non-zero otherwise.

ERRORS

  • NNG_ENOMEM: Insufficient memory is available.
  • NNG_ENOTSUP: The protocol does not support separate contexts, or the socket was opened in raw mode.

SEE ALSO

nng_ctx_close, nng_ctx_get, nng_ctx_recv, nng_ctx_send, nng_ctx_set, Sockets

nng_ctx_recv

NAME

nng_ctx_recv — receive message using context asynchronously

SYNOPSIS

#include <nng/nng.h>

void nng_ctx_recv(nng_ctx ctx, nng_aio *aio);

DESCRIPTION

The nng_ctx_recv() receives a message using the context ctx asynchronously.

When a message is successfully received by the context, it is stored in the aio by an internal call equivalent to nng_aio_set_msg(), then the completion callback on the aio is executed. In this case, nng_aio_result() will return zero. The callback function is responsible for retrieving the message and disposing of it appropriately.

important

Failing to accept and dispose of messages in this case can lead to memory leaks.

If for some reason the asynchronous receive cannot be completed successfully (including by being canceled or timing out), then the callback will still be executed, but nng_aio_result() will be non-zero.

tip

The semantics of what receiving a message means varies from protocol to protocol, so examination of the protocol documentation is encouraged.

ERRORS

The following errors may be set on the aio, if the operation fails.

  • NNG_ECANCELED: The operation was aborted.
  • NNG_ECLOSED: The context ctx is not open.
  • NNG_ENOMEM: Insufficient memory is available.
  • NNG_ENOTSUP: The protocol for context ctx does not support receiving.
  • NNG_ESTATE: The context ctx cannot receive data in this state.
  • NNG_ETIMEDOUT: The receive timeout expired.

SEE ALSO

Asynchronous I/O, Messages

nng_ctx_recvmsg

NAME

nng_ctx_recvmsg — receive message using socket

SYNOPSIS

#include <nng/nng.h>

int nng_ctx_recvmsg(nng_ctx ctx, nng_msg **msgp, int flags);

DESCRIPTION

The nng_ctx_recvmsg() receives a message on context ctx, storing the received message at the location pointed to by msgp.

The flags may contain the following value:

  • NNG_FLAG_NONBLOCK:
    The function returns immediately, even if no message is available. Without this flag, the function will wait until a message is receivable on the context ctx, or any configured timer expires.

tip

The semantics of what receiving a message means vary from protocol to protocol, so examination of the protocol documentation is encouraged.

RETURN VALUES

This function returns 0 on success, and non-zero otherwise.

ERRORS

  • NNG_EAGAIN: The operation would block, but NNG_FLAG_NONBLOCK was specified.
  • NNG_ECLOSED: The context or socket is not open.
  • NNG_EINVAL: An invalid set of flags was specified.
  • NNG_ENOMEM: Insufficient memory is available.
  • NNG_ENOTSUP: The protocol does not support receiving.
  • NNG_ESTATE: The context cannot receive data in this state.
  • NNG_ETIMEDOUT: The operation timed out.

SEE ALSO

nng_msg_free, nng_ctx_open, nng_ctx_recv, nng_ctx_sendmsg, Messages

nng_ctx_send

NAME

nng_ctx_send — send message using context asynchronously

SYNOPSIS

#include <nng/nng.h>

void nng_ctx_send(nng_ctx ctx, nng_aio *aio);

DESCRIPTION

The nng_ctx_send() sends a message using the [context][nng_ctx] ctx asynchronously.

The message to send must have previously been set on the aio using the nng_aio_set_msg() function. The function assumes ownership of the message.

If the message was successfully queued for delivery to the socket, then the aio will be completed, and nng_aio_result() will return zero. In this case the socket will dispose of the message when it is finished with it.

note

The operation will be completed, and the callback associated with the aio executed, as soon as the socket accepts the message for sending. This does not indicate that the message was actually delivered, as it may still be buffered in the sending socket, buffered in the receiving socket, or in flight over physical media.

If the operation fails for any reason (including cancellation or timeout), then the aio callback will be executed and nng_aio_result() will return a non-zero error status. In this case, the callback has a responsibility to retrieve the message from the aio with nng_aio_get_msg() and dispose of it appropriately. (This may include retrying the send operation on the same or a different socket, or deallocating the message with nng_msg_free().

tip

The semantics of what sending a message means varies from protocol to protocol, so examination of the protocol documentation is encouraged.

ERRORS

  • NNG_ECANCELED: The operation was aborted.
  • NNG_ECLOSED: The context ctx is not open.
  • NNG_EMSGSIZE: The message is too large.
  • NNG_ENOMEM: Insufficient memory is available.
  • NNG_ENOTSUP: The protocol for context ctx does not support sending.
  • NNG_ESTATE: The context ctx cannot send data in this state.
  • NNG_ETIMEDOUT: The send timeout expired.

SEE ALSO

nng_aio_get_msg, nng_aio_set_msg, nng_ctx_sendmsg, nng_msg_alloc, nng_msg_free, Asynchronous I/O, Messages

nng_ctx_sendmsg()

NAME

nng_ctx_sendmsg — send message using context

SYNOPSIS

#include <nng/nng.h>

int nng_ctx_sendmsg(nng_ctx c, nng_msg *msg, int flags);

DESCRIPTION

The nng_ctx_sendmsg() sends message msg using the context ctx.

If the function returns zero, indicating it has accepted the message for delivery, then the msg is owned by the socket s, and the caller must not make any further use of it. The socket will free the message when it is finished.

If the function returns non-zero, then it is the caller’s responsibility to dispose of the msg, which may include freeing it, sending it to another socket, or simply trying again later.

tip

The semantics of what sending a message means vary from protocol to protocol, so examination of the protocol documentation is encouraged.

The flags may contain the following value:

  • NNG_FLAG_NONBLOCK:
    The function returns immediately, regardless of whether the context is able to accept the data or not. If the context is unable to accept the data (such as if backpressure exists because the peers are consuming messages too slowly, or no peer is present), then the function will return with NNG_EAGAIN. If this flag is not specified, then the function will block if such a condition exists.1
1

Regardless of the presence or absence of NNG_FLAG_NONBLOCK, there may be queues between the sender and the receiver. Furthermore, there is no guarantee that the message has actually been delivered. Finally, with some protocols, the semantic is implicitly NNG_FLAG_NONBLOCK.

RETURN VALUES

This function returns 0 on success, and non-zero otherwise.

ERRORS

  • NNG_EAGAIN: The operation would block, but NNG_FLAG_NONBLOCK was specified.
  • NNG_ECLOSED: The context or socket is not open.
  • NNG_EINVAL: An invalid set of flags was specified.
  • NNG_EMSGSIZE: The value of size is too large.
  • NNG_ENOMEM: Insufficient memory is available.
  • NNG_ENOTSUP: The protocol does not support sending.
  • NNG_ESTATE: The context cannot send data in this state.
  • NNG_ETIMEDOUT: The operation timed out.

SEE ALSO

nng_ctx_send, Messages

nng_ctx_set

NAME

nng_ctx_set — set context option

SYNOPSIS

#include <nng/nng.h>

int nng_ctx_set(nng_ctx ctx, const char *opt, const void *val, size_t valsz);

int nng_ctx_set_bool(nng_ctx ctx, const char *opt, int bval);

int nng_ctx_set_int(nng_ctx ctx, const char *opt, int ival);

int nng_ctx_set_ms(nng_ctx ctx, const char *opt, nng_duration dur);

int nng_ctx_set_size(nng_ctx ctx, const char *opt, size_t z);

int nng_ctx_set_string(nng_ctx ctx, const char *opt, const char *str);

int nng_ctx_set_uint64(nng_ctx ctx, const char *opt, uint64_t u64);

DESCRIPTION

The nng_ctx_set() functions are used to configure options for the context ctx. The actual options that may be configured in this way vary, and are specified by opt.

note

Context options are protocol specific. The details will be documented with the protocol.

Forms

The details of the type, size, and semantics of the option will depend on the actual option, and will be documented with the option itself.

  • nng_ctx_set():
    This function is untyped, and can be used to configure any arbitrary data. The val pointer addresses the data to copy, and valsz is the size of the objected located at val.

  • nng_ctx_set_bool():
    This function is for options which take a Boolean (bool). The bval is passed to the option.

  • nng_ctx_set_int():
    This function is for options which take an integer (int). The ival is passed to the option.

  • nng_ctx_set_ms():
    This function is used to configure time durations (such as timeouts) using type [nng_duration][nng_duration]. The duration dur is an integer number of milliseconds.

  • nng_ctx_set_size():
    This function is used to configure a size, z, typically for buffer sizes, message maximum sizes, and similar options.

  • nng_ctx_set_string():
    This function is used to pass configure a string, str. Strings passed this way must be legal UTF-8 or ASCII strings, terminated with a NUL (\0) byte. (Other constraints may apply as well, see the documentation for each option for details.)

  • nng_ctx_set_uint64():
    This function is used to configure a 64-bit unsigned value, u64. This is typically used for options related to identifiers, network numbers, and similar.

RETURN VALUES

These functions return 0 on success, and non-zero otherwise.

ERRORS

  • NNG_ECLOSED: Parameter s does not refer to an open socket.
  • NNG_EINVAL: The value being passed is invalid.
  • NNG_ENOTSUP: The option opt is not supported.
  • NNG_EREADONLY: The option opt is read-only.
  • NNG_ESTATE: The socket is in an inappropriate state for setting this option.

SEE ALSO

nng_ctx_get, [nng_socket_set][nng_socket_get], [Options][options]

nng_ctx_setopt

NAME

nng_ctx_setopt — set context option (deprecated)

SYNOPSIS

#include <nng/nng.h>

int nng_ctx_setopt(nng_ctx ctx, const char *opt, const void *val, size_t valsz);

int nng_ctx_setopt_bool(nng_ctx ctx, const char *opt, int bval);

int nng_ctx_setopt_int(nng_ctx ctx, const char *opt, int ival);

int nng_ctx_setopt_ms(nng_ctx ctx, const char *opt, nng_duration dur);

int nng_ctx_setopt_size(nng_ctx ctx, const char *opt, size_t z);

int nng_ctx_setopt_string(nng_ctx ctx, const char *opt, const char *str);

int nng_ctx_setopt_uint64(nng_ctx ctx, const char *opt, uint64_t u64);

DESCRIPTION

important

These functions are deprecated. Please see nng_ctx_set(). They may not be present if the library was built with NNG_ELIDE_DEPRECATED. They may also be removed entirely in a future version of NNG.

The nng_ctx_setopt() functions are used to configure options for the context ctx. The actual options that may be configured in this way vary, and are specified by opt.

note

Context options are protocol specific. The details will be documented with the protocol.

Forms

The details of the type, size, and semantics of the option will depend on the actual option, and will be documented with the option itself.

  • nng_ctx_setopt():
    This function is untyped, and can be used to configure any arbitrary data. The val pointer addresses the data to copy, and valsz is the size of the objected located at val.

  • nng_ctx_setopt_bool():
    This function is for options which take a Boolean (bool). The bval is passed to the option.

  • nng_ctx_setopt_int():
    This function is for options which take an integer (int). The ival is passed to the option.

  • nng_ctx_setopt_ms():
    This function is used to configure time durations (such as timeouts) using type [nng_duration][nng_duration]. The duration dur is an integer number of milliseconds.

  • nng_ctx_setopt_size():
    This function is used to configure a size, z, typically for buffer sizes, message maximum sizes, and similar options.

  • nng_ctx_setopt_string():
    This function is used to pass configure a string, str. Strings passed this way must be legal UTF-8 or ASCII strings, terminated with a NUL (\0) byte. (Other constraints may apply as well, see the documentation for each option for details.)

  • nng_ctx_setopt_uint64():
    This function is used to configure a 64-bit unsigned value, u64. This is typically used for options related to identifiers, network numbers, and similar.

RETURN VALUES

These functions return 0 on success, and non-zero otherwise.

ERRORS

  • NNG_ECLOSED: Parameter s does not refer to an open socket.
  • NNG_EINVAL: The value being passed is invalid.
  • NNG_ENOTSUP: The option opt is not supported.
  • NNG_EREADONLY: The option opt is read-only.
  • NNG_ESTATE: The socket is in an inappropriate state for setting this option.

SEE ALSO

nng_ctx_set, [Options][options]

Aysnchronous I/O

NNG provides rich support for asynchronous I/O. This allows applications to achieve high levels of concurrency with a minimum of fuss, optimized for the platform.

Asynchronous I/O is performed without blocking calling application threads, so they may continue to perform other work.

AIO Handles

Applications create an nng_aio object with a function to call when the operation is done (along with a pointer to application private data), then submit the operation.

These nng_aio objects are created using the nng_aio_alloc(), and destroyed using nng_aio_free().

The nng_aio object itself is declared like this:

#include <nng/nng.h>

typedef struct nng_aio nng_aio;

Every asynchronous operation uses its own instance an nng_aio, and each nng_aio can only be used with a single operation at a time.

important

Attempting to submit an operation using an nng_aio that is already in use for another operation will crash the application. However, it is possible to submit another operation on the nng_aio from the callback associated with the same nng_aio.

When the operation is complete, whether successfully or otherwise, the callback function is executed. The callback will be executed exactly once.

Cancellation

The asynchronous I/O framework also supports cancellation of operations that are already in progress (see nng_aio_cancel()), as well setting a maximum timeout for them to complete within (see nng_aio_set_timeout()).

Waiting for Completion

It is also possible to initiate an asynchronous operation, and wait for it to complete nng_aio_wait().

important

Applications must never call nng_aio_wait() or nng_aio_stop() from a callback registered to an nng_aio object. Doing so can lead to a deadlock.

See Also

nng_aio_abort, nng_aio_alloc, nng_aio_cancel, nng_aio_count, nng_aio_free, nng_aio_get_input, nng_aio_get_msg, nng_aio_get_output, nng_aio_result, nng_aio_set_input, nng_aio_set_iov, nng_aio_set_msg, nng_aio_set_timeout, nng_aio_stop, nng_aio_wait

nng_aio_abort

NAME

nng_aio_abort — abort asynchronous I/O operation

SYNOPSIS

#include <nng/nng.h>

void nng_aio_abort(nng_aio *aio, int err);

DESCRIPTION

The nng_aio_abort() function aborts an operation previously started with the handle aio. If the operation is aborted, then the callback for the handle will be called, and the function nng_aio_result() will return the error err.

This function does not wait for the operation to be fully aborted, but returns immediately.

If no operation is currently in progress (either because it has already finished, or no operation has been started yet), then this function has no effect.

SEE ALSO

nng_aio_alloc, nng_aio_cancel, nng_aio_result

nng_aio_alloc

NAME

nng_aio_alloc — allocate asynchronous I/O handle

SYNOPSIS

#include <nng/nng.h>

int nng_aio_alloc(nng_aio **aiop, void (*callb)(void *), void *arg);

DESCRIPTION

The nng_aio_alloc() function allocates a handle for asynchronous I/O operations, and stores a pointer to it in the location referenced by aiop. The handle is initialized with a completion callback of callb, which will be executed when an associated asynchronous operation finishes. It will be called with the argument arg.

important

The callback callb must not perform any blocking operations, and must complete its execution quickly. If callb does block, this can lead ultimately to an apparent “hang” or deadlock in the application. This also means you should avoid operations such as allocating new objects, which also means opening or closing sockets, dialers, and so forth.

tip

If more complex or blocking work needs to be performed by callb, a separate thread can be used, along with a condition variable which can be signaled by the callback.

Asynchronous I/O operations all take an nng_aio handle such as allocated by this function. Such operations are usually started by a function that returns immediately. The operation is then run asynchronously, and completes sometime later. When that operation is complete, the callback supplied here is called, and that callback is able to determine the result of the operation using nng_aio_result(), nng_aio_count(), and nng_aio_get_output().

It is possible to wait synchronously for an otherwise asynchronous operation by using the function nng_aio_wait(). In that case, it is permissible for callb and arg to both be NULL. Note that if these are NULL, then it will not be possible to determine when the operation is complete except by calling the aforementioned nng_aio_wait().

RETURN VALUES

This function returns 0 on success, and non-zero otherwise.

ERRORS

  • NNG_ENOMEM: Insufficient free memory to perform the operation.

SEE ALSO

nng_aio_abort, nng_aio_cancel, nng_aio_count, nng_aio_free, nng_aio_get_msg, nng_aio_get_output, nng_aio_result, nng_aio_set_input, nng_aio_set_iov, nng_aio_set_msg, nng_aio_set_timeout, nng_aio_stop, nng_aio_wait

nng_aio_busy

NAME

nng_aio_busy — test if asynchronous I/O is busy

SYNOPSIS

#include <nng/nng.h>

bool nng_aio_busy(nng_aio *aio);

DESCRIPTION

The nng_aio_busy() function returns true if the aio is currently busy performing an asynchronous I/O operation or is executing a completion callback.

If no operation has been started, or the operation has been completed or canceled, and any callback has been executed, then it returns false.

This is the same test used internally by nng_aio_wait().

important

Care should be taken to ensure that the aio object is not freed when using this function. The caller is responsible for coordinating any use of this with any reuse of the aio.

RETURN VALUES

True if the aio is busy, false otherwise.

SEE ALSO

nng_aio_abort, nng_aio_alloc, nng_aio_wait

nng_aio_cancel

NAME

nng_aio_cancel — cancel asynchronous I/O operation

SYNOPSIS

#include <nng/nng.h>

void nng_aio_cancel(nng_aio *aio);

DESCRIPTION

The nng_aio_cancel() function aborts an operation previously started with the handle aio. If the operation is aborted, then the callback for the handle will be called, and the function nng_aio_result() will return the error NNG_ECANCELED.

This function does not wait for the operation to be fully aborted, but returns immediately.

If no operation is currently in progress (either because it has already finished, or no operation has been started yet), then this function has no effect.

This function is the same as calling nng_aio_abort() with the error NNG_ECANCELED.

SEE ALSO

nng_aio_abort, nng_aio_alloc, nng_aio_result

nng_aio_count

NAME

nng_aio_count — return number of bytes transferred

SYNOPSIS

#include <nng/nng.h>

size_t nng_aio_count(nng_aio *aio);

DESCRIPTION

The nng_aio_count() returns the number of bytes transferred by the asynchronous operation associated with the handle aio.

Some asynchronous operations do not provide meaningful data for this function; for example operations that establish connections do not transfer user data (they may transfer protocol data though) – in this case this function will generally return zero.

This function is most useful when used with operations that make use of of a scatter/gather vector (set by nng_aio_set_iov()).

note

The return value from this function is undefined if the operation has not completed yet. Either call this from the handle’s completion callback, or after waiting for the operation to complete with nng_aio_wait().

RETURN VALUES

The number of bytes transferred by the operation.

SEE ALSO

nng_aio_alloc, nng_aio_result, nng_aio_set_iov, nng_aio_wait

nng_aio_free

NAME

nng_aio_free — free asynchronous I/O handle

SYNOPSIS

#include <nng/nng.h>

void nng_aio_free(nng_aio *aio);
void nng_aio_reap(nng_aio *aio);

DESCRIPTION

The nng_aio_free() function frees an allocated asynchronous I/O handle. If any operation is in progress, the operation is canceled, and the caller is blocked until the operation is completely canceled, to ensure that it is safe to deallocate the handle and any associated resources. (This is done by implicitly calling nng_aio_stop().)

The nng_aio_reap() function is the same as nng_aio_free(), but does its work in a background thread. This can be useful to discard the aio object from within the callback for the aio.

important

Once either of these functions are called, the aio object is invalid and must not be used again.

SEE ALSO

nng_aio_alloc, nng_aio_stop

nng_aio_get_msg

NAME

nng_aio_get_msg — get message from asynchronous receive

SYNOPSIS

#include <nng/nng.h>

nng_msg *nng_aio_get_msg(nng_aio *aio);

DESCRIPTION

The nng_aio_get_msg() function gets any message stored in aio as either a result of a successful receive (see nng_recv_aio()) or that was previously stored with nng_aio_set_msg().

important

The aio must not have an operation in progress.

SEE ALSO

nng_aio_set_msg, nng_recv_aio, Messages

nng_aio_get_output

NAME

nng_aio_get_output — return output result

SYNOPSIS

#include <nng/nng.h>

void *nng_aio_get_output(nng_aio *aio, unsigned int index);

DESCRIPTION

The nng_aio_get_output() function returns the output result at index resulting from the asynchronous operation associated with aio.

The type and semantics of output parameters are determined by specific operations.

note

If the index does not correspond to a defined output for the operation, or the operation did not succeed, then the return value will be NULL.

important

It is an error to call this function while the aio is currently in use by an active asynchronous operation, or if no operation has been performed using the aio yet.

RETURN VALUES

The indexth output from the operation, or NULL.

SEE ALSO

nng_aio_alloc, nng_aio_set_output, nng_aio_result

nng_aio_result

NAME

nng_aio_result — return result of asynchronous operation

SYNOPSIS

#include <nng/nng.h>

int nng_aio_result(nng_aio *aio);

DESCRIPTION

The nng_aio_result() returns the result of the operation associated with the handle aio. If the operation was successful, then 0 is returned. Otherwise a non-zero error code is returned.

note

The return value from this function is undefined if the operation has not completed yet. Either call this from the handle’s completion callback, or after waiting for the operation to complete with nng_aio_wait().

RETURN VALUES

The result of the operation, either zero on success, or an error number on failure.

ERRORS

  • NNG_ETIMEDOUT: The operation timed out.
  • NNG_ECANCELED: The operation was canceled.

Various other return values are possible depending on the operation.

SEE ALSO

nng_aio_abort, nng_aio_alloc, nng_aio_wait, nng_strerror

nng_aio_set_input

NAME

nng_aio_set_input — set input parameter

SYNOPSIS

#include <nng/nng.h>

void nng_aio_set_input(nng_aio *aio, unsigned int index, void *param);

DESCRIPTION

The nng_aio_set_input() function sets the input parameter at index to param for the asynchronous operation associated with aio.

The type and semantics of input parameters are determined by specific operations; the caller must supply appropriate inputs for the operation to be performed.

The valid values of index range from zero (0) to three (3), as no operation currently defined can accept more than four parameters. (This limit could increase in the future.)

note

If the index does not correspond to a defined input for the operation, then this function will have no effect.

important

It is an error to call this function while the aio is currently in use by an active asynchronous operation.

An input parameter set with this function may be retrieved later with the nng_aio_get_input() function.

SEE ALSO

nng_aio_alloc, nng_aio_get_input

nng_aio_set_iov()

NAME

nng_aio_set_iov — set scatter/gather vector

SYNOPSIS

#include <nng/nng.h>

int nng_aio_set_iov(nng_aio *aio, unsigned int niov, nng_iov *iov);

DESCRIPTION

The nng_aio_set_iov() function sets a scatter/gather vector iov on the handle aio.

The iov is a pointer to an array of niov [nng_iov][nng_iov] structures, which have the following definition:

typedef struct nng_iov {
    void * iov_buf;
    size_t iov_len;
};

The iov is copied into storage in the aio itself, so that callers may use stack allocated nng_iov structures. The values pointed to by the iov_buf members are not copied by this function though.

A maximum of four (4) nng_iov members may be supplied.

RETURN VALUES

This function returns 0 on success, and non-zero otherwise.

ERRORS

  • NNG_EINVAL: Value of specified niov is too large.

nng_aio_set_msg()

NAME

nng_aio_set_msg — set message for asynchronous send

SYNOPSIS

#include <nng/nng.h>

void nng_aio_set_msg(nng_aio *aio, nng_msg *msg);

DESCRIPTION

The nng_aio_set_msg() function sets the message that will be used for an asynchronous send operation (see nng_send_aio()).

important

The aio must not have an operation in progress.

SEE ALSO

nng_aio_get_msg, nng_send_aio, Messages

nng_aio_set_timeout

NAME

nng_aio_set_timeout — set asynchronous I/O timeout

SYNOPSIS

#include <nng/nng.h>

typedef int nng_duration;
void nng_aio_set_timeout(nng_aio *aio, nng_duration timeout);

typedef uint64_t nng_time;
void nng_aio_set_expire(nng_aio *aio, nng_time expiration);

DESCRIPTION

The nng_aio_set_timeout() function sets a timeout for the asynchronous operation associated with aio. This causes a timer to be started when the operation is actually started. If the timer expires before the operation is completed, then it is aborted with an error of NNG_ETIMEDOUT. The timeout is specified as a relative number of milliseconds.

If the timeout is NNG_DURATION_INFINITE, then no timeout is used. If the timeout is NNG_DURATION_DEFAULT, then a “default” or socket-specific timeout is used. (This is frequently the same as NNG_DURATION_INFINITE.)

The nng_aio_set_expire() function is similar to nng_aio_set_timeout(), but sets an absolute expiration time based on the system clock. The expiration is expressed as a number of milliseconds since some point in the past. The nng_clock() function can be used to determine the current value of the clock.

tip

As most operations involve some context switching, it is usually a good idea to allow at least a few tens of milliseconds before timing them out – a too small timeout might not allow the operation to properly begin before giving up!

The value of timeout set for the aio is persistent, so that if the handle is reused for future operations, it will have the same relative or absolute timeout.

SEE ALSO

nng_aio_cancel, nng_aio_result, nng_clock

nng_aio_stop

NAME

nng_aio_stop - stop asynchronous I/O operation

SYNOPSIS

#include <nng/nng.h>

void nng_aio_stop(nng_aio *aio);

DESCRIPTION

The nng_aio_stop() function stops the asynchronous I/O operation associated with aio by aborting with NNG_ECANCELED, and then waits for it to complete or to be completely aborted, and for the callback associated with the aio to have completed executing.

Further calls to nng_aio_begin() using this aio will return false.

It is safe to call this for an aio, even when no operation is currently pending for it.

tip

When multiple asynchronous I/O handles are in use and need to be shut down, it is safest to stop all of them, before deallocating any of them with nng_aio_free(), particularly if the callbacks might attempt to reschedule additional operations.

SEE ALSO

nng_aio_cancel, nng_aio_free, nng_aio_wait

nng_aio_wait

NAME

nng_aio_wait — wait for asynchronous I/O operation

SYNOPSIS

#include <nng/nng.h>

void nng_aio_wait(nng_aio *aio);

DESCRIPTION

The nng_aio_wait() function waits for an asynchronous I/O operation to complete. If the operation has not been started, or has already completed, then it returns immediately.

If a callback was set with aio when it was allocated, then this function will not be called until the callback has completed.

important

This function should never be called from a function that itself is a callback of an nng_aio, either this one or any other. Doing so may result in a deadlock.

SEE ALSO

nng_aio_abort, nng_aio_busy

Asynchronous I/O for Providers

I/O providers perform the operations that are linked to an nng_aio object, on behalf of applications that submit requests for the same operations.

Most applications will not use the functions listed here. Applications that implement their own HTTP handler functions, or custom transport providers, might make use of these functions.

In addition to these functions, I/O providers may utilize the other consumer functions for Aysnchronous I/O.

See Also

nng_aio_begin, nng_aio_defer, nng_aio_finish, nng_aio_get_input, nng_aio_set_output, Asynchronous I/O

nng_aio_begin

NAME

nng_aio_begin — begin asynchronous I/O operation

SYNOPSIS

#include <nng/nng.h>

bool nng_aio_begin(nng_aio *aio);

DESCRIPTION

The nng_aio_begin() function is called by the I/O provider to indicate that it is going to process the operation.

The function may return false, indicating that the aio has been closed. In this case the provider should abandon the operation and do nothing else.

This operation should be called at the start of any I/O operation, and must be called not more than once for a given I/O operation on a given aio.

Once this function is called, if true is returned, then the provider MUST guarantee that nng_aio_finish() is called for the aio exactly once, when the operation is complete or canceled.

tip

This function is only for I/O providers (those actually performing the operation such as HTTP handler functions or transport providers); ordinary users of the aio should not call this function.

RETURN VALUES

  • true: The operation has been started.
  • false: The operation cannot be started.

SEE ALSO

nng_aio_cancel, nng_aio_defer, nng_aio_finish

nng_aio_defer

NAME

nng_aio_defer — defer asynchronous I/O operation

SYNOPSIS

#include <nng/nng.h>

typedef void (*nng_aio_cancelfn)(nng_aio *aio, void *arg, int err);

void nng_aio_defer(nng_aio *aio, nng_aio_cancelfn fn, void *arg);

DESCRIPTION

The nng_aio_defer() function marks operation associated with aio as being deferred for asynchronous completion, registering a cancellation function fn and associated argument arg. This permits the operation to be canceled.

If the aio is canceled, the cancellation routine fn will be called with the aio, the arg specified by nng_aio_defer(), and an error value in err, which is the reason that the operation is being canceled.

At any given time, the operation may not be cancelable. For example it may have already been completed, or be in a state where it is no longer possible to unschedule it. In this case, the cancelfn should just return without making any changes.

If the cancellation routine successfully canceled the operation, it should ensure that nng_aio_finish() is called, with the error code specified by err.

important

It is mandatory that I/O providers call nng_aio_finish() exactly once when they are finished with the operation.

important

Care must be taken to ensure that cancellation and completion of the routine are multi-thread safe. This will usually involve the use of locks or other synchronization primitives.

tip

For operations that complete synchronously, without any need to be deferred, the provider need not call nng_aio_defer().

tip

This function is only for I/O providers (those actually performing the operation such as HTTP handler functions or transport providers); ordinary users of the aio should not call this function.

SEE ALSO

nng_aio_alloc, nng_aio_cancel, nng_aio_finish

nng_aio_finish

NAME

nng_aio_finish — finish asynchronous I/O operation

SYNOPSIS

#include <nng/nng.h>

void nng_aio_finish(nng_aio *aio, int err);

DESCRIPTION

The nng_aio_finish() function marks operation associated with aio as complete, with the status err. This will be the result returned by nng_aio_result().

This function causes the callback associated with the aio to called.

important

It is mandatory that operation providers call this function exactly once when they are finished with the operation. After calling this function, the provider must not perform any further accesses to the aio.

tip

This function is only for I/O providers (those actually performing the operation such as HTTP handler functions or transport providers); ordinary users of the aio should not have any need for this function.

SEE ALSO

nng_aio_begin, nng_aio_cancel, nng_aio_defer, nng_aio_result

nng_aio_get_input

NAME

nng_aio_get_input — return input parameter

SYNOPSIS

#include <nng/nng.h>

void *nng_aio_get_input(nng_aio *aio, unsigned int index);

DESCRIPTION

The nng_aio_get_input() function returns the value of the input parameter previously set at index on aio with the nng_aio_set_input()function.

The valid values of index range from zero (0) to three (3), as no operation currently defined can accept more than four parameters. If the index supplied is outside of this range, or if the input parameter was not previously set, then NULL is returned.

RETURN VALUES

Value previously set, or NULL.

SEE ALSO

nng_aio_alloc, nng_aio_get_output, nng_aio_set_input

nng_aio_set_output

NAME

nng_aio_set_output — set output result

SYNOPSIS

#include <nng/nng.h>

void nng_aio_set_output(nng_aio *aio, unsigned int index, void *result);

DESCRIPTION

The nng_aio_set_output() function sets the output result at index to result for the asynchronous operation associated with aio.

The type and semantics of output results are determined by specific operations; the operation must supply appropriate output results when the operation completes successfully.

The valid values of index range from zero (0) to three (3), as no operation currently defined can return more than four results.

note

Note that attempts to set results with an index greater than three (3) will be ignored.

An output result set with this function may be retrieved later with the nng_aio_get_output() function.

SEE ALSO

nng_aio_get_output

General Purpose Functions

See Also

nng_alloc, nng_clock, nng_free, nng_random, nng_version

nng_alloc

NAME

nng_alloc — allocate memory

SYNOPSIS

#include <nng/nng.h>

void *nng_alloc(size_t size);

DESCRIPTION

The nng_alloc() function allocates a contiguous memory region of at least size bytes. The memory will be 64-bit aligned.

The returned memory can be used to hold message buffers, in which case it can be directly passed to nng_send() using the flag NNG_FLAG_ALLOC. Alternatively, it can be freed when no longer needed using nng_free().

important

Do not use the system free() function (or the C++ delete operator) to release this memory. On some configurations this may work, but on others it will lead to a crash or other unpredictable behavior.

RETURN VALUES

This function returns a pointer to the allocated memory on success, and NULL otherwise.

ERRORS

No errors are returned, but if memory cannot be allocated then NULL is returned.

SEE ALSO

nng_free, nng_send

nng_clock

NAME

nng_clock - get time

SYNOPSIS

#include <nng/nng.h>
#include <nng/supplemental/util/platform.h>

typedef uint64_t nng_time;

nng_time nng_clock(void);

DESCRIPTION

The nng_clock() function returns the number of elapsed milliseconds since some arbitrary time in the past. The resolution of the clock depends on the underlying timing facilities of the system. This function may be used for timing, but applications should not expect very fine-grained values.

note

The reference time will be the same for a given program, but different programs may have different references.

This function is intended to help with setting appropriate timeouts using nng_cv_until() or nng_aio_set_expire().

RETURN VALUES

Milliseconds since reference time.

SEE ALSO

nng_sleep_aio, nng_cv_until, nng_msleep, nng_duration

nng_free

NAME

nng_free — free memory

SYNOPSIS

#include <nng/nng.h>

void nng_free(void *ptr, size_t size);

DESCRIPTION

The nng_free() function deallocates a memory region of size size, that was previously allocated by nng_alloc() or nng_recv() with the NNG_FLAG_ALLOC flag.

important

It is very important that size match the allocation size used to allocate the memory.

important

Do not attempt to use this function to deallocate memory obtained by a call to the system malloc() or calloc() functions, or the C++ new operator. Doing so may result in unpredictable behavior, including corruption of application memory.

SEE ALSO

nng_alloc, nng_recv

nng_id_map

NAME

nng_id_map — identifier based mapping table

SYNOPSIS

#include <nng/nng.h>
#include <nng/supplemental/util/idhash.h>

typedef struct nng_id_map_s nng_id_map;

#define NNG_MAP_RANDOM 1

int   nng_id_map_alloc(nng_id_map **map_p, uint64_t lo, uint64_t hi, int flags);
void  nng_id_map_free(nng_id_map *map);
void *nng_id_get(nng_id_map *map, uint64_t id);
int   nng_id_set(nng_id_map *map, uint64_t, void *value);
int   nng_id_alloc(nng_id_map *map, uint64_t *id_p, void *value);
int   nng_id_remove(nng_id_map *map, uint64_t id);

DESCRIPTION

These functions provide support for managing tables of data based on identifiers, ensuring that identifiers are allocated uniquely and within specified range limits.

The table stores data pointers (which must not be NULL) at a logical numeric index. It does so efficiently, even if large gaps exist, and it provides a means to efficiently allocate a numeric identifier from a pool of unused identifiers.

Identifiers are allocated in increasing order, without reusing old identifiers until the largest possible identifier is allocated. After wrapping, only identifiers that are no longer in use will be considered. No effort is made to order the availability of identifiers based on when they were freed.1

1

The concern about possibly reusing a recently released identifier comes into consideration after the range has wrapped. Given a sufficiently large range, this is unlikely to be a concern.

An initial table is allocated with nng_id_map_alloc(), which takes the lowest legal identifier in lo, and the largest legal identifier in hi. The new table is returned in map_p, and should be used as the map argument to the rest of these functions.

If these lo and hi are both zero, then a full range of 32-bit identifiers is assumed.2

2

Consequently, if identifiers larger than or equal to 232 are required, then both lo and hi must be specified with the exact values desired.

The flags argument is a bit mask of flags for the table. If NNG_MAP_RANDOM is specified, then the starting point for allocations is randomized, but subsequent allocations will then be monotonically increasing. This is useful to reduce the odds of different instances of an application using the same identifiers at the same time.

The nng_id_get() function returns the value previously stored with the given identifier. If no value is currently associated with the identifer, it returns NULL.

The nng_id_set() function sets the value with the associated identifier. This can be used to replace a previously allocated identifier. If the identifier was not previously allocated, then it is allocated as part of the call. This function does not necessarily honor the identifier range limits set for the map when it was allocated.

The nng_id_alloc() function allocates a new identifier from the range for the map, and associates it with the supplied value.

The nng_id_remove() function removes the identifier and its associated value from the table.

note

These functions are limited to storing at most 232 used identifiers, even though the identifers may themselves be larger than 232.

note

These functions are not thread-safe. Callers should use a [mutex][mutex] or similar approach when thread-safety is needed.

RETURN VALUES

The nng_id_map_alloc(), nng_id_set(), nng_id_alloc(), and nng_id_remove() functions return 0 on success, or -1 on failure.

The nng_id_map_get() function returns the requested data pointer, or NULL if the identifier was not found.

ERRORS

  • NNG_ENOENT: The id does not exist in the table.
  • NNG_ENOMEM: Insufficient memory is available, or the table is full.

nng_msleep

NAME

nng_msleep — sleep milliseconds

SYNOPSIS

#include <nng/nng.h>
#include <nng/supplemental/util/platform.h>

void nng_msleep(nng_duration msec);

DESCRIPTION

The nng_msleep() blocks the caller for at least msec milliseconds.

note

This function may block for longer than requested. The actual wait time is determined by the capabilities of the underlying system.

SEE ALSO

nng_sleep_aio, nng_clock

nng_random

NAME

nng_random — get random number

SYNOPSIS

#include <nng/nng.h>
#include <nng/supplemental/util/platform.h>

uint32_t nng_random(void);

DESCRIPTION

The nng_random() returns a random number. The value returned is suitable for use with cryptographic functions such as key generation. The value is obtained using platform-specific cryptographically strong random number facilities when available.

RETURN VALUES

Returns a random 32-bit value.

nng_sleep_aio

NAME

nng_sleep_aio - sleep asynchronously

SYNOPSIS

#include <nng/nng.h>

void nng_sleep_aio(nng_duration msec, nng_aio *aio);

DESCRIPTION

The nng_sleep_aio() function provides an asynchronous delay mechanism, causing the callback for aio to be executed after msec milliseconds. If the sleep finishes completely, the result will always be zero.

note

If a timeout is set on aio using nng_aio_set_timeout(), and it is shorter than msec, then the sleep will wake up early, with a result code of NNG_ETIMEDOUT.

SEE ALSO

nng_clock, nng_msleep, Asynchronous I/O

nng_socket_pair

NAME

nng_socket_pair — create a connected pair of BSD sockets

SYNOPSIS

#include <nng/nng.h>
#include <nng/supplemental/util/platform.h>

int nng_socket_pair(int fds[2]);

DESCRIPTION

The nng_socket_pair() function creates a pair of connected BSD sockets. These sockets, which are returned in the fds array, are suitable for use with the BSD Socket transport.

On POSIX platforms, this is a thin wrapper around the standard socketpair() function, using the AF_UNIX family and the SOCK_STREAM socket type.1

1

At present only POSIX platforms implementing socketpair() support this function.

tip

This function may be useful for creating a shared connection between a parent process and a child process on UNIX platforms, without requiring the processes use a shared filesystem or TCP connection.

RETURN VALUES

This function returns 0 on success, and non-zero otherwise.

ERRORS

  • NNG_ENOMEM: Insufficient memory exists.
  • NNG_ENOTSUP: This platform does not support socket pairs.

SEE ALSO

BSD Socket Transport

nng_strdup

NAME

nng_strdup — duplicate string

SYNOPSIS

#include <nng/nng.h>

char *nng_strdup(const char *src);

DESCRIPTION

The nng_strdup() duplicates the string src and returns it.

This is logically equivalent to using nng_alloc() to allocate a region of memory of strlen(s) + 1 bytes, and then using strcpy() to copy the string into the destination before returning it.

The returned string should be deallocated with nng_strfree(), or may be deallocated using the nng_free() using the length of the returned string plus one (for the NUL terminating byte).

important

Do not use the system free() or similar functions to deallocate the string, since those may use a different memory arena!

RETURN VALUES

This function returns the new string on success, and NULL on failure.

ERRORS

No errors are returned, but a NULL return value should be treated the same as NNG_ENOMEM.

SEE ALSO

nng_alloc.md, nng_free.md, nng_strfree.md

nng_strerror

NAME

nng_strerror — return an error description

SYNOPSIS

#include <nng/nng.h>

const char * nng_strerror(int err);

DESCRIPTION

The nng_strerror() returns the human-readable description of the given error in err.

The returned error message is provided in US English, but in the future locale-specific strings may be presented instead.

note

The specific strings associated with specific error messages are subject to change. Therefore applications must not depend on the message, but may use them verbatim when supplying information to end-users, such as in diagnostic messages or log entries.

RETURN VALUES

This function returns the human-readable error message, terminated by a NUL byte.

nng_strfree

NAME

nng_strfree — free memory

SYNOPSIS

#include <nng/nng.h>

void nng_strfree(char *str);

DESCRIPTION

The nng_strfree() function deallocates the string str. This is equivalent to using nng_free() with the length of str plus one (for the NUL terminating byte) as the size.

important

This should only be used with strings that were allocated by nng_strdup() or nng_alloc(). In all cases, the allocation size of the string must be the same as strlen(__str__) + 1.

important

Consequently, if the a string created with nng_strdup() is modified to be shorter, then it is incorrect to call this function. (The nng_free() function can be used instead in that case, using the length of the original string plus one for the size.)

SEE ALSO

nng_alloc, nng_free, nng_strdup

nng_version

NAME

nng_version — report library version

SYNOPSIS

#include <nng/nng.h>

const char * nng_version(void);

DESCRIPTION

The nng_version() function returns a human readable version number for NNG.

Additionally, compile time version information is available via some predefined macros:

  • NNG_MAJOR_VERSION: Major version number.
  • NNG_MINOR_VERSION: Minor version number.
  • NNG_PATCH_VERSION: Patch version number.

NNG is developed and released using Semantic Versioning 2.0, and the version numbers reported refer to both the API and the library itself. (The ABI – application binary interface – between the library and the application is controlled in a similar, but different manner depending upon the link options and how the library is built.)

RETURN VALUES

NUL-terminated string containing the library version number.

Threads and Synchronization

Threads

Mutexes

Condition Variables

nng_cv_alloc

NAME

nng_cv_alloc — allocate condition variable

SYNOPSIS

#include <nng/nng.h>
#include <nng/supplemental/util/platform.h>

typedef struct nng_cv nng_cv;

int nng_cv_alloc(nng_cv **cvp, nng_mtx *mtx);

DESCRIPTION

The nng_cv_alloc() function allocates a condition variable, using the mutex mtx, and returns it in cvp.

Every condition variable is associated with a mutex, which must be owned when a thread waits for the condition using nng_cv_wait() or nng_cv_until(). The mutex must also be owned when signaling the condition using the nng_cv_wake() or nng_cv_wake1() functions.

RETURN VALUES

This function returns 0 on success, and non-zero otherwise.

ERRORS

  • NNG_ENOMEM: Insufficient free memory exists.

SEE ALSO

nng_cv_free, nng_cv_until, nng_cv_wait, nng_cv_wake, nng_cv_wake1, nng_mtx_alloc

nng_cv_free

NAME

nng_cv_free — free condition variable

SYNOPSIS

#include <nng/nng.h>
#include <nng/supplemental/util/platform.h>

void nng_cv_free(nng_cv *cv);

DESCRIPTION

The nng_cv_free() function frees the condition variable cv.

SEE ALSO

nng_cv_alloc

nng_cv_until()

NAME

nng_cv_until — wait for condition or timeout

SYNOPSIS

#include <nng/nng.h>
#include <nng/supplemental/util/platform.h>

int nng_cv_until(nng_cv *cv, nng_time when);

DESCRIPTION

The nng_cv_until() waits until either the condition variable cv is signaled by another thread calling either nng_cv_wake() or nng_cv_wake1(), or the system clock (as tracked by nng_clock()) reaches when.

The caller must have have ownership of the mutex that was used when cv was allocated. This function will drop the ownership of that mutex, and reacquire it atomically just before returning to the caller. (The waiting is done without holding the mutex.)

Spurious wakeups can occur.

tip

Any condition may be used or checked, but the condition must be checked, as it is possible for this function to wake up spuriously. The best way to do this is inside a loop that repeats until the condition tests for true.

EXAMPLE

The following example demonstrates use of this function:

Example 1: Waiting for the condition

    expire = nng_clock() + 1000; // 1 second in the future
    nng_mtx_lock(m);  // assume cv was allocated using m
    while (!condition_true) {
        if (nng_cv_until(cv, expire) == NNG_ETIMEDOUT) {
            printf("Time out reached!\n");
            break;
        }
    }
    // condition_true is true
    nng_mtx_unlock(m);

Example 2: Signaling the condition

    nng_mtx_lock(m);
    condition_true = true;
    nng_cv_wake(cv);
    nng_mtx_unlock(m);

SEE ALSO

nng_clock(), nng_cv_alloc(), nng_cv_wait(), nng_cv_wake(), nng_cv_wake1(), nng_mtx_alloc(), nng_mtx_lock(), nng_mtx_unlock()

nng_cv_wait

NAME

nng_cv_wait — wait for condition

SYNOPSIS

#include <nng/nng.h>
#include <nng/supplemental/util/platform.h>

void nng_cv_wait(nng_cv *cv);

DESCRIPTION

The nng_cv_wait() waits for the condition variable cv to be signaled by another thread calling either nng_cv_wake() or nng_cv_wake1().

The caller must have have ownership of the mutex that was used when cv was allocated. This function will drop the ownership of that mutex, and reacquire it atomically just before returning to the caller. (The waiting is done without holding the mutex.)

Spurious wakeups are possible.

tip

Any condition may be used or checked, but the condition must be checked, as it is possible for this function to wake up spuriously. The best way to do this is inside a loop that repeats until the condition tests for true.

EXAMPLE

The following example demonstrates use of this function:

Example 1: Waiting for the condition

    nng_mtx_lock(m);  // assume cv was allocated using m
    while (!condition_true) {
        nng_cv_wait(cv);
    }
    // condition_true is true
    nng_mtx_unlock(m);

Example 2: Signaling the condition

    nng_mtx_lock(m);
    condition_true = true;
    nng_cv_wake(cv);
    nng_mtx_unlock(m);

SEE ALSO

nng_cv_alloc, nng_cv_until, nng_cv_wake, nng_cv_wake1, nng_mtx_alloc, nng_mtx_lock, nng_mtx_unlock

nng_cv_wake

NAME

nng_cv_wake — wake all waiters

SYNOPSIS

#include <nng/nng.h>
#include <nng/supplemental/util/platform.h>

void nng_cv_wake(nng_cv *cv);

DESCRIPTION

The nng_cv_wake() wakes any threads waiting for the condition variable cv to be signaled in the nng_cv_wait() or nng_cv_until() functions.

The caller must have have ownership of the mutex that was used when cv was allocated.

The caller should already have set the condition that the waiters will check, while holding the mutex.

tip

This function wakes all threads, which is generally safer but can lead to a performance problem when there are many waiters, as they are all woken simultaneously and may contend for resources. See nng_cv_wake1() for a solution to this problem.

SEE ALSO

nng_cv_alloc, nng_cv_until, nng_cv_wait, nng_cv_wake1, nng_mtx_alloc, nng_mtx_lock, nng_mtx_unlock

nng_cv_wake1

NAME

nng_cv_wake1 — wake one waiter

SYNOPSIS

#include <nng/nng.h>
#include <nng/supplemental/util/platform.h>

void nng_cv_wake1(nng_cv *cv);

DESCRIPTION

The nng_cv_wake1() wakes at most one thread waiting for the condition variable cv to be signaled in the nng_cv_wait() or nng_cv_until() functions.

The caller must have have ownership of the mutex that was used when cv was allocated.

The caller should already have set the condition that the waiters will check, while holding the mutex.

note

The caller cannot predict which waiter will be woken, and so the design must ensure that it is sufficient that any waiter be woken. When in doubt, it is safer to use nng_cv_wake().

SEE ALSO

nng_cv_alloc, nng_cv_until, nng_cv_wait, nng_cv_wake, nng_mtx_alloc, nng_mtx_lock, nng_mtx_unlock

nng_mtx_alloc

NAME

nng_mtx_alloc — allocate mutex

SYNOPSIS

#include <nng/nng.h>
#include <nng/supplemental/util/platform.h>

typedef struct nng_mtx nng_mtx;

int nng_mtx_alloc(nng_mtx **mtxp);

DESCRIPTION

The nng_mtx_alloc() function allocates mutex and returns it in mtxp.

The mutex objects created by this function are suitable only for simple lock and unlock operations, and are not recursive. Every effort has been made to use light-weight underlying primitives when available.

Mutex (mutual exclusion) objects can be thought of as binary semaphores, where only a single thread of execution is permitted to acquire the semaphore.

Furthermore, a mutex can only be unlocked by the thread that locked it.

RETURN VALUES

This function returns 0 on success, and non-zero otherwise.

ERRORS

  • NNG_ENOMEM: Insufficient free memory exists.

SEE ALSO

nng_cv_alloc, nng_mtx_free, nng_mtx_lock, nng_mtx_unlock

nng_mtx_free

NAME

nng_mtx_free — free mutex

SYNOPSIS

#include <nng/nng.h>
#include <nng/supplemental/util/platform.h>

void nng_mtx_free(nng_mtx *mtx);

DESCRIPTION

The nng_mtx_free() function frees the mutex mtx. The mutex must not be locked when this function is called.

SEE ALSO

nng_mtx_alloc

nng_mtx_lock

NAME

nng_mtx_lock — lock mutex

SYNOPSIS

#include <nng/nng.h>
#include <nng/supplemental/util/platform.h>

void nng_mtx_lock(nng_mtx *mtx);

DESCRIPTION

The nng_mtx_lock() acquires exclusive ownership of the mutex mtx. If the lock is already owned, this function will wait until the current owner releases it with nng_mtx_unlock().

If multiple threads are waiting for the lock, the order of acquisition is not specified.

note

A mutex can only be unlocked by the thread that locked it.

note

Mutex locks are not recursive; attempts to reacquire the same mutex may result in deadlock or aborting the current program. It is a programming error for the owner of a mutex to attempt to reacquire it.

SEE ALSO

nng_cv_alloc, nng_mtx_alloc, nng_mtx_unlock

nng_mtx_unlock(3supp)

NAME

nng_mtx_unlock — unlock mutex

SYNOPSIS

#include <nng/nng.h>
#include <nng/supplemental/util/platform.h>

void nng_mtx_unlock(nng_mtx *mtx);

DESCRIPTION

The nng_mtx_unlock() relinquishes ownership of the mutex mtx that was previously acquired via nng_mtx_lock().

note

A mutex can only be unlocked by the thread that locked it. Attempting to unlock a mutex that is not owned by the caller will result in undefined behavior.

SEE ALSO

nng_mtx_alloc, nng_mtx_lock

Legacy Compatibility Functions

NNG provides source-level compatibility for most libnanomsg 1.0 applications.

This is intended to facilitate converting legacy applications to use NNG. New applications should use the newer NNG APIs instead.

Applications making use of this must take care to link with libnng instead of libnn.

tip

While not recommended for long term use, the value returned by nng_socket_id() can be used with these functions just like a value returned by nn_socket(). This can be way to facilitate incremental transition to the new API.

Some capabilities, protocols, and transports, will not be accessible using this API, as the compatible API has no provision for expression of certain concepts introduced in the new API.

While reasonable efforts have been made to provide for compatibility, some things may behave differently, and some less common parts of the libnanomsg 1.0 API are not supported at this time, including certain options and the statistics API. See the Caveats section below.

Availability

The availability of this legacy API depends on whether the library was configured to include it.

note

Future versions of NNG may not include this compatibility layer by default, or even at all. Modernizing applications to use the new API is strongly recommended.

Compiling

When compiling legacy nanomsg applications, it will generally be necessary to change the include search path to add the compat subdirectory of the directory where headers were installed. For example, if NNG is installed in $prefix, then header files will normally be located in $prefix/include/nng. In this case, to build legacy nanomsg apps against NNG you would add $prefix/include/nng/compat to your compiler’s search path.

Alternatively, you can change your source code so that #include statements referring to <nanomsg> instead refer to <nng/compat/nanomsg>. For example, instead of:

#include <nanomsg/nn.h>
#include <nanomsg/reqrep.h>

you would have this:

#include <nng/compat/nanomsg/nn.h>
#include <nng/compat/nanomsg/reqrep.h>

Legacy applications built using these methods should be linked against libnng instead of libnn, just like any other NNG application.

Caveats

The following caveats apply when using the legacy API with NNG.

  • Socket numbers can be quite large. The legacy libnanomsg attempted to reuse socket numbers, like file descriptors in UNIX systems. NNG avoids this to prevent accidental reuse or collision after a descriptor is closed. Consequently, socket numbers can become quite large, and should probably not be used for array indices.

  • The following options (nn_getsockopt) are unsupported: NN_SNDPRIO, NN_RCVPRIO, NN_IPV4ONLY.

  • Access to statistics using this legacy API nn_get_statistic() is unsupported.

  • Some transports can support longer URLs than legacy libnanomsg can. It is a good idea to use short pathnames in URLs if interoperability is a concern.

  • Only absolute paths are supported in ipc:// URLs. For example, ipc:///tmp/mysocket is acceptable, but ipc://mysocket is not.

  • The WebSocket transport in this implementation (ws:// URLs) only supports BINARY frames.

  • Some newer transports are unusable from this mode. In particular, this legacy API offers no way to configure TLS or ZeroTier parameters that may be required for use.

  • ABI versioning of the compatibility layer is not supported, and the NN_VERSION_ macros are not present.

  • Runtime symbol information is not implemented. Specifically, there is no nn_symbol() function.

  • The TCP transport (tcp:// URLs) does not support specifying the local address or interface when binding. (This could be fixed in the future, but most likely this will be available only using the new API.)

  • The values of NN_RCVMAXSIZE are constrained. Specifically, values set larger than 2GB using the new API will be reported as unlimited (-1) in the new API, and the value 0 will disable any enforcement, just like -1. (There is no practical reason to ever want to limit the receive size to zero.)

  • This implementation counts buffers in terms of messages rather than bytes. As a result, the buffer sizes accessed with NN_SNDBUF and NN_RCVBUF are rounded up to a whole number of kilobytes, then divided by 1024, in order to approximate buffering assuming 1 KB messages. Few applications should need to adjust the default values.

Index

socket transport, 1
ABI, 1
abstract sockets, 1
AF_UNIX, 1, 2
application binary interface, 1
asynchronous I/O, 1, 2
back-pressure, 1, 2, 3
backtrace, 1, 2, 3, 4, 5
best-effort, 1, 2, 3
BUS protocol, 1
callback, 1, 2
compatibility layer, 1
concurrent, 1
condition variable, 1
context, 1, 2
cooked mode, 1
flow control, 1
forwarder, 1
half-duplex, 1
headroom, 1
horizontal scalability, 1
idempotent, 1
identifiers, 1
INADDR_ANY, 1
inproc transport, 1, 2
intra-process, 1
ipc transport, 1
IPv6, 1
leader election, 1
legacy applications, 1
load-balancing, 1, 2, 3
loop-back, 1
message, 1
      body, 1, 2, 3, 4
      header, 1, 2
mutex, 1
named pipes, 1
NNG_AF_UNSPEC, 1
NNG_CTX_INITIALIZER, 1
NNG_DURATION_DEFAULT, 1, 2
NNG_DURATION_INFINITE, 1, 2
NNG_ELIDE_DEPRECATED, 1, 2
NNG_FLAG_ALLOC, 1, 2
NNG_FLAG_NONBLOCK, 1, 2, 3, 4, 5, 6
NNG_MAJOR_VERSION, 1
NNG_MAP_RANDOM, 1
NNG_MINOR_VERSION, 1
NNG_OPT_SOCKET_FD, 1, 2
NNG_PATCH_VERSION, 1
NNG_SOCKET_INITIALIZER, 1
option, see Options
      NNG_OPT_LOCADDR, 1
      NNG_OPT_PEER_UID, 1
      NNG_OPT_REQ_RESENDTICK, 1
      NNG_OPT_REQ_RESENDTIME, 1
      NNG_OPT_SUB_PREFNEW, 1
      NNG_OPT_SUB_SUBSCRIBE, 1
      NNG_OPT_SUB_UNSUBSCRIBE, 1
      NNG_OPT_SURVEYOR_SURVEYTIME, 1
options, context, 1, 2
PAIR protocol, 1
pipeline pattern, 1, 2, 3
polyamorous mode, 1, 2
port number, 1
protocol, 1
      BUS, 1, 2
      PAIR, 1, 2
      PUB, 1, 2
      PULL, 1, 2
      PUSH, 1, 2
      REP, 1, 2
      REQ, 1, 2
      RESPONDENT, 1, 2
      SUB, 1, 2
      SURVEYOR, 1, 2
PUB protocol, 1
publisher, 1
PULL protocol, 1
PUSH protocol, 1
raw mode, 1, 2, 3
reflector, 1
REP protocol, 1
REQ protocol, 1
request/reply pattern, 1, 2, 3
RESPONDENT protocol, 1
scatter/gather, 1
service discovery, 1
socket://, 1
SUB protocol, 1
subscribe, 1
subscriber, 1
survey pattern, 1, 2
SURVEYOR protocol, 1
tailroom, 1
tcp transport, 1, 2
TCP/IP, 1, 2
time-to-live, 1
timeout, 1
transport, 1
      inproc, 1
      ipc, 1
      tcp, 1
UNIX domain sockets, 1
URI, see URI
      abstract://, 1
      inproc://, 1
      ipc://, 1
      tcp://, 1
      unix://, 1
version number, 1
voting, 1
zero-copy, 1