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
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
|
# Messages
Messages {{hi:messages}} in Scalability Protocols are the fundamental unit of
transmission and reception, as these protocols are fundamentally message-oriented.
Messages have a [body][`nng_msg_body`]{{hi:body}}, containing the application-supplied
payload, and a [header][`nng_msg_header`]{{hi:header}}, containing protocol specific routing and similar
related information.
> [!TIP]
> Only applications using [raw mode][raw] need to access the message header.
> Very few _NNG_ applications do this.
## Message Structure
```c
typedef struct nng_msg nng_msg;
```
The {{i:`nng_msg`}} structure represents a single message. It carries a body
and a header.
### Create a Message
```c
int nng_msg_alloc(nng_msg **msgp, size_t size);
```
The {{i:`nng_msg_alloc`}} function allocates a new message.
It takes a _size_ argument, and returns a message
with a preallocated body of that size in the _msgp_ parameter.
If it succeeds, it returns zero, otherwise this function may return [`NNG_ENOMEM`],
indicating that insufficient memory is available to allocate a new message.
### Destroy a Message
```c
void nng_msg_free(nng_msg *msg);
```
The {{i:`nng_msg_free`}} function deallocates a message.
### Duplicate a Message
```c
int nng_msg_dup(nng_msg **dup, nng_msg *msg);
```
The {{i:`nng_msg_dup`}} function duplicates the message _msg_, storing a pointer
to the new duplicate in _dup_. This function also returns zero on success, or [`NNG_ENOMEM`]
if memory is exhausted.
## Message Size and Capacity
```c
size_t nng_msg_capacity(nng_msg *msg);
int nng_msg_realloc(nng_msg *msg, size_t size);
int nng_msg_reserve(nng_msg *msg, size_t capacity);
```
Messages have a certain amount of pre-reserved space, which may exceed the total
size of the message. This allows for content to be added to the message later,
without necessarily performing a reallocation.
The {{i:`nng_msg_capacity`}} function returns the amount of prereserved space.
If a message size change is required, and the new size will fit within the capacity
reported by this function, then change will be done without a reallocation, and
likely without a data copy as well.
> [!TIP]
> The capacity reported by `nng_msg_capacity` may not include reserved headroom, which
> is present to allow a very limited amount of content to be inserted in front of the
> message without requiring the rest of the message to be copied.
The message size may be changed by use of the {{i:`nng_msg_realloc`}} function. This
function will reallocate the underlying memory for the message _msg_,
preserving contents while doing so.
If the new size is smaller than the original message, it will
truncate the message, but not perform any allocations.
If reallocation fails due to insufficient memory, then the original is left intact.
The {{i:`nng_msg_reserve`}} function ensures that the total message capacity
is at least _capacity_ bytes. Use of this function to ensure the total anticipated
capacity is present in the message may help prevent many small allocations.
Both `nng_msg_realloc` and `nng_msg_reserve` return zero on success, or may return
[`NNG_ENOMEM`] if insufficient memory exists to preform allocation.
> [!IMPORTANT]
> Any pointers to message content obtained before a call to `nng_msg_realloc` or
> `nng_msg_reserve` (or any other function that changes the message size) should be
> treated as invalid, as the locations pointed to may be deallocated by these functions.
## Message Body
```c
void *nng_msg_body(nng_msg *msg);
size_t nng_msg_len(nng_msg *msg);
```
The body and body length of _msg_ are returned by {{i:`nng_msg_body`}} and
{{i:`nng_msg_len`}}, respectively.
### Clear the Body
```c
void *nng_msg_clear(nng_msg *msg);
```
The {{i:`nng_msg_clear`}} simply resets the total message body length to zero, but does
not affect the capacity. It does not change the underlying bytes of the message.
### Add to Body
```c
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);
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);
```
Appending data to a message body is done by using the {{i:`nng_msg_append`}} functions.
The base `nng_msg_append` function appends _size_ bytes of untyped data to the end of the
message.
Use of the typed versions, ending in suffixes `_u16`, `_u32`, and `_u64` allows
for unsigned integers to be appended directly. The integers are encoded in network byte order, with
the most significant byte appearing first. The message body will by two, four, or eight
bytes accordingly.
Data may inserted before the rest of the message body by using the {{i:`nng_msg_insert`}} functions.
This will attempt to use "headroom" in the message to avoid a data copy.
Otherwise they are like the `nng_msg_append` functions except that the put the data in front
of the messages instead of at the end.
> [!TIP]
> Message headroom is limited, so `nng_msg_insert` is best used sparingly.
> It is much more efficient to build the message content from start to end
> using `nng_msg_append`.
### Consume From Body
```c
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);
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);
```
The {{i:`nng_msg_chop`}} functions remove data from the end of the body of message _msg_,
reducing the message length by either _size_, or the appropriate value size.
The {{i:`nng_msg_trim`}} functions remove data from the beginning of the message body of _msg_.
but are otherwise just like the `nng_msg_chop` functions.
If the message is not big enough to remove requisite amount of bytes, these functions
return `NNG_EINVAL`. Otherwise they return zero.
Additionally, functions with typed suffixes (`_u16`, `_u32`, `_u64`) decode the data and return it
through the appropriate _val_ pointer.
The data is assumed to have been in network byte order in the message, but is returned in
the native machine byte order. The appropriate number of bytes is consumed for each of these types,
so two bytes for `_u16`, four bytes for `_u32`, and eight bytes for `_u64`.
## Message Header
```c
void *nng_msg_header(nng_msg *msg);
size_t nng_msg_header_len(nng_msg *msg);
```
The header and header length of _msg_ are returned by {{i:`nng_msg_header`}} and
{{i:`nng_msg_header_len`}}, respectively.
The message headers are generally intended for limited use, to store protocol headers.
> [!IMPORTANT]
> The message headers are for protocol and transport headers, and not for general
> application payloads. Misuse of the header may prevent the application from functioning
> properly.
### Clear the Header
```c
void *nng_msg_header_clear(nng_msg *msg);
```
The {{i:`nng_msg_header_clear`}} simply resets the total message header length to zero.
### Append or Insert Header
```c
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);
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);
```
Appending data to a message header is done by using the {{i:`nng_msg_header_append`}} functions,
and inserting data in the header is done using the {{i:`nng_msg_header_insert`}} functions.
These functions act just like the [`nng_msg_append`] and [`nng_msg_insert`] functions,
except that they operate on the message header rather than the message body.
### Consume from Header
```c
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);
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);
```
The {{i:`nng_msg_header_trim`}} functions remove data from the beginning of the message header,
and the {{i:`nng_msg_header_chop`}} functions remove data from the end of the message header.
These functions act just like the [`nng_msg_trim`] and [`nng_msg_chop`] functions,
except that they operate the message header rather than the message body.
## Message Pipe
```c
nng_pipe nng_msg_get_pipe(nng_msg *msg);
void nng_msg_get_pipe(nng_msg *msg, nng_pipe p);
```
The {{i:`nng_msg_set_pipe`}} function sets the [pipe] associated with _msg_ to _p_.
This is most often useful when used with protocols that support directing
a message to a specific peer.
For example the [_PAIR_][pair] version 1 protocol can do
this when `NNG_OPT_PAIR1_POLY` mode is set.
The {{i:`nng_msg_get_pipe`}} function returns the pipe that was previously set on the message _m_,
either directly by the application, or when the message was received by the protocol.
> [!NOTE]
> Not all protocols support overriding the destination pipe.
## Examples
### Example 1: Preparing a message for use
```c
#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
```c
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
}
}
```
{{#include ../xref.md}}
|