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  if (CURLE_OK !=
763  curl_easy_getinfo (eh,
764  CURLINFO_RESPONSE_CODE,
765  response_code))
766  {
767  /* unexpected error... */
768  GNUNET_break (0);
769  *response_code = 0;
770  }
771  if ((CURLE_OK !=
772  curl_easy_getinfo (eh,
773  CURLINFO_CONTENT_TYPE,
774  &ct)) ||
775  (NULL == ct) ||
776  (! is_json (ct)))
777  {
778  /* No content type or explicitly not JSON, refuse to parse
779  (but keep response code) */
780  if (0 != db->buf_size)
782  "Did NOT detect response `%.*s' as JSON\n",
783  (int) db->buf_size,
784  (const char *) db->buf);
785  return NULL;
786  }
787  if (MHD_HTTP_NO_CONTENT == *response_code)
788  return NULL;
789  if (0 == *response_code)
790  {
791  char *url;
792 
793  if (CURLE_OK !=
794  curl_easy_getinfo (eh,
795  CURLINFO_EFFECTIVE_URL,
796  &url))
797  url = "<unknown URL>";
799  "Failed to download response from `%s': \n",
800  url);
801  return NULL;
802  }
803  json = NULL;
804  if (0 == db->eno)
805  {
806  json = json_loadb (db->buf,
807  db->buf_size,
808  JSON_REJECT_DUPLICATES | JSON_DISABLE_EOF_CHECK,
809  &error);
810  if (NULL == json)
811  {
812  JSON_WARN (error);
813  *response_code = 0;
814  }
815  }
816  GNUNET_free (db->buf);
817  db->buf = NULL;
818  db->buf_size = 0;
819  return json;
820 }
821 
822 
832  const char *header)
833 {
834  ctx->common_headers = curl_slist_append (ctx->common_headers, header);
835  if (NULL == ctx->common_headers)
836  return GNUNET_SYSERR;
837 
838  return GNUNET_OK;
839 }
840 
841 
842 #if ENABLE_BENCHMARK
843 static void
844 do_benchmark (CURLMsg *cmsg)
845 {
846  char *url = NULL;
847  double total_as_double = 0;
848  struct GNUNET_TIME_Relative total;
849  struct UrlRequestData *urd;
850  /* Some care required, as curl is using data types (long vs curl_off_t vs
851  * double) inconsistently to store byte count. */
852  curl_off_t size_curl = 0;
853  long size_long = 0;
854  uint64_t bytes_sent = 0;
855  uint64_t bytes_received = 0;
856 
857  GNUNET_break (CURLE_OK == curl_easy_getinfo (cmsg->easy_handle,
858  CURLINFO_TOTAL_TIME,
859  &total_as_double));
860  total.rel_value_us = total_as_double * 1000 * 1000;
861 
862  GNUNET_break (CURLE_OK == curl_easy_getinfo (cmsg->easy_handle,
863  CURLINFO_EFFECTIVE_URL,
864  &url));
865 
866  /* HEADER_SIZE + SIZE_DOWNLOAD_T is hopefully the total
867  number of bytes received, not clear from curl docs. */
868 
869  GNUNET_break (CURLE_OK == curl_easy_getinfo (cmsg->easy_handle,
870  CURLINFO_HEADER_SIZE,
871  &size_long));
872  bytes_received += size_long;
873 
874  GNUNET_break (CURLE_OK == curl_easy_getinfo (cmsg->easy_handle,
875  CURLINFO_SIZE_DOWNLOAD_T,
876  &size_curl));
877  bytes_received += size_curl;
878 
879  /* REQUEST_SIZE + SIZE_UPLOAD_T is hopefully the total number of bytes
880  sent, again docs are not completely clear. */
881 
882  GNUNET_break (CURLE_OK == curl_easy_getinfo (cmsg->easy_handle,
883  CURLINFO_REQUEST_SIZE,
884  &size_long));
885  bytes_sent += size_long;
886 
887  /* We obtain this value to check an invariant, but never use it otherwise. */
888  GNUNET_break (CURLE_OK == curl_easy_getinfo (cmsg->easy_handle,
889  CURLINFO_SIZE_UPLOAD_T,
890  &size_curl));
891 
892  /* CURLINFO_SIZE_UPLOAD_T <= CURLINFO_REQUEST_SIZE should
893  be an invariant.
894  As verified with
895  curl -w "foo%{size_request} -XPOST --data "ABC" $URL
896  the CURLINFO_REQUEST_SIZE should be the whole size of the request
897  including headers and body.
898  */
899  GNUNET_break (size_curl <= size_long);
900 
901  urd = get_url_benchmark_data (url, (unsigned int) response_code);
902  urd->count++;
903  urd->time = GNUNET_TIME_relative_add (urd->time, total);
904  urd->time_max = GNUNET_TIME_relative_max (total, urd->time_max);
905  urd->bytes_sent += bytes_sent;
907 }
908 
909 
910 #endif
911 
912 
921 void
925 {
926  CURLMsg *cmsg;
927  int n_running;
928  int n_completed;
929 
930  (void) curl_multi_perform (ctx->multi,
931  &n_running);
932  while (NULL != (cmsg = curl_multi_info_read (ctx->multi, &n_completed)))
933  {
934  struct GNUNET_CURL_Job *job;
935  long response_code;
936  void *response;
937 
938  /* Only documented return value is CURLMSG_DONE */
939  GNUNET_break (CURLMSG_DONE == cmsg->msg);
940  GNUNET_assert (CURLE_OK == curl_easy_getinfo (cmsg->easy_handle,
941  CURLINFO_PRIVATE,
942  (char **) &job));
943  GNUNET_assert (job->ctx == ctx);
944  response_code = 0;
945  if (NULL != job->jcc_raw)
946  {
947  /* RAW mode, no parsing */
948  GNUNET_break (CURLE_OK ==
949  curl_easy_getinfo (job->easy_handle,
950  CURLINFO_RESPONSE_CODE,
951  &response_code));
952  job->jcc_raw (job->jcc_raw_cls,
953  response_code,
954  job->db.buf,
955  job->db.buf_size);
956  }
957  else
958  {
959  /* to be parsed via 'rp' */
960  response = rp (&job->db,
961  job->easy_handle,
962  &response_code);
963  job->jcc (job->jcc_cls,
964  response_code,
965  response);
966  rc (response);
967  }
968 #if ENABLE_BENCHMARK
969  do_benchmark (cmsg);
970 #endif
972  }
973 }
974 
975 
981 void
983 {
986  (GNUNET_CURL_ResponseCleaner) & json_decref);
987 }
988 
989 
1018 void
1020  fd_set *read_fd_set,
1021  fd_set *write_fd_set,
1022  fd_set *except_fd_set,
1023  int *max_fd,
1024  long *timeout)
1025 {
1026  long to;
1027  int m;
1028 
1029  m = -1;
1030  GNUNET_assert (CURLM_OK == curl_multi_fdset (ctx->multi,
1031  read_fd_set,
1032  write_fd_set,
1033  except_fd_set,
1034  &m));
1035  to = *timeout;
1036  *max_fd = GNUNET_MAX (m, *max_fd);
1037  GNUNET_assert (CURLM_OK == curl_multi_timeout (ctx->multi, &to));
1038 
1039  /* Only if what we got back from curl is smaller than what we
1040  already had (-1 == infinity!), then update timeout */
1041  if ((to < *timeout) && (-1 != to))
1042  *timeout = to;
1043  if ((-1 == (*timeout)) && (NULL != ctx->jobs_head))
1044  *timeout = to;
1045 }
1046 
1047 
1055 void
1057 {
1058  /* all jobs must have been cancelled at this time, assert this */
1059  GNUNET_assert (NULL == ctx->jobs_head);
1060  curl_share_cleanup (ctx->share);
1061  curl_multi_cleanup (ctx->multi);
1062  curl_slist_free_all (ctx->common_headers);
1063  GNUNET_free (ctx->userpass);
1064  GNUNET_free (ctx->certtype);
1065  GNUNET_free (ctx->certfile);
1066  GNUNET_free (ctx->keyfile);
1067  GNUNET_free (ctx->keypass);
1068  GNUNET_free (ctx);
1069 }
1070 
1071 
1075 __attribute__ ((constructor)) void
1076 GNUNET_CURL_constructor__ (void)
1077 {
1078  CURLcode ret;
1079 
1080  if (CURLE_OK != (ret = curl_global_init (CURL_GLOBAL_DEFAULT)))
1081  {
1082  CURL_STRERROR (GNUNET_ERROR_TYPE_ERROR, "curl_global_init", ret);
1083  curl_fail = 1;
1084  }
1085 }
1086 
1087 
1091 __attribute__ ((destructor)) void
1092 GNUNET_CURL_destructor__ (void)
1093 {
1094  if (curl_fail)
1095  return;
1096  curl_global_cleanup ();
1097 }
1098 
1099 
1100 /* 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
#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
GNUNET_GenericReturnValue
Named constants for return values.
Definition: gnunet_common.h:83
void GNUNET_CURL_fini(struct GNUNET_CURL_Context *ctx)
Cleanup library initialisation resources.
Definition: curl.c:1056
#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
enum GNUNET_GenericReturnValue GNUNET_CURL_append_header(struct GNUNET_CURL_Context *ctx, const char *header)
Add custom request header.
Definition: curl.c:831
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:1075
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:1019
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:982
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:750
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:922
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