Provided by: libcoap3t64_4.3.4-1.1build4_amd64 bug

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

SYNOPSIS

       #include <coap3/coap.h>

       int coap_persist_startup(coap_context_t *context, const char *dyn_resource_save_file,
       const char *observe_save_file, const char *obs_cnt_save_file, uint32_t save_freq);

       void coap_persist_stop(coap_context_t *context);

       void coap_persist_track_funcs(coap_context_t *context, coap_observe_added_t observe_added,
       coap_observe_deleted_t observe_deleted, coap_track_observe_value_t track_observe_value,
       coap_dyn_resource_added_t dyn_resource_added, coap_resource_deleted_t resource_deleted,
       uint32_t save_freq, void *user_data);

       coap_subscription_t *coap_persist_observe_add(coap_context_t *context, coap_proto_t
       e_proto, const coap_address_t *e_listen_addr, const coap_addr_tuple_t *s_addr_info, const
       coap_bin_const_t *raw_packet, const coap_bin_const_t *oscore_info);

       void coap_persist_set_observe_num(coap_resource_t *resource, uint32_t start_observe_no);

       For specific (D)TLS library support, link with -lcoap-3-notls, -lcoap-3-gnutls,
       -lcoap-3-openssl, -lcoap-3-mbedtls or -lcoap-3-tinydtls. Otherwise, link with -lcoap-3 to
       get the default (D)TLS library support.

DESCRIPTION

       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.

       There are callbacks provided to support doing this as an alternative persist storage in
       the coap-server application.

       NOTE: The observe persist support is only available for UDP sessions.

       When using the libcoap compiled in support, only two functions need to be called by the
       application. coap_persist_startup() defines the file names to use for maintaining the
       persist information over an application restart, and coap_persist_stop() is called to
       preserve any persist information over the server restart.

FUNCTIONS

       Function: coap_persist_startup()

       The coap_persist_startup() function is used to enable persist tracking for context so when
       a coap-server is restarted, the persist tracked information can be added back in for the
       server logic. dyn_resource_save_file is used to save the current list of resources created
       from a request to the unknown resource. observe_save_file is used to save the current list
       of active observe subscriptions. obs_cnt_save_file is used to save the current observe
       counter used when sending an observe unsolicited response. obs_cnt_save_file only gets
       updated every save_freq updates.

       If any of the files exist and are not empty, when coap_persist_startup() 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).

       If a file is defined as NULL, then that particular persist information is not tracked by
       the libcoap module. This allows a combination of coap_persist_track_funcs() for customized
       persist tracking followed by a call to coap_persist_startup().

       Function: coap_persist_stop()

       The coap_persist_stop() function is used to disable any current persist tracking as set up
       by coap_persist_startup() for context and preserve the tracking for when the coap-server
       application restarts.

       If using coap_persist_track_funcs(), then calling coap_persist_stop() will stop any 4.04
       unsolicited response messages being sent when a resource that has an active observe
       subscription is deleted (as happens when coap_free_context() is subsequentially called).

       Function: coap_persist_track_funcs()

       The coap_persist_track_funcs() function is used to setup callback functions associated
       with context 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.

       The observe_added callback function prototype, called when a client subscribes to a
       resource for observation, is defined as:

           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);

       The observe_deleted callback function prototype, called when a client removes the
       subscription to a resource for observation, is defined as:

           typedef int (*coap_observe_deleted_t)(coap_session_t *session,
                                                 coap_subscription_t *observe_key,
                                                 void *user_data);

       The track_observe_value callback function prototype, called when a new unsolicited observe
       response is went (every save_freq), is defined as:

           typedef int (*coap_track_observe_value_t)(coap_context_t *context,
                                                     coap_str_const_t *resource_name,
                                                     uint32_t observe_num,
                                                     void *user_data);

       The dyn_resource_added callback function prototype, called whenever a resource is created
       from a request that is calling the resource unknown handler, is defined as:

           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);

       The resource_deleted callback function prototype, called whenever a resource is deleted,
       is defined as:

           typedef int (*coap_resource_deleted_t)(coap_context_t *context,
                                                  coap_str_const_t *resource_name,
                                                  void *user_data);

       save_freq defines the frequency of the update to the observe value when libcoap calls
       track_observe_value. user_data is application defined and is passed into all of the
       callback handlers.

       Function: coap_persist_observe_add()

       The coap_persist_observe_add() 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 e_proto and e_listen_address. The session has the IP addresses as defined by
       s_addr_info. raw_packet contains the layer 7 of the IP packet that was originally used to
       request the observe subscription. Optional oscore_info defines the OSCORE information if
       packets are protected by OSCORE. e_proto, e_listen_addr, s_addr_info, raw_packet and
       oscore_info are the same as passed into the coap_observe_added_t callback.

       Function: coap_persist_set_observe_num()

       The coap_persist_set_observe_num() function is used to update the resource's current
       observe counter to start from start_observe_no instead of 0,

RETURN VALUES

       coap_persist_startup() returns 1 on success else 0.

       coap_persist_observe_add() returns a newly created observe subscription or NULL on
       failure.

EXAMPLES

       Simple Time Server

           #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 'now' 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\n");
               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);

           }

SEE ALSO

       coap_block(3), coap_context(3), coap_handler(3), coap_init(3), coap_observe(3),
       coap_pdu_setup(3), coap_resource(3) and coap_session(3)

FURTHER INFORMATION

       See

       "RFC7252: The Constrained Application Protocol (CoAP)"

       "RFC7641: Observing Resources in the Constrained Application Protocol (CoAP)"

       "RFC8613: Object Security for Constrained RESTful Environments (OSCORE)"

       for further information.

BUGS

       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

AUTHORS

       The libcoap project <libcoap-developers@lists.sourceforge.net>