24#include <freeradius-devel/curl/base.h>
25#include <freeradius-devel/util/debug.h>
26#include <freeradius-devel/util/syserror.h>
36#define SET_MOPTION(_mandle, _opt, _val)\
38 if ((ret = curl_multi_setopt(mandle, _opt, _val)) != CURLM_OK) {\
39 option = STRINGIFY(_opt);\
54 while ((m = curl_multi_info_read(mandle, &msg_queued))) {
60 CURL *candle = m->easy_handle;
67 ret = curl_easy_getinfo(candle, CURLINFO_PRIVATE, &randle);
80 "Failed retrieving request data from CURL easy handle (candle)")) {
81 curl_multi_remove_handle(mandle, candle);
91 if (m->data.result != CURLE_OK) {
92 REDEBUG(
"curl request failed: %s (%i)",
93 curl_easy_strerror(m->data.result), m->data.result);
95 randle->
result = m->data.result;
101 curl_multi_remove_handle(mandle, candle);
109 DEBUG4(
"Got unknown msg (%i) when dequeueing curl responses", msg_queued);
125 CURLM *mandle = mhandle->
mandle;
129 DEBUG4(
"multi-handle %p - Timer fired", mandle);
131 ret = curl_multi_socket_action(mandle, CURL_SOCKET_TIMEOUT, 0, &running);
132 if (ret != CURLM_OK) {
133 ERROR(
"multi-handle %p - Servicing timer failed -%s (%i)", mandle, curl_multi_strerror(ret), ret);
137 DEBUG3(
"multi-handle %p - Serviced by timer. %i request(s) in progress, %" PRIu64
" requests(s) to dequeue",
138 mandle, running, mhandle->
transfers - (uint64_t)running);
152 CURLM *mandle = mhandle->
mandle;
155 ret = curl_multi_socket_action(mandle, fd, event, &running);
156 if (ret != CURLM_OK) {
157 ERROR(
"multi-handle %p - Servicing I/O failed - %s (%i)", mandle, curl_multi_strerror(ret), ret);
162 char const *event_str;
165 case CURL_CSELECT_ERR:
169 case CURL_CSELECT_OUT:
170 event_str =
"socket-writable";
173 case CURL_CSELECT_IN:
174 event_str =
"socket-readable";
178 event_str =
"closed";
182 event_str =
"<INVALID>";
186 DEBUG3(
"multi-handle %p - Serviced on fd %i event (%s). "
187 "%i request(s) in progress, %" PRIu64
" requests(s) to dequeue",
188 mandle, fd, event_str, running, mhandle->
transfers - (uint64_t)running);
218 if (flags & EV_EOF) {
237 DEBUG4(
"multi-handle %p - fd %i now writable", mhandle->
mandle, fd);
253 DEBUG4(
"multi-handle %p - fd %i now readable", mhandle->
mandle, fd);
277 if (timeout_ms < 0) {
279 DEBUG3(
"multi-handle %p - Timer removed", mandle);
283 DEBUG3(
"multi-handle %p will need servicing in %li ms", mandle, timeout_ms);
334 PERROR(
"multi-handle %p registration failed for read+error events on FD %i",
338 DEBUG4(
"multi-handle %p registered for read+error events on FD %i", mhandle->
mandle, fd);
347 PERROR(
"multi-handle %p registration failed for write+error events on FD %i",
351 DEBUG4(
"multi-handle %p registered for write+error events on FD %i", mhandle->
mandle, fd);
354 case CURL_POLL_INOUT:
360 PERROR(
"multi-handle %p registration failed for read+write+error events on FD %i",
364 DEBUG4(
"multi-handle %p registered for read+write+error events on FD %i", mhandle->
mandle, fd);
367 case CURL_POLL_REMOVE:
369 PERROR(
"multi-handle %p de-registration failed for FD %i", mhandle->
mandle, fd);
372 DEBUG4(
"multi-handle %p unregistered events for FD %i", mhandle->
mandle, fd);
400 char const *p =
data, *q, *end = p + len;
410 q = memchr(p,
'\n', end - p);
419 case CURLINFO_HEADER_IN:
423 q = memchr(p,
'\n', end - p);
438 case CURLINFO_HEADER_OUT:
442 case CURLINFO_DATA_IN:
446 case CURLINFO_DATA_OUT:
450 case CURLINFO_SSL_DATA_OUT:
454 case CURLINFO_SSL_DATA_IN:
507 ret = curl_easy_setopt(randle->
candle, CURLOPT_PRIVATE, randle);
508 if (ret != CURLE_OK) {
509 REDEBUG(
"Request failed: %i - %s", ret, curl_easy_strerror(ret));
519 mret = curl_multi_add_handle(mhandle->
mandle, randle->
candle);
520 if (mret != CURLM_OK) {
522 REDEBUG(
"Request failed: %i - %s", mret, curl_multi_strerror(mret));
534 curl_easy_cleanup(randle->
candle);
549 randle->
candle = curl_easy_init();
565 curl_multi_cleanup(mhandle->
mandle);
582#ifndef CURLPIPE_MULTIPLEX
592 mandle = curl_multi_init();
594 ERROR(
"Curl multi-handle instantiation failed");
616#ifdef CURLPIPE_MULTIPLEX
617 SET_MOPTION(mandle, CURLMOPT_PIPELINING, multiplex ? CURLPIPE_MULTIPLEX : CURLPIPE_NOTHING);
623 ERROR(
"Failed setting curl option %s: %s (%i)", option, curl_multi_strerror(ret), ret);
#define DIAG_UNKNOWN_PRAGMAS
fr_timer_t * ev
Multi-Handle timer.
#define FR_CURL_REQUEST_SET_OPTION(_x, _y)
fr_event_list_t * el
Event list servicing I/O events.
CURLcode result
Result of executing the request.
uint64_t transfers
How many transfers are current in progress.
CURLM * mandle
The multi handle.
request_t * request
Current request.
CURL * candle
Request specific handle.
Uctx data for timer and I/O functions.
Structure representing an individual request being passed to curl for processing.
#define fr_cond_assert_msg(_x, _fmt,...)
Calls panic_action ifndef NDEBUG, else logs error and evaluates to value of _x.
#define fr_event_fd_insert(...)
@ FR_EVENT_FILTER_IO
Combined filter for read/write functions/.
void unlang_interpret_mark_runnable(request_t *request)
Mark a request as resumable.
static int _fr_curl_io_event_modify(UNUSED CURL *easy, curl_socket_t fd, int what, void *ctx, UNUSED void *fd_ctx)
Called by libcurl to register a socket that it's intefr_curled in receiving IO events for.
static int _fr_curl_io_request_free(fr_curl_io_request_t *randle)
static void _fr_curl_io_service_writable(UNUSED fr_event_list_t *el, int fd, UNUSED int flags, void *uctx)
File descriptor became writable.
#define SET_MOPTION(_mandle, _opt, _val)
static void _fr_curl_io_demux(fr_curl_handle_t *mhandle, CURLM *mandle)
De-queue curl requests and wake up the requests that initiated them.
static void _fr_curl_io_service_errored(UNUSED fr_event_list_t *el, int fd, int flags, int fd_errno, void *uctx)
File descriptor experienced an error.
static int curl_debug_log(UNUSED CURL *candle, curl_infotype type, char *data, size_t len, void *uctx)
Callback to receive debugging data from libcurl.
static void _fr_curl_io_service_readable(UNUSED fr_event_list_t *el, int fd, UNUSED int flags, void *uctx)
File descriptor became readable.
int fr_curl_io_request_enqueue(fr_curl_handle_t *mhandle, request_t *request, fr_curl_io_request_t *randle)
Sends a request using libcurl.
static int _fr_curl_io_timer_modify(CURLM *mandle, long timeout_ms, void *ctx)
Callback called by libcurl to set/unset timers.
fr_curl_io_request_t * fr_curl_io_request_alloc(TALLOC_CTX *ctx)
Allocate a new curl easy request and wrapper struct.
fr_curl_handle_t * fr_curl_io_init(TALLOC_CTX *ctx, fr_event_list_t *el, UNUSED bool multiplex)
Performs the libcurl initialisation of the thread.
static void _fr_curl_io_timer_expired(UNUSED fr_timer_list_t *tl, UNUSED fr_time_t now, void *uctx)
libcurl's timer expired
static void _fr_curl_io_service(fr_curl_handle_t *mhandle, int fd, int event)
Service an IO event on a file descriptor.
static int _mhandle_free(fr_curl_handle_t *mhandle)
Free the multi-handle.
#define RDEBUG_ENABLED3
True if request debug level 1-3 messages are enabled.
#define RHEXDUMP4(_data, _len, _fmt,...)
#define RHEXDUMP3(_data, _len, _fmt,...)
#define DEBUG_ENABLED3
True if global debug level 1-3 messages are enabled.
#define RDEBUG_ENABLED4
True if request debug level 1-4 messages are enabled.
int fr_event_fd_delete(fr_event_list_t *el, int fd, fr_event_filter_t filter)
Remove a file descriptor from the event loop.
Stores all information relating to an event list.
#define REQUEST_VERIFY(_x)
fr_aka_sim_id_type_t type
char const * fr_syserror(int num)
Guaranteed to be thread-safe version of strerror.
static fr_time_delta_t fr_time_delta_from_msec(int64_t msec)
#define FR_TIMER_DISARM_RETURN(_ev)
static fr_event_list_t * el
#define fr_box_strvalue_len(_val, _len)