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_cache_delete_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       Work with CoAP cache functions
10

SYNOPSIS

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

DESCRIPTION

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

RETURN VALUES

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

EXAMPLES

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

SEE ALSO

336       coap_block(3), coap_pdu_setup(3), coap_resource(3) and coap_string(3)
337

FURTHER INFORMATION

339       See
340
341       "RFC7252: The Constrained Application Protocol (CoAP)"
342
343       "RFC7959: Block-Wise Transfers in the Constrained Application Protocol
344       (CoAP)"
345
346       for further information.
347

BUGS

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

AUTHORS

354       The libcoap project <libcoap-developers@lists.sourceforge.net>
355
356
357
358coap_cache 4.3.0                  01/20/2022                     COAP_CACHE(3)
Impressum