Skip site navigation (1)Skip section navigation (2)

FreeBSD Manual Pages

  
 
  

home | help
COAP_BLOCK(3)			libcoap	Manual			 COAP_BLOCK(3)

NAME
       coap_block, coap_context_set_block_mode,
       coap_context_set_max_block_size,	coap_add_data_large_request,
       coap_add_data_large_response, coap_get_data_large,
       coap_block_build_body, coap_q_block_is_supported	- Work with CoAP
       Blocks

SYNOPSIS
       #include	<coap3/coap.h>

       void coap_context_set_block_mode(coap_context_t *context, uint32_t
       block_mode);

       int coap_context_set_max_block_size(coap_context_t *context, size_t
       max_block_size);

       int coap_add_data_large_request(coap_session_t *session,	coap_pdu_t
       *pdu, size_t length, const uint8_t *data, coap_release_large_data_t
       release_func, void *app_ptr);

       int coap_add_data_large_response(coap_resource_t	*resource,
       coap_session_t *session,	const coap_pdu_t *request, coap_pdu_t
       *response, const	coap_string_t *query, uint16_t media_type, int maxage,
       uint64_t	etag, size_t length, const uint8_t *data,
       coap_release_large_data_t release_func, void *app_ptr);

       int coap_get_data_large(const coap_pdu_t	*pdu, size_t *length, const
       uint8_t **_data,	size_t *offset,	size_t *total);

       coap_binary_t *coap_block_build_body(coap_binary_t *body_data, size_t
       length, const uint8_t *data, size_t offset, size_t total);

       int coap_q_block_is_supported(void);

       For specific (D)TLS library support, link with -lcoap-3-notls,
       -lcoap-3-gnutls,	-lcoap-3-openssl, -lcoap-3-mbedtls, -lcoap-3-wolfssl
       or -lcoap-3-tinydtls. Otherwise,	link with -lcoap-3 to get the default
       (D)TLS library support.

DESCRIPTION
       Regular setting up of a PDU and transmission is covered in
       coap_pdu_setup(3) where all the payload data can	fit in a single
       packet. This man	page covers how	to work	with PDUs where	the overall
       body of information may need to be split	across several packets by
       using CoAP Block-Wise Transfers (RFC7959	and RFC9177).

       The block-wise transfers	can be controlled by the application, or
       libcoap is instructed to	do all the requests for	the next blocks	and
       only present the	final body of the result to the	application. In
       summary,	the following three ways handle	processing a body of data that
       has to be split across multiple payloads	(blocks).

	1. Application does all	the work

	   It is the responsibility of the application to analyze each block
	   transmission	at receipt and then generate the next request as per
	   RFC7959. In this case, coap_context_set_block_mode()	function must
	   not be called to maintain backward compatibility with applications
	   that	did the	block handling within the application.

	2. Application sees individual blocks

	   By calling coap_context_set_block_mode(context,
	   COAP_BLOCK_USE_LIBCOAP) and using the appropriate functions,	the
	   requests for	the next block of data is handled automatically	by the
	   libcoap layer. Each individual block	of data	is presented to	the
	   application for processing.

	   By calling coap_get_data_large(), the application can determine if
	   this	is the first block or not (using offset	value),	whether	the
	   first block is all the data (offset = 0, length = total) and
	   whether this	is the last block (offset + length = total). It	is the
	   responsibility of the application to	re-assemble the	individual
	   blocks into a single	body of	data.

	   NOTE: total is only an approximation	(it will be > offset + length)
	   until the final block is received.

	   If this is the request handler in a server, the server still	needs
	   to return a COAP_RESPONSE_CODE_CONTINUE 2.31	(Continue) response
	   code	if the received	data is	not for	the final block, otherwise a
	   COAP_RESPONSE_CODE_CREATED 2.01 (Created) or
	   COAP_RESPONSE_CODE_CHANGED 2.04 (Changed) should be returned.

	3. Application only sees all of	the body

	   By calling coap_context_set_block_mode(context,
	   COAP_BLOCK_USE_LIBCOAP|COAP_BLOCK_SINGLE_BODY) and using the
	   appropriate functions, the requests for all the blocks of data is
	   handled automatically by the	libcoap	layer. Only the	complete body
	   of the data is presented to the application,	unless there is	an
	   error.

	   coap_get_data_large() will only return the entire body of data
	   (offset always 0, length = total) and there is no need to
	   re-assemble individual blocks into a	large body of data.

	   In RAM constrained environments, option 2 may be the	preferred
	   method.

       This man	page focuses on	getting	libcoap	to do all the work, not	how to
       do it all in the	application.

       However,	if the client supplies a Block1	or Block2 Option in a GET
       request type PDU	where the block	number is not 0, this is assumed to be
       a random	access request and any other blocks will not be	requested by
       libcoap even if instructed otherwise.

       The functions that are named _large are intended	as replacements	for
       the equivalent functions	as described in	coap_pdu_setup(3).

CALLBACK HANDLER
       Callback	Type: coap_release_large_data_t

	   /**
	    * Callback handler for de-allocating the data based	on @p app_ptr provided to
	    * coap_add_data_large_*() functions	following transmission of the supplied
	    * data.
	    *
	    * @param session The session that this data	is associated with
	    * @param app_ptr The application provided pointer to the
	    *		     coap_add_data_large_*() functions
	    */
	   typedef void	(*coap_release_large_data_t)(coap_session_t *session,
						     void *app_ptr);

FUNCTIONS
       Function: coap_context_set_block_mode()

       The coap_context_set_block_mode() function is used to set up the
       context level block_mode	block handling bits for	supporting RFC7959
       block_mode flows	down to	a session when a session is created and	if the
       peer does not support the respective block mode,	an appropriate bit may
       get disabled in the session block_mode.

	   #define COAP_BLOCK_USE_LIBCOAP   0x01 /* Use	libcoap	to do block requests */
	   #define COAP_BLOCK_SINGLE_BODY   0x02 /* Deliver the	data as	a single body */
	   #define COAP_BLOCK_TRY_Q_BLOCK   0x04 /* Try	Q-Block	method */
	   #define COAP_BLOCK_USE_M_Q_BLOCK 0x08 /* (Client) Use M bit when recovering Q-Block2	*/
	   #define COAP_BLOCK_NO_PREEMPTIVE_RTAG 0x10 /* (Client) Don't	use pre-emptive	Request-Tags */
	   #define COAP_BLOCK_STLESS_FETCH  0x20 /* (Client) Assume server supports stateless FETCH */
	   #define COAP_BLOCK_STLESS_BLOCK2 0x40 /* (Server) Server is stateless for Block2 transfers */
	   #define COAP_BLOCK_NOT_RANDOM_BLOCK1	0x80 /*	(Server) Disable server	handling random	order block1 */

       block_mode is an	or'd set of zero or more COAP_BLOCK_* definitions.

       If COAP_BLOCK_USE_LIBCOAP is not	set, then everything works as per
       Option 1	above.

       If COAP_BLOCK_SINGLE_BODY is set, then the entire body of data is
       presented to the	receiving handler, otherwise each individual block is
       presented on arrival. To	obtain the data, length	and current offset,
       coap_get_data_large() must be used instead of coap_get_data(). It may
       be appropriate not to set COAP_BLOCK_SINGLE_BODY	if there are RAM
       limitations.

       NOTE: It	is the responsibility of the receiving application to
       re-assemble the data as appropriate (e.g., using
       coap_block_build_body())	if COAP_BLOCK_SINGLE_BODY is not set.

       NOTE: If	COAP_BLOCK_SINGLE_BODY is not set, then	the CoAP server	on
       receiving request data that is split over multiple data blocks must
       respond with COAP_RESPONSE_CODE_CONTINUE	2.31 (Continue)	response code
       if the received data is not for the final block,	otherwise a
       COAP_RESPONSE_CODE_CREATED 2.01 (Created) or COAP_RESPONSE_CODE_CHANGED
       2.04 (Changed) should be	returned.

       To indicate support for Q-Block-1 and Q-Block2, COAP_BLOCK_TRY_Q_BLOCK
       needs to	be set on both the client and server. COAP_BLOCK_SINGLE_BODY
       is assumed to be	set if using Q-Block as	the data will always be
       presented as a single body. If COAP_BLOCK_USE_M_Q_BLOCK is defined,
       then the	M bit version of recovery will be used if possible.

       If COAP_BLOCK_USE_LIBCOAP is set, then any PDUs presented to the
       application handlers will get the tokens	set back to the	initiating
       token so	that requests can be matched with responses even if different
       tokens had to be	used for the series of packet interchanges.
       Furthermore, if COAP_BLOCK_SINGLE_BODY is set, then the PDU that
       presents	the entire body	will have any BlockX or	Q-BlockX option
       removed.

       NOTE: COAP_BLOCK_USE_LIBCOAP must be set	if libcoap is to do all	the
       block tracking and requesting, otherwise	the application	will have to
       do all of this work (the	default	if coap_context_set_block_mode() is
       not called).

       If COAP_BLOCK_NO_PREEMPTIVE_RTAG	is set,	then Request-Tag options are
       only sent when a	large amount of	data is	being sent to the server using
       the Block1 option. Otherwise, a Request-Tag option is sent with any
       request (apart from DELETE) on the off chance that there	may be
       multiple	Block2 based responses for multiple requests to	the same
       resource	that need to be	differentiated between.

       If COAP_BLOCK_STLESS_FETCH is set, then it is assumed that the server
       supports	stateless support for FETCH requests - in other	words, the
       FETCH request always includes the FETCH data when requesting the	next
       block of	data from the server when using	Block2.

       If COAP_BLOCK_STLESS_BLOCK2 is set, then	the server does	not maintain
       state for any data returned that	uses Block2 to split up	the data
       chunks. The application is called for every request to get the complete
       set of data which is then split into the	separate Block2	responses as
       appropriate.

       If COAP_BLOCK_NOT_RANDOM_BLOCK1 is set, then the	server does not	allow
       any Block1 packets arriving in the wrong	block number order by
       returning 4.08 error codes. Normally this should	not be set as networks
       can re-order the	arrival	of UDP packets,	in particular this may happen
       if NON is being used for	Block1 by the client.

       NOTE: This is ignored if	Q-Block1 is being used.

       Function: coap_context_set_max_block_size()

       The coap_context_set_max_block_size() function is used to set the
       max_block_size in the context that a server supports when the Block1 or
       Block2 options are used.	This must be set before	a server session is
       created.

       Function: coap_add_data_large_request()

       The coap_add_data_large_request() function is similar to
       coap_add_data(),	but supports the transmission of data that has a body
       size that is potentially	larger than can	be fitted into a single	client
       request PDU. The	specified payload data of length length	is associated
       with the	session	with the first block of	data added to the PDU pdu
       along with the appropriate CoAP options such as (Q-)Block1, Size1 and
       Request-Tag if the data does not	fit in a single	PDU.

       When the	block receipt has been acknowledged by the peer, the library
       will then send the next block of	data until all the data	has been
       transmitted.

       The data	passed to the function coap_add_data_large_request() must
       exist until all blocks have been	transmitted. The callback function
       release_func can	be used	to release storage that	has been dynamically
       allocated to hold the transmit data. If not NULL, the callback function
       is called once the final	block of data has been transmitted. The
       user-defined parameter app_ptr is the same value	that was passed	to
       coap_add_data_large_request(). Even if there is an error	return,
       release_func (if	set) is	always called.

       NOTE: This function must	only be	called once per	pdu.

       NOTE: Options cannot be added to	the pdu	after
       coap_add_data_large_request() is	called.

       Function: coap_add_data_large_response()

       The coap_add_data_large_response() function is responsible for handling
       the server's large responses to requests.
       coap_add_data_large_response() should be	used as	a direct replacement
       for coap_add_data() if it is possible that the length of	data will not
       fit in a	single server's	response pdu. This function adds in the
       initial part of the payload data	of length length to the	PDU pdu.

       The data	passed to the function coap_add_data_large_response() must
       exist until all blocks have been	transmitted. The callback function
       release_func can	be used	to release storage that	has been dynamically
       allocated to hold the transmit data. If not NULL, the callback function
       is called once the final	block of data has been transmitted. The
       user-defined parameter app_ptr is the same value	that was passed	to
       coap_add_data_large_response(). Even if there is	an error return,
       release_func (if	set) is	always called.

       It also adds in the appropriate CoAP options such as Block2, Size2 and
       ETag to handle block-wise transfer if the data does not fit in a	single
       PDU.

       resource, query,	session, request, and response are the same parameters
       as in the called	resource handler that invokes
       coap_add_data_large_response(). If etag is 0, then a unique ETag	value
       will be generated, else is the ETag value to use. The media_type	is for
       the format of the data and maxage defines the lifetime of the response.
       If maxage is set	to -1, then the	Max-Age	option does not	get included
       (which indicates	the default value of 60	seconds	according to "RFC7252
       5.6.1. Freshness	Model").

       The application request handler for the resource	is only	called once
       instead of potentially multiple times.

       NOTE: This function must	only be	called once per	pdu.

       NOTE: Options cannot be added to	the pdu	after
       coap_add_data_large_request() is	called.

       Function: coap_get_data_large()

       The coap_get_data_large() function is used abstract from	the pdu
       information about the received data by updating length with the length
       of data available, data with a pointer to where the data	is located,
       offset with where this block of data starts and total with the total
       amount of data. offset will always be zero if block_mode	includes
       COAP_BLOCK_SINGLE_BODY. All of the body's data has been received	if
       "offset + length	== total".

       NOTE: total is potentially only an indication of	the total size of the
       body and	is only	exact when all of the data has been received.

       Function: coap_block_build_body()

       The coap_block_build_body() function is used to re-assemble the
       received	data as	returned by coap_get_data_large() into a single	blob
       of data.	Data from data of length length	starting from offset offset is
       added to	body_data. The resultant state of body_data is returned. If
       body_data is NULL, or total is larger than the current size of
       body_data, then body_data is re-allocated and returned. If there	is an
       error, body_data	gets de-allocated.

       If block_mode (as set by	coap_context_set_block_mode()) includes
       COAP_BLOCK_SINGLE_BODY, then the	request/response handler will only get
       called once with	the entire body	containing the data from all of	the
       individual blocks. If there is a	change of data during the blocks
       receipt (e.g., ETag value changes), then	the entire set of data is
       re-requested and	the partial body dropped.

       Function: coap_q_block_is_supported()

       The coap_q_block_is_supported() function	is used	to determine whether
       libcoap has been	build with Q-Block support or not.

RETURN VALUES
       coap_add_data_large_request(), coap_add_data_large_response(), and
       coap_get_data_large() return 0 on failure, 1 on success.

       coap_block_build_body() returns the current state of the	body's data
       (which may have some missing gaps) or NULL on error.

       coap_context_set_max_block_size() returns 0 on failure, 1 on success.

       coap_q_block_is_supported() returns 0 on	failure, 1 on success.

EXAMPLES
       Setup PDU and Transmit

	   #include <coap3/coap.h>

	   static int
	   build_send_pdu(coap_context_t *context, coap_session_t *session,
			  uint8_t msgtype, uint8_t request_code, const char *path,
			  const	char *query, unsigned char *data, size_t length,
			  int observe) {
	     coap_pdu_t	*pdu;
	     uint8_t buf[8];
	     size_t buflen;
	     coap_optlist_t *optlist_chain = NULL;
	     /*	Remove (void) definition if variable is	used */
	     (void)context;

	     /*	Create the pdu with the	appropriate options */
	     pdu = coap_pdu_init(msgtype, request_code,	coap_new_message_id(session),
				 coap_session_max_pdu_size(session));
	     if	(!pdu)
	       return 0;

	     /*
	      *	Create unique token for	this request for handling unsolicited /
	      *	delayed	responses
	      */
	     coap_session_new_token(session, &buflen, buf);
	     if	(!coap_add_token(pdu, buflen, buf)) {
	       coap_log_debug("cannot add token	to request\n");
	       goto error;
	     }

	     if	(path) {
	       /* Add in the Uri-Path options */
	       if (!coap_path_into_optlist((const uint8_t *)path, strlen(path),
					   COAP_OPTION_URI_PATH, &optlist_chain))
		 goto error;
	     }

	     if	(query)	{
	       /* Add in the Uri-Query options */
	       if (!coap_query_into_optlist((const uint8_t *)query, strlen(query),
					    COAP_OPTION_URI_QUERY, &optlist_chain))
		 goto error;
	     }

	     if	(request_code == COAP_REQUEST_GET && observe) {
	       /* Indicate that	we want	to observe this	resource */
	       if (!coap_insert_optlist(&optlist_chain,
					coap_new_optlist(COAP_OPTION_OBSERVE,
							 coap_encode_var_safe(buf, sizeof(buf),
							     COAP_OBSERVE_ESTABLISH), buf)
				       ))
		 goto error;
	     }

	     /*	... Other code / options etc. ... */

	     /*	Add in all the options (after internal sorting)	to the pdu */
	     if	(!coap_add_optlist_pdu(pdu, &optlist_chain))
	       goto error;

	     if	(data && length) {
	       /* Add in the specified data */
	       if (!coap_add_data_large_request(session, pdu, length, data, NULL, NULL))
		 goto error;
	     }

	     if	(coap_send(session, pdu) == COAP_INVALID_MID)
	       goto error;
	     coap_delete_optlist(optlist_chain);
	     return 1;

	   error:

	     if	(pdu)
	       coap_delete_pdu(pdu);
	     coap_delete_optlist(optlist_chain);
	     return 0;

	   }

	   int
	   main(int argc, char *argv[])	{
	     coap_context_t *context = NULL;
	     coap_session_t *session = NULL;
	     unsigned char *data = NULL;
	     size_t data_length	= 0;

	     (void)argc;
	     (void)argv;

	     /*	Initialize libcoap library */
	     coap_startup();

	     /*	... Set	up context, session etc. ... */

	     /*	Set up using libcoap to	do the block work */
	     coap_context_set_block_mode(context,
					 COAP_BLOCK_USE_LIBCOAP	| COAP_BLOCK_SINGLE_BODY);

	     /*	... Other code etc. ...	*/

	     /*	.. build data and define data_length ... */

	     build_send_pdu(context, session, COAP_MESSAGE_CON,	COAP_REQUEST_PUT,
			    "/example/uri", NULL, data,	data_length, 0);

	     /*	... Other code etc. ...	*/

	     coap_cleanup();
	     return 0;
	   }

       Resource	Request	Handler	Response PDU Update

	   #include <coap3/coap.h>

	   #include <stdio.h>

	   static void
	   hnd_get_time(coap_resource_t	*resource, coap_session_t *session,
			const coap_pdu_t *request, const coap_string_t *query,
			coap_pdu_t *response) {
	     unsigned char buf[40];
	     size_t len;
	     time_t now;

	     /*	... Additional analysis	code for resource, request pdu etc.  ... */

	     /*	After analysis,	generate a failure response and	return if needed */

	     now = time(NULL);

	     if	(query != NULL && coap_string_equal(query, coap_make_str_const("secs"))) {
	       /* Output secs since Jan	1 1970 */
	       len = snprintf((char *)buf, sizeof(buf),	"%lu", now);
	     } else {
	       /* Output human-readable	time */
	       struct tm *tmp;
	       tmp = gmtime(&now);
	       if (!tmp) {
		 /* If 'now' is	not valid */
		 coap_pdu_set_code(response, COAP_RESPONSE_CODE_NOT_FOUND);
		 return;
	       }
	       len = strftime((char *)buf, sizeof(buf),	"%b %d %H:%M:%S", tmp);
	     }
	     coap_pdu_set_code(response, COAP_RESPONSE_CODE_CONTENT);
	     /*
	      *	Invoke coap_add_data_large_response() to do all	the hard work.
	      *	[A good	practice, even though ins this case, the amount	of data	is small]
	      *
	      *	Define the format - COAP_MEDIATYPE_TEXT_PLAIN -	to add in
	      *	Define how long	this response is valid for (secs) - 1 -	to add in.
	      *
	      *	Observe	Option added internally	if needed within the function
	      *	Block2 Option added internally if output too large
	      *	Size2 Option added internally
	      *	ETag Option added internally
	      */
	     coap_add_data_large_response(resource, session, request, response,
					  query, COAP_MEDIATYPE_TEXT_PLAIN, 1, 0,
					  len,
					  buf,
					  NULL,	NULL);
	     /*
	      *	When request handler returns, the response pdu will get	automatically
	      *	sent, unless the pdu code is not updated and this is a NON or TCP based
	      *	request.
	      */
	   }

	   int
	   main(int argc, char *argv[])	{
	     coap_context_t *context = NULL;
	     coap_resource_t *r;
	     coap_resource_t *time_resource;
	     int not_exit = 1;

	     /*	Initialize libcoap library */
	     coap_startup();

	     (void)argc;
	     (void)argv;

	     /*	... Set	up context etc.	... */

	     /*	Set up using libcoap to	do the block work */
	     coap_context_set_block_mode(context,
					 COAP_BLOCK_USE_LIBCOAP	| COAP_BLOCK_SINGLE_BODY);

	     /*	Create a resource to return time */
	     r = coap_resource_init(coap_make_str_const("time"),
				    COAP_RESOURCE_FLAGS_NOTIFY_CON);
	     coap_resource_set_get_observable(r, 1);
	     coap_register_request_handler(r, COAP_REQUEST_GET,	hnd_get_time);

	     /*	Document resource for 'time' request */
	     coap_add_attr(r, coap_make_str_const("ct"), coap_make_str_const("0"), 0);
	     coap_add_attr(r, coap_make_str_const("title"),
			   coap_make_str_const("\"Internal Clock\""), 0);
	     coap_add_attr(r, coap_make_str_const("rt"), coap_make_str_const("\"secs\""),
			   0);
	     coap_add_attr(r, coap_make_str_const("if"), coap_make_str_const("\"clock\""),
			   0);

	     coap_add_resource(context,	r);
	     time_resource = r;

	     /*	... Loop waiting for incoming traffic ... */
	     while (!not_exit) {
	       coap_io_process(context,	1000);

	       /* Cause	a notification to anyone Observing 'time' */
	       coap_resource_notify_observers(time_resource, NULL);
	     }

	     /*	Clean up */

	     coap_free_context(context);
	     coap_cleanup();

	   }

SEE ALSO
       coap_init(3) coap_pdu_setup(3), coap_observe(3),	and coap_resource(3)

FURTHER	INFORMATION
       See

       "RFC7252: The Constrained Application Protocol (CoAP)"

       "RFC7959: Block-Wise Transfers in the Constrained Application Protocol
       (CoAP)"

       for further information.

BUGS
       Please raise an issue on	GitHub at
       https://github.com/obgm/libcoap/issues to report	any bugs.

       Please raise a Pull Request at https://github.com/obgm/libcoap/pulls
       for any fixes.

AUTHORS
       The libcoap project <libcoap-developers@lists.sourceforge.net>

coap_block 4.3.5		  11/03/2025			 COAP_BLOCK(3)

Want to link to this manual page? Use this URL:
<https://man.freebsd.org/cgi/man.cgi?query=coap_block&sektion=3&manpath=FreeBSD+Ports+15.0>

home | help