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
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
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
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
344 coap_block(3), coap_pdu_setup(3), coap_resource(3) and coap_string(3)
345
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
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
362 The libcoap project <libcoap-developers@lists.sourceforge.net>
363
364
365
366coap_cache 4.3.1 01/19/2023 COAP_CACHE(3)