'\" t .\" Title: coap_cache .\" Author: [see the "AUTHORS" section] .\" Generator: DocBook XSL Stylesheets vsnapshot .\" Date: 10/28/2023 .\" Manual: libcoap Manual .\" Source: coap_cache 4.3.4 .\" Language: English .\" .TH "COAP_CACHE" "3" "10/28/2023" "coap_cache 4\&.3\&.4" "libcoap Manual" .\" ----------------------------------------------------------------- .\" * Define some portability stuff .\" ----------------------------------------------------------------- .\" ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ .\" http://bugs.debian.org/507673 .\" http://lists.gnu.org/archive/html/groff/2009-02/msg00013.html .\" ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ .ie \n(.g .ds Aq \(aq .el .ds Aq ' .\" ----------------------------------------------------------------- .\" * set default formatting .\" ----------------------------------------------------------------- .\" disable hyphenation .nh .\" disable justification (adjust text to left margin only) .ad l .\" ----------------------------------------------------------------- .\" * MAIN CONTENT STARTS HERE * .\" ----------------------------------------------------------------- .SH "NAME" coap_cache, coap_cache_derive_key, coap_cache_derive_key_w_ignore, coap_delete_cache_key, coap_cache_ignore_options, coap_new_cache_entry, coap_delete_cache_entry, coap_cache_get_by_key, coap_cache_get_by_pdu, coap_cache_get_pdu, coap_cache_set_app_data, coap_cache_get_app_data \- Work with CoAP cache functions .SH "SYNOPSIS" .sp \fB#include \fR .sp \fBcoap_cache_key_t *coap_cache_derive_key(const coap_session_t *\fR\fB\fIsession\fR\fR\fB, const coap_pdu_t *\fR\fB\fIpdu\fR\fR\fB, coap_cache_session_based_t \fR\fB\fIsession_based\fR\fR\fB);\fR .sp \fBcoap_cache_key_t *coap_cache_derive_key_w_ignore( const coap_session_t *\fR\fB\fIsession\fR\fR\fB, const coap_pdu_t *\fR\fB\fIpdu\fR\fR\fB, coap_cache_session_based_t \fR\fB\fIsession_based\fR\fR\fB, const uint16_t *\fR\fB\fIignore_options\fR\fR\fB, size_t \fR\fB\fIignore_count\fR\fR\fB);\fR .sp \fBvoid coap_delete_cache_key(coap_cache_key_t *\fR\fB\fIcache_key\fR\fR\fB);\fR .sp \fBint coap_cache_ignore_options(coap_context_t *\fR\fB\fIcontext\fR\fR\fB, const uint16_t *\fR\fB\fIoptions\fR\fR\fB, size_t \fR\fB\fIcount\fR\fR\fB);\fR .sp \fBcoap_cache_entry_t *coap_new_cache_entry(coap_session_t *\fR\fB\fIsession\fR\fR\fB, const coap_pdu_t *\fR\fB\fIpdu\fR\fR\fB, coap_cache_record_pdu_t \fR\fB\fIrecord_pdu\fR\fR\fB, coap_cache_session_based_t \fR\fB\fIsession_based\fR\fR\fB, unsigned int \fR\fB\fIidle_timeout\fR\fR\fB);\fR .sp \fBvoid coap_delete_cache_entry(coap_context_t *\fR\fB\fIcontext\fR\fR\fB, coap_cache_entry_t *\fR\fB\fIcache_entry\fR\fR\fB);\fR .sp \fBcoap_cache_entry_t *coap_cache_get_by_key(coap_context_t *\fR\fB\fIcontext\fR\fR\fB, const coap_cache_key_t *\fR\fB\fIcache_key\fR\fR\fB);\fR .sp \fBcoap_cache_entry_t *coap_cache_get_by_pdu(coap_session_t *\fR\fB\fIsession\fR\fR\fB, const coap_pdu_t *\fR\fB\fIpdu\fR\fR\fB, coap_cache_session_based_t \fR\fB\fIsession_based\fR\fR\fB);\fR .sp \fBconst coap_pdu_t *coap_cache_get_pdu(const coap_cache_entry_t *\fR\fB\fIcache_entry\fR\fR\fB);\fR .sp \fBvoid coap_cache_set_app_data(coap_cache_entry_t *\fR\fB\fIcache_entry\fR\fR\fB, void *\fR\fB\fIdata\fR\fR\fB, coap_cache_app_data_free_callback_t \fR\fB\fIcallback\fR\fR\fB);\fR .sp \fBvoid *coap_cache_get_app_data(const coap_cache_entry_t *\fR\fB\fIcache_entry\fR\fR\fB);\fR .sp For specific (D)TLS library support, link with \fB\-lcoap\-3\-notls\fR, \fB\-lcoap\-3\-gnutls\fR, \fB\-lcoap\-3\-openssl\fR, \fB\-lcoap\-3\-mbedtls\fR or \fB\-lcoap\-3\-tinydtls\fR\&. Otherwise, link with \fB\-lcoap\-3\fR to get the default (D)TLS library support\&. .SH "DESCRIPTION" .sp The CoAP Cache provides support for two opaque objects that can be used for tracking requests and responses\&. .sp The first is the ability to derive a Cache Key from the cacheable parts of a CoAP PDU as defined in "RFC7252 5\&.6\&. Caching" updated by "RFC7641 2\&. The Observe Option" and "RFC8132 2\&. Fetch Method"\&. .sp The Cache Key is a SHA256 digest if libcoap was built with TLS support, otherwise it uses the internal coap_hash() function, using the information abstracted from the PDU and (optionally) the CoAP session\&. .sp This Cache Key can then be used to match against incoming PDUs and then appropriate action logic can take place\&. .sp There is support for excluding specific CoAP options from the Cache Key\&. Examples could be to exclude CoAP BLOCK1 and BLOCK2 Options for the client or server for ease of tracking a large PUT or GET response, but to not exclude these CoAP options in a proxy where it makes sense to cache the individual blocks\&. .sp The second is providing Cache Entries (which can be looked up by PDU and hence by Cache Key) which hold additional information to make information tracking simpler\&. These Cache Entries are automatically deleted when a session closes or a context is deleted\&. These Cache Entries are maintained on a hashed list for speed of lookup\&. .sp The following enums are defined\&. .sp .if n \{\ .RS 4 .\} .nf typedef enum coap_cache_session_based_t { COAP_CACHE_NOT_SESSION_BASED, COAP_CACHE_IS_SESSION_BASED } coap_cache_session_based_t; typedef enum coap_cache_record_pdu_t { COAP_CACHE_NOT_RECORD_PDU, COAP_CACHE_RECORD_PDU } coap_cache_record_pdu_t; .fi .if n \{\ .RE .\} .SH "FUNCTIONS" .sp \fBFunction: coap_cache_derive_key()\fR .sp The \fBcoap_cache_derive_key\fR() function abstracts all the non NoCacheKey CoAP options, ignores the CoAP Observe option and includes a FETCH body from \fIpdu\fR\&. If \fIsession_based\fR is COAP_CACHE_IS_SESSION_BASED, then \fIsession\fR pointer is also included\&. CoAP options can be specifically ignored by the use of \fBcoap_cache_ignore_options\fR()\&. A digest is then built from all of the information and returned\&. NULL is returned on error\&. .sp \fBFunction: coap_cache_derive_key_w_ignore()\fR .sp The \fBcoap_cache_derive_key_w_ignore\fR() function abstracts all the non NoCacheKey CoAP options, ignores the CoAP Observe option and includes a FETCH body from \fIpdu\fR\&. Further options to ignore are specified by the \fIignore_count\fR of \fIignore_options\fR\&. If \fIsession_based\fR is COAP_CACHE_IS_SESSION_BASED, then \fIsession\fR pointer is also included\&. A digest is then built from all of the information and returned\&. NULL is returned on error\&. .sp \fBFunction: coap_delete_cache_key()\fR .sp The \fBcoap_delete_cache_key\fR() function deletes the \fIcache_key\fR that was returned from a \fBcoap_cache_derive_key\fR() or \fBcoap_cache_derive_key_w_ignore\fR() call\&. .sp \fBFunction: coap_cache_ignore_options()\fR .sp The \fBcoap_cache_ignore_options\fR() function is used to store in \fIcontext\fR a list of \fIcount\fR options held in \fIoptions\fR\&. The specified \fIoptions\fR will not be included in the data used for the \fBcoap_cache_derive_key\fR() function\&. .sp \fBFunction: coap_new_cache_entry()\fR .sp The \fBcoap_new_cache_entry\fR() function will create a new Cache Entry based on the Cache Key derived from the \fIpdu\fR, \fIsession_based\fR and \fIsession\fR\&. If \fIrecord_pdu\fR is COAP_CACHE_RECORD_PDU, then a copy of the \fIpdu\fR is stored in the Cache Entry for subsequent retrieval\&. The Cache Entry can also store application specific data (\fBcoap_cache_set_app_data\fR() and \fBcoap_cache_get_app_data\fR())\&. \fIidle_timeout\fR in seconds defines the length of time not being used before it gets deleted\&. If \fIidle_timeout\fR is set to 0, then the Cache Entry will not get idle expired\&. The created Cache Entry is returned, or NULL on error\&. .sp \fBFunction: coap_delete_cache_entry()\fR .sp The \fBcoap_delete_cache_entry\fR() function can be used to delete the Cache Entry \fIcache_entry\fR held within \fIcontext\fR\&. This will remove the Cache Entry from the hash lookup list and free off any internally held data\&. If the Cache Entry is session based, then it will automatically get deleted when the session is freed off or when the idle timeout expires\&. .sp \fBFunction: coap_cache_get_by_key()\fR .sp The \fBcoap_cache_get_by_key\fR() function will locate the Cache Entry held in the \fIcontext\fR environment that has Cache Key \fIcache_key\fR\&. Returns NULL if the Cache Key was not found\&. .sp \fBFunction: coap_cache_get_by_pdu()\fR .sp The \fBcoap_cache_get_by_pdu\fR() function will locate the Cache Entry held in the \fIsession\fR environment that has a Cache Key derived from the \fIpdu\fR and whether \fIsession_based\fR or not\&. This function calls \fBcoap_cache_derive_key\fR() internally, and so normally \fBcoap_cache_ignore_options\fR() would have previously been called with COAP_OPTION_BLOCK1 or COAP_OPTION_BLOCK2 to ignore the values held within these options\&. .sp \fBFunction: coap_cache_get_pdu()\fR .sp The \fBcoap_cache_get_pdu\fR() function returns the PDU that was stored with the Cache Entry when it was created with \fBcoap_new_cache_entry\fR() and \fIrecord_pdu\fR was set to COAP_CACHE_RECORD_PDU\&. If a PDU was not initially stored, NULL is returned\&. \fBNOTE:\fR A copy of the returned PDU must be taken for use in sending a CoAP packet using \fBcoap_pdu_duplicate\fR()\&. .sp \fBFunction: coap_cache_set_app_data()\fR .sp The \fBcoap_cache_set_app_data\fR() function is used to associate \fIdata\fR with the \fIcache_entry\fR\&. If \fIcallback\fR is not NULL, it points to a function to free off \fIdata\fR when the \fIcache_entry\fR is deleted\&. If any data has been previously stored in the \fIcache_entry\fR, the pointer to the old data will get overwritten, but the old data will not get freed off\&. .sp The \fIcallback\fR handler function prototype is defined as: .sp .if n \{\ .RS 4 .\} .nf typedef void (*coap_cache_app_data_free_callback_t)(void *data); .fi .if n \{\ .RE .\} .sp where \fIdata\fR is passed into the callback function whenever the Cache Entry is deleted\&. .sp \fBFunction: coap_cache_get_app_data()\fR .sp The \fBcoap_cache_get_app_data\fR() function is used to get the previously stored \fIdata\fR in the \fIcache_entry\fR\&. .SH "RETURN VALUES" .sp \fBcoap_cache_derive_key\fR() and \fBcoap_cache_derive_key_w_ignore\fR() returns a newly created Cache Key or NULL if there is a creation failure\&. .sp \fBcoap_cache_ignore_options\fR() returns 1 if success, 0 on failure\&. .sp \fBcoap_new_cache_entry\fR(), \fBcoap_cache_get_by_key\fR() and \fBcoap_cache_get_by_pdu\fR() return the Cache Entry or NULL if there is a failure\&. .sp \fBcoap_cache_get_pdu\fR() returns the PDU that is held within the Cache Entry or NULL if there is no PDU available\&. .sp \fBcoap_cache_get_app_data\fR() returns the application data value previously set by the \fBcoap_cache_set_app_data\fR() function or NULL\&. .SH "EXAMPLES" .sp \fBPUT Handler supporting BLOCK1\fR .sp .if n \{\ .RS 4 .\} .nf #include static coap_binary_t *example_data_ptr = NULL; static int example_data_media_type = COAP_MEDIATYPE_TEXT_PLAIN; static void cache_free_app_data(void *data) { coap_binary_t *bdata = (coap_binary_t*)data; coap_delete_binary(bdata); } /* * Large Data PUT handler */ static void hnd_put_example_data(coap_context_t *ctx, coap_resource_t *resource, coap_session_t *session, coap_pdu_t *request, coap_binary_t *token, coap_string_t *query, coap_pdu_t *response ) { size_t size; const uint8_t *data; coap_opt_iterator_t opt_iter; coap_opt_t *option; size_t offset; size_t total; coap_binary_t *data_so_far; /* Remove (void) definition if variable is used */ (void)ctx; (void)token; (void)query; if (coap_get_data_large(request, &size, &data, &offset, &total) && size != total) { /* * A part of the data has been received (COAP_BLOCK_SINGLE_BODY not set)\&. * However, total unfortunately is only an indication, so it is not safe to * allocate a block based on total\&. As per * https://rfc\-editor\&.org/rfc/rfc7959#section\-4 * o In a request carrying a Block1 Option, to indicate the current * estimate the client has of the total size of the resource * representation, measured in bytes ("size indication")\&. * * coap_cache_ignore_options() must have previously been called with at * least COAP_OPTION_BLOCK1 set as the option value will change per block\&. */ coap_cache_entry_t *cache_entry = coap_cache_get_by_pdu(session, request, COAP_CACHE_IS_SESSION_BASED); if (offset == 0) { if (!cache_entry) { /* * Set idle_timeout parameter to COAP_MAX_TRANSMIT_WAIT if you want * early removal on transmission failure\&. 0 means only delete when * the session is deleted as session_based is set here\&. */ cache_entry = coap_new_cache_entry(session, request, COAP_CACHE_NOT_RECORD_PDU, COAP_CACHE_IS_SESSION_BASED, 0); } else { data_so_far = coap_cache_get_app_data(cache_entry); if (data_so_far) { coap_delete_binary(data_so_far); data_so_far = NULL; } coap_cache_set_app_data(cache_entry, NULL, NULL); } } if (!cache_entry) { if (offset == 0) { coap_log_warn("Unable to create a new cache entry\en"); } else { coap_log_warn( "No cache entry available for the non\-first BLOCK\en"); } coap_pdu_set_code(response, COAP_RESPONSE_CODE_INTERNAL_ERROR); return; } if (size) { /* Add in the new data to cache entry */ data_so_far = coap_cache_get_app_data(cache_entry); data_so_far = coap_block_build_body(data_so_far, size, data, offset, total); /* Yes, data_so_far can be NULL if error */ coap_cache_set_app_data(cache_entry, data_so_far, cache_free_app_data); } if (offset + size == total) { /* All the data is now in */ data_so_far = coap_cache_get_app_data(cache_entry); coap_cache_set_app_data(cache_entry, NULL, NULL); } else { /* Give us the next block response */ coap_pdu_set_code(response, COAP_RESPONSE_CODE_CONTINUE); return; } } else { /* single body of data received */ data_so_far = coap_new_binary(size); if (data_so_far) { memcpy(data_so_far\->s, data, size); } } if (example_data_ptr) { /* pre\-existed response */ coap_pdu_set_code(response, COAP_RESPONSE_CODE_CHANGED); coap_delete_binary(example_data_ptr); } else /* just generated response */ coap_pdu_set_code(response, COAP_RESPONSE_CODE_CREATED); example_data_ptr = data_so_far; if ((option = coap_check_option(request, COAP_OPTION_CONTENT_FORMAT, &opt_iter)) != NULL) { example_data_media_type = coap_decode_var_bytes (coap_opt_value (option), coap_opt_length (option)); } else { example_data_media_type = COAP_MEDIATYPE_TEXT_PLAIN; } coap_pdu_set_code(response, COAP_RESPONSE_CODE_CHANGED); coap_resource_notify_observers(resource, NULL); } int main(int argc, char* argv[]) { coap_context_t *ctx = NULL; /* Set up as normal */ /* \&.\&.\&. */ uint16_t cache_ignore_options[] = { COAP_OPTION_BLOCK1, COAP_OPTION_BLOCK2 }; /* Initialize libcoap library */ coap_startup(); /* Remove (void) definition if variable is used */ (void)argc; (void)argv; /* \&.\&.\&. */ /** Define the options to ignore when setting up cache\-keys */ coap_cache_ignore_options(ctx, cache_ignore_options, sizeof(cache_ignore_options)/sizeof(cache_ignore_options[0])); /* \&.\&.\&. */ coap_cleanup(); } .fi .if n \{\ .RE .\} .SH "SEE ALSO" .sp \fBcoap_block\fR(3), \fBcoap_init\fR(3), \fBcoap_pdu_setup\fR(3), \fBcoap_resource\fR(3) and \fBcoap_string\fR(3) .SH "FURTHER INFORMATION" .sp See .sp "RFC7252: The Constrained Application Protocol (CoAP)" .sp "RFC7959: Block\-Wise Transfers in the Constrained Application Protocol (CoAP)" .sp for further information\&. .SH "BUGS" .sp Please report bugs on the mailing list for libcoap: libcoap\-developers@lists\&.sourceforge\&.net or raise an issue on GitHub at https://github\&.com/obgm/libcoap/issues .SH "AUTHORS" .sp The libcoap project