aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorChristian Grothoff <christian@grothoff.org>2016-04-17 15:09:23 +0000
committerChristian Grothoff <christian@grothoff.org>2016-04-17 15:09:23 +0000
commit16642c4cb25faae335591b39795c71dedbeb37f1 (patch)
tree99eced0e91cb1455f4dc5afd1fd3918259aa5dd3
parentda7b8273d9f2229fe163ef4fbdcf046fb6227b73 (diff)
downloadgnunet-16642c4cb25faae335591b39795c71dedbeb37f1.tar.gz
gnunet-16642c4cb25faae335591b39795c71dedbeb37f1.zip
adding libgnunetcurl
-rw-r--r--configure.ac1
-rw-r--r--po/POTFILES.in1
-rw-r--r--src/Makefile.am7
-rw-r--r--src/curl/Makefile.am33
-rw-r--r--src/curl/curl.c574
-rw-r--r--src/include/Makefile.am1
-rw-r--r--src/include/gnunet_curl_lib.h155
-rw-r--r--src/json/json.c2
8 files changed, 774 insertions, 0 deletions
diff --git a/configure.ac b/configure.ac
index 2b90bc1ee..369ad99ee 100644
--- a/configure.ac
+++ b/configure.ac
@@ -1534,6 +1534,7 @@ src/consensus/Makefile
1534src/consensus/consensus.conf 1534src/consensus/consensus.conf
1535src/conversation/Makefile 1535src/conversation/Makefile
1536src/conversation/conversation.conf 1536src/conversation/conversation.conf
1537src/curl/Makefile
1537src/datacache/Makefile 1538src/datacache/Makefile
1538src/datastore/Makefile 1539src/datastore/Makefile
1539src/datastore/datastore.conf 1540src/datastore/datastore.conf
diff --git a/po/POTFILES.in b/po/POTFILES.in
index 84bf8735e..06d180231 100644
--- a/po/POTFILES.in
+++ b/po/POTFILES.in
@@ -74,6 +74,7 @@ src/core/gnunet-service-core_kx.c
74src/core/gnunet-service-core_neighbours.c 74src/core/gnunet-service-core_neighbours.c
75src/core/gnunet-service-core_sessions.c 75src/core/gnunet-service-core_sessions.c
76src/core/gnunet-service-core_typemap.c 76src/core/gnunet-service-core_typemap.c
77src/curl/curl.c
77src/datacache/datacache.c 78src/datacache/datacache.c
78src/datacache/plugin_datacache_heap.c 79src/datacache/plugin_datacache_heap.c
79src/datacache/plugin_datacache_postgres.c 80src/datacache/plugin_datacache_postgres.c
diff --git a/src/Makefile.am b/src/Makefile.am
index f38dd19d3..5244c795d 100644
--- a/src/Makefile.am
+++ b/src/Makefile.am
@@ -24,6 +24,13 @@ endif
24 24
25if HAVE_JSON 25if HAVE_JSON
26 JSON_DIR = json 26 JSON_DIR = json
27if HAVE_LIBGNURL
28 JSON_DIR += curl
29else
30if HAVE_LIBCURL
31 JSON_DIR += curl
32endif
33endif
27endif 34endif
28 35
29if BUILD_PULSE_HELPERS 36if BUILD_PULSE_HELPERS
diff --git a/src/curl/Makefile.am b/src/curl/Makefile.am
new file mode 100644
index 000000000..4bdd03039
--- /dev/null
+++ b/src/curl/Makefile.am
@@ -0,0 +1,33 @@
1# This Makefile.am is in the public domain
2AM_CPPFLAGS = -I$(top_srcdir)/src/include
3
4if USE_COVERAGE
5 AM_CFLAGS = --coverage -O0
6 XLIB = -lgcov
7endif
8
9lib_LTLIBRARIES = \
10 libgnunetcurl.la
11
12libgnunetcurl_la_LDFLAGS = \
13 -version-info 0:0:0 \
14 -no-undefined
15libgnunetcurl_la_SOURCES = \
16 curl.c
17libgnunetcurl_la_LIBADD = \
18 $(top_builddir)/src/util/libgnunetutil.la \
19 -ljansson \
20 $(XLIB)
21
22#check_PROGRAMS = \
23# test_curl
24
25#TESTS = \
26# $(check_PROGRAMS)
27
28#test_curl_SOURCES = \
29# test_curl.c
30#test_curl_LDADD = \
31# libgnunetcurl.la \
32# $(top_builddir)/src/util/libgnunetutil.la \
33# -ljansson -lcurl
diff --git a/src/curl/curl.c b/src/curl/curl.c
new file mode 100644
index 000000000..10ba7f719
--- /dev/null
+++ b/src/curl/curl.c
@@ -0,0 +1,574 @@
1/*
2 This file is part of GNUnet
3 Copyright (C) 2014, 2015, 2016 GNUnet e.V.
4
5 GNUnet is free software; you can redistribute it and/or modify it under the
6 terms of the GNU General Public License as published by the Free Software
7 Foundation; either version 3, or (at your option) any later version.
8
9 GNUnet is distributed in the hope that it will be useful, but WITHOUT ANY
10 WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR
11 A PARTICULAR PURPOSE. See the GNU General Public License for more details.
12
13 You should have received a copy of the GNU General Public License along with
14 GNUnet; see the file COPYING. If not, If not, see
15 <http://www.gnu.org/licenses/>
16*/
17/**
18 * @file curl/curl.c
19 * @brief API for downloading JSON via CURL
20 * @author Sree Harsha Totakura <sreeharsha@totakura.in>
21 * @author Christian Grothoff
22 */
23#include "platform.h"
24#include <curl/curl.h>
25#include <jansson.h>
26#include "gnunet_curl_lib.h"
27
28
29/**
30 * Log error related to CURL operations.
31 *
32 * @param type log level
33 * @param function which function failed to run
34 * @param code what was the curl error code
35 */
36#define CURL_STRERROR(type, function, code) \
37 GNUNET_log (type, \
38 "Curl function `%s' has failed at `%s:%d' with error: %s\n", \
39 function, __FILE__, __LINE__, curl_easy_strerror (code));
40
41/**
42 * Print JSON parsing related error information
43 */
44#define JSON_WARN(error) \
45 GNUNET_log (GNUNET_ERROR_TYPE_WARNING, \
46 "JSON parsing failed at %s:%u: %s (%s)\n", \
47 __FILE__, __LINE__, error.text, error.source)
48
49
50/**
51 * Failsafe flag. Raised if our constructor fails to initialize
52 * the Curl library.
53 */
54static int curl_fail;
55
56
57/**
58 * @brief Buffer data structure we use to buffer the HTTP download
59 * before giving it to the JSON parser.
60 */
61struct DownloadBuffer
62{
63
64 /**
65 * Download buffer
66 */
67 void *buf;
68
69 /**
70 * The size of the download buffer
71 */
72 size_t buf_size;
73
74 /**
75 * Error code (based on libc errno) if we failed to download
76 * (i.e. response too large).
77 */
78 int eno;
79
80};
81
82
83/**
84 * Jobs are CURL requests running within a `struct GNUNET_CURL_Context`.
85 */
86struct GNUNET_CURL_Job
87{
88
89 /**
90 * We keep jobs in a DLL.
91 */
92 struct GNUNET_CURL_Job *next;
93
94 /**
95 * We keep jobs in a DLL.
96 */
97 struct GNUNET_CURL_Job *prev;
98
99 /**
100 * Easy handle of the job.
101 */
102 CURL *easy_handle;
103
104 /**
105 * Context this job runs in.
106 */
107 struct GNUNET_CURL_Context *ctx;
108
109 /**
110 * Function to call upon completion.
111 */
112 GNUNET_CURL_JobCompletionCallback jcc;
113
114 /**
115 * Closure for @e jcc.
116 */
117 void *jcc_cls;
118
119 /**
120 * Buffer for response received from CURL.
121 */
122 struct DownloadBuffer db;
123
124};
125
126
127/**
128 * Context
129 */
130struct GNUNET_CURL_Context
131{
132 /**
133 * Curl multi handle
134 */
135 CURLM *multi;
136
137 /**
138 * Curl share handle
139 */
140 CURLSH *share;
141
142 /**
143 * We keep jobs in a DLL.
144 */
145 struct GNUNET_CURL_Job *jobs_head;
146
147 /**
148 * We keep jobs in a DLL.
149 */
150 struct GNUNET_CURL_Job *jobs_tail;
151
152 /**
153 * HTTP header "application/json", created once and used
154 * for all requests that need it.
155 */
156 struct curl_slist *json_header;
157
158};
159
160
161/**
162 * Initialise this library. This function should be called before using any of
163 * the following functions.
164 *
165 * @return library context
166 */
167struct GNUNET_CURL_Context *
168GNUNET_CURL_init ()
169{
170 struct GNUNET_CURL_Context *ctx;
171 CURLM *multi;
172 CURLSH *share;
173
174 if (curl_fail)
175 {
176 GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
177 "Curl was not initialised properly\n");
178 return NULL;
179 }
180 if (NULL == (multi = curl_multi_init ()))
181 {
182 GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
183 "Failed to create a Curl multi handle\n");
184 return NULL;
185 }
186 if (NULL == (share = curl_share_init ()))
187 {
188 GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
189 "Failed to create a Curl share handle\n");
190 return NULL;
191 }
192 ctx = GNUNET_new (struct GNUNET_CURL_Context);
193 ctx->multi = multi;
194 ctx->share = share;
195 GNUNET_assert (NULL != (ctx->json_header =
196 curl_slist_append (NULL,
197 "Content-Type: application/json")));
198 return ctx;
199}
200
201
202/**
203 * Callback used when downloading the reply to an HTTP request.
204 * Just appends all of the data to the `buf` in the
205 * `struct DownloadBuffer` for further processing. The size of
206 * the download is limited to #GNUNET_MAX_MALLOC_CHECKED, if
207 * the download exceeds this size, we abort with an error.
208 *
209 * @param bufptr data downloaded via HTTP
210 * @param size size of an item in @a bufptr
211 * @param nitems number of items in @a bufptr
212 * @param cls the `struct DownloadBuffer`
213 * @return number of bytes processed from @a bufptr
214 */
215static size_t
216download_cb (char *bufptr,
217 size_t size,
218 size_t nitems,
219 void *cls)
220{
221 struct DownloadBuffer *db = cls;
222 size_t msize;
223 void *buf;
224
225 if (0 == size * nitems)
226 {
227 /* Nothing (left) to do */
228 return 0;
229 }
230 msize = size * nitems;
231 if ( (msize + db->buf_size) >= GNUNET_MAX_MALLOC_CHECKED)
232 {
233 db->eno = ENOMEM;
234 return 0; /* signals an error to curl */
235 }
236 db->buf = GNUNET_realloc (db->buf,
237 db->buf_size + msize);
238 buf = db->buf + db->buf_size;
239 memcpy (buf, bufptr, msize);
240 db->buf_size += msize;
241 return msize;
242}
243
244
245/**
246 * Schedule a CURL request to be executed and call the given @a jcc
247 * upon its completion. Note that the context will make use of the
248 * CURLOPT_PRIVATE facility of the CURL @a eh.
249 *
250 * This function modifies the CURL handle to add the
251 * "Content-Type: application/json" header if @a add_json is set.
252 *
253 * @param ctx context to execute the job in
254 * @param eh curl easy handle for the request, will
255 * be executed AND cleaned up
256 * @param add_json add "application/json" content type header
257 * @param jcc callback to invoke upon completion
258 * @param jcc_cls closure for @a jcc
259 * @return NULL on error (in this case, @eh is still released!)
260 */
261struct GNUNET_CURL_Job *
262GNUNET_CURL_job_add (struct GNUNET_CURL_Context *ctx,
263 CURL *eh,
264 int add_json,
265 GNUNET_CURL_JobCompletionCallback jcc,
266 void *jcc_cls)
267{
268 struct GNUNET_CURL_Job *job;
269
270 if (GNUNET_YES == add_json)
271 if (CURLE_OK !=
272 curl_easy_setopt (eh,
273 CURLOPT_HTTPHEADER,
274 ctx->json_header))
275 {
276 GNUNET_break (0);
277 curl_easy_cleanup (eh);
278 return NULL;
279 }
280
281 job = GNUNET_new (struct GNUNET_CURL_Job);
282 if ( (CURLE_OK !=
283 curl_easy_setopt (eh,
284 CURLOPT_PRIVATE,
285 job)) ||
286 (CURLE_OK !=
287 curl_easy_setopt (eh,
288 CURLOPT_WRITEFUNCTION,
289 &download_cb)) ||
290 (CURLE_OK !=
291 curl_easy_setopt (eh,
292 CURLOPT_WRITEDATA,
293 &job->db)) ||
294 (CURLE_OK !=
295 curl_easy_setopt (eh,
296 CURLOPT_SHARE,
297 ctx->share)) ||
298 (CURLM_OK !=
299 curl_multi_add_handle (ctx->multi,
300 eh)) )
301 {
302 GNUNET_break (0);
303 GNUNET_free (job);
304 curl_easy_cleanup (eh);
305 return NULL;
306 }
307
308 job->easy_handle = eh;
309 job->ctx = ctx;
310 job->jcc = jcc;
311 job->jcc_cls = jcc_cls;
312 GNUNET_CONTAINER_DLL_insert (ctx->jobs_head,
313 ctx->jobs_tail,
314 job);
315 return job;
316}
317
318
319/**
320 * Cancel a job. Must only be called before the job completion
321 * callback is called for the respective job.
322 *
323 * @param job job to cancel
324 */
325void
326GNUNET_CURL_job_cancel (struct GNUNET_CURL_Job *job)
327{
328 struct GNUNET_CURL_Context *ctx = job->ctx;
329
330 GNUNET_CONTAINER_DLL_remove (ctx->jobs_head,
331 ctx->jobs_tail,
332 job);
333 GNUNET_break (CURLM_OK ==
334 curl_multi_remove_handle (ctx->multi,
335 job->easy_handle));
336 curl_easy_cleanup (job->easy_handle);
337 GNUNET_free_non_null (job->db.buf);
338 GNUNET_free (job);
339}
340
341
342/**
343 * Obtain information about the final result about the
344 * HTTP download. If the download was successful, parses
345 * the JSON in the @a db and returns it. Also returns
346 * the HTTP @a response_code. If the download failed,
347 * the return value is NULL. The response code is set
348 * in any case, on download errors to zero.
349 *
350 * Calling this function also cleans up @a db.
351 *
352 * @param db download buffer
353 * @param eh CURL handle (to get the response code)
354 * @param[out] response_code set to the HTTP response code
355 * (or zero if we aborted the download, i.e.
356 * because the response was too big, or if
357 * the JSON we received was malformed).
358 * @return NULL if downloading a JSON reply failed
359 */
360static json_t *
361download_get_result (struct DownloadBuffer *db,
362 CURL *eh,
363 long *response_code)
364{
365 json_t *json;
366 json_error_t error;
367 char *ct;
368
369 if ( (CURLE_OK !=
370 curl_easy_getinfo (eh,
371 CURLINFO_CONTENT_TYPE,
372 &ct)) ||
373 (NULL == ct) ||
374 (0 != strcasecmp (ct,
375 "application/json")) )
376 {
377 /* No content type or explicitly not JSON, refuse to parse
378 (but keep response code) */
379 if (CURLE_OK !=
380 curl_easy_getinfo (eh,
381 CURLINFO_RESPONSE_CODE,
382 response_code))
383 {
384 /* unexpected error... */
385 GNUNET_break (0);
386 *response_code = 0;
387 }
388 return NULL;
389 }
390
391 json = NULL;
392 if (0 == db->eno)
393 {
394 json = json_loadb (db->buf,
395 db->buf_size,
396 JSON_REJECT_DUPLICATES | JSON_DISABLE_EOF_CHECK,
397 &error);
398 if (NULL == json)
399 {
400 JSON_WARN (error);
401 *response_code = 0;
402 }
403 }
404 GNUNET_free_non_null (db->buf);
405 db->buf = NULL;
406 db->buf_size = 0;
407 if (NULL != json)
408 {
409 if (CURLE_OK !=
410 curl_easy_getinfo (eh,
411 CURLINFO_RESPONSE_CODE,
412 response_code))
413 {
414 /* unexpected error... */
415 GNUNET_break (0);
416 *response_code = 0;
417 }
418 }
419 return json;
420}
421
422
423/**
424 * Run the main event loop for the Taler interaction.
425 *
426 * @param ctx the library context
427 */
428void
429GNUNET_CURL_perform (struct GNUNET_CURL_Context *ctx)
430{
431 CURLMsg *cmsg;
432 struct GNUNET_CURL_Job *job;
433 int n_running;
434 int n_completed;
435 long response_code;
436 json_t *j;
437
438 (void) curl_multi_perform (ctx->multi,
439 &n_running);
440 while (NULL != (cmsg = curl_multi_info_read (ctx->multi,
441 &n_completed)))
442 {
443 /* Only documented return value is CURLMSG_DONE */
444 GNUNET_break (CURLMSG_DONE == cmsg->msg);
445 GNUNET_assert (CURLE_OK ==
446 curl_easy_getinfo (cmsg->easy_handle,
447 CURLINFO_PRIVATE,
448 (char **) &job));
449 GNUNET_assert (job->ctx == ctx);
450 j = download_get_result (&job->db,
451 job->easy_handle,
452 &response_code);
453 job->jcc (job->jcc_cls,
454 response_code,
455 j);
456 GNUNET_CURL_job_cancel (job);
457 }
458}
459
460
461/**
462 * Obtain the information for a select() call to wait until
463 * #GNUNET_CURL_perform() is ready again. Note that calling
464 * any other GNUNET_CURL-API may also imply that the library
465 * is again ready for #GNUNET_CURL_perform().
466 *
467 * Basically, a client should use this API to prepare for select(),
468 * then block on select(), then call #GNUNET_CURL_perform() and then
469 * start again until the work with the context is done.
470 *
471 * This function will NOT zero out the sets and assumes that @a max_fd
472 * and @a timeout are already set to minimal applicable values. It is
473 * safe to give this API FD-sets and @a max_fd and @a timeout that are
474 * already initialized to some other descriptors that need to go into
475 * the select() call.
476 *
477 * @param ctx context to get the event loop information for
478 * @param read_fd_set will be set for any pending read operations
479 * @param write_fd_set will be set for any pending write operations
480 * @param except_fd_set is here because curl_multi_fdset() has this argument
481 * @param max_fd set to the highest FD included in any set;
482 * if the existing sets have no FDs in it, the initial
483 * value should be "-1". (Note that `max_fd + 1` will need
484 * to be passed to select().)
485 * @param timeout set to the timeout in milliseconds (!); -1 means
486 * no timeout (NULL, blocking forever is OK), 0 means to
487 * proceed immediately with #GNUNET_CURL_perform().
488 */
489void
490GNUNET_CURL_get_select_info (struct GNUNET_CURL_Context *ctx,
491 fd_set *read_fd_set,
492 fd_set *write_fd_set,
493 fd_set *except_fd_set,
494 int *max_fd,
495 long *timeout)
496{
497 long to;
498 int m;
499
500 m = -1;
501 GNUNET_assert (CURLM_OK ==
502 curl_multi_fdset (ctx->multi,
503 read_fd_set,
504 write_fd_set,
505 except_fd_set,
506 &m));
507 to = *timeout;
508 *max_fd = GNUNET_MAX (m, *max_fd);
509 GNUNET_assert (CURLM_OK ==
510 curl_multi_timeout (ctx->multi,
511 &to));
512
513 /* Only if what we got back from curl is smaller than what we
514 already had (-1 == infinity!), then update timeout */
515 if ( (to < *timeout) &&
516 (-1 != to) )
517 *timeout = to;
518 if ( (-1 == (*timeout)) &&
519 (NULL != ctx->jobs_head) )
520 *timeout = to;
521}
522
523
524/**
525 * Cleanup library initialisation resources. This function should be called
526 * after using this library to cleanup the resources occupied during library's
527 * initialisation.
528 *
529 * @param ctx the library context
530 */
531void
532GNUNET_CURL_fini (struct GNUNET_CURL_Context *ctx)
533{
534 /* all jobs must have been cancelled at this time, assert this */
535 GNUNET_assert (NULL == ctx->jobs_head);
536 curl_share_cleanup (ctx->share);
537 curl_multi_cleanup (ctx->multi);
538 curl_slist_free_all (ctx->json_header);
539 GNUNET_free (ctx);
540}
541
542
543/**
544 * Initial global setup logic, specifically runs the Curl setup.
545 */
546__attribute__ ((constructor))
547void
548GNUNET_CURL_constructor__ (void)
549{
550 CURLcode ret;
551
552 if (CURLE_OK != (ret = curl_global_init (CURL_GLOBAL_DEFAULT)))
553 {
554 CURL_STRERROR (GNUNET_ERROR_TYPE_ERROR,
555 "curl_global_init",
556 ret);
557 curl_fail = 1;
558 }
559}
560
561
562/**
563 * Cleans up after us, specifically runs the Curl cleanup.
564 */
565__attribute__ ((destructor))
566void
567GNUNET_CURL_destructor__ (void)
568{
569 if (curl_fail)
570 return;
571 curl_global_cleanup ();
572}
573
574/* end of curl.c */
diff --git a/src/include/Makefile.am b/src/include/Makefile.am
index 82fa9006b..92893f7c7 100644
--- a/src/include/Makefile.am
+++ b/src/include/Makefile.am
@@ -45,6 +45,7 @@ gnunetinclude_HEADERS = \
45 gnunet_conversation_service.h \ 45 gnunet_conversation_service.h \
46 gnunet_core_service.h \ 46 gnunet_core_service.h \
47 gnunet_crypto_lib.h \ 47 gnunet_crypto_lib.h \
48 gnunet_curl_lib.h \
48 gnunet_datacache_lib.h \ 49 gnunet_datacache_lib.h \
49 gnunet_datacache_plugin.h \ 50 gnunet_datacache_plugin.h \
50 gnunet_datastore_service.h \ 51 gnunet_datastore_service.h \
diff --git a/src/include/gnunet_curl_lib.h b/src/include/gnunet_curl_lib.h
new file mode 100644
index 000000000..098b4dc37
--- /dev/null
+++ b/src/include/gnunet_curl_lib.h
@@ -0,0 +1,155 @@
1/*
2 This file is part of GNUnet
3 Copyright (C) 2014, 2015, 2016 GNUnet e.V.
4
5 GNUnet is free software; you can redistribute it and/or modify it under the
6 terms of the GNU General Public License as published by the Free Software
7 Foundation; either version 3, or (at your option) any later version.
8
9 GNUnet is distributed in the hope that it will be useful, but WITHOUT ANY
10 WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR
11 A PARTICULAR PURPOSE. See the GNU General Public License for more details.
12
13 You should have received a copy of the GNU General Public License along with
14 GNUnet; see the file COPYING. If not, If not, see
15 <http://www.gnu.org/licenses/>
16*/
17/**
18 * @file src/include/gnunet_curl_lib.h
19 * @brief library to make it easy to download JSON replies over HTTP
20 * @author Sree Harsha Totakura <sreeharsha@totakura.in>
21 * @author Christian Grothoff
22 *
23 * @defgroup curl CURL integration library
24 * Download JSON using libcurl.
25 * @{
26 */
27#ifndef GNUNET_CURL_LIB_H
28#define GNUNET_CURL_LIB_H
29#include <curl/curl.h>
30#include <jansson.h>
31#include <gnunet/gnunet_util_lib.h>
32
33
34/**
35 * Initialise this library. This function should be called before using any of
36 * the following functions.
37 *
38 * @return library context
39 */
40struct GNUNET_CURL_Context *
41GNUNET_CURL_init (void);
42
43
44/**
45 * Obtain the information for a select() call to wait until
46 * #GNUNET_CURL_perform() is ready again. Note that calling
47 * any other TALER_EXCHANGE-API may also imply that the library
48 * is again ready for #GNUNET_CURL_perform().
49 *
50 * Basically, a client should use this API to prepare for select(),
51 * then block on select(), then call #GNUNET_CURL_perform() and then
52 * start again until the work with the context is done.
53 *
54 * This function will NOT zero out the sets and assumes that @a max_fd
55 * and @a timeout are already set to minimal applicable values. It is
56 * safe to give this API FD-sets and @a max_fd and @a timeout that are
57 * already initialized to some other descriptors that need to go into
58 * the select() call.
59 *
60 * @param ctx context to get the event loop information for
61 * @param read_fd_set will be set for any pending read operations
62 * @param write_fd_set will be set for any pending write operations
63 * @param except_fd_set is here because curl_multi_fdset() has this argument
64 * @param max_fd set to the highest FD included in any set;
65 * if the existing sets have no FDs in it, the initial
66 * value should be "-1". (Note that `max_fd + 1` will need
67 * to be passed to select().)
68 * @param timeout set to the timeout in milliseconds (!); -1 means
69 * no timeout (NULL, blocking forever is OK), 0 means to
70 * proceed immediately with #GNUNET_CURL_perform().
71 */
72void
73GNUNET_CURL_get_select_info (struct GNUNET_CURL_Context *ctx,
74 fd_set *read_fd_set,
75 fd_set *write_fd_set,
76 fd_set *except_fd_set,
77 int *max_fd,
78 long *timeout);
79
80
81/**
82 * Run the main event loop for the Taler interaction.
83 *
84 * @param ctx the library context
85 */
86void
87GNUNET_CURL_perform (struct GNUNET_CURL_Context *ctx);
88
89
90/**
91 * Cleanup library initialisation resources. This function should be called
92 * after using this library to cleanup the resources occupied during library's
93 * initialisation.
94 *
95 * @param ctx the library context
96 */
97void
98GNUNET_CURL_fini (struct GNUNET_CURL_Context *ctx);
99
100
101/**
102 * Entry in the context's job queue.
103 */
104struct GNUNET_CURL_Job;
105
106/**
107 * Function to call upon completion of a job.
108 *
109 * @param cls closure
110 * @param response_code HTTP response code from server, 0 on hard error
111 * @param json response, NULL if response was not in JSON format
112 */
113typedef void
114(*GNUNET_CURL_JobCompletionCallback)(void *cls,
115 long response_code,
116 json_t *json);
117
118
119/**
120 * Schedule a CURL request to be executed and call the given @a jcc
121 * upon its completion. Note that the context will make use of the
122 * CURLOPT_PRIVATE facility of the CURL @a eh.
123 *
124 * This function modifies the CURL handle to add the
125 * "Content-Type: application/json" header if @a add_json is set.
126 *
127 * @param ctx context to execute the job in
128 * @param eh curl easy handle for the request, will
129 * be executed AND cleaned up
130 * @param add_json add "application/json" content type header
131 * @param jcc callback to invoke upon completion
132 * @param jcc_cls closure for @a jcc
133 * @return NULL on error (in this case, @eh is still released!)
134 */
135struct GNUNET_CURL_Job *
136GNUNET_CURL_job_add (struct GNUNET_CURL_Context *ctx,
137 CURL *eh,
138 int add_json,
139 GNUNET_CURL_JobCompletionCallback jcc,
140 void *jcc_cls);
141
142
143/**
144 * Cancel a job. Must only be called before the job completion
145 * callback is called for the respective job.
146 *
147 * @param job job to cancel
148 */
149void
150GNUNET_CURL_job_cancel (struct GNUNET_CURL_Job *job);
151
152#endif
153/** @} */ /* end of group */
154
155/* end of gnunet_curl_lib.h */
diff --git a/src/json/json.c b/src/json/json.c
index aa74bfd48..a2d1a9608 100644
--- a/src/json/json.c
+++ b/src/json/json.c
@@ -46,6 +46,8 @@ GNUNET_JSON_parse (const json_t *root,
46 unsigned int i; 46 unsigned int i;
47 json_t *pos; 47 json_t *pos;
48 48
49 if (NULL == root)
50 return GNUNET_SYSERR;
49 for (i=0;NULL != spec[i].parser;i++) 51 for (i=0;NULL != spec[i].parser;i++)
50 { 52 {
51 if (NULL == spec[i].field) 53 if (NULL == spec[i].field)