The FreeRADIUS server  $Id: 15bac2a4c627c01d1aa2047687b3418955ac7f00 $
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  */
36 DIAG_OFF(disabled-macro-expansion)
38 #define SET_MOPTION(_mandle, _opt, _val)\
39 do {\
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  */
51 static 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  {
60  fr_curl_io_request_t *randle;
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  */
151 static 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  */
205 static 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  */
235 static 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  */
251 static 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  */
275 static 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  */
327 static 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  */
401 static 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 
532 error:
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  */
567 static 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 
626 error:
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:454
#define DIAG_ON(_x)
Definition: build.h:456
#define unlikely(_x)
Definition: build.h:379
#define UNUSED
Definition: build.h:313
#define DIAG_OFF(_x)
Definition: build.h:455
#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
fr_dcursor_eval_t void const * uctx
Definition: dcursor.h:546
#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 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
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 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
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
Definition: merged_model.c:30
#define REDEBUG(fmt,...)
Definition: radclient.h:52
#define REQUEST_VERIFY(_x)
Definition: request.h:276
fr_assert(0)
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.
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