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