From 039826b83e4f7a532c3422e9b5130a461bf1e6d9 Mon Sep 17 00:00:00 2001 From: Jon Shallow Date: Tue, 29 Oct 2019 20:45:57 +0000 Subject: [PATCH] coap_io.c: Add in additional FD checking support for coap_run_once() coap_write() and coap_read() are really internal functions that are called from within coap_run_once() separated by a select() to wait for i/o and ideally should not be used in applications. However, currently, coap_write() and coap_read() are needed instead of coap_run_once() if there is no epoll support in libcoap so that if additional non libcoap FDs need to be set up and monitored by the select() call they then can be processed accordingly if the non libcoap FDs are set in the select() response. coap_io_process_with_fds() is a new function extending coap_run_once() that allows non libcoap FDs to be monitored in the coap_run_once() internal select() call and can then be tested by the caller of coap_io_process_with_fds(). coap_run_once() now calls coap_io_process_with_fds() with readfds, writefds, exceptfds set to NULL and nfds set to 0. Note: nfds, readfds, writefds and exceptfds are ignored if there is underlying epoll support in libcoap as epoll functions are used, not select(). Use coap_context_get_coap_fd() to get a single FD that covers all the libcoap FDs that can be used in the application along with other non-libcoap FDs when there is epoll support. See coap_io(3) for further information. include/coap2/net.h: libcoap-2.map: libcoap-2.sym: man/coap_io.txt.in: src/coap_io.c: Include and document the new coap_io_process_with_fds() function. --- include/coap2/net.h | 30 ++++++++++++++++++- libcoap-2.map | 1 + libcoap-2.sym | 1 + man/coap_io.txt.in | 73 ++++++++++++++++++++++++++++++++++++++++++--- src/coap_io.c | 45 ++++++++++++++++++++++++++-- 5 files changed, 142 insertions(+), 8 deletions(-) diff --git a/include/coap2/net.h b/include/coap2/net.h index 057cb43a..94c3f50d 100644 --- a/include/coap2/net.h +++ b/include/coap2/net.h @@ -584,9 +584,36 @@ void coap_read(coap_context_t *ctx, coap_tick_t now); * @return Number of milliseconds spent in coap_run_once, or @c -1 if there * was an error */ - int coap_run_once( coap_context_t *ctx, unsigned int timeout_ms ); +/** + * The main message processing loop with additional fds for internal select. + * + * @param ctx The CoAP context + * @param timeout_ms Minimum number of milliseconds to wait for new packets + * before returning. If COAP_RUN_BLOCK, the call will block + * until at least one new packet is received. If + * COAP_RUN_NONBLOCK, the function will return immediately + * following without waiting for any new input not already + * available. + * @param nfds The maximum FD set in readfds, writefds or exceptfds + * plus one, + * @param readfds Read FDs to additionally check for in internal select() + * or NULL if not required. + * @param writefds Write FDs to additionally check for in internal select() + * or NULL if not required. + * @param exceptfds Except FDs to additionally check for in internal select() + * or NULL if not required. + * + * + * @return Number of milliseconds spent in coap_io_process_with_fds, or @c -1 + * if there was an error. If defined, readfds, writefds, exceptfds + * are updated as returned by the internal select() call. + */ +int coap_io_process_with_fds(coap_context_t *ctx, unsigned int timeout_ms, + int nfds, fd_set *readfds, fd_set *writefds, + fd_set *exceptfds); + /** * Any now timed out delayed packet is transmitted, along with any packets * associated with requested observable response. @@ -610,6 +637,7 @@ unsigned int coap_io_prepare_epoll(coap_context_t *ctx, coap_tick_t now); struct epoll_event; + /** * Process all the epoll events * diff --git a/libcoap-2.map b/libcoap-2.map index 07b8e986..d90f0b6a 100644 --- a/libcoap-2.map +++ b/libcoap-2.map @@ -78,6 +78,7 @@ global: coap_insert_node; coap_insert_optlist; coap_io_prepare_epoll; + coap_io_process_with_fds; coap_is_mcast; coap_join_mcast_group; coap_log_impl; diff --git a/libcoap-2.sym b/libcoap-2.sym index e593b219..7b3d2ae6 100644 --- a/libcoap-2.sym +++ b/libcoap-2.sym @@ -76,6 +76,7 @@ coap_hash_impl coap_insert_node coap_insert_optlist coap_io_prepare_epoll +coap_io_process_with_fds coap_is_mcast coap_join_mcast_group coap_log_impl diff --git a/man/coap_io.txt.in b/man/coap_io.txt.in index 23315a61..825bbb2d 100644 --- a/man/coap_io.txt.in +++ b/man/coap_io.txt.in @@ -10,7 +10,7 @@ coap_io(3) NAME ---- -coap_io, coap_run_once, coap_context_get_coap_fd +coap_io, coap_run_once, coap_io_process_with_fds, coap_context_get_coap_fd - Work with CoAP I/O to do the packet send and receives SYNOPSIS @@ -19,6 +19,10 @@ SYNOPSIS *int coap_run_once(coap_context_t *_context_, unsigned int _timeout_ms_)*; +*int coap_io_process_with_fds(coap_context_t *_context_, +unsigned int _timeout_ms_, int _nfds_, fd_set *_readfds_, fd_set *_writefds_, +fd_set *_exceptfds_)*; + *int coap_context_get_coap_fd(coap_context_t *_context_)*; Link with *-lcoap-@LIBCOAP_API_VERSION@*, *-lcoap-@LIBCOAP_API_VERSION@-gnutls*, @@ -61,6 +65,21 @@ NOTE: This method is only available for environments that support epoll (mostly Linux) as libcoap will then be using epoll internally to process all the file descriptors of the different sessions. +The *coap_io_process_with_fds*() function is the same as *coap_run_once*() +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. + 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 @@ -69,8 +88,9 @@ internal to libcoap file descriptors (sockets) change state. RETURN VALUES ------------- -*coap_run_once*() returns the time, in milli-seconds, that was spent in the -function. If -1 is returned, there was an unexpected error. +*coap_run_once*() and *coap_io_process_with_fds*() returns the time, in +milli-seconds, that was spent in the function. If -1 is returned, there was +an unexpected error. *coap_context_get_coap_fd*() returns a non-negative number as the file descriptor to monitor, or -1 if epoll is not supported by the host @@ -78,7 +98,7 @@ environment. EXAMPLES -------- -*Method One* +*Method One - coap_run_once* [source, c] ---- @@ -116,6 +136,51 @@ int main(int argc, char *argv[]){ } ---- +*Method One - coap_io_process_with_fds* + +[source, c] +---- +#include + +int main(int argc, char *argv[]){ + + coap_context_t *ctx = NULL; + unsigned wait_ms; + fd_set readfds; + int nfds = 0; + + /* Create the libcoap context */ + ctx = coap_new_context(NULL); + if (!ctx) { + exit(1); + } + + 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); + + /* Do any other cleanup */ + + exit(0); + +} +---- + *Method Two - select* [source, c] diff --git a/src/coap_io.c b/src/coap_io.c index 88ca5263..2c4627a2 100644 --- a/src/coap_io.c +++ b/src/coap_io.c @@ -1468,6 +1468,13 @@ coap_write(coap_context_t *ctx, int coap_run_once(coap_context_t *ctx, unsigned timeout_ms) { + return coap_io_process_with_fds(ctx, timeout_ms, 0, NULL, NULL, NULL); +} + +int +coap_io_process_with_fds(coap_context_t *ctx, unsigned int timeout_ms, + int enfds, fd_set *ereadfds, fd_set *ewritefds, + fd_set *eexceptfds) { #if COAP_CONSTRAINED_STACK static coap_mutex_t static_mutex = COAP_MUTEX_INITIALIZER; # ifndef COAP_EPOLL_SUPPORT @@ -1502,9 +1509,27 @@ coap_run_once(coap_context_t *ctx, unsigned timeout_ms) { if (timeout == 0 || timeout_ms < timeout) timeout = timeout_ms; - FD_ZERO(&readfds); - FD_ZERO(&writefds); - FD_ZERO(&exceptfds); + if (ereadfds) { + readfds = *ereadfds; + nfds = enfds; + } + else { + FD_ZERO(&readfds); + } + if (ewritefds) { + writefds = *ewritefds; + nfds = enfds; + } + else { + FD_ZERO(&writefds); + } + if (eexceptfds) { + exceptfds = *eexceptfds; + nfds = enfds; + } + else { + FD_ZERO(&exceptfds); + } for (i = 0; i < num_sockets; i++) { if (sockets[i]->fd + 1 > nfds) nfds = sockets[i]->fd + 1; @@ -1558,8 +1583,22 @@ coap_run_once(coap_context_t *ctx, unsigned timeout_ms) { coap_ticks(&now); coap_read(ctx, now); + if (ereadfds) { + *ereadfds = readfds; + } + if (ewritefds) { + *ewritefds = writefds; + } + if (eexceptfds) { + *eexceptfds = exceptfds; + } #else /* COAP_EPOLL_SUPPORT */ + (void)ereadfds; + (void)ewritefds; + (void)eexceptfds; + (void)enfds; + timeout = coap_io_prepare_epoll(ctx, before); if (timeout == 0 || timeout_ms < timeout)