SYNOPSIS
#include <coap3/coap.h>
int coap_io_process(coap_context_t *context, uint32_t timeout_ms);
int coap_io_process_with_fds(coap_context_t *context,
uint32_t timeout_ms, int nfds, fd_set *readfds, fd_set *writefds,
fd_set *exceptfds);
int coap_context_get_coap_fd(const coap_context_t *context);
unsigned int coap_io_prepare_io(coap_context_t *context,
coap_socket_t *sockets[], unsigned int max_sockets,
unsigned int *num_sockets, coap_tick_t now);
void coap_io_do_io(coap_context_t *context, coap_tick_t now);
unsigned int coap_io_prepare_epoll(coap_context_t *context,
coap_tick_t now);
void coap_io_do_epoll(coap_context_t *context, struct epoll_event *events,
size_t nevents);
int coap_io_pending(coap_context_t *context);
int coap_can_exit(coap_context_t *context);
For specific (D)TLS library support, link with
-lcoap-3-notls, -lcoap-3-gnutls,
-lcoap-3-openssl, -lcoap-3-mbedtls,
-lcoap-3-wolfssl
or -lcoap-3-tinydtls. Otherwise, link with
-lcoap-3 to get the default (D)TLS library support.
DESCRIPTION
After setting up all the contexts, resources, endpoints sessions etc., the
underlying CoAP and (D)TLS need to send (and possible re-send) created packets
as well as receive packets for processing.
The coap_io_process() function is the primary function applications should
use. There are internal functions that coap_io_process() calls which are
available to use if absolutely necessary. These internal functions and how to
use them is different depending on whether libcoap has been compiled to use
epoll (Linux systems only) or not.
For epoll libcoap, coap_io_process() in simple terms calls
coap_io_prepare_epoll(), does an epoll_wait() and then calls
coap_io_do_epoll() if needed to make sure that all event based i/o has been
completed.
For non-epoll libcoap, coap_io_process() in simple terms calls
coap_io_prepare_io() to set up sockets[], sets up all of the select()
parameters based on the COAP_SOCKET_WANT* values in the sockets[], does a
select(), updates the sockets[] with COAP_SOCKET_CAN_* as appropriate and
then calls coap_io_do_io() to make sure that all current i/o has been
completed.
FUNCTIONS
Function: coap_io_process()
The coap_io_process() function will process any outstanding packets to send
for the specified context, process any available input packets and then wait
for processing any new input packets, or for when to re-transmit a packet, for
up to timeout_ms milli-seconds before returning. There are 2 special case
timeout_ms values.
#define COAP_IO_WAIT 0
#define COAP_IO_NO_WAIT ((uint32_t)-1)
If timeout_ms is set to COAP_IO_WAIT, then coap_io_process() will block
until the next internal action (e.g. packet retransmit) if any, or block until
the next packet is received whichever is the sooner and do the necessary
processing. If timeout_ms is set to COAP_IO_NO_WAIT, then coap_io_process()
will return immediately after processing without waiting for any new input
packets to arrive.
NOTE: coap_io_process() should not be called from within a callback
handler as defined using the coap_register_*_handler() as coap_io_process()
will likely recursively call the same handler.
There are two methods of how to call coap_io_process().
-
Have coap_io_process() called from within a while() loop. Under idle
conditions (no input traffic) coap_io_process() will then get called every
timeout_ms, but more frequently if there is input / retransmission traffic.
-
Wait on the file descriptor returned by coap_context_get_coap_fd()
using select(), poll() or an event returned by epoll_wait(). If read is
available on the CoAP file descriptor, call coap_io_process() with
timeout_ms set to COAP_IO_NO_WAIT.
NOTE: This second method is only available for environments that support epoll
(mostly Linux) with libcoap compiled to use epoll (the default) as libcoap
will then be using epoll internally to process all the file descriptors of
the different sessions.
See EXAMPLES below.
Function: coap_io_prepare_epoll()
The coap_io_prepare_epoll() function for the specified context will
iterate through the endpoints and sessions to transmit any triggered observer
responses as well as handling any timed out packet re-transmissions. Returned,
based on now, is the number of milli-secs needed to delay until the next
time that coap_io_prepare_epoll() needs to get called. After this call an
epoll_wait() should done.
Function: coap_io_do_epoll()
The coap_io_do_epoll() function for the specified context will
iterate through the nevents of events returned by epoll_wait() and
execute the appropriate low level i/o function to send / receive / process the
packets. Where appropriate, structure information (endpoints, sessions etc.)
is updated with the value of now in the lower level functions.
Function: coap_io_prepare_io()
The coap_io_prepare_io() function for the specified context will iterate
through the endpoints and sessions to add all of sockets waiting for network
traffic (COAP_SOCKET_WANT_* is set) found to sockets (limited by
max_sockets) and updates num_sockets with the number of sockets found.
Furthermore, any triggered observer responses are transmitted
as well as handling any timed out packet re-transmissions. Returned, based on
now, is the number of milli-secs needed to delay until the next time that
coap_io_prepare_io() needs to get called. After this call a select() should
done on all the file descriptors (COAP_WANT_READ for readfds etc.), and any
that are returned active should set the appropriate COAP_SOCKET_CAN_* in the
sockets.
Function: coap_io_do_io()
The coap_io_do_io() function for the specified context will
iterate through the endpoints and sessions to find all of sockets that have
COAP_SOCKET_CAN_* set and then execute the appropriate low level i/o function
to send / receive / process the packets. Where appropriate, structure
information (endpoints, sessions etc.) is updated with the value of now in
the lower level functions.
Function: coap_io_process_with_fds()
The coap_io_process_with_fds() function is the same as coap_process_io()
but supports additional select() style parameters nfds, readfds,
writefds and exceptfds. This provides the ability to add in additional
non libcoap FDs to test for in the internal select() call which can then
tested after the return from coap_io_process_with_fds(). readfds,
writefds and exceptfds can either point to a defined and pre-filled fd_set
structure or NULL if not required. nfds needs to be set to the maximum FD to
test for in readfds, writefds or exceptfds if any of them are set plus 1.
If none of them are set, then nfds should be set to 0.
NOTE: The additional parameters for coap_io_process_with_fds() are only used
if there is no epoll support in libcoap. If there is epoll support, then
coap_context_get_coap_fd() should be used and this returned FD along with
other non libcoap FDs can separately be monitored using method 2 above.
Function: coap_context_get_coap_fd()
The coap_context_get_coap_fd() function obtains from the specified
context a single file descriptor that can be monitored by a select() or
as an event returned from a epoll_wait() call. This file descriptor will get
updated with information (read, write etc. available) whenever any of the
internal to libcoap file descriptors (sockets) change state.
Function: coap_io_pending()
The coap_io_pending() function checks to see if there are any outstanding
i/o requests / responses associated with context as well as if Observe has
been set up (client only) and large transfers are in process.
Function: coap_can_exit()
The coap_can_exit() function checks to see if there are any outstanding
PDUs to transmit associated with context and returns 1 if there is nothing
outstanding else 0. This function does not check that all requests transmitted
have been responded to.
EXAMPLES
Method One - use coap_io_process()
#include <coap3/coap.h>
int
main(int argc, char *argv[]) {
coap_context_t *ctx = NULL;
unsigned wait_ms;
/* Remove (void) definition if variable is used */
(void)argc;
(void)argv;
/* Initialize libcoap library */
coap_startup();
/* 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);
/* Other Set up Code */
wait_ms = COAP_RESOURCE_CHECK_TIME * 1000;
while (1) {
int result = coap_io_process(ctx, wait_ms);
if (result < 0) {
/* There is an internal issue */
break;
}
/* Do any other housekeeping */
}
coap_free_context(ctx);
coap_cleanup();
/* Do any other cleanup */
exit(0);
}
Method One - coap_io_process_with_fds
#include <coap3/coap.h>
int
main(int argc, char *argv[]) {
coap_context_t *ctx = NULL;
unsigned wait_ms;
fd_set readfds;
int nfds = 0;
/* Remove (void) definition if variable is used */
(void)argc;
(void)argv;
/* Initialize libcoap library */
coap_startup();
/* 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);
FD_ZERO(&readfds);
/* Set up readfds and nfds to handle other non libcoap FDs */
/* Other Set up Code */
wait_ms = COAP_RESOURCE_CHECK_TIME * 1000;
while (1) {
int result = coap_io_process_with_fds(ctx, wait_ms, nfds, &readfds, NULL, NULL);
if (result < 0) {
/* There is an internal issue */
break;
}
/* Check if set non libcoap FDs and process accordingly */
/* Do any other housekeeping */
}
coap_free_context(ctx);
coap_cleanup();
/* Do any other cleanup */
exit(0);
}
Method Two - select() based on monitorable file descriptor
#include <coap3/coap.h>
#include <errno.h>
int
main(int argc, char *argv[]) {
coap_context_t *ctx = NULL;
int coap_fd;
fd_set m_readfds;
int nfds;
/* Remove (void) definition if variable is used */
(void)argc;
(void)argv;
/* Initialize libcoap library */
coap_startup();
/* 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_fd = coap_context_get_coap_fd(ctx);
if (coap_fd == -1) {
/* epoll is not supported */
exit(1);
}
FD_ZERO(&m_readfds);
FD_SET(coap_fd, &m_readfds);
nfds = coap_fd + 1;
/* Other Set up Code */
while (1) {
fd_set readfds = m_readfds;
int result;
/* Wait until any i/o takes place */
result = select(nfds, &readfds, NULL, NULL, NULL);
if (result == -1) {
if (errno != EAGAIN) {
coap_log_debug("select: %s (%d)\n", coap_socket_strerror(), errno);
break;
}
}
if (result > 0) {
if (FD_ISSET(coap_fd, &readfds)) {
result = coap_io_process(ctx, COAP_IO_NO_WAIT);
if (result < 0) {
/* There is an internal issue */
break;
}
}
}
/* Do any other housekeeping */
}
coap_free_context(ctx);
coap_cleanup();
/* Do any other cleanup */
exit(0);
}
Method Two - epoll_wait() based on monitorable file descriptor
#include <coap3/coap.h>
#include <sys/epoll.h>
#include <errno.h>
#define MAX_EVENTS 10
int
main(int argc, char *argv[]) {
coap_context_t *ctx = NULL;
int coap_fd;
int epoll_fd;
struct epoll_event ev;
struct epoll_event events[MAX_EVENTS];
int nevents;
int i;
/* Remove (void) definition if variable is used */
(void)argc;
(void)argv;
/* Initialize libcoap library */
coap_startup();
/* 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_fd = coap_context_get_coap_fd(ctx);
if (coap_fd == -1) {
exit(1);
}
epoll_fd = epoll_create1(0);
if (epoll_fd == -1) {
exit(2);
}
ev.events = EPOLLIN;
ev.data.fd = coap_fd;
if (epoll_ctl(epoll_fd, EPOLL_CTL_ADD, coap_fd, &ev) == -1) {
exit(3);
}
/* Other Set up Code */
while (1) {
int result;
/* Wait until any i/o takes place */
nevents = epoll_wait(epoll_fd, events, MAX_EVENTS, -1);
if (nevents == -1) {
if (errno != EAGAIN) {
coap_log_debug("epoll_wait: %s (%d)\n", coap_socket_strerror(), errno);
break;
}
}
for (i = 0; i < nevents; i++) {
if (events[i].data.fd == coap_fd) {
result = coap_io_process(ctx, COAP_IO_NO_WAIT);
if (result < 0) {
/* There is an internal issue */
break;
}
} else {
/* Process other events */
}
}
/* Do any other housekeeping */
}
if (epoll_ctl(epoll_fd, EPOLL_CTL_DEL, coap_fd, &ev) == -1) {
coap_log_debug("epoll_ctl: %s (%d)\n", coap_socket_strerror(), errno);
}
coap_free_context(ctx);
coap_cleanup();
/* Do any other cleanup */
exit(0);
}