GNUnet  0.10.x
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 
34 #define INVALID_GNSKEY "<html><head><title>Error</title><body>Invalid GNS public key given.</body></html>"
35 
39 #define NOT_FOUND "<html><head><title>Error</title><body>404 not found</body></html>"
40 
44 static struct MHD_Daemon *daemon_handle;
45 
49 static const struct GNUNET_CONFIGURATION_Handle *cfg;
50 
55 
59 static struct MHD_Response *main_response;
60 
64 static struct MHD_Response *invalid_gnskey_response;
65 
69 static struct MHD_Response *not_found_response;
70 
74 static char *resfile;
75 
79 static uint16_t port = 8888;
80 
81 
82 struct Entry
83 {
84  const char *formname;
85  const char *texname;
86 };
87 
88 
92 static int
94  struct MHD_Connection *connection,
95  const char *url,
96  const char *method,
97  const char *version,
98  const char *upload_data,
99  size_t * upload_data_size,
100  void **con_cls)
101 {
102  static int dummy;
103  static const struct Entry map[] = {
104  { "prefix", "prefix" },
105  { "name", "name" },
106  { "suffix", "suffix" },
107  { "street", "street" },
108  { "city", "city" },
109  { "phone", "phone" },
110  { "fax", "fax" },
111  { "email", "email"},
112  { "homepage", "homepage" },
113  { "orga", "orga"},
114  { "departmenti18n", "departmentde"},
115  { "departmenten", "departmenten"},
116  { "subdepartmenti18n", "subdepartmentde"},
117  { "subdepartmenten", "subdepartmenten"},
118  { "jobtitlei18n", "jobtitlegerman"},
119  { "jobtitleen", "jobtitleenglish"},
120  { "subdepartmenten", "subdepartmenten"},
121  { NULL, NULL }
122  };
123 
124  if (0 != strcmp (method, MHD_HTTP_METHOD_GET))
125  {
127  _("Refusing `%s' request to HTTP server\n"),
128  method);
129  return MHD_NO;
130  }
131  if (NULL == *con_cls)
132  {
133  (*con_cls) = &dummy;
135  "Sending 100 CONTINUE reply\n");
136  return MHD_YES; /* send 100 continue */
137  }
138  if (0 == strcasecmp (url, "/"))
139  return MHD_queue_response (connection,
140  MHD_HTTP_OK,
141  main_response);
142  if (0 == strcasecmp (url, "/submit.pdf"))
143  {
144  unsigned int i;
145  char *p;
146  char *tmp;
147  char *deffile;
148  struct GNUNET_CRYPTO_EcdsaPublicKey pub;
149  size_t slen;
150  FILE *f;
151  struct stat st;
152  struct MHD_Response *response;
153  int fd;
154  int ret;
155 
156  const char *gpg_fp = MHD_lookup_connection_value (connection,
157  MHD_GET_ARGUMENT_KIND,
158  "gpgfingerprint");
159  const char *gns_nick = MHD_lookup_connection_value (connection,
160  MHD_GET_ARGUMENT_KIND,
161  "gnsnick");
162  const char *gnskey = MHD_lookup_connection_value (connection,
163  MHD_GET_ARGUMENT_KIND,
164  "gnskey");
165  if ( (NULL == gnskey) ||
166  (GNUNET_OK !=
168  strlen (gnskey),
169  &pub)))
170  {
171  return MHD_queue_response (connection,
172  MHD_HTTP_OK,
174  }
175  tmp = GNUNET_DISK_mkdtemp (gnskey);
176  if (NULL == tmp)
177  {
179  return MHD_NO;
180  }
181  GNUNET_asprintf (&deffile,
182  "%s%s%s",
183  tmp, DIR_SEPARATOR_STR, "def.tex");
184  f = FOPEN (deffile, "w");
185  if (NULL == f)
186  {
188  GNUNET_free (deffile);
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,
200  "\\def\\%s{%s}\n",
201  map[i].texname, val);
202  else
203  FPRINTF (f,
204  "\\def\\%s{}\n",
205  map[i].texname);
206  }
207  if (NULL != gpg_fp)
208  {
209  char *gpg1;
210  char *gpg2;
211 
212  slen = strlen (gpg_fp);
213  gpg1 = GNUNET_strndup (gpg_fp, slen / 2);
214  gpg2 = GNUNET_strdup (&gpg_fp[slen / 2]);
215  FPRINTF (f,
216  "\\def\\gpglineone{%s}\n\\def\\gpglinetwo{%s}\n",
217  gpg1, gpg2);
218  GNUNET_free (gpg2);
219  GNUNET_free (gpg1);
220  }
221  FPRINTF (f,
222  "\\def\\gns{%s/%s}\n",
223  gnskey,
224  (NULL == gns_nick) ? "" : gns_nick);
225  FCLOSE (f);
226  GNUNET_asprintf (&p,
227  "cd %s; cp %s gns-bcd.tex | pdflatex --enable-write18 gns-bcd.tex > /dev/null 2> /dev/null",
228  tmp,
229  resfile);
230  GNUNET_free (deffile);
231  ret = system (p);
232  if (WIFSIGNALED (ret) || (0 != WEXITSTATUS(ret)))
234  "system",
235  p);
236  GNUNET_asprintf (&deffile,
237  "%s%s%s",
238  tmp, DIR_SEPARATOR_STR, "gns-bcd.pdf");
239  fd = OPEN (deffile, O_RDONLY);
240  if (-1 == fd)
241  {
243  "open",
244  deffile);
245  GNUNET_free (deffile);
246  GNUNET_free (p);
248  GNUNET_free (tmp);
249  return MHD_NO;
250  }
251  GNUNET_break (0 == STAT (deffile, &st));
252  if (NULL == (response = MHD_create_response_from_fd ((size_t) st.st_size, fd)))
253  {
254  GNUNET_break (0);
255  GNUNET_break (0 == CLOSE (fd));
256  GNUNET_free (deffile);
257  GNUNET_free (p);
259  GNUNET_free (tmp);
260  return MHD_NO;
261  }
262  (void) MHD_add_response_header (response,
263  MHD_HTTP_HEADER_CONTENT_TYPE,
264  "application/pdf");
265  ret = MHD_queue_response (connection,
266  MHD_HTTP_OK,
267  response);
268  MHD_destroy_response (response);
269  GNUNET_free (deffile);
270  GNUNET_free (p);
272  GNUNET_free (tmp);
273  return ret;
274  }
275  return MHD_queue_response (connection,
276  MHD_HTTP_NOT_FOUND,
278 }
279 
280 
285 static struct GNUNET_SCHEDULER_Task *
286 prepare_daemon (struct MHD_Daemon *daemon_handle);
287 
288 
293 static void
294 run_daemon (void *cls)
295 {
296  struct MHD_Daemon *daemon_handle = cls;
297 
298  http_task = NULL;
299  GNUNET_assert (MHD_YES == MHD_run (daemon_handle));
300  http_task = prepare_daemon (daemon_handle);
301 }
302 
303 
308 static struct GNUNET_SCHEDULER_Task *
309 prepare_daemon (struct MHD_Daemon *daemon_handle)
310 {
311  struct GNUNET_SCHEDULER_Task * ret;
312  fd_set rs;
313  fd_set ws;
314  fd_set es;
315  struct GNUNET_NETWORK_FDSet *wrs;
316  struct GNUNET_NETWORK_FDSet *wws;
317  int max;
318  MHD_UNSIGNED_LONG_LONG timeout;
319  int haveto;
320  struct GNUNET_TIME_Relative tv;
321 
322  FD_ZERO (&rs);
323  FD_ZERO (&ws);
324  FD_ZERO (&es);
327  max = -1;
328  GNUNET_assert (MHD_YES == MHD_get_fdset (daemon_handle, &rs, &ws, &es, &max));
329  haveto = MHD_get_timeout (daemon_handle, &timeout);
330  if (haveto == MHD_YES)
331  tv.rel_value_us = (uint64_t) timeout * 1000LL;
332  else
334  GNUNET_NETWORK_fdset_copy_native (wrs, &rs, max + 1);
335  GNUNET_NETWORK_fdset_copy_native (wws, &ws, max + 1);
336  ret =
338  tv, wrs, wws,
339  &run_daemon, daemon_handle);
342  return ret;
343 }
344 
345 
351 static int
353 {
354  if (0 == port)
355  {
357  _("Invalid port number %u. Exiting.\n"),
358  port);
359  return GNUNET_SYSERR;
360  }
362  _("Businesscard HTTP server starts on %u\n"),
363  port);
364  daemon_handle = MHD_start_daemon (MHD_USE_DUAL_STACK | MHD_USE_DEBUG,
365  port,
366  NULL /* accept_policy_callback */, NULL,
368  MHD_OPTION_CONNECTION_LIMIT, (unsigned int) 512,
369  MHD_OPTION_PER_IP_CONNECTION_LIMIT, (unsigned int) 2,
370  MHD_OPTION_CONNECTION_TIMEOUT, (unsigned int) 60,
371  MHD_OPTION_CONNECTION_MEMORY_LIMIT, (size_t) (16 * 1024),
372  MHD_OPTION_END);
373  if (NULL == daemon_handle)
374  {
376  _("Could not start businesscard HTTP server on port %u\n"),
377  (unsigned int) port);
378  return GNUNET_SYSERR;
379  }
380  http_task = prepare_daemon (daemon_handle);
381  return GNUNET_OK;
382 }
383 
384 
388 static void
389 server_stop (void *cls)
390 {
392  "HTTP server shutdown\n");
393  if (NULL != http_task)
394  {
395  GNUNET_SCHEDULER_cancel (http_task);
396  http_task = NULL;
397  }
398  if (NULL != daemon_handle)
399  {
400  MHD_stop_daemon (daemon_handle);
401  daemon_handle = NULL;
402  }
403  if (NULL != main_response)
404  {
405  MHD_destroy_response (main_response);
406  main_response = NULL;
407  }
408  if (NULL != invalid_gnskey_response)
409  {
410  MHD_destroy_response (invalid_gnskey_response);
412  }
413  if (NULL != not_found_response)
414  {
415  MHD_destroy_response (not_found_response);
416  not_found_response = NULL;
417  }
418  if (NULL != resfile)
419  {
421  resfile = NULL;
422  }
423 }
424 
425 
434 static void
435 run (void *cls,
436  char *const *args,
437  const char *cfgfile,
438  const struct GNUNET_CONFIGURATION_Handle *c)
439 {
440  struct stat st;
441  char *dir;
442  char *fn;
443  int fd;
444 
445  cfg = c;
447  GNUNET_assert (NULL != dir);
448  GNUNET_asprintf (&fn,
449  "%s%s%s",
450  dir,
452  "gns-bcd.html");
454  "%s%s%s",
455  dir,
457  "gns-bcd.tex");
458  GNUNET_free (dir);
459  fd = OPEN (fn, O_RDONLY);
460  if (-1 == fd)
461  {
463  "open",
464  fn);
465  GNUNET_free (fn);
466  return;
467  }
468  if (0 != STAT (fn, &st))
469  {
471  "open",
472  fn);
473  GNUNET_free (fn);
474  GNUNET_break (0 == CLOSE (fd));
475  return;
476  }
477  GNUNET_free (fn);
478  if (NULL == (main_response = MHD_create_response_from_fd ((size_t) st.st_size, fd)))
479  {
480  GNUNET_break (0);
481  GNUNET_break (0 == CLOSE (fd));
482  return;
483  }
484  (void) MHD_add_response_header (main_response,
485  MHD_HTTP_HEADER_CONTENT_TYPE,
486  "text/html");
487  invalid_gnskey_response = MHD_create_response_from_buffer (strlen (INVALID_GNSKEY),
489  MHD_RESPMEM_PERSISTENT);
490  (void) MHD_add_response_header (invalid_gnskey_response,
491  MHD_HTTP_HEADER_CONTENT_TYPE,
492  "text/html");
493  not_found_response = MHD_create_response_from_buffer (strlen (NOT_FOUND),
494  NOT_FOUND,
495  MHD_RESPMEM_PERSISTENT);
496  (void) MHD_add_response_header (not_found_response,
497  MHD_HTTP_HEADER_CONTENT_TYPE,
498  "text/html");
499  if (GNUNET_OK !=
500  server_start ())
501  return;
503  NULL);
504  GNUNET_break (0 == CLOSE(fd));
505 }
506 
507 
515 int
516 main (int argc, char *const *argv)
517 {
518  struct GNUNET_GETOPT_CommandLineOption options[] = {
519 
521  "port",
522  "PORT",
523  gettext_noop ("Run HTTP serve on port PORT (default is 8888)"),
524  &port),
526  };
527  int ret;
528 
529  if (GNUNET_OK !=
530  GNUNET_STRINGS_get_utf8_args (argc, argv, &argc, &argv))
531  return 2;
532  GNUNET_log_setup ("gnunet-bcd", "WARNING", NULL);
533  ret =
534  (GNUNET_OK ==
535  GNUNET_PROGRAM_run (argc, argv, "gnunet-bcd",
536  _("GNUnet HTTP server to create business cards"),
537  options,
538  &run, NULL)) ? 0 : 1;
539  GNUNET_free ((void*) argv);
540  return ret;
541 }
542 
543 
544 /* end of gnunet-bcd.c */
static const struct GNUNET_CONFIGURATION_Handle * cfg
Our configuration.
Definition: gnunet-bcd.c:49
static struct MHD_Daemon * daemon_handle
Handle to the HTTP server as provided by libmicrohttpd.
Definition: gnunet-bcd.c:44
static char * dir
Set to the directory where runtime files are stored.
Definition: gnunet-arm.c:84
static struct MHD_Response * invalid_gnskey_response
Error: invalid gns key.
Definition: gnunet-bcd.c:64
#define OPEN
Definition: plibc.h:651
Run with high priority (important requests).
uint64_t rel_value_us
The actual value.
static struct in_addr dummy
Target "dummy" address.
int main(int argc, char *const *argv)
The main function for gnunet-gns.
Definition: gnunet-bcd.c:516
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:435
#define NOT_FOUND
Error page to display on 404.
Definition: gnunet-bcd.c:39
#define FPRINTF
Definition: plibc.h:683
static struct MHD_Response * not_found_response
Error: 404.
Definition: gnunet-bcd.c:69
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, or when GNUNET_SCHEDULER_shutdown() is being invoked.
Definition: scheduler.c:1293
int GNUNET_STRINGS_get_utf8_args(int argc, char *const *argv, int *u8argc, char *const **u8argv)
Returns utf-8 encoded arguments.
Definition: strings.c:1521
#define GNUNET_assert(cond)
Use this for fatal errors that cannot be handled.
static struct GNUNET_SCHEDULER_Task * http_task
Our primary task for the HTTPD.
Definition: gnunet-bcd.c:54
static int server_start()
Start server offering our hostlist.
Definition: gnunet-bcd.c:352
#define GNUNET_OK
Named constants for return values.
Definition: gnunet_common.h:78
Definition of a command line option.
const char * texname
Definition: gnunet-bcd.c:85
#define STAT(p, b)
Definition: plibc.h:663
static int ret
Final status code.
Definition: gnunet-arm.c:89
#define GNUNET_strdup(a)
Wrapper around GNUNET_xstrdup_.
#define FOPEN(f, m)
Definition: plibc.h:644
#define GNUNET_break(cond)
Use this for internal assertion violations that are not fatal (can be handled) but should not occur...
struct GNUNET_GETOPT_CommandLineOption GNUNET_GETOPT_OPTION_END
Definition: 002.c:13
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:1308
#define _(String)
GNU gettext support macro.
Definition: platform.h:208
void GNUNET_NETWORK_fdset_destroy(struct GNUNET_NETWORK_FDSet *fds)
Releases the associated memory of an fd set.
Definition: network.c:1554
int GNUNET_asprintf(char **buf, const char *format,...)
Like asprintf, just portable.
struct GNUNET_NETWORK_FDSet * GNUNET_NETWORK_fdset_create(void)
Creates an fd set.
Definition: network.c:1538
static struct GNUNET_TIME_Relative timeout
User defined timestamp for completing operations.
Definition: gnunet-arm.c:114
static struct GNUNET_OS_Process * p
Helper process we started.
Definition: gnunet-qr.c:59
#define GNUNET_log_strerror_file(level, cmd, filename)
Log an error message at log-level &#39;level&#39; that indicates a failure of the command &#39;cmd&#39; with the mess...
static char * fn
Filename of the unique file.
int GNUNET_DISK_directory_remove(const char *filename)
Remove all files in a directory (rm -rf).
Definition: disk.c:1359
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, the current running apps installation directory.
collection of IO descriptors
#define CLOSE(f)
Definition: plibc.h:653
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:1829
#define GNUNET_TIME_UNIT_FOREVER_REL
Constant used to specify "forever".
#define GNUNET_SYSERR
Definition: gnunet_common.h:79
char * GNUNET_DISK_mkdtemp(const char *t)
Create an (empty) temporary directory on disk.
Definition: disk.c:530
const char * formname
Definition: gnunet-bcd.c:84
static int access_handler_callback(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 **con_cls)
Main request handler.
Definition: gnunet-bcd.c:93
static struct GNUNET_SCHEDULER_Task * prepare_daemon(struct MHD_Daemon *daemon_handle)
Function that queries MHD&#39;s select sets and starts the task waiting for them.
Definition: gnunet-bcd.c:309
static struct MHD_Response * main_response
Our main website.
Definition: gnunet-bcd.c:59
#define GNUNET_strndup(a, length)
Wrapper around GNUNET_xstrndup_.
int GNUNET_CRYPTO_ecdsa_public_key_from_string(const char *enc, size_t enclen, struct GNUNET_CRYPTO_EcdsaPublicKey *pub)
Convert a string representing a public key to a public key.
Definition: crypto_ecc.c:468
static uint16_t port
Port number.
Definition: gnunet-bcd.c:79
configuration data
Definition: configuration.c:85
Public ECC key (always for Curve25519) encoded in a format suitable for network transmission and ECDS...
#define GNUNET_log(kind,...)
Entry in list of pending tasks.
Definition: scheduler.c:134
static struct MHD_Response * response
Our canonical response.
int 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, parse options).
Definition: program.c:361
#define FCLOSE(f)
Definition: plibc.h:645
static void server_stop(void *cls)
Stop HTTP server.
Definition: gnunet-bcd.c:389
#define DIR_SEPARATOR_STR
Definition: plibc.h:632
int GNUNET_log_setup(const char *comp, const char *loglevel, const char *logfile)
Setup logging.
static char * resfile
Absolute name of the &#39;gns-bcd.tex&#39; file.
Definition: gnunet-bcd.c:74
Entry type to be used in the map to store old latency values.
Definition: gnunet-bcd.c:82
static void run_daemon(void *cls)
Call MHD to process pending requests and then go back and schedule the next run.
Definition: gnunet-bcd.c:294
Return the directory where data is installed (share/gnunet/)
#define GNUNET_free(ptr)
Wrapper around free.
Time for relative time used by GNUnet, in microseconds.
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 gettext_noop(String)
Definition: gettext.h:69
void * GNUNET_SCHEDULER_cancel(struct GNUNET_SCHEDULER_Task *task)
Cancel the task with the specified identifier.
Definition: scheduler.c:965
#define INVALID_GNSKEY
Error page to display if submitted GNS key is invalid.
Definition: gnunet-bcd.c:34