Skip to content

Commit

Permalink
coap_io.c: Add in support for getting state of internal file descriptors
Browse files Browse the repository at this point in the history
Add in a new function coap_io_get_fds() to get the lists of (internal
to libcoap) file descriptors that are in a read or write pending state,
as well as the timeout time for the next internal to libcoap activity
(e.g. packet retransmission).
  • Loading branch information
mrdeep1 committed Dec 16, 2024
1 parent ebb8f07 commit 8361f8c
Show file tree
Hide file tree
Showing 8 changed files with 233 additions and 6 deletions.
22 changes: 22 additions & 0 deletions include/coap3/coap_net.h
Original file line number Diff line number Diff line change
Expand Up @@ -845,6 +845,28 @@ COAP_API void coap_io_do_epoll(coap_context_t *ctx, struct epoll_event *events,
*/
COAP_API coap_fd_t coap_socket_get_fd(coap_socket_t *socket);

/*
* Get the current libcoap usage of file descriptors that are in a read or write pending state.
*
* @param context The current CoAP context.
* @param read_fds Array to populate with file descriptors in the read pending state.
* @param have_read_fds Updated wth the number of fds found in read pending state.
* @param max_read_fds Maximum size of read_fds[] array.
* @param write_fds Array to populate with file descriptors in the write pending state.
* @param have_write_fds Updated wth the number of fds found in write pending state.
* @param max_write_fds Maximum size of write_fds[] array.
* @param rem_timeout_ms Remaining timeout time to next libcoap activity in milli-secs.
*
* @return @c 1 if successful, else @c 0 if error.
*/
COAP_API unsigned int coap_io_get_fds(coap_context_t *context, coap_fd_t read_fds[],
unsigned int *have_read_fds,
unsigned int max_read_fds,
coap_fd_t write_fds[],
unsigned int *have_write_fds,
unsigned int max_write_fds,
unsigned int *rem_timeout_ms);

/**
* Get the libcoap internal flags for a socket. This can be used to
* integrate libcoap in an external event loop instead of using one of its
Expand Down
26 changes: 25 additions & 1 deletion include/coap3/coap_net_internal.h
Original file line number Diff line number Diff line change
Expand Up @@ -173,10 +173,10 @@ struct coap_context_t {
#endif /* COAP_SERVER_SUPPORT */
void *app; /**< application-specific data */
uint32_t max_token_size; /**< Largest token size supported RFC8974 */
coap_tick_t next_timeout; /**< When the next timeout is to occur */
#ifdef COAP_EPOLL_SUPPORT
int epfd; /**< External FD for epoll */
int eptimerfd; /**< Internal FD for timeout */
coap_tick_t next_timeout; /**< When the next timeout is to occur */
#else /* ! COAP_EPOLL_SUPPORT */
#if !defined(RIOT_VERSION) && !defined(WITH_CONTIKI)
fd_set readfds, writefds, exceptfds; /**< Used for select call
Expand Down Expand Up @@ -779,6 +779,30 @@ int coap_io_process_with_fds_lkd(coap_context_t *ctx, uint32_t timeout_ms,
fd_set *exceptfds);
#endif /* ! RIOT_VERSION && ! WITH_CONTIKI */

/*
* Get the current libcoap usage of file descriptors that are in a read or write pending state.
*
* Note: This function must be called in the locked state.
*
* @param context The current CoAP context.
* @param read_fds Array to populate with file descriptors in the read pending state.
* @param have_read_fds Updated wth the number of fds found in read pending state.
* @param max_read_fds Maximum size of read_fds[] array.
* @param write_fds Array to populate with file descriptors in the write pending state.
* @param have_write_fds Updated wth the number of fds found in write pending state.
* @param max_write_fds Maximum size of write_fds[] array.
* @param rem_timeout_ms Remaining timeout time to next libcoap activity in milli-secs.
*
* @return @c 1 if successful, else @c 0 if error.
*/
unsigned int coap_io_get_fds_lkd(coap_context_t *context, coap_fd_t read_fds[],
unsigned int *have_read_fds,
unsigned int max_read_fds,
coap_fd_t write_fds[],
unsigned int *have_write_fds,
unsigned int max_write_fds,
unsigned int *rem_timeout_ms);

/**
* Sends a CoAP message to given peer. The memory that is
* allocated for the pdu will be released by coap_send_lkd().
Expand Down
1 change: 1 addition & 0 deletions libcoap-3.map
Original file line number Diff line number Diff line change
Expand Up @@ -123,6 +123,7 @@ global:
coap_insert_optlist;
coap_io_do_epoll;
coap_io_do_io;
coap_io_get_fds;
coap_io_pending;
coap_io_prepare_epoll;
coap_io_prepare_io;
Expand Down
1 change: 1 addition & 0 deletions libcoap-3.sym
Original file line number Diff line number Diff line change
Expand Up @@ -121,6 +121,7 @@ coap_host_is_unix_domain
coap_insert_optlist
coap_io_do_epoll
coap_io_do_io
coap_io_get_fds
coap_io_pending
coap_io_prepare_epoll
coap_io_prepare_io
Expand Down
1 change: 1 addition & 0 deletions man/Makefile.am
Original file line number Diff line number Diff line change
Expand Up @@ -135,6 +135,7 @@ install-man: install-man3 install-man5 install-man7
@echo ".so man3/coap_deprecated.3" > coap_set_event_handler.3
@echo ".so man3/coap_deprecated.3" > coap_write.3
@echo ".so man3/coap_io.3" > coap_io_pending.3
@echo ".so man3/coap_io.3" > coap_io_get_fds.3
@echo ".so man3/coap_io.3" > coap_can_exit.3
@echo ".so man3/coap_io.3" > coap_socket_get_fd.3
@echo ".so man3/coap_io.3" > coap_socket_get_flags.3
Expand Down
28 changes: 27 additions & 1 deletion man/coap_io.txt.in
Original file line number Diff line number Diff line change
Expand Up @@ -19,6 +19,7 @@ coap_io_do_io,
coap_io_prepare_epoll,
coap_io_do_epoll,
coap_io_pending,
coap_io_get_fds,
coap_can_exit,
coap_socket_get_fd,
coap_socket_get_flags,
Expand Down Expand Up @@ -51,6 +52,11 @@ size_t _nevents_)*;

*int coap_io_pending(coap_context_t *_context_)*;

*unsigned int coap_io_get_fds(coap_context_t *_context_, coap_fd_t _read_fds_[],
unsigned int *_have_read_fds_, unsigned int _max_read_fds_, coap_fd_t _write_fds_[],
unsigned int *_have_write_fds_, unsigned int _max_write_dfs_,
unsigned int *rem_timeout_ms)*;

*int coap_can_exit(coap_context_t *_context_)*;

*coap_fd_t coap_socket_get_fd(coap_socket_t *socket);*
Expand All @@ -69,7 +75,7 @@ or *-lcoap-@LIBCOAP_API_VERSION@-tinydtls*. Otherwise, link with
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
underlying CoAP and (D)TLS need to send (and possibly re-send) created packets
as well as receive packets for processing.

The *coap_io_process*() function is the primary function applications should
Expand Down Expand Up @@ -204,6 +210,24 @@ 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_io_get_fds()*

The *coap_io_get_fds*() function is used to get all of the libcoap internally
used file descriptors associated with _context_ in a read or write pending state.

_read_fds_[] is a defined array to hold all the file descriptors that are in a
read pending state with a size of _max_read_fds_. _have_read_fds_ is returned
with the number of file descriptors in _read_fds_[].

_write_fds_[] is a defined array to hold all the file descriptors that are in a
write pending state with a size of _max_write_fds_. _have_write_fds_ is returned
with the number of file descriptors in _write_fds_[].

_rem_timeout_ms_ is updated with the remaining milli-seconds before coap_io_process()
needs to be called again to handle any internal timeouts. If _rem_timeout_ms_ is 0,
then there is no timeout and the next event will be a change in state of one of
the file descriptors.

*Function: coap_can_exit()*

The *coap_can_exit*() function checks to see if there are any outstanding
Expand Down Expand Up @@ -241,6 +265,8 @@ milli-seconds that need to be waited before the function should next be called.

*coap_io_pending*() returns 1 if there is outstanding i/o else returns 0.

*coap_io_get_fds*() returns 1 if file descriptors returned, else returns 0.

*coap_can_exit*() returns 1 if there is nothing outstanding to transmit else
returns 0.

Expand Down
154 changes: 150 additions & 4 deletions src/coap_io.c
Original file line number Diff line number Diff line change
Expand Up @@ -534,10 +534,14 @@ coap_update_io_timer(coap_context_t *context, coap_tick_t delay) {
#endif /* COAP_DEBUG_WAKEUP_TIMES */
}
}
#else /* COAP_EPOLL_SUPPORT */
(void)context;
(void)delay;
#endif /* COAP_EPOLL_SUPPORT */
#else /* ! COAP_EPOLL_SUPPORT */
coap_tick_t now;

coap_ticks(&now);
if (context->next_timeout == 0 || context->next_timeout > now + delay) {
context->next_timeout = now + delay;
}
#endif /* ! COAP_EPOLL_SUPPORT */
}
#endif /* ! WITH_CONTIKI */

Expand Down Expand Up @@ -1576,6 +1580,147 @@ coap_io_prepare_io_lkd(coap_context_t *ctx,
return (unsigned int)((timeout * 1000 + COAP_TICKS_PER_SECOND - 1) / COAP_TICKS_PER_SECOND);
}

/*
* return 0 Insufficient space to hold fds, or fds not supported
* 1 All fds found
*/
COAP_API unsigned int
coap_io_get_fds(coap_context_t *ctx,
coap_fd_t read_fds[],
unsigned int *have_read_fds,
unsigned int max_read_fds,
coap_fd_t write_fds[],
unsigned int *have_write_fds,
unsigned int max_write_fds,
unsigned int *rem_timeout_ms) {
unsigned int ret;

coap_lock_lock(ctx, return 0);
ret = coap_io_get_fds_lkd(ctx, read_fds, have_read_fds, max_read_fds, write_fds,
have_write_fds, max_write_fds, rem_timeout_ms);
coap_lock_unlock(ctx);
return ret;
}

#if !defined(WITH_LWIP) && !defined(WITH_CONTIKI)
static int
coap_add_fd(coap_fd_t fd, coap_fd_t this_fds[], unsigned int *have_this_fds,
unsigned int max_this_fds) {
if (*have_this_fds < max_this_fds) {
this_fds[(*have_this_fds)++] = fd;
return 1;
}
coap_log_warn("coap_io_get_fds: Insufficient space for new fd (%u >= %u)\n", *have_this_fds,
max_this_fds);
return 0;
}

/*
* return 0 Insufficient space to hold fds, or fds not supported
* 1 All fds found
*/
unsigned int
coap_io_get_fds_lkd(coap_context_t *ctx,
coap_fd_t read_fds[],
unsigned int *have_read_fds,
unsigned int max_read_fds,
coap_fd_t write_fds[],
unsigned int *have_write_fds,
unsigned int max_write_fds,
unsigned int *rem_timeout_ms) {
*have_read_fds = 0;
*have_write_fds = 0;

#ifdef COAP_EPOLL_SUPPORT
(void)write_fds;
(void)max_write_fds;;

if (!coap_add_fd(ctx->epfd, read_fds, have_read_fds, max_read_fds))
return 0;
/* epoll is making use of timerfd, so no need to return any timeout */
*rem_timeout_ms = 0;
return 1;
#else /* ! COAP_EPOLL_SUPPORT */
coap_session_t *s, *rtmp;
coap_tick_t now;
unsigned int timeout_ms;
#if COAP_SERVER_SUPPORT
coap_endpoint_t *ep;

LL_FOREACH(ctx->endpoint, ep) {
if (ep->sock.flags & (COAP_SOCKET_WANT_READ | COAP_SOCKET_WANT_ACCEPT)) {
if (!coap_add_fd(ep->sock.fd, read_fds, have_read_fds, max_read_fds))
return 0;
}
if (ep->sock.flags & (COAP_SOCKET_WANT_WRITE | COAP_SOCKET_WANT_CONNECT)) {
if (!coap_add_fd(ep->sock.fd, write_fds, have_write_fds, max_write_fds))
return 0;
}
SESSIONS_ITER_SAFE(ep->sessions, s, rtmp) {
if (s->sock.flags & (COAP_SOCKET_WANT_READ | COAP_SOCKET_WANT_ACCEPT)) {
if (!coap_add_fd(s->sock.fd, read_fds, have_read_fds, max_read_fds))
return 0;
}
if (s->sock.flags & (COAP_SOCKET_WANT_WRITE | COAP_SOCKET_WANT_CONNECT)) {
if (!coap_add_fd(s->sock.fd, write_fds, have_write_fds, max_write_fds))
return 0;
}
}
}
#endif /* COAP_SERVER_SUPPORT */

#if COAP_CLIENT_SUPPORT
SESSIONS_ITER_SAFE(ctx->sessions, s, rtmp) {
if (s->sock.flags & (COAP_SOCKET_WANT_READ | COAP_SOCKET_WANT_ACCEPT)) {
if (!coap_add_fd(s->sock.fd, read_fds, have_read_fds, max_read_fds))
return 0;
}
if (s->sock.flags & (COAP_SOCKET_WANT_WRITE | COAP_SOCKET_WANT_CONNECT)) {
if (!coap_add_fd(s->sock.fd, write_fds, have_write_fds, max_write_fds))
return 0;
}
}
#endif /* COAP_CLIENT_SUPPORT */

coap_ticks(&now);
timeout_ms = (unsigned int)(ctx->next_timeout ? ctx->next_timeout > now ?
ctx->next_timeout - now : 0 : 0) *
1000 / COAP_TICKS_PER_SECOND;
*rem_timeout_ms = timeout_ms;
return 1;
#endif /* ! COAP_EPOLL_SUPPORT */
}

#else /* WITH_LWIP || WITH_CONTIKI */

/*
* return 0 Insufficient space to hold fds, or fds not supported
* 1 All fds found
*/
unsigned int
coap_io_get_fds_lkd(coap_context_t *ctx,
coap_fd_t read_fds[],
unsigned int *have_read_fds,
unsigned int max_read_fds,
coap_fd_t write_fds[],
unsigned int *have_write_fds,
unsigned int max_write_fds,
unsigned int *rem_timeout_ms) {
(void)ctx;
(void)read_fds;
(void)max_read_fds;
(void)write_fds;
(void)max_write_fds;

*have_read_fds = 0;
*have_write_fds = 0;
*rem_timeout_ms = 0;

coap_log_warn("coap_io_get_fds: Not supported\n");
return 0;
}
#endif /* WITH_LWIP || WITH_CONTIKI */

#if !defined(WITH_LWIP) && !defined(CONTIKI) && !defined(RIOT_VERSION)
COAP_API int
coap_io_process(coap_context_t *ctx, uint32_t timeout_ms) {
Expand Down Expand Up @@ -1626,6 +1771,7 @@ coap_io_process_with_fds_lkd(coap_context_t *ctx, uint32_t timeout_ms,
timeout = coap_io_prepare_io_lkd(ctx, ctx->sockets,
(sizeof(ctx->sockets) / sizeof(ctx->sockets[0])),
&ctx->num_sockets, before);
ctx->next_timeout = timeout ? timeout + before : 0;

if (ereadfds) {
ctx->readfds = *ereadfds;
Expand Down
6 changes: 6 additions & 0 deletions src/coap_io_contiki.c
Original file line number Diff line number Diff line change
Expand Up @@ -39,6 +39,8 @@ on_io_timer_expired(void *ptr) {

void
coap_update_io_timer(coap_context_t *ctx, coap_tick_t delay) {
coap_tick_t now;

if (!ctimer_expired(&ctx->io_timer)) {
ctimer_stop(&ctx->io_timer);
}
Expand All @@ -50,6 +52,10 @@ coap_update_io_timer(coap_context_t *ctx, coap_tick_t delay) {
on_io_timer_expired,
ctx);
}
coap_ticks(&now);
if (ctx->next_timeout == 0 || ctx->next_timeout > now + delay) {
ctx->next_timeout = now + delay;
}
}

static void
Expand Down

0 comments on commit 8361f8c

Please sign in to comment.