'\" t
.\"     Title: coap_cache
.\"    Author: [see the "AUTHORS" section]
.\" Generator: DocBook XSL Stylesheets vsnapshot <http://docbook.sf.net/>
.\"      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 <coap3/coap\&.h>\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 <coap3/coap\&.h>

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 <libcoap\-developers@lists\&.sourceforge\&.net>