libcoap-sys 0.2.2+libcoap-4.3.1

Raw bindings to the libcoap CoAP library.
Documentation
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
369
370
371
372
373
374
375
376
377
378
379
380
381
382
383
384
385
386
387
388
389
390
391
392
393
394
395
396
397
398
399
400
401
402
403
404
405
// -*- mode:doc; -*-
// vim: set syntax=asciidoc,tw=0:

coap_observe(3)
=================
:doctype: manpage
:man source:   coap_observe
:man version:  @PACKAGE_VERSION@
:man manual:   libcoap Manual

NAME
----
coap_observe,
coap_resource_set_get_observable,
coap_resource_notify_observers,
coap_cancel_observe,
coap_session_set_no_observe_cancel
- work with CoAP observe

SYNOPSIS
--------
*#include <coap@LIBCOAP_API_VERSION@/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-@LIBCOAP_API_VERSION@-notls*, *-lcoap-@LIBCOAP_API_VERSION@-gnutls*,
*-lcoap-@LIBCOAP_API_VERSION@-openssl*, *-lcoap-@LIBCOAP_API_VERSION@-mbedtls*
or *-lcoap-@LIBCOAP_API_VERSION@-tinydtls*.   Otherwise, link with
*-lcoap-@LIBCOAP_API_VERSION@* to get the default (D)TLS library support.

DESCRIPTION
-----------
RFC 7641 extends the CoAP protocol to be able to monitor the state of a
resource 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 updated
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_ESTABLISH.
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_OBSERVE_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.

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_observers*().

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".  The client will receive this observe response
in the handler defined by *coap_register_response_handler*(3).  It is the
responsibility of the client application to match the supplied token and
update the appropriate internal information.

The *coap_resource_set_get_observable*() function enables or disables the
observable 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_resource_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
handler 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
independently by the server as per
https://tools.ietf.org/html/rfc7641#section-3.5.  This is controlled by the
flags (one of COAP_RESOURCE_FLAGS_NOTIFY_NON,
COAP_RESOURCE_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 https://tools.ietf.org/html/rfc7641#section-4.5.
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 violation, where non-confirmable "observe" responses are always sent
as required by some higher layer protocols.

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.

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).

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
-------------
The *coap_resource_set_get_observable*() function return 0 on failure, 1 on
success.

The *coap_cancel_observe*() function return 0 on failure, 1 on success.

EXAMPLES
--------
*Simple Time Server*

[source, c]
----
#include <coap@LIBCOAP_API_VERSION@/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};
  /* 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;
      }
    }
  }
  exit(0);

}
----

*Client Observe Request Setup*

[source, c]
----
#include <coap@LIBCOAP_API_VERSION@/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(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_pdu_setup*(3), *coap_resource*(3) and *coap_session*(3)

FURTHER INFORMATION
-------------------
"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)"

BUGS
----
Please report bugs on the mailing list for libcoap:
libcoap-developers@lists.sourceforge.net or raise an issue on GitHub at
https://github.com/obgm/libcoap/issues

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