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: 98d02a345a06f513e1017d56cf7faed67a09ccce $
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] tl 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 timer 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 I/O 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 FR_TIMER_DISARM_RETURN(mhandle->ev);
281 DEBUG3("multi-handle %p - Timer removed", mandle);
282 return 0;
283 }
284
285 DEBUG3("multi-handle %p will need servicing in %li ms", mandle, timeout_ms);
286
287 /*
288 * https://curl.haxx.se/libcurl/c/CURLMOPT_TIMERFUNCTION.html
289 *
290 * WARNING: even if it feels tempting, avoid calling libcurl directly from within the
291 * callback itself when the timeout_ms value is zero, since it risks triggering an
292 * unpleasant recursive behavior that immediately calls another call to the callback
293 * with a zero timeout...
294 *
295 * Setting a timeout of zero when calling fr_timer_in should result in the event
296 * repeating at most twice during one iteration of the event loop.
297 *
298 * In a previous version of this code we called curl_multi_socket_action immediately
299 * if timeout_ms was 0. It was observed that this lead to this callback being called
300 * ~665 times per request which is why we no longer do that.
301 */
302 if (fr_timer_in(mhandle, mhandle->el->tl, &mhandle->ev,
303 fr_time_delta_from_msec(timeout_ms),
304 false, _fr_curl_io_timer_expired, mhandle) < 0) return -1;
305 return 0;
306}
307
308/** Called by libcurl to register a socket that it's intefr_curled in receiving IO events for
309 *
310 *
311 * @param[in] easy handle this fd relates to.
312 * @param[in] fd File descriptor curl wants to be notified about.
313 * @param[in] what Which events libcurl wants to be notified of, may be one of:
314 * - CURL_POLL_IN Wait for incoming data. For the socket
315 * to become readable.
316 * - CURL_POLL_OUT Wait for outgoing data. For the socket
317 * to become writable.
318 * - CURL_POLL_INOUT Wait for incoming and outgoing data.
319 * For the socket to become readable or writable.
320 * - CURL_POLL_REMOVE The specified socket/file descriptor is no
321 * longer used by libcurl.
322 * @param[in] ctx The fr_curl_handle_t specific to this thread.
323 * @param[in] fd_ctx Private data associated with the socket.
324 */
325static int _fr_curl_io_event_modify(UNUSED CURL *easy, curl_socket_t fd, int what, void *ctx, UNUSED void *fd_ctx)
326{
327 fr_curl_handle_t *mhandle = talloc_get_type_abort(ctx, fr_curl_handle_t);
328
329 switch (what) {
330 case CURL_POLL_IN:
331 if (fr_event_fd_insert(mhandle, NULL, mhandle->el, fd,
333 NULL,
335 mhandle) < 0) {
336 PERROR("multi-handle %p registration failed for read+error events on FD %i",
337 mhandle->mandle, fd);
338 return -1;
339 }
340 DEBUG4("multi-handle %p registered for read+error events on FD %i", mhandle->mandle, fd);
341 break;
342
343 case CURL_POLL_OUT:
344 if (fr_event_fd_insert(mhandle, NULL, mhandle->el, fd,
345 NULL,
348 mhandle) < 0) {
349 PERROR("multi-handle %p registration failed for write+error events on FD %i",
350 mhandle->mandle, fd);
351 return -1;
352 }
353 DEBUG4("multi-handle %p registered for write+error events on FD %i", mhandle->mandle, fd);
354 break;
355
356 case CURL_POLL_INOUT:
357 if (fr_event_fd_insert(mhandle, NULL, mhandle->el, fd,
361 mhandle) < 0) {
362 PERROR("multi-handle %p registration failed for read+write+error events on FD %i",
363 mhandle->mandle, fd);
364 return -1;
365 }
366 DEBUG4("multi-handle %p registered for read+write+error events on FD %i", mhandle->mandle, fd);
367 break;
368
369 case CURL_POLL_REMOVE:
370 if (fr_event_fd_delete(mhandle->el, fd, FR_EVENT_FILTER_IO) < 0) {
371 PERROR("multi-handle %p de-registration failed for FD %i", mhandle->mandle, fd);
372 return -1;
373 }
374 DEBUG4("multi-handle %p unregistered events for FD %i", mhandle->mandle, fd);
375 break;
376
377 default:
378 fr_assert(0);
379 return -1;
380 }
381
382 return CURLM_OK;
383}
384
385/** Callback to receive debugging data from libcurl
386 *
387 * @note Should only be set on a handle if RDEBUG_ENABLED3 is true.
388 *
389 * @param[in] candle Curl handle the debugging data pertains to.
390 * @param[in] type The type of debugging data we received.
391 * @param[in] data Buffer containing debug data (not \0 terminated). Despite the
392 * type being char *, this can be binary data depending on the
393 * curl_infotype.
394 * @param[in] len The length of the data in the buffer.
395 * @param[in] uctx The current request.
396 * @return
397 * - 0 (we always indicate success)
398 */
399static int curl_debug_log(UNUSED CURL *candle, curl_infotype type, char *data, size_t len, void *uctx)
400{
401 request_t *request = talloc_get_type_abort(uctx, request_t);
402 char const *p = data, *q, *end = p + len;
403 char const *verb;
404
405 switch (type) {
406 case CURLINFO_TEXT:
407 /*
408 * Curl debug output has trailing newlines, and could conceivably
409 * span multiple lines. Take care of both cases.
410 */
411 while (p < end) {
412 q = memchr(p, '\n', end - p);
413 if (!q) q = end;
414
415 RDEBUG3("libcurl - %pV", fr_box_strvalue_len(p, q ? q - p : p - end));
416 p = q + 1;
417 }
418
419 break;
420
421 case CURLINFO_HEADER_IN:
422 verb = "received";
423 print_header:
424 while (p < end) {
425 q = memchr(p, '\n', end - p);
426 q = q ? q + 1 : end;
427
428 if (RDEBUG_ENABLED4) {
429 RHEXDUMP4((uint8_t const *)p, q - p,
430 "%s header: %pV",
431 verb, fr_box_strvalue_len(p, q - p));
432 } else {
433 RDEBUG3("%s header: %pV",
434 verb, fr_box_strvalue_len(p, q - p));
435 }
436 p = q;
437 }
438 break;
439
440 case CURLINFO_HEADER_OUT:
441 verb = "sending";
442 goto print_header;
443
444 case CURLINFO_DATA_IN:
445 RHEXDUMP4((uint8_t const *)data, len, "received data[length %zu]", len);
446 break;
447
448 case CURLINFO_DATA_OUT:
449 RHEXDUMP4((uint8_t const *)data, len, "sending data[length %zu]", len);
450 break;
451
452 case CURLINFO_SSL_DATA_OUT:
453 RHEXDUMP4((uint8_t const *)data, len, "sending ssl-data[length %zu]", len);
454 break;
455
456 case CURLINFO_SSL_DATA_IN:
457 RHEXDUMP4((uint8_t const *)data, len, "received ssl-data[length %zu]", len);
458 break;
459
460 default:
461 RHEXDUMP3((uint8_t const *)data, len, "libcurl - debug data (unknown type %i)", (int)type);
462 break;
463 }
464
465 return 0;
466}
467
468/** Sends a request using libcurl
469 *
470 * Send the actual curl request to the server. The response will be handled by
471 * the numerous callbacks configured for the easy handle.
472 *
473 * @param[in] mhandle Thread-specific mhandle wrapper.
474 * @param[in] request Current request.
475 * @param[in] randle representing the request.
476 * @return
477 * - 0 on success.
478 * - -1 on failure.
479 */
481{
482 CURLcode ret;
483 CURLMcode mret;
484
485 REQUEST_VERIFY(request);
486
487 randle->request = request;
488
489 /*
490 * Set debugging functions so we can track the
491 * IO request's progress.
492 */
493 if (RDEBUG_ENABLED3) {
494 FR_CURL_REQUEST_SET_OPTION(CURLOPT_DEBUGFUNCTION, curl_debug_log);
495 FR_CURL_REQUEST_SET_OPTION(CURLOPT_DEBUGDATA, request);
496 FR_CURL_REQUEST_SET_OPTION(CURLOPT_VERBOSE, 1L);
497 }
498
499 /*
500 * Stick the current request in the curl handle's
501 * private data. This makes it simple to resume
502 * the request in the demux function later...
503 *
504 * Note: If you get 0xdeadc341 in the private data
505 * in the demux function, the result for the easy
506 * handle was erroneously delivered after a
507 * cancellation.
508 */
509 ret = curl_easy_setopt(randle->candle, CURLOPT_PRIVATE, randle);
510 if (ret != CURLE_OK) {
511 REDEBUG("Request failed: %i - %s", ret, curl_easy_strerror(ret));
512 return -1;
513 }
514
515 /*
516 * Increment here, else the debug output looks
517 * messed up is curl_multi_add_handle triggers
518 * event loop modifications calls immediately.
519 */
520 mhandle->transfers++;
521 mret = curl_multi_add_handle(mhandle->mandle, randle->candle);
522 if (mret != CURLM_OK) {
523 mhandle->transfers--;
524 REDEBUG("Request failed: %i - %s", mret, curl_multi_strerror(mret));
525 return -1;
526 }
527
528 return 0;
529
530error:
531 return -1;
532}
533
535{
536 curl_easy_cleanup(randle->candle);
537
538 return 0;
539}
540
541/** Allocate a new curl easy request and wrapper struct
542 *
543 */
545{
546 fr_curl_io_request_t *randle;
547
548 randle = talloc_zero(ctx, fr_curl_io_request_t);
549 if (unlikely(!randle)) return NULL;
550
551 randle->candle = curl_easy_init();
552 if (!randle->candle) {
553 talloc_free(randle);
554 return NULL;
555 }
556
557 talloc_set_destructor(randle, _fr_curl_io_request_free);
558
559 return randle;
560}
561
562/** Free the multi-handle
563 *
564 */
565static int _mhandle_free(fr_curl_handle_t *mhandle)
566{
567 curl_multi_cleanup(mhandle->mandle);
568
569 return 0;
570}
571
572/** Performs the libcurl initialisation of the thread
573 *
574 * @param[in] ctx to alloc handle in.
575 * @param[in] el to initial.
576 * @param[in] multiplex Run multiple requests over the same connection simultaneously.
577 * HTTP/2 only.
578 * @return
579 * - 0 on success.
580 * - -1 on error.
581 */
584#ifndef CURLPIPE_MULTIPLEX
585 UNUSED
586#endif
587 bool multiplex)
588{
589 CURLMcode ret;
590 CURLM *mandle;
591 fr_curl_handle_t *mhandle;
592 char const *option;
593
594 mandle = curl_multi_init();
595 if (!mandle) {
596 ERROR("Curl multi-handle instantiation failed");
597 return NULL;
598 }
599
600 /*
601 * Structure to store extra data.
602 *
603 * Passed to all curl I/O and timer callbacks.
604 *
605 * If uctx data is needed in the future, can be added here.
606 */
607 MEM(mhandle = talloc_zero(ctx, fr_curl_handle_t));
608 mhandle->el = el;
609 mhandle->mandle = mandle;
610 talloc_set_destructor(mhandle, _mhandle_free);
611
612 SET_MOPTION(mandle, CURLMOPT_TIMERFUNCTION, _fr_curl_io_timer_modify);
613 SET_MOPTION(mandle, CURLMOPT_TIMERDATA, mhandle);
614
615 SET_MOPTION(mandle, CURLMOPT_SOCKETFUNCTION, _fr_curl_io_event_modify);
616 SET_MOPTION(mandle, CURLMOPT_SOCKETDATA, mhandle);
617
618#ifdef CURLPIPE_MULTIPLEX
619 SET_MOPTION(mandle, CURLMOPT_PIPELINING, multiplex ? CURLPIPE_MULTIPLEX : CURLPIPE_NOTHING);
620#endif
621
622 return mhandle;
623
624error:
625 ERROR("Failed setting curl option %s: %s (%i)", option, curl_multi_strerror(ret), ret);
626
627 return NULL;
628}
#define DIAG_UNKNOWN_PRAGMAS
Definition build.h:458
#define DIAG_ON(_x)
Definition build.h:460
#define unlikely(_x)
Definition build.h:383
#define UNUSED
Definition build.h:317
#define DIAG_OFF(_x)
Definition build.h:459
fr_timer_t * ev
Multi-Handle timer.
Definition base.h:93
#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
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:248
@ FR_EVENT_FILTER_IO
Combined filter for read/write functions/.
Definition event.h:84
void unlang_interpret_mark_runnable(request_t *request)
Mark a request as resumable.
Definition interpret.c:1418
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:325
static int _fr_curl_io_request_free(fr_curl_io_request_t *randle)
Definition io.c:534
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_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:399
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:480
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:544
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:582
static void _fr_curl_io_timer_expired(UNUSED fr_timer_list_t *tl, UNUSED fr_time_t now, void *uctx)
libcurl's timer expired
Definition io.c:124
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:565
#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_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:1203
Stores all information relating to an event list.
Definition event.c:377
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:305
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
An event timer list.
Definition timer.c:49
#define FR_TIMER_DISARM_RETURN(_ev)
Definition timer.h:97
#define fr_timer_in(...)
Definition timer.h:86
static fr_event_list_t * el
static fr_slen_t data
Definition value.h:1274
#define fr_box_strvalue_len(_val, _len)
Definition value.h:297