'\" t
.\"     Title: coap_persist
.\"    Author: [see the "AUTHORS" section]
.\" Generator: DocBook XSL Stylesheets vsnapshot <http://docbook.sf.net/>
.\"      Date: 10/28/2023
.\"    Manual: libcoap Manual
.\"    Source: coap_persist 4.3.4
.\"  Language: English
.\"
.TH "COAP_PERSIST" "3" "10/28/2023" "coap_persist 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_persist, coap_persist_startup, coap_persist_stop, coap_persist_track_funcs, coap_persist_observe_add, coap_persist_set_observe_num \- Work with CoAP persist support 
.SH "SYNOPSIS"
.sp
\fB#include <coap3/coap\&.h>\fR
.sp
\fBint coap_persist_startup(coap_context_t *\fR\fB\fIcontext\fR\fR\fB, const char *\fR\fB\fIdyn_resource_save_file\fR\fR\fB, const char *\fR\fB\fIobserve_save_file\fR\fR\fB, const char *\fR\fB\fIobs_cnt_save_file\fR\fR\fB, uint32_t \fR\fB\fIsave_freq\fR\fR\fB);\fR
.sp
\fBvoid coap_persist_stop(coap_context_t *\fR\fB\fIcontext\fR\fR\fB);\fR
.sp
\fBvoid coap_persist_track_funcs(coap_context_t *\fR\fB\fIcontext\fR\fR\fB, coap_observe_added_t \fR\fB\fIobserve_added\fR\fR\fB, coap_observe_deleted_t \fR\fB\fIobserve_deleted\fR\fR\fB, coap_track_observe_value_t \fR\fB\fItrack_observe_value\fR\fR\fB, coap_dyn_resource_added_t \fR\fB\fIdyn_resource_added\fR\fR\fB, coap_resource_deleted_t \fR\fB\fIresource_deleted\fR\fR\fB, uint32_t \fR\fB\fIsave_freq\fR\fR\fB, void *\fR\fB\fIuser_data\fR\fR\fB);\fR
.sp
\fBcoap_subscription_t *coap_persist_observe_add(coap_context_t *\fR\fB\fIcontext\fR\fR\fB, coap_proto_t \fR\fB\fIe_proto\fR\fR\fB, const coap_address_t *\fR\fB\fIe_listen_addr\fR\fR\fB, const coap_addr_tuple_t *\fR\fB\fIs_addr_info\fR\fR\fB, const coap_bin_const_t *\fR\fB\fIraw_packet\fR\fR\fB, const coap_bin_const_t *\fR\fB\fIoscore_info\fR\fR\fB);\fR
.sp
\fBvoid coap_persist_set_observe_num(coap_resource_t *\fR\fB\fIresource\fR\fR\fB, uint32_t \fR\fB\fIstart_observe_no\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
When a coap\-server is restarted, state information does not usually persist over the restart\&. libcoap has optional compiled in support for maintaining resources that were dynamically created, tracking ongoing observe subscriptions and maintaining OSCORE protection\&.
.sp
There are callbacks provided to support doing this as an alternative persist storage in the coap\-server application\&.
.sp
\fBNOTE:\fR The observe persist support is only available for UDP sessions\&.
.sp
When using the libcoap compiled in support, only two functions need to be called by the application\&. \fBcoap_persist_startup\fR() defines the file names to use for maintaining the persist information over an application restart, and \fBcoap_persist_stop\fR() is called to preserve any persist information over the server restart\&.
.SH "FUNCTIONS"
.sp
\fBFunction: coap_persist_startup()\fR
.sp
The \fBcoap_persist_startup\fR() function is used to enable persist tracking for \fIcontext\fR so when a coap\-server is restarted, the persist tracked information can be added back in for the server logic\&. \fIdyn_resource_save_file\fR is used to save the current list of resources created from a request to the unknown resource\&. \fIobserve_save_file\fR is used to save the current list of active observe subscriptions\&. \fIobs_cnt_save_file\fR is used to save the current observe counter used when sending an observe unsolicited response\&. \fIobs_cnt_save_file\fR only gets updated every \fIsave_freq\fR updates\&.
.sp
If any of the files exist and are not empty, when \fBcoap_persist_startup\fR() is called, the information is loaded back into the server logic, and for the active observe subscriptions a new server session is created for sending out the ongoing observe updates (UDP only supported)\&.
.sp
If a file is defined as NULL, then that particular persist information is not tracked by the libcoap module\&. This allows a combination of \fBcoap_persist_track_funcs\fR() for customized persist tracking followed by a call to \fBcoap_persist_startup\fR()\&.
.sp
\fBFunction: coap_persist_stop()\fR
.sp
The \fBcoap_persist_stop\fR() function is used to disable any current persist tracking as set up by \fBcoap_persist_startup\fR() for \fIcontext\fR and preserve the tracking for when the coap\-server application restarts\&.
.sp
If using \fBcoap_persist_track_funcs\fR(), then calling \fBcoap_persist_stop\fR() will stop any 4\&.04 unsolicited response messages being sent when a resource that has an active observe subscription is deleted (as happens when \fBcoap_free_context\fR() is subsequentially called)\&.
.sp
\fBFunction: coap_persist_track_funcs()\fR
.sp
The \fBcoap_persist_track_funcs\fR() function is used to setup callback functions associated with \fIcontext\fR that track information so that the current tracked information state can be rebuilt following a server application restart\&. It is the responsibility of the server application to track the appropriate information\&.
.sp
The \fIobserve_added\fR callback function prototype, called when a client subscribes to a resource for observation, is defined as:
.sp
.if n \{\
.RS 4
.\}
.nf
typedef int (*coap_observe_added_t)(coap_session_t *session,
                                    coap_subscription_t *observe_key,
                                    coap_proto_t e_proto,
                                    coap_address_t *e_listen_addr,
                                    coap_addr_tuple_t *s_addr_info,
                                    coap_bin_const_t *raw_packet,
                                    coap_bin_const_t *oscore_info,
                                    void *user_data);
.fi
.if n \{\
.RE
.\}
.sp
The \fIobserve_deleted\fR callback function prototype, called when a client removes the subscription to a resource for observation, is defined as:
.sp
.if n \{\
.RS 4
.\}
.nf
typedef int (*coap_observe_deleted_t)(coap_session_t *session,
                                      coap_subscription_t *observe_key,
                                      void *user_data);
.fi
.if n \{\
.RE
.\}
.sp
The \fItrack_observe_value\fR callback function prototype, called when a new unsolicited observe response is went (every \fIsave_freq\fR), is defined as:
.sp
.if n \{\
.RS 4
.\}
.nf
typedef int (*coap_track_observe_value_t)(coap_context_t *context,
                                          coap_str_const_t *resource_name,
                                          uint32_t observe_num,
                                          void *user_data);
.fi
.if n \{\
.RE
.\}
.sp
The \fIdyn_resource_added\fR callback function prototype, called whenever a resource is created from a request that is calling the resource unknown handler, is defined as:
.sp
.if n \{\
.RS 4
.\}
.nf
typedef int (*coap_dyn_resource_added_t)(coap_session_t *session,
                                         coap_str_const_t *resource_name,
                                         coap_bin_const_t *raw_packet,
                                         void *user_data);
.fi
.if n \{\
.RE
.\}
.sp
The \fIresource_deleted\fR callback function prototype, called whenever a resource is deleted, is defined as:
.sp
.if n \{\
.RS 4
.\}
.nf
typedef int (*coap_resource_deleted_t)(coap_context_t *context,
                                       coap_str_const_t *resource_name,
                                       void *user_data);
.fi
.if n \{\
.RE
.\}
.sp
\fIsave_freq\fR defines the frequency of the update to the observe value when libcoap calls \fItrack_observe_value\fR\&. \fIuser_data\fR is application defined and is passed into all of the callback handlers\&.
.sp
\fBFunction: coap_persist_observe_add()\fR
.sp
The \fBcoap_persist_observe_add\fR() function is used to set up a session and a observe subscription request (typically following a server reboot) so that a client can continue to receive unsolicited observe responses without having to establish a new session and issue a new observe subscription request\&. The new session is associated with the endpoint defined by \fIe_proto\fR and \fIe_listen_address\fR\&. The session has the IP addresses as defined by \fIs_addr_info\fR\&. \fIraw_packet\fR contains the layer 7 of the IP packet that was originally used to request the observe subscription\&. Optional \fIoscore_info\fR defines the OSCORE information if packets are protected by OSCORE\&. \fIe_proto\fR, \fIe_listen_addr\fR, \fIs_addr_info\fR, \fIraw_packet\fR and \fIoscore_info\fR are the same as passed into the \fIcoap_observe_added_t\fR callback\&.
.sp
\fBFunction: coap_persist_set_observe_num()\fR
.sp
The \fBcoap_persist_set_observe_num\fR() function is used to update the \fIresource\fR\*(Aqs current observe counter to start from \fIstart_observe_no\fR instead of 0,
.SH "RETURN VALUES"
.sp
\fBcoap_persist_startup\fR() returns 1 on success else 0\&.
.sp
\fBcoap_persist_observe_add\fR() returns a newly created observe subscription or NULL on failure\&.
.SH "EXAMPLES"
.sp
\fBSimple Time Server\fR
.sp
.if n \{\
.RS 4
.\}
.nf
#include <coap3/coap\&.h>

#include <stdio\&.h>

coap_resource_t *time_resource = NULL;

/* specific GET "time" handler, called from hnd_get_generic() */

static void
hnd_get_time(coap_resource_t *resource, coap_session_t *session,
const coap_pdu_t *request, const coap_string_t *query, coap_pdu_t *response) {

  unsigned char buf[40];
  size_t len;
  time_t now;
  (void)resource;
  (void)session;

  /* \&.\&.\&. Additional analysis code for resource, request pdu etc\&.  \&.\&.\&. */

  /* After analysis, generate a suitable response */

  /* Note that token, if set, is already in the response pdu */

  now = time(NULL);

  if (query != NULL && coap_string_equal(query, coap_make_str_const("secs"))) {
    /* Output secs since Jan 1 1970 */
    len = snprintf((char *)buf, sizeof(buf), "%lu", now);
  }
  else {
    /* Output human\-readable time */
    struct tm *tmp;
    tmp = gmtime(&now);
    if (!tmp) {
      /* If \*(Aqnow\*(Aq is not valid */
      coap_pdu_set_code(response, COAP_RESPONSE_CODE_NOT_FOUND);
      return;
    }
    len = strftime((char *)buf, sizeof(buf), "%b %d %H:%M:%S", tmp);
  }
  coap_pdu_set_code(response, COAP_RESPONSE_CODE_CONTENT);
  /*
   * Invoke coap_add_data_large_response() to do all the hard work\&.
   *
   * Define the format \- COAP_MEDIATYPE_TEXT_PLAIN \- to add in
   * Define how long this response is valid for (secs) \- 1 \- to add in\&.
   * ETAG Option added internally with unique value as param set to 0
   *
   * OBSERVE Option added internally if needed within the function
   * BLOCK2 Option added internally if output too large
   * SIZE2 Option added internally
   */
  coap_add_data_large_response(resource, session, request, response,
                               query, COAP_MEDIATYPE_TEXT_PLAIN, 1, 0,
                               len,
                               buf, NULL, NULL);
}

/* Generic GET handler */

static void
hnd_get_generic(coap_resource_t *resource, coap_session_t *session,
const coap_pdu_t *request, const coap_string_t *query, coap_pdu_t *response) {

  coap_str_const_t *uri_path = coap_resource_get_uri_path(resource);

  if (!uri_path) {
    /* Unexpected Failure */
    coap_pdu_set_code(response, COAP_RESPONSE_CODE_BAD_REQUEST);
    return;
  }

  /* Is this the "time" resource" ? */
  if (coap_string_equal(uri_path, coap_make_str_const("time"))) {
    hnd_get_time(resource, session, request, query, response);
    return;
  }

  /* Other resources code */

  /* Failure response */
  coap_pdu_set_code(response, COAP_RESPONSE_CODE_BAD_REQUEST);
}

/* Initialize generic GET handler */

static void
init_resources(coap_context_t *ctx)
{

  coap_resource_t *r;

  /* Create a resource to return return or update time */
  r = coap_resource_init(coap_make_str_const("time"),
                         COAP_RESOURCE_FLAGS_NOTIFY_CON);

  /* We are using a generic GET handler here */
  coap_register_request_handler(r, COAP_REQUEST_GET, hnd_get_generic);

  coap_resource_set_get_observable(r, 1);

  coap_add_resource(ctx, r);
  time_resource = r;

}

int
main(int argc, char *argv[]) {

  coap_context_t *ctx = NULL;
  coap_endpoint_t *ep = NULL;
  coap_address_t addr;
  unsigned wait_ms;
  struct timeval tv_last = {0, 0};
  /* Remove (void) definition if variable is used */
  (void)argc;
  (void)argv;

  /* Initialize libcoap library */
  coap_startup();

  memset (&tv_last, 0, sizeof(tv_last));

  /* Create the libcoap context */
  ctx = coap_new_context(NULL);
  if (!ctx) {
    exit(1);
  }
  /* See coap_block(3) */
  coap_context_set_block_mode(ctx,
                              COAP_BLOCK_USE_LIBCOAP | COAP_BLOCK_SINGLE_BODY);

  coap_address_init(&addr);
  addr\&.addr\&.sa\&.sa_family = AF_INET;
  addr\&.addr\&.sin\&.sin_port = ntohs(COAP_DEFAULT_PORT);
  ep = coap_new_endpoint(ctx, &addr, COAP_PROTO_UDP);

  /* Other Set up Code */

  init_resources(ctx);

  if (!coap_persist_startup(ctx,
                            "/tmp/coap_dyn_resource_save_file",
                            "/tmp/coap_observe_save_file",
                            "/tmp/coap_obs_cnt_save_file", 10)) {
    fprintf(stderr, "Unable to set up persist logic\en");
    exit(1);
  }

  wait_ms = COAP_RESOURCE_CHECK_TIME * 1000;

  while (1) {
    int result = coap_io_process( ctx, wait_ms );
    if ( result < 0 ) {
      break;
    } else if ( result && (unsigned)result < wait_ms ) {
      /* decrement if there is a result wait time returned */
      wait_ms \-= result;
    } else {
      /*
       * result == 0, or result >= wait_ms
       * (wait_ms could have decremented to a small value, below
       * the granularity of the timer in coap_io_process() and hence
       * result == 0)
       */
      wait_ms = COAP_RESOURCE_CHECK_TIME * 1000;
    }
    if (time_resource) {
      struct timeval tv_now;
      if (gettimeofday (&tv_now, NULL) == 0) {
        if (tv_last\&.tv_sec != tv_now\&.tv_sec) {
          /* Happens once per second */
          tv_last = tv_now;
          coap_resource_notify_observers(time_resource, NULL);
        }
        /* need to wait until next second starts if wait_ms is too large */
        unsigned next_sec_ms = 1000 \- (tv_now\&.tv_usec / 1000);

        if (next_sec_ms && next_sec_ms < wait_ms)
          wait_ms = next_sec_ms;
      }
    }
  }
  coap_persist_stop(ctx);
  coap_free_context(ctx);
  coap_cleanup();
  exit(0);

}
.fi
.if n \{\
.RE
.\}
.SH "SEE ALSO"
.sp
\fBcoap_block\fR(3), \fBcoap_context\fR(3), \fBcoap_handler\fR(3), \fBcoap_init\fR(3), \fBcoap_observe\fR(3), \fBcoap_pdu_setup\fR(3), \fBcoap_resource\fR(3) and \fBcoap_session\fR(3)
.SH "FURTHER INFORMATION"
.sp
See
.sp
"RFC7252: The Constrained Application Protocol (CoAP)"
.sp
"RFC7641: Observing Resources in the Constrained Application Protocol (CoAP)"
.sp
"RFC8613: Object Security for Constrained RESTful Environments (OSCORE)"
.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>