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;
393  NULL != curr;
394  curr = curr->next)
395  {
396  GNUNET_assert (NULL !=
397  (all_headers = curl_slist_append (all_headers,
398  curr->data)));
399  }
400 
401  for (const struct curl_slist *curr = ctx->common_headers;
402  NULL != curr;
403  curr = curr->next)
404  {
405  GNUNET_assert (NULL !=
406  (all_headers = curl_slist_append (all_headers,
407  curr->data)));
408  }
409 
410  if (NULL != ctx->async_scope_id_header)
411  {
412  struct GNUNET_AsyncScopeSave scope;
413 
414  GNUNET_async_scope_get (&scope);
415  if (GNUNET_YES == scope.have_scope)
416  {
417  char *aid_header;
418 
419  aid_header =
421  &scope.scope_id,
422  sizeof(struct GNUNET_AsyncScopeId));
423  GNUNET_assert (NULL != aid_header);
424  GNUNET_assert (NULL != curl_slist_append (all_headers, aid_header));
425  GNUNET_free (aid_header);
426  }
427  }
428  return all_headers;
429 }
430 
431 
440 static struct GNUNET_CURL_Job *
441 setup_job (CURL *eh,
442  struct GNUNET_CURL_Context *ctx,
443  struct curl_slist *all_headers)
444 {
445  struct GNUNET_CURL_Job *job;
446 
447  if (CURLE_OK !=
448  curl_easy_setopt (eh, CURLOPT_HTTPHEADER, all_headers))
449  {
450  GNUNET_break (0);
451  curl_slist_free_all (all_headers);
452  curl_easy_cleanup (eh);
453  return NULL;
454  }
455  job = GNUNET_new (struct GNUNET_CURL_Job);
456  job->job_headers = all_headers;
457 
458  if ((CURLE_OK != curl_easy_setopt (eh, CURLOPT_PRIVATE, job)) ||
459  (CURLE_OK !=
460  curl_easy_setopt (eh, CURLOPT_WRITEFUNCTION, &download_cb)) ||
461  (CURLE_OK != curl_easy_setopt (eh, CURLOPT_WRITEDATA, &job->db)) ||
462  (CURLE_OK != curl_easy_setopt (eh, CURLOPT_SHARE, ctx->share)) ||
463  (CURLM_OK != curl_multi_add_handle (ctx->multi, eh)))
464  {
465  GNUNET_break (0);
466  GNUNET_free (job);
467  curl_easy_cleanup (eh);
468  return NULL;
469  }
470  job->easy_handle = eh;
471  job->ctx = ctx;
473  ctx->jobs_tail,
474  job);
475  return job;
476 }
477 
478 
485 void
487  const struct curl_slist *extra_headers)
488 {
489  struct curl_slist *all_headers = job->job_headers;
490 
491  for (const struct curl_slist *curr = extra_headers;
492  NULL != curr;
493  curr = curr->next)
494  {
495  GNUNET_assert (NULL !=
496  (all_headers = curl_slist_append (all_headers,
497  curr->data)));
498  }
499  job->job_headers = all_headers;
500 }
501 
502 
518 struct GNUNET_CURL_Job *
520  CURL *eh,
521  const struct curl_slist *job_headers,
523  void *jcc_cls)
524 {
525  struct GNUNET_CURL_Job *job;
526  struct curl_slist *all_headers;
527 
528  GNUNET_assert (NULL != jcc);
529  all_headers = setup_job_headers (ctx,
530  job_headers);
531  if (NULL == (job = setup_job (eh,
532  ctx,
533  all_headers)))
534  return NULL;
535  job->jcc_raw = jcc;
536  job->jcc_raw_cls = jcc_cls;
537  ctx->cb (ctx->cb_cls);
538  return job;
539 }
540 
541 
561 struct GNUNET_CURL_Job *
563  CURL *eh,
564  const struct curl_slist *job_headers,
566  void *jcc_cls)
567 {
568  struct GNUNET_CURL_Job *job;
569  struct curl_slist *all_headers;
570 
571  GNUNET_assert (NULL != jcc);
572  if ( (NULL != ctx->userpass) &&
573  (0 != curl_easy_setopt (eh,
574  CURLOPT_USERPWD,
575  ctx->userpass)) )
576  return NULL;
577  if ( (NULL != ctx->certfile) &&
578  (0 != curl_easy_setopt (eh,
579  CURLOPT_SSLCERT,
580  ctx->certfile)) )
581  return NULL;
582  if ( (NULL != ctx->certtype) &&
583  (0 != curl_easy_setopt (eh,
584  CURLOPT_SSLCERTTYPE,
585  ctx->certtype)) )
586  return NULL;
587  if ( (NULL != ctx->keyfile) &&
588  (0 != curl_easy_setopt (eh,
589  CURLOPT_SSLKEY,
590  ctx->keyfile)) )
591  return NULL;
592  if ( (NULL != ctx->keypass) &&
593  (0 != curl_easy_setopt (eh,
594  CURLOPT_KEYPASSWD,
595  ctx->keypass)) )
596  return NULL;
597 
598  all_headers = setup_job_headers (ctx,
599  job_headers);
600  if (NULL == (job = setup_job (eh,
601  ctx,
602  all_headers)))
603  return NULL;
604 
605  job->jcc = jcc;
606  job->jcc_cls = jcc_cls;
607  ctx->cb (ctx->cb_cls);
608  return job;
609 }
610 
611 
627 struct GNUNET_CURL_Job *
629  CURL *eh,
631  void *jcc_cls)
632 {
633  struct GNUNET_CURL_Job *job;
634  struct curl_slist *job_headers = NULL;
635 
636  GNUNET_assert (NULL != (job_headers =
637  curl_slist_append (NULL,
638  "Content-Type: application/json")));
639  job = GNUNET_CURL_job_add2 (ctx,
640  eh,
641  job_headers,
642  jcc,
643  jcc_cls);
644  curl_slist_free_all (job_headers);
645  return job;
646 }
647 
648 
661 struct GNUNET_CURL_Job *
663  CURL *eh,
665  void *jcc_cls)
666 {
667  return GNUNET_CURL_job_add2 (ctx,
668  eh,
669  NULL,
670  jcc,
671  jcc_cls);
672 }
673 
674 
681 void
683 {
684  struct GNUNET_CURL_Context *ctx = job->ctx;
685 
687  GNUNET_break (CURLM_OK ==
688  curl_multi_remove_handle (ctx->multi, job->easy_handle));
689  curl_easy_cleanup (job->easy_handle);
690  GNUNET_free (job->db.buf);
691  curl_slist_free_all (job->job_headers);
692  ctx->cb (ctx->cb_cls);
693  GNUNET_free (job);
694 }
695 
696 
703 static bool
704 is_json (const char *ct)
705 {
706  const char *semi;
707 
708  /* check for "application/json" exact match */
709  if (0 == strcasecmp (ct,
710  "application/json"))
711  return true;
712  /* check for "application/json;[ANYTHING]" */
713  semi = strchr (ct,
714  ';');
715  /* also allow "application/json [ANYTHING]" (note the space!) */
716  if (NULL == semi)
717  semi = strchr (ct,
718  ' ');
719  if (NULL == semi)
720  return false; /* no delimiter we accept, forget it */
721  if (semi - ct != strlen ("application/json"))
722  return false; /* delimiter past desired length, forget it */
723  if (0 == strncasecmp (ct,
724  "application/json",
725  strlen ("application/json")))
726  return true; /* OK */
727  return false;
728 }
729 
730 
749 void *
751  CURL *eh,
752  long *response_code)
753 {
754  json_t *json;
755  json_error_t error;
756  char *ct;
757 
759  "Downloaded body: %.*s\n",
760  (int) db->buf_size,
761  (char *) db->buf);
762 
763  if ((CURLE_OK !=
764  curl_easy_getinfo (eh,
765  CURLINFO_CONTENT_TYPE,
766  &ct)) ||
767  (NULL == ct) ||
768  (! is_json (ct)))
769  {
770  /* No content type or explicitly not JSON, refuse to parse
771  (but keep response code) */
772  if (CURLE_OK !=
773  curl_easy_getinfo (eh,
774  CURLINFO_RESPONSE_CODE,
775  response_code))
776  {
777  /* unexpected error... */
778  GNUNET_break (0);
779  *response_code = 0;
780  }
781  if (0 != db->buf_size)
783  "Did NOT detect response `%.*s' as JSON\n",
784  (int) db->buf_size,
785  (const char *) db->buf);
786  return NULL;
787  }
788  if (MHD_HTTP_NO_CONTENT == *response_code)
789  return NULL;
790  json = NULL;
791  if (0 == db->eno)
792  {
793  json = json_loadb (db->buf,
794  db->buf_size,
795  JSON_REJECT_DUPLICATES | JSON_DISABLE_EOF_CHECK,
796  &error);
797  if (NULL == json)
798  {
799  JSON_WARN (error);
800  *response_code = 0;
801  }
802  }
803  GNUNET_free (db->buf);
804  db->buf = NULL;
805  db->buf_size = 0;
806  if (NULL != json)
807  {
808  if (CURLE_OK !=
809  curl_easy_getinfo (eh,
810  CURLINFO_RESPONSE_CODE,
811  response_code))
812  {
813  /* unexpected error... */
814  GNUNET_break (0);
815  *response_code = 0;
816  }
817  }
818  return json;
819 }
820 
821 
829 int
830 GNUNET_CURL_append_header (struct GNUNET_CURL_Context *ctx, const char *header)
831 {
832  ctx->common_headers = curl_slist_append (ctx->common_headers, header);
833  if (NULL == ctx->common_headers)
834  return GNUNET_SYSERR;
835 
836  return GNUNET_OK;
837 }
838 
839 
840 #if ENABLE_BENCHMARK
841 static void
842 do_benchmark (CURLMsg *cmsg)
843 {
844  char *url = NULL;
845  double total_as_double = 0;
846  struct GNUNET_TIME_Relative total;
847  struct UrlRequestData *urd;
848  /* Some care required, as curl is using data types (long vs curl_off_t vs
849  * double) inconsistently to store byte count. */
850  curl_off_t size_curl = 0;
851  long size_long = 0;
852  uint64_t bytes_sent = 0;
853  uint64_t bytes_received = 0;
854 
855  GNUNET_break (CURLE_OK == curl_easy_getinfo (cmsg->easy_handle,
856  CURLINFO_TOTAL_TIME,
857  &total_as_double));
858  total.rel_value_us = total_as_double * 1000 * 1000;
859 
860  GNUNET_break (CURLE_OK == curl_easy_getinfo (cmsg->easy_handle,
861  CURLINFO_EFFECTIVE_URL,
862  &url));
863 
864  /* HEADER_SIZE + SIZE_DOWNLOAD_T is hopefully the total
865  number of bytes received, not clear from curl docs. */
866 
867  GNUNET_break (CURLE_OK == curl_easy_getinfo (cmsg->easy_handle,
868  CURLINFO_HEADER_SIZE,
869  &size_long));
870  bytes_received += size_long;
871 
872  GNUNET_break (CURLE_OK == curl_easy_getinfo (cmsg->easy_handle,
873  CURLINFO_SIZE_DOWNLOAD_T,
874  &size_curl));
875  bytes_received += size_curl;
876 
877  /* REQUEST_SIZE + SIZE_UPLOAD_T is hopefully the total number of bytes
878  sent, again docs are not completely clear. */
879 
880  GNUNET_break (CURLE_OK == curl_easy_getinfo (cmsg->easy_handle,
881  CURLINFO_REQUEST_SIZE,
882  &size_long));
883  bytes_sent += size_long;
884 
885  /* We obtain this value to check an invariant, but never use it otherwise. */
886  GNUNET_break (CURLE_OK == curl_easy_getinfo (cmsg->easy_handle,
887  CURLINFO_SIZE_UPLOAD_T,
888  &size_curl));
889 
890  /* CURLINFO_SIZE_UPLOAD_T <= CURLINFO_REQUEST_SIZE should
891  be an invariant.
892  As verified with
893  curl -w "foo%{size_request} -XPOST --data "ABC" $URL
894  the CURLINFO_REQUEST_SIZE should be the whole size of the request
895  including headers and body.
896  *///
897  GNUNET_break (size_curl <= size_long);
898 
899  urd = get_url_benchmark_data (url, (unsigned int) response_code);
900  urd->count++;
901  urd->time = GNUNET_TIME_relative_add (urd->time, total);
902  urd->time_max = GNUNET_TIME_relative_max (total, urd->time_max);
903  urd->bytes_sent += bytes_sent;
905 }
906 
907 
908 #endif
909 
910 
919 void
923 {
924  CURLMsg *cmsg;
925  int n_running;
926  int n_completed;
927 
928  (void) curl_multi_perform (ctx->multi,
929  &n_running);
930  while (NULL != (cmsg = curl_multi_info_read (ctx->multi, &n_completed)))
931  {
932  struct GNUNET_CURL_Job *job;
933  long response_code;
934  void *response;
935 
936  /* Only documented return value is CURLMSG_DONE */
937  GNUNET_break (CURLMSG_DONE == cmsg->msg);
938  GNUNET_assert (CURLE_OK == curl_easy_getinfo (cmsg->easy_handle,
939  CURLINFO_PRIVATE,
940  (char **) &job));
941  GNUNET_assert (job->ctx == ctx);
942  response_code = 0;
943  if (NULL != job->jcc_raw)
944  {
945  /* RAW mode, no parsing */
946  GNUNET_break (CURLE_OK ==
947  curl_easy_getinfo (job->easy_handle,
948  CURLINFO_RESPONSE_CODE,
949  &response_code));
950  job->jcc_raw (job->jcc_raw_cls,
951  response_code,
952  job->db.buf,
953  job->db.buf_size);
954  }
955  else
956  {
957  /* to be parsed via 'rp' */
958  response = rp (&job->db,
959  job->easy_handle,
960  &response_code);
961  job->jcc (job->jcc_cls,
962  response_code,
963  response);
964  rc (response);
965  }
966 #if ENABLE_BENCHMARK
967  do_benchmark (cmsg);
968 #endif
970  }
971 }
972 
973 
979 void
981 {
984  (GNUNET_CURL_ResponseCleaner) & json_decref);
985 }
986 
987 
1016 void
1018  fd_set *read_fd_set,
1019  fd_set *write_fd_set,
1020  fd_set *except_fd_set,
1021  int *max_fd,
1022  long *timeout)
1023 {
1024  long to;
1025  int m;
1026 
1027  m = -1;
1028  GNUNET_assert (CURLM_OK == curl_multi_fdset (ctx->multi,
1029  read_fd_set,
1030  write_fd_set,
1031  except_fd_set,
1032  &m));
1033  to = *timeout;
1034  *max_fd = GNUNET_MAX (m, *max_fd);
1035  GNUNET_assert (CURLM_OK == curl_multi_timeout (ctx->multi, &to));
1036 
1037  /* Only if what we got back from curl is smaller than what we
1038  already had (-1 == infinity!), then update timeout */
1039  if ((to < *timeout) && (-1 != to))
1040  *timeout = to;
1041  if ((-1 == (*timeout)) && (NULL != ctx->jobs_head))
1042  *timeout = to;
1043 }
1044 
1045 
1053 void
1055 {
1056  /* all jobs must have been cancelled at this time, assert this */
1057  GNUNET_assert (NULL == ctx->jobs_head);
1058  curl_share_cleanup (ctx->share);
1059  curl_multi_cleanup (ctx->multi);
1060  curl_slist_free_all (ctx->common_headers);
1061  GNUNET_free (ctx->userpass);
1062  GNUNET_free (ctx->certtype);
1063  GNUNET_free (ctx->certfile);
1064  GNUNET_free (ctx->keyfile);
1065  GNUNET_free (ctx->keypass);
1066  GNUNET_free (ctx);
1067 }
1068 
1069 
1073 __attribute__ ((constructor)) void
1074 GNUNET_CURL_constructor__ (void)
1075 {
1076  CURLcode ret;
1077 
1078  if (CURLE_OK != (ret = curl_global_init (CURL_GLOBAL_DEFAULT)))
1079  {
1080  CURL_STRERROR (GNUNET_ERROR_TYPE_ERROR, "curl_global_init", ret);
1081  curl_fail = 1;
1082  }
1083 }
1084 
1085 
1089 __attribute__ ((destructor)) void
1090 GNUNET_CURL_destructor__ (void)
1091 {
1092  if (curl_fail)
1093  return;
1094  curl_global_cleanup ();
1095 }
1096 
1097 
1098 /* 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:562
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:208
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:830
#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:1054
#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:682
#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:628
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:662
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:519
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:486
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:1073
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:411
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:704
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:1017
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:980
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:937
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:920
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:441
Time for relative time used by GNUnet, in microseconds.
int eno
Error code (based on libc errno) if we failed to download (e.g.
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:750
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