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);
82 "Failed retrieving request data from CURL easy handle (candle)")) {
83 curl_multi_remove_handle(mandle, candle);
93 if (m->data.result != CURLE_OK) {
94 REDEBUG(
"curl request failed: %s (%i)",
95 curl_easy_strerror(m->data.result), m->data.result);
97 randle->
result = m->data.result;
103 curl_multi_remove_handle(mandle, candle);
111 DEBUG4(
"Got unknown msg (%i) when dequeueing curl responses", msg_queued);
127 CURLM *mandle = mhandle->
mandle;
131 DEBUG4(
"multi-handle %p - Timer fired", mandle);
133 ret = curl_multi_socket_action(mandle, CURL_SOCKET_TIMEOUT, 0, &running);
134 if (ret != CURLM_OK) {
135 ERROR(
"multi-handle %p - Servicing failed - %s (%i)", mandle, curl_multi_strerror(ret), ret);
139 DEBUG3(
"multi-handle %p - Serviced by timer. %i request(s) in progress, %" PRIu64
" requests(s) to dequeue",
140 mandle, running, mhandle->
transfers - (uint64_t)running);
154 CURLM *mandle = mhandle->
mandle;
157 ret = curl_multi_socket_action(mandle, fd, event, &running);
158 if (ret != CURLM_OK) {
159 ERROR(
"multi-handle %p - Servicing failed - %s (%i)", mandle, curl_multi_strerror(ret), ret);
164 char const *event_str;
167 case CURL_CSELECT_ERR:
171 case CURL_CSELECT_OUT:
172 event_str =
"socket-writable";
175 case CURL_CSELECT_IN:
176 event_str =
"socket-readable";
180 event_str =
"closed";
184 event_str =
"<INVALID>";
188 DEBUG3(
"multi-handle %p - Serviced on fd %i event (%s). "
189 "%i request(s) in progress, %" PRIu64
" requests(s) to dequeue",
190 mandle, fd, event_str, running, mhandle->
transfers - (uint64_t)running);
220 if (flags & EV_EOF) {
239 DEBUG4(
"multi-handle %p - fd %i now writable", mhandle->
mandle, fd);
255 DEBUG4(
"multi-handle %p - fd %i now readable", mhandle->
mandle, fd);
279 if (timeout_ms < 0) {
281 PERROR(
"Failed deleting multi-handle timer");
284 DEBUG3(
"multi-handle %p - Timer removed", mandle);
288 DEBUG3(
"multi-handle %p will need servicing in %li ms", mandle, timeout_ms);
338 PERROR(
"multi-handle %p registration failed for read+error events on FD %i",
342 DEBUG4(
"multi-handle %p registered for read+error events on FD %i", mhandle->
mandle, fd);
351 PERROR(
"multi-handle %p registration failed for write+error events on FD %i",
355 DEBUG4(
"multi-handle %p registered for write+error events on FD %i", mhandle->
mandle, fd);
358 case CURL_POLL_INOUT:
364 PERROR(
"multi-handle %p registration failed for read+write+error events on FD %i",
368 DEBUG4(
"multi-handle %p registered for read+write+error events on FD %i", mhandle->
mandle, fd);
371 case CURL_POLL_REMOVE:
373 PERROR(
"multi-handle %p de-registration failed for FD %i", mhandle->
mandle, fd);
376 DEBUG4(
"multi-handle %p unregistered events for FD %i", mhandle->
mandle, fd);
404 char const *p =
data, *q, *end = p + len;
414 q = memchr(p,
'\n', end - p);
423 case CURLINFO_HEADER_IN:
427 q = memchr(p,
'\n', end - p);
442 case CURLINFO_HEADER_OUT:
446 case CURLINFO_DATA_IN:
450 case CURLINFO_DATA_OUT:
454 case CURLINFO_SSL_DATA_OUT:
458 case CURLINFO_SSL_DATA_IN:
511 ret = curl_easy_setopt(randle->
candle, CURLOPT_PRIVATE, randle);
512 if (ret != CURLE_OK) {
513 REDEBUG(
"Request failed: %i - %s", ret, curl_easy_strerror(ret));
523 mret = curl_multi_add_handle(mhandle->
mandle, randle->
candle);
524 if (mret != CURLM_OK) {
526 REDEBUG(
"Request failed: %i - %s", mret, curl_multi_strerror(mret));
538 curl_easy_cleanup(randle->
candle);
553 randle->
candle = curl_easy_init();
569 curl_multi_cleanup(mhandle->
mandle);
586 #ifndef CURLPIPE_MULTIPLEX
596 mandle = curl_multi_init();
598 ERROR(
"Curl multi-handle instantiation failed");
620 #ifdef CURLPIPE_MULTIPLEX
621 SET_MOPTION(mandle, CURLMOPT_PIPELINING, multiplex ? CURLPIPE_MULTIPLEX : CURLPIPE_NOTHING);
627 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.
fr_dcursor_eval_t void const * uctx
#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)