2 This file is part of GNUnet.
3 Copyright (C) 2012-2014 Christian Grothoff (and other contributing authors)
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.
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.
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.
21 * @file gnunet-namestore-fcfsd.c
22 * @brief HTTP daemon that offers first-come-first-serve GNS domain registration
23 * @author Christian Grothoff
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
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"
41 * Invalid method page.
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>"
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>"
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>"
56 * Fcfs zoneinfo page (/Zoneinfo)
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>"
60 #define FCFS_ZONEINFO_URL "/Zoneinfo"
63 * Mime type for HTML pages.
65 #define MIME_HTML "text/html"
70 #define COOKIE_NAME "namestore-fcfsd"
72 #define DEFAULT_ZONEINFO_BUFSIZE 2048
75 * Phases a request goes through.
80 * Start phase (parsing POST, checking).
85 * Lookup to see if the domain name is taken.
90 * Storing of the record.
95 * We're done with success.
100 * Send failure message.
107 * Data kept per request.
113 * Associated session.
115 // FIXME: struct Session *session;
118 * Post processor handling form data (IF this is
121 struct MHD_PostProcessor *pp;
124 * URL to serve in response to this POST (if this request
127 const char *post_url;
130 * Active request with the namestore.
132 struct GNUNET_NAMESTORE_QueueEntry *qe;
135 * Active iteration with the namestore.
137 struct GNUNET_NAMESTORE_ZoneIterator *zi;
140 * Current processing phase.
145 * Domain name submitted via form.
147 char domain_name[64];
150 * Public key submitted via form.
152 char public_key[128];
154 struct GNUNET_CRYPTO_EcdsaPublicKey pub;
161 struct ZoneinfoRequest
166 struct MHD_Connection *connection;
171 struct GNUNET_NAMESTORE_ZoneIterator *list_it;
184 * Buffer write offset
190 * MHD deamon reference.
192 static struct MHD_Daemon *httpd;
197 static struct GNUNET_SCHEDULER_Task * httpd_task;
200 * Handle to the namestore.
202 static struct GNUNET_NAMESTORE_Handle *ns;
205 * Private key for the fcfsd zone.
207 static struct GNUNET_CRYPTO_EcdsaPrivateKey fcfs_zone_pkey;
210 * Connection to identity service.
212 static struct GNUNET_IDENTITY_Handle *identity;
215 * Request for our ego.
217 static struct GNUNET_IDENTITY_Operation *id_op;
220 * Port we use for the HTTP server.
222 static unsigned long long port;
226 * Task run whenever HTTP server operations are pending.
229 * @param tc scheduler context
233 const struct GNUNET_SCHEDULER_TaskContext *tc);
237 * Schedule task to run MHD server now.
242 if (NULL != httpd_task)
244 GNUNET_SCHEDULER_cancel (httpd_task);
247 httpd_task = GNUNET_SCHEDULER_add_now (&do_httpd, NULL);
252 * Process a record that was stored in the namestore, adding
253 * the information to the HTML.
255 * @param cls closure with the `struct ZoneinfoRequest *`
256 * @param zone_key private key of the zone; NULL on disconnect
257 * @param name label of the records; NULL on disconnect
258 * @param rd_len number of entries in @a rd array, 0 if label was deleted
259 * @param rd array of records with data to store
262 iterate_cb (void *cls,
263 const struct GNUNET_CRYPTO_EcdsaPrivateKey *zone_key,
266 const struct GNUNET_GNSRECORD_Data *rd)
268 struct ZoneinfoRequest *zr = cls;
269 struct MHD_Response *response;
280 /* return static form */
281 GNUNET_asprintf (&full_page,
285 response = MHD_create_response_from_buffer (strlen (full_page),
287 MHD_RESPMEM_MUST_FREE);
288 MHD_add_response_header (response,
289 MHD_HTTP_HEADER_CONTENT_TYPE,
291 MHD_queue_response (zr->connection,
294 MHD_destroy_response (response);
295 GNUNET_free (zr->zoneinfo);
303 GNUNET_NAMESTORE_zone_iterator_next (zr->list_it);
307 if (GNUNET_GNSRECORD_TYPE_PKEY != rd->record_type)
309 GNUNET_NAMESTORE_zone_iterator_next (zr->list_it);
313 bytes_free = zr->buf_len - zr->write_offset;
314 pkey = GNUNET_GNSRECORD_value_to_string (rd->record_type,
320 GNUNET_NAMESTORE_zone_iterator_next (zr->list_it);
323 if (bytes_free < (strlen (name) + strlen (pkey) + 40))
325 new_buf = GNUNET_malloc (zr->buf_len * 2);
326 memcpy (new_buf, zr->zoneinfo, zr->write_offset);
327 GNUNET_free (zr->zoneinfo);
328 zr->zoneinfo = new_buf;
331 sprintf (zr->zoneinfo + zr->write_offset,
332 "<tr><td>%s</td><td>%s</td></tr>",
335 zr->write_offset = strlen (zr->zoneinfo);
336 GNUNET_NAMESTORE_zone_iterator_next (zr->list_it);
342 * Handler that returns FCFS zoneinfo page.
344 * @param connection connection to use
345 * @return MHD_YES on success
348 serve_zoneinfo_page (struct MHD_Connection *connection)
350 struct ZoneinfoRequest *zr;
352 zr = GNUNET_new (struct ZoneinfoRequest);
353 zr->zoneinfo = GNUNET_malloc (DEFAULT_ZONEINFO_BUFSIZE);
354 zr->buf_len = DEFAULT_ZONEINFO_BUFSIZE;
355 zr->connection = connection;
356 zr->write_offset = 0;
357 zr->list_it = GNUNET_NAMESTORE_zone_iteration_start (ns,
366 * Handler that returns a simple static HTTP page.
368 * @param connection connection to use
369 * @return MHD_YES on success
372 serve_main_page (struct MHD_Connection *connection)
375 struct MHD_Response *response;
377 /* return static form */
378 response = MHD_create_response_from_buffer (strlen (MAIN_PAGE),
380 MHD_RESPMEM_PERSISTENT);
381 MHD_add_response_header (response,
382 MHD_HTTP_HEADER_CONTENT_TYPE,
384 ret = MHD_queue_response (connection,
387 MHD_destroy_response (response);
393 * Send the 'SUBMIT_PAGE'.
395 * @param info information string to send to the user
396 * @param request request information
397 * @param connection connection to use
400 fill_s_reply (const char *info,
401 struct Request *request,
402 struct MHD_Connection *connection)
406 struct MHD_Response *response;
408 GNUNET_asprintf (&reply,
412 /* return static form */
413 response = MHD_create_response_from_buffer (strlen (reply),
415 MHD_RESPMEM_MUST_FREE);
416 MHD_add_response_header (response,
417 MHD_HTTP_HEADER_CONTENT_TYPE,
419 ret = MHD_queue_response (connection,
422 MHD_destroy_response (response);
428 * Iterator over key-value pairs where the value
429 * maybe made available in increments and/or may
430 * not be zero-terminated. Used for processing
433 * @param cls user-specified closure
434 * @param kind type of the value
435 * @param key 0-terminated key for the value
436 * @param filename name of the uploaded file, NULL if not known
437 * @param content_type mime-type of the data, NULL if not known
438 * @param transfer_encoding encoding of the data, NULL if not known
439 * @param data pointer to size bytes of data at the
441 * @param off offset of data in the overall value
442 * @param size number of bytes in data available
443 * @return MHD_YES to continue iterating,
444 * MHD_NO to abort the iteration
447 post_iterator (void *cls,
448 enum MHD_ValueKind kind,
450 const char *filename,
451 const char *content_type,
452 const char *transfer_encoding,
453 const char *data, uint64_t off, size_t size)
455 struct Request *request = cls;
457 if (0 == strcmp ("domain", key))
459 if (size + off >= sizeof(request->domain_name))
460 size = sizeof (request->domain_name) - off - 1;
461 memcpy (&request->domain_name[off],
464 request->domain_name[size+off] = '\0';
467 if (0 == strcmp ("pkey", key))
469 if (size + off >= sizeof(request->public_key))
470 size = sizeof (request->public_key) - off - 1;
471 memcpy (&request->public_key[off],
474 request->public_key[size+off] = '\0';
477 GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
478 _("Unsupported form value `%s'\n"),
485 * Continuation called to notify client about result of the
489 * @param success #GNUNET_SYSERR on failure (including timeout/queue drop/failure to validate)
490 * #GNUNET_NO if content was already there
491 * #GNUNET_YES (or other positive value) on success
492 * @param emsg NULL on success, otherwise an error message
495 put_continuation (void *cls,
499 struct Request *request = cls;
504 GNUNET_log (GNUNET_ERROR_TYPE_WARNING,
505 _("Failed to create record for domain `%s': %s\n"),
506 request->domain_name,
508 request->phase = RP_FAIL;
511 request->phase = RP_SUCCESS;
517 * Test if a name mapping was found, if so, refuse. If not, initiate storing of the record.
520 * @param zone_key public key of the zone
521 * @param name name that is being mapped (at most 255 characters long)
522 * @param rd_count number of entries in @a rd array
523 * @param rd array of records with data to store
526 zone_to_name_cb (void *cls,
527 const struct GNUNET_CRYPTO_EcdsaPrivateKey *zone_key,
529 unsigned int rd_count,
530 const struct GNUNET_GNSRECORD_Data *rd)
532 struct Request *request = cls;
533 struct GNUNET_GNSRECORD_Data r;
538 GNUNET_log (GNUNET_ERROR_TYPE_INFO,
539 _("Found existing name `%s' for the given key\n"),
541 request->phase = RP_FAIL;
545 if (NULL == zone_key)
547 GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
548 _("Error when mapping zone to name\n"));
549 request->phase = RP_FAIL;
554 r.data = &request->pub;
555 r.data_size = sizeof (request->pub);
556 r.expiration_time = UINT64_MAX;
557 r.record_type = GNUNET_GNSRECORD_TYPE_PKEY;
558 r.flags = GNUNET_GNSRECORD_RF_NONE;
559 request->qe = GNUNET_NAMESTORE_records_store (ns,
561 request->domain_name,
569 * We got a block back from the namestore. Decrypt it
570 * and continue to process the result.
572 * @param cls the 'struct Request' we are processing
573 * @param zone private key of the zone; NULL on disconnect
574 * @param label label of the records; NULL on disconnect
575 * @param rd_count number of entries in @a rd array, 0 if label was deleted
576 * @param rd array of records with data to store
579 lookup_block_processor (void *cls,
580 const struct GNUNET_CRYPTO_EcdsaPrivateKey *zone,
582 unsigned int rd_count,
583 const struct GNUNET_GNSRECORD_Data *rd)
585 struct Request *request = cls;
592 GNUNET_CRYPTO_ecdsa_public_key_from_string (request->public_key,
593 strlen (request->public_key),
597 request->phase = RP_FAIL;
601 request->qe = GNUNET_NAMESTORE_zone_to_name (ns,
608 GNUNET_break (0 != rd_count);
609 GNUNET_log (GNUNET_ERROR_TYPE_INFO,
610 _("Found %u existing records for domain `%s'\n"),
612 request->domain_name);
613 request->phase = RP_FAIL;
620 * Main MHD callback for handling requests.
623 * @param connection MHD connection handle
624 * @param url the requested url
625 * @param method the HTTP method used ("GET", "PUT", etc.)
626 * @param version the HTTP version string (i.e. "HTTP/1.1")
627 * @param upload_data the data being uploaded (excluding HEADERS,
628 * for a POST that fits into memory and that is encoded
629 * with a supported encoding, the POST data will NOT be
630 * given in upload_data and is instead available as
631 * part of MHD_get_connection_values; very large POST
632 * data *will* be made available incrementally in
634 * @param upload_data_size set initially to the size of the
635 * @a upload_data provided; the method must update this
636 * value to the number of bytes NOT processed;
637 * @param ptr pointer to location where we store the 'struct Request'
638 * @return MHD_YES if the connection was handled successfully,
639 * MHD_NO if the socket must be closed due to a serious
640 * error while handling the request
643 create_response (void *cls,
644 struct MHD_Connection *connection,
648 const char *upload_data,
649 size_t *upload_data_size,
652 struct MHD_Response *response;
653 struct Request *request;
654 struct GNUNET_CRYPTO_EcdsaPublicKey pub;
657 if ( (0 == strcmp (method, MHD_HTTP_METHOD_GET)) ||
658 (0 == strcmp (method, MHD_HTTP_METHOD_HEAD)) )
660 if (0 == strcmp (url, FCFS_ZONEINFO_URL))
661 ret = serve_zoneinfo_page (connection);
663 ret = serve_main_page (connection);
665 GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
666 _("Failed to create page for `%s'\n"),
670 if (0 == strcmp (method, MHD_HTTP_METHOD_POST))
675 request = GNUNET_new (struct Request);
677 request->pp = MHD_create_post_processor (connection, 1024,
678 &post_iterator, request);
679 if (NULL == request->pp)
681 GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
682 _("Failed to setup post processor for `%s'\n"),
684 return MHD_NO; /* internal error */
688 if (NULL != request->pp)
690 /* evaluate POST data */
691 MHD_post_process (request->pp,
694 if (0 != *upload_data_size)
696 *upload_data_size = 0;
699 /* done with POST data, serve response */
700 MHD_destroy_post_processor (request->pp);
704 GNUNET_CRYPTO_ecdsa_public_key_from_string (request->public_key,
705 strlen (request->public_key),
709 return fill_s_reply ("Failed to parse given public key",
710 request, connection);
712 switch (request->phase)
715 if (NULL != strchr (request->domain_name, (int) '.'))
717 GNUNET_log (GNUNET_ERROR_TYPE_INFO,
718 _("Domain name must not contain `.'\n"));
719 request->phase = RP_FAIL;
720 return fill_s_reply ("Domain name must not contain `.', sorry.",
721 request, connection);
723 if (NULL != strchr (request->domain_name, (int) '+'))
725 GNUNET_log (GNUNET_ERROR_TYPE_INFO,
726 _("Domain name must not contain `+'\n"));
727 request->phase = RP_FAIL;
728 return fill_s_reply ("Domain name must not contain `+', sorry.",
729 request, connection);
731 request->phase = RP_LOOKUP;
732 request->qe = GNUNET_NAMESTORE_records_lookup (ns,
734 request->domain_name,
735 &lookup_block_processor,
743 return fill_s_reply ("Request failed, sorry.",
744 request, connection);
746 return fill_s_reply ("Success.",
747 request, connection);
752 return MHD_YES; /* will have a reply later... */
754 /* unsupported HTTP method */
755 response = MHD_create_response_from_buffer (strlen (METHOD_ERROR),
756 (void *) METHOD_ERROR,
757 MHD_RESPMEM_PERSISTENT);
758 ret = MHD_queue_response (connection,
759 MHD_HTTP_NOT_ACCEPTABLE,
761 MHD_destroy_response (response);
767 * Callback called upon completion of a request.
768 * Decrements session reference counter.
770 * @param cls not used
771 * @param connection connection that completed
772 * @param con_cls session handle
773 * @param toe status code
776 request_completed_callback (void *cls,
777 struct MHD_Connection *connection,
779 enum MHD_RequestTerminationCode toe)
781 struct Request *request = *con_cls;
785 if (NULL != request->pp)
786 MHD_destroy_post_processor (request->pp);
787 if (NULL != request->qe)
788 GNUNET_NAMESTORE_cancel (request->qe);
789 GNUNET_free (request);
793 #define UNSIGNED_MHD_LONG_LONG unsigned MHD_LONG_LONG
797 * Schedule tasks to run MHD server.
805 struct GNUNET_NETWORK_FDSet *wrs;
806 struct GNUNET_NETWORK_FDSet *wws;
807 struct GNUNET_NETWORK_FDSet *wes;
810 UNSIGNED_MHD_LONG_LONG timeout;
811 struct GNUNET_TIME_Relative tv;
816 wrs = GNUNET_NETWORK_fdset_create ();
817 wes = GNUNET_NETWORK_fdset_create ();
818 wws = GNUNET_NETWORK_fdset_create ();
820 GNUNET_assert (MHD_YES == MHD_get_fdset (httpd, &rs, &ws, &es, &max));
821 haveto = MHD_get_timeout (httpd, &timeout);
822 if (haveto == MHD_YES)
823 tv.rel_value_us = (uint64_t) timeout * 1000LL;
825 tv = GNUNET_TIME_UNIT_FOREVER_REL;
826 GNUNET_NETWORK_fdset_copy_native (wrs, &rs, max + 1);
827 GNUNET_NETWORK_fdset_copy_native (wws, &ws, max + 1);
828 GNUNET_NETWORK_fdset_copy_native (wes, &es, max + 1);
830 GNUNET_SCHEDULER_add_select (GNUNET_SCHEDULER_PRIORITY_HIGH,
833 GNUNET_NETWORK_fdset_destroy (wrs);
834 GNUNET_NETWORK_fdset_destroy (wws);
835 GNUNET_NETWORK_fdset_destroy (wes);
840 * Task run whenever HTTP server operations are pending.
843 * @param tc scheduler context
847 const struct GNUNET_SCHEDULER_TaskContext *tc)
856 * Task run on shutdown. Cleans up everything.
859 * @param tc scheduler context
862 do_shutdown (void *cls,
863 const struct GNUNET_SCHEDULER_TaskContext *tc)
865 if (NULL != httpd_task)
867 GNUNET_SCHEDULER_cancel (httpd_task);
872 GNUNET_NAMESTORE_disconnect (ns);
877 MHD_stop_daemon (httpd);
882 GNUNET_IDENTITY_cancel (id_op);
885 if (NULL != identity)
887 GNUNET_IDENTITY_disconnect (identity);
894 * Method called to inform about the egos of this peer.
896 * When used with #GNUNET_IDENTITY_create or #GNUNET_IDENTITY_get,
897 * this function is only called ONCE, and 'NULL' being passed in
898 * @a ego does indicate an error (i.e. name is taken or no default
899 * value is known). If @a ego is non-NULL and if '*ctx'
900 * is set in those callbacks, the value WILL be passed to a subsequent
901 * call to the identity callback of #GNUNET_IDENTITY_connect (if
902 * that one was not NULL).
904 * @param cls closure, NULL
905 * @param ego ego handle
906 * @param ctx context for application to store data for this ego
907 * (during the lifetime of this process, initially NULL)
908 * @param name name assigned by the user for this ego,
909 * NULL if the user just deleted the ego and it
910 * must thus no longer be used
913 identity_cb (void *cls,
914 struct GNUNET_IDENTITY_Ego *ego,
923 GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
924 _("No ego configured for `fcfsd` subsystem\n"));
927 fcfs_zone_pkey = *GNUNET_IDENTITY_ego_get_private_key (ego);
929 options = MHD_USE_DUAL_STACK | MHD_USE_DEBUG;
932 httpd = MHD_start_daemon (options,
935 &create_response, NULL,
936 MHD_OPTION_CONNECTION_LIMIT, (unsigned int) 128,
937 MHD_OPTION_PER_IP_CONNECTION_LIMIT, (unsigned int) 1,
938 MHD_OPTION_CONNECTION_TIMEOUT, (unsigned int) 16,
939 MHD_OPTION_CONNECTION_MEMORY_LIMIT, (size_t) (4 * 1024),
940 MHD_OPTION_NOTIFY_COMPLETED, &request_completed_callback, NULL,
942 if (MHD_USE_DEBUG == options)
944 options = MHD_USE_DEBUG;
946 while (NULL == httpd);
949 GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
950 _("Failed to start HTTP server\n"));
951 GNUNET_SCHEDULER_shutdown ();
959 * Main function that will be run.
962 * @param args remaining command-line arguments
963 * @param cfgfile name of the configuration file used (for saving, can be NULL!)
964 * @param cfg configuration
967 run (void *cls, char *const *args, const char *cfgfile,
968 const struct GNUNET_CONFIGURATION_Handle *cfg)
971 GNUNET_CONFIGURATION_get_value_number (cfg,
976 GNUNET_log_config_missing (GNUNET_ERROR_TYPE_ERROR,
977 "fcfsd", "HTTPPORT");
980 ns = GNUNET_NAMESTORE_connect (cfg);
983 GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
984 _("Failed to connect to namestore\n"));
987 identity = GNUNET_IDENTITY_connect (cfg,
989 if (NULL == identity)
991 GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
992 _("Failed to connect to identity\n"));
995 id_op = GNUNET_IDENTITY_get (identity, "fcfsd",
997 GNUNET_SCHEDULER_add_delayed (GNUNET_TIME_UNIT_FOREVER_REL,
1003 * The main function for the fcfs daemon.
1005 * @param argc number of arguments from the command line
1006 * @param argv command line arguments
1007 * @return 0 ok, 1 on error
1010 main (int argc, char *const *argv)
1012 static const struct GNUNET_GETOPT_CommandLineOption options[] = {
1013 GNUNET_GETOPT_OPTION_END
1018 if (GNUNET_OK != GNUNET_STRINGS_get_utf8_args (argc, argv, &argc, &argv))
1021 GNUNET_log_setup ("fcfsd", "WARNING", NULL);
1024 GNUNET_PROGRAM_run (argc, argv, "fcfsd",
1025 _("GNU Name System First Come First Serve name registration service"),
1027 &run, NULL)) ? 0 : 1;
1028 GNUNET_free ((void*) argv);
1029 GNUNET_CRYPTO_ecdsa_key_clear (&fcfs_zone_pkey);
1033 /* end of gnunet-namestore-fcfsd.c */