From 9cf4f10b3584f9a7ff579565e98d7885bbb9b5a7 Mon Sep 17 00:00:00 2001 From: Jon Shallow Date: Thu, 31 Oct 2019 10:53:58 +0000 Subject: [PATCH] Rename coap_run_once() to coap_io_process() coap_read(), coap_write() and coap_run_once() are confusing in their names and do not really describe what they do. For example, coap_read() does both reading and writing, coap_write() may do some writing, but primarily is used to determine what should be monitored and for how long to wait in the following select() or epoll_wait() calls. coap_run_once() implies that the code is only to be run once - again confusing. By renaming coap_read() to coap_io_do_io(), this better describes what this function does. By renaming coap_write() to coap_io_prepare_io() this better describes what this function does. By renaming coap_run_once() to coap_io_process(), this better describes what this function does. By renaming coap_io_do_events() to coap_io_do_epoll(), this better describes what this function does and is associated with. A wrapper function coap_io_prepare_epoll() has been created, using coap_io_prepare_io() with some preset values to simplify function usage. include/coap2/net.h: Update with the new function names, and deprecate the old functions. Also document the fact that coap_io_prepare_io(), coap_io_do_io(), coap_io_prepare_epoll(), and coap_io_do_epoll() are really internal functions. Create app_io module for Doxygen. libcoap-2.map: libcoap-2.sym: Expose the new functions to applications. examples/client.c: examples/coap-rd.c: examples/coap-server.c: examples/contiki/coap-observer.c: examples/contiki/server.c: examples/etsi_iot_01.c: man/coap_io.txt.in: man/coap_observe.txt.in: src/coap_io.c: src/coap_io_lwip.c: src/net.c: src/pdu.c: Update using the new function names. Setting the etimer has been moved out of coap_io_process() into coap_io_do_epoll(), making the logic easier for applications to use coap_io_do_epoll() should they need to. This also gets rid of a potential timing window where a pending etimer event gets missed. coap_io_do_epoll() now calls coap_io_prepare_epoll() if the etimer has triggered removing the need for applications using coap_io_do_epoll() to set up their own loops if etimer is triggered. --- examples/client.c | 2 +- examples/coap-rd.c | 2 +- examples/coap-server.c | 6 +- examples/contiki/coap-observer.c | 2 +- examples/contiki/server.c | 2 +- examples/etsi_iot_01.c | 2 +- include/coap2/net.h | 347 ++++++++++++++++++++----------- libcoap-2.map | 7 +- libcoap-2.sym | 7 +- man/coap_io.txt.in | 144 ++++++++++--- man/coap_observe.txt.in | 6 +- src/coap_io.c | 32 +-- src/coap_io_lwip.c | 4 +- src/net.c | 12 +- src/pdu.c | 2 +- 15 files changed, 384 insertions(+), 193 deletions(-) diff --git a/examples/client.c b/examples/client.c index 847e12a5..2ce48de5 100644 --- a/examples/client.c +++ b/examples/client.c @@ -1740,7 +1740,7 @@ main(int argc, char **argv) { while (!quit && !(ready && !doing_getting_block && coap_can_exit(ctx)) ) { - result = coap_run_once( ctx, wait_ms == 0 ? + result = coap_io_process( ctx, wait_ms == 0 ? obs_ms : obs_ms == 0 ? min(wait_ms, 1000) : min( wait_ms, obs_ms ) ); diff --git a/examples/coap-rd.c b/examples/coap-rd.c index b4aaaa95..174616cb 100644 --- a/examples/coap-rd.c +++ b/examples/coap-rd.c @@ -859,7 +859,7 @@ main(int argc, char **argv) { #endif while ( !quit ) { - result = coap_run_once( ctx, COAP_RESOURCE_CHECK_TIME * 1000 ); + result = coap_io_process( ctx, COAP_RESOURCE_CHECK_TIME * 1000 ); if ( result >= 0 ) { /* coap_check_resource_list( ctx ); */ } diff --git a/examples/coap-server.c b/examples/coap-server.c index 5a6ab017..7ae162be 100644 --- a/examples/coap-server.c +++ b/examples/coap-server.c @@ -1453,13 +1453,13 @@ main(int argc, char **argv) { } if (result > 0) { if (FD_ISSET(coap_fd, &readfds)) { - result = coap_run_once(ctx, COAP_RUN_NONBLOCK); + result = coap_io_process(ctx, COAP_RUN_NONBLOCK); } } } else { /* epoll is not supported within libcoap */ - result = coap_run_once( ctx, wait_ms ); + result = coap_io_process(ctx, wait_ms); } if ( result < 0 ) { break; @@ -1470,7 +1470,7 @@ main(int argc, char **argv) { /* * result == 0, or result >= wait_ms * (wait_ms could have decremented to a small value, below - * the granularity of the timer in coap_run_once() and hence + * the granularity of the timer in coap_io_process() and hence * result == 0) */ time_t t_now = time(NULL); diff --git a/examples/contiki/coap-observer.c b/examples/contiki/coap-observer.c index 776c6bb5..8b7810ef 100644 --- a/examples/contiki/coap-observer.c +++ b/examples/contiki/coap-observer.c @@ -176,7 +176,7 @@ PROCESS_THREAD(coap_server_process, ev, data) while(1) { PROCESS_YIELD(); if(ev == tcpip_event) { - coap_read(coap_context); /* read received data */ + coap_io_do_io(coap_context); /* read received data */ coap_dispatch(coap_context); /* and dispatch PDUs from receivequeue */ } } diff --git a/examples/contiki/server.c b/examples/contiki/server.c index ae8f3450..efdfe6db 100644 --- a/examples/contiki/server.c +++ b/examples/contiki/server.c @@ -216,7 +216,7 @@ PROCESS_THREAD(coap_server_process, ev, data) PROCESS_YIELD(); if(ev == tcpip_event) { /* There is something to read on the endpoint */ - coap_run_once(coap_context, COAP_RUN_BLOCK); + coap_io_process(coap_context, COAP_RUN_BLOCK); } else if (ev == PROCESS_EVENT_TIMER && etimer_expired(&dirty_timer)) { coap_resource_notify_observers(time_resource, NULL); etimer_reset(&dirty_timer); diff --git a/examples/etsi_iot_01.c b/examples/etsi_iot_01.c index 51869a3c..c33e110b 100644 --- a/examples/etsi_iot_01.c +++ b/examples/etsi_iot_01.c @@ -667,7 +667,7 @@ main(int argc, char **argv) { sigaction (SIGPIPE, &sa, NULL); while ( !quit ) { - result = coap_run_once( ctx, COAP_RESOURCE_CHECK_TIME * 1000 ); + result = coap_io_process( ctx, COAP_RESOURCE_CHECK_TIME * 1000 ); if ( result >= 0 ) { /* coap_check_resource_list( ctx ); */ } diff --git a/include/coap2/net.h b/include/coap2/net.h index 6b9ddbf5..a848b3ad 100644 --- a/include/coap2/net.h +++ b/include/coap2/net.h @@ -541,126 +541,6 @@ coap_tid_t coap_send( coap_session_t *session, coap_pdu_t *pdu ); */ coap_tid_t coap_retransmit(coap_context_t *context, coap_queue_t *node); -/** -* For applications with their own message loop, send all pending retransmits and -* return the list of sockets with events to wait for and the next timeout -* The application should call coap_read, then coap_write again when any condition below is true: -* - data is available on any of the sockets with the COAP_SOCKET_WANT_READ -* - an incoming connection is pending in the listen queue and the COAP_SOCKET_WANT_ACCEPT flag is set -* - at least some data can be written without blocking on any of the sockets with the COAP_SOCKET_WANT_WRITE flag set -* - a connection event occured (success or failure) and the COAP_SOCKET_WANT_CONNECT flag is set -* - the timeout has expired -* Before calling coap_read or coap_write again, the application should position COAP_SOCKET_CAN_READ and COAP_SOCKET_CAN_WRITE flags as applicable. -* -* @param ctx The CoAP context -* @param sockets array of socket descriptors, filled on output -* @param max_sockets size of socket array. -* @param num_sockets pointer to the number of valid entries in the socket arrays on output -* @param now Current time. -* -* @return timeout as maxmimum number of milliseconds that the application should wait for network events or 0 if the application should wait forever. -*/ - -unsigned int -coap_write(coap_context_t *ctx, - coap_socket_t *sockets[], - unsigned int max_sockets, - unsigned int *num_sockets, - coap_tick_t now -); - -/** - * For applications with their own message loop, reads all data from the network. - * - * @param ctx The CoAP context - * @param now Current time - */ -void coap_read(coap_context_t *ctx, coap_tick_t now); - -#define COAP_RUN_BLOCK 0 -#define COAP_RUN_NONBLOCK 1 - -/** - * The main message processing loop. - * - * @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. - * - * @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. - * - * In addition, it returns when the next expected I/O is expected to take place - * (e.g. a packet retransmit). - * - * Note: If epoll support is compiled into libcoap, coap_io_prepare_epoll() must - * be used instead of coap_write(). - * - * Internal function. - * - * @param ctx The CoAP context - * @param now Current time. - * - * @return timeout Maxmimum number of milliseconds that can be used by a - * epoll_wait() to wait for network events or 0 if wait should be - * forever. - */ -unsigned int -coap_io_prepare_epoll(coap_context_t *ctx, coap_tick_t now); - -struct epoll_event; - -/** - * Process all the epoll events - * - * Internal function - * - * @param ctx The current CoAP context. - * @param events The list of events returned from an epoll_wait() call. - * @param nevents The number of events. - * - */ -void coap_io_do_events(coap_context_t *ctx, struct epoll_event* events, - size_t nevents); - /** * Parses and interprets a CoAP datagram with context @p ctx. This function * returns @c 0 if the datagram was handled, or a value less than zero on @@ -844,4 +724,231 @@ unsigned int coap_calc_timeout(coap_session_t *session, unsigned char r); int coap_join_mcast_group(coap_context_t *ctx, const char *groupname); +/** + * @defgroup app_io Application I/O Handling + * API functions for Application Input / Output + * @{ + */ + +#define COAP_RUN_BLOCK 0 +#define COAP_RUN_NONBLOCK 1 + +/** + * The main I/O processing function. All pending network I/O is completed, + * and then optionally waits for the next input packet. + * + * This internally calls coap_io_prepare_io(), then select() for the appropriate + * sockets, updates COAP_SOCKET_CAN_xxx where appropriate and then calls + * coap_io_do_io() before returning with the time spent in the function. + * + * Alternatively, if libcoap is compiled with epoll support, this internally + * calls coap_io_prepare_epoll(), then epoll_wait() for waiting for any file + * descriptors that have (internally) been set up with epoll_ctl() and + * finally coap_io_do_epoll() before returning with the time spent in the + * function. + * + * @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. + * + * @return Number of milliseconds spent in function or @c -1 if there was + * an error + */ +int coap_io_process(coap_context_t *ctx, unsigned int timeout_ms); + +/** + * @deprecated Use coap_io_process() instead. + * + * This function just calls coap_io_process(). + * + * @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. + * + * @return Number of milliseconds spent in function or @c -1 if there was + * an error + */ +COAP_STATIC_INLINE COAP_DEPRECATED int +coap_run_once(coap_context_t *ctx, unsigned int timeout_ms) +{ + return coap_io_process(ctx, 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 + * after processing any existing input packets. + * @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); + +/** +* Iterates through all the coap_socket_t structures embedded in endpoints or +* sessions associated with the @p ctx to determine which are wanting any +* read, write, accept or connect I/O (COAP_SOCKET_WANT_xxx is set). If set, +* the coap_socket_t is added to the @p sockets. +* +* Any now timed out delayed packet is transmitted, along with any packets +* associated with requested observable response. +* +* In addition, it returns when the next expected I/O is expected to take place +* (e.g. a packet retransmit). +* +* Prior to calling coap_io_do_io(), the @p sockets must be tested to see +* if any of the COAP_SOCKET_WANT_xxx have the appropriate information and if +* so, COAP_SOCKET_CAN_xxx is set. This typically will be done after using a +* select() call. +* +* Note: If epoll support is compiled into libcoap, coap_io_prepare_epoll() must +* be used instead of coap_io_prepare_io(). +* +* Internal function. +* +* @param ctx The CoAP context +* @param sockets Array of socket descriptors, filled on output +* @param max_sockets Size of socket array. +* @param num_sockets Pointer to the number of valid entries in the socket +* arrays on output. +* @param now Current time. +* +* @return timeout Maxmimum number of milliseconds that can be used by a +* select() to wait for network events or 0 if wait should be +* forever. +*/ +unsigned int +coap_io_prepare_io(coap_context_t *ctx, + coap_socket_t *sockets[], + unsigned int max_sockets, + unsigned int *num_sockets, + coap_tick_t now +); + +/** +* @deprecated Use coap_io_prepare_io() instead. +* +* This function just calls coap_io_prepare_io(). +* +* Internal function. +* +* @param ctx The CoAP context +* @param sockets Array of socket descriptors, filled on output +* @param max_sockets Size of socket array. +* @param num_sockets Pointer to the number of valid entries in the socket +* arrays on output. +* @param now Current time. +* +* @return timeout Maxmimum number of milliseconds that can be used by a +* select() to wait for network events or 0 if wait should be +* forever. +*/ +COAP_STATIC_INLINE COAP_DEPRECATED unsigned int +coap_write(coap_context_t *ctx, + coap_socket_t *sockets[], + unsigned int max_sockets, + unsigned int *num_sockets, + coap_tick_t now +) { + return coap_io_prepare_io(ctx, sockets, max_sockets, num_sockets, now); +} + +/** + * Processes any outstanding read, write, accept or connect I/O as indicated + * in the coap_socket_t structures (COAP_SOCKET_CAN_xxx set) embedded in + * endpoints or sessions associated with @p ctx. + * + * Note: If epoll support is compiled into libcoap, coap_io_do_epoll() must + * be used instead of coap_io_do_io(). + * + * Internal function. + * + * @param ctx The CoAP context + * @param now Current time + */ +void coap_io_do_io(coap_context_t *ctx, coap_tick_t now); + +/** + * @deprecated Use coap_io_do_io() instead. + * + * This function just calls coap_io_do_io(). + * + * Internal function. + * + * @param ctx The CoAP context + * @param now Current time + */ +COAP_STATIC_INLINE COAP_DEPRECATED void +coap_read(coap_context_t *ctx, coap_tick_t now +) { + coap_io_do_io(ctx, now); +} + +/** + * Any now timed out delayed packet is transmitted, along with any packets + * associated with requested observable response. + * + * In addition, it returns when the next expected I/O is expected to take place + * (e.g. a packet retransmit). + * + * Note: If epoll support is compiled into libcoap, coap_io_prepare_epoll() must + * be used instead of coap_io_prepare_io(). + * + * Internal function. + * + * @param ctx The CoAP context + * @param now Current time. + * + * @return timeout Maxmimum number of milliseconds that can be used by a + * epoll_wait() to wait for network events or 0 if wait should be + * forever. + */ +unsigned int +coap_io_prepare_epoll(coap_context_t *ctx, coap_tick_t now); + +struct epoll_event; + +/** + * Process all the epoll events + * + * Note: If epoll support is compiled into libcoap, coap_io_do_epoll() must + * be used instead of coap_io_do_io(). + * + * Internal function + * + * @param ctx The current CoAP context. + * @param events The list of events returned from an epoll_wait() call. + * @param nevents The number of events. + * + */ +void coap_io_do_epoll(coap_context_t *ctx, struct epoll_event* events, + size_t nevents); + +/**@}*/ + #endif /* COAP_NET_H_ */ diff --git a/libcoap-2.map b/libcoap-2.map index 7755d479..ed173694 100644 --- a/libcoap-2.map +++ b/libcoap-2.map @@ -79,7 +79,11 @@ global: coap_hash_impl; coap_insert_node; coap_insert_optlist; + coap_io_do_epoll; + coap_io_do_io; coap_io_prepare_epoll; + coap_io_prepare_io; + coap_io_process; coap_io_process_with_fds; coap_is_mcast; coap_join_mcast_group; @@ -137,7 +141,6 @@ global: coap_print_addr; coap_print_link; coap_print_wellknown; - coap_read; coap_register_async; coap_register_event_handler; coap_register_handler; @@ -149,7 +152,6 @@ global: coap_resource_unknown_init; coap_response_phrase; coap_retransmit; - coap_run_once; coap_send; coap_send_ack; coap_send_error; @@ -199,7 +201,6 @@ global: coap_touch_observer; coap_wait_ack; coap_wellknown_response; - coap_write; coap_write_block_opt; local: *; diff --git a/libcoap-2.sym b/libcoap-2.sym index 06d9e0b7..51df132c 100644 --- a/libcoap-2.sym +++ b/libcoap-2.sym @@ -77,7 +77,11 @@ coap_handle_failed_notify coap_hash_impl coap_insert_node coap_insert_optlist +coap_io_do_epoll +coap_io_do_io coap_io_prepare_epoll +coap_io_prepare_io +coap_io_process coap_io_process_with_fds coap_is_mcast coap_join_mcast_group @@ -135,7 +139,6 @@ coap_pop_next coap_print_addr coap_print_link coap_print_wellknown -coap_read coap_register_async coap_register_event_handler coap_register_handler @@ -147,7 +150,6 @@ coap_resource_set_dirty coap_resource_unknown_init coap_response_phrase coap_retransmit -coap_run_once coap_send coap_send_ack coap_send_error @@ -197,5 +199,4 @@ coap_tls_is_supported coap_touch_observer coap_wait_ack coap_wellknown_response -coap_write coap_write_block_opt diff --git a/man/coap_io.txt.in b/man/coap_io.txt.in index 825bbb2d..71268802 100644 --- a/man/coap_io.txt.in +++ b/man/coap_io.txt.in @@ -10,14 +10,15 @@ coap_io(3) NAME ---- -coap_io, coap_run_once, coap_io_process_with_fds, coap_context_get_coap_fd +coap_io, coap_io_process, coap_io_process_with_fds, coap_context_get_coap_fd, +coap_io_prepare_io, coap_io_do_io, coap_io_prepare_epoll, coap_io_do_epoll - Work with CoAP I/O to do the packet send and receives SYNOPSIS -------- *#include * -*int coap_run_once(coap_context_t *_context_, unsigned int _timeout_ms_)*; +*int coap_io_process(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_, @@ -25,6 +26,18 @@ fd_set *_exceptfds_)*; *int coap_context_get_coap_fd(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_)*; + +*int coap_io_do_epoll(coap_context_t *_context_, struct epoll_event *_events_, +size_t _nevents_)* + Link with *-lcoap-@LIBCOAP_API_VERSION@*, *-lcoap-@LIBCOAP_API_VERSION@-gnutls*, *-lcoap-@LIBCOAP_API_VERSION@-openssl* or *-lcoap-@LIBCOAP_API_VERSION@-tinydtls* depending on your (D)TLS library @@ -36,39 +49,92 @@ 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_run_once*() function will process any outstanding packets to send -for the specified _context_ and wait for processing any input packets for up to -_timeout_ms_ milli-seconds before returning. Once any outstanding input packets -have been processed, the function will return. There are 2 special case +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. [source, c] ---- #define COAP_RUN_BLOCK 0 #define COAP_RUN_NONBLOCK 1 ---- -If _timeout_ms_ is set to COAP_RUN_BLOCK, then *coap_run_once*() will wait -indefinitely for the first new input packet to come in. If _timeout_ms_ is set -to COAP_RUN_NONBLOCK, then there is no wait if there are no more input packets. +If _timeout_ms_ is set to COAP_RUN_BLOCK, then *coap_io_process*() will wait +indefinitely for the first new input packet to come in, or for when to +re-transmit a packet. If _timeout_ms_ is set to COAP_RUN_NONBLOCK, then there +is no wait if there is no more input or output to process. -There are two methods of how to call *coap_run_once*(). +There are two methods of how to call *coap_io_process*(). -1. Have *coap_run_once*() called from within a while() loop. Under idle -conditions (no input traffic) *coap_run_once*() will then get called every -_timeout_ms_, but more frequently if there is input traffic. +1. 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. 2. Wait on the file descriptor returned by *coap_context_get_coap_fd*() -using select() or an event returned by epoll_wait(). If 'read' is available on -the file descriptor, call *coap_run_once*() with _timeout_ms_ set to -COAP_RUN_NONBLOCK. See EXAMPLES below. +using *select*() or an event returned by epoll_wait(). If 'read' is available on +the file descriptor, call *coap_io_process*() with _timeout_ms_ set to +COAP_RUN_NONBLOCK. + +*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. -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. +See EXAMPLES below. -The *coap_io_process_with_fds*() function is the same as *coap_run_once*() +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. + +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. + +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. + +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_. + +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. + +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 +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 @@ -81,24 +147,26 @@ if there is no epoll support in libcoap. If there is epoll support, then 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 +_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. RETURN VALUES ------------- -*coap_run_once*() and *coap_io_process_with_fds*() returns the time, in +*coap_io_process*() 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 -environment. +descriptor to monitor, or -1 if epoll is not configured in libcoap. + +*coap_io_prepare_io*() and *coap_io_prepare_epoll*() returns the number of +milli-seconds that need to be waited before the function should next be called. EXAMPLES -------- -*Method One - coap_run_once* +*Method One - use coap_io_process()* [source, c] ---- @@ -109,6 +177,9 @@ int main(int argc, char *argv[]){ coap_context_t *ctx = NULL; unsigned wait_ms; + (void)argc; + (void)argv; + /* Create the libcoap context */ ctx = coap_new_context(NULL); if (!ctx) { @@ -120,7 +191,7 @@ int main(int argc, char *argv[]){ wait_ms = COAP_RESOURCE_CHECK_TIME * 1000; while (1) { - int result = coap_run_once(ctx, wait_ms); + int result = coap_io_process(ctx, wait_ms); if (result < 0) { /* There is an internal issue */ break; @@ -149,6 +220,9 @@ int main(int argc, char *argv[]){ fd_set readfds; int nfds = 0; + (void)argc; + (void)argv; + /* Create the libcoap context */ ctx = coap_new_context(NULL); if (!ctx) { @@ -181,7 +255,7 @@ int main(int argc, char *argv[]){ } ---- -*Method Two - select* +*Method Two - select() based on monitorable file descriptor* [source, c] ---- @@ -196,6 +270,9 @@ int main(int argc, char *argv[]){ fd_set m_readfds; int nfds; + (void)argc; + (void)argv; + /* Create the libcoap context */ ctx = coap_new_context(NULL); if (!ctx) { @@ -224,7 +301,7 @@ int main(int argc, char *argv[]){ } if (result > 0) { if (FD_ISSET(coap_fd, &readfds)) { - result = coap_run_once(ctx, COAP_RUN_NONBLOCK); + result = coap_io_process(ctx, COAP_RUN_NONBLOCK); if (result < 0) { /* There is an internal issue */ break; @@ -242,7 +319,7 @@ int main(int argc, char *argv[]){ } ---- -*Method Two - epoll* +*Method Two - epoll_wait() based on monitorable file descriptor* [source, c] ---- @@ -264,6 +341,9 @@ int main(int argc, char *argv[]){ int nevents; int i; + (void)argc; + (void)argv; + /* Create the libcoap context */ ctx = coap_new_context(NULL); if (!ctx) { @@ -297,7 +377,7 @@ int main(int argc, char *argv[]){ } for (i = 0; i < nevents; i++) { if (events[i].data.fd == coap_fd) { - result = coap_run_once(ctx, COAP_RUN_NONBLOCK); + result = coap_io_process(ctx, COAP_RUN_NONBLOCK); if (result < 0) { /* There is an internal issue */ break; diff --git a/man/coap_observe.txt.in b/man/coap_observe.txt.in index 713c29bd..34ee223d 100644 --- a/man/coap_observe.txt.in +++ b/man/coap_observe.txt.in @@ -70,7 +70,7 @@ appropriate GET handler within the server application is called to fill in the response packet with the appropriate information. This "fake GET request" is triggered by a call to *coap_resource_notify_observers*(). -The call to *coap_run_once*() in the main server application i/o loop will do +The call to *coap_io_process*() in the main server application i/o loop will do all the necessary processing of sending any outstanding "fake GET requests". Whenever the server sends a copy of the state of the "observed" resource to @@ -286,7 +286,7 @@ int main(int argc, char *argv[]){ wait_ms = COAP_RESOURCE_CHECK_TIME * 1000; while (1) { - int result = coap_run_once( ctx, wait_ms ); + int result = coap_io_process( ctx, wait_ms ); if ( result < 0 ) { break; } else if ( result && (unsigned)result < wait_ms ) { @@ -296,7 +296,7 @@ int main(int argc, char *argv[]){ /* * result == 0, or result >= wait_ms * (wait_ms could have decremented to a small value, below - * the granularity of the timer in coap_run_once() and hence + * the granularity of the timer in coap_io_process() and hence * result == 0) */ time_t t_now = time(NULL); diff --git a/src/coap_io.c b/src/coap_io.c index a3f6cfd4..c1ca5dd6 100644 --- a/src/coap_io.c +++ b/src/coap_io.c @@ -945,6 +945,8 @@ error: return -1; } +#if !defined(WITH_CONTIKI) + unsigned int coap_io_prepare_epoll(coap_context_t *ctx, coap_tick_t now) { #ifndef COAP_EPOLL_SUPPORT @@ -960,7 +962,7 @@ coap_io_prepare_epoll(coap_context_t *ctx, coap_tick_t now) { unsigned int timeout; /* Use the common logic */ - timeout = coap_write(ctx, sockets, max_sockets, &num_sockets, now); + timeout = coap_io_prepare_io(ctx, sockets, max_sockets, &num_sockets, now); /* Save when the next expected I/O is to take place */ ctx->next_timeout = timeout ? now + timeout : 0; if (ctx->eptimerfd != -1) { @@ -989,10 +991,8 @@ coap_io_prepare_epoll(coap_context_t *ctx, coap_tick_t now) { #endif /* COAP_EPOLL_SUPPORT */ } -#if !defined(WITH_CONTIKI) - unsigned int -coap_write(coap_context_t *ctx, +coap_io_prepare_io(coap_context_t *ctx, coap_socket_t *sockets[], unsigned int max_sockets, unsigned int *num_sockets, @@ -1174,7 +1174,7 @@ coap_write(coap_context_t *ctx, } int -coap_run_once(coap_context_t *ctx, unsigned timeout_ms) { +coap_io_process(coap_context_t *ctx, unsigned timeout_ms) { return coap_io_process_with_fds(ctx, timeout_ms, 0, NULL, NULL, NULL); } @@ -1212,7 +1212,9 @@ coap_io_process_with_fds(coap_context_t *ctx, unsigned int timeout_ms, coap_ticks(&before); #ifndef COAP_EPOLL_SUPPORT - timeout = coap_write(ctx, sockets, (unsigned int)(sizeof(sockets) / sizeof(sockets[0])), &num_sockets, before); + timeout = coap_io_prepare_io(ctx, sockets, + (sizeof(sockets) / sizeof(sockets[0])), + &num_sockets, before); if (timeout == 0 || timeout_ms < timeout) timeout = timeout_ms; @@ -1293,7 +1295,7 @@ coap_io_process_with_fds(coap_context_t *ctx, unsigned int timeout_ms, } coap_ticks(&now); - coap_read(ctx, now); + coap_io_do_io(ctx, now); if (ereadfds) { *ereadfds = readfds; } @@ -1334,7 +1336,7 @@ coap_io_process_with_fds(coap_context_t *ctx, unsigned int timeout_ms, break; } - coap_io_do_events(ctx, events, nfds); + coap_io_do_epoll(ctx, events, nfds); /* * reset to COAP_RUN_NONBLOCK (which causes etimeout to become 0) @@ -1357,23 +1359,23 @@ coap_io_process_with_fds(coap_context_t *ctx, unsigned int timeout_ms, } #else /* WITH_CONTIKI */ -int coap_run_once(coap_context_t *ctx, unsigned int timeout_ms) { +int coap_io_process(coap_context_t *ctx, unsigned int timeout_ms) { coap_tick_t now; coap_ticks(&now); /* There is something to read on the endpoint */ ctx->endpoint->sock.flags |= COAP_SOCKET_CAN_READ; /* read in, and send off any responses */ - coap_read(ctx, now); /* read received data */ + coap_io_do_io(ctx, now); /* read received data */ return -1; } unsigned int -coap_write(coap_context_t *ctx, - coap_socket_t *sockets[], - unsigned int max_sockets, - unsigned int *num_sockets, - coap_tick_t now) +coap_io_prepare(coap_context_t *ctx, + coap_socket_t *sockets[], + unsigned int max_sockets, + unsigned int *num_sockets, + coap_tick_t now) { *num_sockets = 0; return 0; diff --git a/src/coap_io_lwip.c b/src/coap_io_lwip.c index 501c405d..dcdbdafb 100644 --- a/src/coap_io_lwip.c +++ b/src/coap_io_lwip.c @@ -48,9 +48,9 @@ struct pbuf *coap_packet_extract_pbuf(coap_packet_t *packet) * * The current implementation deals this to coap_dispatch immediately, but * other mechanisms (as storing the package in a queue and later fetching it - * when coap_read is called) can be envisioned. + * when coap_io_do_io is called) can be envisioned. * - * It handles everything coap_read does on other implementations. + * It handles everything coap_io_do_io does on other implementations. */ static void coap_recv(void *arg, struct udp_pcb *upcb, struct pbuf *p, const ip_addr_t *addr, u16_t port) { diff --git a/src/net.c b/src/net.c index 4e2e7a55..4543e45e 100644 --- a/src/net.c +++ b/src/net.c @@ -1125,7 +1125,7 @@ coap_retransmit(coap_context_t *context, coap_queue_t *node) { #ifdef WITH_LWIP /* WITH_LWIP, this is handled by coap_recv in a different way */ void -coap_read(coap_context_t *ctx, coap_tick_t now) { +coap_io_do_io(coap_context_t *ctx, coap_tick_t now) { return; } #else /* WITH_LWIP */ @@ -1419,12 +1419,12 @@ coap_accept_endpoint(coap_context_t *ctx, coap_endpoint_t *endpoint, } void -coap_read(coap_context_t *ctx, coap_tick_t now) { +coap_io_do_io(coap_context_t *ctx, coap_tick_t now) { #ifdef COAP_EPOLL_SUPPORT (void)ctx; (void)now; coap_log(LOG_EMERG, - "coap_read() requires libcoap not compiled for using epoll\n"); + "coap_io_do_io() requires libcoap not compiled for using epoll\n"); #else /* ! COAP_EPOLL_SUPPORT */ coap_endpoint_t *ep, *tmp; coap_session_t *s, *rtmp; @@ -1476,17 +1476,17 @@ coap_read(coap_context_t *ctx, coap_tick_t now) { } /* - * While this code in part replicates coap_read(), doing the functions + * While this code in part replicates coap_io_do_io(), doing the functions * directly saves having to iterate through the endpoints / sessions. */ void -coap_io_do_events(coap_context_t *ctx, struct epoll_event *events, size_t nevents) { +coap_io_do_epoll(coap_context_t *ctx, struct epoll_event *events, size_t nevents) { #ifndef COAP_EPOLL_SUPPORT (void)ctx; (void)events; (void)nevents; coap_log(LOG_EMERG, - "coap_io_do_events() requires libcoap compiled for using epoll\n"); + "coap_io_do_epoll() requires libcoap compiled for using epoll\n"); #else /* COAP_EPOLL_SUPPORT */ coap_tick_t now; size_t j; diff --git a/src/pdu.c b/src/pdu.c index 7515c1c2..4fe88352 100644 --- a/src/pdu.c +++ b/src/pdu.c @@ -57,7 +57,7 @@ coap_pdu_from_pbuf( struct pbuf *pbuf ) if (pbuf == NULL) return NULL; LWIP_ASSERT("Can only deal with contiguous PBUFs", pbuf->tot_len == pbuf->len); - LWIP_ASSERT("coap_read needs to receive an exclusive copy of the incoming pbuf", pbuf->ref == 1); + LWIP_ASSERT("coap_io_do_io needs to receive an exclusive copy of the incoming pbuf", pbuf->ref == 1); pdu = coap_malloc_type(COAP_PDU, sizeof(coap_pdu_t) ); if (!pdu) {