1COAP_CACHE(3)                   libcoap Manual                   COAP_CACHE(3)
2
3
4

NAME

6       coap_cache, coap_cache_derive_key, coap_cache_derive_key_w_ignore,
7       coap_delete_cache_key, coap_cache_ignore_options, coap_new_cache_entry,
8       coap_delete_cache_entry, coap_cache_get_by_key, coap_cache_get_by_pdu,
9       coap_cache_get_pdu, coap_cache_set_app_data, coap_cache_get_app_data -
10       Work with CoAP cache functions
11

SYNOPSIS

13       #include <coap3/coap.h>
14
15       coap_cache_key_t *coap_cache_derive_key(const coap_session_t *session,
16       const coap_pdu_t *pdu, coap_cache_session_based_t session_based);
17
18       coap_cache_key_t *coap_cache_derive_key_w_ignore( const coap_session_t
19       *session, const coap_pdu_t *pdu, coap_cache_session_based_t
20       session_based, const uint16_t *ignore_options, size_t ignore_count);
21
22       void coap_delete_cache_key(coap_cache_key_t *cache_key);
23
24       int coap_cache_ignore_options(coap_context_t *context, const uint16_t
25       *options, size_t count);
26
27       coap_cache_entry_t *coap_new_cache_entry(coap_session_t *session, const
28       coap_pdu_t *pdu, coap_cache_record_pdu_t record_pdu,
29       coap_cache_session_based_t session_based, unsigned int idle_timeout);
30
31       void coap_delete_cache_entry(coap_context_t *context,
32       coap_cache_entry_t *cache_entry);
33
34       coap_cache_entry_t *coap_cache_get_by_key(coap_context_t *context,
35       const coap_cache_key_t *cache_key);
36
37       coap_cache_entry_t *coap_cache_get_by_pdu(coap_session_t *session,
38       const coap_pdu_t *pdu, coap_cache_session_based_t session_based);
39
40       const coap_pdu_t *coap_cache_get_pdu(const coap_cache_entry_t
41       *cache_entry);
42
43       void coap_cache_set_app_data(coap_cache_entry_t *cache_entry, void
44       *data, coap_cache_app_data_free_callback_t callback);
45
46       void *coap_cache_get_app_data(const coap_cache_entry_t *cache_entry);
47
48       For specific (D)TLS library support, link with -lcoap-3-notls,
49       -lcoap-3-gnutls, -lcoap-3-openssl, -lcoap-3-mbedtls or
50       -lcoap-3-tinydtls. Otherwise, link with -lcoap-3 to get the default
51       (D)TLS library support.
52

DESCRIPTION

54       The CoAP Cache provides support for two opaque objects that can be used
55       for tracking requests and responses.
56
57       The first is the ability to derive a Cache Key from the cacheable parts
58       of a CoAP PDU as defined in "RFC7252 5.6. Caching" updated by "RFC7641
59       2. The Observe Option" and "RFC8132 2. Fetch Method".
60
61       The Cache Key is a SHA256 digest if libcoap was built with TLS support,
62       otherwise it uses the internal coap_hash() function, using the
63       information abstracted from the PDU and (optionally) the CoAP session.
64
65       This Cache Key can then be used to match against incoming PDUs and then
66       appropriate action logic can take place.
67
68       There is support for excluding specific CoAP options from the Cache
69       Key. Examples could be to exclude CoAP BLOCK1 and BLOCK2 Options for
70       the client or server for ease of tracking a large PUT or GET response,
71       but to not exclude these CoAP options in a proxy where it makes sense
72       to cache the individual blocks.
73
74       The second is providing Cache Entries (which can be looked up by PDU
75       and hence by Cache Key) which hold additional information to make
76       information tracking simpler. These Cache Entries are automatically
77       deleted when a session closes or a context is deleted. These Cache
78       Entries are maintained on a hashed list for speed of lookup.
79
80       The following enums are defined.
81
82           typedef enum coap_cache_session_based_t {
83             COAP_CACHE_NOT_SESSION_BASED,
84             COAP_CACHE_IS_SESSION_BASED
85           } coap_cache_session_based_t;
86
87           typedef enum coap_cache_record_pdu_t {
88             COAP_CACHE_NOT_RECORD_PDU,
89             COAP_CACHE_RECORD_PDU
90           } coap_cache_record_pdu_t;
91

FUNCTIONS

93       Function: coap_cache_derive_key()
94
95       The coap_cache_derive_key() function abstracts all the non NoCacheKey
96       CoAP options, ignores the CoAP Observe option and includes a FETCH body
97       from pdu. If session_based is COAP_CACHE_IS_SESSION_BASED, then session
98       pointer is also included. CoAP options can be specifically ignored by
99       the use of coap_cache_ignore_options(). A digest is then built from all
100       of the information and returned. NULL is returned on error.
101
102       Function: coap_cache_derive_key_w_ignore()
103
104       The coap_cache_derive_key_w_ignore() function abstracts all the non
105       NoCacheKey CoAP options, ignores the CoAP Observe option and includes a
106       FETCH body from pdu. Further options to ignore are specified by the
107       ignore_count of ignore_options. If session_based is
108       COAP_CACHE_IS_SESSION_BASED, then session pointer is also included. A
109       digest is then built from all of the information and returned. NULL is
110       returned on error.
111
112       Function: coap_delete_cache_key()
113
114       The coap_delete_cache_key() function deletes the cache_key that was
115       returned from a coap_cache_derive_key() or
116       coap_cache_derive_key_w_ignore() call.
117
118       Function: coap_cache_ignore_options()
119
120       The coap_cache_ignore_options() function is used to store in context a
121       list of count options held in options. The specified options will not
122       be included in the data used for the coap_cache_derive_key() function.
123
124       Function: coap_new_cache_entry()
125
126       The coap_new_cache_entry() function will create a new Cache Entry based
127       on the Cache Key derived from the pdu, session_based and session. If
128       record_pdu is COAP_CACHE_RECORD_PDU, then a copy of the pdu is stored
129       in the Cache Entry for subsequent retrieval. The Cache Entry can also
130       store application specific data (coap_cache_set_app_data() and
131       coap_cache_get_app_data()). idle_timeout in seconds defines the length
132       of time not being used before it gets deleted. If idle_timeout is set
133       to 0, then the Cache Entry will not get idle expired. The created Cache
134       Entry is returned, or NULL on error.
135
136       Function: coap_delete_cache_entry()
137
138       The coap_delete_cache_entry() function can be used to delete the Cache
139       Entry cache_entry held within context. This will remove the Cache Entry
140       from the hash lookup list and free off any internally held data. If the
141       Cache Entry is session based, then it will automatically get deleted
142       when the session is freed off or when the idle timeout expires.
143
144       Function: coap_cache_get_by_key()
145
146       The coap_cache_get_by_key() function will locate the Cache Entry held
147       in the context environment that has Cache Key cache_key. Returns NULL
148       if the Cache Key was not found.
149
150       Function: coap_cache_get_by_pdu()
151
152       The coap_cache_get_by_pdu() function will locate the Cache Entry held
153       in the session environment that has a Cache Key derived from the pdu
154       and whether session_based or not. This function calls
155       coap_cache_derive_key() internally, and so normally
156       coap_cache_ignore_options() would have previously been called with
157       COAP_OPTION_BLOCK1 or COAP_OPTION_BLOCK2 to ignore the values held
158       within these options.
159
160       Function: coap_cache_get_pdu()
161
162       The coap_cache_get_pdu() function returns the PDU that was stored with
163       the Cache Entry when it was created with coap_new_cache_entry() and
164       record_pdu was set to COAP_CACHE_RECORD_PDU. If a PDU was not initially
165       stored, NULL is returned. NOTE: A copy of the returned PDU must be
166       taken for use in sending a CoAP packet using coap_pdu_duplicate().
167
168       Function: coap_cache_set_app_data()
169
170       The coap_cache_set_app_data() function is used to associate data with
171       the cache_entry. If callback is not NULL, it points to a function to
172       free off data when the cache_entry is deleted. If any data has been
173       previously stored in the cache_entry, the pointer to the old data will
174       get overwritten, but the old data will not get freed off.
175
176       The callback handler function prototype is defined as:
177
178           typedef void (*coap_cache_app_data_free_callback_t)(void *data);
179
180       where data is passed into the callback function whenever the Cache
181       Entry is deleted.
182
183       Function: coap_cache_get_app_data()
184
185       The coap_cache_get_app_data() function is used to get the previously
186       stored data in the cache_entry.
187

RETURN VALUES

189       coap_cache_derive_key() and coap_cache_derive_key_w_ignore() returns a
190       newly created Cache Key or NULL if there is a creation failure.
191
192       coap_cache_ignore_options() returns 1 if success, 0 on failure.
193
194       coap_new_cache_entry(), coap_cache_get_by_key() and
195       coap_cache_get_by_pdu() return the Cache Entry or NULL if there is a
196       failure.
197
198       coap_cache_get_pdu() returns the PDU that is held within the Cache
199       Entry or NULL if there is no PDU available.
200
201       coap_cache_get_app_data() returns the application data value previously
202       set by the coap_cache_set_app_data() function or NULL.
203

EXAMPLES

205       PUT Handler supporting BLOCK1
206
207           #include <coap3/coap.h>
208
209           static coap_binary_t *example_data_ptr = NULL;
210           static int example_data_media_type = COAP_MEDIATYPE_TEXT_PLAIN;
211
212           static void
213           cache_free_app_data(void *data) {
214             coap_binary_t *bdata = (coap_binary_t*)data;
215             coap_delete_binary(bdata);
216           }
217
218           /*
219            * Large Data PUT handler
220            */
221
222           static void
223           hnd_put_example_data(coap_context_t *ctx,
224                   coap_resource_t *resource,
225                   coap_session_t *session,
226                   coap_pdu_t *request,
227                   coap_binary_t *token,
228                   coap_string_t *query,
229                   coap_pdu_t *response
230           ) {
231             size_t size;
232             const uint8_t *data;
233             coap_opt_iterator_t opt_iter;
234             coap_opt_t *option;
235             size_t offset;
236             size_t total;
237             coap_binary_t *data_so_far;
238
239             /* Remove (void) definition if variable is used */
240             (void)ctx;
241             (void)token;
242             (void)query;
243
244             if (coap_get_data_large(request, &size, &data, &offset, &total) &&
245               size != total) {
246               /*
247                * A part of the data has been received (COAP_BLOCK_SINGLE_BODY not set).
248                * However, total unfortunately is only an indication, so it is not safe to
249                * allocate a block based on total.  As per
250                * https://rfc-editor.org/rfc/rfc7959#section-4
251                *   o  In a request carrying a Block1 Option, to indicate the current
252                *         estimate the client has of the total size of the resource
253                *         representation, measured in bytes ("size indication").
254                *
255                * coap_cache_ignore_options() must have previously been called with at
256                * least COAP_OPTION_BLOCK1 set as the option value will change per block.
257                */
258               coap_cache_entry_t *cache_entry = coap_cache_get_by_pdu(session,
259                                                                       request,
260                                                         COAP_CACHE_IS_SESSION_BASED);
261
262               if (offset == 0) {
263                 if (!cache_entry) {
264                   /*
265                    * Set idle_timeout parameter to COAP_MAX_TRANSMIT_WAIT if you want
266                    * early removal on transmission failure. 0 means only delete when
267                    * the session is deleted as session_based is set here.
268                    */
269                   cache_entry = coap_new_cache_entry(session, request,
270                                                    COAP_CACHE_NOT_RECORD_PDU,
271                                                    COAP_CACHE_IS_SESSION_BASED, 0);
272                 }
273                 else {
274                   data_so_far = coap_cache_get_app_data(cache_entry);
275                   if (data_so_far) {
276                     coap_delete_binary(data_so_far);
277                     data_so_far = NULL;
278                   }
279                   coap_cache_set_app_data(cache_entry, NULL, NULL);
280                 }
281               }
282               if (!cache_entry) {
283                 if (offset == 0) {
284                   coap_log_warn("Unable to create a new cache entry\n");
285                 }
286                 else {
287                   coap_log_warn(
288                            "No cache entry available for the non-first BLOCK\n");
289                 }
290                 coap_pdu_set_code(response, COAP_RESPONSE_CODE_INTERNAL_ERROR);
291                 return;
292               }
293
294               if (size) {
295                 /* Add in the new data to cache entry */
296                 data_so_far = coap_cache_get_app_data(cache_entry);
297                 data_so_far = coap_block_build_body(data_so_far, size, data,
298                                                     offset, total);
299                 /* Yes, data_so_far can be NULL if error */
300                 coap_cache_set_app_data(cache_entry, data_so_far, cache_free_app_data);
301               }
302               if (offset + size == total) {
303                 /* All the data is now in */
304                 data_so_far = coap_cache_get_app_data(cache_entry);
305                 coap_cache_set_app_data(cache_entry, NULL, NULL);
306               }
307               else {
308                 /* Give us the next block response */
309                 coap_pdu_set_code(response, COAP_RESPONSE_CODE_CONTINUE);
310                 return;
311               }
312             }
313             else {
314               /* single body of data received */
315               data_so_far = coap_new_binary(size);
316               if (data_so_far) {
317                 memcpy(data_so_far->s, data, size);
318               }
319             }
320
321             if (example_data_ptr) {
322               /* pre-existed response */
323               coap_pdu_set_code(response, COAP_RESPONSE_CODE_CHANGED);
324               coap_delete_binary(example_data_ptr);
325             }
326             else
327               /* just generated response */
328               coap_pdu_set_code(response, COAP_RESPONSE_CODE_CREATED);
329
330             example_data_ptr = data_so_far;
331             if ((option = coap_check_option(request, COAP_OPTION_CONTENT_FORMAT,
332                                             &opt_iter)) != NULL) {
333               example_data_media_type =
334                       coap_decode_var_bytes (coap_opt_value (option),
335                                              coap_opt_length (option));
336             }
337             else {
338               example_data_media_type = COAP_MEDIATYPE_TEXT_PLAIN;
339             }
340
341             coap_pdu_set_code(response, COAP_RESPONSE_CODE_CHANGED);
342             coap_resource_notify_observers(resource, NULL);
343           }
344
345           int
346           main(int argc, char* argv[]) {
347             coap_context_t *ctx = NULL;  /* Set up as normal */
348             /* ... */
349             uint16_t cache_ignore_options[] = { COAP_OPTION_BLOCK1,
350                                                 COAP_OPTION_BLOCK2 };
351
352             /* Initialize libcoap library */
353             coap_startup();
354
355             /* Remove (void) definition if variable is used */
356             (void)argc;
357             (void)argv;
358
359             /* ... */
360
361             /** Define the options to ignore when setting up cache-keys */
362             coap_cache_ignore_options(ctx, cache_ignore_options,
363                        sizeof(cache_ignore_options)/sizeof(cache_ignore_options[0]));
364
365             /* ... */
366             coap_cleanup();
367
368           }
369

SEE ALSO

371       coap_block(3), coap_init(3), coap_pdu_setup(3), coap_resource(3) and
372       coap_string(3)
373

FURTHER INFORMATION

375       See
376
377       "RFC7252: The Constrained Application Protocol (CoAP)"
378
379       "RFC7959: Block-Wise Transfers in the Constrained Application Protocol
380       (CoAP)"
381
382       for further information.
383

BUGS

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

AUTHORS

390       The libcoap project <libcoap-developers@lists.sourceforge.net>
391
392
393
394coap_cache 4.3.4                  10/09/2023                     COAP_CACHE(3)
Impressum