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

FreeBSD Manual Pages

  
 
  

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

NAME
     coap_observe,   coap_resource_set_get_observable,	coap_resource_notify_ob-
     servers,  coap_cancel_observe,  coap_session_set_no_observe_cancel  -  Work
     with CoAP observe

SYNOPSIS
     #include <coap3/coap.h>

     void coap_resource_set_get_observable(coap_resource_t *resource, int mode);

     int    coap_resource_notify_observers(coap_resource_t    *resource,   const
     coap_string_t *query);

     int  coap_cancel_observe(coap_session_t  *session,  coap_binary_t	 *token,
     coap_pdu_type_t message_type);

     void coap_session_set_no_observe_cancel(coap_session_t *session);

     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
     RFC7641 extends the CoAP protocol to be able to monitor the state of a  re-
     source over time.

     This  enables clients to "observe" resources with a defined query, i.e., to
     retrieve a representation of a resource and keep  this  representation  up-
     dated by the server over a period of time.

     The  server has to flag a resource as "observable", and then the client has
     to request in a GET request that it wants to observe this resource  by  the
     use  of  the COAP_OPTION_OBSERVE Option with a value of COAP_OBSERVE_ESTAB-
     LISH. Optionally, the client can specify query options for the resource, or
     by using a FETCH request instead of a GET to define a query (RFC8132).

     To remove the "observe" subscription, the client has to  issue  a	GET  (or
     FETCH) request with the COAP_OPTION_OBSERVE Option with a value of COAP_OB-
     SERVE_CANCEL  using  the  same  token and other options used for making the
     initial "observe" request. Alternatively, "observe" can be cancelled  using
     coap_cancel_observe() instead.

     The  underlying  library adds in and removes "subscribers" to "observe" the
     resource as appropriate in the server side logic.

     NOTE: COAP_RESOURCE_MAX_SUBSCRIBER may have been defined to limit the  num-
     ber of subscribers to a resource when libcoap was built.

     Within the server application, it needs to determine that there is a change
     of state of the resource under observation, and then cause the CoAP library
     layer  to	initiate a "fake GET/FETCH request" so that an observe GET/FETCH
     response gets sent back to all the clients that are observing the resource.
     The appropriate GET/FETCH handler within the server application  is  called
     to fill in the response packet with the appropriate information. This "fake
     GET/FETCH	request"  is  triggered  by  a	call to coap_resource_notify_ob-
     servers().

     The call to coap_io_process() in the main server application i/o loop  will
     do  all the necessary processing of sending any outstanding "fake GET/FETCH
     requests".

     Whenever the server sends a copy of the state of the "observed" resource to
     the client, it will use the same token used by the client when  the  client
     requested the "observe" (or the last token used for a FETCH that spans mul-
     tiple blocks). The client will receive this observe response in the handler
     defined by coap_register_response_handler(3) (with the token updated to the
     initial  token used by the client application for a large FETCH). It is the
     responsibility of the client application to match the  supplied  token  and
     update the appropriate internal information.

FUNCTIONS
     Function: coap_resource_set_get_observable()

     The coap_resource_set_get_observable() function enables or disables the ob-
     servable  status of the resource by the setting of mode. If mode is 1, then
     the resource is observable. If mode is 0, then the resource  is  no  longer
     observable.

     NOTE:  It	is  not  possible  for the Unknown Resource, created by coap_re-
     source_unknown_init(3), to be observable as the Uri-Path is not known  when
     libcoap  creates  a "fake GET/FETCH request". The Unknown Resource PUT han-
     dler must create a new resource and mark the resource as "observable" if  a
     specific  resource needs to be observable. The application must then manage
     the deletion of the resource at the appropriate time.

     NOTE: The type (confirmable or non-confirmable) of  the  triggered  observe
     GET  response is determined not by the initial GET/FETCH request, but inde-
     pendently by the server as per "RFC7641 3.5. Transmission".  This	is  con-
     trolled  by  the  flags  (one  of	COAP_RESOURCE_FLAGS_NOTIFY_NON, COAP_RE-
     SOURCE_FLAGS_NOTIFY_NON_ALWAYS or COAP_RESOURCE_FLAGS_NOTIFY_CON) used when
     creating the resource using coap_resource_init(3).

     NOTE: Furthermore, the server must send at least one "observe" response  as
     confirmable,  when  generally  sending  non-confirmable,  at least every 24
     hours as per "RFC7641 4.5.  Transmission".  Libcoap  automatically  handles
     this  by  sending	every fifth (COAP_OBS_MAX_NON) response as a confirmable
     response for detection that  the  client  is  still  responding  unless  if
     COAP_RESOURCE_FLAGS_NOTIFY_NON_ALWAYS  is	set,  which  is  a "RFC7641 4.5.
     Transmission" violation, where non-confirmable "observe" responses are  al-
     ways sent as required by some higher layer protocols.

     Function: coap_resource_notify_observers()

     The  coap_resource_notify_observers()  function needs to be called whenever
     the server application determines that there has been a change to the state
     of resource. The query parameter is obsolete and ignored.

     Function: coap_cancel_observe()

     The coap_cancel_observe() function can be used by the client to  cancel  an
     observe  request that is being tracked. This will cause the appropriate PDU
     to be sent to the server to cancel the observation, based	on  the  session
     and  token  used  to set up the observe and the PDU is of type message_type
     (use COAP_MESSAGE_NON or COAP_MESSAGE_CON).

     Function: coap_session_set_no_observe_cancel()

     The coap_session_set_no_observe_cancel() function	can  be  called  by  the
     client  to  disable calling coap_cancel_observe() when the session is being
     closed down / freed off. coap_cancel_observe() can still be called directly
     by the client application.

RETURN VALUES
     coap_resource_notify_observers() returns 0 if  not  observable  or  no  ob-
     servers, 1 on success.

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

EXAMPLES
     Simple Time Server

	 #include <coap3/coap.h>

	 #include <stdio.h>

	 coap_resource_t *time_resource = NULL;

	 /* specific GET "time" handler, called from hnd_get_generic() */

	 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;
	   (void)resource;
	   (void)session;

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

	   /* After analysis, generate a suitable response */

	   /* Note that token, if set, is already in the response pdu */

	   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.
	    *
	    * Define the format - COAP_MEDIATYPE_TEXT_PLAIN - to add in
	    * Define how long this response is valid for (secs) - 1 - to add in.
	    * ETAG Option added internally with unique value as param set to 0
	    *
	    * OBSERVE Option added internally if needed within the function
	    * BLOCK2 Option added internally if output too large
	    * SIZE2 Option added internally
	    */
	   coap_add_data_large_response(resource, session, request, response,
					query, COAP_MEDIATYPE_TEXT_PLAIN, 1, 0,
					len,
					buf, NULL, NULL);
	 }

	 /* Generic GET handler */

	 static void
	 hnd_get_generic(coap_resource_t *resource, coap_session_t *session,
			 const coap_pdu_t *request, const coap_string_t *query,
			 coap_pdu_t *response) {
	   coap_str_const_t *uri_path = coap_resource_get_uri_path(resource);

	   if (!uri_path) {
	     /* Unexpected Failure */
	     coap_pdu_set_code(response, COAP_RESPONSE_CODE_BAD_REQUEST);
	     return;
	   }

	   /* Is this the "time" resource" ? */
	   if (coap_string_equal(uri_path, coap_make_str_const("time"))) {
	     hnd_get_time(resource, session, request, query, response);
	     return;
	   }

	   /* Other resources code */

	   /* Failure response */
	   coap_pdu_set_code(response, COAP_RESPONSE_CODE_BAD_REQUEST);
	 }

	 /* Initialize generic GET handler */

	 static void
	 init_resources(coap_context_t *ctx) {
	   coap_resource_t *r;

	   /* Create a resource to return return or update time */
	   r = coap_resource_init(coap_make_str_const("time"),
				  COAP_RESOURCE_FLAGS_NOTIFY_CON);

	   /* We are using a generic GET handler here */
	   coap_register_request_handler(r, COAP_REQUEST_GET, hnd_get_generic);

	   coap_resource_set_get_observable(r, 1);

	   coap_add_resource(ctx, r);
	   time_resource = r;

	 }

	 int
	 main(int argc, char *argv[]) {

	   coap_context_t *ctx = NULL;
	   coap_endpoint_t *ep = NULL;
	   coap_address_t addr;
	   unsigned wait_ms;
	   struct timeval tv_last = {0, 0};

	   /* Initialize libcoap library */
	   coap_startup();

	   /* Remove (void) definition if variable is used */
	   (void)argc;
	   (void)argv;

	   memset(&tv_last, 0, sizeof(tv_last));

	   /* Create the libcoap context */
	   ctx = coap_new_context(NULL);
	   if (!ctx) {
	     exit(1);
	   }
	   /* See coap_block(3) */
	   coap_context_set_block_mode(ctx,
				       COAP_BLOCK_USE_LIBCOAP | COAP_BLOCK_SINGLE_BODY);

	   coap_address_init(&addr);
	   addr.addr.sa.sa_family = AF_INET;
	   addr.addr.sin.sin_port = ntohs(COAP_DEFAULT_PORT);
	   ep = coap_new_endpoint(ctx, &addr, COAP_PROTO_UDP);

	   /* Other Set up Code */

	   init_resources(ctx);

	   wait_ms = COAP_RESOURCE_CHECK_TIME * 1000;

	   while (1) {
	     int result = coap_io_process(ctx, wait_ms);
	     if (result < 0) {
	       break;
	     } else if (result && (unsigned)result < wait_ms) {
	       /* decrement if there is a result wait time returned */
	       wait_ms -= result;
	     } else {
	       /*
		* result == 0, or result >= wait_ms
		* (wait_ms could have decremented to a small value, below
		* the granularity of the timer in coap_io_process() and hence
		* result == 0)
		*/
	       wait_ms = COAP_RESOURCE_CHECK_TIME * 1000;
	     }
	     if (time_resource) {
	       struct timeval tv_now;
	       if (gettimeofday(&tv_now, NULL) == 0) {
		 if (tv_last.tv_sec != tv_now.tv_sec) {
		   /* Happens once per second */
		   tv_last = tv_now;
		   coap_resource_notify_observers(time_resource, NULL);
		 }
		 /* need to wait until next second starts if wait_ms is too large */
		 unsigned next_sec_ms = 1000 - (tv_now.tv_usec / 1000);

		 if (next_sec_ms && next_sec_ms < wait_ms)
		   wait_ms = next_sec_ms;
	       }
	     }
	   }
	   coap_free_context(ctx);
	   coap_cleanup();
	   exit(0);

	 }

     Client Observe Request Setup

	 #include <coap3/coap.h>

	 /* Usually, requests are sent confirmable */

	 static unsigned char msgtype = COAP_MESSAGE_CON;

	 static unsigned int token = 0;

	 static coap_pdu_t *
	 coap_new_request(coap_context_t *context, coap_session_t *session,
			  char request_code, coap_optlist_t **options,
			  unsigned char *data, size_t length, int observe) {
	   coap_pdu_t *pdu;
	   /* 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 NULL;

	   /*
	    * Create uniqueness token for this request for handling unsolicited /
	    * delayed responses
	    */
	   token++;
	   if (!coap_add_token(pdu, sizeof(token), (unsigned char *)&token)) {
	     coap_log_debug("cannot add token to request\n");
	     goto error;
	   }

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

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

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

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

	   return pdu;

	 error:

	   coap_delete_pdu(pdu);
	   return NULL;

	 }

SEE ALSO
     coap_block(3),	 coap_context(3),     coap_handler(3),	   coap_init(3),
     coap_pdu_setup(3), coap_resource(3) and coap_session(3)

FURTHER INFORMATION
     See

     "RFC7252: The Constrained Application Protocol (CoAP)"

     "RFC7641: Observing  Resources  in  the  Constrained  Application	Protocol
     (CoAP)"

     "RFC8132:	PATCH and FETCH Methods for 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_observe 4.3.5		   08/02/2026			 COAP_OBSERVE(3)

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

home | help