diff options
Diffstat (limited to 'docs/ref/api/msg.md')
| -rw-r--r-- | docs/ref/api/msg.md | 274 |
1 files changed, 274 insertions, 0 deletions
diff --git a/docs/ref/api/msg.md b/docs/ref/api/msg.md new file mode 100644 index 00000000..569d4692 --- /dev/null +++ b/docs/ref/api/msg.md @@ -0,0 +1,274 @@ +# 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:message body}}, containing the application-supplied +payload, and a [header][nng_msg_header]{{hi:message 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 succes, 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. +This function returns either zero, or `NNG_ENOMEM`. + +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 + +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`][nng_msg_append] and [`nng_msg_insert`][nng_msg_insert] +functions, except that they operate on the message header rather than the message body. + +### Consume from Header + +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`][nng_msg_trim] and [`nng_msg_chop`][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][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 + } + } +``` + +[nng_msg_body]: #message-body +[nng_msg_header]: #message-header +[nng_msg_append]: #add-to-body +[nng_msg_insert]: #add-to-body +[nng_msg_trim]: #consume-from-body +[nng_msg_chop]: #consume-from-body +[nng_msg_header_append]: #append-or-insert-header +[raw]: TODO.md +[pair]: ../proto/pair.md +[pipe]: TODO.md |
