1// -*- mode:doc; -*- 2// vim: set syntax=asciidoc,tw=0: 3 4coap_cache(3) 5============= 6:doctype: manpage 7:man source: coap_cache 8:man version: @PACKAGE_VERSION@ 9:man manual: libcoap Manual 10 11NAME 12---- 13coap_cache, 14coap_cache_derive_key, 15coap_cache_derive_key_w_ignore, 16coap_cache_delete_key, 17coap_cache_ignore_options, 18coap_new_cache_entry, 19coap_delete_cache_entry, 20coap_cache_get_by_key, 21coap_cache_get_by_pdu, 22coap_cache_get_pdu, 23coap_cache_set_app_data, 24coap_cache_get_app_data 25- Work with CoAP cache functions 26 27SYNOPSIS 28-------- 29*#include <coap@LIBCOAP_API_VERSION@/coap.h>* 30 31*coap_cache_key_t *coap_cache_derive_key(const coap_session_t *_session_, 32const coap_pdu_t *_pdu_, coap_cache_session_based_t _session_based_);* 33 34*coap_cache_key_t *coap_cache_derive_key_w_ignore( 35const coap_session_t *_session_, const coap_pdu_t *_pdu_, 36coap_cache_session_based_t _session_based_, 37const uint16_t *_ignore_options_, size_t _ignore_count_);* 38 39*void coap_delete_cache_key(coap_cache_key_t *_cache_key_);* 40 41*int coap_cache_ignore_options(coap_context_t *_context_, 42const uint16_t *_options_, size_t _count_);* 43 44*coap_cache_entry_t *coap_new_cache_entry(coap_session_t *_session_, 45const coap_pdu_t *_pdu_, coap_cache_record_pdu_t _record_pdu_, 46coap_cache_session_based_t _session_based_, unsigned int _idle_timeout_);* 47 48*void coap_delete_cache_entry(coap_context_t *_context_, 49coap_cache_entry_t *_cache_entry_);* 50 51*coap_cache_entry_t *coap_cache_get_by_key(coap_context_t *_context_, 52const coap_cache_key_t *_cache_key_);* 53 54*coap_cache_entry_t *coap_cache_get_by_pdu(coap_session_t *_session_, 55const coap_pdu_t *_pdu_, coap_cache_session_based_t _session_based_);* 56 57*const coap_pdu_t *coap_cache_get_pdu(const coap_cache_entry_t *_cache_entry_);* 58 59*void coap_cache_set_app_data(coap_cache_entry_t *_cache_entry_, void *_data_, 60coap_cache_app_data_free_callback_t _callback_);* 61 62*void *coap_cache_get_app_data(const coap_cache_entry_t *_cache_entry_);* 63 64For specific (D)TLS library support, link with 65*-lcoap-@LIBCOAP_API_VERSION@-notls*, *-lcoap-@LIBCOAP_API_VERSION@-gnutls*, 66*-lcoap-@LIBCOAP_API_VERSION@-openssl*, *-lcoap-@LIBCOAP_API_VERSION@-mbedtls* 67or *-lcoap-@LIBCOAP_API_VERSION@-tinydtls*. Otherwise, link with 68*-lcoap-@LIBCOAP_API_VERSION@* to get the default (D)TLS library support. 69 70DESCRIPTION 71----------- 72 73The CoAP Cache provides support for two opaque objects that can be used for 74tracking requests and responses. 75 76The first is the ability to derive a Cache Key from the cacheable parts of a 77CoAP PDU as defined in 78https://tools.ietf.org/html/rfc7252#section-5.6 updated by 79https://tools.ietf.org/html/rfc7641#section-2 and 80https://tools.ietf.org/html/rfc8132#section-2 . 81 82The Cache Key is a SHA256 digest if libcoap was built with TLS support, 83otherwise it uses the coap_hash() function, using the information abstracted 84from the PDU and (optionally) the CoAP session. 85 86This Cache Key can then be used to match against incoming PDUs and then 87appropriate action logic can take place. 88 89There is support for excluding specific CoAP options from the Cache Key. 90Examples could be to exclude CoAP BLOCK1 and BLOCK2 Options for the client or 91server for ease of tracking a large PUT or GET response, but to not exclude 92these CoAP options in a proxy where it makes sense to cache the individual 93blocks. 94 95The second is providing Cache Entries (which can be looked up by PDU and hence 96by Cache Key) which hold additional information to make information tracking 97simpler. These Cache Entries are automatically deleted when a session closes 98or a context is deleted. These Cache Entries are maintained on a hashed list 99for speed of lookup. 100 101The following enums are defined. 102 103[source, c] 104---- 105typedef enum coap_cache_session_based_t { 106 COAP_CACHE_NOT_SESSION_BASED, 107 COAP_CACHE_IS_SESSION_BASED 108} coap_cache_session_based_t; 109 110typedef enum coap_cache_record_pdu_t { 111 COAP_CACHE_NOT_RECORD_PDU, 112 COAP_CACHE_RECORD_PDU 113} coap_cache_record_pdu_t; 114---- 115 116The *coap_cache_derive_key*() function abstracts all the non NoCacheKey CoAP 117options, ignores the CoAP Observer option and includes a FETCH body from _pdu_. 118If _session_based_ is COAP_CACHE_IS_SESSION_BASED, then _session_ pointer is 119also included. CoAP options can be specifically ignored by the use of 120*coap_cache_ignore_options*(). A digest is then built from all of the 121information and returned. NULL is returned on error. 122 123The *coap_cache_derive_key_w_ignore*() function abstracts all the non 124NoCacheKey CoAP options, ignores the CoAP Observer option and includes a FETCH 125body from _pdu_. Further options to ignore are specified by the _ignore_count_ 126of _ignore_options_. If _session_based_ is COAP_CACHE_IS_SESSION_BASED, then 127_session_ pointer is also included. A digest is then built from all of the 128information and returned. NULL is returned on error. 129 130The *coap_delete_cache_key*() function deletes the _cache_key_ that was 131returned from a *coap_cache_derive_key*() call. 132 133The *coap_cache_ignore_options*() function is used to store in _context_ a 134list of _count_ options held in _options_. The specified _options_ will not 135be included in the data used for the *coap_cache_derive_key*() function. 136 137The *coap_new_cache_entry*() function will create a new Cache Entry based on 138the Cache Key derived from the _pdu_, _session_based_ and _session_. If 139_record_pdu_ is COAP_CACHE_RECORD_PDU, then a copy of the _pdu_ is stored in 140the Cache Entry for subsequent retrieval. The Cache Entry can also store 141application specific data (*coap_cache_set_app_data*() and 142*coap_cache_get_app_data*()). _idle_timeout_ in seconds defines the length of 143time not being used before it gets deleted. If _idle_timeout_ is set to 1440, then the Cache Entry will not get idle expired. The created Cache 145Entry is returned, or NULL on error. 146 147The *coap_delete_cache_entry*() function can be used to delete the Cache Entry 148_cache_entry_. This will remove the Cache Entry from the hash lookup list and 149free off any internally held data. If the Cache Entry is session based, then 150it will automatically get deleted when the session is freed off or when the 151idle timeout expires. 152 153The *coap_cache_get_by_key*() function will locate the Cache Entry held in the 154_context_ environment that has Cache Key _cache_key_. Returns NULL if the 155Cache Key was not found. 156 157The *coap_cache_get_by_pdu*() function will locate the Cache Entry held in the 158_context_ environment that has a Cache Key derived from the _pdu_ and 159whether _session_based_ or not. 160 161The *coap_cache_get_pdu*() function returns the PDU that was stored with the 162Cache Entry when it was created with *coap_new_cache_entry*() and _record_pdu_ 163was set. If a PDU was not initially stored, NULL is returned. + 164*NOTE:* A copy of the returned PDU must be taken for using in sending a CoAP 165packet. 166 167The *coap_cache_set_app_data*() function is used to associate _data_ with the 168_cache_entry_. If _callback_ is not NULL, it points to a function to free off 169_data_ when the _cache_entry_ is deleted. If any data has been previously 170stored in the _cache_entry_, the pointer to the old data will get overwritten, 171but the old data will not get freed off. 172 173The _callback_ handler function prototype is defined as: 174[source, c] 175---- 176typedef void (*coap_cache_app_data_free_callback_t)(void *data); 177---- 178where _data_ is passed into the callback function whenever the Cache Entry is 179deleted. 180 181The *coap_cache_get_app_data*() function is used to get the previously stored 182_data_ in the _cache_entry_. 183 184RETURN VALUES 185------------- 186*coap_cache_derive_key*() and *coap_cache_derive_key_w_ignore*() functions 187returns a newly created Cache Key or NULL if there is a creation failure. 188 189*coap_cache_ignore_options*() function returns 1 if success, 0 on failure. 190 191*coap_new_cache_entry*(), *coap_cache_get_by_key*() and 192*coap_cache_get_by_pdu*() functions return the Cache Entry or NULL if there 193is a failure. 194 195*coap_cache_get_pdu*() function the PDU that is held within the Cache Entry or 196NULL if there is no PDU available. 197 198EXAMPLES 199-------- 200*PUT Handler supporting BLOCK1* 201 202[source, c] 203---- 204#include <coap@LIBCOAP_API_VERSION@/coap.h> 205 206static coap_binary_t *example_data_ptr = NULL; 207static int example_data_media_type = COAP_MEDIATYPE_TEXT_PLAIN; 208 209static void 210cache_free_app_data(void *data) { 211 coap_binary_t *bdata = (coap_binary_t*)data; 212 coap_delete_binary(bdata); 213} 214 215/* 216 * Large Data PUT handler 217 */ 218 219static void 220hnd_put_example_data(coap_context_t *ctx, 221 coap_resource_t *resource, 222 coap_session_t *session, 223 coap_pdu_t *request, 224 coap_binary_t *token, 225 coap_string_t *query, 226 coap_pdu_t *response 227) { 228 size_t size; 229 const uint8_t *data; 230 coap_opt_iterator_t opt_iter; 231 coap_opt_t *option; 232 size_t offset; 233 size_t total; 234 coap_binary_t *data_so_far; 235 236 /* Remove (void) definition if variable is used */ 237 (void)ctx; 238 (void)token; 239 (void)query; 240 241 if (coap_get_data_large(request, &size, &data, &offset, &total) && 242 size != total) { 243 /* 244 * A part of the data has been received (COAP_BLOCK_SINGLE_BODY not set). 245 * However, total unfortunately is only an indication, so it is not safe to 246 * allocate a block based on total. As per 247 * https://tools.ietf.org/html/rfc7959#section-4 248 * o In a request carrying a Block1 Option, to indicate the current 249 * estimate the client has of the total size of the resource 250 * representation, measured in bytes ("size indication"). 251 */ 252 coap_cache_entry_t *cache_entry = coap_cache_get_by_pdu(session, 253 request, 254 COAP_CACHE_IS_SESSION_BASED); 255 256 if (offset == 0) { 257 if (!cache_entry) { 258 /* 259 * Set idle_timeout parameter to COAP_MAX_TRANSMIT_WAIT if you want 260 * early removal on transmission failure. 0 means only delete when 261 * the session is deleted as session_based is set here. 262 */ 263 cache_entry = coap_new_cache_entry(session, request, 264 COAP_CACHE_NOT_RECORD_PDU, 265 COAP_CACHE_IS_SESSION_BASED, 0); 266 } 267 else { 268 data_so_far = coap_cache_get_app_data(cache_entry); 269 if (data_so_far) { 270 coap_delete_binary(data_so_far); 271 data_so_far = NULL; 272 } 273 coap_cache_set_app_data(cache_entry, NULL, NULL); 274 } 275 } 276 if (!cache_entry) { 277 if (offset == 0) { 278 coap_log(LOG_WARNING, "Unable to create a new cache entry\n"); 279 } 280 else { 281 coap_log(LOG_WARNING, 282 "No cache entry available for the non-first BLOCK\n"); 283 } 284 coap_pdu_set_code(response, COAP_RESPONSE_CODE_INTERNAL_ERROR); 285 return; 286 } 287 288 if (size) { 289 /* Add in the new data to cache entry */ 290 data_so_far = coap_cache_get_app_data(cache_entry); 291 data_so_far = coap_block_build_body(data_so_far, size, data, 292 offset, total); 293 /* Yes, data_so_far can be NULL if error */ 294 coap_cache_set_app_data(cache_entry, data_so_far, cache_free_app_data); 295 } 296 if (offset + size == total) { 297 /* All the data is now in */ 298 data_so_far = coap_cache_get_app_data(cache_entry); 299 coap_cache_set_app_data(cache_entry, NULL, NULL); 300 } 301 else { 302 /* Give us the next block response */ 303 coap_pdu_set_code(response, COAP_RESPONSE_CODE_CONTINUE); 304 return; 305 } 306 } 307 else { 308 /* single body of data received */ 309 data_so_far = coap_new_binary(size); 310 if (data_so_far) { 311 memcpy(data_so_far->s, data, size); 312 } 313 } 314 315 if (example_data_ptr) { 316 /* pre-existed response */ 317 coap_pdu_set_code(response, COAP_RESPONSE_CODE_CHANGED); 318 coap_delete_binary(example_data_ptr); 319 } 320 else 321 /* just generated response */ 322 coap_pdu_set_code(response, COAP_RESPONSE_CODE_CREATED); 323 324 example_data_ptr = data_so_far; 325 if ((option = coap_check_option(request, COAP_OPTION_CONTENT_FORMAT, 326 &opt_iter)) != NULL) { 327 example_data_media_type = 328 coap_decode_var_bytes (coap_opt_value (option), 329 coap_opt_length (option)); 330 } 331 else { 332 example_data_media_type = COAP_MEDIATYPE_TEXT_PLAIN; 333 } 334 335 coap_pdu_set_code(response, COAP_RESPONSE_CODE_CHANGED); 336 coap_resource_notify_observers(resource, NULL); 337} 338 339int main(int argc, char* argv[]){ 340 coap_context_t *ctx = NULL; /* Set up as normal */ 341 /* ... */ 342 uint16_t cache_ignore_options[] = { COAP_OPTION_BLOCK1, 343 COAP_OPTION_BLOCK2 }; 344 345 /* Remove (void) definition if variable is used */ 346 (void)argc; 347 (void)argv; 348 349 /* ... */ 350 351 /** Define the options to ignore when setting up cache-keys */ 352 coap_cache_ignore_options(ctx, cache_ignore_options, 353 sizeof(cache_ignore_options)/sizeof(cache_ignore_options[0])); 354 355 /* ... */ 356 357} 358---- 359 360SEE ALSO 361-------- 362*coap_block*(3), *coap_pdu_setup*(3), *coap_resource*(3) and *coap_string*(3) 363 364FURTHER INFORMATION 365------------------- 366See 367 368"RFC7252: The Constrained Application Protocol (CoAP)" 369 370"RFC7959: Block-Wise Transfers in the Constrained Application Protocol (CoAP)" 371 372for further information. 373 374BUGS 375---- 376Please report bugs on the mailing list for libcoap: 377libcoap-developers@lists.sourceforge.net or raise an issue on GitHub at 378https://github.com/obgm/libcoap/issues 379 380AUTHORS 381------- 382The libcoap project <libcoap-developers@lists.sourceforge.net> 383