1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
|
# 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, char **valp);
```
{{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`}}
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 string is created as if by [`nng_strdup`], and must be freed by
the caller using [`nng_strfree`] when no longer needed.
## 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`}}<a name="NNG_PIPE_EV_ADD_PRE"></a> | 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`}}<a name="NNG_PIPE_EV_ADD_POST"></a> | 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`}}<a name="NNG_PIPE_EV_REM_POST"></a> | 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}}
|