1COAP_CACHE(3) libcoap Manual COAP_CACHE(3)
2
3
4
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
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
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
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
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
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
371 coap_block(3), coap_init(3), coap_pdu_setup(3), coap_resource(3) and
372 coap_string(3)
373
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
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
390 The libcoap project <libcoap-developers@lists.sourceforge.net>
391
392
393
394coap_cache 4.3.4 10/09/2023 COAP_CACHE(3)