GNUnet  0.11.x
curl.c
Go to the documentation of this file.
1 /*
2  This file is part of GNUnet
3  Copyright (C) 2014, 2015, 2016, 2018 GNUnet e.V.
4 
5  GNUnet is free software: you can redistribute it and/or modify it
6  under the terms of the GNU Affero General Public License as published
7  by the Free Software Foundation, either version 3 of the License,
8  or (at your option) any later version.
9 
10  GNUnet is distributed in the hope that it will be useful, but
11  WITHOUT ANY WARRANTY; without even the implied warranty of
12  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
13  Affero General Public License for more details.
14 
15  You should have received a copy of the GNU Affero General Public License
16  along with this program. If not, see <http://www.gnu.org/licenses/>.
17 
18  SPDX-License-Identifier: AGPL3.0-or-later
19  */
26 #include "platform.h"
27 #include <jansson.h>
28 #include <microhttpd.h>
29 #include "gnunet_curl_lib.h"
30 
31 #if ENABLE_BENCHMARK
32 #include "../util/benchmark.h"
33 #endif
34 
35 
43 #define CURL_STRERROR(type, function, code) \
44  GNUNET_log (type, \
45  "Curl function `%s' has failed at `%s:%d' with error: %s\n", \
46  function, \
47  __FILE__, \
48  __LINE__, \
49  curl_easy_strerror (code));
50 
54 #define JSON_WARN(error) \
55  GNUNET_log (GNUNET_ERROR_TYPE_WARNING, \
56  "JSON parsing failed at %s:%u: %s (%s)\n", \
57  __FILE__, \
58  __LINE__, \
59  error.text, \
60  error.source)
61 
62 
67 static int curl_fail;
68 
73 {
78 
83 
87  CURL *easy_handle;
88 
93 
98 
102  void *jcc_cls;
103 
108 
112  void *jcc_raw_cls;
113 
118 
123  struct curl_slist *job_headers;
124 };
125 
126 
131 {
135  CURLM *multi;
136 
140  CURLSH *share;
141 
146 
151 
155  struct curl_slist *common_headers;
156 
162 
168 
172  void *cb_cls;
173 
178  char *userpass;
179 
183  char *certtype;
184 
188  char *certfile;
189 
194  char *keyfile;
195 
199  char *keypass;
200 
201 };
202 
203 
212 void
214  const char *userpass)
215 {
216  GNUNET_free (ctx->userpass);
217  if (NULL != userpass)
218  ctx->userpass = GNUNET_strdup (userpass);
219 }
220 
221 
237 void
239  const char *certtype,
240  const char *certfile,
241  const char *keyfile,
242  const char *keypass)
243 {
244  GNUNET_free (ctx->certtype);
245  GNUNET_free (ctx->certfile);
246  GNUNET_free (ctx->keyfile);
247  GNUNET_free (ctx->keypass);
248  if (NULL != certtype)
249  ctx->certtype = GNUNET_strdup (certtype);
250  if (NULL != certfile)
251  ctx->certfile = GNUNET_strdup (certfile);
252  if (NULL != keyfile)
253  ctx->certtype = GNUNET_strdup (keyfile);
254  if (NULL != keypass)
255  ctx->certtype = GNUNET_strdup (keypass);
256 }
257 
258 
267 struct GNUNET_CURL_Context *
269  void *cb_cls)
270 {
271  struct GNUNET_CURL_Context *ctx;
272  CURLM *multi;
273  CURLSH *share;
274 
275  if (curl_fail)
276  {
278  "Curl was not initialised properly\n");
279  return NULL;
280  }
281  if (NULL == (multi = curl_multi_init ()))
282  {
284  "Failed to create a Curl multi handle\n");
285  return NULL;
286  }
287  if (NULL == (share = curl_share_init ()))
288  {
290  "Failed to create a Curl share handle\n");
291  return NULL;
292  }
293  ctx = GNUNET_new (struct GNUNET_CURL_Context);
294  ctx->cb = cb;
295  ctx->cb_cls = cb_cls;
296  ctx->multi = multi;
297  ctx->share = share;
298  return ctx;
299 }
300 
301 
308 void
310  const char *header_name)
311 {
312  ctx->async_scope_id_header = header_name;
313 }
314 
315 
325 int
326 GNUNET_CURL_is_valid_scope_id (const char *scope_id)
327 {
328  if (strlen (scope_id) >= 64)
329  return GNUNET_NO;
330  for (size_t i = 0; i < strlen (scope_id); i++)
331  if (! (isalnum (scope_id[i]) || (scope_id[i] == '-')))
332  return GNUNET_NO;
333  return GNUNET_YES;
334 }
335 
336 
350 static size_t
351 download_cb (char *bufptr,
352  size_t size,
353  size_t nitems,
354  void *cls)
355 {
356  struct GNUNET_CURL_DownloadBuffer *db = cls;
357  size_t msize;
358  void *buf;
359 
360  if (0 == size * nitems)
361  {
362  /* Nothing (left) to do */
363  return 0;
364  }
365  msize = size * nitems;
366  if ((msize + db->buf_size) >= GNUNET_MAX_MALLOC_CHECKED)
367  {
368  db->eno = ENOMEM;
369  return 0; /* signals an error to curl */
370  }
371  db->buf = GNUNET_realloc (db->buf, db->buf_size + msize);
372  buf = db->buf + db->buf_size;
373  GNUNET_memcpy (buf, bufptr, msize);
374  db->buf_size += msize;
375  return msize;
376 }
377 
378 
386 static struct curl_slist *
388  const struct curl_slist *job_headers)
389 {
390  struct curl_slist *all_headers = NULL;
391 
392  for (const struct curl_slist *curr = job_headers; curr != NULL;
393  curr = curr->next)
394  {
395  GNUNET_assert (NULL !=
396  (all_headers = curl_slist_append (all_headers, curr->data)));
397  }
398 
399  for (const struct curl_slist *curr = ctx->common_headers; curr != NULL;
400  curr = curr->next)
401  {
402  GNUNET_assert (NULL !=
403  (all_headers = curl_slist_append (all_headers, curr->data)));
404  }
405 
406  if (NULL != ctx->async_scope_id_header)
407  {
408  struct GNUNET_AsyncScopeSave scope;
409 
410  GNUNET_async_scope_get (&scope);
411  if (GNUNET_YES == scope.have_scope)
412  {
413  char *aid_header = NULL;
414  aid_header =
416  sizeof(
417  struct GNUNET_AsyncScopeId));
418  GNUNET_assert (NULL != aid_header);
419  GNUNET_assert (NULL != curl_slist_append (all_headers, aid_header));
420  GNUNET_free (aid_header);
421  }
422  }
423  return all_headers;
424 }
425 
426 
435 static struct GNUNET_CURL_Job *
436 setup_job (CURL *eh,
437  struct GNUNET_CURL_Context *ctx,
438  struct curl_slist *all_headers)
439 {
440  struct GNUNET_CURL_Job *job;
441 
442  if (CURLE_OK !=
443  curl_easy_setopt (eh, CURLOPT_HTTPHEADER, all_headers))
444  {
445  GNUNET_break (0);
446  curl_slist_free_all (all_headers);
447  curl_easy_cleanup (eh);
448  return NULL;
449  }
450  job = GNUNET_new (struct GNUNET_CURL_Job);
451  job->job_headers = all_headers;
452 
453  if ((CURLE_OK != curl_easy_setopt (eh, CURLOPT_PRIVATE, job)) ||
454  (CURLE_OK !=
455  curl_easy_setopt (eh, CURLOPT_WRITEFUNCTION, &download_cb)) ||
456  (CURLE_OK != curl_easy_setopt (eh, CURLOPT_WRITEDATA, &job->db)) ||
457  (CURLE_OK != curl_easy_setopt (eh, CURLOPT_SHARE, ctx->share)) ||
458  (CURLM_OK != curl_multi_add_handle (ctx->multi, eh)))
459  {
460  GNUNET_break (0);
461  GNUNET_free (job);
462  curl_easy_cleanup (eh);
463  return NULL;
464  }
465  job->easy_handle = eh;
466  job->ctx = ctx;
468  ctx->jobs_tail,
469  job);
470  return job;
471 }
472 
473 
480 void
482  const struct curl_slist *extra_headers)
483 {
484  struct curl_slist *all_headers = job->job_headers;
485 
486  for (const struct curl_slist *curr = extra_headers;
487  NULL != curr;
488  curr = curr->next)
489  {
490  GNUNET_assert (NULL !=
491  (all_headers = curl_slist_append (all_headers,
492  curr->data)));
493  }
494  job->job_headers = all_headers;
495 }
496 
497 
513 struct GNUNET_CURL_Job *
515  CURL *eh,
516  const struct curl_slist *job_headers,
518  void *jcc_cls)
519 {
520  struct GNUNET_CURL_Job *job;
521  struct curl_slist *all_headers;
522 
523  GNUNET_assert (NULL != jcc);
524  all_headers = setup_job_headers (ctx,
525  job_headers);
526  if (NULL == (job = setup_job (eh,
527  ctx,
528  all_headers)))
529  return NULL;
530  job->jcc_raw = jcc;
531  job->jcc_raw_cls = jcc_cls;
532  ctx->cb (ctx->cb_cls);
533  return job;
534 }
535 
536 
556 struct GNUNET_CURL_Job *
558  CURL *eh,
559  const struct curl_slist *job_headers,
561  void *jcc_cls)
562 {
563  struct GNUNET_CURL_Job *job;
564  struct curl_slist *all_headers;
565 
566  GNUNET_assert (NULL != jcc);
567  if ( (NULL != ctx->userpass) &&
568  (0 != curl_easy_setopt (eh,
569  CURLOPT_USERPWD,
570  ctx->userpass)) )
571  return NULL;
572  if ( (NULL != ctx->certfile) &&
573  (0 != curl_easy_setopt (eh,
574  CURLOPT_SSLCERT,
575  ctx->certfile)) )
576  return NULL;
577  if ( (NULL != ctx->certtype) &&
578  (0 != curl_easy_setopt (eh,
579  CURLOPT_SSLCERTTYPE,
580  ctx->certtype)) )
581  return NULL;
582  if ( (NULL != ctx->keyfile) &&
583  (0 != curl_easy_setopt (eh,
584  CURLOPT_SSLKEY,
585  ctx->keyfile)) )
586  return NULL;
587  if ( (NULL != ctx->keypass) &&
588  (0 != curl_easy_setopt (eh,
589  CURLOPT_KEYPASSWD,
590  ctx->keypass)) )
591  return NULL;
592 
593  all_headers = setup_job_headers (ctx,
594  job_headers);
595  if (NULL == (job = setup_job (eh,
596  ctx,
597  all_headers)))
598  return NULL;
599 
600  job->jcc = jcc;
601  job->jcc_cls = jcc_cls;
602  ctx->cb (ctx->cb_cls);
603  return job;
604 }
605 
606 
622 struct GNUNET_CURL_Job *
624  CURL *eh,
626  void *jcc_cls)
627 {
628  struct GNUNET_CURL_Job *job;
629  struct curl_slist *job_headers = NULL;
630 
631  GNUNET_assert (NULL != (job_headers =
632  curl_slist_append (NULL,
633  "Content-Type: application/json")));
634  job = GNUNET_CURL_job_add2 (ctx,
635  eh,
636  job_headers,
637  jcc,
638  jcc_cls);
639  curl_slist_free_all (job_headers);
640  return job;
641 }
642 
643 
656 struct GNUNET_CURL_Job *
658  CURL *eh,
660  void *jcc_cls)
661 {
662  return GNUNET_CURL_job_add2 (ctx,
663  eh,
664  NULL,
665  jcc,
666  jcc_cls);
667 }
668 
669 
676 void
678 {
679  struct GNUNET_CURL_Context *ctx = job->ctx;
680 
682  GNUNET_break (CURLM_OK ==
683  curl_multi_remove_handle (ctx->multi, job->easy_handle));
684  curl_easy_cleanup (job->easy_handle);
685  GNUNET_free (job->db.buf);
686  curl_slist_free_all (job->job_headers);
687  ctx->cb (ctx->cb_cls);
688  GNUNET_free (job);
689 }
690 
691 
698 static bool
699 is_json (const char *ct)
700 {
701  const char *semi;
702 
703  /* check for "application/json" exact match */
704  if (0 == strcasecmp (ct,
705  "application/json"))
706  return true;
707  /* check for "application/json;[ANYTHING]" */
708  semi = strchr (ct,
709  ';');
710  /* also allow "application/json [ANYTHING]" (note the space!) */
711  if (NULL == semi)
712  semi = strchr (ct,
713  ' ');
714  if (NULL == semi)
715  return false; /* no delimiter we accept, forget it */
716  if (semi - ct != strlen ("application/json"))
717  return false; /* delimiter past desired length, forget it */
718  if (0 == strncasecmp (ct,
719  "application/json",
720  strlen ("application/json")))
721  return true; /* OK */
722  return false;
723 }
724 
725 
744 void *
746  CURL *eh,
747  long *response_code)
748 {
749  json_t *json;
750  json_error_t error;
751  char *ct;
752 
754  "Downloaded body: %.*s\n",
755  (int) db->buf_size,
756  (char *) db->buf);
757 
758  if ((CURLE_OK !=
759  curl_easy_getinfo (eh,
760  CURLINFO_CONTENT_TYPE,
761  &ct)) ||
762  (NULL == ct) ||
763  (! is_json (ct)))
764  {
765  /* No content type or explicitly not JSON, refuse to parse
766  (but keep response code) */
767  if (CURLE_OK !=
768  curl_easy_getinfo (eh,
769  CURLINFO_RESPONSE_CODE,
770  response_code))
771  {
772  /* unexpected error... */
773  GNUNET_break (0);
774  *response_code = 0;
775  }
776  if (0 != db->buf_size)
778  "Did NOT detect response `%.*s' as JSON\n",
779  (int) db->buf_size,
780  (const char *) db->buf);
781  return NULL;
782  }
783  if (MHD_HTTP_NO_CONTENT == *response_code)
784  return NULL;
785  json = NULL;
786  if (0 == db->eno)
787  {
788  json = json_loadb (db->buf,
789  db->buf_size,
790  JSON_REJECT_DUPLICATES | JSON_DISABLE_EOF_CHECK,
791  &error);
792  if (NULL == json)
793  {
794  JSON_WARN (error);
795  *response_code = 0;
796  }
797  }
798  GNUNET_free (db->buf);
799  db->buf = NULL;
800  db->buf_size = 0;
801  if (NULL != json)
802  {
803  if (CURLE_OK !=
804  curl_easy_getinfo (eh,
805  CURLINFO_RESPONSE_CODE,
806  response_code))
807  {
808  /* unexpected error... */
809  GNUNET_break (0);
810  *response_code = 0;
811  }
812  }
813  return json;
814 }
815 
816 
824 int
825 GNUNET_CURL_append_header (struct GNUNET_CURL_Context *ctx, const char *header)
826 {
827  ctx->common_headers = curl_slist_append (ctx->common_headers, header);
828  if (NULL == ctx->common_headers)
829  return GNUNET_SYSERR;
830 
831  return GNUNET_OK;
832 }
833 
834 
835 #if ENABLE_BENCHMARK
836 static void
837 do_benchmark (CURLMsg *cmsg)
838 {
839  char *url = NULL;
840  double total_as_double = 0;
841  struct GNUNET_TIME_Relative total;
842  struct UrlRequestData *urd;
843  /* Some care required, as curl is using data types (long vs curl_off_t vs
844  * double) inconsistently to store byte count. */
845  curl_off_t size_curl = 0;
846  long size_long = 0;
847  uint64_t bytes_sent = 0;
848  uint64_t bytes_received = 0;
849 
850  GNUNET_break (CURLE_OK == curl_easy_getinfo (cmsg->easy_handle,
851  CURLINFO_TOTAL_TIME,
852  &total_as_double));
853  total.rel_value_us = total_as_double * 1000 * 1000;
854 
855  GNUNET_break (CURLE_OK == curl_easy_getinfo (cmsg->easy_handle,
856  CURLINFO_EFFECTIVE_URL,
857  &url));
858 
859  /* HEADER_SIZE + SIZE_DOWNLOAD_T is hopefully the total
860  number of bytes received, not clear from curl docs. */
861 
862  GNUNET_break (CURLE_OK == curl_easy_getinfo (cmsg->easy_handle,
863  CURLINFO_HEADER_SIZE,
864  &size_long));
865  bytes_received += size_long;
866 
867  GNUNET_break (CURLE_OK == curl_easy_getinfo (cmsg->easy_handle,
868  CURLINFO_SIZE_DOWNLOAD_T,
869  &size_curl));
870  bytes_received += size_curl;
871 
872  /* REQUEST_SIZE + SIZE_UPLOAD_T is hopefully the total number of bytes
873  sent, again docs are not completely clear. */
874 
875  GNUNET_break (CURLE_OK == curl_easy_getinfo (cmsg->easy_handle,
876  CURLINFO_REQUEST_SIZE,
877  &size_long));
878  bytes_sent += size_long;
879 
880  /* We obtain this value to check an invariant, but never use it otherwise. */
881  GNUNET_break (CURLE_OK == curl_easy_getinfo (cmsg->easy_handle,
882  CURLINFO_SIZE_UPLOAD_T,
883  &size_curl));
884 
885  /* CURLINFO_SIZE_UPLOAD_T <= CURLINFO_REQUEST_SIZE should
886  be an invariant.
887  As verified with
888  curl -w "foo%{size_request} -XPOST --data "ABC" $URL
889  the CURLINFO_REQUEST_SIZE should be the whole size of the request
890  including headers and body.
891  *///
892  GNUNET_break (size_curl <= size_long);
893 
894  urd = get_url_benchmark_data (url, (unsigned int) response_code);
895  urd->count++;
896  urd->time = GNUNET_TIME_relative_add (urd->time, total);
897  urd->time_max = GNUNET_TIME_relative_max (total, urd->time_max);
898  urd->bytes_sent += bytes_sent;
900 }
901 
902 
903 #endif
904 
905 
914 void
918 {
919  CURLMsg *cmsg;
920  int n_running;
921  int n_completed;
922 
923  (void) curl_multi_perform (ctx->multi,
924  &n_running);
925  while (NULL != (cmsg = curl_multi_info_read (ctx->multi, &n_completed)))
926  {
927  struct GNUNET_CURL_Job *job;
928  long response_code;
929  void *response;
930 
931  /* Only documented return value is CURLMSG_DONE */
932  GNUNET_break (CURLMSG_DONE == cmsg->msg);
933  GNUNET_assert (CURLE_OK == curl_easy_getinfo (cmsg->easy_handle,
934  CURLINFO_PRIVATE,
935  (char **) &job));
936  GNUNET_assert (job->ctx == ctx);
937  response_code = 0;
938  if (NULL != job->jcc_raw)
939  {
940  /* RAW mode, no parsing */
941  GNUNET_break (CURLE_OK ==
942  curl_easy_getinfo (job->easy_handle,
943  CURLINFO_RESPONSE_CODE,
944  &response_code));
945  job->jcc_raw (job->jcc_raw_cls,
946  response_code,
947  job->db.buf,
948  job->db.buf_size);
949  }
950  else
951  {
952  /* to be parsed via 'rp' */
953  response = rp (&job->db,
954  job->easy_handle,
955  &response_code);
956  job->jcc (job->jcc_cls,
957  response_code,
958  response);
959  rc (response);
960  }
961 #if ENABLE_BENCHMARK
962  do_benchmark (cmsg);
963 #endif
965  }
966 }
967 
968 
974 void
976 {
979  (GNUNET_CURL_ResponseCleaner) & json_decref);
980 }
981 
982 
1011 void
1013  fd_set *read_fd_set,
1014  fd_set *write_fd_set,
1015  fd_set *except_fd_set,
1016  int *max_fd,
1017  long *timeout)
1018 {
1019  long to;
1020  int m;
1021 
1022  m = -1;
1023  GNUNET_assert (CURLM_OK == curl_multi_fdset (ctx->multi,
1024  read_fd_set,
1025  write_fd_set,
1026  except_fd_set,
1027  &m));
1028  to = *timeout;
1029  *max_fd = GNUNET_MAX (m, *max_fd);
1030  GNUNET_assert (CURLM_OK == curl_multi_timeout (ctx->multi, &to));
1031 
1032  /* Only if what we got back from curl is smaller than what we
1033  already had (-1 == infinity!), then update timeout */
1034  if ((to < *timeout) && (-1 != to))
1035  *timeout = to;
1036  if ((-1 == (*timeout)) && (NULL != ctx->jobs_head))
1037  *timeout = to;
1038 }
1039 
1040 
1048 void
1050 {
1051  /* all jobs must have been cancelled at this time, assert this */
1052  GNUNET_assert (NULL == ctx->jobs_head);
1053  curl_share_cleanup (ctx->share);
1054  curl_multi_cleanup (ctx->multi);
1055  curl_slist_free_all (ctx->common_headers);
1056  GNUNET_free (ctx->userpass);
1057  GNUNET_free (ctx->certtype);
1058  GNUNET_free (ctx->certfile);
1059  GNUNET_free (ctx->keyfile);
1060  GNUNET_free (ctx->keypass);
1061  GNUNET_free (ctx);
1062 }
1063 
1064 
1068 __attribute__ ((constructor)) void
1069 GNUNET_CURL_constructor__ (void)
1070 {
1071  CURLcode ret;
1072 
1073  if (CURLE_OK != (ret = curl_global_init (CURL_GLOBAL_DEFAULT)))
1074  {
1075  CURL_STRERROR (GNUNET_ERROR_TYPE_ERROR, "curl_global_init", ret);
1076  curl_fail = 1;
1077  }
1078 }
1079 
1080 
1084 __attribute__ ((destructor)) void
1085 GNUNET_CURL_destructor__ (void)
1086 {
1087  if (curl_fail)
1088  return;
1089  curl_global_cleanup ();
1090 }
1091 
1092 
1093 /* end of curl.c */
#define GNUNET_CONTAINER_DLL_remove(head, tail, element)
Remove an element from a DLL.
#define CURL_STRERROR(type, function, code)
Log error related to CURL operations.
Definition: curl.c:43
struct GNUNET_CURL_Job * GNUNET_CURL_job_add2(struct GNUNET_CURL_Context *ctx, CURL *eh, const struct curl_slist *job_headers, GNUNET_CURL_JobCompletionCallback jcc, void *jcc_cls)
Schedule a CURL request to be executed and call the given jcc upon its completion.
Definition: curl.c:557
uint64_t rel_value_us
The actual value.
#define GNUNET_CONTAINER_DLL_insert(head, tail, element)
Insert an element at the head of a DLL.
library to make it easy to download JSON replies over HTTP
struct GNUNET_TIME_Relative GNUNET_TIME_relative_max(struct GNUNET_TIME_Relative t1, struct GNUNET_TIME_Relative t2)
Return the maximum of two relative time values.
Definition: time.c:287
struct GNUNET_CURL_Job * prev
We keep jobs in a DLL.
Definition: curl.c:82
#define GNUNET_assert(cond)
Use this for fatal errors that cannot be handled.
int GNUNET_CURL_is_valid_scope_id(const char *scope_id)
Return GNUNET_YES if given a valid scope ID and GNUNET_NO otherwise.
Definition: curl.c:326
int GNUNET_CURL_append_header(struct GNUNET_CURL_Context *ctx, const char *header)
Add custom request header.
Definition: curl.c:825
#define GNUNET_memcpy(dst, src, n)
Call memcpy() but check for n being 0 first.
static int ret
Return value of the commandline.
Definition: gnunet-abd.c:81
void GNUNET_CURL_fini(struct GNUNET_CURL_Context *ctx)
Cleanup library initialisation resources.
Definition: curl.c:1049
#define GNUNET_new(type)
Allocate a struct or union of the given type.
Identifier for an asynchronous execution context.
Struct for benchmark data for one URL.
Definition: benchmark.h:65
GNUNET_CURL_RescheduleCallback cb
Function we need to call whenever the event loop&#39;s socket set changed.
Definition: curl.c:167
struct GNUNET_TIME_Relative time_max
Slowest time to response.
Definition: benchmark.h:100
void(* GNUNET_CURL_JobCompletionCallback)(void *cls, long response_code, const void *response)
Function to call upon completion of a job.
#define GNUNET_strdup(a)
Wrapper around GNUNET_xstrdup_.
void GNUNET_CURL_job_cancel(struct GNUNET_CURL_Job *job)
Cancel a job.
Definition: curl.c:677
#define GNUNET_break(cond)
Use this for internal assertion violations that are not fatal (can be handled) but should not occur...
uint64_t count
How often was the URL requested?
Definition: benchmark.h:80
struct GNUNET_CURL_Job * GNUNET_CURL_job_add_with_ct_json(struct GNUNET_CURL_Context *ctx, CURL *eh, GNUNET_CURL_JobCompletionCallback jcc, void *jcc_cls)
Schedule a CURL request to be executed and call the given jcc upon its completion.
Definition: curl.c:623
void * jcc_cls
Closure for jcc.
Definition: curl.c:102
struct GNUNET_CURL_Job * GNUNET_CURL_job_add(struct GNUNET_CURL_Context *ctx, CURL *eh, GNUNET_CURL_JobCompletionCallback jcc, void *jcc_cls)
Schedule a CURL request to be executed and call the given jcc upon its completion.
Definition: curl.c:657
static struct GNUNET_ARM_MonitorHandle * m
Monitor connection with ARM.
Definition: gnunet-arm.c:104
struct GNUNET_CURL_Job * GNUNET_CURL_job_add_raw(struct GNUNET_CURL_Context *ctx, CURL *eh, const struct curl_slist *job_headers, GNUNET_CURL_RawJobCompletionCallback jcc, void *jcc_cls)
Schedule a CURL request to be executed and call the given jcc upon its completion.
Definition: curl.c:514
void *(* GNUNET_CURL_RawParser)(struct GNUNET_CURL_DownloadBuffer *db, CURL *eh, long *response_code)
Parses the raw response we got from the Web server.
GNUNET_CURL_JobCompletionCallback jcc
Function to call upon completion.
Definition: curl.c:97
struct GNUNET_CURL_Job * jobs_head
We keep jobs in a DLL.
Definition: curl.c:145
static struct GNUNET_TIME_Relative timeout
Desired timeout for the lookup (default is no timeout).
Definition: gnunet-abd.c:61
#define GNUNET_realloc(ptr, size)
Wrapper around realloc.
struct GNUNET_CURL_Job * next
We keep jobs in a DLL.
Definition: curl.c:77
#define JSON_WARN(error)
Print JSON parsing related error information.
Definition: curl.c:54
#define GNUNET_MAX(a, b)
Definition: gnunet_common.h:95
void GNUNET_CURL_extend_headers(struct GNUNET_CURL_Job *job, const struct curl_slist *extra_headers)
Add extra_headers to the HTTP headers for job.
Definition: curl.c:481
static struct curl_slist * setup_job_headers(struct GNUNET_CURL_Context *ctx, const struct curl_slist *job_headers)
Create the HTTP headers for the request.
Definition: curl.c:387
static CURLM * multi
Current multi-CURL handle.
CURLSH * share
Curl share handle.
Definition: curl.c:140
static char buf[2048]
static int curl_fail
Failsafe flag.
Definition: curl.c:67
void GNUNET_CURL_set_userpass(struct GNUNET_CURL_Context *ctx, const char *userpass)
Force use of the provided username and password for client authentication for all operations performe...
Definition: curl.c:213
Context.
Definition: curl.c:130
uint64_t bytes_sent
How many bytes were sent in total to request the URL.
Definition: benchmark.h:85
struct GNUNET_TIME_Relative time
Total time spent requesting this URL.
Definition: benchmark.h:95
void GNUNET_async_scope_get(struct GNUNET_AsyncScopeSave *scope_ret)
Get the current async scope.
char * keyfile
File with the private key to authenticate the TLS client, or NULL.
Definition: curl.c:194
GNUNET_CURL_RawJobCompletionCallback jcc_raw
Function to call upon completion.
Definition: curl.c:107
void GNUNET_CURL_set_tlscert(struct GNUNET_CURL_Context *ctx, const char *certtype, const char *certfile, const char *keyfile, const char *keypass)
Force use of the provided TLS client certificate for client authentication for all operations perform...
Definition: curl.c:238
void(* GNUNET_CURL_ResponseCleaner)(void *response)
Deallocate the response.
__attribute__((constructor))
Initial global setup logic, specifically runs the Curl setup.
Definition: curl.c:1068
CURLM * multi
Curl multi handle.
Definition: curl.c:135
static unsigned int size
Size of the "table".
Definition: peer.c:67
uint64_t bytes_received
How many bytes were received in total as response to requesting this URL.
Definition: benchmark.h:90
int have_scope
GNUNET_YES unless this saved scope is the unnamed root scope.
Saved async scope identifier or root scope.
CURL * easy_handle
Easy handle of the job.
Definition: curl.c:87
#define GNUNET_MAX_MALLOC_CHECKED
Maximum allocation with GNUNET_malloc macro.
static struct GNUNET_SCHEDULER_Task * job
Task for main job.
Definition: gnunet-cadet.c:137
struct GNUNET_TIME_Relative GNUNET_TIME_relative_add(struct GNUNET_TIME_Relative a1, struct GNUNET_TIME_Relative a2)
Add relative times together.
Definition: time.c:579
char * keypass
Passphrase to decrypt keyfile, or NULL.
Definition: curl.c:199
static bool is_json(const char *ct)
Test if the given content type ct is JSON.
Definition: curl.c:699
void GNUNET_CURL_get_select_info(struct GNUNET_CURL_Context *ctx, fd_set *read_fd_set, fd_set *write_fd_set, fd_set *except_fd_set, int *max_fd, long *timeout)
Obtain the information for a select() call to wait until GNUNET_CURL_perform() is ready again...
Definition: curl.c:1012
Buffer data structure we use to buffer the HTTP download before giving it to the JSON parser...
struct GNUNET_AsyncScopeId scope_id
Saved scope.
void GNUNET_CURL_perform(struct GNUNET_CURL_Context *ctx)
Run the main event loop for the HTTP interaction.
Definition: curl.c:975
char * certtype
Type of the TLS client certificate used, or NULL.
Definition: curl.c:183
void * buf
Download buffer.
void(* GNUNET_CURL_RescheduleCallback)(void *cls)
Function called by the context to ask for the event loop to be rescheduled, that is the application s...
void * cb_cls
Closure for cb.
Definition: curl.c:172
Jobs are CURL requests running within a struct GNUNET_CURL_Context.
Definition: curl.c:72
#define GNUNET_log(kind,...)
struct GNUNET_CURL_Context * GNUNET_CURL_init(GNUNET_CURL_RescheduleCallback cb, void *cb_cls)
Initialise this library.
Definition: curl.c:268
const char * async_scope_id_header
If non-NULL, the async scope ID is sent in a request header of this name.
Definition: curl.c:161
static char * rp
Relying party.
struct GNUNET_CURL_Job * jobs_tail
We keep jobs in a DLL.
Definition: curl.c:150
static struct MHD_Response * response
Our canonical response.
void(* GNUNET_CURL_RawJobCompletionCallback)(void *cls, long response_code, const void *body, size_t body_size)
Function to call upon completion of a raw job.
struct GNUNET_CURL_DownloadBuffer db
Buffer for response received from CURL.
Definition: curl.c:117
struct UrlRequestData * get_url_benchmark_data(char *url, unsigned int status)
Get benchmark data for a URL.
Definition: benchmark.c:241
char * GNUNET_STRINGS_data_to_string_alloc(const void *buf, size_t size)
Return the base32crockford encoding of the given buffer.
Definition: strings.c:936
size_t buf_size
The size of the download buffer.
void GNUNET_CURL_perform2(struct GNUNET_CURL_Context *ctx, GNUNET_CURL_RawParser rp, GNUNET_CURL_ResponseCleaner rc)
Run the main event loop for the HTTP interaction.
Definition: curl.c:915
struct curl_slist * job_headers
Headers used for this job, the list needs to be freed after the job has finished. ...
Definition: curl.c:123
char * certfile
File with the TLS client certificate, or NULL.
Definition: curl.c:188
void GNUNET_CURL_enable_async_scope_header(struct GNUNET_CURL_Context *ctx, const char *header_name)
Enable sending the async scope ID as a header.
Definition: curl.c:309
void * jcc_raw_cls
Closure for jcc_raw.
Definition: curl.c:112
char * userpass
USERNAME:PASSWORD to use for client-authentication with all requests of this context, or NULL.
Definition: curl.c:178
#define GNUNET_free(ptr)
Wrapper around free.
struct GNUNET_CURL_Context * ctx
Context this job runs in.
Definition: curl.c:92
struct curl_slist * common_headers
Headers common for all requests in the context.
Definition: curl.c:155
static struct GNUNET_CURL_Job * setup_job(CURL *eh, struct GNUNET_CURL_Context *ctx, struct curl_slist *all_headers)
Create a job.
Definition: curl.c:436
Time for relative time used by GNUnet, in microseconds.
int eno
Error code (based on libc errno) if we failed to download (i.e.
void * GNUNET_CURL_download_get_result_(struct GNUNET_CURL_DownloadBuffer *db, CURL *eh, long *response_code)
Obtain information about the final result about the HTTP download.
Definition: curl.c:745
static size_t download_cb(char *bufptr, size_t size, size_t nitems, void *cls)
Callback used when downloading the reply to an HTTP request.
Definition: curl.c:351