# Pipes ```c typedef struct nng_pipe_s nng_pipe; ``` An {{i:`nng_pipe`}} is a handle to a {{i:pipe}} object, which can be thought of as a single {{i:connection}}. (In most cases this is actually the case -- the pipe is an abstraction for a single TCP or IPC connection.) Pipes are associated with either the listener or dialer that created them, and therefore are also automatically associated with a single socket. > [!NOTE] > The `nng_pipe` 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. > [!TIP] > Most applications should never concern themselves with individual pipes. > However it is possible to access a pipe when more information about the > source of a message is needed, or when more control is required over message delivery. Pipe objects are created by [dialers][dialer] and and [listeners][listener]. ## Initialization A pipe may be initialized using the macro {{i:`NNG_PIPE_INITIALIZER`}} before it is opened, to prevent confusion with valid open pipes. For example: ```c nng_pipe p = NNG_PIPE_INITIALIZER; ``` ## Pipe Identity ```c int nng_pipe_id(nng_pipe p); ``` The {{i:`nng_pipe_id`}} function returns a positive identifier for the pipe _p_, if it is valid. Otherwise it returns `-1`. > [!NOTE] > A pipe is considered valid if it was ever created by the socket. > Pipes that are allocated on the stack or statically should be initialized with the macro > [`NNG_PIPE_INITIALIZER`] to ensure that they cannot be confused with a valid pipe. ## Closing a Pipe ```c nng_err nng_pipe_close(nng_pipe p); ``` The {{i:`nng_pipe_close`}} function closes the supplied pipe, _p_. Messages that have been submitted for sending may be flushed or delivered, depending upon the transport. Further attempts to use the pipe after this call returns will result in [`NNG_ECLOSED`]. > [!TIP] > Pipes are automatically closed when their creator closes, or when the > remote peer closes the underlying connection. ## Pipe Creator ```c nng_dialer nng_pipe_dialer(nng_pipe p); nng_listener nng_pipe_listener(nng_pipe p); nng_socket nng_pipe_socket(nng_pipe p); ``` {{hi:`nng_pipe_dialer`}} {{hi:`nng_pipe_listener`}} {{hi:`nng_pipe_socket`}} These functions return the [socket], [dialer], or [listener] that created or owns the pipe. If the pipe was does not have an associated dialer or listener, then the associated will return [`NNG_DIALER_INITIALIZER`] or [`NNG_LISTENER_INITIALIZER`], as appropriate, and either [`nng_dialer_id`] or [`nng_listener_id`] for the returned object will return -1. > [!NOTE] > The socket, or the endpoint, returned by these functions may be in the process of closing, > and might not be further usable as a result. (Other functions will result in [`NNG_ECLOSED`].) ## Pipe Options ```c nng_err nng_pipe_get_bool(nng_pipe p, const char *opt, bool *valp); nng_err nng_pipe_get_int(nng_pipe p, const char *opt, int *valp); nng_err nng_pipe_get_ms(nng_pipe p, const char *opt, nng_duration *valp); nng_err nng_pipe_get_size(nng_pipe p, const char *opt, size_t *valp); nng_err nng_pipe_get_addr(nng_pipe p, const char *opt, nng_sockaddr *valp); nng_err nng_pipe_get_string(nng_pipe p, const char *opt, const char **valp); nng_err nng_pipe_get_strcpy(nng_pipe p, const char *opt, char *val, size_t len); nng_err nng_pipe_get_strdup(nng_pipe p, const char *opt, char **valp); nng_err nng_pipe_get_strlen(nng_pipe p, const char *opt, size_t *lenp); ``` {{hi:`nng_pipe_get_bool`}} {{hi:`nng_pipe_get_int`}} {{hi:`nng_pipe_get_ms`}} {{hi:`nng_pipe_get_size`}} {{hi:`nng_pipe_get_addr`}} {{hi:`nng_pipe_get_string`}} {{hi:`nng_pipe_get_strcpy`}} {{hi:`nng_pipe_get_strdup`}} These functions are used to obtain value of an option named _opt_ from the pipe _p_, and store it in the location referenced by _valp_. These functions access an option as a specific type. The transport layer will have details about which options are available, and which type they may be accessed using. In the case of `nng_pipe_get_string`, the underlying string may only be valid for as long as the pipe is valid. Thus, this function can only be safely called in a pipe event callback set up with [`nng_pipe_notify`]. The `nng_pipe_get_strdup` function is like `nng_pipe_get_string`, but makes a copy into a newly allocated buffer, so that the string must be freed by the caller using [`nng_strfree`]. The `nng_pipe_get_strcpy` function is also like `nng_pipe_get_string`, but it makes a copy into a buffer supplied by the caller. The buffer is passed in _val_, and the size of the buffer is passed in _len_. The value of _len_ must be large enough to hold the string and the terminating zero byte. The `nng_pipe_get_strlen` function is used to obtain the length of the string. This can be useful to find the size of the buffer needed by the `nng_pipe_get_strcpy` function for a property. Note that like `strlen`, this size does not account for the zero byte to terminate the string. ## Pipe Notifications ```c typedef enum { NNG_PIPE_EV_ADD_PRE, NNG_PIPE_EV_ADD_POST, NNG_PIPE_EV_REM_POST, } nng_pipe_ev; typedef void (*nng_pipe_cb)(nng_pipe, nng_pipe_ev, void *); nng_err nng_pipe_notify(nng_socket s, nng_pipe_ev ev, nng_pipe_cb cb, void *arg); ``` The {{i:`nng_pipe_notify`}} function registers the callback function _cb_ to be called whenever the pipe event specified by _ev_ occurs on the socket _s_. The callback _cb_ will be passed _arg_ as its final argument. A different callback may be supplied for each event. Each event may have at most one callback registered. Registering a callback implicitly unregisters any previously registered. The following pipe events are supported: | Event | Description | | --------------------------------------------------------------- | ------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------ | | {{i:`NNG_PIPE_EV_ADD_PRE`}} | This event occurs after a connection and negotiation has completed, but before the pipe is added to the socket. If the pipe is closed (using [`nng_pipe_close`]) at this point, the socket will never see the pipe, and no further events will occur for the given pipe. | | {{i:`NNG_PIPE_EV_ADD_POST`}} | This event occurs after the pipe is fully added to the socket. Prior to this time, it is not possible to communicate over the pipe with the socket. | | {{i:`NNG_PIPE_EV_REM_POST`}} | This event occurs after the pipe has been removed from the socket. The underlying transport may be closed at this point, and it is not possible communicate using this pipe. | > [!WARNING] > The callback _cb_ function must _not_ attempt to perform any > accesses to the socket, as it is called with a lock on the socket held! > Doing so would thus result in a deadlock. > [!TIP] > The callback _cb_ may close a pipe for any reason by simply closing it using [`nng_pipe_close`]. > For example, this might be done to prevent an unauthorized peer from connecting to the socket, > if an authorization check made during `NNG_PIPE_EV_ADD_PRE` fails. > [!NOTE] > This function ignores invalid values for _ev_. {{#include ../xref.md}}