The FreeRADIUS server $Id: 15bac2a4c627c01d1aa2047687b3418955ac7f00 $
Loading...
Searching...
No Matches
io.c
Go to the documentation of this file.
1/*
2 * This program is is free software; you can redistribute it and/or modify
3 * it under the terms of the GNU General Public License as published by
4 * the Free Software Foundation; either version 2 of the License, or (at
5 * your option) any later version.
6 *
7 * This program is distributed in the hope that it will be useful,
8 * but WITHOUT ANY WARRANTY; without even the implied warranty of
9 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
10 * GNU General Public License for more details.
11 *
12 * You should have received a copy of the GNU General Public License
13 * along with this program; if not, write to the Free Software
14 * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA
15 */
16
17/**
18 * $Id: b72064bb98a3e1e49d61f15f5941c5cb9465dbc7 $
19 * @file curl/io.c
20 * @brief Implement asynchronous callbacks for curl
21 *
22 * @copyright 2020 Arran Cudbard-Bell (a.cudbardb@freeradius.org)
23 */
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>
29
30/*
31 * CURL headers do:
32 *
33 * #define curl_easy_setopt(handle,opt,param) curl_easy_setopt(handle,opt,param)
34 */
36DIAG_OFF(disabled-macro-expansion)
38#define SET_MOPTION(_mandle, _opt, _val)\
39do {\
40 if ((ret = curl_multi_setopt(mandle, _opt, _val)) != CURLM_OK) {\
41 option = STRINGIFY(_opt);\
42 goto error;\
43 }\
44} while (0)
45
46/** De-queue curl requests and wake up the requests that initiated them
47 *
48 * @param[in] mhandle containing the event loop and request counter.
49 * @param[in] mandle to dequeue curl easy handles/responses from.
50 */
51static inline void _fr_curl_io_demux(fr_curl_handle_t *mhandle, CURLM *mandle)
52{
53 struct CURLMsg *m;
54 int msg_queued = 0;
55
56 while ((m = curl_multi_info_read(mandle, &msg_queued))) {
57 switch (m->msg) {
58 case CURLMSG_DONE:
59 {
61 request_t *request = NULL;
62 CURL *candle = m->easy_handle;
63 CURLcode ret;
64
65 fr_assert(candle);
66
67 mhandle->transfers--;
68
69 ret = curl_easy_getinfo(candle, CURLINFO_PRIVATE, &randle);
70 /*
71 * In curl 7.61 we got bad request data returned
72 * here after cancellations were processed.
73 *
74 * For debug builds if the value is equal to
75 * 0xdeadc341, we know the request was cancelled.
76 *
77 * There is no good work around for this other than
78 * upgrading to a newer version of curl.
79 */
80 talloc_get_type_abort(randle, fr_curl_io_request_t);
81 if (!fr_cond_assert_msg(ret == CURLE_OK,
82 "Failed retrieving request data from CURL easy handle (candle)")) {
83 curl_multi_remove_handle(mandle, candle);
84 return;
85 }
86 request = randle->request;
87
88 REQUEST_VERIFY(request);
89
90 /*
91 * If the request failed, say why...
92 */
93 if (m->data.result != CURLE_OK) {
94 REDEBUG("curl request failed: %s (%i)",
95 curl_easy_strerror(m->data.result), m->data.result);
96 }
97 randle->result = m->data.result;
98
99 /*
100 * This needs to be done last, else m->data.result
101 * ends up being junk.
102 */
103 curl_multi_remove_handle(mandle, candle);
104
106 }
107 break;
108
109 default:
110#ifndef NDEBUG
111 DEBUG4("Got unknown msg (%i) when dequeueing curl responses", msg_queued);
112#endif
113 break;
114 }
115 }
116}
117
118/** libcurl's timer expired
119 *
120 * @param[in] el the timer was inserted into.
121 * @param[in] now The current time according to the event loop.
122 * @param[in] uctx The rlm_fr_curl_thread_t specific to this thread.
123 */
125{
126 fr_curl_handle_t *mhandle = talloc_get_type_abort(uctx, fr_curl_handle_t);
127 CURLM *mandle = mhandle->mandle;
128 CURLMcode ret;
129 int running = 0;
130
131 DEBUG4("multi-handle %p - Timer fired", mandle);
132
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);
136 return;
137 }
138
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);
141
142 _fr_curl_io_demux(mhandle, mandle);
143}
144
145/** Service an IO event on a file descriptor
146 *
147 * @param[in] mhandle containing the event loop and request counter.
148 * @param[in] fd the IO event occurred for.
149 * @param[in] event type.
150 */
151static inline void _fr_curl_io_service(fr_curl_handle_t *mhandle, int fd, int event)
152{
153 CURLMcode ret;
154 CURLM *mandle = mhandle->mandle;
155 int running = 0;
156
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);
160 return;
161 }
162
163 if (DEBUG_ENABLED3) {
164 char const *event_str;
165
166 switch (event) {
167 case CURL_CSELECT_ERR:
168 event_str = "error";
169 break;
170
171 case CURL_CSELECT_OUT:
172 event_str = "socket-writable";
173 break;
174
175 case CURL_CSELECT_IN:
176 event_str = "socket-readable";
177 break;
178
179 case 0:
180 event_str = "closed"; /* Not really closed, more do your own eval! */
181 break;
182
183 default:
184 event_str = "<INVALID>";
185 break;
186 }
187
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);
191 }
192
193
194 _fr_curl_io_demux(mhandle, mandle);
195}
196
197/** File descriptor experienced an error
198 *
199 * @param[in] el fd was registered with.
200 * @param[in] fd that errored.
201 * @param[in] flags from kevent.
202 * @param[in] fd_errno from kevent.
203 * @param[in] uctx The rlm_fr_curl_thread_t specific to this thread.
204 */
205static void _fr_curl_io_service_errored(UNUSED fr_event_list_t *el, int fd, int flags, int fd_errno, void *uctx)
206{
207 fr_curl_handle_t *mhandle = talloc_get_type_abort(uctx, fr_curl_handle_t);
208
209 DEBUG4("multi-handle %p - fd %i errored: %s", mhandle->mandle, fd, fr_syserror(fd_errno));
210
211 /*
212 * The remote server closed the socket
213 *
214 * Instead of signalling curl with CURL_CSELECT_ERR
215 * which always results in spurious errors being
216 * printed, pass in '0', which causes libcurl to do
217 * its own evaluation on the socket state, and hopefully
218 * run the right code for socket closure.
219 */
220 if (flags & EV_EOF) {
221 _fr_curl_io_service(mhandle, fd, 0);
222 return;
223 }
224
225 _fr_curl_io_service(mhandle, fd, CURL_CSELECT_ERR);
226}
227
228/** File descriptor became writable
229 *
230 * @param[in] el fd was registered with.
231 * @param[in] fd that became writable.
232 * @param[in] flags from kevent.
233 * @param[in] uctx The rlm_fr_curl_thread_t specific to this thread.
234 */
235static void _fr_curl_io_service_writable(UNUSED fr_event_list_t *el, int fd, UNUSED int flags, void *uctx)
236{
237 fr_curl_handle_t *mhandle = talloc_get_type_abort(uctx, fr_curl_handle_t);
238
239 DEBUG4("multi-handle %p - fd %i now writable", mhandle->mandle, fd);
240
241 _fr_curl_io_service(mhandle, fd, CURL_CSELECT_OUT);
242}
243
244/** File descriptor became readable
245 *
246 * @param[in] el fd was registered with.
247 * @param[in] fd that became readable.
248 * @param[in] flags from kevent.
249 * @param[in] uctx The rlm_fr_curl_thread_t specific to this thread.
250 */
251static void _fr_curl_io_service_readable(UNUSED fr_event_list_t *el, int fd, UNUSED int flags, void *uctx)
252{
253 fr_curl_handle_t *mhandle = talloc_get_type_abort(uctx, fr_curl_handle_t);
254
255 DEBUG4("multi-handle %p - fd %i now readable", mhandle->mandle, fd);
256
257 _fr_curl_io_service(mhandle, fd, CURL_CSELECT_IN);
258}
259
260/** Callback called by libcurl to set/unset timers
261 *
262 * Each rlm_fr_curl_thread_t has a timer event which is controller by libcurl.
263 * This allows libcurl to honour timeouts set on requests to remote hosts,
264 * and means we don't need to set timeouts for individual I/O events.
265 *
266 * @param[in] mandle handle requesting the timer be set/unset.
267 * @param[in] timeout_ms If > 0, how long to wait before calling curl_multi_socket_action.
268 * If == 0, we call curl_multi_socket_action as soon as possible.
269 * If < 0, we delete the timer.
270 * @param[in] ctx The rlm_fr_curl_thread_t specific to this thread.
271 * @return
272 * - 0 on success.
273 * - -1 on error.
274 */
275static int _fr_curl_io_timer_modify(CURLM *mandle, long timeout_ms, void *ctx)
276{
277 fr_curl_handle_t *mhandle = talloc_get_type_abort(ctx, fr_curl_handle_t);
278
279 if (timeout_ms < 0) {
280 if (fr_event_timer_delete(&mhandle->ev) < 0) {
281 PERROR("Failed deleting multi-handle timer");
282 return -1;
283 }
284 DEBUG3("multi-handle %p - Timer removed", mandle);
285 return 0;
286 }
287
288 DEBUG3("multi-handle %p will need servicing in %li ms", mandle, timeout_ms);
289
290 /*
291 * https://curl.haxx.se/libcurl/c/CURLMOPT_TIMERFUNCTION.html
292 *
293 * WARNING: even if it feels tempting, avoid calling libcurl directly from within the
294 * callback itself when the timeout_ms value is zero, since it risks triggering an
295 * unpleasant recursive behavior that immediately calls another call to the callback
296 * with a zero timeout...
297 *
298 * Setting a timeout of zero when calling fr_event_timer_in should result in the event
299 * repeating at most twice during one iteration of the event loop.
300 *
301 * In a previous version of this code we called curl_multi_socket_action immediately
302 * if timeout_ms was 0. It was observed that this lead to this callback being called
303 * ~665 times per request which is why we no longer do that.
304 */
305 if (fr_event_timer_in(mhandle, mhandle->el, &mhandle->ev,
306 fr_time_delta_from_msec(timeout_ms), _fr_curl_io_timer_expired, mhandle) < 0) return -1;
307 return 0;
308}
309
310/** Called by libcurl to register a socket that it's intefr_curled in receiving IO events for
311 *
312 *
313 * @param[in] easy handle this fd relates to.
314 * @param[in] fd File descriptor curl wants to be notified about.
315 * @param[in] what Which events libcurl wants to be notified of, may be one of:
316 * - CURL_POLL_IN Wait for incoming data. For the socket
317 * to become readable.
318 * - CURL_POLL_OUT Wait for outgoing data. For the socket
319 * to become writable.
320 * - CURL_POLL_INOUT Wait for incoming and outgoing data.
321 * For the socket to become readable or writable.
322 * - CURL_POLL_REMOVE The specified socket/file descriptor is no
323 * longer used by libcurl.
324 * @param[in] ctx The fr_curl_handle_t specific to this thread.
325 * @param[in] fd_ctx Private data associated with the socket.
326 */
327static int _fr_curl_io_event_modify(UNUSED CURL *easy, curl_socket_t fd, int what, void *ctx, UNUSED void *fd_ctx)
328{
329 fr_curl_handle_t *mhandle = talloc_get_type_abort(ctx, fr_curl_handle_t);
330
331 switch (what) {
332 case CURL_POLL_IN:
333 if (fr_event_fd_insert(mhandle, NULL, mhandle->el, fd,
335 NULL,
337 mhandle) < 0) {
338 PERROR("multi-handle %p registration failed for read+error events on FD %i",
339 mhandle->mandle, fd);
340 return -1;
341 }
342 DEBUG4("multi-handle %p registered for read+error events on FD %i", mhandle->mandle, fd);
343 break;
344
345 case CURL_POLL_OUT:
346 if (fr_event_fd_insert(mhandle, NULL, mhandle->el, fd,
347 NULL,
350 mhandle) < 0) {
351 PERROR("multi-handle %p registration failed for write+error events on FD %i",
352 mhandle->mandle, fd);
353 return -1;
354 }
355 DEBUG4("multi-handle %p registered for write+error events on FD %i", mhandle->mandle, fd);
356 break;
357
358 case CURL_POLL_INOUT:
359 if (fr_event_fd_insert(mhandle, NULL, mhandle->el, fd,
363 mhandle) < 0) {
364 PERROR("multi-handle %p registration failed for read+write+error events on FD %i",
365 mhandle->mandle, fd);
366 return -1;
367 }
368 DEBUG4("multi-handle %p registered for read+write+error events on FD %i", mhandle->mandle, fd);
369 break;
370
371 case CURL_POLL_REMOVE:
372 if (fr_event_fd_delete(mhandle->el, fd, FR_EVENT_FILTER_IO) < 0) {
373 PERROR("multi-handle %p de-registration failed for FD %i", mhandle->mandle, fd);
374 return -1;
375 }
376 DEBUG4("multi-handle %p unregistered events for FD %i", mhandle->mandle, fd);
377 break;
378
379 default:
380 fr_assert(0);
381 return -1;
382 }
383
384 return CURLM_OK;
385}
386
387/** Callback to receive debugging data from libcurl
388 *
389 * @note Should only be set on a handle if RDEBUG_ENABLED3 is true.
390 *
391 * @param[in] candle Curl handle the debugging data pertains to.
392 * @param[in] type The type of debugging data we received.
393 * @param[in] data Buffer containing debug data (not \0 terminated). Despite the
394 * type being char *, this can be binary data depending on the
395 * curl_infotype.
396 * @param[in] len The length of the data in the buffer.
397 * @param[in] uctx The current request.
398 * @return
399 * - 0 (we always indicate success)
400 */
401static int curl_debug_log(UNUSED CURL *candle, curl_infotype type, char *data, size_t len, void *uctx)
402{
403 request_t *request = talloc_get_type_abort(uctx, request_t);
404 char const *p = data, *q, *end = p + len;
405 char const *verb;
406
407 switch (type) {
408 case CURLINFO_TEXT:
409 /*
410 * Curl debug output has trailing newlines, and could conceivably
411 * span multiple lines. Take care of both cases.
412 */
413 while (p < end) {
414 q = memchr(p, '\n', end - p);
415 if (!q) q = end;
416
417 RDEBUG3("libcurl - %pV", fr_box_strvalue_len(p, q ? q - p : p - end));
418 p = q + 1;
419 }
420
421 break;
422
423 case CURLINFO_HEADER_IN:
424 verb = "received";
425 print_header:
426 while (p < end) {
427 q = memchr(p, '\n', end - p);
428 q = q ? q + 1 : end;
429
430 if (RDEBUG_ENABLED4) {
431 RHEXDUMP4((uint8_t const *)p, q - p,
432 "%s header: %pV",
433 verb, fr_box_strvalue_len(p, q - p));
434 } else {
435 RDEBUG3("%s header: %pV",
436 verb, fr_box_strvalue_len(p, q - p));
437 }
438 p = q;
439 }
440 break;
441
442 case CURLINFO_HEADER_OUT:
443 verb = "sending";
444 goto print_header;
445
446 case CURLINFO_DATA_IN:
447 RHEXDUMP4((uint8_t const *)data, len, "received data[length %zu]", len);
448 break;
449
450 case CURLINFO_DATA_OUT:
451 RHEXDUMP4((uint8_t const *)data, len, "sending data[length %zu]", len);
452 break;
453
454 case CURLINFO_SSL_DATA_OUT:
455 RHEXDUMP4((uint8_t const *)data, len, "sending ssl-data[length %zu]", len);
456 break;
457
458 case CURLINFO_SSL_DATA_IN:
459 RHEXDUMP4((uint8_t const *)data, len, "received ssl-data[length %zu]", len);
460 break;
461
462 default:
463 RHEXDUMP3((uint8_t const *)data, len, "libcurl - debug data (unknown type %i)", (int)type);
464 break;
465 }
466
467 return 0;
468}
469
470/** Sends a request using libcurl
471 *
472 * Send the actual curl request to the server. The response will be handled by
473 * the numerous callbacks configured for the easy handle.
474 *
475 * @param[in] mhandle Thread-specific mhandle wrapper.
476 * @param[in] request Current request.
477 * @param[in] randle representing the request.
478 * @return
479 * - 0 on success.
480 * - -1 on failure.
481 */
483{
484 CURLcode ret;
485 CURLMcode mret;
486
487 REQUEST_VERIFY(request);
488
489 randle->request = request;
490
491 /*
492 * Set debugging functions so we can track the
493 * IO request's progress.
494 */
495 if (RDEBUG_ENABLED3) {
496 FR_CURL_REQUEST_SET_OPTION(CURLOPT_DEBUGFUNCTION, curl_debug_log);
497 FR_CURL_REQUEST_SET_OPTION(CURLOPT_DEBUGDATA, request);
498 FR_CURL_REQUEST_SET_OPTION(CURLOPT_VERBOSE, 1L);
499 }
500
501 /*
502 * Stick the current request in the curl handle's
503 * private data. This makes it simple to resume
504 * the request in the demux function later...
505 *
506 * Note: If you get 0xdeadc341 in the private data
507 * in the demux function, the result for the easy
508 * handle was erroneously delivered after a
509 * cancellation.
510 */
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));
514 return -1;
515 }
516
517 /*
518 * Increment here, else the debug output looks
519 * messed up is curl_multi_add_handle triggers
520 * event loop modifications calls immediately.
521 */
522 mhandle->transfers++;
523 mret = curl_multi_add_handle(mhandle->mandle, randle->candle);
524 if (mret != CURLM_OK) {
525 mhandle->transfers--;
526 REDEBUG("Request failed: %i - %s", mret, curl_multi_strerror(mret));
527 return -1;
528 }
529
530 return 0;
531
532error:
533 return -1;
534}
535
537{
538 curl_easy_cleanup(randle->candle);
539
540 return 0;
541}
542
543/** Allocate a new curl easy request and wrapper struct
544 *
545 */
547{
548 fr_curl_io_request_t *randle;
549
550 randle = talloc_zero(ctx, fr_curl_io_request_t);
551 if (unlikely(!randle)) return NULL;
552
553 randle->candle = curl_easy_init();
554 if (!randle->candle) {
555 talloc_free(randle);
556 return NULL;
557 }
558
559 talloc_set_destructor(randle, _fr_curl_io_request_free);
560
561 return randle;
562}
563
564/** Free the multi-handle
565 *
566 */
567static int _mhandle_free(fr_curl_handle_t *mhandle)
568{
569 curl_multi_cleanup(mhandle->mandle);
570
571 return 0;
572}
573
574/** Performs the libcurl initialisation of the thread
575 *
576 * @param[in] ctx to alloc handle in.
577 * @param[in] el to initial.
578 * @param[in] multiplex Run multiple requests over the same connection simultaneously.
579 * HTTP/2 only.
580 * @return
581 * - 0 on success.
582 * - -1 on error.
583 */
586#ifndef CURLPIPE_MULTIPLEX
587 UNUSED
588#endif
589 bool multiplex)
590{
591 CURLMcode ret;
592 CURLM *mandle;
593 fr_curl_handle_t *mhandle;
594 char const *option;
595
596 mandle = curl_multi_init();
597 if (!mandle) {
598 ERROR("Curl multi-handle instantiation failed");
599 return NULL;
600 }
601
602 /*
603 * Structure to store extra data.
604 *
605 * Passed to all curl I/O and timer callbacks.
606 *
607 * If uctx data is needed in the future, can be added here.
608 */
609 MEM(mhandle = talloc_zero(ctx, fr_curl_handle_t));
610 mhandle->el = el;
611 mhandle->mandle = mandle;
612 talloc_set_destructor(mhandle, _mhandle_free);
613
614 SET_MOPTION(mandle, CURLMOPT_TIMERFUNCTION, _fr_curl_io_timer_modify);
615 SET_MOPTION(mandle, CURLMOPT_TIMERDATA, mhandle);
616
617 SET_MOPTION(mandle, CURLMOPT_SOCKETFUNCTION, _fr_curl_io_event_modify);
618 SET_MOPTION(mandle, CURLMOPT_SOCKETDATA, mhandle);
619
620#ifdef CURLPIPE_MULTIPLEX
621 SET_MOPTION(mandle, CURLMOPT_PIPELINING, multiplex ? CURLPIPE_MULTIPLEX : CURLPIPE_NOTHING);
622#endif
623
624 return mhandle;
625
626error:
627 ERROR("Failed setting curl option %s: %s (%i)", option, curl_multi_strerror(ret), ret);
628
629 return NULL;
630}
#define DIAG_UNKNOWN_PRAGMAS
Definition build.h:456
#define DIAG_ON(_x)
Definition build.h:458
#define unlikely(_x)
Definition build.h:381
#define UNUSED
Definition build.h:315
#define DIAG_OFF(_x)
Definition build.h:457
#define FR_CURL_REQUEST_SET_OPTION(_x, _y)
Definition base.h:67
fr_event_list_t * el
Event list servicing I/O events.
Definition base.h:92
CURLcode result
Result of executing the request.
Definition base.h:103
uint64_t transfers
How many transfers are current in progress.
Definition base.h:94
CURLM * mandle
The multi handle.
Definition base.h:95
request_t * request
Current request.
Definition base.h:104
fr_event_timer_t const * ev
Multi-Handle timer.
Definition base.h:93
CURL * candle
Request specific handle.
Definition base.h:102
Uctx data for timer and I/O functions.
Definition base.h:91
Structure representing an individual request being passed to curl for processing.
Definition base.h:101
#define fr_cond_assert_msg(_x, _fmt,...)
Calls panic_action ifndef NDEBUG, else logs error and evaluates to value of _x.
Definition debug.h:156
#define MEM(x)
Definition debug.h:36
#define ERROR(fmt,...)
Definition dhcpclient.c:41
#define fr_event_fd_insert(...)
Definition event.h:232
@ FR_EVENT_FILTER_IO
Combined filter for read/write functions/.
Definition event.h:62
#define fr_event_timer_in(...)
Definition event.h:255
void unlang_interpret_mark_runnable(request_t *request)
Mark a request as resumable.
Definition interpret.c:1359
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.
Definition io.c:327
static int _fr_curl_io_request_free(fr_curl_io_request_t *randle)
Definition io.c:536
static void _fr_curl_io_service_writable(UNUSED fr_event_list_t *el, int fd, UNUSED int flags, void *uctx)
File descriptor became writable.
Definition io.c:235
#define SET_MOPTION(_mandle, _opt, _val)
Definition io.c:38
static void _fr_curl_io_timer_expired(UNUSED fr_event_list_t *el, UNUSED fr_time_t now, void *uctx)
libcurl's timer expired
Definition io.c:124
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.
Definition io.c:51
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.
Definition io.c:205
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.
Definition io.c:401
static void _fr_curl_io_service_readable(UNUSED fr_event_list_t *el, int fd, UNUSED int flags, void *uctx)
File descriptor became readable.
Definition io.c:251
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.
Definition io.c:482
static int _fr_curl_io_timer_modify(CURLM *mandle, long timeout_ms, void *ctx)
Callback called by libcurl to set/unset timers.
Definition io.c:275
fr_curl_io_request_t * fr_curl_io_request_alloc(TALLOC_CTX *ctx)
Allocate a new curl easy request and wrapper struct.
Definition io.c:546
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.
Definition io.c:584
static void _fr_curl_io_service(fr_curl_handle_t *mhandle, int fd, int event)
Service an IO event on a file descriptor.
Definition io.c:151
static int _mhandle_free(fr_curl_handle_t *mhandle)
Free the multi-handle.
Definition io.c:567
#define PERROR(_fmt,...)
Definition log.h:228
#define DEBUG3(_fmt,...)
Definition log.h:266
#define RDEBUG_ENABLED3
True if request debug level 1-3 messages are enabled.
Definition log.h:335
#define RDEBUG3(fmt,...)
Definition log.h:343
#define RHEXDUMP4(_data, _len, _fmt,...)
Definition log.h:706
#define DEBUG4(_fmt,...)
Definition log.h:267
#define RHEXDUMP3(_data, _len, _fmt,...)
Definition log.h:705
#define DEBUG_ENABLED3
True if global debug level 1-3 messages are enabled.
Definition log.h:259
#define RDEBUG_ENABLED4
True if request debug level 1-4 messages are enabled.
Definition log.h:336
talloc_free(reap)
int fr_event_timer_delete(fr_event_timer_t const **ev_p)
Delete a timer event from the event list.
Definition event.c:1611
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.
Definition event.c:1260
Stores all information relating to an event list.
Definition event.c:411
unsigned char uint8_t
#define fr_assert(_expr)
Definition rad_assert.h:38
#define REDEBUG(fmt,...)
Definition radclient.h:52
#define REQUEST_VERIFY(_x)
Definition request.h:276
fr_aka_sim_id_type_t type
char const * fr_syserror(int num)
Guaranteed to be thread-safe version of strerror.
Definition syserror.c:243
static fr_time_delta_t fr_time_delta_from_msec(int64_t msec)
Definition time.h:575
"server local" time.
Definition time.h:69
static fr_event_list_t * el
static fr_slen_t data
Definition value.h:1265
#define fr_box_strvalue_len(_val, _len)
Definition value.h:286