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_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
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
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
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
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
336 coap_block(3), coap_pdu_setup(3), coap_resource(3) and coap_string(3)
337
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
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
354 The libcoap project <libcoap-developers@lists.sourceforge.net>
355
356
357
358coap_cache 4.3.0 01/20/2022 COAP_CACHE(3)