1// -*- mode:doc; -*- 2// vim: set syntax=asciidoc tw=0 3 4coap_block(3) 5============= 6:doctype: manpage 7:man source: coap_block 8:man version: @PACKAGE_VERSION@ 9:man manual: libcoap Manual 10 11NAME 12---- 13coap_block, 14coap_context_set_block_mode, 15coap_add_data_large_request, 16coap_add_data_large_response, 17coap_get_data_large, 18coap_block_build_body, 19coap_q_block_is_supported 20- Work with CoAP Blocks 21 22SYNOPSIS 23-------- 24*#include <coap@LIBCOAP_API_VERSION@/coap.h>* 25 26*void coap_context_set_block_mode(coap_context_t *_context_, 27uint8_t _block_mode_);* 28 29*int coap_add_data_large_request(coap_session_t *_session_, 30coap_pdu_t *_pdu_, size_t _length_, const uint8_t *_data_, 31coap_release_large_data_t _release_func_, void *_app_ptr_);* 32 33*int coap_add_data_large_response(coap_resource_t *_resource_, 34coap_session_t *_session_, const coap_pdu_t *_request_, coap_pdu_t *_response_, 35const coap_string_t *query, uint16_t _media_type_, int _maxage_, 36uint64_t etag, size_t _length_, const uint8_t *_data_, 37coap_release_large_data_t _release_func_, void *_app_ptr_);* 38 39*int coap_get_data_large(const coap_pdu_t *_pdu_, size_t *_length, 40const uint8_t **_data_, size_t *_offset_, size_t *_total_);* 41 42*coap_binary_t *coap_block_build_body(coap_binary_t *_body_data_, 43size_t _length_, const uint8_t *_data_, size_t _offset_, size_t _total_);* 44 45*int coap_q_block_is_supported(void);* 46 47For specific (D)TLS library support, link with 48*-lcoap-@LIBCOAP_API_VERSION@-notls*, *-lcoap-@LIBCOAP_API_VERSION@-gnutls*, 49*-lcoap-@LIBCOAP_API_VERSION@-openssl*, *-lcoap-@LIBCOAP_API_VERSION@-mbedtls* 50or *-lcoap-@LIBCOAP_API_VERSION@-tinydtls*. Otherwise, link with 51*-lcoap-@LIBCOAP_API_VERSION@* to get the default (D)TLS library support. 52 53DESCRIPTION 54----------- 55Regular setting up of a PDU and transmission is covered in *coap_pdu_setup*(3) 56where all the payload data can fit in a single packet. This man page covers 57how to work with PDUs where the overall body of information may need to be 58split across several packets by using CoAP Block-Wise Transfers 59(https://rfc-editor.org/rfc/rfc7959[RFC7959] and 60https://rfc-editor.org/rfc/rfc9177[RFC9177]). 61 62The block-wise transfers can be controlled by the application, or libcoap is 63instructed to do all the requests for the next blocks and only present the 64final body of the result to the application. In summary, the following three 65ways handle processing a body of data that has to be split across multiple 66payloads (blocks). 67 681. Application does all the work + 69It is the responsibility of the application to analyze each block transmission 70at receipt and then generate the next request as per 71https://rfc-editor.org/rfc/rfc7959[RFC7959]. In this case, 72*coap_context_set_block_mode*() function must not be called to maintain 73backward compatibility with applications that did the block handling within the 74application. 75 762. Application sees individual blocks + 77By calling *coap_context_set_block_mode(context, COAP_BLOCK_USE_LIBCOAP)* and 78using the appropriate functions, the requests for the next block of data is 79handled automatically by the libcoap layer. Each individual block of data is 80presented to the application for processing. + 81By calling *coap_get_data_large*(), the application can determine if this is 82the first block or not (using _offset_ value), whether the first block is all 83the data (_offset_ = 0, _length_ = _total_) and whether this is the last block 84(_offset_ + _length_ = _total_). It is the responsibility of the application to 85re-assemble the individual blocks into a single body of data. + 86*NOTE:* _total_ is only an approximation (it will be > _offset_ + _length_) 87until the final block is received. + 88If this is the request handler in a server, the server still needs to return a 89COAP_RESPONSE_CODE_CONTINUE 2.31 (Continue) response code if the received data 90is not for the final block, otherwise a COAP_RESPONSE_CODE_CREATED 2.01 91(Created) or COAP_RESPONSE_CODE_CHANGED 2.04 (Changed) should be returned. 92 933. Application only sees all of the body + 94By calling *coap_context_set_block_mode(context, 95COAP_BLOCK_USE_LIBCOAP|COAP_BLOCK_SINGLE_BODY)* and using the appropriate 96functions, the requests for all the blocks of data is handled automatically by 97the libcoap layer. Only the complete body of the data is presented to the 98application, unless there is an error. + 99*coap_get_data_large*() will only return the entire body of data (_offset_ 100always 0, _length_ = _total_) and there is no need to re-assemble individual 101blocks into a large body of data. + 102In RAM constrained environments, option 2 may be the preferred method. 103 104This man page focuses on getting libcoap to do all the work, not how to do it 105all in the application. 106 107However, if the client supplies a Block1 or Block2 Option in the PDU where the 108block number is not 0, this is assumed to be a random access request and any 109other blocks will not be requested by libcoap even if instructed otherwise. 110 111The functions that are named *_large* are intended as replacements for the 112equivalent functions as described in *coap_pdu_setup*(3). 113 114CALLBACK HANDLER 115---------------- 116 117*Callback Type: coap_release_large_data_t* 118 119[source, c] 120---- 121/** 122 * Callback handler for de-allocating the data based on @p app_ptr provided to 123 * coap_add_data_large_*() functions following transmission of the supplied 124 * data. 125 * 126 * @param session The session that this data is associated with 127 * @param app_ptr The application provided pointer to the 128 * coap_add_data_large_*() functions 129 */ 130typedef void (*coap_release_large_data_t)(coap_session_t *session, 131 void *app_ptr); 132---- 133 134FUNCTIONS 135--------- 136 137*Function: coap_context_set_block_mode()* 138 139The *coap_context_set_block_mode*() function is used to set up the _context_ 140level _block_mode_ block handling bits for supporting 141https://rfc-editor.org/rfc/rfc7959[RFC7959] _block_mode_ 142flows down to a session when a session is created and if the peer does not 143support the respective block mode, an appropriate bit may get disabled in the 144session _block_mode_. 145 146[source, c] 147---- 148#define COAP_BLOCK_USE_LIBCOAP 0x01 /* Use libcoap to do block requests */ 149#define COAP_BLOCK_SINGLE_BODY 0x02 /* Deliver the data as a single body */ 150#define COAP_BLOCK_TRY_Q_BLOCK 0x04 /* Try Q-Block method */ 151#define COAP_BLOCK_USE_M_Q_BLOCK 0x08 /* Use M bit when recovering Q-Block2 */ 152#define COAP_BLOCK_NO_PREEMPTIVE_RTAG 0x10 /* Don't use pre-emptive Request-Tags */ 153---- 154_block_mode_ is an or'd set of zero or more COAP_BLOCK_* definitions. 155 156If *COAP_BLOCK_USE_LIBCOAP* is not set, then everything works as per Option 1 157above. 158 159If *COAP_BLOCK_SINGLE_BODY* is set, then the entire body of data is presented to 160the receiving handler, otherwise each individual block is presented on arrival. 161To obtain the data, length and current offset, *coap_get_data_large*() must 162be used instead of *coap_get_data*(). It may be appropriate not to set 163*COAP_BLOCK_SINGLE_BODY* if there are RAM limitations. 164 165*NOTE:* It is the responsibility of the receiving application to re-assemble 166the _data_ as appropriate (e.g., using *coap_block_build_body*()) if 167*COAP_BLOCK_SINGLE_BODY* is not set. 168 169*NOTE:* If *COAP_BLOCK_SINGLE_BODY* is not set, then the CoAP server on 170receiving 171request data that is split over multiple data blocks must respond with 172COAP_RESPONSE_CODE_CONTINUE 2.31 (Continue) response code if the received data 173is not for the final block, otherwise a COAP_RESPONSE_CODE_CREATED 2.01 174(Created) or COAP_RESPONSE_CODE_CHANGED 2.04 (Changed) should be returned. 175 176To indicate support for Q-Block-1 and Q-Block2, *COAP_BLOCK_TRY_Q_BLOCK* needs 177to be set on both the client and server. *COAP_BLOCK_SINGLE_BODY* is assumed to 178be set if using Q-Block as the data will always be presented as a single body. 179If *COAP_BLOCK_USE_M_Q_BLOCK* is defined, then the 'M' bit version of recovery 180will be used if possible. 181 182If *COAP_BLOCK_USE_LIBCOAP* is set, then any PDUs presented to the application 183handlers will get the tokens set back to the initiating token so that requests 184can be matched with responses even if different tokens had to be used for the 185series of packet interchanges. Furthermore, if *COAP_BLOCK_SINGLE_BODY* is set, 186then the PDU that presents the entire body will have any BlockX or Q-BlockX 187option removed. 188 189*NOTE:* *COAP_BLOCK_USE_LIBCOAP* must be set if libcoap is to do all the 190block tracking and requesting, otherwise the application will have to do all 191of this work (the default if *coap_context_set_block_mode*() is not called). 192 193If *COAP_BLOCK_NO_PREEMPTIVE_RTAG* is set, then Request-Tag options are only 194sent when a large amount of data is being sent to the server using the Block1 195option. Otherwise, a Request-Tag option is sent with any request (apart from 196DELETE) on the off chance that there may be multiple Block2 based 197responses for multiple requests to the same resource that need to be 198differentiated between. 199 200*Function: coap_add_data_large_request()* 201 202The *coap_add_data_large_request*() function is similar to *coap_add_data*(), 203but supports the transmission of data that has a body size that is potentially 204larger than can be fitted into a single client request PDU. The specified 205payload _data_ of length _length_ is associated with the _session_ with the 206first block of data added to the PDU _pdu_ along with the appropriate CoAP 207options such as (Q-)Block1, Size1 and Request-Tag if the data does not fit in 208a single PDU. 209 210When the block receipt has been acknowledged by the peer, the library 211will then send the next block of data until all the data has been transmitted. 212 213The _data_ passed to the 214function *coap_add_data_large_request*() must exist until all blocks have been 215transmitted. The callback function _release_func_ can be used to release 216storage that has been dynamically allocated to hold the transmit data. If not 217NULL, the callback function is called once the final block of _data_ has been 218transmitted. The user-defined parameter _app_ptr_ is the same value that was 219passed to *coap_add_data_large_request*(). 220 221*NOTE:* This function must only be called once per _pdu_. 222 223*NOTE:* Options cannot be added to the _pdu_ after 224coap_add_data_large_request() is called. 225 226*Function: coap_add_data_large_response()* 227 228The *coap_add_data_large_response*() function is responsible for handling 229the server's large responses to requests. *coap_add_data_large_response*() 230should be used as a direct replacement for *coap_add_data*() if it is possible 231that the _length_ of _data_ will not fit in a single server's response pdu. 232This function adds in the initial part of the payload _data_ of length 233_length_ to the PDU _pdu_. 234 235The _data_ passed to the function 236*coap_add_data_large_response*() must exist until all blocks have been 237transmitted. The callback function _release_func_ can be used to release 238storage that has been dynamically allocated to hold the transmit data. If not 239NULL, the callback function is called once the final block of _data_ has been 240transmitted. The user-defined parameter _app_ptr_ is the same value that was 241passed to *coap_add_data_large_response*(). 242 243It also adds in the appropriate CoAP options such as Block2, Size2 and ETag to 244handle block-wise transfer if the data does not fit in a single PDU. 245 246_resource_, _query_, _session_, _request_, and _response_ are the same 247parameters as in the called resource handler that invokes 248*coap_add_data_large_response*(). If _etag_ is 0, then a unique ETag value will 249be generated, else is the ETag value to use. 250The _media_type_ is for the format of the _data_ and _maxage_ defines the 251lifetime of the response. If _maxage_ is set to -1, then the Max-Age option 252does not get included (which indicates the default value of 60 seconds 253according to 254"https://rfc-editor.org/rfc/rfc7252#section-5.6.1[RFC7252 5.6.1. Freshness 255Model]"). 256 257The application request handler for the resource is only called once instead of 258potentially multiple times. 259 260*NOTE:* This function must only be called once per _pdu_. 261 262*NOTE:* Options cannot be added to the _pdu_ after 263coap_add_data_large_request() is called. 264 265*Function: coap_get_data_large()* 266 267The *coap_get_data_large*() function is used abstract from the _pdu_ 268information about the received data by updating _length_ with the length of 269data available, _data_ with a pointer to where the data is located, _offset_ 270with where this block of data starts and _total_ with the total amount of data. 271_offset_ will always be zero if block_mode includes COAP_BLOCK_SINGLE_BODY. 272All of the body's data has been received if "_offset_ + _length_ == _total_". 273 274*NOTE:* _total_ is potentially only an indication of the total size of the 275body and is only exact when all of the data has been received. 276 277*Function: coap_block_build_body()* 278 279The *coap_block_build_body*() function is used to re-assemble the received 280data as returned by *coap_get_data_large*() into a single blob of data. Data 281from _data_ of length _length_ starting from offset _offset_ is added to 282_body_data_. The resultant state of _body_data_ is returned. If _body_data_ 283is NULL, or _total_ is larger than the current size of _body_data_, then 284_body_data_ is re-allocated and returned. If there is an error, _body_data_ 285gets de-allocated. 286 287If _block_mode_ (as set by *coap_context_set_block_mode*()) includes 288COAP_BLOCK_SINGLE_BODY, then the request/response handler will only get called 289once with the entire body containing the data from all of the individual 290blocks. If there is a change of data during the blocks receipt (e.g., ETag 291value changes), then the entire set of data is re-requested and the partial 292body dropped. 293 294*Function: coap_q_block_is_supported()* 295 296The *coap_q_block_is_supported*() function is used to determine whether 297libcoap has been build with Q-Block support or not. 298 299RETURN VALUES 300------------- 301*coap_add_data_large_request*(), *coap_add_data_large_response*(), and 302*coap_get_data_large*() return 0 on failure, 1 on success. 303 304*coap_block_build_body*() returns the current state of the body's data 305(which may have some missing gaps) or NULL on error. 306 307*coap_q_block_is_supported*() returns 0 on failure, 1 on success. 308 309EXAMPLES 310-------- 311*Setup PDU and Transmit* 312 313[source, c] 314---- 315#include <coap@LIBCOAP_API_VERSION@/coap.h> 316 317static int 318build_send_pdu(coap_context_t *context, coap_session_t *session, 319uint8_t msgtype, uint8_t request_code, const char *uri, const char *query, 320unsigned char *data, size_t length, int observe) { 321 322 coap_pdu_t *pdu; 323 uint8_t buf[1024]; 324 size_t buflen; 325 uint8_t *sbuf = buf; 326 int res; 327 coap_optlist_t *optlist_chain = NULL; 328 /* Remove (void) definition if variable is used */ 329 (void)context; 330 331 /* Create the pdu with the appropriate options */ 332 pdu = coap_pdu_init(msgtype, request_code, coap_new_message_id(session), 333 coap_session_max_pdu_size(session)); 334 if (!pdu) 335 return 0; 336 337 /* 338 * Create unique token for this request for handling unsolicited / 339 * delayed responses 340 */ 341 coap_session_new_token(session, &buflen, buf); 342 if (!coap_add_token(pdu, buflen, buf)) { 343 coap_log_debug("cannot add token to request\n"); 344 goto error; 345 } 346 347 if (uri) { 348 /* Add in the URI options */ 349 buflen = sizeof(buf); 350 res = coap_split_path((const uint8_t*)uri, strlen(uri), sbuf, &buflen); 351 while (res--) { 352 if (!coap_insert_optlist(&optlist_chain, 353 coap_new_optlist(COAP_OPTION_URI_PATH, 354 coap_opt_length(sbuf), coap_opt_value(sbuf)))) 355 goto error; 356 sbuf += coap_opt_size(sbuf); 357 } 358 } 359 360 if (query) { 361 /* Add in the QUERY options */ 362 buflen = sizeof(buf); 363 res = coap_split_query((const uint8_t*)query, strlen(query), sbuf, &buflen); 364 while (res--) { 365 if (!coap_insert_optlist(&optlist_chain, 366 coap_new_optlist(COAP_OPTION_URI_QUERY, 367 coap_opt_length(sbuf), coap_opt_value(sbuf)))) 368 goto error; 369 sbuf += coap_opt_size(sbuf); 370 } 371 } 372 373 if (request_code == COAP_REQUEST_GET && observe) { 374 /* Indicate that we want to observe this resource */ 375 if (!coap_insert_optlist(&optlist_chain, 376 coap_new_optlist(COAP_OPTION_OBSERVE, 377 coap_encode_var_safe(buf, sizeof(buf), 378 COAP_OBSERVE_ESTABLISH), buf) 379 )) 380 goto error; 381 } 382 383 /* ... Other code / options etc. ... */ 384 385 /* Add in all the options (after internal sorting) to the pdu */ 386 if (!coap_add_optlist_pdu(pdu, &optlist_chain)) 387 goto error; 388 389 if (data && length) { 390 /* Add in the specified data */ 391 if (!coap_add_data_large_request(session, pdu, length, data, NULL, NULL)) 392 goto error; 393 } 394 395 if (coap_send(session, pdu) == COAP_INVALID_MID) 396 goto error; 397 return 1; 398 399error: 400 401 if (pdu) 402 coap_delete_pdu(pdu); 403 return 0; 404 405} 406 407int 408main(int argc, char *argv[]) { 409 coap_context_t *context = NULL; 410 coap_session_t *session = NULL; 411 unsigned char *data = NULL; 412 size_t data_length = 0; 413 414 (void)argc; 415 (void)argv; 416 417 /* Initialize libcoap library */ 418 coap_startup(); 419 420 /* ... Set up context, session etc. ... */ 421 422 /* Set up using libcoap to do the block work */ 423 coap_context_set_block_mode(context, 424 COAP_BLOCK_USE_LIBCOAP | COAP_BLOCK_SINGLE_BODY); 425 426 /* ... Other code etc. ... */ 427 428 /* .. build data and define data_length ... */ 429 430 build_send_pdu(context, session, COAP_MESSAGE_CON, COAP_REQUEST_PUT, 431 "/example/uri", NULL, data, data_length, 0); 432 433 /* ... Other code etc. ... */ 434 435 coap_cleanup(); 436 return 0; 437} 438---- 439 440*Resource Request Handler Response PDU Update* 441 442[source, c] 443---- 444#include <coap@LIBCOAP_API_VERSION@/coap.h> 445 446#include <stdio.h> 447 448static void 449hnd_get_time(coap_resource_t *resource, coap_session_t *session, 450const coap_pdu_t *request, const coap_string_t *query, coap_pdu_t *response) { 451 452 unsigned char buf[40]; 453 size_t len; 454 time_t now; 455 456 /* ... Additional analysis code for resource, request pdu etc. ... */ 457 458 /* After analysis, generate a failure response and return if needed */ 459 460 now = time(NULL); 461 462 if (query != NULL && coap_string_equal(query, coap_make_str_const("secs"))) { 463 /* Output secs since Jan 1 1970 */ 464 len = snprintf((char *)buf, sizeof(buf), "%lu", now); 465 } 466 else { 467 /* Output human-readable time */ 468 struct tm *tmp; 469 tmp = gmtime(&now); 470 if (!tmp) { 471 /* If 'now' is not valid */ 472 coap_pdu_set_code(response, COAP_RESPONSE_CODE_NOT_FOUND); 473 return; 474 } 475 len = strftime((char *)buf, sizeof(buf), "%b %d %H:%M:%S", tmp); 476 } 477 coap_pdu_set_code(response, COAP_RESPONSE_CODE_CONTENT); 478 /* 479 * Invoke coap_add_data_large_response() to do all the hard work. 480 * [A good practice, even though ins this case, the amount of data is small] 481 * 482 * Define the format - COAP_MEDIATYPE_TEXT_PLAIN - to add in 483 * Define how long this response is valid for (secs) - 1 - to add in. 484 * 485 * Observe Option added internally if needed within the function 486 * Block2 Option added internally if output too large 487 * Size2 Option added internally 488 * ETag Option added internally 489 */ 490 coap_add_data_large_response(resource, session, request, response, 491 query, COAP_MEDIATYPE_TEXT_PLAIN, 1, 0, 492 len, 493 buf, 494 NULL, NULL); 495 /* 496 * When request handler returns, the response pdu will get automatically 497 * sent, unless the pdu code is not updated and this is a NON or TCP based 498 * request. 499 */ 500} 501 502int 503main(int argc, char *argv[]) { 504 coap_context_t *context = NULL; 505 coap_resource_t *r; 506 coap_resource_t *time_resource; 507 int not_exit = 1; 508 509 /* Initialize libcoap library */ 510 coap_startup(); 511 512 (void)argc; 513 (void)argv; 514 515 /* ... Set up context etc. ... */ 516 517 /* Set up using libcoap to do the block work */ 518 coap_context_set_block_mode(context, 519 COAP_BLOCK_USE_LIBCOAP | COAP_BLOCK_SINGLE_BODY); 520 521 /* Create a resource to return time */ 522 r = coap_resource_init(coap_make_str_const("time"), 523 COAP_RESOURCE_FLAGS_NOTIFY_CON); 524 coap_resource_set_get_observable(r, 1); 525 coap_register_request_handler(r, COAP_REQUEST_GET, hnd_get_time); 526 527 /* Document resource for 'time' request */ 528 coap_add_attr(r, coap_make_str_const("ct"), coap_make_str_const("0"), 0); 529 coap_add_attr(r, coap_make_str_const("title"), 530 coap_make_str_const("\"Internal Clock\""), 0); 531 coap_add_attr(r, coap_make_str_const("rt"), coap_make_str_const("\"secs\""), 532 0); 533 coap_add_attr(r, coap_make_str_const("if"), coap_make_str_const("\"clock\""), 534 0); 535 536 coap_add_resource(context, r); 537 time_resource = r; 538 539 /* ... Loop waiting for incoming traffic ... */ 540 while (!not_exit) { 541 coap_io_process(context, 1000); 542 543 /* Cause a notification to anyone Observing 'time' */ 544 coap_resource_notify_observers(time_resource, NULL); 545 } 546 547 /* Clean up */ 548 549 coap_free_context(context); 550 coap_cleanup(); 551 552} 553---- 554 555SEE ALSO 556-------- 557*coap_init*(3) *coap_pdu_setup*(3), *coap_observe*(3), and *coap_resource*(3) 558 559FURTHER INFORMATION 560------------------- 561See 562 563"https://rfc-editor.org/rfc/rfc7252[RFC7252: The Constrained Application Protocol (CoAP)]" 564 565"https://rfc-editor.org/rfc/rfc7959[RFC7959: Block-Wise Transfers in the Constrained Application Protocol (CoAP)]" 566 567for further information. 568 569BUGS 570---- 571Please report bugs on the mailing list for libcoap: 572libcoap-developers@lists.sourceforge.net or raise an issue on GitHub at 573https://github.com/obgm/libcoap/issues 574 575AUTHORS 576------- 577The libcoap project <libcoap-developers@lists.sourceforge.net> 578