• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1// -*- mode:doc; -*-
2// vim: set syntax=asciidoc,tw=0:
3
4coap_cache(3)
5=============
6:doctype: manpage
7:man source:   coap_cache
8:man version:  @PACKAGE_VERSION@
9:man manual:   libcoap Manual
10
11NAME
12----
13coap_cache,
14coap_cache_derive_key,
15coap_cache_derive_key_w_ignore,
16coap_cache_delete_key,
17coap_cache_ignore_options,
18coap_new_cache_entry,
19coap_delete_cache_entry,
20coap_cache_get_by_key,
21coap_cache_get_by_pdu,
22coap_cache_get_pdu,
23coap_cache_set_app_data,
24coap_cache_get_app_data
25- Work with CoAP cache functions
26
27SYNOPSIS
28--------
29*#include <coap@LIBCOAP_API_VERSION@/coap.h>*
30
31*coap_cache_key_t *coap_cache_derive_key(const coap_session_t *_session_,
32const coap_pdu_t *_pdu_, coap_cache_session_based_t _session_based_);*
33
34*coap_cache_key_t *coap_cache_derive_key_w_ignore(
35const coap_session_t *_session_, const coap_pdu_t *_pdu_,
36coap_cache_session_based_t _session_based_,
37const uint16_t *_ignore_options_, size_t _ignore_count_);*
38
39*void coap_delete_cache_key(coap_cache_key_t *_cache_key_);*
40
41*int coap_cache_ignore_options(coap_context_t *_context_,
42const uint16_t *_options_, size_t _count_);*
43
44*coap_cache_entry_t *coap_new_cache_entry(coap_session_t *_session_,
45const coap_pdu_t *_pdu_, coap_cache_record_pdu_t _record_pdu_,
46coap_cache_session_based_t _session_based_, unsigned int _idle_timeout_);*
47
48*void coap_delete_cache_entry(coap_context_t *_context_,
49coap_cache_entry_t *_cache_entry_);*
50
51*coap_cache_entry_t *coap_cache_get_by_key(coap_context_t *_context_,
52const coap_cache_key_t *_cache_key_);*
53
54*coap_cache_entry_t *coap_cache_get_by_pdu(coap_session_t *_session_,
55const coap_pdu_t *_pdu_, coap_cache_session_based_t _session_based_);*
56
57*const coap_pdu_t *coap_cache_get_pdu(const coap_cache_entry_t *_cache_entry_);*
58
59*void coap_cache_set_app_data(coap_cache_entry_t *_cache_entry_, void *_data_,
60coap_cache_app_data_free_callback_t _callback_);*
61
62*void *coap_cache_get_app_data(const coap_cache_entry_t *_cache_entry_);*
63
64For specific (D)TLS library support, link with
65*-lcoap-@LIBCOAP_API_VERSION@-notls*, *-lcoap-@LIBCOAP_API_VERSION@-gnutls*,
66*-lcoap-@LIBCOAP_API_VERSION@-openssl*, *-lcoap-@LIBCOAP_API_VERSION@-mbedtls*
67or *-lcoap-@LIBCOAP_API_VERSION@-tinydtls*.   Otherwise, link with
68*-lcoap-@LIBCOAP_API_VERSION@* to get the default (D)TLS library support.
69
70DESCRIPTION
71-----------
72
73The CoAP Cache provides support for two opaque objects that can be used for
74tracking requests and responses.
75
76The first is the ability to derive a Cache Key from the cacheable parts of a
77CoAP PDU as defined in
78https://tools.ietf.org/html/rfc7252#section-5.6 updated by
79https://tools.ietf.org/html/rfc7641#section-2 and
80https://tools.ietf.org/html/rfc8132#section-2 .
81
82The Cache Key is a SHA256 digest if libcoap was built with TLS support,
83otherwise it uses the coap_hash() function, using the information abstracted
84from the PDU and (optionally) the CoAP session.
85
86This Cache Key can then be used to match against incoming PDUs and then
87appropriate action logic can take place.
88
89There is support for excluding specific CoAP options from the Cache Key.
90Examples could be to exclude CoAP BLOCK1 and BLOCK2 Options for the client or
91server for ease of tracking a large PUT or GET response, but to not exclude
92these CoAP options in a proxy where it makes sense to cache the individual
93blocks.
94
95The second is providing Cache Entries (which can be looked up by PDU and hence
96by Cache Key) which hold additional information to make information tracking
97simpler.  These Cache Entries are automatically deleted when a session closes
98or a context is deleted. These Cache Entries are maintained on a hashed list
99for speed of lookup.
100
101The following enums are defined.
102
103[source, c]
104----
105typedef enum coap_cache_session_based_t {
106  COAP_CACHE_NOT_SESSION_BASED,
107  COAP_CACHE_IS_SESSION_BASED
108} coap_cache_session_based_t;
109
110typedef enum coap_cache_record_pdu_t {
111  COAP_CACHE_NOT_RECORD_PDU,
112  COAP_CACHE_RECORD_PDU
113} coap_cache_record_pdu_t;
114----
115
116The *coap_cache_derive_key*() function abstracts all the non NoCacheKey CoAP
117options, ignores the CoAP Observer option and includes a FETCH body from _pdu_.
118If _session_based_ is COAP_CACHE_IS_SESSION_BASED, then _session_ pointer is
119also included. CoAP options can be specifically ignored by the use of
120*coap_cache_ignore_options*().  A digest is then built from all of the
121information and returned. NULL is returned on error.
122
123The *coap_cache_derive_key_w_ignore*() function abstracts all the non
124NoCacheKey CoAP options, ignores the CoAP Observer option and includes a FETCH
125body from _pdu_. Further options to ignore are specified by the _ignore_count_
126of _ignore_options_.  If _session_based_ is COAP_CACHE_IS_SESSION_BASED, then
127_session_ pointer is also included. A digest is then built from all of the
128information and returned. NULL is returned on error.
129
130The *coap_delete_cache_key*() function deletes the _cache_key_ that was
131returned from a *coap_cache_derive_key*() call.
132
133The *coap_cache_ignore_options*() function is used to store in _context_ a
134list of _count_ options held in _options_.  The specified _options_ will not
135be included in the data used for the *coap_cache_derive_key*() function.
136
137The *coap_new_cache_entry*() function will create a new Cache Entry based on
138the Cache Key derived from the _pdu_, _session_based_ and _session_. If
139_record_pdu_ is COAP_CACHE_RECORD_PDU, then a copy of the _pdu_ is stored in
140the Cache Entry for subsequent retrieval. The Cache Entry can also store
141application specific data (*coap_cache_set_app_data*() and
142*coap_cache_get_app_data*()).  _idle_timeout_ in seconds defines the length of
143time not being used before it gets deleted.  If _idle_timeout_ is set to
1440, then the Cache Entry will not get idle expired. The created Cache
145Entry is returned, or NULL on error.
146
147The *coap_delete_cache_entry*() function can be used to delete the Cache Entry
148_cache_entry_.  This will remove the Cache Entry from the hash lookup list and
149free off any internally held data.  If the Cache Entry is session based, then
150it will automatically get deleted when the session is freed off or when the
151idle timeout expires.
152
153The *coap_cache_get_by_key*() function will locate the Cache Entry held in the
154_context_ environment that has Cache Key _cache_key_.  Returns NULL if the
155Cache Key was not found.
156
157The *coap_cache_get_by_pdu*() function will locate the Cache Entry held in the
158_context_ environment that has a Cache Key derived from the _pdu_ and
159whether _session_based_ or not.
160
161The *coap_cache_get_pdu*() function returns the PDU that was stored with the
162Cache Entry when it was created with *coap_new_cache_entry*() and _record_pdu_
163was set.  If a PDU was not initially stored, NULL is returned. +
164*NOTE:* A copy of the returned PDU must be taken for using in sending a CoAP
165packet.
166
167The *coap_cache_set_app_data*() function is used to associate _data_ with the
168_cache_entry_.  If _callback_ is not NULL, it points to a function to free off
169_data_ when the _cache_entry_ is deleted.  If any data has been previously
170stored in the _cache_entry_, the pointer to the old data will get overwritten,
171but the old data will not get freed off.
172
173The _callback_ handler function prototype is defined as:
174[source, c]
175----
176typedef void (*coap_cache_app_data_free_callback_t)(void *data);
177----
178where _data_ is passed into the callback function whenever the Cache Entry is
179deleted.
180
181The *coap_cache_get_app_data*() function is used to get the previously stored
182_data_ in the _cache_entry_.
183
184RETURN VALUES
185-------------
186*coap_cache_derive_key*() and *coap_cache_derive_key_w_ignore*() functions
187returns a newly created Cache Key or NULL if there is a creation failure.
188
189*coap_cache_ignore_options*() function returns 1 if success, 0 on failure.
190
191*coap_new_cache_entry*(), *coap_cache_get_by_key*() and
192*coap_cache_get_by_pdu*() functions return the Cache Entry or NULL if there
193is a failure.
194
195*coap_cache_get_pdu*() function the PDU that is held within the Cache Entry or
196NULL if there is no PDU available.
197
198EXAMPLES
199--------
200*PUT Handler supporting BLOCK1*
201
202[source, c]
203----
204#include <coap@LIBCOAP_API_VERSION@/coap.h>
205
206static coap_binary_t *example_data_ptr = NULL;
207static int example_data_media_type = COAP_MEDIATYPE_TEXT_PLAIN;
208
209static void
210cache_free_app_data(void *data) {
211  coap_binary_t *bdata = (coap_binary_t*)data;
212  coap_delete_binary(bdata);
213}
214
215/*
216 * Large Data PUT handler
217 */
218
219static void
220hnd_put_example_data(coap_context_t *ctx,
221        coap_resource_t *resource,
222        coap_session_t *session,
223        coap_pdu_t *request,
224        coap_binary_t *token,
225        coap_string_t *query,
226        coap_pdu_t *response
227) {
228  size_t size;
229  const uint8_t *data;
230  coap_opt_iterator_t opt_iter;
231  coap_opt_t *option;
232  size_t offset;
233  size_t total;
234  coap_binary_t *data_so_far;
235
236  /* Remove (void) definition if variable is used */
237  (void)ctx;
238  (void)token;
239  (void)query;
240
241  if (coap_get_data_large(request, &size, &data, &offset, &total) &&
242    size != total) {
243    /*
244     * A part of the data has been received (COAP_BLOCK_SINGLE_BODY not set).
245     * However, total unfortunately is only an indication, so it is not safe to
246     * allocate a block based on total.  As per
247     * https://tools.ietf.org/html/rfc7959#section-4
248     *   o  In a request carrying a Block1 Option, to indicate the current
249     *         estimate the client has of the total size of the resource
250     *         representation, measured in bytes ("size indication").
251     */
252    coap_cache_entry_t *cache_entry = coap_cache_get_by_pdu(session,
253                                                            request,
254                                              COAP_CACHE_IS_SESSION_BASED);
255
256    if (offset == 0) {
257      if (!cache_entry) {
258        /*
259         * Set idle_timeout parameter to COAP_MAX_TRANSMIT_WAIT if you want
260         * early removal on transmission failure. 0 means only delete when
261         * the session is deleted as session_based is set here.
262         */
263        cache_entry = coap_new_cache_entry(session, request,
264                                         COAP_CACHE_NOT_RECORD_PDU,
265                                         COAP_CACHE_IS_SESSION_BASED, 0);
266      }
267      else {
268        data_so_far = coap_cache_get_app_data(cache_entry);
269        if (data_so_far) {
270          coap_delete_binary(data_so_far);
271          data_so_far = NULL;
272        }
273        coap_cache_set_app_data(cache_entry, NULL, NULL);
274      }
275    }
276    if (!cache_entry) {
277      if (offset == 0) {
278        coap_log(LOG_WARNING, "Unable to create a new cache entry\n");
279      }
280      else {
281        coap_log(LOG_WARNING,
282                 "No cache entry available for the non-first BLOCK\n");
283      }
284      coap_pdu_set_code(response, COAP_RESPONSE_CODE_INTERNAL_ERROR);
285      return;
286    }
287
288    if (size) {
289      /* Add in the new data to cache entry */
290      data_so_far = coap_cache_get_app_data(cache_entry);
291      data_so_far = coap_block_build_body(data_so_far, size, data,
292                                          offset, total);
293      /* Yes, data_so_far can be NULL if error */
294      coap_cache_set_app_data(cache_entry, data_so_far, cache_free_app_data);
295    }
296    if (offset + size == total) {
297      /* All the data is now in */
298      data_so_far = coap_cache_get_app_data(cache_entry);
299      coap_cache_set_app_data(cache_entry, NULL, NULL);
300    }
301    else {
302      /* Give us the next block response */
303      coap_pdu_set_code(response, COAP_RESPONSE_CODE_CONTINUE);
304      return;
305    }
306  }
307  else {
308    /* single body of data received */
309    data_so_far = coap_new_binary(size);
310    if (data_so_far) {
311      memcpy(data_so_far->s, data, size);
312    }
313  }
314
315  if (example_data_ptr) {
316    /* pre-existed response */
317    coap_pdu_set_code(response, COAP_RESPONSE_CODE_CHANGED);
318    coap_delete_binary(example_data_ptr);
319  }
320  else
321    /* just generated response */
322    coap_pdu_set_code(response, COAP_RESPONSE_CODE_CREATED);
323
324  example_data_ptr = data_so_far;
325  if ((option = coap_check_option(request, COAP_OPTION_CONTENT_FORMAT,
326                                  &opt_iter)) != NULL) {
327    example_data_media_type =
328            coap_decode_var_bytes (coap_opt_value (option),
329                                   coap_opt_length (option));
330  }
331  else {
332    example_data_media_type = COAP_MEDIATYPE_TEXT_PLAIN;
333  }
334
335  coap_pdu_set_code(response, COAP_RESPONSE_CODE_CHANGED);
336  coap_resource_notify_observers(resource, NULL);
337}
338
339int main(int argc, char* argv[]){
340  coap_context_t *ctx = NULL;  /* Set up as normal */
341  /* ... */
342  uint16_t cache_ignore_options[] = { COAP_OPTION_BLOCK1,
343                                      COAP_OPTION_BLOCK2 };
344
345  /* Remove (void) definition if variable is used */
346  (void)argc;
347  (void)argv;
348
349  /* ... */
350
351  /** Define the options to ignore when setting up cache-keys */
352  coap_cache_ignore_options(ctx, cache_ignore_options,
353             sizeof(cache_ignore_options)/sizeof(cache_ignore_options[0]));
354
355  /* ... */
356
357}
358----
359
360SEE ALSO
361--------
362*coap_block*(3), *coap_pdu_setup*(3), *coap_resource*(3) and *coap_string*(3)
363
364FURTHER INFORMATION
365-------------------
366See
367
368"RFC7252: The Constrained Application Protocol (CoAP)"
369
370"RFC7959: Block-Wise Transfers in the Constrained Application Protocol (CoAP)"
371
372for further information.
373
374BUGS
375----
376Please report bugs on the mailing list for libcoap:
377libcoap-developers@lists.sourceforge.net or raise an issue on GitHub at
378https://github.com/obgm/libcoap/issues
379
380AUTHORS
381-------
382The libcoap project <libcoap-developers@lists.sourceforge.net>
383