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
59       https://tools.ietf.org/html/rfc7252#section-5.6 updated by
60       https://tools.ietf.org/html/rfc7641#section-2 and
61       https://tools.ietf.org/html/rfc8132#section-2 .
62
63       The Cache Key is a SHA256 digest if libcoap was built with TLS support,
64       otherwise it uses the coap_hash() function, using the information
65       abstracted from the PDU and (optionally) the CoAP session.
66
67       This Cache Key can then be used to match against incoming PDUs and then
68       appropriate action logic can take place.
69
70       There is support for excluding specific CoAP options from the Cache
71       Key. Examples could be to exclude CoAP BLOCK1 and BLOCK2 Options for
72       the client or server for ease of tracking a large PUT or GET response,
73       but to not exclude these CoAP options in a proxy where it makes sense
74       to cache the individual blocks.
75
76       The second is providing Cache Entries (which can be looked up by PDU
77       and hence by Cache Key) which hold additional information to make
78       information tracking simpler. These Cache Entries are automatically
79       deleted when a session closes or a context is deleted. These Cache
80       Entries are maintained on a hashed list for speed of lookup.
81
82       The following enums are defined.
83
84           typedef enum coap_cache_session_based_t {
85             COAP_CACHE_NOT_SESSION_BASED,
86             COAP_CACHE_IS_SESSION_BASED
87           } coap_cache_session_based_t;
88
89           typedef enum coap_cache_record_pdu_t {
90             COAP_CACHE_NOT_RECORD_PDU,
91             COAP_CACHE_RECORD_PDU
92           } coap_cache_record_pdu_t;
93
94       The coap_cache_derive_key() function abstracts all the non NoCacheKey
95       CoAP options, ignores the CoAP Observer option and includes a FETCH
96       body from pdu. If session_based is COAP_CACHE_IS_SESSION_BASED, then
97       session pointer is also included. CoAP options can be specifically
98       ignored by the use of coap_cache_ignore_options(). A digest is then
99       built from all of the information and returned. NULL is returned on
100       error.
101
102       The coap_cache_derive_key_w_ignore() function abstracts all the non
103       NoCacheKey CoAP options, ignores the CoAP Observer option and includes
104       a FETCH body from pdu. Further options to ignore are specified by the
105       ignore_count of ignore_options. If session_based is
106       COAP_CACHE_IS_SESSION_BASED, then session pointer is also included. A
107       digest is then built from all of the information and returned. NULL is
108       returned on error.
109
110       The coap_delete_cache_key() function deletes the cache_key that was
111       returned from a coap_cache_derive_key() call.
112
113       The coap_cache_ignore_options() function is used to store in context a
114       list of count options held in options. The specified options will not
115       be included in the data used for the coap_cache_derive_key() function.
116
117       The coap_new_cache_entry() function will create a new Cache Entry based
118       on the Cache Key derived from the pdu, session_based and session. If
119       record_pdu is COAP_CACHE_RECORD_PDU, then a copy of the pdu is stored
120       in the Cache Entry for subsequent retrieval. The Cache Entry can also
121       store application specific data (coap_cache_set_app_data() and
122       coap_cache_get_app_data()). idle_timeout in seconds defines the length
123       of time not being used before it gets deleted. If idle_timeout is set
124       to 0, then the Cache Entry will not get idle expired. The created Cache
125       Entry is returned, or NULL on error.
126
127       The coap_delete_cache_entry() function can be used to delete the Cache
128       Entry cache_entry held within context. This will remove the Cache Entry
129       from the hash lookup list and free off any internally held data. If the
130       Cache Entry is session based, then it will automatically get deleted
131       when the session is freed off or when the idle timeout expires.
132
133       The coap_cache_get_by_key() function will locate the Cache Entry held
134       in the context environment that has Cache Key cache_key. Returns NULL
135       if the Cache Key was not found.
136
137       The coap_cache_get_by_pdu() function will locate the Cache Entry held
138       in the session environment that has a Cache Key derived from the pdu
139       and whether session_based or not. This function calls
140       coap_cache_derive_key() internally, and so normally
141       coap_cache_ignore_options() would have previously been called with
142       COAP_OPTION_BLOCK1 or COAP_OPTION_BLOCK2 to ignore the values held
143       within these options.
144
145       The coap_cache_get_pdu() function returns the PDU that was stored with
146       the Cache Entry when it was created with coap_new_cache_entry() and
147       record_pdu was set to COAP_CACHE_RECORD_PDU. If a PDU was not initially
148       stored, NULL is returned. NOTE: A copy of the returned PDU must be
149       taken for using in sending a CoAP packet using coap_pdu_duplicate().
150
151       The coap_cache_set_app_data() function is used to associate data with
152       the cache_entry. If callback is not NULL, it points to a function to
153       free off data when the cache_entry is deleted. If any data has been
154       previously stored in the cache_entry, the pointer to the old data will
155       get overwritten, but the old data will not get freed off.
156
157       The callback handler function prototype is defined as:
158
159           typedef void (*coap_cache_app_data_free_callback_t)(void *data);
160
161       where data is passed into the callback function whenever the Cache
162       Entry is deleted.
163
164       The coap_cache_get_app_data() function is used to get the previously
165       stored data in the cache_entry.
166

RETURN VALUES

168       coap_cache_derive_key() and coap_cache_derive_key_w_ignore() functions
169       returns a newly created Cache Key or NULL if there is a creation
170       failure.
171
172       coap_cache_ignore_options() function returns 1 if success, 0 on
173       failure.
174
175       coap_new_cache_entry(), coap_cache_get_by_key() and
176       coap_cache_get_by_pdu() functions return the Cache Entry or NULL if
177       there is a failure.
178
179       coap_cache_get_pdu() function the PDU that is held within the Cache
180       Entry or NULL if there is no PDU available.
181

EXAMPLES

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

SEE ALSO

344       coap_block(3), coap_pdu_setup(3), coap_resource(3) and coap_string(3)
345

FURTHER INFORMATION

347       See
348
349       "RFC7252: The Constrained Application Protocol (CoAP)"
350
351       "RFC7959: Block-Wise Transfers in the Constrained Application Protocol
352       (CoAP)"
353
354       for further information.
355

BUGS

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

AUTHORS

362       The libcoap project <libcoap-developers@lists.sourceforge.net>
363
364
365
366coap_cache 4.3.1                  01/19/2023                     COAP_CACHE(3)
Impressum