COAP_IO(3)
π COAP_IO(3) β from the libcoap Manual π
π NAME π
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, coap_io_pending, coap_can_exit β Work with CoAP I/O to do the packet send and receives. That's the whole assignment, bestie: sending and receiving packets. π
β¨ SYNOPSIS β¨
Okay so here's the exact spellbook, no cap πͺ:
#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. Link flags: literally iconic, do not freestyle them. π«Ά
πΈ 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. It's giving "the actual network has entered the chat." π
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. Vibe check: epoll or not epoll, that is the question.
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. Select-based I/O said "I'm the main character now." π
π¦ 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. Two little defines with big main character energy:
#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. No waiting, no vibes, just processing and out. π
NOTE:coap_io_process()should not be called from within a callback handler as defined using thecoap_register_*_handler()ascoap_io_process()will likely recursively call the same handler. Bestie, do NOT do that β recursive chaos is not the look. π
There are two methods of how to call coap_io_process().
- Have
coap_io_process()called from within awhile()loop. Under idle conditions (no input traffic)coap_io_process()will then get called everytimeout_ms, but more frequently if there is input / retransmission traffic. - Wait on the file descriptor returned by
coap_context_get_coap_fd()usingselect(),poll()or an event returned byepoll_wait(). If read is available on the CoAP file descriptor, callcoap_io_process()withtimeout_msset toCOAP_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. iykyk β epoll girlies get the extra method. π¦
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 be done. Basically: prep the epoll situation, then let it cook. π
β 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. This is the "actually do the I/O" part, periodt. π₯
π 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 the sockets it finds that are waiting for network traffic (COAP_SOCKET_WANT_* is set) into 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 be 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. It's a whole prep-and-select routine, and honestly? Obsessed. π
π 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. This is the "go do the thing now" function. β¨
π 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. Extra FDs? We can test those too, bestie. π«Ά
NOTE: The additional parameters forcoap_io_process_with_fds()are only used if there is no epoll support in libcoap. If there is epoll support, thencoap_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. Epoll girlies, listen up: use the returned FD method instead. π
π¦ 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. One FD to monitor them all β iconic behavior, honestly. π
πΈ 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. Are we still waiting on stuff? This function says yes/no. π
π 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. So like, "can I leave?" energy β but it only checks outstanding PDUs, not whether your requests got answers. π
π RETURN VALUES π
coap_io_process()andcoap_io_process_with_fds()β return the time, in milli-seconds, that was spent in the function. If-1is returned, there was an unexpected error. Unexpected error? Not the vibe.coap_context_get_coap_fd()β returns a non-negative number as the file descriptor to monitor, or-1if epoll is not configured in libcoap.coap_io_prepare_io()andcoap_io_prepare_epoll()β return the number of 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_can_exit()β returns 1 if there is nothing outstanding to transmit else returns 0.
π EXAMPLES π
okay bestie, real talk β this is where the page gets hands-on. There are four whole example flows, and yes, two of them are both labeled Method One. We are not questioning the lore. We are simply presenting the code, exactly as it appears. π
β¨ Method One - use coap_io_process() β¨
This is the βlet libcoap handle the loopβ era. You set up your context, set block mode, then loop on coap_io_process(ctx, wait_ms). If the result is < 0, that's your internal-issue signal and the example breaks out. Full code:
#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);
}
Lowkey the whole main-character loop. π«Ά
π Method One - coap_io_process_with_fds π
Same loop vibe, but now you're bringing your own readfds and nfds so non-libcoap FDs can hang out too. The call is coap_io_process_with_fds(ctx, wait_ms, nfds, &readfds, NULL, NULL). Full code:
#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 π¦
Now you're doing it yourself with select() and the fd from coap_context_get_coap_fd(ctx). If coap_fd == -1, the comment says epoll is not supported, and the example exits. Also yes, the errno != EAGAIN check and the coap_log_debug("select: ...") line are both here. No missing pieces. Full code:
#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 π
epoll_wait() girlies rise β this is the fd-based method using epoll_create1(0), epoll_ctl() and epoll_wait(). It has MAX_EVENTS 10, the full event loop, and the cleanup EPOLL_CTL_DEL call. Full code:
#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);
}
And that's all four example methods β iconic behavior only. π β¨
π SEE ALSO π
Go give these a read too, bestie: coap_block(3), coap_context(3), coap_init(3) and coap_supported(3). π«Ά
π FURTHER INFORMATION π
The actual RFC tea is here:
βRFC7252: The Constrained Application Protocol (CoAP)β
...for further information.
π BUGS π
Got a bug? Please raise an issue on GitHub at https://github.com/obgm/libcoap/issues to report any bugs.
Got a fix? Please raise a Pull Request at https://github.com/obgm/libcoap/pulls for any fixes.
π AUTHORS π
The libcoap project <libcoap-developers@lists.sourceforge.net> π«Ά
That's the whole page, bestie β from coap_io 4.3.5, dated 08/24/2026. Go forth and event-loop slay. π
β¨
π¦ where this page comes from
- ubuntu stonking: libcoap3t64 4.3.5-4ubuntu1 Β· BSD-2-Clause
- π girlified by deepseek-ai/DeepSeek-V4.1-Flash-1017 on : a language model's rewrite of the original, under its terms