Merge branch 'master' of git+ssh://gnunet.org/gnunet
[oweals/gnunet.git] / src / namestore / gnunet-namestore-fcfsd.c
1 /*
2      This file is part of GNUnet.
3      Copyright (C) 2012-2014 GNUnet e.V.
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., 51 Franklin Street, Fifth Floor,
18      Boston, MA 02110-1301, USA.
19 */
20 /**
21  * @file gnunet-namestore-fcfsd.c
22  * @brief HTTP daemon that offers first-come-first-serve GNS domain registration
23  * @author Christian Grothoff
24  *
25  * TODO:
26  * - need to track active zone info requests so we can cancel them
27  *   during shutdown, right?
28  * - the code currently contains a 'race' between checking that the
29  *   domain name is available and allocating it to the new public key
30  *   (should this race be solved by namestore or by fcfsd?)
31  * - nicer error reporting to browser
32  */
33 #include "platform.h"
34 #include <microhttpd.h>
35 #include "gnunet_util_lib.h"
36 #include "gnunet_identity_service.h"
37 #include "gnunet_gnsrecord_lib.h"
38 #include "gnunet_namestore_service.h"
39
40 /**
41  * Invalid method page.
42  */
43 #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>"
44
45 /**
46  * Front page. (/)
47  */
48 #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>"
49
50 /**
51  * Second page (/S)
52  */
53 #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>"
54
55 /**
56  * Fcfs zoneinfo page (/Zoneinfo)
57  */
58 #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>"
59
60 #define FCFS_ZONEINFO_URL "/Zoneinfo"
61
62 /**
63  * Mime type for HTML pages.
64  */
65 #define MIME_HTML "text/html"
66
67 /**
68  * Name of our cookie.
69  */
70 #define COOKIE_NAME "namestore-fcfsd"
71
72 #define DEFAULT_ZONEINFO_BUFSIZE 2048
73
74 /**
75  * Phases a request goes through.
76  */
77 enum Phase
78   {
79     /**
80      * Start phase (parsing POST, checking).
81      */
82     RP_START = 0,
83
84     /**
85      * Lookup to see if the domain name is taken.
86      */
87     RP_LOOKUP,
88
89     /**
90      * Storing of the record.
91      */
92     RP_PUT,
93
94     /**
95      * We're done with success.
96      */
97     RP_SUCCESS,
98
99     /**
100      * Send failure message.
101      */
102     RP_FAIL
103   };
104
105
106 /**
107  * Data kept per request.
108  */
109 struct Request
110 {
111
112   /**
113    * Associated session.
114    */
115   // FIXME: struct Session *session;
116
117   /**
118    * Post processor handling form data (IF this is
119    * a POST request).
120    */
121   struct MHD_PostProcessor *pp;
122
123   /**
124    * URL to serve in response to this POST (if this request
125    * was a 'POST')
126    */
127   const char *post_url;
128
129   /**
130    * Active request with the namestore.
131    */
132   struct GNUNET_NAMESTORE_QueueEntry *qe;
133
134   /**
135    * Active iteration with the namestore.
136    */
137   struct GNUNET_NAMESTORE_ZoneIterator *zi;
138
139   /**
140    * Current processing phase.
141    */
142   enum Phase phase;
143
144   /**
145    * Domain name submitted via form.
146    */
147   char domain_name[64];
148
149   /**
150    * Public key submitted via form.
151    */
152   char public_key[128];
153
154   struct GNUNET_CRYPTO_EcdsaPublicKey pub;
155
156 };
157
158 /**
159  * Zoneinfo request
160  */
161 struct ZoneinfoRequest
162 {
163   /**
164    * Connection
165    */
166   struct MHD_Connection *connection;
167
168   /**
169    * List iterator
170    */
171   struct GNUNET_NAMESTORE_ZoneIterator *list_it;
172
173   /**
174    * Buffer
175    */
176   char* zoneinfo;
177
178   /**
179    * Buffer length
180    */
181   size_t buf_len;
182
183   /**
184    * Buffer write offset
185    */
186   size_t write_offset;
187 };
188
189 /**
190  * MHD deamon reference.
191  */
192 static struct MHD_Daemon *httpd;
193
194 /**
195  * Main HTTP task.
196  */
197 static struct GNUNET_SCHEDULER_Task * httpd_task;
198
199 /**
200  * Handle to the namestore.
201  */
202 static struct GNUNET_NAMESTORE_Handle *ns;
203
204 /**
205  * Private key for the fcfsd zone.
206  */
207 static struct GNUNET_CRYPTO_EcdsaPrivateKey fcfs_zone_pkey;
208
209 /**
210  * Connection to identity service.
211  */
212 static struct GNUNET_IDENTITY_Handle *identity;
213
214 /**
215  * Request for our ego.
216  */
217 static struct GNUNET_IDENTITY_Operation *id_op;
218
219 /**
220  * Port we use for the HTTP server.
221  */
222 static unsigned long long port;
223
224
225 /**
226  * Task run whenever HTTP server operations are pending.
227  *
228  * @param cls unused
229  */
230 static void
231 do_httpd (void *cls);
232
233
234 /**
235  * Schedule task to run MHD server now.
236  */
237 static void
238 run_httpd_now ()
239 {
240   if (NULL != httpd_task)
241   {
242     GNUNET_SCHEDULER_cancel (httpd_task);
243     httpd_task = NULL;
244   }
245   httpd_task = GNUNET_SCHEDULER_add_now (&do_httpd, NULL);
246 }
247
248
249 /**
250  * Function called on error in zone iteration.
251  */
252 static void
253 zone_iteration_error (void *cls)
254 {
255   struct ZoneinfoRequest *zr = cls;
256   struct MHD_Response *response;
257
258   zr->list_it = NULL;
259   response = MHD_create_response_from_buffer (strlen ("internal error"),
260                                               (void *) "internal error",
261                                               MHD_RESPMEM_PERSISTENT);
262   MHD_queue_response (zr->connection,
263                       MHD_HTTP_INTERNAL_SERVER_ERROR,
264                       response);
265   MHD_destroy_response (response);
266   GNUNET_free (zr->zoneinfo);
267   GNUNET_free (zr);
268   run_httpd_now ();
269 }
270
271
272 /**
273  * Function called once the zone iteration is done.
274  */
275 static void
276 zone_iteration_end (void *cls)
277 {
278   struct ZoneinfoRequest *zr = cls;
279   struct MHD_Response *response;
280   char* full_page;
281
282   zr->list_it = NULL;
283
284   /* return static form */
285   GNUNET_asprintf (&full_page,
286                    ZONEINFO_PAGE,
287                    zr->zoneinfo,
288                    zr->zoneinfo);
289   response = MHD_create_response_from_buffer (strlen (full_page),
290                                               (void *) full_page,
291                                               MHD_RESPMEM_MUST_FREE);
292   MHD_add_response_header (response,
293                            MHD_HTTP_HEADER_CONTENT_TYPE,
294                            MIME_HTML);
295   MHD_queue_response (zr->connection,
296                       MHD_HTTP_OK,
297                       response);
298   MHD_destroy_response (response);
299   GNUNET_free (zr->zoneinfo);
300   GNUNET_free (zr);
301   run_httpd_now ();
302 }
303
304
305 /**
306  * Process a record that was stored in the namestore, adding
307  * the information to the HTML.
308  *
309  * @param cls closure with the `struct ZoneinfoRequest *`
310  * @param zone_key private key of the zone; NULL on disconnect
311  * @param name label of the records; NULL on disconnect
312  * @param rd_len number of entries in @a rd array, 0 if label was deleted
313  * @param rd array of records with data to store
314  */
315 static void
316 iterate_cb (void *cls,
317             const struct GNUNET_CRYPTO_EcdsaPrivateKey *zone_key,
318             const char *name,
319             unsigned int rd_len,
320             const struct GNUNET_GNSRECORD_Data *rd)
321 {
322   struct ZoneinfoRequest *zr = cls;
323   size_t bytes_free;
324   char* pkey;
325   char* new_buf;
326
327   if (1 != rd_len)
328   {
329     GNUNET_NAMESTORE_zone_iterator_next (zr->list_it);
330     return;
331   }
332
333   if (GNUNET_GNSRECORD_TYPE_PKEY != rd->record_type)
334   {
335     GNUNET_NAMESTORE_zone_iterator_next (zr->list_it);
336     return;
337   }
338
339   bytes_free = zr->buf_len - zr->write_offset;
340   pkey = GNUNET_GNSRECORD_value_to_string (rd->record_type,
341                                            rd->data,
342                                            rd->data_size);
343   if (NULL == pkey)
344   {
345     GNUNET_break (0);
346     GNUNET_NAMESTORE_zone_iterator_next (zr->list_it);
347     return;
348   }
349   if (bytes_free < (strlen (name) + strlen (pkey) + 40))
350   {
351     new_buf = GNUNET_malloc (zr->buf_len * 2);
352     GNUNET_memcpy (new_buf, zr->zoneinfo, zr->write_offset);
353     GNUNET_free (zr->zoneinfo);
354     zr->zoneinfo = new_buf;
355     zr->buf_len *= 2;
356   }
357   sprintf (zr->zoneinfo + zr->write_offset,
358            "<tr><td>%s</td><td>%s</td></tr>",
359            name,
360            pkey);
361   zr->write_offset = strlen (zr->zoneinfo);
362   GNUNET_NAMESTORE_zone_iterator_next (zr->list_it);
363   GNUNET_free (pkey);
364 }
365
366
367 /**
368  * Handler that returns FCFS zoneinfo page.
369  *
370  * @param connection connection to use
371  * @return MHD_YES on success
372  */
373 static int
374 serve_zoneinfo_page (struct MHD_Connection *connection)
375 {
376   struct ZoneinfoRequest *zr;
377
378   zr = GNUNET_new (struct ZoneinfoRequest);
379   zr->zoneinfo = GNUNET_malloc (DEFAULT_ZONEINFO_BUFSIZE);
380   zr->buf_len = DEFAULT_ZONEINFO_BUFSIZE;
381   zr->connection = connection;
382   zr->write_offset = 0;
383   zr->list_it = GNUNET_NAMESTORE_zone_iteration_start (ns,
384                                                        &fcfs_zone_pkey,
385                                                        &zone_iteration_error,
386                                                        zr,
387                                                        &iterate_cb,
388                                                        zr,
389                                                        &zone_iteration_end,
390                                                        zr);
391   return MHD_YES;
392 }
393
394
395 /**
396  * Handler that returns a simple static HTTP page.
397  *
398  * @param connection connection to use
399  * @return MHD_YES on success
400  */
401 static int
402 serve_main_page (struct MHD_Connection *connection)
403 {
404   int ret;
405   struct MHD_Response *response;
406
407   /* return static form */
408   response = MHD_create_response_from_buffer (strlen (MAIN_PAGE),
409                                               (void *) MAIN_PAGE,
410                                               MHD_RESPMEM_PERSISTENT);
411   MHD_add_response_header (response,
412                            MHD_HTTP_HEADER_CONTENT_TYPE,
413                            MIME_HTML);
414   ret = MHD_queue_response (connection,
415                             MHD_HTTP_OK,
416                             response);
417   MHD_destroy_response (response);
418   return ret;
419 }
420
421
422 /**
423  * Send the 'SUBMIT_PAGE'.
424  *
425  * @param info information string to send to the user
426  * @param request request information
427  * @param connection connection to use
428  */
429 static int
430 fill_s_reply (const char *info,
431               struct Request *request,
432               struct MHD_Connection *connection)
433 {
434   int ret;
435   char *reply;
436   struct MHD_Response *response;
437
438   GNUNET_asprintf (&reply,
439                    SUBMIT_PAGE,
440                    info,
441                    info);
442   /* return static form */
443   response = MHD_create_response_from_buffer (strlen (reply),
444                                               (void *) reply,
445                                               MHD_RESPMEM_MUST_FREE);
446   MHD_add_response_header (response,
447                            MHD_HTTP_HEADER_CONTENT_TYPE,
448                            MIME_HTML);
449   ret = MHD_queue_response (connection,
450                             MHD_HTTP_OK,
451                             response);
452   MHD_destroy_response (response);
453   return ret;
454 }
455
456
457 /**
458  * Iterator over key-value pairs where the value
459  * maybe made available in increments and/or may
460  * not be zero-terminated.  Used for processing
461  * POST data.
462  *
463  * @param cls user-specified closure
464  * @param kind type of the value
465  * @param key 0-terminated key for the value
466  * @param filename name of the uploaded file, NULL if not known
467  * @param content_type mime-type of the data, NULL if not known
468  * @param transfer_encoding encoding of the data, NULL if not known
469  * @param data pointer to size bytes of data at the
470  *              specified offset
471  * @param off offset of data in the overall value
472  * @param size number of bytes in data available
473  * @return MHD_YES to continue iterating,
474  *         MHD_NO to abort the iteration
475  */
476 static int
477 post_iterator (void *cls,
478                enum MHD_ValueKind kind,
479                const char *key,
480                const char *filename,
481                const char *content_type,
482                const char *transfer_encoding,
483                const char *data,
484                uint64_t off,
485                size_t size)
486 {
487   struct Request *request = cls;
488
489   (void) kind;
490   (void) filename;
491   (void) content_type;
492   (void) transfer_encoding;
493   if (0 == strcmp ("domain", key))
494     {
495       if (size + off >= sizeof(request->domain_name))
496         size = sizeof (request->domain_name) - off - 1;
497       GNUNET_memcpy (&request->domain_name[off],
498               data,
499               size);
500       request->domain_name[size+off] = '\0';
501       return MHD_YES;
502     }
503   if (0 == strcmp ("pkey", key))
504     {
505       if (size + off >= sizeof(request->public_key))
506         size = sizeof (request->public_key) - off - 1;
507       GNUNET_memcpy (&request->public_key[off],
508               data,
509               size);
510       request->public_key[size+off] = '\0';
511       return MHD_YES;
512     }
513   GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
514               _("Unsupported form value `%s'\n"),
515               key);
516   return MHD_YES;
517 }
518
519
520 /**
521  * Continuation called to notify client about result of the
522  * operation.
523  *
524  * @param cls closure
525  * @param success #GNUNET_SYSERR on failure (including timeout/queue drop/failure to validate)
526  *                #GNUNET_NO if content was already there
527  *                #GNUNET_YES (or other positive value) on success
528  * @param emsg NULL on success, otherwise an error message
529  */
530 static void
531 put_continuation (void *cls,
532                   int32_t success,
533                   const char *emsg)
534 {
535   struct Request *request = cls;
536
537   request->qe = NULL;
538   if (0 >= success)
539   {
540     GNUNET_log (GNUNET_ERROR_TYPE_WARNING,
541                 _("Failed to create record for domain `%s': %s\n"),
542                 request->domain_name,
543                 emsg);
544     request->phase = RP_FAIL;
545   }
546   else
547     request->phase = RP_SUCCESS;
548   run_httpd_now ();
549 }
550
551
552 /**
553  * Function called if we had an error in zone-to-name mapping.
554  */
555 static void
556 zone_to_name_error (void *cls)
557 {
558   struct Request *request = cls;
559
560   GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
561               _("Error when mapping zone to name\n"));
562   request->phase = RP_FAIL;
563   run_httpd_now ();
564 }
565
566
567 /**
568  * Test if a name mapping was found, if so, refuse.  If not, initiate storing of the record.
569  *
570  * @param cls closure
571  * @param zone_key public key of the zone
572  * @param name name that is being mapped (at most 255 characters long)
573  * @param rd_count number of entries in @a rd array
574  * @param rd array of records with data to store
575  */
576 static void
577 zone_to_name_cb (void *cls,
578                  const struct GNUNET_CRYPTO_EcdsaPrivateKey *zone_key,
579                  const char *name,
580                  unsigned int rd_count,
581                  const struct GNUNET_GNSRECORD_Data *rd)
582 {
583   struct Request *request = cls;
584   struct GNUNET_GNSRECORD_Data r;
585
586   request->qe = NULL;
587   if (0 != rd_count)
588   {
589     GNUNET_log (GNUNET_ERROR_TYPE_INFO,
590                 _("Found existing name `%s' for the given key\n"),
591                 name);
592     request->phase = RP_FAIL;
593     run_httpd_now ();
594     return;
595   }
596   r.data = &request->pub;
597   r.data_size = sizeof (request->pub);
598   r.expiration_time = UINT64_MAX;
599   r.record_type = GNUNET_GNSRECORD_TYPE_PKEY;
600   r.flags = GNUNET_GNSRECORD_RF_NONE;
601   request->qe = GNUNET_NAMESTORE_records_store (ns,
602                                                 &fcfs_zone_pkey,
603                                                 request->domain_name,
604                                                 1, &r,
605                                                 &put_continuation,
606                                                 request);
607 }
608
609
610 /**
611  * We encountered an error in the name lookup.
612  */
613 static void
614 lookup_block_error (void *cls)
615 {
616   struct Request *request = cls;
617
618   request->qe = NULL;
619   request->phase = RP_FAIL;
620   run_httpd_now ();
621 }
622
623
624 /**
625  * We got a block back from the namestore.  Decrypt it
626  * and continue to process the result.
627  *
628  * @param cls the 'struct Request' we are processing
629  * @param zone private key of the zone; NULL on disconnect
630  * @param label label of the records; NULL on disconnect
631  * @param rd_count number of entries in @a rd array, 0 if label was deleted
632  * @param rd array of records with data to store
633  */
634 static void
635 lookup_block_processor (void *cls,
636                         const struct GNUNET_CRYPTO_EcdsaPrivateKey *zone,
637                         const char *label,
638                         unsigned int rd_count,
639                         const struct GNUNET_GNSRECORD_Data *rd)
640 {
641   struct Request *request = cls;
642
643   request->qe = NULL;
644   if (0 == rd_count)
645   {
646     if (GNUNET_OK !=
647         GNUNET_CRYPTO_ecdsa_public_key_from_string (request->public_key,
648                                                     strlen (request->public_key),
649                                                     &request->pub))
650     {
651       GNUNET_break (0);
652       request->phase = RP_FAIL;
653       run_httpd_now ();
654       return;
655     }
656     request->qe = GNUNET_NAMESTORE_zone_to_name (ns,
657                                                  &fcfs_zone_pkey,
658                                                  &request->pub,
659                                                  &zone_to_name_error,
660                                                  request,
661                                                  &zone_to_name_cb,
662                                                  request);
663     return;
664   }
665   GNUNET_break (0 != rd_count);
666   GNUNET_log (GNUNET_ERROR_TYPE_INFO,
667               _("Found %u existing records for domain `%s'\n"),
668               rd_count,
669               request->domain_name);
670   request->phase = RP_FAIL;
671   run_httpd_now ();
672   return;
673 }
674
675
676 /**
677  * Main MHD callback for handling requests.
678  *
679  * @param cls unused
680  * @param connection MHD connection handle
681  * @param url the requested url
682  * @param method the HTTP method used ("GET", "PUT", etc.)
683  * @param version the HTTP version string (i.e. "HTTP/1.1")
684  * @param upload_data the data being uploaded (excluding HEADERS,
685  *        for a POST that fits into memory and that is encoded
686  *        with a supported encoding, the POST data will NOT be
687  *        given in upload_data and is instead available as
688  *        part of MHD_get_connection_values; very large POST
689  *        data *will* be made available incrementally in
690  *        upload_data)
691  * @param upload_data_size set initially to the size of the
692  *        @a upload_data provided; the method must update this
693  *        value to the number of bytes NOT processed;
694  * @param ptr pointer to location where we store the 'struct Request'
695  * @return MHD_YES if the connection was handled successfully,
696  *         MHD_NO if the socket must be closed due to a serious
697  *         error while handling the request
698  */
699 static int
700 create_response (void *cls,
701                  struct MHD_Connection *connection,
702                  const char *url,
703                  const char *method,
704                  const char *version,
705                  const char *upload_data,
706                  size_t *upload_data_size,
707                  void **ptr)
708 {
709   struct MHD_Response *response;
710   struct Request *request;
711   struct GNUNET_CRYPTO_EcdsaPublicKey pub;
712   int ret;
713
714   if ( (0 == strcmp (method, MHD_HTTP_METHOD_GET)) ||
715        (0 == strcmp (method, MHD_HTTP_METHOD_HEAD)) )
716     {
717       if (0 == strcmp (url, FCFS_ZONEINFO_URL))
718         ret = serve_zoneinfo_page (connection);
719       else
720         ret = serve_main_page (connection);
721       if (ret != MHD_YES)
722         GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
723                     _("Failed to create page for `%s'\n"),
724                     url);
725       return ret;
726     }
727   if (0 == strcmp (method, MHD_HTTP_METHOD_POST))
728     {
729       request = *ptr;
730       if (NULL == request)
731       {
732         request = GNUNET_new (struct Request);
733         *ptr = request;
734         request->pp = MHD_create_post_processor (connection,
735                                                  1024,
736                                                  &post_iterator,
737                                                  request);
738         if (NULL == request->pp)
739           {
740             GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
741                         _("Failed to setup post processor for `%s'\n"),
742                         url);
743             return MHD_NO; /* internal error */
744           }
745         return MHD_YES;
746       }
747       if (NULL != request->pp)
748       {
749         /* evaluate POST data */
750         MHD_post_process (request->pp,
751                           upload_data,
752                           *upload_data_size);
753         if (0 != *upload_data_size)
754           {
755             *upload_data_size = 0;
756             return MHD_YES;
757           }
758         /* done with POST data, serve response */
759         MHD_destroy_post_processor (request->pp);
760         request->pp = NULL;
761       }
762       if (GNUNET_OK !=
763           GNUNET_CRYPTO_ecdsa_public_key_from_string (request->public_key,
764                                                       strlen (request->public_key),
765                                                       &pub))
766       {
767         /* parse error */
768         return fill_s_reply ("Failed to parse given public key",
769                              request, connection);
770       }
771       switch (request->phase)
772         {
773         case RP_START:
774           if (NULL != strchr (request->domain_name, (int) '.'))
775           {
776             GNUNET_log (GNUNET_ERROR_TYPE_INFO,
777                         _("Domain name must not contain `.'\n"));
778             request->phase = RP_FAIL;
779             return fill_s_reply ("Domain name must not contain `.', sorry.",
780                                  request,
781                                  connection);
782           }
783           if (NULL != strchr (request->domain_name, (int) '+'))
784           {
785             GNUNET_log (GNUNET_ERROR_TYPE_INFO,
786                         _("Domain name must not contain `+'\n"));
787             request->phase = RP_FAIL;
788             return fill_s_reply ("Domain name must not contain `+', sorry.",
789                                  request, connection);
790           }
791           request->phase = RP_LOOKUP;
792           request->qe
793             = GNUNET_NAMESTORE_records_lookup (ns,
794                                                &fcfs_zone_pkey,
795                                                request->domain_name,
796                                                &lookup_block_error,
797                                                request,
798                                                &lookup_block_processor,
799                                                request);
800           break;
801         case RP_LOOKUP:
802           break;
803         case RP_PUT:
804           break;
805         case RP_FAIL:
806           return fill_s_reply ("Request failed, sorry.",
807                                request, connection);
808         case RP_SUCCESS:
809           return fill_s_reply ("Success.",
810                                request, connection);
811         default:
812           GNUNET_break (0);
813           return MHD_NO;
814         }
815         return MHD_YES; /* will have a reply later... */
816     }
817   /* unsupported HTTP method */
818   response = MHD_create_response_from_buffer (strlen (METHOD_ERROR),
819                                               (void *) METHOD_ERROR,
820                                               MHD_RESPMEM_PERSISTENT);
821   ret = MHD_queue_response (connection,
822                             MHD_HTTP_NOT_ACCEPTABLE,
823                             response);
824   MHD_destroy_response (response);
825   return ret;
826 }
827
828
829 /**
830  * Callback called upon completion of a request.
831  * Decrements session reference counter.
832  *
833  * @param cls not used
834  * @param connection connection that completed
835  * @param con_cls session handle
836  * @param toe status code
837  */
838 static void
839 request_completed_callback (void *cls,
840                             struct MHD_Connection *connection,
841                             void **con_cls,
842                             enum MHD_RequestTerminationCode toe)
843 {
844   struct Request *request = *con_cls;
845
846   (void) cls;
847   (void) connection;
848   (void) toe;
849   if (NULL == request)
850     return;
851   if (NULL != request->pp)
852     MHD_destroy_post_processor (request->pp);
853   if (NULL != request->qe)
854     GNUNET_NAMESTORE_cancel (request->qe);
855   GNUNET_free (request);
856 }
857
858
859 #define UNSIGNED_MHD_LONG_LONG unsigned MHD_LONG_LONG
860
861
862 /**
863  * Schedule tasks to run MHD server.
864  */
865 static void
866 run_httpd ()
867 {
868   fd_set rs;
869   fd_set ws;
870   fd_set es;
871   struct GNUNET_NETWORK_FDSet *wrs;
872   struct GNUNET_NETWORK_FDSet *wws;
873   struct GNUNET_NETWORK_FDSet *wes;
874   int max;
875   int haveto;
876   UNSIGNED_MHD_LONG_LONG timeout;
877   struct GNUNET_TIME_Relative tv;
878
879   FD_ZERO (&rs);
880   FD_ZERO (&ws);
881   FD_ZERO (&es);
882   wrs = GNUNET_NETWORK_fdset_create ();
883   wes = GNUNET_NETWORK_fdset_create ();
884   wws = GNUNET_NETWORK_fdset_create ();
885   max = -1;
886   GNUNET_assert (MHD_YES ==
887                  MHD_get_fdset (httpd,
888                                 &rs,
889                                 &ws,
890                                 &es,
891                                 &max));
892   haveto = MHD_get_timeout (httpd,
893                             &timeout);
894   if (haveto == MHD_YES)
895     tv.rel_value_us = (uint64_t) timeout * 1000LL;
896   else
897     tv = GNUNET_TIME_UNIT_FOREVER_REL;
898   GNUNET_NETWORK_fdset_copy_native (wrs,
899                                     &rs,
900                                     max + 1);
901   GNUNET_NETWORK_fdset_copy_native (wws,
902                                     &ws,
903                                     max + 1);
904   GNUNET_NETWORK_fdset_copy_native (wes,
905                                     &es,
906                                     max + 1);
907   httpd_task =
908       GNUNET_SCHEDULER_add_select (GNUNET_SCHEDULER_PRIORITY_HIGH,
909                                    tv,
910                                    wrs,
911                                    wws,
912                                    &do_httpd,
913                                    NULL);
914   GNUNET_NETWORK_fdset_destroy (wrs);
915   GNUNET_NETWORK_fdset_destroy (wws);
916   GNUNET_NETWORK_fdset_destroy (wes);
917 }
918
919
920 /**
921  * Task run whenever HTTP server operations are pending.
922  *
923  * @param cls unused
924  */
925 static void
926 do_httpd (void *cls)
927 {
928   (void) cls;
929   httpd_task = NULL;
930   MHD_run (httpd);
931   run_httpd ();
932 }
933
934
935 /**
936  * Task run on shutdown.  Cleans up everything.
937  *
938  * @param cls unused
939  */
940 static void
941 do_shutdown (void *cls)
942 {
943   (void) cls;
944   if (NULL != httpd_task)
945   {
946     GNUNET_SCHEDULER_cancel (httpd_task);
947     httpd_task = NULL;
948   }
949   if (NULL != ns)
950   {
951     GNUNET_NAMESTORE_disconnect (ns);
952     ns = NULL;
953   }
954   if (NULL != httpd)
955   {
956     MHD_stop_daemon (httpd);
957     httpd = NULL;
958   }
959   if (NULL != id_op)
960   {
961     GNUNET_IDENTITY_cancel (id_op);
962     id_op = NULL;
963   }
964   if (NULL != identity)
965   {
966     GNUNET_IDENTITY_disconnect (identity);
967     identity = NULL;
968   }
969 }
970
971
972 /**
973  * Method called to inform about the egos of this peer.
974  *
975  * When used with #GNUNET_IDENTITY_create or #GNUNET_IDENTITY_get,
976  * this function is only called ONCE, and 'NULL' being passed in
977  * @a ego does indicate an error (i.e. name is taken or no default
978  * value is known).  If @a ego is non-NULL and if '*ctx'
979  * is set in those callbacks, the value WILL be passed to a subsequent
980  * call to the identity callback of #GNUNET_IDENTITY_connect (if
981  * that one was not NULL).
982  *
983  * @param cls closure, NULL
984  * @param ego ego handle
985  * @param ctx context for application to store data for this ego
986  *                 (during the lifetime of this process, initially NULL)
987  * @param name name assigned by the user for this ego,
988  *                   NULL if the user just deleted the ego and it
989  *                   must thus no longer be used
990  */
991 static void
992 identity_cb (void *cls,
993              struct GNUNET_IDENTITY_Ego *ego,
994              void **ctx,
995              const char *name)
996 {
997   int options;
998
999   (void) cls;
1000   (void) ctx;
1001   (void) name;
1002   id_op = NULL;
1003   if (NULL == ego)
1004   {
1005     GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
1006                 _("No ego configured for `fcfsd` subsystem\n"));
1007     return;
1008   }
1009   fcfs_zone_pkey = *GNUNET_IDENTITY_ego_get_private_key (ego);
1010
1011   options = MHD_USE_DUAL_STACK | MHD_USE_DEBUG;
1012   do
1013     {
1014       httpd = MHD_start_daemon (options,
1015                                 (uint16_t) port,
1016                                 NULL, NULL,
1017                                 &create_response, NULL,
1018                                 MHD_OPTION_CONNECTION_LIMIT, (unsigned int) 128,
1019                                 MHD_OPTION_PER_IP_CONNECTION_LIMIT, (unsigned int) 1,
1020                                 MHD_OPTION_CONNECTION_TIMEOUT, (unsigned int) 16,
1021                                 MHD_OPTION_CONNECTION_MEMORY_LIMIT, (size_t) (4 * 1024),
1022                                 MHD_OPTION_NOTIFY_COMPLETED, &request_completed_callback, NULL,
1023                                 MHD_OPTION_END);
1024       if (MHD_USE_DEBUG == options)
1025         break;
1026       options = MHD_USE_DEBUG;
1027     }
1028   while (NULL == httpd);
1029   if (NULL == httpd)
1030   {
1031     GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
1032                 _("Failed to start HTTP server\n"));
1033     GNUNET_SCHEDULER_shutdown ();
1034     return;
1035   }
1036   run_httpd ();
1037 }
1038
1039
1040 /**
1041  * Main function that will be run.
1042  *
1043  * @param cls closure
1044  * @param args remaining command-line arguments
1045  * @param cfgfile name of the configuration file used (for saving, can be NULL!)
1046  * @param cfg configuration
1047  */
1048 static void
1049 run (void *cls,
1050      char *const *args,
1051      const char *cfgfile,
1052      const struct GNUNET_CONFIGURATION_Handle *cfg)
1053 {
1054   (void) cls;
1055   (void) args;
1056   (void) cfgfile;
1057   if (GNUNET_OK !=
1058       GNUNET_CONFIGURATION_get_value_number (cfg,
1059                                              "fcfsd",
1060                                              "HTTPPORT",
1061                                              &port))
1062   {
1063     GNUNET_log_config_missing (GNUNET_ERROR_TYPE_ERROR,
1064                                "fcfsd", "HTTPPORT");
1065     return;
1066   }
1067   ns = GNUNET_NAMESTORE_connect (cfg);
1068   if (NULL == ns)
1069     {
1070       GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
1071                   _("Failed to connect to namestore\n"));
1072       return;
1073     }
1074   identity = GNUNET_IDENTITY_connect (cfg,
1075                                       NULL, NULL);
1076   if (NULL == identity)
1077   {
1078     GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
1079                 _("Failed to connect to identity\n"));
1080     return;
1081   }
1082   id_op = GNUNET_IDENTITY_get (identity, "fcfsd",
1083                                &identity_cb, NULL);
1084   GNUNET_SCHEDULER_add_shutdown (&do_shutdown, NULL);
1085 }
1086
1087
1088 /**
1089  * The main function for the fcfs daemon.
1090  *
1091  * @param argc number of arguments from the command line
1092  * @param argv command line arguments
1093  * @return 0 ok, 1 on error
1094  */
1095 int
1096 main (int argc,
1097       char *const *argv)
1098 {
1099   static const struct GNUNET_GETOPT_CommandLineOption options[] = {
1100     GNUNET_GETOPT_OPTION_END
1101   };
1102   int ret;
1103
1104   if (GNUNET_OK !=
1105       GNUNET_STRINGS_get_utf8_args (argc, argv,
1106                                     &argc, &argv))
1107     return 2;
1108
1109   GNUNET_log_setup ("fcfsd",
1110                     "WARNING",
1111                     NULL);
1112   ret =
1113       (GNUNET_OK ==
1114        GNUNET_PROGRAM_run (argc,
1115                            argv,
1116                            "gnunet-namestore-fcfsd",
1117                            _("GNU Name System First Come First Serve name registration service"),
1118                            options,
1119                            &run, NULL)) ? 0 : 1;
1120   GNUNET_free ((void*) argv);
1121   GNUNET_CRYPTO_ecdsa_key_clear (&fcfs_zone_pkey);
1122   return ret;
1123 }
1124
1125 /* end of gnunet-namestore-fcfsd.c */