GNUnet 0.22.0
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"
30#include "gnunet_mhd_compat.h"
31
33{
38
42 uint64_t size;
43
47 struct MHD_Response *response;
48};
49
51{
55 const char *name;
56
60 const char *definition;
61};
62
66static struct MHD_Daemon *httpd = NULL;
67
71static struct GNUNET_SCHEDULER_Task *httpd_task = NULL;
72
76static struct StaticResource *index_simple = NULL;
77
81static struct StaticResource *index_full = NULL;
82
86static struct StaticResource *key_error = NULL;
87
91static struct StaticResource *notfound_error = NULL;
92
96static struct StaticResource *internal_error = NULL;
97
101static struct StaticResource *forbidden_error = NULL;
102
106static char *tex_file_simple = NULL;
107
111static char *tex_file_full = NULL;
112
116static char *tex_file_png = NULL;
117
121static int continue_100 = 100;
122
126static const struct ParameterMap pmap[] = {
127 {"prefix", "prefix"},
128 {"name", "name"},
129 {"suffix", "suffix"},
130 {"street", "street"},
131 {"city", "city"},
132 {"phone", "phone"},
133 {"fax", "fax"},
134 {"email", "email"},
135 {"homepage", "homepage"},
136 {"org", "organization"},
137 {"department", "department"},
138 {"subdepartment", "subdepartment"},
139 {"jobtitle", "jobtitle"},
140 {NULL, NULL},
141};
142
146static uint16_t port = 8888;
147
153static void
154do_shutdown (void *cls)
155{
156 /* We cheat a bit here: the file descriptor is implicitly closed by MHD, so
157 calling `GNUNET_DISK_file_close' would generate a spurious warning message
158 in the log. Since that function does nothing but close the descriptor and
159 free the allocated memory, After destroying the response all that's left to
160 do is call `GNUNET_free'. */
161 if (NULL != index_simple)
162 {
163 MHD_destroy_response (index_simple->response);
166 }
167 if (NULL != index_full)
168 {
169 MHD_destroy_response (index_full->response);
172 }
173 if (NULL != key_error)
174 {
175 MHD_destroy_response (key_error->response);
178 }
179 if (NULL != notfound_error)
180 {
181 MHD_destroy_response (notfound_error->response);
184 }
185 if (NULL != internal_error)
186 {
187 MHD_destroy_response (internal_error->response);
190 }
191 if (NULL != forbidden_error)
192 {
193 MHD_destroy_response (forbidden_error->response);
196 }
197
198 if (NULL != httpd_task)
199 {
201 }
202 if (NULL != httpd)
203 {
204 MHD_stop_daemon (httpd);
205 }
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 int max = -1;
227 unsigned MHD_LONG_LONG timeout = 0;
229
233
234 FD_ZERO (&rs);
235 FD_ZERO (&ws);
236 FD_ZERO (&es);
237
238 GNUNET_assert (MHD_YES == MHD_get_fdset (httpd, &rs, &ws, &es, &max));
239
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
261
267static void
268do_httpd (void *cls)
269{
270 httpd_task = NULL;
271 MHD_run (httpd);
272 run_httpd ();
273}
274
275
289static MHD_RESULT
291 struct MHD_Connection *connection,
292 const char *url,
293 const char *method,
294 const char *version,
295 const char *upload_data,
296 size_t *upload_data_size,
297 void **ptr)
298{
300 bool isget = (0 == strcmp (method, MHD_HTTP_METHOD_GET));
301 bool ishead = (0 == strcmp (method, MHD_HTTP_METHOD_HEAD));
302 bool isfull = (0 == strcmp ("/submit/full", url));
303 bool issimple = (0 == strcmp ("/submit/simple", url));
304 char *tmpd;
305 char *defpath = NULL;
306 const char *gpgfp = MHD_lookup_connection_value (connection,
307 MHD_GET_ARGUMENT_KIND,
308 "gpgfingerprint");
309 const char *gnsnick = MHD_lookup_connection_value (connection,
310 MHD_GET_ARGUMENT_KIND,
311 "gnsnick");
312 const char *gnskey = MHD_lookup_connection_value (connection,
313 MHD_GET_ARGUMENT_KIND,
314 "gnskey");
315 const char *qrpng = MHD_lookup_connection_value (connection,
316 MHD_GET_ARGUMENT_KIND,
317 "gnspng");
318
319 (void) cls;
320 (void) version;
321 (void) upload_data;
322 (void) upload_data_size;
323
324 if (! isget && ! ishead)
325 {
326 return MHD_queue_response (connection,
329 }
330
331 if (ishead)
332 {
333 /* Dedicated branch in case we want to provide a different result for some
334 reason (e.g. a non-web browser application using the web UI) */
335 return MHD_queue_response (connection,
338 }
339
340 /* Send a 100 CONTINUE response to tell clients that the result of the
341 request might take some time */
342 if (NULL == *ptr)
343 {
344 *ptr = &continue_100;
345 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "Sending 100 CONTINUE\n");
346 return MHD_YES;
347 }
348
349 if (0 == strcmp ("/", url))
350 {
351 return MHD_queue_response (connection,
354 }
355
356 if (0 == strcmp ("/full", url))
357 {
358 return MHD_queue_response (connection,
361 }
362
363
364 if (! isfull && ! issimple)
365 {
366 return MHD_queue_response (connection,
369 }
370
371
372 if (NULL == gnskey
374 {
375 return MHD_queue_response (connection,
378 }
379
380 tmpd = GNUNET_DISK_mkdtemp (gnskey);
381 if (NULL == tmpd)
382 {
384 return MHD_queue_response (connection,
387 }
388
389 GNUNET_asprintf (&defpath, "%s%s%s", tmpd, DIR_SEPARATOR_STR, "def.tex");
390
391 {
392 FILE *deffile = fopen (defpath, "w");
393 if (NULL == deffile)
394 {
396 GNUNET_free (defpath);
398 GNUNET_free (tmpd);
399 return MHD_queue_response (connection,
402 }
403
404 GNUNET_free (defpath);
405
406 for (size_t i = 0; NULL!=pmap[i].name; ++i)
407 {
408 const char *value = MHD_lookup_connection_value (connection,
409 MHD_GET_ARGUMENT_KIND,
410 pmap[i].name);
411 fprintf (deffile,
412 "\\def\\%s{%s}\n",
413 pmap[i].definition,
414 (NULL == value) ? "" : value);
415 }
416
417 if (NULL != gpgfp)
418 {
419 size_t len = strlen (gpgfp);
420 char *line1 = GNUNET_strndup (gpgfp, len / 2);
421 char *line2 = GNUNET_strdup (&gpgfp[len / 2]);
422 fprintf (deffile,
423 "\\def\\gpglineone{%s}\n\\def\\gpglinetwo{%s}\n",
424 line1,
425 line2);
426 GNUNET_free (line1);
427 GNUNET_free (line2);
428 }
429
430 fprintf (deffile,
431 "\\def\\gns{%s/%s}\n",
432 gnskey,
433 (NULL == gnsnick) ? "" : gnsnick);
434
435 fclose (deffile);
436 }
437 {
438 char *command = NULL;
439 int ret;
440 GNUNET_asprintf (&command,
441 "cd %s; cp %s gns-bcd.tex; "
442 "pdflatex %s gns-bcd.tex >/dev/null 2>&1",
443 tmpd,
444 (isfull) ? tex_file_full :
445 ((NULL == qrpng) ? tex_file_simple : tex_file_png),
446 (NULL == qrpng) ? "" : "-shell-escape");
447
448 ret = system (command);
449
450 if (WIFSIGNALED (ret) || 0 != WEXITSTATUS (ret))
451 {
453 }
454
455 GNUNET_free (command);
456 }
457 GNUNET_asprintf (&defpath,
458 "%s%s%s",
459 tmpd,
461 (NULL == qrpng) ? "gns-bcd.pdf" : "gns-bcd.png");
462 {
463 MHD_RESULT r;
464 struct MHD_Response *pdfrs;
465 struct stat statret;
466 int pdf = open (defpath, O_RDONLY);
467 if (-1 == pdf)
468 {
470 GNUNET_free (defpath);
472 GNUNET_free (tmpd);
473 return MHD_queue_response (connection,
476 }
477
478 GNUNET_break (0 == stat (defpath, &statret));
479
480 GNUNET_free (defpath);
481
482 pdfrs = MHD_create_response_from_fd ((size_t) statret.st_size, pdf);
483 if (NULL == pdfrs)
484 {
485 GNUNET_break (0);
486 GNUNET_break (0 == close (pdf));
488 GNUNET_free (tmpd);
489 return MHD_queue_response (connection,
492 }
493
494 GNUNET_assert (MHD_NO != MHD_add_response_header (pdfrs,
495 MHD_HTTP_HEADER_CONTENT_TYPE,
496 (NULL == qrpng) ?
497 "application/pdf" :
498 "image/png"));
499 GNUNET_assert (MHD_NO !=
500 MHD_add_response_header (pdfrs,
501 MHD_HTTP_HEADER_CONTENT_DISPOSITION,
502 (NULL == qrpng) ?
503 "attachment; filename=\"gns-business-card.pdf\""
504 :
505 "attachment; filename=\"gns-qr-code.png\""));
506 r = MHD_queue_response (connection, MHD_HTTP_OK, pdfrs);
507
508 MHD_destroy_response (pdfrs);
510 GNUNET_free (tmpd);
511 return r;
512 }
513}
514
515
523static struct StaticResource *
524open_static_resource (const char *name, const char *basedir)
525{
526 char *fullname = NULL;
527 off_t size = 0;
529 struct MHD_Response *response;
530 struct StaticResource *res;
531 GNUNET_asprintf (&fullname, "%s%s%s", basedir, DIR_SEPARATOR_STR, name);
532
533 f = GNUNET_DISK_file_open (fullname,
536
537 GNUNET_free (fullname);
538
539 if (NULL == f)
540 {
541 return NULL;
542 }
543
545 {
547 return NULL;
548 }
549
550 response = MHD_create_response_from_fd64 (size, f->fd);
551
552 if (NULL == response)
553 {
555 return NULL;
556 }
557
558 res = GNUNET_new (struct StaticResource);
559 res->handle = f;
560 res->size = (uint64_t) size;
561 res->response = response;
562
563 return res;
564}
565
566
575static void
576run (void *cls,
577 char *const *args,
578 const char *cfgfile,
579 const struct GNUNET_CONFIGURATION_Handle *c)
580{
581 char *datadir;
582 (void) cls;
583 (void) args;
584 (void) cfgfile;
585
586 if (0 == port)
587 {
589 _ ("Invalid port number %u\n"),
590 port);
592 return;
593 }
594
596
598 GNUNET_assert (NULL != datadir);
599
601 "%s%s%s",
602 datadir,
604 "gns-bcd.tex");
606 "%s%s%s",
607 datadir,
609 "gns-bcd-simple.tex");
611 "%s%s%s",
612 datadir,
614 "gns-bcd-png.tex");
615
616 index_simple = open_static_resource ("gns-bcd-simple.html", datadir);
617 index_full = open_static_resource ("gns-bcd.html", datadir);
618 key_error = open_static_resource ("gns-bcd-invalid-key.html", datadir);
619 notfound_error = open_static_resource ("gns-bcd-not-found.html", datadir);
620 internal_error = open_static_resource ("gns-bcd-internal-error.html", datadir)
621 ;
622 forbidden_error = open_static_resource ("gns-bcd-forbidden.html", datadir);
623
624 GNUNET_free (datadir);
625
626 if ((NULL == index_simple) || (NULL == index_full)
627 || (NULL == key_error) || (NULL == notfound_error)
628 || (NULL == internal_error) || (NULL == forbidden_error))
629 {
631 _ ("Unable to set up the daemon\n"));
633 return;
634 }
635
636 {
637 int flags = MHD_USE_DUAL_STACK | MHD_USE_DEBUG | MHD_ALLOW_SUSPEND_RESUME;
638 do
639 {
640 httpd = MHD_start_daemon (flags,
641 port,
642 NULL, NULL,
643 &create_response, NULL,
644 MHD_OPTION_CONNECTION_LIMIT, 512,
645 MHD_OPTION_PER_IP_CONNECTION_LIMIT, 2,
646 MHD_OPTION_CONNECTION_TIMEOUT, 60,
647 MHD_OPTION_CONNECTION_MEMORY_LIMIT, 16 * 1024,
648 MHD_OPTION_END);
649 flags = MHD_USE_DEBUG;
650 } while (NULL == httpd && flags != MHD_USE_DEBUG);
651 }
652 if (NULL == httpd)
653 {
655 _ ("Failed to start HTTP server\n"));
657 return;
658 }
659
660 run_httpd ();
661}
662
663
671int
672main (int argc, char *const *argv)
673{
676 'p',
677 "port",
678 "PORT",
679 gettext_noop ("Run HTTP server on port PORT (default is 8888)"),
680 &port),
682 };
683
684 return ((GNUNET_OK ==
685 GNUNET_PROGRAM_run (argc,
686 argv,
687 "gnunet-bcd",
688 _ ("GNUnet HTTP server to create business cards")
689 ,
690 options,
691 &run,
692 NULL))
693 ? 0
694 : 1);
695}
696
697
698/* 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:74
static int ret
Final status code.
Definition: gnunet-arm.c:93
static struct GNUNET_TIME_Relative timeout
User defined timestamp for completing operations.
Definition: gnunet-arm.c:118
static char * tex_file_full
Full path to the TeX template file (full result)
Definition: gnunet-bcd.c:111
static struct StaticResource * key_error
Error: invalid gns key.
Definition: gnunet-bcd.c:86
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:290
static struct StaticResource * index_full
Index file resource (full result).
Definition: gnunet-bcd.c:81
static int continue_100
Used as a sort of singleton to send exactly one 100 CONTINUE per request.
Definition: gnunet-bcd.c:121
static const struct ParameterMap pmap[]
Map of names with TeX definitions, used during PDF generation.
Definition: gnunet-bcd.c:126
static struct MHD_Daemon * httpd
Handle to the HTTP server as provided by libmicrohttpd.
Definition: gnunet-bcd.c:66
static char * tex_file_png
Full path to the TeX template file (PNG result)
Definition: gnunet-bcd.c:116
static struct StaticResource * forbidden_error
Other errors.
Definition: gnunet-bcd.c:101
static struct StaticResource * index_simple
Index file resource (simple result).
Definition: gnunet-bcd.c:76
static void do_shutdown(void *cls)
Task ran at shutdown to clean up everything.
Definition: gnunet-bcd.c:154
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:576
static uint16_t port
Port number.
Definition: gnunet-bcd.c:146
static void do_httpd(void *cls)
Called when the HTTP server has some pending operations.
Definition: gnunet-bcd.c:268
static char * tex_file_simple
Full path to the TeX template file (simple result)
Definition: gnunet-bcd.c:106
static struct GNUNET_SCHEDULER_Task * httpd_task
Our primary task for the HTTPD.
Definition: gnunet-bcd.c:71
int main(int argc, char *const *argv)
The main function for gnunet-gns.
Definition: gnunet-bcd.c:672
static struct StaticResource * internal_error
Errors after receiving the form data.
Definition: gnunet-bcd.c:96
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:524
static struct StaticResource * notfound_error
Error: 404.
Definition: gnunet-bcd.c:91
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.
#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:1238
char * GNUNET_DISK_mkdtemp(const char *t)
Create an (empty) temporary directory on disk.
Definition: disk.c:340
enum GNUNET_GenericReturnValue GNUNET_DISK_directory_remove(const char *filename)
Remove all files in a directory (rm -rf).
Definition: disk.c:1088
enum GNUNET_GenericReturnValue GNUNET_DISK_file_close(struct GNUNET_DISK_FileHandle *h)
Close an open file.
Definition: disk.c:1309
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:193
@ 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:399
@ 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:1187
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:1041
struct GNUNET_NETWORK_FDSet * GNUNET_NETWORK_fdset_create(void)
Creates an fd set.
Definition: network.c:1171
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:566
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:1834
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:1338
void * GNUNET_SCHEDULER_cancel(struct GNUNET_SCHEDULER_Task *task)
Cancel the task with the specified identifier.
Definition: scheduler.c:979
#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:486
@ 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:135
Time for relative time used by GNUnet, in microseconds.
const char * name
Name of the parameter from the request.
Definition: gnunet-bcd.c:55
const char * definition
Name of the definition in the TeX output.
Definition: gnunet-bcd.c:60
struct MHD_Response * response
Cached response object to send to clients.
Definition: gnunet-bcd.c:47
struct GNUNET_DISK_FileHandle * handle
Handle to file on disk.
Definition: gnunet-bcd.c:37
uint64_t size
Size in bytes of the file.
Definition: gnunet-bcd.c:42