2 This file is part of GNUnet.
3 Copyright (C) 2012-2014 GNUnet e.V.
5 GNUnet is free software: you can redistribute it and/or modify it
6 under the terms of the GNU Affero General Public License as published
7 by the Free Software Foundation, either version 3 of the License,
8 or (at your option) any later version.
10 GNUnet is distributed in the hope that it will be useful, but
11 WITHOUT ANY WARRANTY; without even the implied warranty of
12 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
13 Affero General Public License for more details.
16 * @file gnunet-namestore-fcfsd.c
17 * @brief HTTP daemon that offers first-come-first-serve GNS domain registration
18 * @author Christian Grothoff
21 * - need to track active zone info requests so we can cancel them
22 * during shutdown, right?
23 * - the code currently contains a 'race' between checking that the
24 * domain name is available and allocating it to the new public key
25 * (should this race be solved by namestore or by fcfsd?)
26 * - nicer error reporting to browser
29 #include <microhttpd.h>
30 #include "gnunet_util_lib.h"
31 #include "gnunet_identity_service.h"
32 #include "gnunet_gnsrecord_lib.h"
33 #include "gnunet_namestore_service.h"
36 * Invalid method page.
38 #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 #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 #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>"
51 * Fcfs zoneinfo page (/Zoneinfo)
53 #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 #define FCFS_ZONEINFO_URL "/Zoneinfo"
58 * Mime type for HTML pages.
60 #define MIME_HTML "text/html"
65 #define COOKIE_NAME "namestore-fcfsd"
67 #define DEFAULT_ZONEINFO_BUFSIZE 2048
70 * Phases a request goes through.
75 * Start phase (parsing POST, checking).
80 * Lookup to see if the domain name is taken.
85 * Storing of the record.
90 * We're done with success.
95 * Send failure message.
102 * Data kept per request.
108 * Associated session.
110 // FIXME: struct Session *session;
113 * Post processor handling form data (IF this is
116 struct MHD_PostProcessor *pp;
119 * URL to serve in response to this POST (if this request
122 const char *post_url;
125 * Active request with the namestore.
127 struct GNUNET_NAMESTORE_QueueEntry *qe;
130 * Active iteration with the namestore.
132 struct GNUNET_NAMESTORE_ZoneIterator *zi;
135 * Current processing phase.
140 * Domain name submitted via form.
142 char domain_name[64];
145 * Public key submitted via form.
147 char public_key[128];
149 struct GNUNET_CRYPTO_EcdsaPublicKey pub;
156 struct ZoneinfoRequest
161 struct MHD_Connection *connection;
166 struct GNUNET_NAMESTORE_ZoneIterator *list_it;
179 * Buffer write offset
185 * MHD deamon reference.
187 static struct MHD_Daemon *httpd;
192 static struct GNUNET_SCHEDULER_Task * httpd_task;
195 * Handle to the namestore.
197 static struct GNUNET_NAMESTORE_Handle *ns;
200 * Private key for the fcfsd zone.
202 static struct GNUNET_CRYPTO_EcdsaPrivateKey fcfs_zone_pkey;
205 * Connection to identity service.
207 static struct GNUNET_IDENTITY_Handle *identity;
210 * Request for our ego.
212 static struct GNUNET_IDENTITY_Operation *id_op;
215 * Port we use for the HTTP server.
217 static unsigned long long port;
220 * Name of the zone we manage.
226 * Task run whenever HTTP server operations are pending.
231 do_httpd (void *cls);
235 * Schedule task to run MHD server now.
240 if (NULL != httpd_task)
242 GNUNET_SCHEDULER_cancel (httpd_task);
245 httpd_task = GNUNET_SCHEDULER_add_now (&do_httpd, NULL);
250 * Function called on error in zone iteration.
253 zone_iteration_error (void *cls)
255 struct ZoneinfoRequest *zr = cls;
256 struct MHD_Response *response;
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,
265 MHD_destroy_response (response);
266 GNUNET_free (zr->zoneinfo);
273 * Function called once the zone iteration is done.
276 zone_iteration_end (void *cls)
278 struct ZoneinfoRequest *zr = cls;
279 struct MHD_Response *response;
284 /* return static form */
285 GNUNET_asprintf (&full_page,
289 response = MHD_create_response_from_buffer (strlen (full_page),
291 MHD_RESPMEM_MUST_FREE);
292 MHD_add_response_header (response,
293 MHD_HTTP_HEADER_CONTENT_TYPE,
295 MHD_queue_response (zr->connection,
298 MHD_destroy_response (response);
299 GNUNET_free (zr->zoneinfo);
306 * Process a record that was stored in the namestore, adding
307 * the information to the HTML.
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
316 iterate_cb (void *cls,
317 const struct GNUNET_CRYPTO_EcdsaPrivateKey *zone_key,
320 const struct GNUNET_GNSRECORD_Data *rd)
322 struct ZoneinfoRequest *zr = cls;
330 GNUNET_NAMESTORE_zone_iterator_next (zr->list_it,
335 if (GNUNET_GNSRECORD_TYPE_PKEY != rd->record_type)
337 GNUNET_NAMESTORE_zone_iterator_next (zr->list_it,
342 bytes_free = zr->buf_len - zr->write_offset;
343 pkey = GNUNET_GNSRECORD_value_to_string (rd->record_type,
349 GNUNET_NAMESTORE_zone_iterator_next (zr->list_it,
353 if (bytes_free < (strlen (name) + strlen (pkey) + 40))
355 new_buf = GNUNET_malloc (zr->buf_len * 2);
356 GNUNET_memcpy (new_buf, zr->zoneinfo, zr->write_offset);
357 GNUNET_free (zr->zoneinfo);
358 zr->zoneinfo = new_buf;
361 sprintf (zr->zoneinfo + zr->write_offset,
362 "<tr><td>%s</td><td>%s</td></tr>",
365 zr->write_offset = strlen (zr->zoneinfo);
366 GNUNET_NAMESTORE_zone_iterator_next (zr->list_it,
373 * Handler that returns FCFS zoneinfo page.
375 * @param connection connection to use
376 * @return MHD_YES on success
379 serve_zoneinfo_page (struct MHD_Connection *connection)
381 struct ZoneinfoRequest *zr;
383 zr = GNUNET_new (struct ZoneinfoRequest);
384 zr->zoneinfo = GNUNET_malloc (DEFAULT_ZONEINFO_BUFSIZE);
385 zr->buf_len = DEFAULT_ZONEINFO_BUFSIZE;
386 zr->connection = connection;
387 zr->write_offset = 0;
388 zr->list_it = GNUNET_NAMESTORE_zone_iteration_start (ns,
390 &zone_iteration_error,
401 * Handler that returns a simple static HTTP page.
403 * @param connection connection to use
404 * @return MHD_YES on success
407 serve_main_page (struct MHD_Connection *connection)
410 struct MHD_Response *response;
412 /* return static form */
413 response = MHD_create_response_from_buffer (strlen (MAIN_PAGE),
415 MHD_RESPMEM_PERSISTENT);
416 MHD_add_response_header (response,
417 MHD_HTTP_HEADER_CONTENT_TYPE,
419 ret = MHD_queue_response (connection,
422 MHD_destroy_response (response);
428 * Send the 'SUBMIT_PAGE'.
430 * @param info information string to send to the user
431 * @param request request information
432 * @param connection connection to use
435 fill_s_reply (const char *info,
436 struct Request *request,
437 struct MHD_Connection *connection)
441 struct MHD_Response *response;
444 GNUNET_asprintf (&reply,
448 /* return static form */
449 response = MHD_create_response_from_buffer (strlen (reply),
451 MHD_RESPMEM_MUST_FREE);
452 MHD_add_response_header (response,
453 MHD_HTTP_HEADER_CONTENT_TYPE,
455 ret = MHD_queue_response (connection,
458 MHD_destroy_response (response);
464 * Iterator over key-value pairs where the value
465 * maybe made available in increments and/or may
466 * not be zero-terminated. Used for processing
469 * @param cls user-specified closure
470 * @param kind type of the value
471 * @param key 0-terminated key for the value
472 * @param filename name of the uploaded file, NULL if not known
473 * @param content_type mime-type of the data, NULL if not known
474 * @param transfer_encoding encoding of the data, NULL if not known
475 * @param data pointer to size bytes of data at the
477 * @param off offset of data in the overall value
478 * @param size number of bytes in data available
479 * @return MHD_YES to continue iterating,
480 * MHD_NO to abort the iteration
483 post_iterator (void *cls,
484 enum MHD_ValueKind kind,
486 const char *filename,
487 const char *content_type,
488 const char *transfer_encoding,
493 struct Request *request = cls;
498 (void) transfer_encoding;
499 if (0 == strcmp ("domain", key))
501 if (size + off >= sizeof(request->domain_name))
502 size = sizeof (request->domain_name) - off - 1;
503 GNUNET_memcpy (&request->domain_name[off],
506 request->domain_name[size+off] = '\0';
509 if (0 == strcmp ("pkey", key))
511 if (size + off >= sizeof(request->public_key))
512 size = sizeof (request->public_key) - off - 1;
513 GNUNET_memcpy (&request->public_key[off],
516 request->public_key[size+off] = '\0';
519 GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
520 _("Unsupported form value `%s'\n"),
527 * Continuation called to notify client about result of the
531 * @param success #GNUNET_SYSERR on failure (including timeout/queue drop/failure to validate)
532 * #GNUNET_NO if content was already there
533 * #GNUNET_YES (or other positive value) on success
534 * @param emsg NULL on success, otherwise an error message
537 put_continuation (void *cls,
541 struct Request *request = cls;
546 GNUNET_log (GNUNET_ERROR_TYPE_WARNING,
547 _("Failed to create record for domain `%s': %s\n"),
548 request->domain_name,
550 request->phase = RP_FAIL;
553 request->phase = RP_SUCCESS;
559 * Function called if we had an error in zone-to-name mapping.
562 zone_to_name_error (void *cls)
564 struct Request *request = cls;
566 GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
567 _("Error when mapping zone to name\n"));
568 request->phase = RP_FAIL;
574 * Test if a name mapping was found, if so, refuse. If not, initiate storing of the record.
577 * @param zone_key public key of the zone
578 * @param name name that is being mapped (at most 255 characters long)
579 * @param rd_count number of entries in @a rd array
580 * @param rd array of records with data to store
583 zone_to_name_cb (void *cls,
584 const struct GNUNET_CRYPTO_EcdsaPrivateKey *zone_key,
586 unsigned int rd_count,
587 const struct GNUNET_GNSRECORD_Data *rd)
589 struct Request *request = cls;
590 struct GNUNET_GNSRECORD_Data r;
597 GNUNET_log (GNUNET_ERROR_TYPE_INFO,
598 _("Found existing name `%s' for the given key\n"),
600 request->phase = RP_FAIL;
604 r.data = &request->pub;
605 r.data_size = sizeof (request->pub);
606 r.expiration_time = UINT64_MAX;
607 r.record_type = GNUNET_GNSRECORD_TYPE_PKEY;
608 r.flags = GNUNET_GNSRECORD_RF_NONE;
609 request->qe = GNUNET_NAMESTORE_records_store (ns,
611 request->domain_name,
619 * We encountered an error in the name lookup.
622 lookup_block_error (void *cls)
624 struct Request *request = cls;
627 request->phase = RP_FAIL;
633 * We got a block back from the namestore. Decrypt it
634 * and continue to process the result.
636 * @param cls the 'struct Request' we are processing
637 * @param zonekey private key of the zone; NULL on disconnect
638 * @param label label of the records; NULL on disconnect
639 * @param rd_count number of entries in @a rd array, 0 if label was deleted
640 * @param rd array of records with data to store
643 lookup_block_processor (void *cls,
644 const struct GNUNET_CRYPTO_EcdsaPrivateKey *zonekey,
646 unsigned int rd_count,
647 const struct GNUNET_GNSRECORD_Data *rd)
649 struct Request *request = cls;
658 GNUNET_CRYPTO_ecdsa_public_key_from_string (request->public_key,
659 strlen (request->public_key),
663 request->phase = RP_FAIL;
667 request->qe = GNUNET_NAMESTORE_zone_to_name (ns,
676 GNUNET_break (0 != rd_count);
677 GNUNET_log (GNUNET_ERROR_TYPE_INFO,
678 _("Found %u existing records for domain `%s'\n"),
680 request->domain_name);
681 request->phase = RP_FAIL;
688 * Main MHD callback for handling requests.
691 * @param connection MHD connection handle
692 * @param url the requested url
693 * @param method the HTTP method used ("GET", "PUT", etc.)
694 * @param version the HTTP version string (i.e. "HTTP/1.1")
695 * @param upload_data the data being uploaded (excluding HEADERS,
696 * for a POST that fits into memory and that is encoded
697 * with a supported encoding, the POST data will NOT be
698 * given in upload_data and is instead available as
699 * part of MHD_get_connection_values; very large POST
700 * data *will* be made available incrementally in
702 * @param upload_data_size set initially to the size of the
703 * @a upload_data provided; the method must update this
704 * value to the number of bytes NOT processed;
705 * @param ptr pointer to location where we store the 'struct Request'
706 * @return MHD_YES if the connection was handled successfully,
707 * MHD_NO if the socket must be closed due to a serious
708 * error while handling the request
711 create_response (void *cls,
712 struct MHD_Connection *connection,
716 const char *upload_data,
717 size_t *upload_data_size,
720 struct MHD_Response *response;
721 struct Request *request;
722 struct GNUNET_CRYPTO_EcdsaPublicKey pub;
727 if ( (0 == strcmp (method, MHD_HTTP_METHOD_GET)) ||
728 (0 == strcmp (method, MHD_HTTP_METHOD_HEAD)) )
730 if (0 == strcmp (url, FCFS_ZONEINFO_URL))
731 ret = serve_zoneinfo_page (connection);
733 ret = serve_main_page (connection);
735 GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
736 _("Failed to create page for `%s'\n"),
740 if (0 == strcmp (method, MHD_HTTP_METHOD_POST))
745 request = GNUNET_new (struct Request);
747 request->pp = MHD_create_post_processor (connection,
751 if (NULL == request->pp)
753 GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
754 _("Failed to setup post processor for `%s'\n"),
756 return MHD_NO; /* internal error */
760 if (NULL != request->pp)
762 /* evaluate POST data */
763 MHD_post_process (request->pp,
766 if (0 != *upload_data_size)
768 *upload_data_size = 0;
771 /* done with POST data, serve response */
772 MHD_destroy_post_processor (request->pp);
776 GNUNET_CRYPTO_ecdsa_public_key_from_string (request->public_key,
777 strlen (request->public_key),
781 return fill_s_reply ("Failed to parse given public key",
782 request, connection);
784 switch (request->phase)
787 if (NULL != strchr (request->domain_name, (int) '.'))
789 GNUNET_log (GNUNET_ERROR_TYPE_INFO,
790 _("Domain name must not contain `.'\n"));
791 request->phase = RP_FAIL;
792 return fill_s_reply ("Domain name must not contain `.', sorry.",
796 if (NULL != strchr (request->domain_name, (int) '+'))
798 GNUNET_log (GNUNET_ERROR_TYPE_INFO,
799 _("Domain name must not contain `+'\n"));
800 request->phase = RP_FAIL;
801 return fill_s_reply ("Domain name must not contain `+', sorry.",
802 request, connection);
804 request->phase = RP_LOOKUP;
806 = GNUNET_NAMESTORE_records_lookup (ns,
808 request->domain_name,
811 &lookup_block_processor,
819 return fill_s_reply ("Request failed, sorry.",
820 request, connection);
822 return fill_s_reply ("Success.",
823 request, connection);
828 return MHD_YES; /* will have a reply later... */
830 /* unsupported HTTP method */
831 response = MHD_create_response_from_buffer (strlen (METHOD_ERROR),
832 (void *) METHOD_ERROR,
833 MHD_RESPMEM_PERSISTENT);
834 ret = MHD_queue_response (connection,
835 MHD_HTTP_NOT_ACCEPTABLE,
837 MHD_destroy_response (response);
843 * Callback called upon completion of a request.
844 * Decrements session reference counter.
846 * @param cls not used
847 * @param connection connection that completed
848 * @param con_cls session handle
849 * @param toe status code
852 request_completed_callback (void *cls,
853 struct MHD_Connection *connection,
855 enum MHD_RequestTerminationCode toe)
857 struct Request *request = *con_cls;
864 if (NULL != request->pp)
865 MHD_destroy_post_processor (request->pp);
866 if (NULL != request->qe)
867 GNUNET_NAMESTORE_cancel (request->qe);
868 GNUNET_free (request);
872 #define UNSIGNED_MHD_LONG_LONG unsigned MHD_LONG_LONG
876 * Schedule tasks to run MHD server.
884 struct GNUNET_NETWORK_FDSet *wrs;
885 struct GNUNET_NETWORK_FDSet *wws;
886 struct GNUNET_NETWORK_FDSet *wes;
889 UNSIGNED_MHD_LONG_LONG timeout;
890 struct GNUNET_TIME_Relative tv;
895 wrs = GNUNET_NETWORK_fdset_create ();
896 wes = GNUNET_NETWORK_fdset_create ();
897 wws = GNUNET_NETWORK_fdset_create ();
899 GNUNET_assert (MHD_YES ==
900 MHD_get_fdset (httpd,
905 haveto = MHD_get_timeout (httpd,
907 if (haveto == MHD_YES)
908 tv.rel_value_us = (uint64_t) timeout * 1000LL;
910 tv = GNUNET_TIME_UNIT_FOREVER_REL;
911 GNUNET_NETWORK_fdset_copy_native (wrs,
914 GNUNET_NETWORK_fdset_copy_native (wws,
917 GNUNET_NETWORK_fdset_copy_native (wes,
921 GNUNET_SCHEDULER_add_select (GNUNET_SCHEDULER_PRIORITY_HIGH,
927 GNUNET_NETWORK_fdset_destroy (wrs);
928 GNUNET_NETWORK_fdset_destroy (wws);
929 GNUNET_NETWORK_fdset_destroy (wes);
934 * Task run whenever HTTP server operations are pending.
949 * Task run on shutdown. Cleans up everything.
954 do_shutdown (void *cls)
957 if (NULL != httpd_task)
959 GNUNET_SCHEDULER_cancel (httpd_task);
964 GNUNET_NAMESTORE_disconnect (ns);
969 MHD_stop_daemon (httpd);
974 GNUNET_IDENTITY_cancel (id_op);
977 if (NULL != identity)
979 GNUNET_IDENTITY_disconnect (identity);
986 * Method called to inform about the egos of this peer.
988 * When used with #GNUNET_IDENTITY_create or #GNUNET_IDENTITY_get,
989 * this function is only called ONCE, and 'NULL' being passed in
990 * @a ego does indicate an error (i.e. name is taken or no default
991 * value is known). If @a ego is non-NULL and if '*ctx'
992 * is set in those callbacks, the value WILL be passed to a subsequent
993 * call to the identity callback of #GNUNET_IDENTITY_connect (if
994 * that one was not NULL).
996 * @param cls closure, NULL
997 * @param ego ego handle
998 * @param ctx context for application to store data for this ego
999 * (during the lifetime of this process, initially NULL)
1000 * @param name name assigned by the user for this ego,
1001 * NULL if the user just deleted the ego and it
1002 * must thus no longer be used
1005 identity_cb (void *cls,
1006 struct GNUNET_IDENTITY_Ego *ego,
1016 if (0 != strcmp (name,
1021 GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
1022 _("No ego configured for `fcfsd` subsystem\n"));
1023 GNUNET_SCHEDULER_shutdown ();
1026 fcfs_zone_pkey = *GNUNET_IDENTITY_ego_get_private_key (ego);
1028 options = MHD_USE_DUAL_STACK | MHD_USE_DEBUG;
1031 httpd = MHD_start_daemon (options,
1034 &create_response, NULL,
1035 MHD_OPTION_CONNECTION_LIMIT, (unsigned int) 128,
1036 MHD_OPTION_PER_IP_CONNECTION_LIMIT, (unsigned int) 1,
1037 MHD_OPTION_CONNECTION_TIMEOUT, (unsigned int) 16,
1038 MHD_OPTION_CONNECTION_MEMORY_LIMIT, (size_t) (4 * 1024),
1039 MHD_OPTION_NOTIFY_COMPLETED, &request_completed_callback, NULL,
1041 if (MHD_USE_DEBUG == options)
1043 options = MHD_USE_DEBUG;
1045 while (NULL == httpd);
1048 GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
1049 _("Failed to start HTTP server\n"));
1050 GNUNET_SCHEDULER_shutdown ();
1058 * Main function that will be run.
1060 * @param cls closure
1061 * @param args remaining command-line arguments
1062 * @param cfgfile name of the configuration file used (for saving, can be NULL!)
1063 * @param cfg configuration
1068 const char *cfgfile,
1069 const struct GNUNET_CONFIGURATION_Handle *cfg)
1075 GNUNET_CONFIGURATION_get_value_number (cfg,
1080 GNUNET_log_config_missing (GNUNET_ERROR_TYPE_ERROR,
1081 "fcfsd", "HTTPPORT");
1084 ns = GNUNET_NAMESTORE_connect (cfg);
1087 GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
1088 _("Failed to connect to namestore\n"));
1091 identity = GNUNET_IDENTITY_connect (cfg,
1094 if (NULL == identity)
1096 GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
1097 _("Failed to connect to identity\n"));
1100 GNUNET_SCHEDULER_add_shutdown (&do_shutdown,
1106 * The main function for the fcfs daemon.
1108 * @param argc number of arguments from the command line
1109 * @param argv command line arguments
1110 * @return 0 ok, 1 on error
1116 struct GNUNET_GETOPT_CommandLineOption options[] = {
1117 GNUNET_GETOPT_option_mandatory
1118 (GNUNET_GETOPT_option_string ('z',
1121 gettext_noop ("name of the zone that is to be managed by FCFSD"),
1123 GNUNET_GETOPT_OPTION_END
1128 GNUNET_STRINGS_get_utf8_args (argc, argv,
1132 GNUNET_log_setup ("fcfsd",
1137 GNUNET_PROGRAM_run (argc,
1139 "gnunet-namestore-fcfsd",
1140 _("GNU Name System First Come First Serve name registration service"),
1142 &run, NULL)) ? 0 : 1;
1143 GNUNET_free ((void*) argv);
1144 GNUNET_CRYPTO_ecdsa_key_clear (&fcfs_zone_pkey);
1148 /* end of gnunet-namestore-fcfsd.c */