1c87c5fbaSopenharmony_ci// -*- mode:doc; -*-
2c87c5fbaSopenharmony_ci// vim: set syntax=asciidoc tw=0
3c87c5fbaSopenharmony_ci
4c87c5fbaSopenharmony_cicoap_observe(3)
5c87c5fbaSopenharmony_ci===============
6c87c5fbaSopenharmony_ci:doctype: manpage
7c87c5fbaSopenharmony_ci:man source:   coap_observe
8c87c5fbaSopenharmony_ci:man version:  @PACKAGE_VERSION@
9c87c5fbaSopenharmony_ci:man manual:   libcoap Manual
10c87c5fbaSopenharmony_ci
11c87c5fbaSopenharmony_ciNAME
12c87c5fbaSopenharmony_ci----
13c87c5fbaSopenharmony_cicoap_observe,
14c87c5fbaSopenharmony_cicoap_resource_set_get_observable,
15c87c5fbaSopenharmony_cicoap_resource_notify_observers,
16c87c5fbaSopenharmony_cicoap_cancel_observe,
17c87c5fbaSopenharmony_cicoap_session_set_no_observe_cancel
18c87c5fbaSopenharmony_ci- Work with CoAP observe
19c87c5fbaSopenharmony_ci
20c87c5fbaSopenharmony_ciSYNOPSIS
21c87c5fbaSopenharmony_ci--------
22c87c5fbaSopenharmony_ci*#include <coap@LIBCOAP_API_VERSION@/coap.h>*
23c87c5fbaSopenharmony_ci
24c87c5fbaSopenharmony_ci*void coap_resource_set_get_observable(coap_resource_t *_resource_,
25c87c5fbaSopenharmony_ciint _mode_);*
26c87c5fbaSopenharmony_ci
27c87c5fbaSopenharmony_ci*int coap_resource_notify_observers(coap_resource_t *_resource_,
28c87c5fbaSopenharmony_ciconst coap_string_t *_query_);*
29c87c5fbaSopenharmony_ci
30c87c5fbaSopenharmony_ci*int coap_cancel_observe(coap_session_t *_session_, coap_binary_t *_token_,
31c87c5fbaSopenharmony_cicoap_pdu_type_t _message_type_);*
32c87c5fbaSopenharmony_ci
33c87c5fbaSopenharmony_ci*void coap_session_set_no_observe_cancel(coap_session_t *_session_);*
34c87c5fbaSopenharmony_ci
35c87c5fbaSopenharmony_ciFor specific (D)TLS library support, link with
36c87c5fbaSopenharmony_ci*-lcoap-@LIBCOAP_API_VERSION@-notls*, *-lcoap-@LIBCOAP_API_VERSION@-gnutls*,
37c87c5fbaSopenharmony_ci*-lcoap-@LIBCOAP_API_VERSION@-openssl*, *-lcoap-@LIBCOAP_API_VERSION@-mbedtls*
38c87c5fbaSopenharmony_cior *-lcoap-@LIBCOAP_API_VERSION@-tinydtls*.   Otherwise, link with
39c87c5fbaSopenharmony_ci*-lcoap-@LIBCOAP_API_VERSION@* to get the default (D)TLS library support.
40c87c5fbaSopenharmony_ci
41c87c5fbaSopenharmony_ciDESCRIPTION
42c87c5fbaSopenharmony_ci-----------
43c87c5fbaSopenharmony_cihttps://rfc-editor.org/rfc/rfc7641[RFC7641] extends the CoAP protocol to be
44c87c5fbaSopenharmony_ciable to monitor the state of a resource over time.
45c87c5fbaSopenharmony_ci
46c87c5fbaSopenharmony_ciThis enables clients to "observe" resources with a defined query, i.e., to
47c87c5fbaSopenharmony_ciretrieve a representation of a resource and keep this representation updated
48c87c5fbaSopenharmony_ciby the server over a period of time.
49c87c5fbaSopenharmony_ci
50c87c5fbaSopenharmony_ciThe server has to flag a resource as "observable", and then the client has
51c87c5fbaSopenharmony_cito request in a GET request that it wants to observe this resource by the use
52c87c5fbaSopenharmony_ciof the COAP_OPTION_OBSERVE Option with a value of COAP_OBSERVE_ESTABLISH.
53c87c5fbaSopenharmony_ciOptionally, the client can specify query options for the resource, or by using
54c87c5fbaSopenharmony_cia FETCH request instead of a GET to define a query
55c87c5fbaSopenharmony_ci(https://rfc-editor.org/rfc/rfc8132[RFC8132]).
56c87c5fbaSopenharmony_ci
57c87c5fbaSopenharmony_ciTo remove the "observe" subscription, the client has to issue a GET (or FETCH)
58c87c5fbaSopenharmony_cirequest with the COAP_OPTION_OBSERVE Option with a value of
59c87c5fbaSopenharmony_ciCOAP_OBSERVE_CANCEL using the same token and other options used for making the
60c87c5fbaSopenharmony_ciinitial "observe" request. Alternatively, "observe" can be cancelled using
61c87c5fbaSopenharmony_ci*coap_cancel_observe*() instead.
62c87c5fbaSopenharmony_ci
63c87c5fbaSopenharmony_ciThe underlying library adds in and removes "subscribers" to "observe" the
64c87c5fbaSopenharmony_ciresource as appropriate in the server side logic.
65c87c5fbaSopenharmony_ci
66c87c5fbaSopenharmony_ci*NOTE:* COAP_RESOURCE_MAX_SUBSCRIBER may have been defined to limit the number
67c87c5fbaSopenharmony_ciof subscribers to a resource when libcoap was built.
68c87c5fbaSopenharmony_ci
69c87c5fbaSopenharmony_ciWithin the server application, it needs to determine that there is a change of
70c87c5fbaSopenharmony_cistate of the resource under observation, and then cause the CoAP library
71c87c5fbaSopenharmony_cilayer to initiate a "fake GET/FETCH request" so that an observe GET/FETCH
72c87c5fbaSopenharmony_ciresponse gets sent back to all the clients that are observing the resource.  The
73c87c5fbaSopenharmony_ciappropriate GET/FETCH handler within the server application is called to fill
74c87c5fbaSopenharmony_ciin the response packet with the appropriate information. This "fake GET/FETCH
75c87c5fbaSopenharmony_cirequest" is triggered by a call to *coap_resource_notify_observers*().
76c87c5fbaSopenharmony_ci
77c87c5fbaSopenharmony_ciThe call to *coap_io_process*() in the main server application i/o loop will do
78c87c5fbaSopenharmony_ciall the necessary processing of sending any outstanding "fake GET/FETCH
79c87c5fbaSopenharmony_cirequests".
80c87c5fbaSopenharmony_ci
81c87c5fbaSopenharmony_ciWhenever the server sends a copy of the state of the "observed" resource to
82c87c5fbaSopenharmony_cithe client, it will use the same token used by the client when the client
83c87c5fbaSopenharmony_cirequested the "observe" (or the last token used for a FETCH that spans
84c87c5fbaSopenharmony_cimultiple blocks).  The client will receive this observe response
85c87c5fbaSopenharmony_ciin the handler defined by *coap_register_response_handler*(3) (with the token
86c87c5fbaSopenharmony_ciupdated to the initial token used by the client application for a large FETCH).
87c87c5fbaSopenharmony_ciIt is the responsibility of the client application to match the supplied token
88c87c5fbaSopenharmony_ciand update the appropriate internal information.
89c87c5fbaSopenharmony_ci
90c87c5fbaSopenharmony_ciFUNCTIONS
91c87c5fbaSopenharmony_ci---------
92c87c5fbaSopenharmony_ci
93c87c5fbaSopenharmony_ci*Function: coap_resource_set_get_observable()*
94c87c5fbaSopenharmony_ci
95c87c5fbaSopenharmony_ciThe *coap_resource_set_get_observable*() function enables or disables the
96c87c5fbaSopenharmony_ciobservable status of the _resource_ by the setting of _mode_.  If _mode_ is
97c87c5fbaSopenharmony_ci1, then the _resource_ is observable.  If _mode_ is 0, then the
98c87c5fbaSopenharmony_ci_resource_ is no longer observable.
99c87c5fbaSopenharmony_ci
100c87c5fbaSopenharmony_ci*NOTE:* It is not possible for the Unknown Resource, created by
101c87c5fbaSopenharmony_ci*coap_resource_unknown_init*(3), to be observable as the Uri-Path is not known
102c87c5fbaSopenharmony_ciwhen libcoap creates a "fake GET/FETCH request".  The Unknown Resource PUT
103c87c5fbaSopenharmony_cihandler must create a new resource and mark the resource as "observable" if
104c87c5fbaSopenharmony_cia specific resource needs to be observable.  The application must then
105c87c5fbaSopenharmony_cimanage the deletion of the resource at the appropriate time.
106c87c5fbaSopenharmony_ci
107c87c5fbaSopenharmony_ci*NOTE:* The type (confirmable or non-confirmable) of the triggered observe
108c87c5fbaSopenharmony_ciGET response is determined not by the initial GET/FETCH request, but
109c87c5fbaSopenharmony_ciindependently by the server as per
110c87c5fbaSopenharmony_ci"https://rfc-editor.org/rfc/rfc7641#section-3.5[RFC7641 3.5. Transmission]".
111c87c5fbaSopenharmony_ciThis is controlled by the flags (one of COAP_RESOURCE_FLAGS_NOTIFY_NON,
112c87c5fbaSopenharmony_ciCOAP_RESOURCE_FLAGS_NOTIFY_NON_ALWAYS or COAP_RESOURCE_FLAGS_NOTIFY_CON)
113c87c5fbaSopenharmony_ciused when creating the resource using *coap_resource_init*(3).
114c87c5fbaSopenharmony_ci
115c87c5fbaSopenharmony_ci*NOTE:* Furthermore, the server must send at least one "observe" response as
116c87c5fbaSopenharmony_ciconfirmable, when generally sending non-confirmable, at least every 24 hours
117c87c5fbaSopenharmony_cias per "https://rfc-editor.org/rfc/rfc7641#section-4.5[RFC7641
118c87c5fbaSopenharmony_ci4.5. Transmission]".
119c87c5fbaSopenharmony_ciLibcoap automatically handles this by sending every fifth (COAP_OBS_MAX_NON)
120c87c5fbaSopenharmony_ciresponse as a confirmable response for detection that the client is still
121c87c5fbaSopenharmony_ciresponding unless if COAP_RESOURCE_FLAGS_NOTIFY_NON_ALWAYS is set, which is a
122c87c5fbaSopenharmony_ci"https://rfc-editor.org/rfc/rfc7641#section-4.5[RFC7641 4.5. Transmission]"
123c87c5fbaSopenharmony_civiolation, where non-confirmable "observe" responses are always sent
124c87c5fbaSopenharmony_cias required by some higher layer protocols.
125c87c5fbaSopenharmony_ci
126c87c5fbaSopenharmony_ci*Function: coap_resource_notify_observers()*
127c87c5fbaSopenharmony_ci
128c87c5fbaSopenharmony_ciThe *coap_resource_notify_observers*() function needs to be called whenever the
129c87c5fbaSopenharmony_ciserver application determines that there has been a change to the state of
130c87c5fbaSopenharmony_ci_resource_.  The _query_ parameter is obsolete and ignored.
131c87c5fbaSopenharmony_ci
132c87c5fbaSopenharmony_ci*Function: coap_cancel_observe()*
133c87c5fbaSopenharmony_ci
134c87c5fbaSopenharmony_ciThe *coap_cancel_observe*() function can be used by the client to cancel an
135c87c5fbaSopenharmony_ciobserve request that is being tracked. This will cause the
136c87c5fbaSopenharmony_ciappropriate PDU to be sent to the server to cancel the observation, based on
137c87c5fbaSopenharmony_cithe _session_ and _token_ used to set up the observe and the PDU is of type
138c87c5fbaSopenharmony_ci_message_type_ (use COAP_MESSAGE_NON or COAP_MESSAGE_CON).
139c87c5fbaSopenharmony_ci
140c87c5fbaSopenharmony_ci*Function: coap_session_set_no_observe_cancel()*
141c87c5fbaSopenharmony_ci
142c87c5fbaSopenharmony_ciThe *coap_session_set_no_observe_cancel*() function can be called by the
143c87c5fbaSopenharmony_ciclient to disable calling *coap_cancel_observe*() when the _session_ is being
144c87c5fbaSopenharmony_ciclosed down / freed off. *coap_cancel_observe*() can still be called directly
145c87c5fbaSopenharmony_ciby the client application.
146c87c5fbaSopenharmony_ci
147c87c5fbaSopenharmony_ciRETURN VALUES
148c87c5fbaSopenharmony_ci-------------
149c87c5fbaSopenharmony_ci*coap_resource_notify_observers*() returns 0 if not observable or
150c87c5fbaSopenharmony_cino observers, 1 on success.
151c87c5fbaSopenharmony_ci
152c87c5fbaSopenharmony_ci*coap_cancel_observe*() returns 0 on failure, 1 on success.
153c87c5fbaSopenharmony_ci
154c87c5fbaSopenharmony_ciEXAMPLES
155c87c5fbaSopenharmony_ci--------
156c87c5fbaSopenharmony_ci*Simple Time Server*
157c87c5fbaSopenharmony_ci
158c87c5fbaSopenharmony_ci[source, c]
159c87c5fbaSopenharmony_ci----
160c87c5fbaSopenharmony_ci#include <coap@LIBCOAP_API_VERSION@/coap.h>
161c87c5fbaSopenharmony_ci
162c87c5fbaSopenharmony_ci#include <stdio.h>
163c87c5fbaSopenharmony_ci
164c87c5fbaSopenharmony_cicoap_resource_t *time_resource = NULL;
165c87c5fbaSopenharmony_ci
166c87c5fbaSopenharmony_ci/* specific GET "time" handler, called from hnd_get_generic() */
167c87c5fbaSopenharmony_ci
168c87c5fbaSopenharmony_cistatic void
169c87c5fbaSopenharmony_cihnd_get_time(coap_resource_t *resource, coap_session_t *session,
170c87c5fbaSopenharmony_ciconst coap_pdu_t *request, const coap_string_t *query, coap_pdu_t *response) {
171c87c5fbaSopenharmony_ci
172c87c5fbaSopenharmony_ci  unsigned char buf[40];
173c87c5fbaSopenharmony_ci  size_t len;
174c87c5fbaSopenharmony_ci  time_t now;
175c87c5fbaSopenharmony_ci  (void)resource;
176c87c5fbaSopenharmony_ci  (void)session;
177c87c5fbaSopenharmony_ci
178c87c5fbaSopenharmony_ci  /* ... Additional analysis code for resource, request pdu etc.  ... */
179c87c5fbaSopenharmony_ci
180c87c5fbaSopenharmony_ci  /* After analysis, generate a suitable response */
181c87c5fbaSopenharmony_ci
182c87c5fbaSopenharmony_ci  /* Note that token, if set, is already in the response pdu */
183c87c5fbaSopenharmony_ci
184c87c5fbaSopenharmony_ci  now = time(NULL);
185c87c5fbaSopenharmony_ci
186c87c5fbaSopenharmony_ci  if (query != NULL && coap_string_equal(query, coap_make_str_const("secs"))) {
187c87c5fbaSopenharmony_ci    /* Output secs since Jan 1 1970 */
188c87c5fbaSopenharmony_ci    len = snprintf((char *)buf, sizeof(buf), "%lu", now);
189c87c5fbaSopenharmony_ci  }
190c87c5fbaSopenharmony_ci  else {
191c87c5fbaSopenharmony_ci    /* Output human-readable time */
192c87c5fbaSopenharmony_ci    struct tm *tmp;
193c87c5fbaSopenharmony_ci    tmp = gmtime(&now);
194c87c5fbaSopenharmony_ci    if (!tmp) {
195c87c5fbaSopenharmony_ci      /* If 'now' is not valid */
196c87c5fbaSopenharmony_ci      coap_pdu_set_code(response, COAP_RESPONSE_CODE_NOT_FOUND);
197c87c5fbaSopenharmony_ci      return;
198c87c5fbaSopenharmony_ci    }
199c87c5fbaSopenharmony_ci    len = strftime((char *)buf, sizeof(buf), "%b %d %H:%M:%S", tmp);
200c87c5fbaSopenharmony_ci  }
201c87c5fbaSopenharmony_ci  coap_pdu_set_code(response, COAP_RESPONSE_CODE_CONTENT);
202c87c5fbaSopenharmony_ci  /*
203c87c5fbaSopenharmony_ci   * Invoke coap_add_data_large_response() to do all the hard work.
204c87c5fbaSopenharmony_ci   *
205c87c5fbaSopenharmony_ci   * Define the format - COAP_MEDIATYPE_TEXT_PLAIN - to add in
206c87c5fbaSopenharmony_ci   * Define how long this response is valid for (secs) - 1 - to add in.
207c87c5fbaSopenharmony_ci   * ETAG Option added internally with unique value as param set to 0
208c87c5fbaSopenharmony_ci   *
209c87c5fbaSopenharmony_ci   * OBSERVE Option added internally if needed within the function
210c87c5fbaSopenharmony_ci   * BLOCK2 Option added internally if output too large
211c87c5fbaSopenharmony_ci   * SIZE2 Option added internally
212c87c5fbaSopenharmony_ci   */
213c87c5fbaSopenharmony_ci  coap_add_data_large_response(resource, session, request, response,
214c87c5fbaSopenharmony_ci                               query, COAP_MEDIATYPE_TEXT_PLAIN, 1, 0,
215c87c5fbaSopenharmony_ci                               len,
216c87c5fbaSopenharmony_ci                               buf, NULL, NULL);
217c87c5fbaSopenharmony_ci}
218c87c5fbaSopenharmony_ci
219c87c5fbaSopenharmony_ci/* Generic GET handler */
220c87c5fbaSopenharmony_ci
221c87c5fbaSopenharmony_cistatic void
222c87c5fbaSopenharmony_cihnd_get_generic(coap_resource_t *resource, coap_session_t *session,
223c87c5fbaSopenharmony_ciconst coap_pdu_t *request, const coap_string_t *query, coap_pdu_t *response) {
224c87c5fbaSopenharmony_ci
225c87c5fbaSopenharmony_ci  coap_str_const_t *uri_path = coap_resource_get_uri_path(resource);
226c87c5fbaSopenharmony_ci
227c87c5fbaSopenharmony_ci  if (!uri_path) {
228c87c5fbaSopenharmony_ci    /* Unexpected Failure */
229c87c5fbaSopenharmony_ci    coap_pdu_set_code(response, COAP_RESPONSE_CODE_BAD_REQUEST);
230c87c5fbaSopenharmony_ci    return;
231c87c5fbaSopenharmony_ci  }
232c87c5fbaSopenharmony_ci
233c87c5fbaSopenharmony_ci  /* Is this the "time" resource" ? */
234c87c5fbaSopenharmony_ci  if (coap_string_equal(uri_path, coap_make_str_const("time"))) {
235c87c5fbaSopenharmony_ci    hnd_get_time(resource, session, request, query, response);
236c87c5fbaSopenharmony_ci    return;
237c87c5fbaSopenharmony_ci  }
238c87c5fbaSopenharmony_ci
239c87c5fbaSopenharmony_ci  /* Other resources code */
240c87c5fbaSopenharmony_ci
241c87c5fbaSopenharmony_ci  /* Failure response */
242c87c5fbaSopenharmony_ci  coap_pdu_set_code(response, COAP_RESPONSE_CODE_BAD_REQUEST);
243c87c5fbaSopenharmony_ci}
244c87c5fbaSopenharmony_ci
245c87c5fbaSopenharmony_ci/* Initialize generic GET handler */
246c87c5fbaSopenharmony_ci
247c87c5fbaSopenharmony_cistatic void
248c87c5fbaSopenharmony_ciinit_resources(coap_context_t *ctx)
249c87c5fbaSopenharmony_ci{
250c87c5fbaSopenharmony_ci
251c87c5fbaSopenharmony_ci  coap_resource_t *r;
252c87c5fbaSopenharmony_ci
253c87c5fbaSopenharmony_ci  /* Create a resource to return return or update time */
254c87c5fbaSopenharmony_ci  r = coap_resource_init(coap_make_str_const("time"),
255c87c5fbaSopenharmony_ci                         COAP_RESOURCE_FLAGS_NOTIFY_CON);
256c87c5fbaSopenharmony_ci
257c87c5fbaSopenharmony_ci  /* We are using a generic GET handler here */
258c87c5fbaSopenharmony_ci  coap_register_request_handler(r, COAP_REQUEST_GET, hnd_get_generic);
259c87c5fbaSopenharmony_ci
260c87c5fbaSopenharmony_ci  coap_resource_set_get_observable(r, 1);
261c87c5fbaSopenharmony_ci
262c87c5fbaSopenharmony_ci  coap_add_resource(ctx, r);
263c87c5fbaSopenharmony_ci  time_resource = r;
264c87c5fbaSopenharmony_ci
265c87c5fbaSopenharmony_ci}
266c87c5fbaSopenharmony_ci
267c87c5fbaSopenharmony_ciint
268c87c5fbaSopenharmony_cimain(int argc, char *argv[]) {
269c87c5fbaSopenharmony_ci
270c87c5fbaSopenharmony_ci  coap_context_t *ctx = NULL;
271c87c5fbaSopenharmony_ci  coap_endpoint_t *ep = NULL;
272c87c5fbaSopenharmony_ci  coap_address_t addr;
273c87c5fbaSopenharmony_ci  unsigned wait_ms;
274c87c5fbaSopenharmony_ci  struct timeval tv_last = {0, 0};
275c87c5fbaSopenharmony_ci
276c87c5fbaSopenharmony_ci  /* Initialize libcoap library */
277c87c5fbaSopenharmony_ci  coap_startup();
278c87c5fbaSopenharmony_ci
279c87c5fbaSopenharmony_ci  /* Remove (void) definition if variable is used */
280c87c5fbaSopenharmony_ci  (void)argc;
281c87c5fbaSopenharmony_ci  (void)argv;
282c87c5fbaSopenharmony_ci
283c87c5fbaSopenharmony_ci  memset (&tv_last, 0, sizeof(tv_last));
284c87c5fbaSopenharmony_ci
285c87c5fbaSopenharmony_ci  /* Create the libcoap context */
286c87c5fbaSopenharmony_ci  ctx = coap_new_context(NULL);
287c87c5fbaSopenharmony_ci  if (!ctx) {
288c87c5fbaSopenharmony_ci    exit(1);
289c87c5fbaSopenharmony_ci  }
290c87c5fbaSopenharmony_ci  /* See coap_block(3) */
291c87c5fbaSopenharmony_ci  coap_context_set_block_mode(ctx,
292c87c5fbaSopenharmony_ci                              COAP_BLOCK_USE_LIBCOAP | COAP_BLOCK_SINGLE_BODY);
293c87c5fbaSopenharmony_ci
294c87c5fbaSopenharmony_ci  coap_address_init(&addr);
295c87c5fbaSopenharmony_ci  addr.addr.sa.sa_family = AF_INET;
296c87c5fbaSopenharmony_ci  addr.addr.sin.sin_port = ntohs(COAP_DEFAULT_PORT);
297c87c5fbaSopenharmony_ci  ep = coap_new_endpoint(ctx, &addr, COAP_PROTO_UDP);
298c87c5fbaSopenharmony_ci
299c87c5fbaSopenharmony_ci  /* Other Set up Code */
300c87c5fbaSopenharmony_ci
301c87c5fbaSopenharmony_ci  init_resources(ctx);
302c87c5fbaSopenharmony_ci
303c87c5fbaSopenharmony_ci  wait_ms = COAP_RESOURCE_CHECK_TIME * 1000;
304c87c5fbaSopenharmony_ci
305c87c5fbaSopenharmony_ci  while (1) {
306c87c5fbaSopenharmony_ci    int result = coap_io_process( ctx, wait_ms );
307c87c5fbaSopenharmony_ci    if ( result < 0 ) {
308c87c5fbaSopenharmony_ci      break;
309c87c5fbaSopenharmony_ci    } else if ( result && (unsigned)result < wait_ms ) {
310c87c5fbaSopenharmony_ci      /* decrement if there is a result wait time returned */
311c87c5fbaSopenharmony_ci      wait_ms -= result;
312c87c5fbaSopenharmony_ci    } else {
313c87c5fbaSopenharmony_ci      /*
314c87c5fbaSopenharmony_ci       * result == 0, or result >= wait_ms
315c87c5fbaSopenharmony_ci       * (wait_ms could have decremented to a small value, below
316c87c5fbaSopenharmony_ci       * the granularity of the timer in coap_io_process() and hence
317c87c5fbaSopenharmony_ci       * result == 0)
318c87c5fbaSopenharmony_ci       */
319c87c5fbaSopenharmony_ci      wait_ms = COAP_RESOURCE_CHECK_TIME * 1000;
320c87c5fbaSopenharmony_ci    }
321c87c5fbaSopenharmony_ci    if (time_resource) {
322c87c5fbaSopenharmony_ci      struct timeval tv_now;
323c87c5fbaSopenharmony_ci      if (gettimeofday (&tv_now, NULL) == 0) {
324c87c5fbaSopenharmony_ci        if (tv_last.tv_sec != tv_now.tv_sec) {
325c87c5fbaSopenharmony_ci          /* Happens once per second */
326c87c5fbaSopenharmony_ci          tv_last = tv_now;
327c87c5fbaSopenharmony_ci          coap_resource_notify_observers(time_resource, NULL);
328c87c5fbaSopenharmony_ci        }
329c87c5fbaSopenharmony_ci        /* need to wait until next second starts if wait_ms is too large */
330c87c5fbaSopenharmony_ci        unsigned next_sec_ms = 1000 - (tv_now.tv_usec / 1000);
331c87c5fbaSopenharmony_ci
332c87c5fbaSopenharmony_ci        if (next_sec_ms && next_sec_ms < wait_ms)
333c87c5fbaSopenharmony_ci          wait_ms = next_sec_ms;
334c87c5fbaSopenharmony_ci      }
335c87c5fbaSopenharmony_ci    }
336c87c5fbaSopenharmony_ci  }
337c87c5fbaSopenharmony_ci  coap_free_context(ctx);
338c87c5fbaSopenharmony_ci  coap_cleanup();
339c87c5fbaSopenharmony_ci  exit(0);
340c87c5fbaSopenharmony_ci
341c87c5fbaSopenharmony_ci}
342c87c5fbaSopenharmony_ci----
343c87c5fbaSopenharmony_ci
344c87c5fbaSopenharmony_ci*Client Observe Request Setup*
345c87c5fbaSopenharmony_ci
346c87c5fbaSopenharmony_ci[source, c]
347c87c5fbaSopenharmony_ci----
348c87c5fbaSopenharmony_ci#include <coap@LIBCOAP_API_VERSION@/coap.h>
349c87c5fbaSopenharmony_ci
350c87c5fbaSopenharmony_ci/* Usually, requests are sent confirmable */
351c87c5fbaSopenharmony_ci
352c87c5fbaSopenharmony_cistatic unsigned char msgtype = COAP_MESSAGE_CON;
353c87c5fbaSopenharmony_ci
354c87c5fbaSopenharmony_cistatic unsigned int token = 0;
355c87c5fbaSopenharmony_ci
356c87c5fbaSopenharmony_cistatic coap_pdu_t *
357c87c5fbaSopenharmony_cicoap_new_request(coap_context_t *context, coap_session_t *session, char request_code,
358c87c5fbaSopenharmony_cicoap_optlist_t **options, unsigned char *data, size_t length, int observe) {
359c87c5fbaSopenharmony_ci
360c87c5fbaSopenharmony_ci  coap_pdu_t *pdu;
361c87c5fbaSopenharmony_ci  /* Remove (void) definition if variable is used */
362c87c5fbaSopenharmony_ci  (void)context;
363c87c5fbaSopenharmony_ci
364c87c5fbaSopenharmony_ci  /* Create the pdu with the appropriate options */
365c87c5fbaSopenharmony_ci  pdu = coap_pdu_init(msgtype, request_code, coap_new_message_id(session),
366c87c5fbaSopenharmony_ci                      coap_session_max_pdu_size(session));
367c87c5fbaSopenharmony_ci  if (!pdu)
368c87c5fbaSopenharmony_ci    return NULL;
369c87c5fbaSopenharmony_ci
370c87c5fbaSopenharmony_ci  /*
371c87c5fbaSopenharmony_ci   * Create uniqueness token for this request for handling unsolicited /
372c87c5fbaSopenharmony_ci   * delayed responses
373c87c5fbaSopenharmony_ci   */
374c87c5fbaSopenharmony_ci  token++;
375c87c5fbaSopenharmony_ci  if (!coap_add_token(pdu, sizeof(token), (unsigned char*)&token)) {
376c87c5fbaSopenharmony_ci    coap_log_debug("cannot add token to request\n");
377c87c5fbaSopenharmony_ci    goto error;
378c87c5fbaSopenharmony_ci  }
379c87c5fbaSopenharmony_ci
380c87c5fbaSopenharmony_ci  if (request_code == COAP_REQUEST_GET && observe) {
381c87c5fbaSopenharmony_ci    /* Indicate that we want to observe this resource */
382c87c5fbaSopenharmony_ci    if (!coap_insert_optlist(options,
383c87c5fbaSopenharmony_ci                             coap_new_optlist(COAP_OPTION_OBSERVE,
384c87c5fbaSopenharmony_ci                                         COAP_OBSERVE_ESTABLISH, NULL)))
385c87c5fbaSopenharmony_ci      goto error;
386c87c5fbaSopenharmony_ci  }
387c87c5fbaSopenharmony_ci
388c87c5fbaSopenharmony_ci  /* ... Other code / options etc. ... */
389c87c5fbaSopenharmony_ci
390c87c5fbaSopenharmony_ci  /* Add in all the options (after internal sorting) to the pdu */
391c87c5fbaSopenharmony_ci  if (!coap_add_optlist_pdu(pdu, options))
392c87c5fbaSopenharmony_ci    goto error;
393c87c5fbaSopenharmony_ci
394c87c5fbaSopenharmony_ci  if (data && length) {
395c87c5fbaSopenharmony_ci    /* Add in the specified data */
396c87c5fbaSopenharmony_ci    if (!coap_add_data(pdu, length, data))
397c87c5fbaSopenharmony_ci      goto error;
398c87c5fbaSopenharmony_ci  }
399c87c5fbaSopenharmony_ci
400c87c5fbaSopenharmony_ci  return pdu;
401c87c5fbaSopenharmony_ci
402c87c5fbaSopenharmony_cierror:
403c87c5fbaSopenharmony_ci
404c87c5fbaSopenharmony_ci  coap_delete_pdu(pdu);
405c87c5fbaSopenharmony_ci  return NULL;
406c87c5fbaSopenharmony_ci
407c87c5fbaSopenharmony_ci}
408c87c5fbaSopenharmony_ci----
409c87c5fbaSopenharmony_ci
410c87c5fbaSopenharmony_ciSEE ALSO
411c87c5fbaSopenharmony_ci--------
412c87c5fbaSopenharmony_ci*coap_block*(3), *coap_context*(3), *coap_handler*(3), *coap_init*(3),
413c87c5fbaSopenharmony_ci*coap_pdu_setup*(3), *coap_resource*(3) and *coap_session*(3)
414c87c5fbaSopenharmony_ci
415c87c5fbaSopenharmony_ciFURTHER INFORMATION
416c87c5fbaSopenharmony_ci-------------------
417c87c5fbaSopenharmony_ciSee
418c87c5fbaSopenharmony_ci
419c87c5fbaSopenharmony_ci"https://rfc-editor.org/rfc/rfc7252[RFC7252: The Constrained Application Protocol (CoAP)]"
420c87c5fbaSopenharmony_ci
421c87c5fbaSopenharmony_ci"https://rfc-editor.org/rfc/rfc7641[RFC7641: Observing Resources in the Constrained Application Protocol (CoAP)]"
422c87c5fbaSopenharmony_ci
423c87c5fbaSopenharmony_ci"https://rfc-editor.org/rfc/rfc8132[RFC8132: PATCH and FETCH Methods for the Constrained Application Protocol (CoAP)]"
424c87c5fbaSopenharmony_ci
425c87c5fbaSopenharmony_cifor further information.
426c87c5fbaSopenharmony_ci
427c87c5fbaSopenharmony_ci
428c87c5fbaSopenharmony_ciBUGS
429c87c5fbaSopenharmony_ci----
430c87c5fbaSopenharmony_ciPlease report bugs on the mailing list for libcoap:
431c87c5fbaSopenharmony_cilibcoap-developers@lists.sourceforge.net or raise an issue on GitHub at
432c87c5fbaSopenharmony_cihttps://github.com/obgm/libcoap/issues
433c87c5fbaSopenharmony_ci
434c87c5fbaSopenharmony_ciAUTHORS
435c87c5fbaSopenharmony_ci-------
436c87c5fbaSopenharmony_ciThe libcoap project <libcoap-developers@lists.sourceforge.net>
437