aboutsummaryrefslogtreecommitdiff
path: root/src
diff options
context:
space:
mode:
authorAlessio Vanni <vannilla@firemail.cc>2021-11-25 20:47:49 +0100
committerAlessio Vanni <vannilla@firemail.cc>2021-11-25 20:47:49 +0100
commita24bbd5b39c7d26d97af357531ed05579016bd69 (patch)
treeaa6094e8ce1c41f2b323ceba803701d385ba3ade /src
parent63854ee52ec8d24928c2346928a3dbea22ebd1fe (diff)
parent0bd99177d2424a76bcf26b5347bfe8ee568348e8 (diff)
downloadgnunet-a24bbd5b39c7d26d97af357531ed05579016bd69.tar.gz
gnunet-a24bbd5b39c7d26d97af357531ed05579016bd69.zip
Merge branch 'dev/vanni/bcd-new'
Diffstat (limited to 'src')
-rw-r--r--src/gns/Makefile.am2
-rw-r--r--src/gns/gnunet-bcd.c884
-rw-r--r--src/namestore/gnunet-namestore-fcfsd.c11
-rw-r--r--src/namestore/gnunet-namestore.c6
-rw-r--r--src/statistics/statistics_api.c6
-rw-r--r--src/transport/tcp_service_legacy.c14
-rw-r--r--src/util/Makefile.am3
-rw-r--r--src/util/gnunet-qr.c597
-rw-r--r--src/util/service.c8
9 files changed, 954 insertions, 577 deletions
diff --git a/src/gns/Makefile.am b/src/gns/Makefile.am
index 3aaa734f2..ba46781f0 100644
--- a/src/gns/Makefile.am
+++ b/src/gns/Makefile.am
@@ -80,7 +80,9 @@ bin_PROGRAMS = \
80noinst_PROGRAMS = \ 80noinst_PROGRAMS = \
81 gnunet-gns-benchmark 81 gnunet-gns-benchmark
82 82
83if HAVE_PDFLATEX
83bin_PROGRAMS += gnunet-bcd 84bin_PROGRAMS += gnunet-bcd
85endif
84 86
85REST_PLUGIN = libgnunet_plugin_rest_gns.la 87REST_PLUGIN = libgnunet_plugin_rest_gns.la
86 88
diff --git a/src/gns/gnunet-bcd.c b/src/gns/gnunet-bcd.c
index a2e94089c..83efcfba5 100644
--- a/src/gns/gnunet-bcd.c
+++ b/src/gns/gnunet-bcd.c
@@ -30,394 +30,522 @@
30#include "gnunet_identity_service.h" 30#include "gnunet_identity_service.h"
31#include "gnunet_mhd_compat.h" 31#include "gnunet_mhd_compat.h"
32 32
33struct StaticResource
34{
35 /**
36 * Handle to file on disk.
37 */
38 struct GNUNET_DISK_FileHandle *handle;
39
40 /**
41 * Size in bytes of the file.
42 */
43 uint64_t size;
44
45 /**
46 * Cached response object to send to clients.
47 */
48 struct MHD_Response *response;
49};
50
51struct ParameterMap
52{
53 /**
54 * Name of the parameter from the request.
55 */
56 char *name;
57
58 /**
59 * Name of the definition in the TeX output.
60 */
61 char *definition;
62};
63
33/** 64/**
34 * Error page to display if submitted GNS key is invalid. 65 * Handle to the HTTP server as provided by libmicrohttpd
35 */ 66 */
36#define INVALID_GNSKEY \ 67static struct MHD_Daemon *httpd = NULL;
37 "<html><head><title>Error</title><body>Invalid GNS public key given.</body></html>"
38 68
39/** 69/**
40 * Error page to display on 404. 70 * Our primary task for the HTTPD.
41 */ 71 */
42#define NOT_FOUND \ 72static struct GNUNET_SCHEDULER_Task *httpd_task = NULL;
43 "<html><head><title>Error</title><body>404 not found</body></html>"
44 73
45/** 74/**
46 * Handle to the HTTP server as provided by libmicrohttpd 75 * Index file resource (simple result).
47 */ 76 */
48static struct MHD_Daemon *daemon_handle; 77static struct StaticResource *index_simple = NULL;
49 78
50/** 79/**
51 * Our configuration. 80 * Index file resource (full result).
52 */ 81 */
53static const struct GNUNET_CONFIGURATION_Handle *cfg; 82static struct StaticResource *index_full = NULL;
54 83
55/** 84/**
56 * Our primary task for the HTTPD. 85 * Error: invalid gns key.
57 */ 86 */
58static struct GNUNET_SCHEDULER_Task *http_task; 87static struct StaticResource *key_error = NULL;
59 88
60/** 89/**
61 * Our main website. 90 * Error: 404
62 */ 91 */
63static struct MHD_Response *main_response; 92static struct StaticResource *notfound_error = NULL;
64 93
65/** 94/**
66 * Error: invalid gns key. 95 * Errors after receiving the form data.
67 */ 96 */
68static struct MHD_Response *invalid_gnskey_response; 97static struct StaticResource *internal_error = NULL;
69 98
70/** 99/**
71 * Error: 404 100 * Other errors.
72 */ 101 */
73static struct MHD_Response *not_found_response; 102static struct StaticResource *forbidden_error = NULL;
74 103
75/** 104/**
76 * Absolute name of the 'gns-bcd.tex' file. 105 * Full path to the TeX template file (simple result)
77 */ 106 */
78static char *resfile; 107static char *tex_file_simple = NULL;
79 108
80/** 109/**
81 * Port number. 110 * Full path to the TeX template file (full result)
82 */ 111 */
83static uint16_t port = 8888; 112static char *tex_file_full = NULL;
84 113
114/**
115 * Full path to the TeX template file (PNG result)
116 */
117static char *tex_file_png = NULL;
85 118
86struct Entry 119/**
87{ 120 * Used as a sort of singleton to send exactly one 100 CONTINUE per request.
88 const char *formname; 121 */
89 const char *texname; 122static int continue_100 = 100;
123
124/**
125 * Map of names with TeX definitions, used during PDF generation.
126 */
127static const struct ParameterMap pmap[] = {
128 {"prefix", "prefix"},
129 {"name", "name"},
130 {"suffix", "suffix"},
131 {"street", "street"},
132 {"city", "city"},
133 {"phone", "phone"},
134 {"fax", "fax"},
135 {"email", "email"},
136 {"homepage", "homepage"},
137 {"org", "organization"},
138 {"department", "department"},
139 {"subdepartment", "subdepartment"},
140 {"jobtitle", "jobtitle"},
141 {NULL, NULL},
90}; 142};
91 143
144/**
145 * Port number.
146 */
147static uint16_t port = 8888;
92 148
93/** 149/**
94 * Main request handler. 150 * Task ran at shutdown to clean up everything.
151 *
152 * @param cls unused
95 */ 153 */
96static MHD_RESULT 154static void
97access_handler_callback (void *cls, 155do_shutdown (void *cls)
98 struct MHD_Connection *connection,
99 const char *url,
100 const char *method,
101 const char *version,
102 const char *upload_data,
103 size_t *upload_data_size,
104 void **con_cls)
105{ 156{
106 static int dummy; 157 /* We cheat a bit here: the file descriptor is implicitly closed by MHD, so
107 static const struct Entry map[] = { { "prefix", "prefix" }, 158 calling `GNUNET_DISK_file_close' would generate a spurious warning message
108 { "name", "name" }, 159 in the log. Since that function does nothing but close the descriptor and
109 { "suffix", "suffix" }, 160 free the allocated memory, After destroying the response all that's left to
110 { "street", "street" }, 161 do is call `GNUNET_free'. */
111 { "city", "city" }, 162 if (NULL != index_simple)
112 { "phone", "phone" },
113 { "fax", "fax" },
114 { "email", "email" },
115 { "homepage", "homepage" },
116 { "orga", "orga" },
117 { "departmenti18n", "departmentde" },
118 { "departmenten", "departmenten" },
119 { "subdepartmenti18n",
120 "subdepartmentde" },
121 { "subdepartmenten", "subdepartmenten" },
122 { "jobtitlei18n", "jobtitlegerman" },
123 { "jobtitleen", "jobtitleenglish" },
124 { "subdepartmenten", "subdepartmenten" },
125 { NULL, NULL } };
126
127 (void) cls;
128 (void) version;
129 (void) upload_data;
130 (void) upload_data_size;
131 if (0 != strcmp (method, MHD_HTTP_METHOD_GET))
132 { 163 {
133 GNUNET_log (GNUNET_ERROR_TYPE_WARNING, 164 MHD_destroy_response (index_simple->response);
134 _ ("Refusing `%s' request to HTTP server\n"), 165 GNUNET_free (index_simple->handle);
135 method); 166 GNUNET_free (index_simple);
136 return MHD_NO;
137 } 167 }
138 if (NULL == *con_cls) 168 if (NULL != index_full)
139 { 169 {
140 (*con_cls) = &dummy; 170 MHD_destroy_response (index_full->response);
141 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "Sending 100 CONTINUE reply\n"); 171 GNUNET_free (index_full->handle);
142 return MHD_YES; /* send 100 continue */ 172 GNUNET_free (index_full);
143 } 173 }
144 if (0 == strcasecmp (url, "/")) 174 if (NULL != key_error)
145 return MHD_queue_response (connection, MHD_HTTP_OK, main_response);
146 if (0 == strcasecmp (url, "/submit.pdf"))
147 { 175 {
148 unsigned int i; 176 MHD_destroy_response (key_error->response);
149 char *p; 177 GNUNET_free (key_error->handle);
150 char *tmp; 178 GNUNET_free (key_error);
151 char *deffile; 179 }
152 struct GNUNET_IDENTITY_PublicKey pub; 180 if (NULL != notfound_error)
153 size_t slen; 181 {
154 FILE *f; 182 MHD_destroy_response (notfound_error->response);
155 struct stat st; 183 GNUNET_free (notfound_error->handle);
156 struct MHD_Response *response; 184 GNUNET_free (notfound_error);
157 int fd; 185 }
158 MHD_RESULT ret; 186 if (NULL != internal_error)
159 187 {
160 const char *gpg_fp = MHD_lookup_connection_value (connection, 188 MHD_destroy_response (internal_error->response);
161 MHD_GET_ARGUMENT_KIND, 189 GNUNET_free (internal_error->handle);
162 "gpgfingerprint"); 190 GNUNET_free (internal_error);
163 const char *gns_nick = MHD_lookup_connection_value (connection, 191 }
164 MHD_GET_ARGUMENT_KIND, 192 if (NULL != forbidden_error)
165 "gnsnick"); 193 {
166 const char *gnskey = 194 MHD_destroy_response (forbidden_error->response);
167 MHD_lookup_connection_value (connection, MHD_GET_ARGUMENT_KIND, "gnskey"); 195 GNUNET_free (forbidden_error->handle);
168 if ((NULL == gnskey) || 196 GNUNET_free (forbidden_error);
169 (GNUNET_OK !=
170 GNUNET_IDENTITY_public_key_from_string (gnskey,
171 &pub)))
172 {
173 return MHD_queue_response (connection,
174 MHD_HTTP_OK,
175 invalid_gnskey_response);
176 }
177 tmp = GNUNET_DISK_mkdtemp (gnskey);
178 if (NULL == tmp)
179 {
180 GNUNET_log_strerror_file (GNUNET_ERROR_TYPE_ERROR, "mktemp", gnskey);
181 return MHD_NO;
182 }
183 GNUNET_asprintf (&deffile, "%s%s%s", tmp, DIR_SEPARATOR_STR, "def.tex");
184 f = fopen (deffile, "w");
185 if (NULL == f)
186 {
187 GNUNET_log_strerror_file (GNUNET_ERROR_TYPE_ERROR, "open", deffile);
188 GNUNET_free (deffile);
189 GNUNET_DISK_directory_remove (tmp);
190 GNUNET_free (tmp);
191 return MHD_NO;
192 }
193 for (i = 0; NULL != map[i].formname; i++)
194 {
195 const char *val = MHD_lookup_connection_value (connection,
196 MHD_GET_ARGUMENT_KIND,
197 map[i].formname);
198 if (NULL != val)
199 fprintf (f, "\\def\\%s{%s}\n", map[i].texname, val);
200 else
201 fprintf (f, "\\def\\%s{}\n", map[i].texname);
202 }
203 if (NULL != gpg_fp)
204 {
205 char *gpg1;
206 char *gpg2;
207
208 slen = strlen (gpg_fp);
209 gpg1 = GNUNET_strndup (gpg_fp, slen / 2);
210 gpg2 = GNUNET_strdup (&gpg_fp[slen / 2]);
211 fprintf (f, "\\def\\gpglineone{%s}\n\\def\\gpglinetwo{%s}\n", gpg1, gpg2);
212 GNUNET_free (gpg2);
213 GNUNET_free (gpg1);
214 }
215 fprintf (f,
216 "\\def\\gns{%s/%s}\n",
217 gnskey,
218 (NULL == gns_nick) ? "" : gns_nick);
219 fclose (f);
220 GNUNET_asprintf (
221 &p,
222 "cd %s; cp %s gns-bcd.tex | pdflatex --enable-write18 gns-bcd.tex > /dev/null 2> /dev/null",
223 tmp,
224 resfile);
225 GNUNET_free (deffile);
226 ret = system (p);
227 if (WIFSIGNALED (ret) || (0 != WEXITSTATUS (ret)))
228 GNUNET_log_strerror_file (GNUNET_ERROR_TYPE_ERROR, "system", p);
229 GNUNET_asprintf (&deffile, "%s%s%s", tmp, DIR_SEPARATOR_STR, "gns-bcd.pdf");
230 fd = open (deffile, O_RDONLY);
231 if (-1 == fd)
232 {
233 GNUNET_log_strerror_file (GNUNET_ERROR_TYPE_ERROR, "open", deffile);
234 GNUNET_free (deffile);
235 GNUNET_free (p);
236 GNUNET_DISK_directory_remove (tmp);
237 GNUNET_free (tmp);
238 return MHD_NO;
239 }
240 GNUNET_break (0 == stat (deffile, &st));
241 if (NULL ==
242 (response = MHD_create_response_from_fd ((size_t) st.st_size, fd)))
243 {
244 GNUNET_break (0);
245 GNUNET_break (0 == close (fd));
246 GNUNET_free (deffile);
247 GNUNET_free (p);
248 GNUNET_DISK_directory_remove (tmp);
249 GNUNET_free (tmp);
250 return MHD_NO;
251 }
252 (void) MHD_add_response_header (response,
253 MHD_HTTP_HEADER_CONTENT_TYPE,
254 "application/pdf");
255 ret = MHD_queue_response (connection, MHD_HTTP_OK, response);
256 MHD_destroy_response (response);
257 GNUNET_free (deffile);
258 GNUNET_free (p);
259 GNUNET_DISK_directory_remove (tmp);
260 GNUNET_free (tmp);
261 return ret;
262 } 197 }
263 return MHD_queue_response (connection,
264 MHD_HTTP_NOT_FOUND,
265 not_found_response);
266}
267
268
269/**
270 * Function that queries MHD's select sets and
271 * starts the task waiting for them.
272 */
273static struct GNUNET_SCHEDULER_Task *
274prepare_daemon (struct MHD_Daemon *daemon_handle);
275 198
199 if (NULL != httpd_task)
200 {
201 GNUNET_SCHEDULER_cancel (httpd_task);
202 }
203 if (NULL != httpd)
204 {
205 MHD_stop_daemon (httpd);
206 }
207}
276 208
277/** 209/**
278 * Call MHD to process pending requests and then go back 210 * Called when the HTTP server has some pending operations.
279 * and schedule the next run. 211 *
212 * @param cls unused
280 */ 213 */
281static void 214static void
282run_daemon (void *cls) 215do_httpd (void *cls);
283{
284 struct MHD_Daemon *daemon_handle = cls;
285
286 http_task = NULL;
287 GNUNET_assert (MHD_YES == MHD_run (daemon_handle));
288 http_task = prepare_daemon (daemon_handle);
289}
290
291 216
292/** 217/**
293 * Function that queries MHD's select sets and 218 * Schedule a task to run MHD.
294 * starts the task waiting for them.
295 */ 219 */
296static struct GNUNET_SCHEDULER_Task * 220static void
297prepare_daemon (struct MHD_Daemon *daemon_handle) 221run_httpd (void)
298{ 222{
299 struct GNUNET_SCHEDULER_Task *ret;
300 fd_set rs; 223 fd_set rs;
301 fd_set ws; 224 fd_set ws;
302 fd_set es; 225 fd_set es;
303 struct GNUNET_NETWORK_FDSet *wrs; 226
304 struct GNUNET_NETWORK_FDSet *wws; 227 struct GNUNET_NETWORK_FDSet *grs = GNUNET_NETWORK_fdset_create ();
305 int max; 228 struct GNUNET_NETWORK_FDSet *gws = GNUNET_NETWORK_fdset_create ();
306 MHD_UNSIGNED_LONG_LONG timeout; 229 struct GNUNET_NETWORK_FDSet *ges = GNUNET_NETWORK_fdset_create ();
307 int haveto;
308 struct GNUNET_TIME_Relative tv;
309 230
310 FD_ZERO (&rs); 231 FD_ZERO (&rs);
311 FD_ZERO (&ws); 232 FD_ZERO (&ws);
312 FD_ZERO (&es); 233 FD_ZERO (&es);
313 wrs = GNUNET_NETWORK_fdset_create (); 234
314 wws = GNUNET_NETWORK_fdset_create (); 235 int max = -1;
315 max = -1; 236 GNUNET_assert (MHD_YES == MHD_get_fdset (httpd, &rs, &ws, &es, &max));
316 GNUNET_assert (MHD_YES == MHD_get_fdset (daemon_handle, &rs, &ws, &es, &max)); 237
317 haveto = MHD_get_timeout (daemon_handle, &timeout); 238 unsigned MHD_LONG_LONG timeout = 0;
318 if (haveto == MHD_YES) 239 struct GNUNET_TIME_Relative gtime = GNUNET_TIME_UNIT_FOREVER_REL;
319 tv.rel_value_us = (uint64_t) timeout * 1000LL; 240 if (MHD_YES == MHD_get_timeout (httpd, &timeout))
320 else 241 {
321 tv = GNUNET_TIME_UNIT_FOREVER_REL; 242 gtime = GNUNET_TIME_relative_multiply (GNUNET_TIME_UNIT_MILLISECONDS,
322 GNUNET_NETWORK_fdset_copy_native (wrs, &rs, max + 1); 243 timeout);
323 GNUNET_NETWORK_fdset_copy_native (wws, &ws, max + 1); 244 }
324 ret = GNUNET_SCHEDULER_add_select (GNUNET_SCHEDULER_PRIORITY_HIGH, 245
325 tv, 246 GNUNET_NETWORK_fdset_copy_native (grs, &rs, max + 1);
326 wrs, 247 GNUNET_NETWORK_fdset_copy_native (gws, &ws, max + 1);
327 wws, 248 GNUNET_NETWORK_fdset_copy_native (ges, &es, max + 1);
328 &run_daemon, 249
329 daemon_handle); 250 httpd_task = GNUNET_SCHEDULER_add_select (GNUNET_SCHEDULER_PRIORITY_HIGH,
330 GNUNET_NETWORK_fdset_destroy (wrs); 251 gtime,
331 GNUNET_NETWORK_fdset_destroy (wws); 252 grs,
332 return ret; 253 gws,
254 &do_httpd,
255 NULL);
256 GNUNET_NETWORK_fdset_destroy (grs);
257 GNUNET_NETWORK_fdset_destroy (gws);
258 GNUNET_NETWORK_fdset_destroy (ges);
333} 259}
334 260
261/**
262 * Called when the HTTP server has some pending operations.
263 *
264 * @param cls unused
265 */
266static void
267do_httpd (void *cls)
268{
269 httpd_task = NULL;
270 MHD_run (httpd);
271 run_httpd ();
272}
335 273
336/** 274/**
337 * Start server offering our hostlist. 275 * Send a response back to a connected client.
338 * 276 *
339 * @return #GNUNET_OK on success 277 * @param cls unused
278 * @param connection the connection with the client
279 * @param url the requested address
280 * @param method the HTTP method used
281 * @param version the protocol version (including the "HTTP/" part)
282 * @param upload_data data sent with a POST request
283 * @param upload_data_size length in bytes of the POST data
284 * @param ptr used to pass data between request handling phases
285 * @return MHD_NO on error
340 */ 286 */
341static int 287static MHD_RESULT
342server_start () 288create_response (void *cls,
289 struct MHD_Connection *connection,
290 const char *url,
291 const char *method,
292 const char *version,
293 const char *upload_data,
294 size_t *upload_data_size,
295 void **ptr)
343{ 296{
344 if (0 == port) 297 (void) cls;
298 (void) version;
299 (void) upload_data;
300 (void) upload_data_size;
301
302 bool isget = (0 == strcmp (method, MHD_HTTP_METHOD_GET));
303 bool ishead = (0 == strcmp (method, MHD_HTTP_METHOD_HEAD));
304
305 if (!isget && !ishead)
345 { 306 {
346 GNUNET_log (GNUNET_ERROR_TYPE_ERROR, 307 return MHD_queue_response (connection,
347 _ ("Invalid port number %u. Exiting.\n"), 308 MHD_HTTP_NOT_IMPLEMENTED,
348 port); 309 forbidden_error->response);
349 return GNUNET_SYSERR;
350 } 310 }
351 GNUNET_log (GNUNET_ERROR_TYPE_INFO, 311
352 _ ("Businesscard HTTP server starts on %u\n"), 312 if (ishead)
353 port);
354 daemon_handle = MHD_start_daemon (MHD_USE_DUAL_STACK | MHD_USE_DEBUG,
355 port,
356 NULL /* accept_policy_callback */,
357 NULL,
358 &access_handler_callback,
359 NULL,
360 MHD_OPTION_CONNECTION_LIMIT,
361 (unsigned int) 512,
362 MHD_OPTION_PER_IP_CONNECTION_LIMIT,
363 (unsigned int) 2,
364 MHD_OPTION_CONNECTION_TIMEOUT,
365 (unsigned int) 60,
366 MHD_OPTION_CONNECTION_MEMORY_LIMIT,
367 (size_t) (16 * 1024),
368 MHD_OPTION_END);
369 if (NULL == daemon_handle)
370 { 313 {
371 GNUNET_log (GNUNET_ERROR_TYPE_ERROR, 314 /* Dedicated branch in case we want to provide a different result for some
372 _ ("Could not start businesscard HTTP server on port %u\n"), 315 reason (e.g. a non-web browser application using the web UI) */
373 (unsigned int) port); 316 return MHD_queue_response (connection,
374 return GNUNET_SYSERR; 317 MHD_HTTP_OK,
318 index_simple->response);
375 } 319 }
376 http_task = prepare_daemon (daemon_handle);
377 return GNUNET_OK;
378}
379 320
321 /* Send a 100 CONTINUE response to tell clients that the result of the
322 request might take some time */
323 if (NULL == *ptr)
324 {
325 *ptr = &continue_100;
326 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "Sending 100 CONTINUE\n");
327 return MHD_YES;
328 }
380 329
381/** 330 if (0 == strcmp ("/", url))
382 * Stop HTTP server. 331 {
383 */ 332 return MHD_queue_response (connection,
384static void 333 MHD_HTTP_OK,
385server_stop (void *cls) 334 index_simple->response);
386{ 335 }
387 (void) cls; 336
388 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "HTTP server shutdown\n"); 337 if (0 == strcmp ("/full", url))
389 if (NULL != http_task) 338 {
339 return MHD_queue_response (connection,
340 MHD_HTTP_OK,
341 index_full->response);
342 }
343
344 bool isfull = (0 == strcmp ("/submit/full", url));
345 bool issimple = (0 == strcmp ("/submit/simple", url));
346
347 if (!isfull && !issimple)
348 {
349 return MHD_queue_response (connection,
350 MHD_HTTP_NOT_FOUND,
351 notfound_error->response);
352 }
353
354 const char *gpgfp = MHD_lookup_connection_value (connection,
355 MHD_GET_ARGUMENT_KIND,
356 "gpgfingerprint");
357 const char *gnsnick = MHD_lookup_connection_value (connection,
358 MHD_GET_ARGUMENT_KIND,
359 "gnsnick");
360 const char *gnskey = MHD_lookup_connection_value (connection,
361 MHD_GET_ARGUMENT_KIND,
362 "gnskey");
363 const char *qrpng = MHD_lookup_connection_value (connection,
364 MHD_GET_ARGUMENT_KIND,
365 "gnspng");
366
367 struct GNUNET_IDENTITY_PublicKey pk;
368 if (NULL == gnskey
369 || GNUNET_OK != GNUNET_IDENTITY_public_key_from_string (gnskey, &pk))
370 {
371 return MHD_queue_response (connection,
372 MHD_HTTP_BAD_REQUEST,
373 key_error->response);
374 }
375
376 char *tmpd = GNUNET_DISK_mkdtemp (gnskey);
377 if (NULL == tmpd)
378 {
379 GNUNET_log_strerror_file (GNUNET_ERROR_TYPE_ERROR, "mktemp", gnskey);
380 return MHD_queue_response (connection,
381 MHD_HTTP_INTERNAL_SERVER_ERROR,
382 internal_error->response);
383 }
384
385 char *defpath = NULL;
386 GNUNET_asprintf (&defpath, "%s%s%s", tmpd, DIR_SEPARATOR_STR, "def.tex");
387
388 FILE *deffile = fopen (defpath, "w");
389 if (NULL == deffile)
390 { 390 {
391 GNUNET_SCHEDULER_cancel (http_task); 391 GNUNET_log_strerror_file (GNUNET_ERROR_TYPE_ERROR, "open", defpath);
392 http_task = NULL; 392 GNUNET_free (defpath);
393 GNUNET_DISK_directory_remove (tmpd);
394 GNUNET_free (tmpd);
395 return MHD_queue_response (connection,
396 MHD_HTTP_INTERNAL_SERVER_ERROR,
397 internal_error->response);
393 } 398 }
394 if (NULL != daemon_handle) 399
400 GNUNET_free (defpath);
401
402 for (size_t i=0; NULL!=pmap[i].name; ++i)
395 { 403 {
396 MHD_stop_daemon (daemon_handle); 404 const char *value = MHD_lookup_connection_value (connection,
397 daemon_handle = NULL; 405 MHD_GET_ARGUMENT_KIND,
406 pmap[i].name);
407 fprintf (deffile,
408 "\\def\\%s{%s}\n",
409 pmap[i].definition,
410 (NULL == value) ? "" : value);
398 } 411 }
399 if (NULL != main_response) 412
413 if (NULL != gpgfp)
400 { 414 {
401 MHD_destroy_response (main_response); 415 size_t len = strlen (gpgfp);
402 main_response = NULL; 416 char *line1 = GNUNET_strndup (gpgfp, len/2);
417 char *line2 = GNUNET_strdup (&gpgfp[len/2]);
418 fprintf (deffile,
419 "\\def\\gpglineone{%s}\n\\def\\gpglinetwo{%s}\n",
420 line1,
421 line2);
403 } 422 }
404 if (NULL != invalid_gnskey_response) 423
424 fprintf (deffile,
425 "\\def\\gns{%s/%s}\n",
426 gnskey,
427 (NULL == gnsnick) ? "" : gnsnick);
428
429 fclose (deffile);
430
431 char *command = NULL;
432 GNUNET_asprintf (&command,
433 "cd %s; cp %s gns-bcd.tex; "
434 "pdflatex %s gns-bcd.tex >/dev/null 2>&1",
435 tmpd,
436 (isfull) ? tex_file_full :
437 ((NULL == qrpng) ? tex_file_simple : tex_file_png),
438 (NULL == qrpng) ? "" : "-shell-escape");
439
440 int ret = system (command);
441
442 GNUNET_free (command);
443
444 if (WIFSIGNALED (ret) || 0 != WEXITSTATUS (ret))
405 { 445 {
406 MHD_destroy_response (invalid_gnskey_response); 446 GNUNET_log_strerror_file (GNUNET_ERROR_TYPE_ERROR, "system", command);
407 invalid_gnskey_response = NULL;
408 } 447 }
409 if (NULL != not_found_response) 448
449 GNUNET_asprintf (&defpath,
450 "%s%s%s",
451 tmpd,
452 DIR_SEPARATOR_STR,
453 (NULL == qrpng) ? "gns-bcd.pdf" : "gns-bcd.png");
454
455 int pdf = open (defpath, O_RDONLY);
456 if (-1 == pdf)
410 { 457 {
411 MHD_destroy_response (not_found_response); 458 GNUNET_log_strerror_file (GNUNET_ERROR_TYPE_ERROR, "open", defpath);
412 not_found_response = NULL; 459 GNUNET_free (defpath);
460 GNUNET_DISK_directory_remove (tmpd);
461 GNUNET_free (tmpd);
462 return MHD_queue_response (connection,
463 MHD_HTTP_INTERNAL_SERVER_ERROR,
464 internal_error->response);
413 } 465 }
414 if (NULL != resfile) 466
467 struct stat statret;
468 GNUNET_break (0 == stat (defpath, &statret));
469
470 GNUNET_free (defpath);
471
472 struct MHD_Response *pdfrs =
473 MHD_create_response_from_fd ((size_t) statret.st_size, pdf);
474 if (NULL == pdfrs)
415 { 475 {
416 GNUNET_free (resfile); 476 GNUNET_break (0);
417 resfile = NULL; 477 GNUNET_break (0 == close (pdf));
478 GNUNET_DISK_directory_remove (tmpd);
479 GNUNET_free (tmpd);
480 return MHD_queue_response (connection,
481 MHD_HTTP_INTERNAL_SERVER_ERROR,
482 internal_error->response);
418 } 483 }
484
485 MHD_add_response_header (pdfrs,
486 MHD_HTTP_HEADER_CONTENT_TYPE,
487 (NULL == qrpng) ? "application/pdf" : "image/png");
488 MHD_add_response_header (pdfrs,
489 MHD_HTTP_HEADER_CONTENT_DISPOSITION,
490 (NULL == qrpng) ?
491 "attachment; filename=\"gns-business-card.pdf\"" :
492 "attachment; filename=\"gns-qr-code.png\"");
493 MHD_RESULT r = MHD_queue_response (connection, MHD_HTTP_OK, pdfrs);
494
495 MHD_destroy_response (pdfrs);
496 GNUNET_DISK_directory_remove (tmpd);
497 GNUNET_free (tmpd);
498
499 return r;
419} 500}
420 501
502/**
503 * Open a file on disk and generate a response for it.
504 *
505 * @param name name of the file to open
506 * @param basedir directory where the file is located
507 * @return NULL on error
508 */
509static struct StaticResource *
510open_static_resource (const char *name, const char *basedir)
511{
512 char *fullname = NULL;
513 GNUNET_asprintf (&fullname, "%s%s%s", basedir, DIR_SEPARATOR_STR, name);
514
515 struct GNUNET_DISK_FileHandle *f =
516 GNUNET_DISK_file_open (fullname,
517 GNUNET_DISK_OPEN_READ,
518 GNUNET_DISK_PERM_NONE);
519
520 GNUNET_free (fullname);
521
522 if (NULL == f)
523 {
524 return NULL;
525 }
526
527 off_t size = 0;
528 if (GNUNET_SYSERR == GNUNET_DISK_file_handle_size (f, &size))
529 {
530 GNUNET_DISK_file_close (f);
531 return NULL;
532 }
533
534 struct MHD_Response *response = MHD_create_response_from_fd64 (size, f->fd);
535
536 if (NULL == response)
537 {
538 GNUNET_DISK_file_close (f);
539 return NULL;
540 }
541
542 struct StaticResource *res = GNUNET_new (struct StaticResource);
543 res->handle = f;
544 res->size = (uint64_t) size;
545 res->response = response;
546
547 return res;
548}
421 549
422/** 550/**
423 * Main function that will be run. 551 * Main function that will be run.
@@ -433,63 +561,84 @@ run (void *cls,
433 const char *cfgfile, 561 const char *cfgfile,
434 const struct GNUNET_CONFIGURATION_Handle *c) 562 const struct GNUNET_CONFIGURATION_Handle *c)
435{ 563{
436 struct stat st;
437 char *dir;
438 char *fn;
439 int fd;
440
441 (void) cls; 564 (void) cls;
442 (void) args; 565 (void) args;
443 (void) cfgfile; 566 (void) cfgfile;
444 cfg = c; 567
445 dir = GNUNET_OS_installation_get_path (GNUNET_OS_IPK_DATADIR); 568 if (0 == port)
446 GNUNET_assert (NULL != dir);
447 GNUNET_asprintf (&fn, "%s%s%s", dir, DIR_SEPARATOR_STR, "gns-bcd.html");
448 GNUNET_asprintf (&resfile, "%s%s%s", dir, DIR_SEPARATOR_STR, "gns-bcd.tex");
449 GNUNET_free (dir);
450 fd = open (fn, O_RDONLY);
451 if (-1 == fd)
452 { 569 {
453 GNUNET_log_strerror_file (GNUNET_ERROR_TYPE_ERROR, "open", fn); 570 GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
454 GNUNET_free (fn); 571 _ ("Invalid port number %u\n"),
572 port);
573 GNUNET_SCHEDULER_shutdown ();
455 return; 574 return;
456 } 575 }
457 if (0 != stat (fn, &st)) 576
577 GNUNET_SCHEDULER_add_shutdown (&do_shutdown, NULL);
578
579 char *datadir = GNUNET_OS_installation_get_path (GNUNET_OS_IPK_DATADIR);
580 GNUNET_assert (NULL != datadir);
581
582 GNUNET_asprintf (&tex_file_full,
583 "%s%s%s",
584 datadir,
585 DIR_SEPARATOR_STR,
586 "gns-bcd.tex");
587 GNUNET_asprintf (&tex_file_simple,
588 "%s%s%s",
589 datadir,
590 DIR_SEPARATOR_STR,
591 "gns-bcd-simple.tex");
592 GNUNET_asprintf(&tex_file_png,
593 "%s%s%s",
594 datadir,
595 DIR_SEPARATOR_STR,
596 "gns-bcd-png.tex");
597
598 index_simple = open_static_resource ("gns-bcd-simple.html", datadir);
599 index_full = open_static_resource ("gns-bcd.html", datadir);
600 key_error = open_static_resource ("gns-bcd-invalid-key.html", datadir);
601 notfound_error = open_static_resource ("gns-bcd-not-found.html", datadir);
602 internal_error = open_static_resource ("gns-bcd-internal-error.html", datadir);
603 forbidden_error = open_static_resource ("gns-bcd-forbidden.html", datadir);
604
605 GNUNET_free (datadir);
606
607 if ((NULL == index_simple) || (NULL == index_full)
608 || (NULL == key_error) || (NULL == notfound_error)
609 || (NULL == internal_error) || (NULL == forbidden_error))
458 { 610 {
459 GNUNET_log_strerror_file (GNUNET_ERROR_TYPE_ERROR, "open", fn); 611 GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
460 GNUNET_free (fn); 612 _ ("Unable to set up the daemon\n"));
461 GNUNET_break (0 == close (fd)); 613 GNUNET_SCHEDULER_shutdown ();
462 return; 614 return;
463 } 615 }
464 GNUNET_free (fn); 616
465 if (NULL == 617 int flags = MHD_USE_DUAL_STACK | MHD_USE_DEBUG | MHD_ALLOW_SUSPEND_RESUME;
466 (main_response = MHD_create_response_from_fd ((size_t) st.st_size, fd))) 618 do
467 { 619 {
468 GNUNET_break (0); 620 httpd = MHD_start_daemon (flags,
469 GNUNET_break (0 == close (fd)); 621 port,
622 NULL, NULL,
623 &create_response, NULL,
624 MHD_OPTION_CONNECTION_LIMIT, 512,
625 MHD_OPTION_PER_IP_CONNECTION_LIMIT, 2,
626 MHD_OPTION_CONNECTION_TIMEOUT, 60,
627 MHD_OPTION_CONNECTION_MEMORY_LIMIT, 16 * 1024,
628 MHD_OPTION_END);
629 flags = MHD_USE_DEBUG;
630 } while (NULL == httpd && flags != MHD_USE_DEBUG);
631
632 if (NULL == httpd)
633 {
634 GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
635 _ ("Failed to start HTTP server\n"));
636 GNUNET_SCHEDULER_shutdown ();
470 return; 637 return;
471 } 638 }
472 (void) MHD_add_response_header (main_response,
473 MHD_HTTP_HEADER_CONTENT_TYPE,
474 "text/html");
475 invalid_gnskey_response =
476 MHD_create_response_from_buffer (strlen (INVALID_GNSKEY),
477 INVALID_GNSKEY,
478 MHD_RESPMEM_PERSISTENT);
479 (void) MHD_add_response_header (invalid_gnskey_response,
480 MHD_HTTP_HEADER_CONTENT_TYPE,
481 "text/html");
482 not_found_response = MHD_create_response_from_buffer (strlen (NOT_FOUND),
483 NOT_FOUND,
484 MHD_RESPMEM_PERSISTENT);
485 (void) MHD_add_response_header (not_found_response,
486 MHD_HTTP_HEADER_CONTENT_TYPE,
487 "text/html");
488 if (GNUNET_OK != server_start ())
489 return;
490 GNUNET_SCHEDULER_add_shutdown (&server_stop, NULL);
491}
492 639
640 run_httpd ();
641}
493 642
494/** 643/**
495 * The main function for gnunet-gns. 644 * The main function for gnunet-gns.
@@ -502,32 +651,25 @@ int
502main (int argc, char *const *argv) 651main (int argc, char *const *argv)
503{ 652{
504 struct GNUNET_GETOPT_CommandLineOption options[] = { 653 struct GNUNET_GETOPT_CommandLineOption options[] = {
505 GNUNET_GETOPT_option_uint16 ('p', 654 GNUNET_GETOPT_option_uint16 (
506 "port", 655 'p',
507 "PORT", 656 "port",
508 gettext_noop ( 657 "PORT",
509 "Run HTTP serve on port PORT (default is 8888)"), 658 gettext_noop ("Run HTTP server on port PORT (default is 8888)"),
510 &port), 659 &port),
511 GNUNET_GETOPT_OPTION_END 660 GNUNET_GETOPT_OPTION_END,
512 }; 661 };
513 int ret;
514
515 if (GNUNET_OK != GNUNET_STRINGS_get_utf8_args (argc, argv, &argc, &argv))
516 return 2;
517 GNUNET_log_setup ("gnunet-bcd", "WARNING", NULL);
518 ret = (GNUNET_OK ==
519 GNUNET_PROGRAM_run (argc,
520 argv,
521 "gnunet-bcd",
522 _ ("GNUnet HTTP server to create business cards"),
523 options,
524 &run,
525 NULL))
526 ? 0
527 : 1;
528 GNUNET_free_nz ((void *) argv);
529 return ret;
530}
531 662
663 return ((GNUNET_OK ==
664 GNUNET_PROGRAM_run (argc,
665 argv,
666 "gnunet-bcd",
667 _ ("GNUnet HTTP server to create business cards"),
668 options,
669 &run,
670 NULL))
671 ? 0
672 : 1);
673}
532 674
533/* end of gnunet-bcd.c */ 675/* end of gnunet-bcd.c */
diff --git a/src/namestore/gnunet-namestore-fcfsd.c b/src/namestore/gnunet-namestore-fcfsd.c
index 95d4c5878..7ec9db156 100644
--- a/src/namestore/gnunet-namestore-fcfsd.c
+++ b/src/namestore/gnunet-namestore-fcfsd.c
@@ -205,6 +205,15 @@ do_shutdown (void *cls)
205 { 205 {
206 GNUNET_IDENTITY_disconnect (identity); 206 GNUNET_IDENTITY_disconnect (identity);
207 } 207 }
208
209 if (NULL != httpd_task)
210 {
211 GNUNET_SCHEDULER_cancel (httpd_task);
212 }
213 if (NULL != httpd)
214 {
215 MHD_stop_daemon (httpd);
216 }
208} 217}
209 218
210 219
@@ -985,7 +994,7 @@ identity_cb (void *cls,
985 * 994 *
986 * @param name name of the file to open 995 * @param name name of the file to open
987 * @param basedir directory where the file is located 996 * @param basedir directory where the file is located
988 * @return #GNUNET_SYSERR on error 997 * @return NULL on error
989 */ 998 */
990static struct StaticPage * 999static struct StaticPage *
991open_static_page (const char *name, const char *basedir) 1000open_static_page (const char *name, const char *basedir)
diff --git a/src/namestore/gnunet-namestore.c b/src/namestore/gnunet-namestore.c
index 92d2cf627..852d99608 100644
--- a/src/namestore/gnunet-namestore.c
+++ b/src/namestore/gnunet-namestore.c
@@ -1212,8 +1212,10 @@ run_with_zone_pkey (const struct GNUNET_CONFIGURATION_Handle *cfg)
1212 char sname[64]; 1212 char sname[64];
1213 struct GNUNET_IDENTITY_PublicKey pkey; 1213 struct GNUNET_IDENTITY_PublicKey pkey;
1214 1214
1215 GNUNET_STRINGS_utf8_tolower (uri, uri); 1215 memset(sh, 0, 105);
1216 if ((2 != (sscanf (uri, "gnunet://gns/%52s/%63s", sh, sname))) || 1216 memset(sname, 0, 64);
1217
1218 if ((2 != (sscanf (uri, "gnunet://gns/%58s/%63s", sh, sname))) ||
1217 (GNUNET_OK != 1219 (GNUNET_OK !=
1218 GNUNET_IDENTITY_public_key_from_string (sh, &pkey))) 1220 GNUNET_IDENTITY_public_key_from_string (sh, &pkey)))
1219 { 1221 {
diff --git a/src/statistics/statistics_api.c b/src/statistics/statistics_api.c
index d6c2680b8..6e6acb3e5 100644
--- a/src/statistics/statistics_api.c
+++ b/src/statistics/statistics_api.c
@@ -270,11 +270,11 @@ update_memory_statistics (struct GNUNET_STATISTICS_Handle *h)
270 270
271 if (GNUNET_NO != h->do_destroy) 271 if (GNUNET_NO != h->do_destroy)
272 return; 272 return;
273#if HAVE_MALLINFO 273#if HAVE_MALLINFO2
274 { 274 {
275 struct mallinfo mi; 275 struct mallinfo2 mi;
276 276
277 mi = mallinfo (); 277 mi = mallinfo2 ();
278 current_heap_size = mi.uordblks + mi.fordblks; 278 current_heap_size = mi.uordblks + mi.fordblks;
279 } 279 }
280#endif 280#endif
diff --git a/src/transport/tcp_service_legacy.c b/src/transport/tcp_service_legacy.c
index 8606b353b..65b090187 100644
--- a/src/transport/tcp_service_legacy.c
+++ b/src/transport/tcp_service_legacy.c
@@ -29,7 +29,7 @@
29#include "gnunet_constants.h" 29#include "gnunet_constants.h"
30#include "gnunet_resolver_service.h" 30#include "gnunet_resolver_service.h"
31 31
32#if HAVE_MALLINFO 32#if HAVE_MALLINFO2
33#include <malloc.h> 33#include <malloc.h>
34#include "gauger.h" 34#include "gauger.h"
35#endif 35#endif
@@ -1450,7 +1450,7 @@ shutdown:
1450 LOG_STRERROR (GNUNET_ERROR_TYPE_WARNING, "write"); 1450 LOG_STRERROR (GNUNET_ERROR_TYPE_WARNING, "write");
1451 GNUNET_break (0 == close (sctx.ready_confirm_fd)); 1451 GNUNET_break (0 == close (sctx.ready_confirm_fd));
1452 } 1452 }
1453#if HAVE_MALLINFO 1453#if HAVE_MALLINFO2
1454 { 1454 {
1455 char *counter; 1455 char *counter;
1456 1456
@@ -1462,9 +1462,9 @@ shutdown:
1462 "GAUGER_HEAP", 1462 "GAUGER_HEAP",
1463 &counter))) 1463 &counter)))
1464 { 1464 {
1465 struct mallinfo mi; 1465 struct mallinfo2 mi;
1466 1466
1467 mi = mallinfo (); 1467 mi = mallinfo2 ();
1468 GAUGER (service_name, counter, mi.usmblks, "blocks"); 1468 GAUGER (service_name, counter, mi.usmblks, "blocks");
1469 GNUNET_free (counter); 1469 GNUNET_free (counter);
1470 } 1470 }
@@ -1599,7 +1599,7 @@ LEGACY_SERVICE_stop (struct LEGACY_SERVICE_Context *sctx)
1599{ 1599{
1600 unsigned int i; 1600 unsigned int i;
1601 1601
1602#if HAVE_MALLINFO 1602#if HAVE_MALLINFO2
1603 { 1603 {
1604 char *counter; 1604 char *counter;
1605 1605
@@ -1611,9 +1611,9 @@ LEGACY_SERVICE_stop (struct LEGACY_SERVICE_Context *sctx)
1611 "GAUGER_HEAP", 1611 "GAUGER_HEAP",
1612 &counter))) 1612 &counter)))
1613 { 1613 {
1614 struct mallinfo mi; 1614 struct mallinfo2 mi;
1615 1615
1616 mi = mallinfo (); 1616 mi = mallinfo2 ();
1617 GAUGER (sctx->service_name, counter, mi.usmblks, "blocks"); 1617 GAUGER (sctx->service_name, counter, mi.usmblks, "blocks");
1618 GNUNET_free (counter); 1618 GNUNET_free (counter);
1619 } 1619 }
diff --git a/src/util/Makefile.am b/src/util/Makefile.am
index c3a0feccc..d21ac5e86 100644
--- a/src/util/Makefile.am
+++ b/src/util/Makefile.am
@@ -239,6 +239,9 @@ gnunet_qr_LDADD = \
239 libgnunetutil.la \ 239 libgnunetutil.la \
240 $(GN_LIBINTL) 240 $(GN_LIBINTL)
241gnunet_qr_LDFLAGS= -lzbar 241gnunet_qr_LDFLAGS= -lzbar
242if HAVE_PNG
243gnunet_qr_LDFLAGS += -lpng
244endif
242 245
243plugin_LTLIBRARIES = \ 246plugin_LTLIBRARIES = \
244 libgnunet_plugin_utiltest.la 247 libgnunet_plugin_utiltest.la
diff --git a/src/util/gnunet-qr.c b/src/util/gnunet-qr.c
index 451d61d40..5bccd3916 100644
--- a/src/util/gnunet-qr.c
+++ b/src/util/gnunet-qr.c
@@ -24,302 +24,500 @@
24 * @author Christian Grothoff (error handling) 24 * @author Christian Grothoff (error handling)
25 */ 25 */
26#include <stdio.h> 26#include <stdio.h>
27#include <zbar.h>
28#include <stdbool.h> 27#include <stdbool.h>
28#include <signal.h>
29#include <zbar.h>
30
29#include "platform.h" 31#include "platform.h"
30#include "gnunet_util_lib.h" 32#include "gnunet_util_lib.h"
31 33
32#define LOG(fmt, ...) \ 34#if HAVE_PNG
33 if (verbose) \ 35#include <png.h>
34 printf (fmt, ## __VA_ARGS__) 36#endif
35 37
36/** 38/**
37 * Video device to capture from. Sane default for GNU/Linux systems. 39 * Global exit code.
40 * Set to non-zero if an error occurs after the scheduler has started.
38 */ 41 */
39static char *device; 42static int exit_code = 0;
40 43
41/** 44/**
42 * --verbose option 45 * Video device to capture from.
46 * Used by default if PNG support is disabled or no PNG file is specified.
47 * Defaults to /dev/video0.
43 */ 48 */
44static unsigned int verbose; 49static char *device = NULL;
45 50
51#if HAVE_PNG
46/** 52/**
47 * --silent option 53 * Name of the file to read from.
54 * If the file is not a PNG-encoded image of a QR code, an error will be
55 * thrown.
48 */ 56 */
49static int silent = false; 57static char *pngfilename = NULL;
58#endif
50 59
51/** 60/**
52 * Handler exit code 61 * Requested verbosity.
53 */ 62 */
54static long unsigned int exit_code = 0; 63static unsigned int verbosity = 0;
55 64
56/** 65/**
57 * Helper process we started. 66 * Child process handle.
58 */ 67 */
59static struct GNUNET_OS_Process *p; 68struct GNUNET_OS_Process *childproc = NULL;
60 69
61/** 70/**
62 * Child signal handler. 71 * Child process handle for waiting.
63 */ 72 */
64static struct GNUNET_SIGNAL_Context *shc_chld; 73static struct GNUNET_ChildWaitHandle *waitchildproc = NULL;
65 74
66/** 75/**
67 * Pipe used to communicate child death via signal. 76 * Macro to handle verbosity when printing messages.
68 */ 77 */
69static struct GNUNET_DISK_PipeHandle *sigpipe; 78#define LOG(fmt, ...) \
79 do \
80 { \
81 if (0 < verbosity) \
82 { \
83 GNUNET_log (GNUNET_ERROR_TYPE_INFO, fmt, ##__VA_ARGS__); \
84 if (verbosity > 1) \
85 { \
86 fprintf (stdout, fmt, ##__VA_ARGS__); \
87 } \
88 } \
89 } \
90 while (0)
70 91
71/** 92/**
72 * Process ID of this process at the time we installed the various 93 * Executed when program is terminating.
73 * signal handlers.
74 */ 94 */
75static pid_t my_pid; 95static void
96shutdown_program (void *cls)
97{
98 if (NULL != waitchildproc)
99 {
100 GNUNET_wait_child_cancel (waitchildproc);
101 }
102 if (NULL != childproc)
103 {
104 /* A bit brutal, but this process is terminating so we're out of time */
105 GNUNET_OS_process_kill (childproc, SIGKILL);
106 }
107}
76 108
77/** 109/**
78 * Task triggered whenever we receive a SIGCHLD (child 110 * Callback executed when the child process terminates.
79 * process died) or when user presses CTRL-C.
80 * 111 *
81 * @param cls closure, NULL 112 * @param cls closure
113 * @param type status of the child process
114 * @param code the exit code of the child process
82 */ 115 */
83static void 116static void
84maint_child_death (void *cls) 117wait_child (void *cls,
118 enum GNUNET_OS_ProcessStatusType type,
119 long unsigned int code)
85{ 120{
86 enum GNUNET_OS_ProcessStatusType type; 121 GNUNET_OS_process_destroy (childproc);
122 childproc = NULL;
123 waitchildproc = NULL;
124
125 char *uri = cls;
87 126
88 if ((GNUNET_OK != GNUNET_OS_process_status (p, &type, &exit_code)) || 127 if (0 != exit_code)
89 (type != GNUNET_OS_PROCESS_EXITED))
90 GNUNET_break (0 == GNUNET_OS_process_kill (p, GNUNET_TERM_SIG));
91 GNUNET_SIGNAL_handler_uninstall (shc_chld);
92 shc_chld = NULL;
93 if (NULL != sigpipe)
94 { 128 {
95 GNUNET_DISK_pipe_close (sigpipe); 129 fprintf (stdout, _("Failed to add URI %s\n"), uri);
96 sigpipe = NULL; 130 }
131 else
132 {
133 fprintf (stdout, _("Added URI %s\n"), uri);
97 } 134 }
98 GNUNET_OS_process_destroy (p);
99}
100 135
136 GNUNET_free (uri);
101 137
102/** 138 GNUNET_SCHEDULER_shutdown ();
103 * Signal handler called for signals that causes us to wait for the child process.
104 */
105static void
106sighandler_chld ()
107{
108 static char c;
109 int old_errno = errno; /* backup errno */
110
111 if (getpid () != my_pid)
112 _exit (1); /* we have fork'ed since the signal handler was created,
113 * ignore the signal, see https://gnunet.org/vfork discussion */
114 GNUNET_DISK_file_write (GNUNET_DISK_pipe_handle
115 (sigpipe, GNUNET_DISK_PIPE_END_WRITE),
116 &c, sizeof(c));
117 errno = old_errno;
118} 139}
119 140
120
121/** 141/**
122 * Dispatch URIs to the appropriate GNUnet helper process 142 * Dispatch URIs to the appropriate GNUnet helper process.
123 * 143 *
124 * @param cls closure 144 * @param cls closure
125 * @param uri uri to dispatch 145 * @param uri URI to dispatch
126 * @param cfgfile name of the configuration file used (for saving, can be NULL!) 146 * @param cfgfile name of the configuration file in use
127 * @param cfg configuration 147 * @param cfg the configuration in use
128 */ 148 */
129static void 149static void
130gnunet_uri (void *cls, 150handle_uri (void *cls,
131 const char *uri, 151 const char *uri,
132 const char *cfgfile, 152 const char *cfgfile,
133 const struct GNUNET_CONFIGURATION_Handle *cfg) 153 const struct GNUNET_CONFIGURATION_Handle *cfg)
134{ 154{
135 const char *orig_uri; 155 const char *cursor = uri;
136 const char *slash;
137 char *subsystem;
138 char *program;
139 struct GNUNET_SCHEDULER_Task *rt;
140 156
141 orig_uri = uri;
142 if (0 != strncasecmp ("gnunet://", uri, strlen ("gnunet://"))) 157 if (0 != strncasecmp ("gnunet://", uri, strlen ("gnunet://")))
143 { 158 {
144 fprintf (stderr, 159 fprintf (stderr,
145 _ ("Invalid URI: does not start with `%s'\n"), 160 _("Invalid URI: does not start with `gnunet://'\n"));
146 "gnunet://"); 161 exit_code = 1;
147 return; 162 return;
148 } 163 }
149 uri += strlen ("gnunet://"); 164
150 if (NULL == (slash = strchr (uri, '/'))) 165 cursor += strlen ("gnunet://");
166
167 const char *slash = strchr (cursor, '/');
168 if (NULL == slash)
151 { 169 {
152 fprintf (stderr, _ ("Invalid URI: fails to specify subsystem\n")); 170 fprintf (stderr, _("Invalid URI: fails to specify a subsystem\n"));
171 exit_code = 1;
153 return; 172 return;
154 } 173 }
155 subsystem = GNUNET_strndup (uri, slash - uri); 174
175 char *subsystem = GNUNET_strndup (cursor, slash - cursor);
176 char *program = NULL;
177
156 if (GNUNET_OK != 178 if (GNUNET_OK !=
157 GNUNET_CONFIGURATION_get_value_string (cfg, "uri", subsystem, &program)) 179 GNUNET_CONFIGURATION_get_value_string (cfg, "uri", subsystem, &program))
158 { 180 {
159 fprintf (stderr, _ ("No handler known for subsystem `%s'\n"), subsystem); 181 fprintf (stderr, _("No known handler for subsystem `%s'\n"), subsystem);
160 GNUNET_free (subsystem); 182 GNUNET_free (subsystem);
183 exit_code = 1;
161 return; 184 return;
162 } 185 }
186
163 GNUNET_free (subsystem); 187 GNUNET_free (subsystem);
164 sigpipe = GNUNET_DISK_pipe (GNUNET_DISK_PF_NONE);
165 GNUNET_assert (NULL != sigpipe);
166 rt = GNUNET_SCHEDULER_add_read_file (
167 GNUNET_TIME_UNIT_FOREVER_REL,
168 GNUNET_DISK_pipe_handle (sigpipe, GNUNET_DISK_PIPE_END_READ),
169 &maint_child_death,
170 NULL);
171 my_pid = getpid ();
172 shc_chld = GNUNET_SIGNAL_handler_install (SIGCHLD,
173 &sighandler_chld);
174
175 {
176 char **argv = NULL;
177 unsigned int argc = 0;
178 char *u = GNUNET_strdup (program);
179
180 for (const char *tok = strtok (u, " ");
181 NULL != tok;
182 tok = strtok (NULL, " "))
183 GNUNET_array_append (argv,
184 argc,
185 GNUNET_strdup (tok));
186 GNUNET_array_append (argv,
187 argc,
188 GNUNET_strdup (orig_uri));
189 GNUNET_array_append (argv,
190 argc,
191 NULL);
192 p = GNUNET_OS_start_process_vap (GNUNET_OS_INHERIT_STD_ALL,
193 NULL,
194 NULL,
195 NULL,
196 argv[0],
197 argv);
198 for (unsigned int i = 0; i<argc - 1; i++)
199 GNUNET_free (argv[i]);
200 GNUNET_array_grow (argv,
201 argc,
202 0);
203 GNUNET_free (u);
204 }
205 if (NULL == p)
206 GNUNET_SCHEDULER_cancel (rt);
207 GNUNET_free (program);
208}
209 188
189 char **childargv = NULL;
190 unsigned int childargc = 0;
191
192 for (const char *token=strtok (program, " ");
193 NULL!=token;
194 token=strtok(NULL, " "))
195 {
196 GNUNET_array_append (childargv, childargc, GNUNET_strdup (token));
197 }
198 GNUNET_array_append (childargv, childargc, GNUNET_strdup (uri));
199 GNUNET_array_append (childargv, childargc, NULL);
200
201 childproc = GNUNET_OS_start_process_vap (GNUNET_OS_INHERIT_STD_ALL,
202 NULL,
203 NULL,
204 NULL,
205 childargv[0],
206 childargv);
207 for (size_t i=0; i<childargc-1; ++i)
208 {
209 GNUNET_free (childargv[i]);
210 }
211
212 GNUNET_array_grow (childargv, childargc, 0);
213
214 if (NULL == childproc)
215 {
216 GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
217 _("Unable to start child process `%s'\n"),
218 program);
219 GNUNET_free (program);
220 exit_code = 1;
221 return;
222 }
223
224 waitchildproc = GNUNET_wait_child (childproc, &wait_child, (void *)uri);
225}
210 226
211/** 227/**
212 * Obtain QR code 'symbol' from @a proc. 228 * Obtain a QR code symbol from @a proc.
213 * 229 *
214 * @param proc zbar processor to use 230 * @param proc the zbar processor to use
215 * @return NULL on error 231 * @return NULL on error
216 */ 232 */
217static const zbar_symbol_t * 233static const zbar_symbol_t *
218get_symbol (zbar_processor_t *proc) 234get_symbol (zbar_processor_t *proc)
219{ 235{
220 const zbar_symbol_set_t *symbols;
221 int rc;
222 int n;
223
224 if (0 != zbar_processor_parse_config (proc, "enable")) 236 if (0 != zbar_processor_parse_config (proc, "enable"))
225 { 237 {
226 GNUNET_break (0); 238 GNUNET_break (0);
227 return NULL; 239 return NULL;
228 } 240 }
229 241
230 /* initialize the Processor */ 242 int r = zbar_processor_init (proc, device, 1);
231 if (NULL == device) 243 if (0 != r)
232 device = GNUNET_strdup ("/dev/video0");
233 if (0 != (rc = zbar_processor_init (proc, device, 1)))
234 { 244 {
235 GNUNET_log (GNUNET_ERROR_TYPE_ERROR, 245 GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
236 "Failed to open device `%s': %d\n", 246 _("Failed to open device: `%s': %d\n"),
237 device, 247 device,
238 rc); 248 r);
239 return NULL; 249 return NULL;
240 } 250 }
241 251
242 /* enable the preview window */ 252 r = zbar_processor_set_visible (proc, 1);
243 if ((0 != (rc = zbar_processor_set_visible (proc, 1))) || 253 r += zbar_processor_set_active (proc, 1);
244 (0 != (rc = zbar_processor_set_active (proc, 1)))) 254 if (0 != r)
245 { 255 {
246 GNUNET_break (0); 256 GNUNET_break (0);
247 return NULL; 257 return NULL;
248 } 258 }
249 259
250 /* read at least one barcode (or until window closed) */ 260 LOG (_("Capturing...\n"));
251 LOG ("Capturing\n"); 261
252 n = zbar_process_one (proc, -1); 262 int n = zbar_process_one (proc, -1);
263
264 zbar_processor_set_active (proc, 0);
265 zbar_processor_set_visible (proc, 0);
253 266
254 /* hide the preview window */
255 (void) zbar_processor_set_active (proc, 0);
256 (void) zbar_processor_set_visible (proc, 0);
257 if (-1 == n) 267 if (-1 == n)
258 return NULL; /* likely user closed the window */ 268 {
259 LOG ("Got %i images\n", n); 269 LOG (_("No captured images\n"));
260 /* extract results */ 270 return NULL;
261 symbols = zbar_processor_get_results (proc); 271 }
272
273 LOG(_("Got %d images\n"), n);
274
275 const zbar_symbol_set_t *symbols = zbar_processor_get_results (proc);
262 if (NULL == symbols) 276 if (NULL == symbols)
263 { 277 {
264 GNUNET_break (0); 278 GNUNET_break (0);
265 return NULL; 279 return NULL;
266 } 280 }
281
267 return zbar_symbol_set_first_symbol (symbols); 282 return zbar_symbol_set_first_symbol (symbols);
268} 283}
269 284
270
271/** 285/**
272 * Run zbar QR code parser. 286 * Run the zbar QR code parser.
273 * 287 *
274 * @return NULL on error, otherwise the URI that we found 288 * @return NULL on error
275 */ 289 */
276static char * 290static char *
277run_zbar () 291run_zbar (void)
278{ 292{
279 zbar_processor_t *proc; 293 zbar_processor_t *proc = zbar_processor_create (1);
280 const char *data;
281 char *ret;
282 const zbar_symbol_t *symbol;
283
284 /* configure the Processor */
285 proc = zbar_processor_create (1);
286 if (NULL == proc) 294 if (NULL == proc)
287 { 295 {
288 GNUNET_break (0); 296 GNUNET_break (0);
289 return NULL; 297 return NULL;
290 } 298 }
291 299
292 symbol = get_symbol (proc); 300 if (NULL == device)
301 {
302 device = GNUNET_strdup ("/dev/video0");
303 }
304
305 const zbar_symbol_t *symbol = get_symbol (proc);
293 if (NULL == symbol) 306 if (NULL == symbol)
294 { 307 {
295 zbar_processor_destroy (proc); 308 zbar_processor_destroy (proc);
296 return NULL; 309 return NULL;
297 } 310 }
298 data = zbar_symbol_get_data (symbol); 311
312 const char *data = zbar_symbol_get_data (symbol);
299 if (NULL == data) 313 if (NULL == data)
300 { 314 {
301 GNUNET_break (0); 315 GNUNET_break (0);
302 zbar_processor_destroy (proc); 316 zbar_processor_destroy (proc);
303 return NULL; 317 return NULL;
304 } 318 }
305 LOG ("Found %s \"%s\"\n", 319
320 LOG (_("Found %s: \"%s\"\n"),
306 zbar_get_symbol_name (zbar_symbol_get_type (symbol)), 321 zbar_get_symbol_name (zbar_symbol_get_type (symbol)),
307 data); 322 data);
308 ret = GNUNET_strdup (data); 323
309 /* clean up */ 324 char *copy = GNUNET_strdup (data);
325
310 zbar_processor_destroy (proc); 326 zbar_processor_destroy (proc);
311 GNUNET_free (device); 327 GNUNET_free (device);
312 return ret; 328
329 return copy;
313} 330}
314 331
332#if HAVE_PNG
333/**
334 * Decode the PNG-encoded file to a raw byte buffer.
335 *
336 * @param width[out] where to store the image width
337 * @param height[out] where to store the image height
338 */
339static char *
340png_parse (uint32_t *width, uint32_t *height)
341{
342 if (NULL == width || NULL == height)
343 {
344 return NULL;
345 }
346
347 FILE *pngfile = fopen (pngfilename, "rb");
348 if (NULL == pngfile)
349 {
350 return NULL;
351 }
352
353 unsigned char header[8];
354 if (8 != fread (header, 1, 8, pngfile))
355 {
356 fclose (pngfile);
357 return NULL;
358 }
359
360 if (png_sig_cmp (header, 0, 8))
361 {
362 fclose (pngfile);
363 GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
364 _("%s is not a PNG file\n"),
365 pngfilename);
366 fprintf (stderr, _("%s is not a PNG file\n"), pngfilename);
367 return NULL;
368 }
369
370 /* libpng's default error handling might or might not conflict with GNUnet's
371 scheduler and event loop. Beware of strange interactions. */
372 png_structp png = png_create_read_struct (PNG_LIBPNG_VER_STRING,
373 NULL,
374 NULL,
375 NULL);
376 if (NULL == png)
377 {
378 GNUNET_break (0);
379 fclose (pngfile);
380 return NULL;
381 }
382
383 png_infop pnginfo = png_create_info_struct (png);
384 if (NULL == pnginfo)
385 {
386 GNUNET_break (0);
387 png_destroy_read_struct (&png, NULL, NULL);
388 fclose (pngfile);
389 return NULL;
390 }
391
392 if (setjmp (png_jmpbuf (png)))
393 {
394 GNUNET_break (0);
395 png_destroy_read_struct (&png, &pnginfo, NULL);
396 fclose (pngfile);
397 return NULL;
398 }
399
400 png_init_io (png, pngfile);
401 png_set_sig_bytes (png, 8);
402
403 png_read_info (png, pnginfo);
404
405 png_byte pngcolor = png_get_color_type (png, pnginfo);
406 png_byte pngdepth = png_get_bit_depth (png, pnginfo);
407
408 /* Normalize picture --- based on a zbar example */
409 if (0 != (pngcolor & PNG_COLOR_TYPE_PALETTE))
410 {
411 png_set_palette_to_rgb (png);
412 }
413
414 if (pngcolor == PNG_COLOR_TYPE_GRAY && pngdepth < 8)
415 {
416 png_set_expand_gray_1_2_4_to_8 (png);
417 }
418
419 if (16 == pngdepth)
420 {
421 png_set_strip_16 (png);
422 }
423
424 if (0 != (pngcolor & PNG_COLOR_MASK_ALPHA))
425 {
426 png_set_strip_alpha (png);
427 }
428
429 if (0 != (pngcolor & PNG_COLOR_MASK_COLOR))
430 {
431 png_set_rgb_to_gray_fixed (png, 1, -1, -1);
432 }
433
434 png_uint_32 pngwidth = png_get_image_width (png, pnginfo);
435 png_uint_32 pngheight = png_get_image_height (png, pnginfo);
436
437 char *buffer = GNUNET_new_array (pngwidth * pngheight, char);
438 png_bytepp rows = GNUNET_new_array (pngheight, png_bytep);
439
440 for (png_uint_32 i=0; i<pngheight; ++i)
441 {
442 rows[i] = (unsigned char *)buffer + (pngwidth * i);
443 }
444
445 png_read_image (png, rows);
446
447 GNUNET_free (rows);
448 fclose (pngfile);
449
450 *width = pngwidth;
451 *height = pngheight;
452
453 return buffer;
454}
455
456/**
457 * Parse a PNG-encoded file for a QR code.
458 *
459 * @return NULL on error
460 */
461static char *
462run_png_reader (void)
463{
464 uint32_t width = 0;
465 uint32_t height = 0;
466 char *buffer = png_parse (&width, &height);
467 if (NULL == buffer)
468 {
469 return NULL;
470 }
471
472 zbar_image_scanner_t *scanner = zbar_image_scanner_create ();
473 zbar_image_scanner_set_config (scanner,0, ZBAR_CFG_ENABLE, 1);
474
475 zbar_image_t *zimage = zbar_image_create ();
476 zbar_image_set_format (zimage, zbar_fourcc ('Y', '8', '0', '0'));
477 zbar_image_set_size (zimage, width, height);
478 zbar_image_set_data (zimage, buffer, width * height, &zbar_image_free_data);
479
480 int n = zbar_scan_image (scanner, zimage);
481
482 if (-1 == n)
483 {
484 LOG (_("No captured images\n"));
485 return NULL;
486 }
487
488 LOG(_("Got %d images\n"), n);
489
490 const zbar_symbol_t *symbol = zbar_image_first_symbol (zimage);
491
492 const char *data = zbar_symbol_get_data (symbol);
493 if (NULL == data)
494 {
495 GNUNET_break (0);
496 zbar_image_destroy (zimage);
497 zbar_image_scanner_destroy (scanner);
498 return NULL;
499 }
500
501 LOG (_("Found %s: \"%s\"\n"),
502 zbar_get_symbol_name (zbar_symbol_get_type (symbol)),
503 data);
504
505 char *copy = GNUNET_strdup (data);
506
507 zbar_image_destroy (zimage);
508 zbar_image_scanner_destroy (scanner);
509
510 return copy;
511}
512#endif
315 513
316/** 514/**
317 * Main function that will be run by the scheduler. 515 * Main function executed by the scheduler.
318 * 516 *
319 * @param cls closure 517 * @param cls closure
320 * @param args remaining command-line arguments 518 * @param args remaining command line arguments
321 * @param cfgfile name of the configuration file used (for saving, can be NULL!) 519 * @param cfgfile name of the configuration file being used
322 * @param cfg configuration 520 * @param cfg the used configuration
323 */ 521 */
324static void 522static void
325run (void *cls, 523run (void *cls,
@@ -327,51 +525,72 @@ run (void *cls,
327 const char *cfgfile, 525 const char *cfgfile,
328 const struct GNUNET_CONFIGURATION_Handle *cfg) 526 const struct GNUNET_CONFIGURATION_Handle *cfg)
329{ 527{
330 char *data; 528 char *data = NULL;
331 529
332 data = run_zbar (); 530 GNUNET_SCHEDULER_add_shutdown (&shutdown_program, NULL);
333 if (NULL == data) 531
334 return; 532#if HAVE_PNG
335 gnunet_uri (cls, data, cfgfile, cfg); 533 if (NULL != pngfilename)
336 if (exit_code != 0)
337 { 534 {
338 printf ("Failed to add URI %s\n", data); 535 data = run_png_reader ();
339 } 536 }
340 else 537 else
538#endif
539 {
540 data = run_zbar ();
541 }
542
543 if (NULL == data)
341 { 544 {
342 printf ("Added URI %s\n", data); 545 LOG (_("No data found\n"));
546 exit_code = 1;
547 GNUNET_SCHEDULER_shutdown ();
548 return;
343 } 549 }
344 GNUNET_free (data);
345};
346 550
551 handle_uri (cls, data, cfgfile, cfg);
552
553 if (0 != exit_code)
554 {
555 fprintf (stdout, _("Failed to add URI %s\n"), data);
556 GNUNET_free (data);
557 GNUNET_SCHEDULER_shutdown ();
558 return;
559 }
560
561 LOG (_("Dispatching the URI\n"));
562}
347 563
348int 564int
349main (int argc, char *const *argv) 565main (int argc, char *const *argv)
350{ 566{
351 int ret;
352 struct GNUNET_GETOPT_CommandLineOption options[] = { 567 struct GNUNET_GETOPT_CommandLineOption options[] = {
353 GNUNET_GETOPT_option_string ( 568 GNUNET_GETOPT_option_string (
354 'd', 569 'd',
355 "device", 570 "device",
356 "DEVICE", 571 "DEVICE",
357 gettext_noop ("use video-device DEVICE (default: /dev/video0"), 572 gettext_noop ("use the video device DEVICE (defaults to /dev/video0)"),
358 &device), 573 &device),
359 GNUNET_GETOPT_option_verbose (&verbose), 574#if HAVE_PNG
360 GNUNET_GETOPT_option_flag ('s', 575 GNUNET_GETOPT_option_string (
361 "silent", 576 'f',
362 gettext_noop ("do not show preview windows"), 577 "file",
363 &silent), 578 "FILE",
364 GNUNET_GETOPT_OPTION_END 579 gettext_noop ("read from the PNG-encoded file FILE"),
580 &pngfilename),
581#endif
582 GNUNET_GETOPT_option_verbose (&verbosity),
583 GNUNET_GETOPT_OPTION_END,
365 }; 584 };
366 585
367 ret = GNUNET_PROGRAM_run ( 586 enum GNUNET_GenericReturnValue ret =
368 argc, 587 GNUNET_PROGRAM_run (argc,
369 argv, 588 argv,
370 "gnunet-qr", 589 "gnunet-qr",
371 gettext_noop ( 590 gettext_noop ("Scan a QR code and import the URI read"),
372 "Scan a QR code using a video device and import the uri read"), 591 options,
373 options, 592 &run,
374 &run, 593 NULL);
375 NULL); 594
376 return ((GNUNET_OK == ret) && (0 == exit_code)) ? 0 : 1; 595 return ((GNUNET_OK == ret) && (0 == exit_code)) ? 0 : 1;
377} 596}
diff --git a/src/util/service.c b/src/util/service.c
index 4c647430d..df4feb0ec 100644
--- a/src/util/service.c
+++ b/src/util/service.c
@@ -31,7 +31,7 @@
31#include "gnunet_resolver_service.h" 31#include "gnunet_resolver_service.h"
32#include "speedup.h" 32#include "speedup.h"
33 33
34#if HAVE_MALLINFO 34#if HAVE_MALLINFO2
35#include <malloc.h> 35#include <malloc.h>
36#include "gauger.h" 36#include "gauger.h"
37#endif 37#endif
@@ -2140,7 +2140,7 @@ shutdown:
2140 LOG_STRERROR (GNUNET_ERROR_TYPE_WARNING, "write"); 2140 LOG_STRERROR (GNUNET_ERROR_TYPE_WARNING, "write");
2141 GNUNET_break (0 == close (sh.ready_confirm_fd)); 2141 GNUNET_break (0 == close (sh.ready_confirm_fd));
2142 } 2142 }
2143#if HAVE_MALLINFO 2143#if HAVE_MALLINFO2
2144 { 2144 {
2145 char *counter; 2145 char *counter;
2146 2146
@@ -2152,9 +2152,9 @@ shutdown:
2152 "GAUGER_HEAP", 2152 "GAUGER_HEAP",
2153 &counter))) 2153 &counter)))
2154 { 2154 {
2155 struct mallinfo mi; 2155 struct mallinfo2 mi;
2156 2156
2157 mi = mallinfo (); 2157 mi = mallinfo2 ();
2158 GAUGER (service_name, counter, mi.usmblks, "blocks"); 2158 GAUGER (service_name, counter, mi.usmblks, "blocks");
2159 GNUNET_free (counter); 2159 GNUNET_free (counter);
2160 } 2160 }