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 \
35  "<html><head><title>Error</title><body>Invalid GNS public key given.</body></html>"
36 
40 #define NOT_FOUND \
41  "<html><head><title>Error</title><body>404 not found</body></html>"
42 
46 static struct MHD_Daemon *daemon_handle;
47 
51 static const struct GNUNET_CONFIGURATION_Handle *cfg;
52 
57 
61 static struct MHD_Response *main_response;
62 
66 static struct MHD_Response *invalid_gnskey_response;
67 
71 static struct MHD_Response *not_found_response;
72 
76 static char *resfile;
77 
81 static uint16_t port = 8888;
82 
83 
84 struct Entry {
85  const char *formname;
86  const char *texname;
87 };
88 
89 
93 static int
95  struct MHD_Connection *connection,
96  const char *url,
97  const char *method,
98  const char *version,
99  const char *upload_data,
100  size_t *upload_data_size,
101  void **con_cls)
102 {
103  static int dummy;
104  static const struct Entry map[] = { { "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  (void)cls;
124  (void)version;
125  (void)upload_data;
126  (void)upload_data_size;
127  if (0 != strcmp(method, MHD_HTTP_METHOD_GET))
128  {
130  _("Refusing `%s' request to HTTP server\n"),
131  method);
132  return MHD_NO;
133  }
134  if (NULL == *con_cls)
135  {
136  (*con_cls) = &dummy;
137  GNUNET_log(GNUNET_ERROR_TYPE_DEBUG, "Sending 100 CONTINUE reply\n");
138  return MHD_YES; /* send 100 continue */
139  }
140  if (0 == strcasecmp(url, "/"))
141  return MHD_queue_response(connection, MHD_HTTP_OK, 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 =
163  MHD_lookup_connection_value(connection, MHD_GET_ARGUMENT_KIND, "gnskey");
164  if ((NULL == gnskey) ||
165  (GNUNET_OK !=
167  strlen(gnskey),
168  &pub)))
169  {
170  return MHD_queue_response(connection,
171  MHD_HTTP_OK,
173  }
174  tmp = GNUNET_DISK_mkdtemp(gnskey);
175  if (NULL == tmp)
176  {
178  return MHD_NO;
179  }
180  GNUNET_asprintf(&deffile, "%s%s%s", tmp, DIR_SEPARATOR_STR, "def.tex");
181  f = fopen(deffile, "w");
182  if (NULL == f)
183  {
185  GNUNET_free(deffile);
187  GNUNET_free(tmp);
188  return MHD_NO;
189  }
190  for (i = 0; NULL != map[i].formname; i++)
191  {
192  const char *val = MHD_lookup_connection_value(connection,
193  MHD_GET_ARGUMENT_KIND,
194  map[i].formname);
195  if (NULL != val)
196  fprintf(f, "\\def\\%s{%s}\n", map[i].texname, val);
197  else
198  fprintf(f, "\\def\\%s{}\n", map[i].texname);
199  }
200  if (NULL != gpg_fp)
201  {
202  char *gpg1;
203  char *gpg2;
204 
205  slen = strlen(gpg_fp);
206  gpg1 = GNUNET_strndup(gpg_fp, slen / 2);
207  gpg2 = GNUNET_strdup(&gpg_fp[slen / 2]);
208  fprintf(f, "\\def\\gpglineone{%s}\n\\def\\gpglinetwo{%s}\n", gpg1, gpg2);
209  GNUNET_free(gpg2);
210  GNUNET_free(gpg1);
211  }
212  fprintf(f,
213  "\\def\\gns{%s/%s}\n",
214  gnskey,
215  (NULL == gns_nick) ? "" : gns_nick);
216  fclose(f);
218  &p,
219  "cd %s; cp %s gns-bcd.tex | pdflatex --enable-write18 gns-bcd.tex > /dev/null 2> /dev/null",
220  tmp,
221  resfile);
222  GNUNET_free(deffile);
223  ret = system(p);
224  if (WIFSIGNALED(ret) || (0 != WEXITSTATUS(ret)))
226  GNUNET_asprintf(&deffile, "%s%s%s", tmp, DIR_SEPARATOR_STR, "gns-bcd.pdf");
227  fd = open(deffile, O_RDONLY);
228  if (-1 == fd)
229  {
231  GNUNET_free(deffile);
232  GNUNET_free(p);
234  GNUNET_free(tmp);
235  return MHD_NO;
236  }
237  GNUNET_break(0 == stat(deffile, &st));
238  if (NULL ==
239  (response = MHD_create_response_from_fd((size_t)st.st_size, fd)))
240  {
241  GNUNET_break(0);
242  GNUNET_break(0 == close(fd));
243  GNUNET_free(deffile);
244  GNUNET_free(p);
246  GNUNET_free(tmp);
247  return MHD_NO;
248  }
249  (void)MHD_add_response_header(response,
250  MHD_HTTP_HEADER_CONTENT_TYPE,
251  "application/pdf");
252  ret = MHD_queue_response(connection, MHD_HTTP_OK, response);
253  MHD_destroy_response(response);
254  GNUNET_free(deffile);
255  GNUNET_free(p);
257  GNUNET_free(tmp);
258  return ret;
259  }
260  return MHD_queue_response(connection,
261  MHD_HTTP_NOT_FOUND,
263 }
264 
265 
270 static struct GNUNET_SCHEDULER_Task *
271 prepare_daemon(struct MHD_Daemon *daemon_handle);
272 
273 
278 static void
279 run_daemon(void *cls)
280 {
281  struct MHD_Daemon *daemon_handle = cls;
282 
283  http_task = NULL;
284  GNUNET_assert(MHD_YES == MHD_run(daemon_handle));
285  http_task = prepare_daemon(daemon_handle);
286 }
287 
288 
293 static struct GNUNET_SCHEDULER_Task *
294 prepare_daemon(struct MHD_Daemon *daemon_handle)
295 {
296  struct GNUNET_SCHEDULER_Task *ret;
297  fd_set rs;
298  fd_set ws;
299  fd_set es;
300  struct GNUNET_NETWORK_FDSet *wrs;
301  struct GNUNET_NETWORK_FDSet *wws;
302  int max;
303  MHD_UNSIGNED_LONG_LONG timeout;
304  int haveto;
305  struct GNUNET_TIME_Relative tv;
306 
307  FD_ZERO(&rs);
308  FD_ZERO(&ws);
309  FD_ZERO(&es);
312  max = -1;
313  GNUNET_assert(MHD_YES == MHD_get_fdset(daemon_handle, &rs, &ws, &es, &max));
314  haveto = MHD_get_timeout(daemon_handle, &timeout);
315  if (haveto == MHD_YES)
316  tv.rel_value_us = (uint64_t)timeout * 1000LL;
317  else
319  GNUNET_NETWORK_fdset_copy_native(wrs, &rs, max + 1);
320  GNUNET_NETWORK_fdset_copy_native(wws, &ws, max + 1);
322  tv,
323  wrs,
324  wws,
325  &run_daemon,
326  daemon_handle);
329  return ret;
330 }
331 
332 
338 static int
340 {
341  if (0 == port)
342  {
344  _("Invalid port number %u. Exiting.\n"),
345  port);
346  return GNUNET_SYSERR;
347  }
349  _("Businesscard HTTP server starts on %u\n"),
350  port);
351  daemon_handle = MHD_start_daemon(MHD_USE_DUAL_STACK | MHD_USE_DEBUG,
352  port,
353  NULL /* accept_policy_callback */,
354  NULL,
356  NULL,
357  MHD_OPTION_CONNECTION_LIMIT,
358  (unsigned int)512,
359  MHD_OPTION_PER_IP_CONNECTION_LIMIT,
360  (unsigned int)2,
361  MHD_OPTION_CONNECTION_TIMEOUT,
362  (unsigned int)60,
363  MHD_OPTION_CONNECTION_MEMORY_LIMIT,
364  (size_t)(16 * 1024),
365  MHD_OPTION_END);
366  if (NULL == daemon_handle)
367  {
369  _("Could not start businesscard HTTP server on port %u\n"),
370  (unsigned int)port);
371  return GNUNET_SYSERR;
372  }
373  http_task = prepare_daemon(daemon_handle);
374  return GNUNET_OK;
375 }
376 
377 
381 static void
382 server_stop(void *cls)
383 {
384  (void)cls;
385  GNUNET_log(GNUNET_ERROR_TYPE_DEBUG, "HTTP server shutdown\n");
386  if (NULL != http_task)
387  {
388  GNUNET_SCHEDULER_cancel(http_task);
389  http_task = NULL;
390  }
391  if (NULL != daemon_handle)
392  {
393  MHD_stop_daemon(daemon_handle);
394  daemon_handle = NULL;
395  }
396  if (NULL != main_response)
397  {
398  MHD_destroy_response(main_response);
399  main_response = NULL;
400  }
401  if (NULL != invalid_gnskey_response)
402  {
403  MHD_destroy_response(invalid_gnskey_response);
405  }
406  if (NULL != not_found_response)
407  {
408  MHD_destroy_response(not_found_response);
409  not_found_response = NULL;
410  }
411  if (NULL != resfile)
412  {
414  resfile = NULL;
415  }
416 }
417 
418 
427 static void
428 run(void *cls,
429  char *const *args,
430  const char *cfgfile,
431  const struct GNUNET_CONFIGURATION_Handle *c)
432 {
433  struct stat st;
434  char *dir;
435  char *fn;
436  int fd;
437 
438  (void)cls;
439  (void)args;
440  (void)cfgfile;
441  cfg = c;
443  GNUNET_assert(NULL != dir);
444  GNUNET_asprintf(&fn, "%s%s%s", dir, DIR_SEPARATOR_STR, "gns-bcd.html");
445  GNUNET_asprintf(&resfile, "%s%s%s", dir, DIR_SEPARATOR_STR, "gns-bcd.tex");
446  GNUNET_free(dir);
447  fd = open(fn, O_RDONLY);
448  if (-1 == fd)
449  {
451  GNUNET_free(fn);
452  return;
453  }
454  if (0 != stat(fn, &st))
455  {
457  GNUNET_free(fn);
458  GNUNET_break(0 == close(fd));
459  return;
460  }
461  GNUNET_free(fn);
462  if (NULL ==
463  (main_response = MHD_create_response_from_fd((size_t)st.st_size, fd)))
464  {
465  GNUNET_break(0);
466  GNUNET_break(0 == close(fd));
467  return;
468  }
469  (void)MHD_add_response_header(main_response,
470  MHD_HTTP_HEADER_CONTENT_TYPE,
471  "text/html");
473  MHD_create_response_from_buffer(strlen(INVALID_GNSKEY),
475  MHD_RESPMEM_PERSISTENT);
476  (void)MHD_add_response_header(invalid_gnskey_response,
477  MHD_HTTP_HEADER_CONTENT_TYPE,
478  "text/html");
479  not_found_response = MHD_create_response_from_buffer(strlen(NOT_FOUND),
480  NOT_FOUND,
481  MHD_RESPMEM_PERSISTENT);
482  (void)MHD_add_response_header(not_found_response,
483  MHD_HTTP_HEADER_CONTENT_TYPE,
484  "text/html");
485  if (GNUNET_OK != server_start())
486  return;
488 }
489 
490 
498 int
499 main(int argc, char *const *argv)
500 {
501  struct GNUNET_GETOPT_CommandLineOption options[] = {
503  "port",
504  "PORT",
505  gettext_noop(
506  "Run HTTP serve on port PORT (default is 8888)"),
507  &port),
509  };
510  int ret;
511 
512  if (GNUNET_OK != GNUNET_STRINGS_get_utf8_args(argc, argv, &argc, &argv))
513  return 2;
514  GNUNET_log_setup("gnunet-bcd", "WARNING", NULL);
515  ret = (GNUNET_OK ==
516  GNUNET_PROGRAM_run(argc,
517  argv,
518  "gnunet-bcd",
519  _("GNUnet HTTP server to create business cards"),
520  options,
521  &run,
522  NULL))
523  ? 0
524  : 1;
525  GNUNET_free((void *)argv);
526  return ret;
527 }
528 
529 
530 /* end of gnunet-bcd.c */
static const struct GNUNET_CONFIGURATION_Handle * cfg
Our configuration.
Definition: gnunet-bcd.c:51
static struct MHD_Daemon * daemon_handle
Handle to the HTTP server as provided by libmicrohttpd.
Definition: gnunet-bcd.c:46
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:66
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:499
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:428
#define NOT_FOUND
Error page to display on 404.
Definition: gnunet-bcd.c:40
static struct MHD_Response * not_found_response
Error: 404.
Definition: gnunet-bcd.c:71
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:1284
int GNUNET_STRINGS_get_utf8_args(int argc, char *const *argv, int *u8argc, char *const **u8argv)
Returns utf-8 encoded arguments.
Definition: strings.c:1439
#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:56
static int server_start()
Start server offering our hostlist.
Definition: gnunet-bcd.c:339
#define GNUNET_OK
Named constants for return values.
Definition: gnunet_common.h:75
Definition of a command line option.
const char * texname
Definition: gnunet-bcd.c:86
static int ret
Final status code.
Definition: gnunet-arm.c:89
#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:1108
#define _(String)
GNU gettext support macro.
Definition: platform.h:181
void GNUNET_NETWORK_fdset_destroy(struct GNUNET_NETWORK_FDSet *fds)
Releases the associated memory of an fd set.
Definition: network.c:1254
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:1238
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.
#define DIR_SEPARATOR_STR
Definition: platform.h:168
int GNUNET_DISK_directory_remove(const char *filename)
Remove all files in a directory (rm -rf).
Definition: disk.c:1026
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:1784
#define GNUNET_TIME_UNIT_FOREVER_REL
Constant used to specify "forever".
#define GNUNET_SYSERR
Definition: gnunet_common.h:76
char * GNUNET_DISK_mkdtemp(const char *t)
Create an (empty) temporary directory on disk.
Definition: disk.c:406
const char * formname
Definition: gnunet-bcd.c:85
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:94
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:294
static struct MHD_Response * main_response
Our main website.
Definition: gnunet-bcd.c:61
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:468
static uint16_t port
Port number.
Definition: gnunet-bcd.c:81
configuration data
Definition: configuration.c:83
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:131
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:382
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:76
Entry type to be used in the map to store old latency values.
Definition: gnunet-bcd.c:84
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:279
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:956
#define INVALID_GNSKEY
Error page to display if submitted GNS key is invalid.
Definition: gnunet-bcd.c:34