GNUnet  0.11.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 #include "gnunet_mhd_compat.h"
31 
35 #define INVALID_GNSKEY \
36  "<html><head><title>Error</title><body>Invalid GNS public key given.</body></html>"
37 
41 #define NOT_FOUND \
42  "<html><head><title>Error</title><body>404 not found</body></html>"
43 
47 static struct MHD_Daemon *daemon_handle;
48 
52 static const struct GNUNET_CONFIGURATION_Handle *cfg;
53 
58 
62 static struct MHD_Response *main_response;
63 
67 static struct MHD_Response *invalid_gnskey_response;
68 
72 static struct MHD_Response *not_found_response;
73 
77 static char *resfile;
78 
82 static uint16_t port = 8888;
83 
84 
85 struct Entry
86 {
87  const char *formname;
88  const char *texname;
89 };
90 
91 
95 static MHD_RESULT
97  struct MHD_Connection *connection,
98  const char *url,
99  const char *method,
100  const char *version,
101  const char *upload_data,
102  size_t *upload_data_size,
103  void **con_cls)
104 {
105  static int dummy;
106  static const struct Entry map[] = { { "prefix", "prefix" },
107  { "name", "name" },
108  { "suffix", "suffix" },
109  { "street", "street" },
110  { "city", "city" },
111  { "phone", "phone" },
112  { "fax", "fax" },
113  { "email", "email" },
114  { "homepage", "homepage" },
115  { "orga", "orga" },
116  { "departmenti18n", "departmentde" },
117  { "departmenten", "departmenten" },
118  { "subdepartmenti18n",
119  "subdepartmentde" },
120  { "subdepartmenten", "subdepartmenten" },
121  { "jobtitlei18n", "jobtitlegerman" },
122  { "jobtitleen", "jobtitleenglish" },
123  { "subdepartmenten", "subdepartmenten" },
124  { NULL, NULL } };
125 
126  (void) cls;
127  (void) version;
128  (void) upload_data;
129  (void) upload_data_size;
130  if (0 != strcmp (method, MHD_HTTP_METHOD_GET))
131  {
133  _ ("Refusing `%s' request to HTTP server\n"),
134  method);
135  return MHD_NO;
136  }
137  if (NULL == *con_cls)
138  {
139  (*con_cls) = &dummy;
140  GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "Sending 100 CONTINUE reply\n");
141  return MHD_YES; /* send 100 continue */
142  }
143  if (0 == strcasecmp (url, "/"))
144  return MHD_queue_response (connection, MHD_HTTP_OK, main_response);
145  if (0 == strcasecmp (url, "/submit.pdf"))
146  {
147  unsigned int i;
148  char *p;
149  char *tmp;
150  char *deffile;
151  struct GNUNET_CRYPTO_EcdsaPublicKey pub;
152  size_t slen;
153  FILE *f;
154  struct stat st;
155  struct MHD_Response *response;
156  int fd;
157  MHD_RESULT ret;
158 
159  const char *gpg_fp = MHD_lookup_connection_value (connection,
160  MHD_GET_ARGUMENT_KIND,
161  "gpgfingerprint");
162  const char *gns_nick = MHD_lookup_connection_value (connection,
163  MHD_GET_ARGUMENT_KIND,
164  "gnsnick");
165  const char *gnskey =
166  MHD_lookup_connection_value (connection, MHD_GET_ARGUMENT_KIND, "gnskey");
167  if ((NULL == gnskey) ||
168  (GNUNET_OK !=
170  strlen (gnskey),
171  &pub)))
172  {
173  return MHD_queue_response (connection,
174  MHD_HTTP_OK,
176  }
177  tmp = GNUNET_DISK_mkdtemp (gnskey);
178  if (NULL == tmp)
179  {
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  {
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, "\\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);
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)))
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  {
234  GNUNET_free (deffile);
235  GNUNET_free (p);
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);
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);
260  GNUNET_free (tmp);
261  return ret;
262  }
263  return MHD_queue_response (connection,
264  MHD_HTTP_NOT_FOUND,
266 }
267 
268 
273 static struct GNUNET_SCHEDULER_Task *
274 prepare_daemon (struct MHD_Daemon *daemon_handle);
275 
276 
281 static void
282 run_daemon (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 
296 static struct GNUNET_SCHEDULER_Task *
297 prepare_daemon (struct MHD_Daemon *daemon_handle)
298 {
299  struct GNUNET_SCHEDULER_Task *ret;
300  fd_set rs;
301  fd_set ws;
302  fd_set es;
303  struct GNUNET_NETWORK_FDSet *wrs;
304  struct GNUNET_NETWORK_FDSet *wws;
305  int max;
306  MHD_UNSIGNED_LONG_LONG timeout;
307  int haveto;
308  struct GNUNET_TIME_Relative tv;
309 
310  FD_ZERO (&rs);
311  FD_ZERO (&ws);
312  FD_ZERO (&es);
315  max = -1;
316  GNUNET_assert (MHD_YES == MHD_get_fdset (daemon_handle, &rs, &ws, &es, &max));
317  haveto = MHD_get_timeout (daemon_handle, &timeout);
318  if (haveto == MHD_YES)
319  tv.rel_value_us = (uint64_t) timeout * 1000LL;
320  else
322  GNUNET_NETWORK_fdset_copy_native (wrs, &rs, max + 1);
323  GNUNET_NETWORK_fdset_copy_native (wws, &ws, max + 1);
325  tv,
326  wrs,
327  wws,
328  &run_daemon,
329  daemon_handle);
332  return ret;
333 }
334 
335 
341 static int
343 {
344  if (0 == port)
345  {
347  _ ("Invalid port number %u. Exiting.\n"),
348  port);
349  return GNUNET_SYSERR;
350  }
352  _ ("Businesscard HTTP server starts on %u\n"),
353  port);
354  daemon_handle = MHD_start_daemon (MHD_USE_DUAL_STACK | MHD_USE_DEBUG,
355  port,
356  NULL /* accept_policy_callback */,
357  NULL,
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  {
372  _ ("Could not start businesscard HTTP server on port %u\n"),
373  (unsigned int) port);
374  return GNUNET_SYSERR;
375  }
376  http_task = prepare_daemon (daemon_handle);
377  return GNUNET_OK;
378 }
379 
380 
384 static void
385 server_stop (void *cls)
386 {
387  (void) cls;
388  GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "HTTP server shutdown\n");
389  if (NULL != http_task)
390  {
391  GNUNET_SCHEDULER_cancel (http_task);
392  http_task = NULL;
393  }
394  if (NULL != daemon_handle)
395  {
396  MHD_stop_daemon (daemon_handle);
397  daemon_handle = NULL;
398  }
399  if (NULL != main_response)
400  {
401  MHD_destroy_response (main_response);
402  main_response = NULL;
403  }
404  if (NULL != invalid_gnskey_response)
405  {
406  MHD_destroy_response (invalid_gnskey_response);
408  }
409  if (NULL != not_found_response)
410  {
411  MHD_destroy_response (not_found_response);
412  not_found_response = NULL;
413  }
414  if (NULL != resfile)
415  {
417  resfile = NULL;
418  }
419 }
420 
421 
430 static void
431 run (void *cls,
432  char *const *args,
433  const char *cfgfile,
434  const struct GNUNET_CONFIGURATION_Handle *c)
435 {
436  struct stat st;
437  char *dir;
438  char *fn;
439  int fd;
440 
441  (void) cls;
442  (void) args;
443  (void) cfgfile;
444  cfg = c;
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  {
454  GNUNET_free (fn);
455  return;
456  }
457  if (0 != stat (fn, &st))
458  {
460  GNUNET_free (fn);
461  GNUNET_break (0 == close (fd));
462  return;
463  }
464  GNUNET_free (fn);
465  if (NULL ==
466  (main_response = MHD_create_response_from_fd ((size_t) st.st_size, fd)))
467  {
468  GNUNET_break (0);
469  GNUNET_break (0 == close (fd));
470  return;
471  }
472  (void) MHD_add_response_header (main_response,
473  MHD_HTTP_HEADER_CONTENT_TYPE,
474  "text/html");
476  MHD_create_response_from_buffer (strlen (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;
491 }
492 
493 
501 int
502 main (int argc, char *const *argv)
503 {
504  struct GNUNET_GETOPT_CommandLineOption options[] = {
506  "port",
507  "PORT",
508  gettext_noop (
509  "Run HTTP serve on port PORT (default is 8888)"),
510  &port),
512  };
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 
532 
533 /* end of gnunet-bcd.c */
static const struct GNUNET_CONFIGURATION_Handle * cfg
Our configuration.
Definition: gnunet-bcd.c:52
static struct MHD_Daemon * daemon_handle
Handle to the HTTP server as provided by libmicrohttpd.
Definition: gnunet-bcd.c:47
static char * dir
Set to the directory where runtime files are stored.
Definition: gnunet-arm.c:89
static struct MHD_Response * invalid_gnskey_response
Error: invalid gns key.
Definition: gnunet-bcd.c:67
Run with high priority (important requests).
uint64_t rel_value_us
The actual value.
int main(int argc, char *const *argv)
The main function for gnunet-gns.
Definition: gnunet-bcd.c:502
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:431
#define NOT_FOUND
Error page to display on 404.
Definition: gnunet-bcd.c:41
static struct MHD_Response * not_found_response
Error: 404.
Definition: gnunet-bcd.c:72
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:1331
int GNUNET_STRINGS_get_utf8_args(int argc, char *const *argv, int *u8argc, char *const **u8argv)
Returns utf-8 encoded arguments.
Definition: strings.c:1458
#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:57
static int ret
Return value of the commandline.
Definition: gnunet-abd.c:81
static int server_start()
Start server offering our hostlist.
Definition: gnunet-bcd.c:342
Definition of a command line option.
const char * texname
Definition: gnunet-bcd.c:88
#define GNUNET_strdup(a)
Wrapper around GNUNET_xstrdup_.
#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:1120
#define _(String)
GNU gettext support macro.
Definition: platform.h:184
void GNUNET_NETWORK_fdset_destroy(struct GNUNET_NETWORK_FDSet *fds)
Releases the associated memory of an fd set.
Definition: network.c:1266
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:1250
static struct GNUNET_TIME_Relative timeout
Desired timeout for the lookup (default is no timeout).
Definition: gnunet-abd.c:61
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.
#define DIR_SEPARATOR_STR
Definition: platform.h:171
int GNUNET_DISK_directory_remove(const char *filename)
Remove all files in a directory (rm -rf).
Definition: disk.c:1028
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
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:1841
static MHD_RESULT 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:96
#define GNUNET_TIME_UNIT_FOREVER_REL
Constant used to specify "forever".
#define GNUNET_free_nz(ptr)
Wrapper around free.
char * GNUNET_DISK_mkdtemp(const char *t)
Create an (empty) temporary directory on disk.
Definition: disk.c:409
const char * formname
Definition: gnunet-bcd.c:87
#define MHD_RESULT
Data type to use for functions return an "MHD result".
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:297
static struct MHD_Response * main_response
Our main website.
Definition: gnunet-bcd.c:62
static struct in_addr dummy
Target "dummy" address of the packet we pretend to respond to.
#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:366
static uint16_t port
Port number.
Definition: gnunet-bcd.c:82
configuration data
Definition: configuration.c:84
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:367
static void server_stop(void *cls)
Stop HTTP server.
Definition: gnunet-bcd.c:385
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:77
Entry type to be used in the map to store old latency values.
Definition: gnunet-bcd.c:85
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:282
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:972
#define INVALID_GNSKEY
Error page to display if submitted GNS key is invalid.
Definition: gnunet-bcd.c:35