---
name: "coap_io"
section: "3"
platform: "linux"
package: "libcoap3t64"
version: "4.3.4-1.1+deb13u3"
release: "Debian 13 (Trixie)"
platforms: ["linux"]
url: "https://new.carta.tech/coap_io"
---

# coap\_io(3)

Work with CoAP I/O to do the packet send and receives

## 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

## SYNOPSIS

**#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** or **-lcoap-3-tinydtls**. Otherwise, link with **-lcoap-3** to get the default (D)TLS library support.

## 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.

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.

## 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.

```
#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.

**NOTE:** **coap\_io\_process**() should not be called from within a callback handler as defined using the coap\_register\_\*\_handler() as **coap\_io\_process**() will likely recursively call the same handler.

There are two methods of how to call **coap\_io\_process**().

 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**(), **poll**() or an event returned by epoll\_wait(). If *read* is available on the CoAP file descriptor, call **coap\_io\_process**() with *timeout\_ms* set to COAP\_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.

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 done.

**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.

**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 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*.

**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.

**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.

**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.

**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.

**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.

**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.

## RETURN VALUES

**coap\_io\_process**() and **coap\_io\_process\_with\_fds**() return 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 configured in libcoap.

**coap\_io\_prepare\_io**() and **coap\_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

**Method One - use coap\_io\_process()**

```
#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);
}
```

**Method One - coap\_io\_process\_with\_fds**

```
#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**

```
#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**

```
#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);
}
```

## SEE ALSO

[**coap\_block**(3)](/coap_block/3.md), [**coap\_context**(3)](/coap_context/3.md) and [**coap\_init**(3)](/coap_init/3.md)

## FURTHER INFORMATION

See

"RFC7252: The Constrained Application Protocol (CoAP)"

for further information.

## BUGS

Please report bugs on the mailing list for libcoap: libcoap-developers@lists.sourceforge.net or raise an issue on GitHub at https://github.com/obgm/libcoap/issues

## AUTHORS

The libcoap project \<libcoap-developers@lists.sourceforge.net\>
