aboutsummaryrefslogtreecommitdiff
path: root/src/namestore/gnunet-namestore-fcfsd.c
diff options
context:
space:
mode:
authorChristian Grothoff <christian@grothoff.org>2013-08-13 22:00:45 +0000
committerChristian Grothoff <christian@grothoff.org>2013-08-13 22:00:45 +0000
commit78f323a26ba33c640162741d4f44b6996239b0e8 (patch)
tree54f1f6cd78ce5232dbf2fa363cbbbf4f224058fc /src/namestore/gnunet-namestore-fcfsd.c
parent59b84fb41a89b6237001e30d75e878d694de957d (diff)
downloadgnunet-78f323a26ba33c640162741d4f44b6996239b0e8.tar.gz
gnunet-78f323a26ba33c640162741d4f44b6996239b0e8.zip
-adapting fcfsd to new namestore API, moving from gns to namestore subsystem
Diffstat (limited to 'src/namestore/gnunet-namestore-fcfsd.c')
-rw-r--r--src/namestore/gnunet-namestore-fcfsd.c947
1 files changed, 947 insertions, 0 deletions
diff --git a/src/namestore/gnunet-namestore-fcfsd.c b/src/namestore/gnunet-namestore-fcfsd.c
new file mode 100644
index 000000000..d949806db
--- /dev/null
+++ b/src/namestore/gnunet-namestore-fcfsd.c
@@ -0,0 +1,947 @@
1/*
2 This file is part of GNUnet.
3 (C) 2012-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 * @file gnunet-gns-fcfsd.c
22 * @brief HTTP daemon that offers first-come-first-serve GNS domain registration
23 * @author Christian Grothoff
24 *
25 * TODO:
26 * - the code currently contains a 'race' between checking that the
27 * domain name is available and allocating it to the new public key
28 * (should this race be solved by namestore or by fcfsd?)
29 * - nicer error reporting to browser
30 */
31#include "platform.h"
32#include <microhttpd.h>
33#include "gnunet_util_lib.h"
34#include "gnunet_namestore_service.h"
35
36/**
37 * Invalid method page.
38 */
39#define METHOD_ERROR "<!DOCTYPE html PUBLIC \"-//W3C//DTD XHTML 1.0 Transitional//EN\" \"http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd\"><html lang=\"en\" xmlns=\"http://www.w3.org/1999/xhtml\"><html><head><title>Illegal request</title></head><body>Go away.</body></html>"
40
41/**
42 * Front page. (/)
43 */
44#define MAIN_PAGE "<!DOCTYPE html PUBLIC \"-//W3C//DTD XHTML 1.0 Transitional//EN\" \"http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd\"><html lang=\"en\" xmlns=\"http://www.w3.org/1999/xhtml\"><html><head><title>GNUnet FCFS Authority Name Registration Service</title></head><body><form action=\"S\" method=\"post\">What is your desired domain name? (at most 63 lowercase characters, no dots allowed.) <input type=\"text\" name=\"domain\" /> <p> What is your public key? (Copy from gnunet-setup.) <input type=\"text\" name=\"pkey\" /> <input type=\"submit\" value=\"Next\" /><br/><a href=./Zoneinfo> List of all registered names </a></body></html>"
45
46/**
47 * Second page (/S)
48 */
49#define SUBMIT_PAGE "<!DOCTYPE html PUBLIC \"-//W3C//DTD XHTML 1.0 Transitional//EN\" \"http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd\"><html lang=\"en\" xmlns=\"http://www.w3.org/1999/xhtml\"><html><head><title>%s</title></head><body>%s</body></html>"
50
51/**
52 * Fcfs zoneinfo page (/Zoneinfo)
53 */
54#define ZONEINFO_PAGE "<!DOCTYPE html PUBLIC \"-//W3C//DTD XHTML 1.0 Transitional//EN\" \"http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd\"><html lang=\"en\" xmlns=\"http://www.w3.org/1999/xhtml\"><html><head><title>FCFS Zoneinfo</title></head><body><h1> FCFS Zoneinfo </h1><table border=\"1\"><th>name</th><th>PKEY</th>%s</table></body></html>"
55
56#define FCFS_ZONEINFO_URL "/Zoneinfo"
57
58/**
59 * Mime type for HTML pages.
60 */
61#define MIME_HTML "text/html"
62
63/**
64 * Name of our cookie.
65 */
66#define COOKIE_NAME "gns-fcfs"
67
68#define DEFAULT_ZONEINFO_BUFSIZE 2048
69
70/**
71 * Phases a request goes through.
72 */
73enum Phase
74 {
75 /**
76 * Start phase (parsing POST, checking).
77 */
78 RP_START = 0,
79
80 /**
81 * Lookup to see if the domain name is taken.
82 */
83 RP_LOOKUP,
84
85 /**
86 * Storing of the record.
87 */
88 RP_PUT,
89
90 /**
91 * We're done with success.
92 */
93 RP_SUCCESS,
94
95 /**
96 * Send failure message.
97 */
98 RP_FAIL
99 };
100
101
102/**
103 * Data kept per request.
104 */
105struct Request
106{
107
108 /**
109 * Associated session.
110 */
111 struct Session *session;
112
113 /**
114 * Post processor handling form data (IF this is
115 * a POST request).
116 */
117 struct MHD_PostProcessor *pp;
118
119 /**
120 * URL to serve in response to this POST (if this request
121 * was a 'POST')
122 */
123 const char *post_url;
124
125 /**
126 * Active request with the namestore.
127 */
128 struct GNUNET_NAMESTORE_QueueEntry *qe;
129
130 /**
131 * Current processing phase.
132 */
133 enum Phase phase;
134
135 /**
136 * Domain name submitted via form.
137 */
138 char domain_name[64];
139
140 /**
141 * Public key submitted via form.
142 */
143 char public_key[128];
144
145};
146
147/**
148 * Zoneinfo request
149 */
150struct ZoneinfoRequest
151{
152 /**
153 * Connection
154 */
155 struct MHD_Connection *connection;
156
157 /**
158 * List iterator
159 */
160 struct GNUNET_NAMESTORE_ZoneIterator *list_it;
161
162 /**
163 * Buffer
164 */
165 char* zoneinfo;
166
167 /**
168 * Buffer length
169 */
170 size_t buf_len;
171
172 /**
173 * Buffer write offset
174 */
175 size_t write_offset;
176};
177
178/**
179 * MHD deamon reference.
180 */
181static struct MHD_Daemon *httpd;
182
183/**
184 * Main HTTP task.
185 */
186static GNUNET_SCHEDULER_TaskIdentifier httpd_task;
187
188/**
189 * Handle to the namestore.
190 */
191static struct GNUNET_NAMESTORE_Handle *ns;
192
193/**
194 * Private key for the fcfsd zone.
195 */
196static struct GNUNET_CRYPTO_EccPrivateKey *fcfs_zone_pkey;
197
198
199/**
200 * Task run whenever HTTP server operations are pending.
201 *
202 * @param cls unused
203 * @param tc scheduler context
204 */
205static void
206do_httpd (void *cls,
207 const struct GNUNET_SCHEDULER_TaskContext *tc);
208
209
210/**
211 * Schedule task to run MHD server now.
212 */
213static void
214run_httpd_now ()
215{
216 if (GNUNET_SCHEDULER_NO_TASK != httpd_task)
217 {
218 GNUNET_SCHEDULER_cancel (httpd_task);
219 httpd_task = GNUNET_SCHEDULER_NO_TASK;
220 }
221 httpd_task = GNUNET_SCHEDULER_add_now (&do_httpd, NULL);
222}
223
224
225static void
226iterate_cb (void *cls,
227 const struct GNUNET_CRYPTO_EccPrivateKey *zone_key,
228 const char *name,
229 unsigned int rd_len,
230 const struct GNUNET_NAMESTORE_RecordData *rd)
231{
232 struct ZoneinfoRequest *zr = cls;
233 struct MHD_Response *response;
234 char* full_page;
235 size_t bytes_free;
236 char* pkey;
237 char* new_buf;
238
239
240 if (NULL == name)
241 {
242 zr->list_it = NULL;
243
244 /* return static form */
245 GNUNET_asprintf (&full_page,
246 ZONEINFO_PAGE,
247 zr->zoneinfo,
248 zr->zoneinfo);
249 response = MHD_create_response_from_buffer (strlen (full_page),
250 (void *) full_page,
251 MHD_RESPMEM_MUST_FREE);
252 MHD_add_response_header (response,
253 MHD_HTTP_HEADER_CONTENT_TYPE,
254 MIME_HTML);
255 MHD_queue_response (zr->connection,
256 MHD_HTTP_OK,
257 response);
258 MHD_destroy_response (response);
259 GNUNET_free (zr->zoneinfo);
260 GNUNET_free (zr);
261 run_httpd_now ();
262 return;
263 }
264
265 if (1 != rd_len)
266 {
267 GNUNET_NAMESTORE_zone_iterator_next (zr->list_it);
268 return;
269 }
270
271 if (GNUNET_NAMESTORE_TYPE_PKEY != rd->record_type)
272 {
273 GNUNET_NAMESTORE_zone_iterator_next (zr->list_it);
274 return;
275 }
276
277 bytes_free = zr->buf_len - zr->write_offset;
278 pkey = GNUNET_NAMESTORE_value_to_string (rd->record_type,
279 rd->data,
280 rd->data_size);
281
282 if (bytes_free < (strlen (name) + strlen (pkey) + 40))
283 {
284 new_buf = GNUNET_malloc (zr->buf_len * 2);
285 memcpy (new_buf, zr->zoneinfo, zr->write_offset);
286 GNUNET_free (zr->zoneinfo);
287 zr->zoneinfo = new_buf;
288 zr->buf_len *= 2;
289 }
290 sprintf (zr->zoneinfo + zr->write_offset,
291 "<tr><td>%s</td><td>%s</td></tr>",
292 name,
293 pkey);
294 zr->write_offset = strlen (zr->zoneinfo);
295 GNUNET_NAMESTORE_zone_iterator_next (zr->list_it);
296 GNUNET_free (pkey);
297}
298
299
300
301/**
302 * Handler that returns FCFS zoneinfo page.
303 *
304 * @param connection connection to use
305 * @return MHD_YES on success
306 */
307static int
308serve_zoneinfo_page (struct MHD_Connection *connection)
309{
310 struct ZoneinfoRequest *zr;
311
312 zr = GNUNET_new (struct ZoneinfoRequest);
313 zr->zoneinfo = GNUNET_malloc (DEFAULT_ZONEINFO_BUFSIZE);
314 zr->buf_len = DEFAULT_ZONEINFO_BUFSIZE;
315 zr->connection = connection;
316 zr->write_offset = 0;
317 zr->list_it = GNUNET_NAMESTORE_zone_iteration_start (ns,
318 fcfs_zone_pkey,
319 &iterate_cb,
320 zr);
321 return MHD_YES;
322}
323
324
325/**
326 * Handler that returns a simple static HTTP page.
327 *
328 * @param connection connection to use
329 * @return MHD_YES on success
330 */
331static int
332serve_main_page (struct MHD_Connection *connection)
333{
334 int ret;
335 struct MHD_Response *response;
336
337 /* return static form */
338 response = MHD_create_response_from_buffer (strlen (MAIN_PAGE),
339 (void *) MAIN_PAGE,
340 MHD_RESPMEM_PERSISTENT);
341 MHD_add_response_header (response,
342 MHD_HTTP_HEADER_CONTENT_TYPE,
343 MIME_HTML);
344 ret = MHD_queue_response (connection,
345 MHD_HTTP_OK,
346 response);
347 MHD_destroy_response (response);
348 return ret;
349}
350
351
352/**
353 * Send the 'SUBMIT_PAGE'.
354 *
355 * @param info information string to send to the user
356 * @param request request information
357 * @param connection connection to use
358 */
359static int
360fill_s_reply (const char *info,
361 struct Request *request,
362 struct MHD_Connection *connection)
363{
364 int ret;
365 char *reply;
366 struct MHD_Response *response;
367
368 GNUNET_asprintf (&reply,
369 SUBMIT_PAGE,
370 info,
371 info);
372 /* return static form */
373 response = MHD_create_response_from_buffer (strlen (reply),
374 (void *) reply,
375 MHD_RESPMEM_MUST_FREE);
376 MHD_add_response_header (response,
377 MHD_HTTP_HEADER_CONTENT_TYPE,
378 MIME_HTML);
379 ret = MHD_queue_response (connection,
380 MHD_HTTP_OK,
381 response);
382 MHD_destroy_response (response);
383 return ret;
384}
385
386
387/**
388 * Iterator over key-value pairs where the value
389 * maybe made available in increments and/or may
390 * not be zero-terminated. Used for processing
391 * POST data.
392 *
393 * @param cls user-specified closure
394 * @param kind type of the value
395 * @param key 0-terminated key for the value
396 * @param filename name of the uploaded file, NULL if not known
397 * @param content_type mime-type of the data, NULL if not known
398 * @param transfer_encoding encoding of the data, NULL if not known
399 * @param data pointer to size bytes of data at the
400 * specified offset
401 * @param off offset of data in the overall value
402 * @param size number of bytes in data available
403 * @return MHD_YES to continue iterating,
404 * MHD_NO to abort the iteration
405 */
406static int
407post_iterator (void *cls,
408 enum MHD_ValueKind kind,
409 const char *key,
410 const char *filename,
411 const char *content_type,
412 const char *transfer_encoding,
413 const char *data, uint64_t off, size_t size)
414{
415 struct Request *request = cls;
416
417 if (0 == strcmp ("domain", key))
418 {
419 if (size + off >= sizeof(request->domain_name))
420 size = sizeof (request->domain_name) - off - 1;
421 memcpy (&request->domain_name[off],
422 data,
423 size);
424 request->domain_name[size+off] = '\0';
425 return MHD_YES;
426 }
427 if (0 == strcmp ("pkey", key))
428 {
429 if (size + off >= sizeof(request->public_key))
430 size = sizeof (request->public_key) - off - 1;
431 memcpy (&request->public_key[off],
432 data,
433 size);
434 request->public_key[size+off] = '\0';
435 return MHD_YES;
436 }
437 GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
438 _("Unsupported form value `%s'\n"),
439 key);
440 return MHD_YES;
441}
442
443
444
445
446/**
447 * Continuation called to notify client about result of the
448 * operation.
449 *
450 * @param cls closure
451 * @param success GNUNET_SYSERR on failure (including timeout/queue drop/failure to validate)
452 * GNUNET_NO if content was already there
453 * GNUNET_YES (or other positive value) on success
454 * @param emsg NULL on success, otherwise an error message
455 */
456static void
457put_continuation (void *cls,
458 int32_t success,
459 const char *emsg)
460{
461 struct Request *request = cls;
462
463 request->qe = NULL;
464 if (0 >= success)
465 {
466 GNUNET_log (GNUNET_ERROR_TYPE_WARNING,
467 _("Failed to create record for domain `%s': %s\n"),
468 request->domain_name,
469 emsg);
470 request->phase = RP_FAIL;
471 }
472 else
473 request->phase = RP_SUCCESS;
474 run_httpd_now ();
475}
476
477
478/**
479 * Test if a name mapping was found, if so, refuse. If not, initiate storing of the record.
480 *
481 * @param cls closure
482 * @param zone_key public key of the zone
483 * @param name name that is being mapped (at most 255 characters long)
484 * @param rd_count number of entries in 'rd' array
485 * @param rd array of records with data to store
486 */
487static void
488zone_to_name_cb (void *cls,
489 const struct GNUNET_CRYPTO_EccPrivateKey *zone_key,
490 const char *name,
491 unsigned int rd_count,
492 const struct GNUNET_NAMESTORE_RecordData *rd)
493{
494 struct Request *request = cls;
495 struct GNUNET_NAMESTORE_RecordData r;
496 struct GNUNET_CRYPTO_ShortHashCode pub;
497
498 request->qe = NULL;
499 if (NULL != name)
500 {
501 GNUNET_log (GNUNET_ERROR_TYPE_INFO,
502 _("Found existing name `%s' for the given key\n"),
503 name);
504 request->phase = RP_FAIL;
505 run_httpd_now ();
506 return;
507 }
508 r.data = &pub;
509 r.data_size = sizeof (pub);
510 r.expiration_time = UINT64_MAX;
511 r.record_type = GNUNET_NAMESTORE_TYPE_PKEY;
512 r.flags = GNUNET_NAMESTORE_RF_AUTHORITY;
513 request->qe = GNUNET_NAMESTORE_records_store (ns,
514 fcfs_zone_pkey,
515 request->domain_name,
516 1, &r,
517 &put_continuation,
518 request);
519}
520
521
522/**
523 * Process a record that was stored in the namestore. Used to check if
524 * the requested name already exists in the namestore. If not,
525 * proceed to check if the requested key already exists.
526 *
527 * @param cls closure
528 * @param zone_key private key of the zone
529 * @param name name that is being mapped (at most 255 characters long)
530 * @param rd_count number of entries in 'rd' array
531 * @param rd array of records with data to store
532 */
533static void
534lookup_result_processor (void *cls,
535 const struct GNUNET_CRYPTO_EccPrivateKey *zone_key,
536 const char *name,
537 unsigned int rd_count,
538 const struct GNUNET_NAMESTORE_RecordData *rd)
539{
540 struct Request *request = cls;
541 struct GNUNET_CRYPTO_EccPublicKey pub;
542
543 request->qe = NULL;
544 if (0 != rd_count)
545 {
546 GNUNET_log (GNUNET_ERROR_TYPE_INFO,
547 _("Found %u existing records for domain `%s'\n"),
548 rd_count,
549 request->domain_name);
550 request->phase = RP_FAIL;
551 run_httpd_now ();
552 return;
553 }
554 if (GNUNET_OK !=
555 GNUNET_CRYPTO_ecc_public_key_from_string (request->public_key,
556 strlen (request->public_key),
557 &pub))
558 {
559 GNUNET_break (0);
560 request->phase = RP_FAIL;
561 run_httpd_now ();
562 return;
563 }
564 request->qe = GNUNET_NAMESTORE_zone_to_name (ns,
565 fcfs_zone_pkey,
566 &pub,
567 &zone_to_name_cb,
568 request);
569}
570
571
572/**
573 * Main MHD callback for handling requests.
574 *
575 * @param cls unused
576 * @param connection MHD connection handle
577 * @param url the requested url
578 * @param method the HTTP method used ("GET", "PUT", etc.)
579 * @param version the HTTP version string (i.e. "HTTP/1.1")
580 * @param upload_data the data being uploaded (excluding HEADERS,
581 * for a POST that fits into memory and that is encoded
582 * with a supported encoding, the POST data will NOT be
583 * given in upload_data and is instead available as
584 * part of MHD_get_connection_values; very large POST
585 * data *will* be made available incrementally in
586 * upload_data)
587 * @param upload_data_size set initially to the size of the
588 * upload_data provided; the method must update this
589 * value to the number of bytes NOT processed;
590 * @param ptr pointer to location where we store the 'struct Request'
591 * @return MHD_YES if the connection was handled successfully,
592 * MHD_NO if the socket must be closed due to a serious
593 * error while handling the request
594 */
595static int
596create_response (void *cls,
597 struct MHD_Connection *connection,
598 const char *url,
599 const char *method,
600 const char *version,
601 const char *upload_data,
602 size_t *upload_data_size,
603 void **ptr)
604{
605 struct MHD_Response *response;
606 struct Request *request;
607 int ret;
608 struct GNUNET_CRYPTO_EccPublicKey pub;
609
610 if ( (0 == strcmp (method, MHD_HTTP_METHOD_GET)) ||
611 (0 == strcmp (method, MHD_HTTP_METHOD_HEAD)) )
612 {
613 if (0 == strcmp (url, FCFS_ZONEINFO_URL))
614 ret = serve_zoneinfo_page (connection);
615 else
616 ret = serve_main_page (connection);
617 if (ret != MHD_YES)
618 GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
619 _("Failed to create page for `%s'\n"),
620 url);
621 return ret;
622 }
623 if (0 == strcmp (method, MHD_HTTP_METHOD_POST))
624 {
625 request = *ptr;
626 if (NULL == request)
627 {
628 request = GNUNET_malloc (sizeof (struct Request));
629 *ptr = request;
630 request->pp = MHD_create_post_processor (connection, 1024,
631 &post_iterator, request);
632 if (NULL == request->pp)
633 {
634 GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
635 _("Failed to setup post processor for `%s'\n"),
636 url);
637 return MHD_NO; /* internal error */
638 }
639 return MHD_YES;
640 }
641 if (NULL != request->pp)
642 {
643 /* evaluate POST data */
644 MHD_post_process (request->pp,
645 upload_data,
646 *upload_data_size);
647 if (0 != *upload_data_size)
648 {
649 *upload_data_size = 0;
650 return MHD_YES;
651 }
652 /* done with POST data, serve response */
653 MHD_destroy_post_processor (request->pp);
654 request->pp = NULL;
655 }
656 if (GNUNET_OK !=
657 GNUNET_CRYPTO_ecc_public_key_from_string (request->public_key,
658 strlen (request->public_key),
659 &pub))
660 {
661 /* parse error */
662 return fill_s_reply ("Failed to parse given public key",
663 request, connection);
664 }
665 switch (request->phase)
666 {
667 case RP_START:
668 if (NULL != strchr (request->domain_name, (int) '.'))
669 {
670 GNUNET_log (GNUNET_ERROR_TYPE_INFO,
671 _("Domain name must not contain `.'\n"));
672 request->phase = RP_FAIL;
673 return fill_s_reply ("Domain name must not contain `.', sorry.",
674 request, connection);
675 }
676 if (NULL != strchr (request->domain_name, (int) '+'))
677 {
678 GNUNET_log (GNUNET_ERROR_TYPE_INFO,
679 _("Domain name must not contain `+'\n"));
680 request->phase = RP_FAIL;
681 return fill_s_reply ("Domain name must not contain `+', sorry.",
682 request, connection);
683 }
684 request->phase = RP_LOOKUP;
685 GNUNET_CRYPTO_ecc_key_get_public (fcfs_zone_pkey,
686 &pub);
687 request->qe = GNUNET_NAMESTORE_lookup (ns,
688 &pub,
689 request->domain_name,
690 &lookup_result_processor,
691 request);
692 break;
693 case RP_LOOKUP:
694 break;
695 case RP_PUT:
696 break;
697 case RP_FAIL:
698 return fill_s_reply ("Request failed, sorry.",
699 request, connection);
700 case RP_SUCCESS:
701 return fill_s_reply ("Success.",
702 request, connection);
703 default:
704 GNUNET_break (0);
705 return MHD_NO;
706 }
707 return MHD_YES; /* will have a reply later... */
708 }
709 /* unsupported HTTP method */
710 response = MHD_create_response_from_buffer (strlen (METHOD_ERROR),
711 (void *) METHOD_ERROR,
712 MHD_RESPMEM_PERSISTENT);
713 ret = MHD_queue_response (connection,
714 MHD_HTTP_METHOD_NOT_ACCEPTABLE,
715 response);
716 MHD_destroy_response (response);
717 return ret;
718}
719
720
721/**
722 * Callback called upon completion of a request.
723 * Decrements session reference counter.
724 *
725 * @param cls not used
726 * @param connection connection that completed
727 * @param con_cls session handle
728 * @param toe status code
729 */
730static void
731request_completed_callback (void *cls,
732 struct MHD_Connection *connection,
733 void **con_cls,
734 enum MHD_RequestTerminationCode toe)
735{
736 struct Request *request = *con_cls;
737
738 if (NULL == request)
739 return;
740 if (NULL != request->pp)
741 MHD_destroy_post_processor (request->pp);
742 if (NULL != request->qe)
743 GNUNET_NAMESTORE_cancel (request->qe);
744 GNUNET_free (request);
745}
746
747
748#define UNSIGNED_MHD_LONG_LONG unsigned MHD_LONG_LONG
749
750
751/**
752 * Schedule tasks to run MHD server.
753 */
754static void
755run_httpd ()
756{
757 fd_set rs;
758 fd_set ws;
759 fd_set es;
760 struct GNUNET_NETWORK_FDSet *wrs;
761 struct GNUNET_NETWORK_FDSet *wws;
762 struct GNUNET_NETWORK_FDSet *wes;
763 int max;
764 int haveto;
765 UNSIGNED_MHD_LONG_LONG timeout;
766 struct GNUNET_TIME_Relative tv;
767
768 FD_ZERO (&rs);
769 FD_ZERO (&ws);
770 FD_ZERO (&es);
771 wrs = GNUNET_NETWORK_fdset_create ();
772 wes = GNUNET_NETWORK_fdset_create ();
773 wws = GNUNET_NETWORK_fdset_create ();
774 max = -1;
775 GNUNET_assert (MHD_YES == MHD_get_fdset (httpd, &rs, &ws, &es, &max));
776 haveto = MHD_get_timeout (httpd, &timeout);
777 if (haveto == MHD_YES)
778 tv.rel_value_us = (uint64_t) timeout * 1000LL;
779 else
780 tv = GNUNET_TIME_UNIT_FOREVER_REL;
781 GNUNET_NETWORK_fdset_copy_native (wrs, &rs, max + 1);
782 GNUNET_NETWORK_fdset_copy_native (wws, &ws, max + 1);
783 GNUNET_NETWORK_fdset_copy_native (wes, &es, max + 1);
784 httpd_task =
785 GNUNET_SCHEDULER_add_select (GNUNET_SCHEDULER_PRIORITY_HIGH,
786 tv, wrs, wws,
787 &do_httpd, NULL);
788 GNUNET_NETWORK_fdset_destroy (wrs);
789 GNUNET_NETWORK_fdset_destroy (wws);
790 GNUNET_NETWORK_fdset_destroy (wes);
791}
792
793
794/**
795 * Task run whenever HTTP server operations are pending.
796 *
797 * @param cls unused
798 * @param tc scheduler context
799 */
800static void
801do_httpd (void *cls,
802 const struct GNUNET_SCHEDULER_TaskContext *tc)
803{
804 httpd_task = GNUNET_SCHEDULER_NO_TASK;
805 MHD_run (httpd);
806 run_httpd ();
807}
808
809
810/**
811 * Task run on shutdown. Cleans up everything.
812 *
813 * @param cls unused
814 * @param tc scheduler context
815 */
816static void
817do_shutdown (void *cls,
818 const struct GNUNET_SCHEDULER_TaskContext *tc)
819{
820 if (GNUNET_SCHEDULER_NO_TASK != httpd_task)
821 {
822 GNUNET_SCHEDULER_cancel (httpd_task);
823 httpd_task = GNUNET_SCHEDULER_NO_TASK;
824 }
825 if (NULL != ns)
826 {
827 GNUNET_NAMESTORE_disconnect (ns);
828 ns = NULL;
829 }
830 if (NULL != httpd)
831 {
832 MHD_stop_daemon (httpd);
833 httpd = NULL;
834 }
835 if (NULL != fcfs_zone_pkey)
836 {
837 GNUNET_CRYPTO_ecc_key_free (fcfs_zone_pkey);
838 fcfs_zone_pkey = NULL;
839 }
840}
841
842
843/**
844 * Main function that will be run.
845 *
846 * @param cls closure
847 * @param args remaining command-line arguments
848 * @param cfgfile name of the configuration file used (for saving, can be NULL!)
849 * @param cfg configuration
850 */
851static void
852run (void *cls, char *const *args, const char *cfgfile,
853 const struct GNUNET_CONFIGURATION_Handle *cfg)
854{
855 char *keyfile;
856 unsigned long long port;
857
858 if (GNUNET_OK !=
859 GNUNET_CONFIGURATION_get_value_number (cfg,
860 "fcfsd",
861 "HTTPPORT",
862 &port))
863 {
864 GNUNET_log_config_missing (GNUNET_ERROR_TYPE_ERROR,
865 "fcfsd", "HTTPPORT");
866 return;
867 }
868 if (GNUNET_OK !=
869 GNUNET_CONFIGURATION_get_value_filename (cfg,
870 "fcfsd",
871 "ZONEKEY",
872 &keyfile))
873 {
874 GNUNET_log_config_missing (GNUNET_ERROR_TYPE_ERROR,
875 "fcfsd", "ZONEKEY");
876 return;
877 }
878 fcfs_zone_pkey = GNUNET_CRYPTO_ecc_key_create_from_file (keyfile);
879 GNUNET_free (keyfile);
880 if (NULL == fcfs_zone_pkey)
881 {
882 GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
883 _("Failed to read or create private zone key\n"));
884 return;
885 }
886 ns = GNUNET_NAMESTORE_connect (cfg);
887 if (NULL == ns)
888 {
889 GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
890 _("Failed to connect to namestore\n"));
891 return;
892 }
893 httpd = MHD_start_daemon (MHD_USE_DEBUG,
894 (uint16_t) port,
895 NULL, NULL,
896 &create_response, NULL,
897 MHD_OPTION_CONNECTION_LIMIT, (unsigned int) 128,
898 MHD_OPTION_PER_IP_CONNECTION_LIMIT, (unsigned int) 1,
899 MHD_OPTION_CONNECTION_TIMEOUT, (unsigned int) 16,
900 MHD_OPTION_CONNECTION_MEMORY_LIMIT, (size_t) (4 * 1024),
901 MHD_OPTION_NOTIFY_COMPLETED, &request_completed_callback, NULL,
902 MHD_OPTION_END);
903 if (NULL == httpd)
904 {
905 GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
906 _("Failed to start HTTP server\n"));
907 GNUNET_NAMESTORE_disconnect (ns);
908 ns = NULL;
909 return;
910 }
911 run_httpd ();
912 GNUNET_SCHEDULER_add_delayed (GNUNET_TIME_UNIT_FOREVER_REL,
913 &do_shutdown, NULL);
914}
915
916
917/**
918 * The main function for the fcfs daemon.
919 *
920 * @param argc number of arguments from the command line
921 * @param argv command line arguments
922 * @return 0 ok, 1 on error
923 */
924int
925main (int argc, char *const *argv)
926{
927 static const struct GNUNET_GETOPT_CommandLineOption options[] = {
928 GNUNET_GETOPT_OPTION_END
929 };
930
931 int ret;
932
933 if (GNUNET_OK != GNUNET_STRINGS_get_utf8_args (argc, argv, &argc, &argv))
934 return 2;
935
936 GNUNET_log_setup ("fcfsd", "WARNING", NULL);
937 ret =
938 (GNUNET_OK ==
939 GNUNET_PROGRAM_run (argc, argv, "fcfsd",
940 _("GNUnet GNS first come first serve registration service"),
941 options,
942 &run, NULL)) ? 0 : 1;
943 GNUNET_free ((void*) argv);
944 return ret;
945}
946
947/* end of gnunet-gns-fcfsd.c */