24 #include <freeradius-devel/curl/base.h>
25 #include <freeradius-devel/server/module.h>
26 #include <freeradius-devel/unlang/interpret.h>
27 #include <freeradius-devel/util/debug.h>
28 #include <freeradius-devel/util/syserror.h>
38 #define SET_MOPTION(_mandle, _opt, _val)\
40 if ((ret = curl_multi_setopt(mandle, _opt, _val)) != CURLM_OK) {\
41 option = STRINGIFY(_opt);\
56 while ((m = curl_multi_info_read(mandle, &msg_queued))) {
62 CURL *candle = m->easy_handle;
69 ret = curl_easy_getinfo(candle, CURLINFO_PRIVATE, &randle);
71 "Failed retrieving request data from CURL easy handle (candle)")) {
72 curl_multi_remove_handle(mandle, candle);
82 if (m->data.result != CURLE_OK) {
83 REDEBUG(
"curl request failed: %s (%i)",
84 curl_easy_strerror(m->data.result), m->data.result);
86 randle->
result = m->data.result;
92 curl_multi_remove_handle(mandle, candle);
100 DEBUG4(
"Got unknown msg (%i) when dequeueing curl responses", msg_queued);
116 CURLM *mandle = mhandle->
mandle;
120 DEBUG4(
"multi-handle %p - Timer fired", mandle);
122 ret = curl_multi_socket_action(mandle, CURL_SOCKET_TIMEOUT, 0, &running);
123 if (ret != CURLM_OK) {
124 ERROR(
"multi-handle %p - Servicing failed - %s (%i)", mandle, curl_multi_strerror(ret), ret);
128 DEBUG3(
"multi-handle %p - Serviced by timer. %i request(s) in progress, %" PRIu64
" requests(s) to dequeue",
129 mandle, running, mhandle->
transfers - (uint64_t)running);
143 CURLM *mandle = mhandle->
mandle;
146 ret = curl_multi_socket_action(mandle, fd, event, &running);
147 if (ret != CURLM_OK) {
148 ERROR(
"multi-handle %p - Servicing failed - %s (%i)", mandle, curl_multi_strerror(ret), ret);
153 char const *event_str;
156 case CURL_CSELECT_ERR:
160 case CURL_CSELECT_OUT:
161 event_str =
"socket-writable";
164 case CURL_CSELECT_IN:
165 event_str =
"socket-readable";
169 event_str =
"closed";
173 event_str =
"<INVALID>";
177 DEBUG3(
"multi-handle %p - Serviced on fd %i event (%s). "
178 "%i request(s) in progress, %" PRIu64
" requests(s) to dequeue",
179 mandle, fd, event_str, running, mhandle->
transfers - (uint64_t)running);
209 if (flags & EV_EOF) {
228 DEBUG4(
"multi-handle %p - fd %i now writable", mhandle->
mandle, fd);
244 DEBUG4(
"multi-handle %p - fd %i now readable", mhandle->
mandle, fd);
268 if (timeout_ms < 0) {
270 PERROR(
"Failed deleting multi-handle timer");
273 DEBUG3(
"multi-handle %p - Timer removed", mandle);
277 DEBUG3(
"multi-handle %p will need servicing in %li ms", mandle, timeout_ms);
327 PERROR(
"multi-handle %p registration failed for read+error events on FD %i",
331 DEBUG4(
"multi-handle %p registered for read+error events on FD %i", mhandle->
mandle, fd);
340 PERROR(
"multi-handle %p registration failed for write+error events on FD %i",
344 DEBUG4(
"multi-handle %p registered for write+error events on FD %i", mhandle->
mandle, fd);
347 case CURL_POLL_INOUT:
353 PERROR(
"multi-handle %p registration failed for read+write+error events on FD %i",
357 DEBUG4(
"multi-handle %p registered for read+write+error events on FD %i", mhandle->
mandle, fd);
360 case CURL_POLL_REMOVE:
362 PERROR(
"multi-handle %p de-registration failed for FD %i", mhandle->
mandle, fd);
365 DEBUG4(
"multi-handle %p unregistered events for FD %i", mhandle->
mandle, fd);
393 char const *p =
data, *q, *end = p + len;
403 q = memchr(p,
'\n', end - p);
412 case CURLINFO_HEADER_IN:
416 q = memchr(p,
'\n', end - p);
431 case CURLINFO_HEADER_OUT:
435 case CURLINFO_DATA_IN:
439 case CURLINFO_DATA_OUT:
443 case CURLINFO_SSL_DATA_OUT:
447 case CURLINFO_SSL_DATA_IN:
495 ret = curl_easy_setopt(randle->
candle, CURLOPT_PRIVATE, randle);
496 if (ret != CURLE_OK) {
497 REDEBUG(
"Request failed: %i - %s", ret, curl_easy_strerror(ret));
507 mret = curl_multi_add_handle(mhandle->
mandle, randle->
candle);
508 if (mret != CURLM_OK) {
510 REDEBUG(
"Request failed: %i - %s", mret, curl_multi_strerror(mret));
522 curl_easy_cleanup(randle->
candle);
537 randle->
candle = curl_easy_init();
553 curl_multi_cleanup(mhandle->
mandle);
570 #ifndef CURLPIPE_MULTIPLEX
580 mandle = curl_multi_init();
582 ERROR(
"Curl multi-handle instantiation failed");
604 #ifdef CURLPIPE_MULTIPLEX
605 SET_MOPTION(mandle, CURLMOPT_PIPELINING, multiplex ? CURLPIPE_MULTIPLEX : CURLPIPE_NOTHING);
611 ERROR(
"Failed setting curl option %s: %s (%i)", option, curl_multi_strerror(ret), ret);
#define DIAG_UNKNOWN_PRAGMAS
#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.
fr_event_timer_t const * ev
Multi-Handle timer.
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/.
#define fr_event_timer_in(...)
void unlang_interpret_mark_runnable(request_t *request)
Mark a request as resumable.
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 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_timer_expired(UNUSED fr_event_list_t *el, UNUSED fr_time_t now, void *uctx)
libcurl's timer expired
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.
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_timer_delete(fr_event_timer_t const **ev_p)
Delete a timer event from the event list.
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)
MEM(pair_append_request(&vp, attr_eap_aka_sim_identity) >=0)
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)
static fr_event_list_t * el
#define fr_box_strvalue_len(_val, _len)