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 infor-
     mation 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) un-
	 til 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_RE-
	 SPONSE_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_LIB-
	 COAP|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 individ-
	 ual 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 receiv-
     ing 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 re-
     turned.

     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 ver-
     sion of recovery will be used if possible.

     If COAP_BLOCK_USE_LIBCOAP is set, then any PDUs presented to  the	applica-
     tion  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_SIN-
     GLE_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 sup-
     ports stateless support for FETCH requests - in other words, the FETCH  re-
     quest 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 ap-
     plication 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 cre-
     ated.

     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 poten-
     tially 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_re-
     quest() 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_re-
     sponse(). 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  de-
     fines  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 in-
     stead 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_re-
     quest() is called.

     Function: coap_get_data_large()

     The  coap_get_data_large()  function is used abstract from the pdu informa-
     tion 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-allo-
     cated.

     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  indi-
     vidual  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  lib-
     coap 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		   08/02/2026			   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.1.quarterly>

home | help