aboutsummaryrefslogtreecommitdiff
path: root/src/gns/gnunet-bcd.c
diff options
context:
space:
mode:
authorChristian Grothoff <christian@grothoff.org>2013-12-05 15:00:53 +0000
committerChristian Grothoff <christian@grothoff.org>2013-12-05 15:00:53 +0000
commit0fb52b8b619ada9923fcb9062b4e7a45008bcbc6 (patch)
tree0a32babdc3ac84d32f761f6432ae85cf87931506 /src/gns/gnunet-bcd.c
parentc529e5bbc5387c936c8ed55268b16a900795e6df (diff)
downloadgnunet-0fb52b8b619ada9923fcb9062b4e7a45008bcbc6.tar.gz
gnunet-0fb52b8b619ada9923fcb9062b4e7a45008bcbc6.zip
creating gnunet-bcd
Diffstat (limited to 'src/gns/gnunet-bcd.c')
-rw-r--r--src/gns/gnunet-bcd.c534
1 files changed, 534 insertions, 0 deletions
diff --git a/src/gns/gnunet-bcd.c b/src/gns/gnunet-bcd.c
new file mode 100644
index 000000000..05eaecff4
--- /dev/null
+++ b/src/gns/gnunet-bcd.c
@@ -0,0 +1,534 @@
1/*
2 This file is part of GNUnet.
3 (C) 2013 Christian Grothoff (and other contributing authors)
4
5 GNUnet is free software; you can redistribute it and/or modify
6 it under the terms of the GNU General Public License as published
7 by the Free Software Foundation; either version 3, or (at your
8 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 General Public License for more details.
14
15 You should have received a copy of the GNU General Public License
16 along with GNUnet; see the file COPYING. If not, write to the
17 Free Software Foundation, Inc., 59 Temple Place - Suite 330,
18 Boston, MA 02111-1307, USA.
19*/
20
21/**
22 * @file gns/gnunet-bcd.c
23 * @author Christian Grothoff
24 * @brief HTTP server to create GNS business cards
25 */
26
27#include "platform.h"
28#include <microhttpd.h>
29#include "gnunet_util_lib.h"
30
31/**
32 * Error page to display if submitted GNS key is invalid.
33 */
34#define INVALID_GNSKEY "<html><head><title>Error</title><body>Invalid GNS public key given.</body></html>"
35
36/**
37 * Error page to display on 404.
38 */
39#define NOT_FOUND "<html><head><title>Error</title><body>404 not found</body></html>"
40
41/**
42 * Handle to the HTTP server as provided by libmicrohttpd
43 */
44static struct MHD_Daemon *daemon_handle;
45
46/**
47 * Our configuration.
48 */
49static const struct GNUNET_CONFIGURATION_Handle *cfg;
50
51/**
52 * Our primary task for the HTTPD.
53 */
54static GNUNET_SCHEDULER_TaskIdentifier http_task;
55
56/**
57 * Our main website.
58 */
59static struct MHD_Response *main_response;
60
61/**
62 * Error: invalid gns key.
63 */
64static struct MHD_Response *invalid_gnskey_response;
65
66/**
67 * Error: 404
68 */
69static struct MHD_Response *not_found_response;
70
71/**
72 * Absolute name of the 'gns-bcd.tex' file.
73 */
74static char *resfile;
75
76/**
77 * Port number.
78 */
79static unsigned int port = 8888;
80
81
82struct Entry
83{
84 const char *formname;
85 const char *texname;
86};
87
88
89/**
90 * Main request handler.
91 */
92static int
93access_handler_callback (void *cls, struct MHD_Connection *connection,
94 const char *url, const char *method,
95 const char *version, const char *upload_data,
96 size_t * upload_data_size, void **con_cls)
97{
98 static int dummy;
99 static const struct Entry map[] = {
100 { "prefix", "prefix" },
101 { "name", "name" },
102 { "suffix", "suffix" },
103 { "street", "street" },
104 { "city", "city" },
105 { "phone", "phone" },
106 { "fax", "fax" },
107 { "email", "email"},
108 { "homepage", "homepage" },
109 { "orga", "orga"},
110 { "departmenti18n", "departmentde"},
111 { "departmenten", "departmenten"},
112 { "subdepartmenti18n", "subdepartmentde"},
113 { "subdepartmenten", "subdepartmenten"},
114 { "jobtitlei18n", "jobtitlegerman"},
115 { "jobtitleen", "jobtitleenglish"},
116 { "subdepartmenten", "subdepartmenten"},
117 { NULL, NULL }
118 };
119
120 if (0 != strcmp (method, MHD_HTTP_METHOD_GET))
121 {
122 GNUNET_log (GNUNET_ERROR_TYPE_WARNING,
123 _("Refusing `%s' request to HTTP server\n"),
124 method);
125 return MHD_NO;
126 }
127 if (NULL == *con_cls)
128 {
129 (*con_cls) = &dummy;
130 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
131 "Sending 100 CONTINUE reply\n");
132 return MHD_YES; /* send 100 continue */
133 }
134 if (0 == strcasecmp (url, "/"))
135 return MHD_queue_response (connection,
136 MHD_HTTP_OK,
137 main_response);
138 if (0 == strcasecmp (url, "/submit.pdf"))
139 {
140 unsigned int i;
141 char *p;
142 char *tmp;
143 char *deffile;
144 struct GNUNET_CRYPTO_EcdsaPublicKey pub;
145 size_t slen;
146 FILE *f;
147 struct stat st;
148 struct MHD_Response *response;
149 int fd;
150 int ret;
151
152 const char *gpg_fp = MHD_lookup_connection_value (connection,
153 MHD_GET_ARGUMENT_KIND,
154 "gpgfingerprint");
155 const char *gns_nick = MHD_lookup_connection_value (connection,
156 MHD_GET_ARGUMENT_KIND,
157 "gnsnick");
158 const char *gnskey = MHD_lookup_connection_value (connection,
159 MHD_GET_ARGUMENT_KIND,
160 "gnskey");
161 if ( (NULL == gnskey) ||
162 (GNUNET_OK !=
163 GNUNET_CRYPTO_ecdsa_public_key_from_string (gnskey,
164 strlen (gnskey),
165 &pub)))
166 {
167 return MHD_queue_response (connection,
168 MHD_HTTP_OK,
169 invalid_gnskey_response);
170 }
171 tmp = GNUNET_DISK_mkdtemp (gnskey);
172 if (NULL == tmp)
173 {
174 GNUNET_log_strerror_file (GNUNET_ERROR_TYPE_ERROR, "mktemp", gnskey);
175 return MHD_NO;
176 }
177 GNUNET_asprintf (&deffile,
178 "%s%s%s",
179 tmp, DIR_SEPARATOR_STR, "def.tex");
180 f = FOPEN (deffile, "w");
181 if (NULL == f)
182 {
183 GNUNET_log_strerror_file (GNUNET_ERROR_TYPE_ERROR, "open", deffile);
184 GNUNET_free (deffile);
185 GNUNET_DISK_directory_remove (tmp);
186 GNUNET_free (tmp);
187 return MHD_NO;
188 }
189 for (i=0; NULL != map[i].formname; i++)
190 {
191 const char *val = MHD_lookup_connection_value (connection,
192 MHD_GET_ARGUMENT_KIND,
193 map[i].formname);
194 if (NULL != val)
195 FPRINTF (f,
196 "\\def\\%s{%s}\n",
197 map[i].texname, val);
198 else
199 FPRINTF (f,
200 "\\def\\%s{}\n",
201 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,
212 "\\def\\gpglineone{%s}\n\\def\\gpglinetwo{%s}\n",
213 gpg1, gpg2);
214 GNUNET_free (gpg2);
215 GNUNET_free (gpg1);
216 }
217 FPRINTF (f,
218 "\\def\\gns{gnunet://gns/%s/%s}\n",
219 gnskey,
220 (NULL == gns_nick) ? "" : gns_nick);
221 FCLOSE (f);
222 GNUNET_asprintf (&p,
223 "cd %s; cp %s gns-bcd.tex | pdflatex --enable-write18 gns-bcd.tex > /dev/null 2> /dev/null",
224 tmp,
225 resfile);
226 GNUNET_free (deffile);
227 ret = system (p);
228 if (WIFSIGNALED (ret) || (0 != WEXITSTATUS(ret)))
229 GNUNET_log_strerror_file (GNUNET_ERROR_TYPE_ERROR,
230 "system",
231 p);
232 GNUNET_asprintf (&deffile,
233 "%s%s%s",
234 tmp, DIR_SEPARATOR_STR, "gns-bcd.pdf");
235 fd = OPEN (deffile, O_RDONLY);
236 if (-1 == fd)
237 {
238 GNUNET_log_strerror_file (GNUNET_ERROR_TYPE_ERROR,
239 "open",
240 deffile);
241 GNUNET_free (deffile);
242 GNUNET_free (p);
243 GNUNET_DISK_directory_remove (tmp);
244 GNUNET_free (tmp);
245 return MHD_NO;
246 }
247 GNUNET_break (0 == STAT (deffile, &st));
248 if (NULL == (response = MHD_create_response_from_fd ((size_t) st.st_size, fd)))
249 {
250 GNUNET_break (0);
251 GNUNET_break (0 == CLOSE (fd));
252 return MHD_NO;
253 }
254 (void) MHD_add_response_header (response,
255 MHD_HTTP_HEADER_CONTENT_TYPE,
256 "application/pdf");
257 ret = MHD_queue_response (connection,
258 MHD_HTTP_OK,
259 response);
260 MHD_destroy_response (response);
261 GNUNET_free (p);
262 GNUNET_DISK_directory_remove (tmp);
263 GNUNET_free (tmp);
264 return ret;
265 }
266 return MHD_queue_response (connection,
267 MHD_HTTP_NOT_FOUND,
268 not_found_response);
269}
270
271
272/**
273 * Function that queries MHD's select sets and
274 * starts the task waiting for them.
275 */
276static GNUNET_SCHEDULER_TaskIdentifier
277prepare_daemon (struct MHD_Daemon *daemon_handle);
278
279
280/**
281 * Call MHD to process pending requests and then go back
282 * and schedule the next run.
283 */
284static void
285run_daemon (void *cls, const struct GNUNET_SCHEDULER_TaskContext *tc)
286{
287 struct MHD_Daemon *daemon_handle = cls;
288
289 http_task = GNUNET_SCHEDULER_NO_TASK;
290 if (0 != (tc->reason & GNUNET_SCHEDULER_REASON_SHUTDOWN))
291 return;
292 GNUNET_assert (MHD_YES == MHD_run (daemon_handle));
293 http_task = prepare_daemon (daemon_handle);
294}
295
296
297/**
298 * Function that queries MHD's select sets and
299 * starts the task waiting for them.
300 */
301static GNUNET_SCHEDULER_TaskIdentifier
302prepare_daemon (struct MHD_Daemon *daemon_handle)
303{
304 GNUNET_SCHEDULER_TaskIdentifier ret;
305 fd_set rs;
306 fd_set ws;
307 fd_set es;
308 struct GNUNET_NETWORK_FDSet *wrs;
309 struct GNUNET_NETWORK_FDSet *wws;
310 int max;
311 MHD_UNSIGNED_LONG_LONG timeout;
312 int haveto;
313 struct GNUNET_TIME_Relative tv;
314
315 FD_ZERO (&rs);
316 FD_ZERO (&ws);
317 FD_ZERO (&es);
318 wrs = GNUNET_NETWORK_fdset_create ();
319 wws = GNUNET_NETWORK_fdset_create ();
320 max = -1;
321 GNUNET_assert (MHD_YES == MHD_get_fdset (daemon_handle, &rs, &ws, &es, &max));
322 haveto = MHD_get_timeout (daemon_handle, &timeout);
323 if (haveto == MHD_YES)
324 tv.rel_value_us = (uint64_t) timeout;
325 else
326 tv = GNUNET_TIME_UNIT_FOREVER_REL;
327 GNUNET_NETWORK_fdset_copy_native (wrs, &rs, max + 1);
328 GNUNET_NETWORK_fdset_copy_native (wws, &ws, max + 1);
329 ret =
330 GNUNET_SCHEDULER_add_select (GNUNET_SCHEDULER_PRIORITY_HIGH,
331 tv, wrs, wws,
332 &run_daemon, daemon_handle);
333 GNUNET_NETWORK_fdset_destroy (wrs);
334 GNUNET_NETWORK_fdset_destroy (wws);
335 return ret;
336}
337
338
339/**
340 * Start server offering our hostlist.
341 *
342 * @return #GNUNET_OK on success
343 */
344static int
345server_start ()
346{
347 if ((0 == port) || (port > UINT16_MAX))
348 {
349 GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
350 _("Invalid port number %llu. Exiting.\n"),
351 port);
352 return GNUNET_SYSERR;
353 }
354 GNUNET_log (GNUNET_ERROR_TYPE_INFO,
355 _("Businesscard HTTP server starts on %llu\n"),
356 port);
357 daemon_handle = MHD_start_daemon (MHD_USE_DUAL_STACK | MHD_USE_DEBUG,
358 (uint16_t) port,
359 NULL /* accept_policy_callback */, NULL,
360 &access_handler_callback, NULL,
361 MHD_OPTION_CONNECTION_LIMIT, (unsigned int) 512,
362 MHD_OPTION_PER_IP_CONNECTION_LIMIT, (unsigned int) 2,
363 MHD_OPTION_CONNECTION_TIMEOUT, (unsigned int) 16,
364 MHD_OPTION_CONNECTION_MEMORY_LIMIT, (size_t) (16 * 1024),
365 MHD_OPTION_END);
366 if (NULL == daemon_handle)
367 {
368 GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
369 _("Could not start businesscard HTTP server on port %u\n"),
370 (unsigned short) port);
371 return GNUNET_SYSERR;
372 }
373 http_task = prepare_daemon (daemon_handle);
374 return GNUNET_OK;
375}
376
377
378/**
379 * Stop HTTP server.
380 */
381static void
382server_stop (void *cls,
383 const struct GNUNET_SCHEDULER_TaskContext *tc)
384{
385 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
386 "HTTP server shutdown\n");
387 if (GNUNET_SCHEDULER_NO_TASK != http_task)
388 {
389 GNUNET_SCHEDULER_cancel (http_task);
390 http_task = GNUNET_SCHEDULER_NO_TASK;
391 }
392 if (NULL != daemon_handle)
393 {
394 MHD_stop_daemon (daemon_handle);
395 daemon_handle = NULL;
396 }
397 if (NULL != main_response)
398 {
399 MHD_destroy_response (main_response);
400 main_response = NULL;
401 }
402 if (NULL != invalid_gnskey_response)
403 {
404 MHD_destroy_response (invalid_gnskey_response);
405 invalid_gnskey_response = NULL;
406 }
407 if (NULL != not_found_response)
408 {
409 MHD_destroy_response (not_found_response);
410 not_found_response = NULL;
411 }
412 if (NULL != resfile)
413 {
414 GNUNET_free (resfile);
415 resfile = NULL;
416 }
417}
418
419
420/**
421 * Main function that will be run.
422 *
423 * @param cls closure
424 * @param args remaining command-line arguments
425 * @param cfgfile name of the configuration file used (for saving, can be NULL!)
426 * @param c configuration
427 */
428static void
429run (void *cls,
430 char *const *args,
431 const char *cfgfile,
432 const struct GNUNET_CONFIGURATION_Handle *c)
433{
434 struct stat st;
435 char *dir;
436 char *fn;
437 int fd;
438
439 cfg = c;
440 dir = GNUNET_OS_installation_get_path (GNUNET_OS_IPK_DATADIR);
441 GNUNET_assert (NULL != dir);
442 GNUNET_asprintf (&fn,
443 "%s%s%s",
444 dir,
445 DIR_SEPARATOR_STR,
446 "gns-bcd.html");
447 GNUNET_asprintf (&resfile,
448 "%s%s%s",
449 dir,
450 DIR_SEPARATOR_STR,
451 "gns-bcd.tex");
452 GNUNET_free (dir);
453 fd = OPEN (fn, O_RDONLY);
454 if (-1 == fd)
455 {
456 GNUNET_log_strerror_file (GNUNET_ERROR_TYPE_ERROR,
457 "open",
458 fn);
459 GNUNET_free (fn);
460 return;
461 }
462 if (0 != STAT (fn, &st))
463 {
464 GNUNET_log_strerror_file (GNUNET_ERROR_TYPE_ERROR,
465 "open",
466 fn);
467 GNUNET_free (fn);
468 CLOSE (fd);
469 return;
470 }
471 GNUNET_free (fn);
472 if (NULL == (main_response = MHD_create_response_from_fd ((size_t) st.st_size, fd)))
473 {
474 GNUNET_break (0);
475 GNUNET_break (0 == CLOSE (fd));
476 return;
477 }
478 (void) MHD_add_response_header (main_response,
479 MHD_HTTP_HEADER_CONTENT_TYPE,
480 "text/html");
481 invalid_gnskey_response = MHD_create_response_from_buffer (strlen (INVALID_GNSKEY),
482 INVALID_GNSKEY,
483 MHD_RESPMEM_PERSISTENT);
484 (void) MHD_add_response_header (invalid_gnskey_response,
485 MHD_HTTP_HEADER_CONTENT_TYPE,
486 "text/html");
487 not_found_response = MHD_create_response_from_buffer (strlen (NOT_FOUND),
488 NOT_FOUND,
489 MHD_RESPMEM_PERSISTENT);
490 (void) MHD_add_response_header (not_found_response,
491 MHD_HTTP_HEADER_CONTENT_TYPE,
492 "text/html");
493 if (GNUNET_OK !=
494 server_start ())
495 return;
496 GNUNET_SCHEDULER_add_delayed (GNUNET_TIME_UNIT_FOREVER_REL,
497 &server_stop,
498 NULL);
499}
500
501
502/**
503 * The main function for gnunet-gns.
504 *
505 * @param argc number of arguments from the command line
506 * @param argv command line arguments
507 * @return 0 ok, 1 on error
508 */
509int
510main (int argc, char *const *argv)
511{
512 static const struct GNUNET_GETOPT_CommandLineOption options[] = {
513 {'p', "port", "PORT",
514 gettext_noop ("Run HTTP serve on port PORT (default is 8888)"), 1,
515 &GNUNET_GETOPT_set_uint, &port},
516 GNUNET_GETOPT_OPTION_END
517 };
518 int ret;
519
520 if (GNUNET_OK != GNUNET_STRINGS_get_utf8_args (argc, argv, &argc, &argv))
521 return 2;
522 GNUNET_log_setup ("gnunet-bcd", "WARNING", NULL);
523 ret =
524 (GNUNET_OK ==
525 GNUNET_PROGRAM_run (argc, argv, "gnunet-bcd",
526 _("GNUnet HTTP server to create business cards"),
527 options,
528 &run, NULL)) ? 0 : 1;
529 GNUNET_free ((void*) argv);
530 return ret;
531}
532
533
534/* end of gnunet-bcd.c */