---
name: "radcli_ctx_get_poll"
section: "3"
platform: "linux"
package: "radcli"
version: "2.0.1-1"
release: "Arch Linux 2026-11-01"
platforms: ["linux"]
url: "https://new.carta.tech/radcli_ctx_get_poll"
---

# radcli\_ctx\_get\_poll(3)

Report what to wait for on ctx's behalf, for the caller's own event loop radcli never calls poll()/select()/epoll\_wait() itself.

## NAME

radcli\_ctx\_get\_poll - Report what to wait for on ctx's behalf, for the caller's own event loop  radcli never calls poll()/select()/epoll\_wait() itself.

## SYNOPSIS

```
#include <radcli/>

int radcli_ctx_get_poll(
    radcli_ctx     *ctx,
    struct pollfd  *pfds,
    size_t          max_pfds,
    size_t         *nfds,
    int            *timeout_ms
);
```

## DESCRIPTION

There is no per-object descriptor accessor (e.g. no radcli\_dae\_fd(), no per-radcli\_request one either  net2.md's REQ-NET2-SEND-013): every descriptor this reports belongs to ctx, not to any one radcli\_dae or radcli\_request, so that a transport sharing one descriptor between dynamic authorization and ordinary requests (already true for TLS/DTLS) never leaves an application holding a watcher on a descriptor that has quietly started meaning something else.

For TLS/DTLS, or for a UDP ctx with no active radcli\_dae, this is always exactly one descriptor: the session fd (TLS/DTLS, also carrying any in-flight RADCLI\_REQUEST\_SENDONLY traffic) or the request-registry socket (UDP, REQ-NET2-SEND-016). A UDP ctx with an active radcli\_dae reports a second, independent descriptor for the DAE listener alongside it  the two are genuinely different local sockets/ports and cannot be merged into one without changing the wire protocol; RADCLI\_CTX\_MAX\_POLLFDS (2) is the maximum this API ever needs. \*timeout\_ms folds together every deadline source that applies (DAE queued-work, RadSec watchdog, and any in-flight RADCLI\_REQUEST\_SENDONLY exchange's own retransmit/timeout) into one caller-facing value, so the caller never computes a min() itself.

A descriptor is closed or replaced only during a call the application itself makes (radcli\_ctx\_dispatch(), radcli\_dae\_free(), radcli\_request\_perform(), rc\_destroy()), never asynchronously  but re-query after any of those regardless, since one may replace it.

## PARAMETERS

- **ctx**

  a context, with or without an active radcli\_dae.

- **pfds**

  filled with up to RADCLI\_CTX\_MAX\_POLLFDS entries (fd/events; revents is left for the caller's poll() to fill in).

- **max\_pfds**

  pfds's capacity; MUST be at least RADCLI\_CTX\_MAX\_POLLFDS.

- **nfds**

  set to how many of pfds were filled in (0 if there is nothing to watch yet).

- **timeout\_ms**

  milliseconds after which to call radcli\_ctx\_dispatch() even without I/O readiness; -1 for "no timeout\
    needed".

## RETURN VALUE

0 on success, -1 if ctx or an out-parameter is NULL, or max\_pfds is too small.

## SEE ALSO

[*radcli\_ctx\_dispatch*(3)](/radcli_ctx_dispatch/3.md), [*radcli\_dae\_free*(3)](/radcli_dae_free/3.md), [*radcli\_dae\_new*(3)](/radcli_dae_new/3.md), [*radcli\_dae\_process*(3)](/radcli_dae_process/3.md), [*radcli\_dae\_reply*(3)](/radcli_dae_reply/3.md), [*radcli\_dae\_reply\_error*(3)](/radcli_dae_reply_error/3.md), [*radcli\_dae\_reply\_to\_buffer*(3)](/radcli_dae_reply_to_buffer/3.md), [*radcli\_dae\_req\_attrs*(3)](/radcli_dae_req_attrs/3.md), [*radcli\_dae\_req\_code*(3)](/radcli_dae_req_code/3.md), [*radcli\_dae\_req\_framed\_ip*(3)](/radcli_dae_req_framed_ip/3.md), [*radcli\_dae\_req\_nas\_port*(3)](/radcli_dae_req_nas_port/3.md), [*radcli\_dae\_req\_session\_id*(3)](/radcli_dae_req_session_id/3.md), [*radcli\_dae\_req\_user\_name*(3)](/radcli_dae_req_user_name/3.md), [*radcli\_dae\_request\_free*(3)](/radcli_dae_request_free/3.md), [*radcli\_dae\_set\_handler*(3)](/radcli_dae_set_handler/3.md), [*radcli\_dae\_start*(3)](/radcli_dae_start/3.md)
