28 #include <microhttpd.h> 32 #include "../util/benchmark.h" 43 #define CURL_STRERROR(type, function, code) \ 45 "Curl function `%s' has failed at `%s:%d' with error: %s\n", \ 49 curl_easy_strerror (code)); 54 #define JSON_WARN(error) \ 55 GNUNET_log (GNUNET_ERROR_TYPE_WARNING, \ 56 "JSON parsing failed at %s:%u: %s (%s)\n", \ 214 const char *userpass)
217 if (NULL != userpass)
239 const char *certtype,
240 const char *certfile,
248 if (NULL != certtype)
250 if (NULL != certfile)
278 "Curl was not initialised properly\n");
281 if (NULL == (multi = curl_multi_init ()))
284 "Failed to create a Curl multi handle\n");
287 if (NULL == (share = curl_share_init ()))
290 "Failed to create a Curl share handle\n");
310 const char *header_name)
328 if (strlen (scope_id) >= 64)
330 for (
size_t i = 0; i < strlen (scope_id); i++)
331 if (! (isalnum (scope_id[i]) || (scope_id[i] ==
'-')))
360 if (0 == size * nitems)
365 msize = size * nitems;
386 static struct curl_slist *
390 struct curl_slist *all_headers = NULL;
392 for (
const struct curl_slist *curr = job_headers;
397 (all_headers = curl_slist_append (all_headers,
406 (all_headers = curl_slist_append (all_headers,
424 GNUNET_assert (NULL != curl_slist_append (all_headers, aid_header));
443 struct curl_slist *all_headers)
448 curl_easy_setopt (eh, CURLOPT_HTTPHEADER, all_headers))
451 curl_slist_free_all (all_headers);
452 curl_easy_cleanup (eh);
458 if ((CURLE_OK != curl_easy_setopt (eh, CURLOPT_PRIVATE, job)) ||
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)))
467 curl_easy_cleanup (eh);
487 const struct curl_slist *extra_headers)
491 for (
const struct curl_slist *curr = extra_headers;
496 (all_headers = curl_slist_append (all_headers,
526 struct curl_slist *all_headers;
569 struct curl_slist *all_headers;
573 (0 != curl_easy_setopt (eh,
578 (0 != curl_easy_setopt (eh,
583 (0 != curl_easy_setopt (eh,
588 (0 != curl_easy_setopt (eh,
593 (0 != curl_easy_setopt (eh,
637 curl_slist_append (NULL,
638 "Content-Type: application/json")));
644 curl_slist_free_all (job_headers);
709 if (0 == strcasecmp (ct,
721 if (semi - ct != strlen (
"application/json"))
723 if (0 == strncasecmp (ct,
725 strlen (
"application/json")))
759 "Downloaded body: %.*s\n",
764 curl_easy_getinfo (eh,
765 CURLINFO_CONTENT_TYPE,
773 curl_easy_getinfo (eh,
774 CURLINFO_RESPONSE_CODE,
783 "Did NOT detect response `%.*s' as JSON\n",
785 (
const char *) db->
buf);
788 if (MHD_HTTP_NO_CONTENT == *response_code)
793 json = json_loadb (db->
buf,
795 JSON_REJECT_DUPLICATES | JSON_DISABLE_EOF_CHECK,
809 curl_easy_getinfo (eh,
810 CURLINFO_RESPONSE_CODE,
842 do_benchmark (CURLMsg *cmsg)
845 double total_as_double = 0;
850 curl_off_t size_curl = 0;
855 GNUNET_break (CURLE_OK == curl_easy_getinfo (cmsg->easy_handle,
860 GNUNET_break (CURLE_OK == curl_easy_getinfo (cmsg->easy_handle,
861 CURLINFO_EFFECTIVE_URL,
867 GNUNET_break (CURLE_OK == curl_easy_getinfo (cmsg->easy_handle,
868 CURLINFO_HEADER_SIZE,
870 bytes_received += size_long;
872 GNUNET_break (CURLE_OK == curl_easy_getinfo (cmsg->easy_handle,
873 CURLINFO_SIZE_DOWNLOAD_T,
875 bytes_received += size_curl;
880 GNUNET_break (CURLE_OK == curl_easy_getinfo (cmsg->easy_handle,
881 CURLINFO_REQUEST_SIZE,
883 bytes_sent += size_long;
886 GNUNET_break (CURLE_OK == curl_easy_getinfo (cmsg->easy_handle,
887 CURLINFO_SIZE_UPLOAD_T,
928 (void) curl_multi_perform (ctx->
multi,
930 while (NULL != (cmsg = curl_multi_info_read (ctx->
multi, &n_completed)))
938 GNUNET_assert (CURLE_OK == curl_easy_getinfo (cmsg->easy_handle,
943 if (NULL != job->jcc_raw)
947 curl_easy_getinfo (job->easy_handle,
948 CURLINFO_RESPONSE_CODE,
950 job->jcc_raw (job->jcc_raw_cls,
958 response =
rp (&job->db,
961 job->jcc (job->jcc_cls,
1018 fd_set *read_fd_set,
1019 fd_set *write_fd_set,
1020 fd_set *except_fd_set,
1039 if ((to < *timeout) && (-1 != to))
1041 if ((-1 == (*timeout)) && (NULL != ctx->
jobs_head))
1058 curl_share_cleanup (ctx->
share);
1059 curl_multi_cleanup (ctx->
multi);
1074 GNUNET_CURL_constructor__ (
void)
1078 if (CURLE_OK != (ret = curl_global_init (CURL_GLOBAL_DEFAULT)))
1090 GNUNET_CURL_destructor__ (
void)
1094 curl_global_cleanup ();
#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.
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.
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.
struct GNUNET_CURL_Job * prev
We keep jobs in a DLL.
#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.
int GNUNET_CURL_append_header(struct GNUNET_CURL_Context *ctx, const char *header)
Add custom request header.
#define GNUNET_memcpy(dst, src, n)
Call memcpy() but check for n being 0 first.
static int ret
Return value of the commandline.
void GNUNET_CURL_fini(struct GNUNET_CURL_Context *ctx)
Cleanup library initialisation resources.
#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.
GNUNET_CURL_RescheduleCallback cb
Function we need to call whenever the event loop's socket set changed.
struct GNUNET_TIME_Relative time_max
Slowest time to response.
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.
#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?
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.
void * jcc_cls
Closure for jcc.
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.
static struct GNUNET_ARM_MonitorHandle * m
Monitor connection with ARM.
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.
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.
struct GNUNET_CURL_Job * jobs_head
We keep jobs in a DLL.
static struct GNUNET_TIME_Relative timeout
Desired timeout for the lookup (default is no timeout).
#define GNUNET_realloc(ptr, size)
Wrapper around realloc.
struct GNUNET_CURL_Job * next
We keep jobs in a DLL.
#define JSON_WARN(error)
Print JSON parsing related error information.
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.
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.
static CURLM * multi
Current multi-CURL handle.
CURLSH * share
Curl share handle.
static int curl_fail
Failsafe flag.
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...
uint64_t bytes_sent
How many bytes were sent in total to request the URL.
struct GNUNET_TIME_Relative time
Total time spent requesting this URL.
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.
GNUNET_CURL_RawJobCompletionCallback jcc_raw
Function to call upon completion.
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...
void(* GNUNET_CURL_ResponseCleaner)(void *response)
Deallocate the response.
__attribute__((constructor))
Initial global setup logic, specifically runs the Curl setup.
CURLM * multi
Curl multi handle.
static unsigned int size
Size of the "table".
uint64_t bytes_received
How many bytes were received in total as response to requesting this URL.
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.
#define GNUNET_MAX_MALLOC_CHECKED
Maximum allocation with GNUNET_malloc macro.
static struct GNUNET_SCHEDULER_Task * job
Task for main job.
struct GNUNET_TIME_Relative GNUNET_TIME_relative_add(struct GNUNET_TIME_Relative a1, struct GNUNET_TIME_Relative a2)
Add relative times together.
char * keypass
Passphrase to decrypt keyfile, or NULL.
static bool is_json(const char *ct)
Test if the given content type ct is JSON.
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...
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.
char * certtype
Type of the TLS client certificate used, or NULL.
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.
Jobs are CURL requests running within a struct GNUNET_CURL_Context.
#define GNUNET_log(kind,...)
struct GNUNET_CURL_Context * GNUNET_CURL_init(GNUNET_CURL_RescheduleCallback cb, void *cb_cls)
Initialise this library.
const char * async_scope_id_header
If non-NULL, the async scope ID is sent in a request header of this name.
static char * rp
Relying party.
struct GNUNET_CURL_Job * jobs_tail
We keep jobs in a DLL.
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.
struct UrlRequestData * get_url_benchmark_data(char *url, unsigned int status)
Get benchmark data for a URL.
char * GNUNET_STRINGS_data_to_string_alloc(const void *buf, size_t size)
Return the base32crockford encoding of the given buffer.
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.
struct curl_slist * job_headers
Headers used for this job, the list needs to be freed after the job has finished. ...
char * certfile
File with the TLS client certificate, or NULL.
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.
void * jcc_raw_cls
Closure for jcc_raw.
char * userpass
USERNAME:PASSWORD to use for client-authentication with all requests of this context, or NULL.
#define GNUNET_free(ptr)
Wrapper around free.
struct GNUNET_CURL_Context * ctx
Context this job runs in.
struct curl_slist * common_headers
Headers common for all requests in the context.
static struct GNUNET_CURL_Job * setup_job(CURL *eh, struct GNUNET_CURL_Context *ctx, struct curl_slist *all_headers)
Create a job.
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.
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.