GNUnet 0.28.1-dev.5-1-gae1c02d74
 
Loading...
Searching...
No Matches
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#include "curl_internal.h"
31
32#if ENABLE_BENCHMARK
33#include "../util/benchmark.h"
34#endif
35
39#define DEBUG 0
40
48#define CURL_STRERROR(type, function, code) \
49 GNUNET_log (type, \
50 "Curl function `%s' has failed at `%s:%d' with error: %s\n", \
51 function, \
52 __FILE__, \
53 __LINE__, \
54 curl_easy_strerror (code));
55
59#define JSON_WARN(error) \
60 GNUNET_log (GNUNET_ERROR_TYPE_WARNING, \
61 "JSON parsing failed at %s:%u: %s (%s)\n", \
62 __FILE__, \
63 __LINE__, \
64 error.text, \
65 error.source)
66
67
72static int curl_fail;
73
147
148
153{
157 CURLM *multi;
158
162 CURLSH *share;
163
168
173
177 struct curl_slist *common_headers;
178
184
190
194 void *cb_cls;
195
200 char *userpass;
201
205 char *certtype;
206
210 char *certfile;
211
216 char *keyfile;
217
221 char *keypass;
222
223};
224
225
226void
228 const char *userpass)
229{
230 GNUNET_free (ctx->userpass);
231 if (NULL != userpass)
232 ctx->userpass = GNUNET_strdup (userpass);
233}
234
235
236void
238 const char *certtype,
239 const char *certfile,
240 const char *keyfile,
241 const char *keypass)
242{
243 GNUNET_free (ctx->certtype);
244 GNUNET_free (ctx->certfile);
245 GNUNET_free (ctx->keyfile);
246 GNUNET_free (ctx->keypass);
247 if (NULL != certtype)
248 ctx->certtype = GNUNET_strdup (certtype);
249 if (NULL != certfile)
250 ctx->certfile = GNUNET_strdup (certfile);
251 if (NULL != keyfile)
252 ctx->keyfile = GNUNET_strdup (keyfile);
253 if (NULL != keypass)
254 ctx->keypass = GNUNET_strdup (keypass);
255}
256
257
258struct GNUNET_CURL_Context *
260 void *cb_cls)
261{
262 struct GNUNET_CURL_Context *ctx;
263 CURLM *multi;
264 CURLSH *share;
265
266 if (curl_fail)
267 {
269 "Curl was not initialised properly\n");
270 return NULL;
271 }
272 if (NULL == (multi = curl_multi_init ()))
273 {
275 "Failed to create a Curl multi handle\n");
276 return NULL;
277 }
278 if (NULL == (share = curl_share_init ()))
279 {
281 "Failed to create a Curl share handle\n");
282 return NULL;
283 }
285 ctx->cb = cb;
286 ctx->cb_cls = cb_cls;
287 ctx->multi = multi;
288 ctx->share = share;
289 return ctx;
290}
291
292
293void
295 const char *header_name)
296{
297 ctx->async_scope_id_header = header_name;
298}
299
300
302GNUNET_CURL_is_valid_scope_id (const char *scope_id)
303{
304 if (strlen (scope_id) >= 64)
305 return GNUNET_NO;
306 for (size_t i = 0; i < strlen (scope_id); i++)
307 if (! (isalnum (scope_id[i]) || (scope_id[i] == '-')))
308 return GNUNET_NO;
309 return GNUNET_YES;
310}
311
312
326static size_t
327download_cb (char *bufptr,
328 size_t size,
329 size_t nitems,
330 void *cls)
331{
332 struct GNUNET_CURL_DownloadBuffer *db = cls;
333 size_t msize;
334 void *buf;
335
336 if (0 == size * nitems)
337 {
338 /* Nothing (left) to do */
339 return 0;
340 }
341 msize = size * nitems;
342 if ((msize + db->buf_size) >= GNUNET_MAX_MALLOC_CHECKED)
343 {
344 db->eno = ENOMEM;
345 return 0; /* signals an error to curl */
346 }
347 db->buf = GNUNET_realloc (db->buf,
348 db->buf_size + msize);
349 buf = db->buf + db->buf_size;
350 GNUNET_memcpy (buf, bufptr, msize);
351 db->buf_size += msize;
352 return msize;
353}
354
355
363static struct curl_slist *
365 const struct curl_slist *job_headers)
366{
367 struct curl_slist *all_headers = NULL;
368
369 for (const struct curl_slist *curr = job_headers;
370 NULL != curr;
371 curr = curr->next)
372 {
373 GNUNET_assert (NULL !=
374 (all_headers = curl_slist_append (all_headers,
375 curr->data)));
376 }
377
378 for (const struct curl_slist *curr = ctx->common_headers;
379 NULL != curr;
380 curr = curr->next)
381 {
382 GNUNET_assert (NULL !=
383 (all_headers = curl_slist_append (all_headers,
384 curr->data)));
385 }
386
387 if (NULL != ctx->async_scope_id_header)
388 {
389 struct GNUNET_AsyncScopeSave scope;
390
391 GNUNET_async_scope_get (&scope);
392 if (GNUNET_YES == scope.have_scope)
393 {
394 char *aid_header;
395
396 aid_header =
398 &scope.scope_id,
399 sizeof(struct GNUNET_AsyncScopeId));
400 GNUNET_assert (NULL != aid_header);
401 GNUNET_assert (NULL != curl_slist_append (all_headers,
402 aid_header));
403 GNUNET_free (aid_header);
404 }
405 }
406 return all_headers;
407}
408
409
423static size_t
424stream_write_cb (char *bufptr,
425 size_t size,
426 size_t nitems,
427 void *cls)
428{
429 struct GNUNET_CURL_Job *job = cls;
430 size_t msize = size * nitems;
431
432 if (0 == msize)
433 return 0; /* nothing (left) to do */
434 return job->sh.scb (job->sh.scb_cls,
435 bufptr,
436 msize);
437}
438
439
455static size_t
456stream_header_cb (char *bufptr,
457 size_t size,
458 size_t nitems,
459 void *cls)
460{
461 struct GNUNET_CURL_Job *job = cls;
462 size_t msize = size * nitems;
463
464 if (NULL == job->sh.hcb)
465 return msize;
466 if (GNUNET_OK !=
467 job->sh.hcb (job->sh.hcb_cls,
468 bufptr,
469 msize))
470 return 0; /* signals an error to curl */
471 return msize;
472}
473
474
483static bool
484setup_job_io (CURL *eh,
485 struct GNUNET_CURL_Job *job)
486{
487 if (! job->streaming)
488 return (CURLE_OK ==
489 curl_easy_setopt (eh,
490 CURLOPT_WRITEFUNCTION,
491 &download_cb)) &&
492 (CURLE_OK ==
493 curl_easy_setopt (eh,
494 CURLOPT_WRITEDATA,
495 &job->db));
496 return (CURLE_OK ==
497 curl_easy_setopt (eh,
498 CURLOPT_WRITEFUNCTION,
499 &stream_write_cb)) &&
500 (CURLE_OK ==
501 curl_easy_setopt (eh,
502 CURLOPT_WRITEDATA,
503 job)) &&
504 (CURLE_OK ==
505 curl_easy_setopt (eh,
506 CURLOPT_HEADERFUNCTION,
507 &stream_header_cb)) &&
508 (CURLE_OK ==
509 curl_easy_setopt (eh,
510 CURLOPT_HEADERDATA,
511 job));
512}
513
514
524static struct GNUNET_CURL_Job *
525setup_job (CURL *eh,
526 struct GNUNET_CURL_Context *ctx,
527 struct curl_slist *all_headers,
528 const struct GNUNET_CURL_StreamHandlers *sh)
529{
530 struct GNUNET_CURL_Job *job;
531
532 if (CURLE_OK !=
533 curl_easy_setopt (eh,
534 CURLOPT_HTTPHEADER,
535 all_headers))
536 {
537 GNUNET_break (0);
538 curl_slist_free_all (all_headers);
539 curl_easy_cleanup (eh);
540 return NULL;
541 }
542 job = GNUNET_new (struct GNUNET_CURL_Job);
543 job->start_time = GNUNET_TIME_absolute_get ();
544 job->job_headers = all_headers;
545 if (NULL != sh)
546 {
547 job->streaming = true;
548 job->sh = *sh;
549 }
550
551 if ( (CURLE_OK !=
552 curl_easy_setopt (eh,
553 CURLOPT_PRIVATE,
554 job)) ||
555 (! setup_job_io (eh,
556 job)) ||
557 (CURLE_OK !=
558 curl_easy_setopt (eh,
559 CURLOPT_SHARE,
560 ctx->share)) )
561 {
562 GNUNET_break (0);
564 curl_easy_cleanup (eh);
565 return NULL;
566 }
567 if ( (CURLM_OK !=
568 curl_multi_add_handle (ctx->multi,
569 eh)) )
570 {
571 GNUNET_break (0);
573 curl_easy_cleanup (eh);
574 return NULL;
575 }
576 job->easy_handle = eh;
577 job->ctx = ctx;
579 ctx->jobs_tail,
580 job);
581 return job;
582}
583
584
585void
587 const struct curl_slist *extra_headers)
588{
589 struct curl_slist *all_headers = job->job_headers;
590
591 for (const struct curl_slist *curr = extra_headers;
592 NULL != curr;
593 curr = curr->next)
594 {
595 GNUNET_assert (NULL !=
596 (all_headers = curl_slist_append (all_headers,
597 curr->data)));
598 }
599 job->job_headers = all_headers;
600 GNUNET_break (CURLE_OK ==
601 curl_easy_setopt (job->easy_handle,
602 CURLOPT_HTTPHEADER,
603 all_headers));
604}
605
606
607struct GNUNET_CURL_Job *
609 CURL *eh,
610 const struct curl_slist *job_headers,
612 void *jcc_cls)
613{
614 struct GNUNET_CURL_Job *job;
615 struct curl_slist *all_headers;
616
617 GNUNET_assert (NULL != jcc);
618 all_headers = setup_job_headers (ctx,
619 job_headers);
620 if (NULL == (job = setup_job (eh,
621 ctx,
622 all_headers,
623 NULL)))
624 return NULL;
625 job->jcc_raw = jcc;
626 job->jcc_raw_cls = jcc_cls;
627 ctx->cb (ctx->cb_cls);
628 return job;
629}
630
631
632struct GNUNET_CURL_Job *
634 CURL *eh,
635 const struct curl_slist *job_headers,
636 const struct GNUNET_CURL_StreamHandlers *sh)
637{
638 struct GNUNET_CURL_Job *job;
639 struct curl_slist *all_headers;
640
641 GNUNET_assert (NULL != sh);
642 GNUNET_assert (NULL != sh->scb);
643 GNUNET_assert (NULL != sh->jcc);
644 all_headers = setup_job_headers (ctx,
645 job_headers);
646 if (NULL == (job = setup_job (eh,
647 ctx,
648 all_headers,
649 sh)))
650 return NULL;
651 ctx->cb (ctx->cb_cls);
652 return job;
653}
654
655
656void
658 bool recv_paused,
659 bool send_paused)
660{
661 /* curl_easy_pause() takes the directions that are to REMAIN paused,
662 which is why this function does not take the ones to resume: every
663 way of naming a single direction to resume (CURLPAUSE_RECV_CONT,
664 CURLPAUSE_SEND_CONT, CURLPAUSE_CONT) is defined as 0. */
665 GNUNET_break (CURLE_OK ==
666 curl_easy_pause (job->easy_handle,
667 (recv_paused ? CURLPAUSE_RECV : 0)
668 | (send_paused ? CURLPAUSE_SEND : 0)));
669 /* Not optional: curl_multi_fdset() leaves out the socket of a
670 paused handle, so until the event loop is told to ask again it
671 will not wait on it -- and the transfer we just resumed would sit
672 there until some other job happened to wake the loop up. */
673 job->ctx->cb (job->ctx->cb_cls);
674}
675
676
677struct GNUNET_CURL_Job *
679 CURL *eh,
680 const struct curl_slist *job_headers,
682 void *jcc_cls)
683{
684 struct GNUNET_CURL_Job *job;
685 struct curl_slist *all_headers;
686
687 GNUNET_assert (NULL != jcc);
688 if ( (NULL != ctx->userpass) &&
689 (0 != curl_easy_setopt (eh,
690 CURLOPT_USERPWD,
691 ctx->userpass)) )
692 return NULL;
693 if ( (NULL != ctx->certfile) &&
694 (0 != curl_easy_setopt (eh,
695 CURLOPT_SSLCERT,
696 ctx->certfile)) )
697 return NULL;
698 if ( (NULL != ctx->certtype) &&
699 (0 != curl_easy_setopt (eh,
700 CURLOPT_SSLCERTTYPE,
701 ctx->certtype)) )
702 return NULL;
703 if ( (NULL != ctx->keyfile) &&
704 (0 != curl_easy_setopt (eh,
705 CURLOPT_SSLKEY,
706 ctx->keyfile)) )
707 return NULL;
708 if ( (NULL != ctx->keypass) &&
709 (0 != curl_easy_setopt (eh,
710 CURLOPT_KEYPASSWD,
711 ctx->keypass)) )
712 return NULL;
713
714 all_headers = setup_job_headers (ctx,
715 job_headers);
716 if (NULL == (job = setup_job (eh,
717 ctx,
718 all_headers,
719 NULL)))
720 return NULL;
721
722 job->jcc = jcc;
723 job->jcc_cls = jcc_cls;
724 ctx->cb (ctx->cb_cls);
725 return job;
726}
727
728
729struct GNUNET_CURL_Job *
731 CURL *eh,
733 void *jcc_cls)
734{
735 struct GNUNET_CURL_Job *job;
736 struct curl_slist *job_headers = NULL;
737
738 GNUNET_assert (NULL != (job_headers =
739 curl_slist_append (NULL,
740 "Content-Type: application/json")
741 ));
743 eh,
744 job_headers,
745 jcc,
746 jcc_cls);
747 curl_slist_free_all (job_headers);
748 return job;
749}
750
751
752struct GNUNET_CURL_Job *
754 CURL *eh,
756 void *jcc_cls)
757{
759 eh,
760 NULL,
761 jcc,
762 jcc_cls);
763}
764
765
766void
768{
769 struct GNUNET_CURL_Context *ctx = job->ctx;
770
772 ctx->jobs_tail,
773 job);
774 GNUNET_break (CURLM_OK ==
775 curl_multi_remove_handle (ctx->multi,
776 job->easy_handle));
777 curl_easy_cleanup (job->easy_handle);
778 GNUNET_free (job->db.buf);
779 curl_slist_free_all (job->job_headers);
780 ctx->cb (ctx->cb_cls);
782}
783
784
791static bool
792is_json (const char *ct)
793{
794 const char *semi;
795
796 /* check for "application/json" exact match */
797 if (0 == strcasecmp (ct,
798 "application/json"))
799 return true;
800 /* check for "application/json;[ANYTHING]" */
801 semi = strchr (ct,
802 ';');
803 /* also allow "application/json [ANYTHING]" (note the space!) */
804 if (NULL == semi)
805 semi = strchr (ct,
806 ' ');
807 if (NULL == semi)
808 return false; /* no delimiter we accept, forget it */
809 if (semi - ct != strlen ("application/json"))
810 return false; /* delimiter past desired length, forget it */
811 if (0 == strncasecmp (ct,
812 "application/json",
813 strlen ("application/json")))
814 return true; /* OK */
815 return false;
816}
817
818
819void *
821 CURL *eh,
822 long *response_code)
823{
824 json_t *json;
825 char *ct;
826
827#if DEBUG
829 "Downloaded body: %.*s\n",
830 (int) db->buf_size,
831 (char *) db->buf);
832#endif
833 if (CURLE_OK !=
834 curl_easy_getinfo (eh,
835 CURLINFO_RESPONSE_CODE,
836 response_code))
837 {
838 /* unexpected error... */
839 GNUNET_break (0);
840 *response_code = 0;
841 }
842 if (MHD_HTTP_NO_CONTENT == *response_code)
843 return NULL;
844 if ((CURLE_OK !=
845 curl_easy_getinfo (eh,
846 CURLINFO_CONTENT_TYPE,
847 &ct)) ||
848 (NULL == ct) ||
849 (! is_json (ct)))
850 {
851 /* No content type or explicitly not JSON, refuse to parse
852 (but keep response code) */
853 if (0 != db->buf_size)
854 {
855 const char *url;
856
857 if (CURLE_OK !=
858 curl_easy_getinfo (eh,
859 CURLINFO_EFFECTIVE_URL,
860 &url))
861 url = "<unknown URL>";
863 "Request to `%s' was expected to return a body of type `application/json', got `%s'\n",
864 url,
865 ct);
866 }
867 return NULL;
868 }
869 if (0 == *response_code)
870 {
871 const char *url;
872
873 if (CURLE_OK !=
874 curl_easy_getinfo (eh,
875 CURLINFO_EFFECTIVE_URL,
876 &url))
877 url = "<unknown URL>";
879 "Failed to download response from `%s': \n",
880 url);
881 return NULL;
882 }
883 json = NULL;
884 if (0 == db->eno)
885 {
886 json_error_t error;
887
888 json = json_loadb (db->buf,
889 db->buf_size,
890 JSON_REJECT_DUPLICATES | JSON_DISABLE_EOF_CHECK,
891 &error);
892 if (NULL == json)
893 {
894 JSON_WARN (error);
895 *response_code = 0;
897 "Failed to parse JSON response: %s\n",
898 error.text);
899 }
900 }
901 GNUNET_free (db->buf);
902 db->buf = NULL;
903 db->buf_size = 0;
904 return json;
905}
906
907
910 const char *header)
911{
912 struct curl_slist *job_headers;
913
914 job_headers = curl_slist_append (ctx->common_headers,
915 header);
916 if (NULL == job_headers)
917 {
918 GNUNET_break (0);
919 return GNUNET_SYSERR;
920 }
921 ctx->common_headers = job_headers;
922 return GNUNET_OK;
923}
924
925
926void
930{
931 CURLMsg *cmsg;
932 int n_running;
933 int n_completed;
934
935 (void) curl_multi_perform (ctx->multi,
936 &n_running);
937 while (NULL != (cmsg = curl_multi_info_read (ctx->multi,
938 &n_completed)))
939 {
940 struct GNUNET_CURL_Job *job;
942 long response_code;
943 void *response;
944
945 /* Only documented return value is CURLMSG_DONE */
946 GNUNET_break (CURLMSG_DONE == cmsg->msg);
947 GNUNET_assert (CURLE_OK ==
948 curl_easy_getinfo (cmsg->easy_handle,
949 CURLINFO_PRIVATE,
950 (char **) &job));
951 GNUNET_assert (job->ctx == ctx);
952 response_code = 0;
954 if (job->streaming)
955 {
956 /* Body already delivered chunk by chunk; nothing was kept, so
957 the completion callback is told about the outcome only.
958
959 A streaming caller has forwarded the status line and part of
960 the body long before this runs, so the one thing it still
961 needs to know is whether the transfer actually finished --
962 and a transfer that died mid-body still has a perfectly good
963 CURLINFO_RESPONSE_CODE from the status line libcurl parsed at
964 the start. Reporting that would say "200 OK" about a
965 connection that was cut in half. Report the hard error
966 instead, and leave telling the two apart to the caller, which
967 knows whether it has already committed to a status. */
968 if (CURLE_OK != cmsg->data.result)
969 {
971 "Streaming transfer failed: %s\n",
972 curl_easy_strerror (cmsg->data.result));
973 }
974 else
975 {
976 GNUNET_break (CURLE_OK ==
977 curl_easy_getinfo (job->easy_handle,
978 CURLINFO_RESPONSE_CODE,
979 &response_code));
980 }
981 job->sh.jcc (job->sh.jcc_cls,
982 response_code,
983 NULL,
984 0);
985 }
986 else if (NULL != job->jcc_raw)
987 {
988 /* RAW mode, no parsing */
989 GNUNET_break (CURLE_OK ==
990 curl_easy_getinfo (job->easy_handle,
991 CURLINFO_RESPONSE_CODE,
992 &response_code));
993 job->jcc_raw (job->jcc_raw_cls,
994 response_code,
995 job->db.buf,
996 job->db.buf_size);
997 }
998 else
999 {
1000 /* to be parsed via 'rp' */
1001 response = rp (&job->db,
1002 job->easy_handle,
1003 &response_code);
1004 job->jcc (job->jcc_cls,
1005 response_code,
1006 response);
1007 rc (response);
1008 }
1009 {
1010 const char *url = NULL;
1011
1012 if (CURLE_UNKNOWN_OPTION ==
1013 curl_easy_getinfo (job->easy_handle,
1014 CURLINFO_EFFECTIVE_URL,
1015 &url))
1016 url = "<unknown>";
1018 "HTTP request for `%s' finished with %u after %s\n",
1019 url,
1020 (unsigned int) response_code,
1022 true));
1023 /* Note: we MUST NOT free 'url' here */
1024 }
1026 }
1027}
1028
1029
1030void
1037
1038
1039void
1041 fd_set *read_fd_set,
1042 fd_set *write_fd_set,
1043 fd_set *except_fd_set,
1044 int *max_fd,
1045 long *timeout)
1046{
1047 long to;
1048 int m;
1049
1050 m = -1;
1051 GNUNET_assert (CURLM_OK ==
1052 curl_multi_fdset (ctx->multi,
1053 read_fd_set,
1054 write_fd_set,
1055 except_fd_set,
1056 &m));
1057 to = *timeout;
1058 *max_fd = GNUNET_MAX (m, *max_fd);
1059 GNUNET_assert (CURLM_OK ==
1060 curl_multi_timeout (ctx->multi,
1061 &to));
1062
1063 /* Only if what we got back from curl is smaller than what we
1064 already had (-1 == infinity!), then update timeout */
1065 if ((to < *timeout) && (-1 != to))
1066 *timeout = to;
1067 if ((-1 == (*timeout)) && (NULL != ctx->jobs_head))
1068 *timeout = to;
1069}
1070
1071
1072void
1074{
1075 /* all jobs must have been cancelled at this time, assert this */
1076 GNUNET_assert (NULL == ctx->jobs_head);
1077 curl_share_cleanup (ctx->share);
1078 curl_multi_cleanup (ctx->multi);
1079 curl_slist_free_all (ctx->common_headers);
1080 GNUNET_free (ctx->userpass);
1081 GNUNET_free (ctx->certtype);
1082 GNUNET_free (ctx->certfile);
1083 GNUNET_free (ctx->keyfile);
1084 GNUNET_free (ctx->keypass);
1085 GNUNET_free (ctx);
1086}
1087
1088
1089void
1091
1095void __attribute__ ((constructor))
1097{
1098 CURLcode ret;
1099
1100 if (CURLE_OK != (ret = curl_global_init (CURL_GLOBAL_DEFAULT)))
1101 {
1103 "curl_global_init",
1104 ret);
1105 curl_fail = 1;
1106 }
1107}
1108
1109
1110void
1112
1116void __attribute__ ((destructor))
1118{
1119 if (curl_fail)
1120 return;
1121 curl_global_cleanup ();
1122}
1123
1124
1125/* end of curl.c */
void GNUNET_CURL_constructor__(void)
#define CURL_STRERROR(type, function, code)
Log error related to CURL operations.
Definition curl.c:48
static bool is_json(const char *ct)
Test if the given content type ct is JSON.
Definition curl.c:792
static bool setup_job_io(CURL *eh, struct GNUNET_CURL_Job *job)
Point eh's body and header handling at job, in whichever of the two modes job was set up for.
Definition curl.c:484
#define JSON_WARN(error)
Print JSON parsing related error information.
Definition curl.c:59
static size_t stream_write_cb(char *bufptr, size_t size, size_t nitems, void *cls)
Callback used when the caller wants the response body as it arrives, instead of buffered.
Definition curl.c:424
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:327
static int curl_fail
Failsafe flag.
Definition curl.c:72
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:364
void GNUNET_CURL_destructor__(void)
void * GNUNET_CURL_download_get_result_(struct GNUNET_CURL_DownloadBuffer *db, CURL *eh, long *response_code)
Definition curl.c:820
static size_t stream_header_cb(char *bufptr, size_t size, size_t nitems, void *cls)
Callback used to pass the response's header lines on to a streaming caller.
Definition curl.c:456
static struct GNUNET_CURL_Job * setup_job(CURL *eh, struct GNUNET_CURL_Context *ctx, struct curl_slist *all_headers, const struct GNUNET_CURL_StreamHandlers *sh)
Create a job.
Definition curl.c:525
static struct GNUNET_ARM_MonitorHandle * m
Monitor connection with ARM.
Definition gnunet-arm.c:103
static int ret
Final status code.
Definition gnunet-arm.c:93
static struct GNUNET_TIME_Relative timeout
User defined timestamp for completing operations.
Definition gnunet-arm.c:118
static struct GNUNET_SCHEDULER_Task * job
Task for main job.
static CURLM * multi
Current multi-CURL handle.
static struct MHD_Response * response
Our canonical response.
static struct GNUNET_FS_Handle * ctx
static struct GNUNET_IDENTITY_Handle * sh
Handle to IDENTITY service.
static char * rp
Relying party.
static struct GNUNET_FS_DirectoryBuilder * db
static struct GNUNET_TIME_Relative duration
Option '-d': duration of the mapping.
Definition gnunet-vpn.c:90
library to make it easy to download JSON replies over HTTP
struct GNUNET_PQ_ResultSpec __attribute__
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:237
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.
void(* GNUNET_CURL_JobCompletionCallback)(void *cls, long response_code, const void *response)
Function to call upon completion of a job.
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:608
void GNUNET_CURL_job_set_paused(struct GNUNET_CURL_Job *job, bool recv_paused, bool send_paused)
Say which directions of job are to be paused from now on.
Definition curl.c:657
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:753
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:1040
struct GNUNET_CURL_Context * GNUNET_CURL_init(GNUNET_CURL_RescheduleCallback cb, void *cb_cls)
Initialise this library.
Definition curl.c:259
void GNUNET_CURL_fini(struct GNUNET_CURL_Context *ctx)
Cleanup library initialisation resources.
Definition curl.c:1073
void(* GNUNET_CURL_ResponseCleaner)(void *response)
Deallocate the response.
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:586
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:927
void GNUNET_CURL_job_cancel(struct GNUNET_CURL_Job *job)
Cancel a job.
Definition curl.c:767
enum GNUNET_GenericReturnValue 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:302
void GNUNET_CURL_perform(struct GNUNET_CURL_Context *ctx)
Run the main event loop for the CURL interaction.
Definition curl.c:1031
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:227
void *(* GNUNET_CURL_RawParser)(struct GNUNET_CURL_DownloadBuffer *db, CURL *eh, long *response_code)
Parses the raw response we got from the Web server.
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:730
struct GNUNET_CURL_Job * GNUNET_CURL_job_add_stream(struct GNUNET_CURL_Context *ctx, CURL *eh, const struct curl_slist *job_headers, const struct GNUNET_CURL_StreamHandlers *sh)
Schedule a CURL request whose response is delivered incrementally, rather than buffered in full and h...
Definition curl.c:633
enum GNUNET_GenericReturnValue GNUNET_CURL_append_header(struct GNUNET_CURL_Context *ctx, const char *header)
Add custom request header.
Definition curl.c:909
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 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:294
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:678
#define GNUNET_CONTAINER_DLL_remove(head, tail, element)
Remove an element from a DLL.
#define GNUNET_CONTAINER_DLL_insert(head, tail, element)
Insert an element at the head of a DLL.
#define GNUNET_log(kind,...)
#define GNUNET_MAX(a, b)
int have_scope
GNUNET_YES unless this saved scope is the unnamed root scope.
void GNUNET_async_scope_get(struct GNUNET_AsyncScopeSave *scope_ret)
Get the current async scope.
#define GNUNET_memcpy(dst, src, n)
Call memcpy() but check for n being 0 first.
GNUNET_GenericReturnValue
Named constants for return values.
struct GNUNET_AsyncScopeId scope_id
Saved scope.
@ GNUNET_OK
@ GNUNET_YES
@ GNUNET_NO
@ GNUNET_SYSERR
#define GNUNET_assert(cond)
Use this for fatal errors that cannot be handled.
#define GNUNET_break(cond)
Use this for internal assertion violations that are not fatal (can be handled) but should not occur.
@ GNUNET_ERROR_TYPE_WARNING
@ GNUNET_ERROR_TYPE_ERROR
@ GNUNET_ERROR_TYPE_DEBUG
@ GNUNET_ERROR_TYPE_INFO
#define GNUNET_strdup(a)
Wrapper around GNUNET_xstrdup_.
#define GNUNET_MAX_MALLOC_CHECKED
Maximum allocation with GNUNET_malloc macro.
#define GNUNET_new(type)
Allocate a struct or union of the given type.
#define GNUNET_realloc(ptr, size)
Wrapper around realloc.
#define GNUNET_free(ptr)
Wrapper around free.
char * GNUNET_STRINGS_data_to_string_alloc(const void *buf, size_t size)
Return the base32crockford encoding of the given buffer.
Definition strings.c:818
const char * GNUNET_TIME_relative2s(struct GNUNET_TIME_Relative delta, bool do_round)
Give relative time in human-readable fancy format.
Definition time.c:264
struct GNUNET_TIME_Relative GNUNET_TIME_absolute_get_duration(struct GNUNET_TIME_Absolute whence)
Get the duration of an operation as the difference of the current time and the given start time "henc...
Definition time.c:438
struct GNUNET_TIME_Absolute GNUNET_TIME_absolute_get(void)
Get the current time.
Definition time.c:111
static unsigned int size
Size of the "table".
Definition peer.c:68
Identifier for an asynchronous execution context.
Saved async scope identifier or root scope.
char * userpass
USERNAME:PASSWORD to use for client-authentication with all requests of this context,...
Definition curl.c:200
char * keypass
Passphrase to decrypt keyfile, or NULL.
Definition curl.c:221
void * cb_cls
Closure for cb.
Definition curl.c:194
char * certtype
Type of the TLS client certificate used, or NULL.
Definition curl.c:205
char * keyfile
File with the private key to authenticate the TLS client, or NULL.
Definition curl.c:216
struct curl_slist * common_headers
Headers common for all requests in the context.
Definition curl.c:177
CURLSH * share
Curl share handle.
Definition curl.c:162
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:183
CURLM * multi
Curl multi handle.
Definition curl.c:157
GNUNET_CURL_RescheduleCallback cb
Function we need to call whenever the event loop's socket set changed.
Definition curl.c:189
struct GNUNET_CURL_Job * jobs_head
We keep jobs in a DLL.
Definition curl.c:167
char * certfile
File with the TLS client certificate, or NULL.
Definition curl.c:210
struct GNUNET_CURL_Job * jobs_tail
We keep jobs in a DLL.
Definition curl.c:172
Buffer data structure we use to buffer the HTTP download before giving it to the JSON parser.
void * buf
Download buffer.
Jobs are CURL requests running within a struct GNUNET_CURL_Context.
Definition curl.c:78
struct GNUNET_CURL_Job * prev
We keep jobs in a DLL.
Definition curl.c:87
CURL * easy_handle
Easy handle of the job.
Definition curl.c:92
struct curl_slist * job_headers
Headers used for this job, the list needs to be freed after the job has finished.
Definition curl.c:140
void * jcc_raw_cls
Closure for jcc_raw.
Definition curl.c:117
struct GNUNET_CURL_Context * ctx
Context this job runs in.
Definition curl.c:97
struct GNUNET_TIME_Absolute start_time
When did we start the job?
Definition curl.c:145
GNUNET_CURL_JobCompletionCallback jcc
Function to call upon completion.
Definition curl.c:102
struct GNUNET_CURL_StreamHandlers sh
Handlers to use if streaming; otherwise all-NULL.
Definition curl.c:122
void * jcc_cls
Closure for jcc.
Definition curl.c:107
struct GNUNET_CURL_DownloadBuffer db
Buffer for response received from CURL.
Definition curl.c:134
struct GNUNET_CURL_Job * next
We keep jobs in a DLL.
Definition curl.c:82
bool streaming
Is the response delivered to sh as it arrives, rather than accumulated in db? If so db stays empty fo...
Definition curl.c:129
GNUNET_CURL_RawJobCompletionCallback jcc_raw
Function to call upon completion.
Definition curl.c:112
What to call for a job added with GNUNET_CURL_job_add_stream().
Time for absolute times used by GNUnet, in microseconds.
Time for relative time used by GNUnet, in microseconds.