1COAP_BLOCK(3)                   libcoap Manual                   COAP_BLOCK(3)
2
3
4

NAME

6       coap_block, coap_context_set_block_mode, coap_add_data_large_request,
7       coap_add_data_large_response, coap_get_data_large,
8       coap_block_build_body - Work with CoAP Blocks
9

SYNOPSIS

11       #include <coap3/coap.h>
12
13       void coap_context_set_block_mode(coap_context_t *context, uint8_t
14       block_mode);
15
16       int coap_add_data_large_request(coap_session_t *session, coap_pdu_t
17       *pdu, size_t length, const uint8_t *data, coap_release_large_data_t
18       release_func, void *app_ptr);
19
20       int coap_add_data_large_response(coap_resource_t *resource,
21       coap_session_t *session, const coap_pdu_t *request, coap_pdu_t
22       *response, const coap_string_t *query, uint16_t media_type, int maxage,
23       uint64_t etag, size_t length, const uint8_t *data,
24       coap_release_large_data_t release_func, void *app_ptr);
25
26       int coap_get_data_large(const coap_pdu_t *pdu, size_t *length, const
27       uint8_t **_data, size_t *offset, size_t *total);
28
29       coap_binary_t * coap_block_build_body(coap_binary_t *body_data, size_t
30       length, const uint8_t *data, size_t offset, size_t total);
31
32       For specific (D)TLS library support, link with -lcoap-3-notls,
33       -lcoap-3-gnutls, -lcoap-3-openssl, -lcoap-3-mbedtls or
34       -lcoap-3-tinydtls. Otherwise, link with -lcoap-3 to get the default
35       (D)TLS library support.
36

DESCRIPTION

38       Regular setting up of a PDU and transmission is covered in
39       coap_pdu_setup(3) where all the payload data can fit into a single
40       packet. This man page covers how to work with PDUs where the overall
41       body of information may need to be split across several packets by
42       using CoAP Block-Wise Transfers (RFC 7959).
43
44       The block-wise transfers can be controlled by the application, or
45       libcoap is instructed to do all the requests for the next blocks and
46       only present the final body of the result to the application. This man
47       page focuses on getting libcoap to do all the work, not how to do it
48       all in the application.
49
50       However, if the client supplies a BLOCK1 or BLOCK2 Option in the PDU
51       where the block number is not 0, this is assumed to be a random access
52       request and any other blocks will not be requested by libcoap even if
53       instructed otherwise.
54
55       The functions that are named _large are intended as replacements for
56       the equivalent functions as described in coap_pdu_setup(3).
57
58       The coap_context_set_block_mode() function is used to set up the
59       context level block_mode block handling bits for supporting RFC7959.
60       block_mode flows down to a session when a session is created and if the
61       peer does not support the respective block mode, an appropriate bit may
62       get disabled in the session block_mode.
63
64           #define COAP_BLOCK_USE_LIBCOAP  0x01 /* Use libcoap to do block requests */
65           #define COAP_BLOCK_SINGLE_BODY  0x02 /* Deliver the data as a single body */
66
67       block_mode is an or’d set of zero or more COAP_BLOCK_* definitions.
68
69       If COAP_BLOCK_SINGLE_BODY is set, then the entire body of data is
70       presented to the receiving handler, otherwise each individual block is
71       presented on arrival. To obtain the data, length and current offset,
72       coap_get_data_large() must be used instead of coap_get_data(). It may
73       be appropriate not to set COAP_BLOCK_SINGLE_BODY if there are RAM
74       limitations.
75
76       NOTE: It is the responsibility of the receiving application to
77       re-assemble the data as appropriate (using coap_block_build_body()) if
78       COAP_BLOCK_SINGLE_BODY is not set.
79
80       NOTE: If COAP_BLOCK_SINGLE_BODY is not set, then the CoAP server on
81       receiving request data split over multiple blocks data must respond
82       with 2.31 (more data still to come), 2.01 or 2.04 (all data
83       successfully received) as appropriate.
84
85       If COAP_BLOCK_USE_LIBCOAP is set, then any PDUs presented to the
86       application handlers will get the tokens set back to the initiating
87       token so that requests can be matched with responses even if different
88       tokens had to be used for the series of packet interchanges.
89       Furthermore, if COAP_BLOCK_SINGLE_BODY is set, then the PDU that
90       presents the entire body will have any BLOCKx option removed.
91
92       NOTE: COAP_BLOCK_USE_LIBCOAP must be set if libcoap is to do all the
93       block tracking and requesting, otherwise the application will have to
94       do all of this work (the default if coap_context_set_block_mode() is
95       not called).
96
97           /**
98            * Callback handler for de-allocating the data based on @p app_ptr provided to
99            * coap_add_data_large_*() functions following transmission of the supplied
100            * data.
101            *
102            * @param session The session that this data is associated with
103            * @param app_ptr The application provided pointer to the
104            *                coap_add_data_large_*() functions
105            */
106           typedef void (*coap_release_large_data_t)(coap_session_t *session,
107                                                     void *app_ptr);
108
109       The coap_add_data_large_request() function is similar to
110       coap_add_data(), but supports the transmission of data that has a body
111       size that is potentially larger than can be fitted into a single client
112       request PDU. The specified payload data of length length is associated
113       with the session with the first block of data added to the PDU pdu
114       along with the appropriate CoAP options such as BLOCK1, and SIZE1 if
115       the data does not fit into a single PDU. When the block has been
116       acknowledged by the peer, the library will then send the next block of
117       data until all the data has been transmitted. This function must only
118       be called once per pdu. When the final block is transmitted, the
119       callback function release_func (if not NULL) with the user defined
120       parameter of app_ptr is called so that the data can be released.
121
122       The coap_add_data_large_response() function is responsible for handling
123       the server’s large responses to requests.
124       coap_add_data_large_response() should be used as a direct replacement
125       for coap_add_data() if it is possible that the length of data will not
126       fit into a single server’s response pdu. This function adds in the
127       initial part of the payload data of length length to the PDU pdu.
128       release_func (if not NULL) and app_ptr are used for releasing the data
129       when the body transfer is complete. It also adds in the appropriate
130       CoAP options such as BLOCK2, SIZE2 and ETAG to handle Block-Wise
131       transfer if the data does not fit into a single PDU. resource, query,
132       session, request, and response are the same parameters as in the called
133       resource handler that invokes coap_add_data_large_response(). If etag
134       is 0, then a unique ETag value will be generated, else is the ETag
135       value to use. The media_type is for the format of the data and maxage
136       defines the lifetime of the response. If maxage is set to -1, then the
137       MAXAGE option does not get included (which indicates the default value
138       of 60 seconds according to RFC 7252). This function must only be called
139       once per pdu. The application handler for the resource is only called
140       once instead of potentially multiple times.
141
142       The coap_get_data_large() function is used abstract from the pdu
143       information about the received data by updating length with the length
144       of data available, data with a pointer to where the data is located,
145       offset with where this block of data starts and total with the total
146       amount of data. offset will always be zero if block_mode includes
147       COAP_BLOCK_SINGLE_BODY. All of the body’s data has been received if
148       "offset + length == total".
149
150       NOTE: total is potentially only an indication of the total size of the
151       body and is only exact when all of the data has been received.
152
153       The coap_block_build_body() function is used to re-assemble the
154       received data as returned by coap_get_data_large() into a single blob
155       of data. Data from data of length length starting from offset offset is
156       added to body_data. The resultant state of body_data is returned. If
157       body_data is NULL, or total is larger than the current size of
158       body_data, then body_data is re-allocated and returned. If there is an
159       error, body_data gets de-allocated.
160
161       If block_mode (as set by coap_context_set_block_mode()) includes
162       COAP_BLOCK_SINGLE_BODY is used, then the response handler will only get
163       called once with the entire body containing the data from all of the
164       individual blocks. If there is a change of data during the blocks
165       receipt (e.g. ETag value changes), then the entire set of data is
166       re-requested and the partial body dropped.
167

RETURN VALUES

169       The coap_add_data_large_request(), coap_add_data_large_response(), and
170       coap_get_data_large() functions return 0 on failure, 1 on success.
171
172       The coap_block_build_body() returns the current state of the body’s
173       data (which may have some missing gaps) or NULL on error.
174

EXAMPLES

176       Setup PDU and Transmit
177
178           #include <coap3/coap.h>
179
180           static int
181           build_send_pdu(coap_context_t *context, coap_session_t *session,
182           uint8_t msgtype, uint8_t request_code, const char *uri, const char *query,
183           unsigned char *data, size_t length, int observe) {
184
185             coap_pdu_t *pdu;
186             uint8_t buf[1024];
187             size_t buflen;
188             uint8_t *sbuf = buf;
189             int res;
190             coap_optlist_t *optlist_chain = NULL;
191             /* Remove (void) definition if variable is used */
192             (void)context;
193
194             /* Create the pdu with the appropriate options */
195             pdu = coap_pdu_init(msgtype, request_code, coap_new_message_id(session),
196                                 coap_session_max_pdu_size(session));
197             if (!pdu)
198               return 0;
199
200             /*
201              * Create unique token for this request for handling unsolicited /
202              * delayed responses
203              */
204             coap_session_new_token(session, &buflen, buf);
205             if (!coap_add_token(pdu, buflen, buf)) {
206               coap_log(LOG_DEBUG, "cannot add token to request\n");
207               goto error;
208             }
209
210             if (uri) {
211               /* Add in the URI options */
212               buflen = sizeof(buf);
213               res = coap_split_path((const uint8_t*)uri, strlen(uri), sbuf, &buflen);
214               while (res--) {
215                 if (!coap_insert_optlist(&optlist_chain,
216                                          coap_new_optlist(COAP_OPTION_URI_PATH,
217                                   coap_opt_length(sbuf), coap_opt_value(sbuf))))
218                   goto error;
219                 sbuf += coap_opt_size(sbuf);
220               }
221             }
222
223             if (query) {
224               /* Add in the QUERY options */
225               buflen = sizeof(buf);
226               res = coap_split_query((const uint8_t*)query, strlen(query), sbuf, &buflen);
227               while (res--) {
228                 if (!coap_insert_optlist(&optlist_chain,
229                                          coap_new_optlist(COAP_OPTION_URI_QUERY,
230                                   coap_opt_length(sbuf), coap_opt_value(sbuf))))
231                   goto error;
232                 sbuf += coap_opt_size(sbuf);
233               }
234             }
235
236             if (request_code == COAP_REQUEST_GET && observe) {
237               /* Indicate that we want to observe this resource */
238               if (!coap_insert_optlist(&optlist_chain,
239                                        coap_new_optlist(COAP_OPTION_OBSERVE,
240                                          coap_encode_var_safe(buf, sizeof(buf),
241                                          COAP_OBSERVE_ESTABLISH), buf)
242                                        ))
243                 goto error;
244             }
245
246             /* ... Other code / options etc. ... */
247
248             /* Add in all the options (after internal sorting) to the pdu */
249             if (!coap_add_optlist_pdu(pdu, &optlist_chain))
250               goto error;
251
252             if (data && length) {
253               /* Add in the specified data */
254               if (!coap_add_data_large_request(session, pdu, length, data, NULL, NULL))
255                 goto error;
256             }
257
258             if (coap_send(session, pdu) == COAP_INVALID_MID)
259               goto error;
260             return 1;
261
262           error:
263
264             if (pdu)
265               coap_delete_pdu(pdu);
266             return 0;
267
268           }
269
270           int main(int argc, char *argv[]) {
271             coap_context_t *context = NULL;
272             coap_session_t *session = NULL;
273             unsigned char *data = NULL;
274             size_t data_length = 0;
275
276             (void)argc;
277             (void)argv;
278
279             /* ... Set up context, session etc. ... */
280
281             /* Set up using libcoap to do the block work */
282             coap_context_set_block_mode(context,
283                                         COAP_BLOCK_USE_LIBCOAP | COAP_BLOCK_SINGLE_BODY);
284
285             /* ... Other code etc. ... */
286
287             /* .. build data and define data_length ... */
288
289             build_send_pdu(context, session, COAP_MESSAGE_CON, COAP_REQUEST_PUT,
290                            "/example/uri", NULL, data, data_length, 0);
291
292             /* ... Other code etc. ... */
293
294             return 0;
295           }
296
297       Resource Handler Response PDU Update
298
299           #include <coap3/coap.h>
300
301           #include <stdio.h>
302
303           static void
304           hnd_get_time(coap_resource_t *resource, coap_session_t *session,
305           const coap_pdu_t *request, const coap_string_t *query, coap_pdu_t *response) {
306
307             unsigned char buf[40];
308             size_t len;
309             time_t now;
310
311             /* Note that request may be NULL if triggered by an observe response */
312
313             /* ... Additional analysis code for resource, request pdu etc.  ... */
314
315             /* After analysis, generate a failure response and return if needed */
316
317             now = time(NULL);
318
319             if (query != NULL && coap_string_equal(query, coap_make_str_const("secs"))) {
320               /* Output secs since Jan 1 1970 */
321               len = snprintf((char *)buf, sizeof(buf), "%lu", now);
322             }
323             else {
324               /* Output human-readable time */
325               struct tm *tmp;
326               tmp = gmtime(&now);
327               if (!tmp) {
328                 /* If 'now' is not valid */
329                 coap_pdu_set_code(response, COAP_RESPONSE_CODE_NOT_FOUND);
330                 return;
331               }
332               len = strftime((char *)buf, sizeof(buf), "%b %d %H:%M:%S", tmp);
333             }
334             coap_pdu_set_code(response, COAP_RESPONSE_CODE_CONTENT);
335             /*
336              * Invoke coap_add_data_large_response() to do all the hard work.
337              * [A good practice, even though ins this case, the amount of data is small]
338              *
339              * Define the format - COAP_MEDIATYPE_TEXT_PLAIN - to add in
340              * Define how long this response is valid for (secs) - 1 - to add in.
341              *
342              * OBSERVE Option added internally if needed within the function
343              * BLOCK2 Option added internally if output too large
344              * SIZE2 Option added internally
345              * ETAG Option added internally
346              */
347             coap_add_data_large_response(resource, session, request, response,
348                                          query, COAP_MEDIATYPE_TEXT_PLAIN, 1, 0,
349                                          len,
350                                          buf,
351                                          NULL, NULL);
352           }
353
354           int main(int argc, char *argv[]) {
355             coap_context_t *context = NULL;
356             coap_resource_t *r;
357
358             (void)argc;
359             (void)argv;
360
361             /* ... Set up context etc. ... */
362
363             /* Set up using libcoap to do the block work */
364             coap_context_set_block_mode(context,
365                                         COAP_BLOCK_USE_LIBCOAP | COAP_BLOCK_SINGLE_BODY);
366
367             /* Create a resource to return time */
368             r = coap_resource_init(coap_make_str_const("time"),
369                                    COAP_RESOURCE_FLAGS_NOTIFY_CON);
370             coap_resource_set_get_observable(r, 1);
371             coap_register_handler(r, COAP_REQUEST_GET, hnd_get_time);
372
373             /* Document resource for 'time' request */
374             coap_add_attr(r, coap_make_str_const("ct"), coap_make_str_const("0"), 0);
375             coap_add_attr(r, coap_make_str_const("title"),
376                           coap_make_str_const("\"Internal Clock\""), 0);
377             coap_add_attr(r, coap_make_str_const("rt"), coap_make_str_const("\"secs\""),
378                           0);
379             coap_add_attr(r, coap_make_str_const("if"), coap_make_str_const("\"clock\""),
380                           0);
381
382             coap_add_resource(context, r);
383
384             /* ... Loop waiting for incoming traffic ... */
385
386           }
387

SEE ALSO

389       coap_pdu_setup(3), coap_observe(3), and coap_resource(3)
390

FURTHER INFORMATION

392       See
393
394       "RFC7252: The Constrained Application Protocol (CoAP)"
395
396       "RFC7959: Block-Wise Transfers in the Constrained Application Protocol
397       (CoAP)"
398
399       for further information.
400
401       See
402       https://www.iana.org/assignments/core-parameters/core-parameters.xhtml#option-numbers
403       for the current set of defined CoAP Options.
404

BUGS

406       Please report bugs on the mailing list for libcoap:
407       libcoap-developers@lists.sourceforge.net or raise an issue on GitHub at
408       https://github.com/obgm/libcoap/issues
409

AUTHORS

411       The libcoap project <libcoap-developers@lists.sourceforge.net>
412
413
414
415coap_block 4.3.0                  01/20/2022                     COAP_BLOCK(3)
Impressum