diff --git a/include/coap2/net.h b/include/coap2/net.h index 025924fc..6b9ddbf5 100644 --- a/include/coap2/net.h +++ b/include/coap2/net.h @@ -594,9 +594,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. @@ -620,6 +647,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 d87feca3..bbb595cf 100644 --- a/libcoap-2.map +++ b/libcoap-2.map @@ -80,6 +80,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 84beb771..63da4b1b 100644 --- a/libcoap-2.sym +++ b/libcoap-2.sym @@ -78,6 +78,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)