GNUnet 0.21.1
gnunet-bcd.c
Go to the documentation of this file.
1/*
2 This file is part of GNUnet.
3 Copyright (C) 2013 GNUnet e.V.
4
5 GNUnet is free software: you can redistribute it and/or modify it
6 under the terms of the GNU Affero General Public License as published
7 by the Free Software Foundation, either version 3 of the License,
8 or (at your option) any later version.
9
10 GNUnet is distributed in the hope that it will be useful, but
11 WITHOUT ANY WARRANTY; without even the implied warranty of
12 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
13 Affero General Public License for more details.
14
15 You should have received a copy of the GNU Affero General Public License
16 along with this program. If not, see <http://www.gnu.org/licenses/>.
17
18 SPDX-License-Identifier: AGPL3.0-or-later
19 */
20
27#include "platform.h"
28#include <microhttpd.h>
29#include "gnunet_util_lib.h"
31#include "gnunet_mhd_compat.h"
32
34{
39
43 uint64_t size;
44
48 struct MHD_Response *response;
49};
50
52{
56 char *name;
57
62};
63
67static struct MHD_Daemon *httpd = NULL;
68
72static struct GNUNET_SCHEDULER_Task *httpd_task = NULL;
73
77static struct StaticResource *index_simple = NULL;
78
82static struct StaticResource *index_full = NULL;
83
87static struct StaticResource *key_error = NULL;
88
92static struct StaticResource *notfound_error = NULL;
93
97static struct StaticResource *internal_error = NULL;
98
102static struct StaticResource *forbidden_error = NULL;
103
107static char *tex_file_simple = NULL;
108
112static char *tex_file_full = NULL;
113
117static char *tex_file_png = NULL;
118
122static int continue_100 = 100;
123
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},
142};
143
147static uint16_t port = 8888;
148
154static void
155do_shutdown (void *cls)
156{
157 /* We cheat a bit here: the file descriptor is implicitly closed by MHD, so
158 calling `GNUNET_DISK_file_close' would generate a spurious warning message
159 in the log. Since that function does nothing but close the descriptor and
160 free the allocated memory, After destroying the response all that's left to
161 do is call `GNUNET_free'. */
162 if (NULL != index_simple)
163 {
164 MHD_destroy_response (index_simple->response);
167 }
168 if (NULL != index_full)
169 {
170 MHD_destroy_response (index_full->response);
173 }
174 if (NULL != key_error)
175 {
176 MHD_destroy_response (key_error->response);
179 }
180 if (NULL != notfound_error)
181 {
182 MHD_destroy_response (notfound_error->response);
185 }
186 if (NULL != internal_error)
187 {
188 MHD_destroy_response (internal_error->response);
191 }
192 if (NULL != forbidden_error)
193 {
194 MHD_destroy_response (forbidden_error->response);
197 }
198
199 if (NULL != httpd_task)
200 {
202 }
203 if (NULL != httpd)
204 {
205 MHD_stop_daemon (httpd);
206 }
207}
208
214static void
215do_httpd (void *cls);
216
220static void
222{
223 fd_set rs;
224 fd_set ws;
225 fd_set es;
226
230
231 FD_ZERO (&rs);
232 FD_ZERO (&ws);
233 FD_ZERO (&es);
234
235 int max = -1;
236 GNUNET_assert (MHD_YES == MHD_get_fdset (httpd, &rs, &ws, &es, &max));
237
238 unsigned MHD_LONG_LONG timeout = 0;
240 if (MHD_YES == MHD_get_timeout (httpd, &timeout))
241 {
243 timeout);
244 }
245
249
251 gtime,
252 grs,
253 gws,
254 &do_httpd,
255 NULL);
259}
260
266static void
267do_httpd (void *cls)
268{
269 httpd_task = NULL;
270 MHD_run (httpd);
271 run_httpd ();
272}
273
287static MHD_RESULT
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)
296{
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)
306 {
307 return MHD_queue_response (connection,
310 }
311
312 if (ishead)
313 {
314 /* Dedicated branch in case we want to provide a different result for some
315 reason (e.g. a non-web browser application using the web UI) */
316 return MHD_queue_response (connection,
319 }
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 }
329
330 if (0 == strcmp ("/", url))
331 {
332 return MHD_queue_response (connection,
335 }
336
337 if (0 == strcmp ("/full", url))
338 {
339 return MHD_queue_response (connection,
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,
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
368 if (NULL == gnskey
370 {
371 return MHD_queue_response (connection,
374 }
375
376 char *tmpd = GNUNET_DISK_mkdtemp (gnskey);
377 if (NULL == tmpd)
378 {
380 return MHD_queue_response (connection,
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 {
392 GNUNET_free (defpath);
394 GNUNET_free (tmpd);
395 return MHD_queue_response (connection,
398 }
399
400 GNUNET_free (defpath);
401
402 for (size_t i=0; NULL!=pmap[i].name; ++i)
403 {
404 const char *value = MHD_lookup_connection_value (connection,
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);
411 }
412
413 if (NULL != gpgfp)
414 {
415 size_t len = strlen (gpgfp);
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);
422 GNUNET_free (line1);
423 GNUNET_free (line2);
424 }
425
426 fprintf (deffile,
427 "\\def\\gns{%s/%s}\n",
428 gnskey,
429 (NULL == gnsnick) ? "" : gnsnick);
430
431 fclose (deffile);
432
433 char *command = NULL;
434 GNUNET_asprintf (&command,
435 "cd %s; cp %s gns-bcd.tex; "
436 "pdflatex %s gns-bcd.tex >/dev/null 2>&1",
437 tmpd,
438 (isfull) ? tex_file_full :
439 ((NULL == qrpng) ? tex_file_simple : tex_file_png),
440 (NULL == qrpng) ? "" : "-shell-escape");
441
442 int ret = system (command);
443
444 GNUNET_free (command);
445
446 if (WIFSIGNALED (ret) || 0 != WEXITSTATUS (ret))
447 {
449 }
450
451 GNUNET_asprintf (&defpath,
452 "%s%s%s",
453 tmpd,
455 (NULL == qrpng) ? "gns-bcd.pdf" : "gns-bcd.png");
456
457 int pdf = open (defpath, O_RDONLY);
458 if (-1 == pdf)
459 {
461 GNUNET_free (defpath);
463 GNUNET_free (tmpd);
464 return MHD_queue_response (connection,
467 }
468
469 struct stat statret;
470 GNUNET_break (0 == stat (defpath, &statret));
471
472 GNUNET_free (defpath);
473
474 struct MHD_Response *pdfrs =
475 MHD_create_response_from_fd ((size_t) statret.st_size, pdf);
476 if (NULL == pdfrs)
477 {
478 GNUNET_break (0);
479 GNUNET_break (0 == close (pdf));
481 GNUNET_free (tmpd);
482 return MHD_queue_response (connection,
485 }
486
487 GNUNET_assert (MHD_NO != MHD_add_response_header (pdfrs,
488 MHD_HTTP_HEADER_CONTENT_TYPE,
489 (NULL == qrpng) ? "application/pdf" : "image/png"));
490 GNUNET_assert (MHD_NO != MHD_add_response_header (pdfrs,
491 MHD_HTTP_HEADER_CONTENT_DISPOSITION,
492 (NULL == qrpng) ?
493 "attachment; filename=\"gns-business-card.pdf\"" :
494 "attachment; filename=\"gns-qr-code.png\""));
495 MHD_RESULT r = MHD_queue_response (connection, MHD_HTTP_OK, pdfrs);
496
497 MHD_destroy_response (pdfrs);
499 GNUNET_free (tmpd);
500
501 return r;
502}
503
511static struct StaticResource *
512open_static_resource (const char *name, const char *basedir)
513{
514 char *fullname = NULL;
515 GNUNET_asprintf (&fullname, "%s%s%s", basedir, DIR_SEPARATOR_STR, name);
516
517 struct GNUNET_DISK_FileHandle *f =
518 GNUNET_DISK_file_open (fullname,
521
522 GNUNET_free (fullname);
523
524 if (NULL == f)
525 {
526 return NULL;
527 }
528
529 off_t size = 0;
531 {
533 return NULL;
534 }
535
536 struct MHD_Response *response = MHD_create_response_from_fd64 (size, f->fd);
537
538 if (NULL == response)
539 {
541 return NULL;
542 }
543
544 struct StaticResource *res = GNUNET_new (struct StaticResource);
545 res->handle = f;
546 res->size = (uint64_t) size;
547 res->response = response;
548
549 return res;
550}
551
560static void
561run (void *cls,
562 char *const *args,
563 const char *cfgfile,
564 const struct GNUNET_CONFIGURATION_Handle *c)
565{
566 (void) cls;
567 (void) args;
568 (void) cfgfile;
569
570 if (0 == port)
571 {
573 _ ("Invalid port number %u\n"),
574 port);
576 return;
577 }
578
580
582 GNUNET_assert (NULL != datadir);
583
585 "%s%s%s",
586 datadir,
588 "gns-bcd.tex");
590 "%s%s%s",
591 datadir,
593 "gns-bcd-simple.tex");
595 "%s%s%s",
596 datadir,
598 "gns-bcd-png.tex");
599
600 index_simple = open_static_resource ("gns-bcd-simple.html", datadir);
601 index_full = open_static_resource ("gns-bcd.html", datadir);
602 key_error = open_static_resource ("gns-bcd-invalid-key.html", datadir);
603 notfound_error = open_static_resource ("gns-bcd-not-found.html", datadir);
604 internal_error = open_static_resource ("gns-bcd-internal-error.html", datadir);
605 forbidden_error = open_static_resource ("gns-bcd-forbidden.html", datadir);
606
607 GNUNET_free (datadir);
608
609 if ((NULL == index_simple) || (NULL == index_full)
610 || (NULL == key_error) || (NULL == notfound_error)
611 || (NULL == internal_error) || (NULL == forbidden_error))
612 {
614 _ ("Unable to set up the daemon\n"));
616 return;
617 }
618
619 int flags = MHD_USE_DUAL_STACK | MHD_USE_DEBUG | MHD_ALLOW_SUSPEND_RESUME;
620 do
621 {
622 httpd = MHD_start_daemon (flags,
623 port,
624 NULL, NULL,
625 &create_response, NULL,
626 MHD_OPTION_CONNECTION_LIMIT, 512,
627 MHD_OPTION_PER_IP_CONNECTION_LIMIT, 2,
628 MHD_OPTION_CONNECTION_TIMEOUT, 60,
629 MHD_OPTION_CONNECTION_MEMORY_LIMIT, 16 * 1024,
630 MHD_OPTION_END);
631 flags = MHD_USE_DEBUG;
632 } while (NULL == httpd && flags != MHD_USE_DEBUG);
633
634 if (NULL == httpd)
635 {
637 _ ("Failed to start HTTP server\n"));
639 return;
640 }
641
642 run_httpd ();
643}
644
652int
653main (int argc, char *const *argv)
654{
657 'p',
658 "port",
659 "PORT",
660 gettext_noop ("Run HTTP server on port PORT (default is 8888)"),
661 &port),
663 };
664
665 return ((GNUNET_OK ==
666 GNUNET_PROGRAM_run (argc,
667 argv,
668 "gnunet-bcd",
669 _ ("GNUnet HTTP server to create business cards"),
670 options,
671 &run,
672 NULL))
673 ? 0
674 : 1);
675}
676
677/* end of gnunet-bcd.c */
struct GNUNET_GETOPT_CommandLineOption GNUNET_GETOPT_OPTION_END
Definition: 002.c:13
struct GNUNET_GETOPT_CommandLineOption options[]
Definition: 002.c:5
#define gettext_noop(String)
Definition: gettext.h:70
static int ret
Final status code.
Definition: gnunet-arm.c:94
static struct GNUNET_TIME_Relative timeout
User defined timestamp for completing operations.
Definition: gnunet-arm.c:119
static char * tex_file_full
Full path to the TeX template file (full result)
Definition: gnunet-bcd.c:112
static struct StaticResource * key_error
Error: invalid gns key.
Definition: gnunet-bcd.c:87
static MHD_RESULT create_response(void *cls, struct MHD_Connection *connection, const char *url, const char *method, const char *version, const char *upload_data, size_t *upload_data_size, void **ptr)
Send a response back to a connected client.
Definition: gnunet-bcd.c:288
static struct StaticResource * index_full
Index file resource (full result).
Definition: gnunet-bcd.c:82
static int continue_100
Used as a sort of singleton to send exactly one 100 CONTINUE per request.
Definition: gnunet-bcd.c:122
static const struct ParameterMap pmap[]
Map of names with TeX definitions, used during PDF generation.
Definition: gnunet-bcd.c:127
static struct MHD_Daemon * httpd
Handle to the HTTP server as provided by libmicrohttpd.
Definition: gnunet-bcd.c:67
static char * tex_file_png
Full path to the TeX template file (PNG result)
Definition: gnunet-bcd.c:117
static struct StaticResource * forbidden_error
Other errors.
Definition: gnunet-bcd.c:102
static struct StaticResource * index_simple
Index file resource (simple result).
Definition: gnunet-bcd.c:77
static void do_shutdown(void *cls)
Task ran at shutdown to clean up everything.
Definition: gnunet-bcd.c:155
static void run_httpd(void)
Schedule a task to run MHD.
Definition: gnunet-bcd.c:221
static void run(void *cls, char *const *args, const char *cfgfile, const struct GNUNET_CONFIGURATION_Handle *c)
Main function that will be run.
Definition: gnunet-bcd.c:561
static uint16_t port
Port number.
Definition: gnunet-bcd.c:147
static void do_httpd(void *cls)
Called when the HTTP server has some pending operations.
Definition: gnunet-bcd.c:267
static char * tex_file_simple
Full path to the TeX template file (simple result)
Definition: gnunet-bcd.c:107
static struct GNUNET_SCHEDULER_Task * httpd_task
Our primary task for the HTTPD.
Definition: gnunet-bcd.c:72
int main(int argc, char *const *argv)
The main function for gnunet-gns.
Definition: gnunet-bcd.c:653
static struct StaticResource * internal_error
Errors after receiving the form data.
Definition: gnunet-bcd.c:97
static struct StaticResource * open_static_resource(const char *name, const char *basedir)
Open a file on disk and generate a response for it.
Definition: gnunet-bcd.c:512
static struct StaticResource * notfound_error
Error: 404.
Definition: gnunet-bcd.c:92
static struct MHD_Response * response
Our canonical response.
struct GNUNET_CRYPTO_PrivateKey pk
Private key from command line option, or NULL.
static char * name
Name (label) of the records to list.
static char * res
Currently read line or NULL on EOF.
static char * value
Value of the record to add/remove.
Identity service; implements identity management for GNUnet.
#define MHD_RESULT
struct GNUNET_DISK_FileHandle * GNUNET_DISK_file_open(const char *fn, enum GNUNET_DISK_OpenFlags flags, enum GNUNET_DISK_AccessPermissions perm)
Open a file.
Definition: disk.c:1237
char * GNUNET_DISK_mkdtemp(const char *t)
Create an (empty) temporary directory on disk.
Definition: disk.c:339
enum GNUNET_GenericReturnValue GNUNET_DISK_directory_remove(const char *filename)
Remove all files in a directory (rm -rf).
Definition: disk.c:1087
enum GNUNET_GenericReturnValue GNUNET_DISK_file_close(struct GNUNET_DISK_FileHandle *h)
Close an open file.
Definition: disk.c:1308
enum GNUNET_GenericReturnValue GNUNET_DISK_file_handle_size(struct GNUNET_DISK_FileHandle *fh, off_t *size)
Get the size of an open file.
Definition: disk.c:192
@ GNUNET_DISK_OPEN_READ
Open the file for reading.
@ GNUNET_DISK_PERM_NONE
Nobody is allowed to do anything to the file.
struct GNUNET_GETOPT_CommandLineOption GNUNET_GETOPT_option_uint16(char shortName, const char *name, const char *argumentHelp, const char *description, uint16_t *val)
Allow user to specify an uint16_t.
#define GNUNET_log(kind,...)
enum GNUNET_GenericReturnValue GNUNET_CRYPTO_public_key_from_string(const char *str, struct GNUNET_CRYPTO_PublicKey *key)
Parses a (Base32) string representation of the public key.
Definition: crypto_pkey.c:571
@ GNUNET_SCHEDULER_PRIORITY_HIGH
Run with high priority (important requests).
@ GNUNET_OK
@ GNUNET_SYSERR
#define GNUNET_assert(cond)
Use this for fatal errors that cannot be handled.
#define GNUNET_break(cond)
Use this for internal assertion violations that are not fatal (can be handled) but should not occur.
#define GNUNET_log_strerror_file(level, cmd, filename)
Log an error message at log-level 'level' that indicates a failure of the command 'cmd' with the mess...
@ GNUNET_ERROR_TYPE_ERROR
@ GNUNET_ERROR_TYPE_DEBUG
int int GNUNET_asprintf(char **buf, const char *format,...) __attribute__((format(printf
Like asprintf, just portable.
#define GNUNET_strdup(a)
Wrapper around GNUNET_xstrdup_.
#define GNUNET_strndup(a, length)
Wrapper around GNUNET_xstrndup_.
#define GNUNET_new(type)
Allocate a struct or union of the given type.
#define GNUNET_free(ptr)
Wrapper around free.
void GNUNET_NETWORK_fdset_destroy(struct GNUNET_NETWORK_FDSet *fds)
Releases the associated memory of an fd set.
Definition: network.c:1186
void GNUNET_NETWORK_fdset_copy_native(struct GNUNET_NETWORK_FDSet *to, const fd_set *from, int nfds)
Copy a native fd set into the GNUnet representation.
Definition: network.c:1040
struct GNUNET_NETWORK_FDSet * GNUNET_NETWORK_fdset_create(void)
Creates an fd set.
Definition: network.c:1170
char * GNUNET_OS_installation_get_path(enum GNUNET_OS_InstallationPathKind dirkind)
Get the path to a specific GNUnet installation directory or, with GNUNET_OS_IPK_SELF_PREFIX,...
@ GNUNET_OS_IPK_DATADIR
Return the directory where data is installed (share/gnunet/)
enum GNUNET_GenericReturnValue GNUNET_PROGRAM_run(int argc, char *const *argv, const char *binaryName, const char *binaryHelp, const struct GNUNET_GETOPT_CommandLineOption *options, GNUNET_PROGRAM_Main task, void *task_cls)
Run a standard GNUnet command startup sequence (initialize loggers and configuration,...
Definition: program.c:400
void GNUNET_SCHEDULER_shutdown(void)
Request the shutdown of a scheduler.
Definition: scheduler.c:567
struct GNUNET_SCHEDULER_Task * GNUNET_SCHEDULER_add_select(enum GNUNET_SCHEDULER_Priority prio, struct GNUNET_TIME_Relative delay, const struct GNUNET_NETWORK_FDSet *rs, const struct GNUNET_NETWORK_FDSet *ws, GNUNET_SCHEDULER_TaskCallback task, void *task_cls)
Schedule a new task to be run with a specified delay or when any of the specified file descriptor set...
Definition: scheduler.c:1836
struct GNUNET_SCHEDULER_Task * GNUNET_SCHEDULER_add_shutdown(GNUNET_SCHEDULER_TaskCallback task, void *task_cls)
Schedule a new task to be run on shutdown, that is when a CTRL-C signal is received,...
Definition: scheduler.c:1340
void * GNUNET_SCHEDULER_cancel(struct GNUNET_SCHEDULER_Task *task)
Cancel the task with the specified identifier.
Definition: scheduler.c:981
#define GNUNET_TIME_UNIT_FOREVER_REL
Constant used to specify "forever".
#define GNUNET_TIME_UNIT_MILLISECONDS
One millisecond.
struct GNUNET_TIME_Relative GNUNET_TIME_relative_multiply(struct GNUNET_TIME_Relative rel, unsigned long long factor)
Multiply relative time by a given factor.
Definition: time.c:484
@ MHD_HTTP_BAD_REQUEST
Bad Request [RFC7231, Section 6.5.1].
@ MHD_HTTP_OK
OK [RFC7231, Section 6.3.1].
@ MHD_HTTP_NOT_FOUND
Not Found [RFC7231, Section 6.5.4].
@ MHD_HTTP_INTERNAL_SERVER_ERROR
Internal Server Error [RFC7231, Section 6.6.1].
@ MHD_HTTP_NOT_IMPLEMENTED
Not Implemented [RFC7231, Section 6.6.2].
#define max(x, y)
static unsigned int size
Size of the "table".
Definition: peer.c:68
#define DIR_SEPARATOR_STR
Definition: platform.h:166
#define _(String)
GNU gettext support macro.
Definition: platform.h:178
An identity key as per LSD0001.
Handle used to access files (and pipes).
Definition of a command line option.
collection of IO descriptors
Entry in list of pending tasks.
Definition: scheduler.c:136
Time for relative time used by GNUnet, in microseconds.
char * name
Name of the parameter from the request.
Definition: gnunet-bcd.c:56
char * definition
Name of the definition in the TeX output.
Definition: gnunet-bcd.c:61
struct MHD_Response * response
Cached response object to send to clients.
Definition: gnunet-bcd.c:48
struct GNUNET_DISK_FileHandle * handle
Handle to file on disk.
Definition: gnunet-bcd.c:38
uint64_t size
Size in bytes of the file.
Definition: gnunet-bcd.c:43