diff options
Diffstat (limited to 'src/namestore/gnunet-namestore-fcfsd.c')
-rw-r--r-- | src/namestore/gnunet-namestore-fcfsd.c | 947 |
1 files changed, 947 insertions, 0 deletions
diff --git a/src/namestore/gnunet-namestore-fcfsd.c b/src/namestore/gnunet-namestore-fcfsd.c new file mode 100644 index 000000000..d949806db --- /dev/null +++ b/src/namestore/gnunet-namestore-fcfsd.c @@ -0,0 +1,947 @@ +/* + This file is part of GNUnet. + (C) 2012-2013 Christian Grothoff (and other contributing authors) + + GNUnet is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published + by the Free Software Foundation; either version 3, or (at your + option) any later version. + + GNUnet is distributed in the hope that it will be useful, but + WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + General Public License for more details. + + You should have received a copy of the GNU General Public License + along with GNUnet; see the file COPYING. If not, write to the + Free Software Foundation, Inc., 59 Temple Place - Suite 330, + Boston, MA 02111-1307, USA. +*/ +/** + * @file gnunet-gns-fcfsd.c + * @brief HTTP daemon that offers first-come-first-serve GNS domain registration + * @author Christian Grothoff + * + * TODO: + * - the code currently contains a 'race' between checking that the + * domain name is available and allocating it to the new public key + * (should this race be solved by namestore or by fcfsd?) + * - nicer error reporting to browser + */ +#include "platform.h" +#include <microhttpd.h> +#include "gnunet_util_lib.h" +#include "gnunet_namestore_service.h" + +/** + * Invalid method page. + */ +#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>" + +/** + * Front page. (/) + */ +#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>" + +/** + * Second page (/S) + */ +#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>" + +/** + * Fcfs zoneinfo page (/Zoneinfo) + */ +#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>" + +#define FCFS_ZONEINFO_URL "/Zoneinfo" + +/** + * Mime type for HTML pages. + */ +#define MIME_HTML "text/html" + +/** + * Name of our cookie. + */ +#define COOKIE_NAME "gns-fcfs" + +#define DEFAULT_ZONEINFO_BUFSIZE 2048 + +/** + * Phases a request goes through. + */ +enum Phase + { + /** + * Start phase (parsing POST, checking). + */ + RP_START = 0, + + /** + * Lookup to see if the domain name is taken. + */ + RP_LOOKUP, + + /** + * Storing of the record. + */ + RP_PUT, + + /** + * We're done with success. + */ + RP_SUCCESS, + + /** + * Send failure message. + */ + RP_FAIL + }; + + +/** + * Data kept per request. + */ +struct Request +{ + + /** + * Associated session. + */ + struct Session *session; + + /** + * Post processor handling form data (IF this is + * a POST request). + */ + struct MHD_PostProcessor *pp; + + /** + * URL to serve in response to this POST (if this request + * was a 'POST') + */ + const char *post_url; + + /** + * Active request with the namestore. + */ + struct GNUNET_NAMESTORE_QueueEntry *qe; + + /** + * Current processing phase. + */ + enum Phase phase; + + /** + * Domain name submitted via form. + */ + char domain_name[64]; + + /** + * Public key submitted via form. + */ + char public_key[128]; + +}; + +/** + * Zoneinfo request + */ +struct ZoneinfoRequest +{ + /** + * Connection + */ + struct MHD_Connection *connection; + + /** + * List iterator + */ + struct GNUNET_NAMESTORE_ZoneIterator *list_it; + + /** + * Buffer + */ + char* zoneinfo; + + /** + * Buffer length + */ + size_t buf_len; + + /** + * Buffer write offset + */ + size_t write_offset; +}; + +/** + * MHD deamon reference. + */ +static struct MHD_Daemon *httpd; + +/** + * Main HTTP task. + */ +static GNUNET_SCHEDULER_TaskIdentifier httpd_task; + +/** + * Handle to the namestore. + */ +static struct GNUNET_NAMESTORE_Handle *ns; + +/** + * Private key for the fcfsd zone. + */ +static struct GNUNET_CRYPTO_EccPrivateKey *fcfs_zone_pkey; + + +/** + * Task run whenever HTTP server operations are pending. + * + * @param cls unused + * @param tc scheduler context + */ +static void +do_httpd (void *cls, + const struct GNUNET_SCHEDULER_TaskContext *tc); + + +/** + * Schedule task to run MHD server now. + */ +static void +run_httpd_now () +{ + if (GNUNET_SCHEDULER_NO_TASK != httpd_task) + { + GNUNET_SCHEDULER_cancel (httpd_task); + httpd_task = GNUNET_SCHEDULER_NO_TASK; + } + httpd_task = GNUNET_SCHEDULER_add_now (&do_httpd, NULL); +} + + +static void +iterate_cb (void *cls, + const struct GNUNET_CRYPTO_EccPrivateKey *zone_key, + const char *name, + unsigned int rd_len, + const struct GNUNET_NAMESTORE_RecordData *rd) +{ + struct ZoneinfoRequest *zr = cls; + struct MHD_Response *response; + char* full_page; + size_t bytes_free; + char* pkey; + char* new_buf; + + + if (NULL == name) + { + zr->list_it = NULL; + + /* return static form */ + GNUNET_asprintf (&full_page, + ZONEINFO_PAGE, + zr->zoneinfo, + zr->zoneinfo); + response = MHD_create_response_from_buffer (strlen (full_page), + (void *) full_page, + MHD_RESPMEM_MUST_FREE); + MHD_add_response_header (response, + MHD_HTTP_HEADER_CONTENT_TYPE, + MIME_HTML); + MHD_queue_response (zr->connection, + MHD_HTTP_OK, + response); + MHD_destroy_response (response); + GNUNET_free (zr->zoneinfo); + GNUNET_free (zr); + run_httpd_now (); + return; + } + + if (1 != rd_len) + { + GNUNET_NAMESTORE_zone_iterator_next (zr->list_it); + return; + } + + if (GNUNET_NAMESTORE_TYPE_PKEY != rd->record_type) + { + GNUNET_NAMESTORE_zone_iterator_next (zr->list_it); + return; + } + + bytes_free = zr->buf_len - zr->write_offset; + pkey = GNUNET_NAMESTORE_value_to_string (rd->record_type, + rd->data, + rd->data_size); + + if (bytes_free < (strlen (name) + strlen (pkey) + 40)) + { + new_buf = GNUNET_malloc (zr->buf_len * 2); + memcpy (new_buf, zr->zoneinfo, zr->write_offset); + GNUNET_free (zr->zoneinfo); + zr->zoneinfo = new_buf; + zr->buf_len *= 2; + } + sprintf (zr->zoneinfo + zr->write_offset, + "<tr><td>%s</td><td>%s</td></tr>", + name, + pkey); + zr->write_offset = strlen (zr->zoneinfo); + GNUNET_NAMESTORE_zone_iterator_next (zr->list_it); + GNUNET_free (pkey); +} + + + +/** + * Handler that returns FCFS zoneinfo page. + * + * @param connection connection to use + * @return MHD_YES on success + */ +static int +serve_zoneinfo_page (struct MHD_Connection *connection) +{ + struct ZoneinfoRequest *zr; + + zr = GNUNET_new (struct ZoneinfoRequest); + zr->zoneinfo = GNUNET_malloc (DEFAULT_ZONEINFO_BUFSIZE); + zr->buf_len = DEFAULT_ZONEINFO_BUFSIZE; + zr->connection = connection; + zr->write_offset = 0; + zr->list_it = GNUNET_NAMESTORE_zone_iteration_start (ns, + fcfs_zone_pkey, + &iterate_cb, + zr); + return MHD_YES; +} + + +/** + * Handler that returns a simple static HTTP page. + * + * @param connection connection to use + * @return MHD_YES on success + */ +static int +serve_main_page (struct MHD_Connection *connection) +{ + int ret; + struct MHD_Response *response; + + /* return static form */ + response = MHD_create_response_from_buffer (strlen (MAIN_PAGE), + (void *) MAIN_PAGE, + MHD_RESPMEM_PERSISTENT); + MHD_add_response_header (response, + MHD_HTTP_HEADER_CONTENT_TYPE, + MIME_HTML); + ret = MHD_queue_response (connection, + MHD_HTTP_OK, + response); + MHD_destroy_response (response); + return ret; +} + + +/** + * Send the 'SUBMIT_PAGE'. + * + * @param info information string to send to the user + * @param request request information + * @param connection connection to use + */ +static int +fill_s_reply (const char *info, + struct Request *request, + struct MHD_Connection *connection) +{ + int ret; + char *reply; + struct MHD_Response *response; + + GNUNET_asprintf (&reply, + SUBMIT_PAGE, + info, + info); + /* return static form */ + response = MHD_create_response_from_buffer (strlen (reply), + (void *) reply, + MHD_RESPMEM_MUST_FREE); + MHD_add_response_header (response, + MHD_HTTP_HEADER_CONTENT_TYPE, + MIME_HTML); + ret = MHD_queue_response (connection, + MHD_HTTP_OK, + response); + MHD_destroy_response (response); + return ret; +} + + +/** + * Iterator over key-value pairs where the value + * maybe made available in increments and/or may + * not be zero-terminated. Used for processing + * POST data. + * + * @param cls user-specified closure + * @param kind type of the value + * @param key 0-terminated key for the value + * @param filename name of the uploaded file, NULL if not known + * @param content_type mime-type of the data, NULL if not known + * @param transfer_encoding encoding of the data, NULL if not known + * @param data pointer to size bytes of data at the + * specified offset + * @param off offset of data in the overall value + * @param size number of bytes in data available + * @return MHD_YES to continue iterating, + * MHD_NO to abort the iteration + */ +static int +post_iterator (void *cls, + enum MHD_ValueKind kind, + const char *key, + const char *filename, + const char *content_type, + const char *transfer_encoding, + const char *data, uint64_t off, size_t size) +{ + struct Request *request = cls; + + if (0 == strcmp ("domain", key)) + { + if (size + off >= sizeof(request->domain_name)) + size = sizeof (request->domain_name) - off - 1; + memcpy (&request->domain_name[off], + data, + size); + request->domain_name[size+off] = '\0'; + return MHD_YES; + } + if (0 == strcmp ("pkey", key)) + { + if (size + off >= sizeof(request->public_key)) + size = sizeof (request->public_key) - off - 1; + memcpy (&request->public_key[off], + data, + size); + request->public_key[size+off] = '\0'; + return MHD_YES; + } + GNUNET_log (GNUNET_ERROR_TYPE_ERROR, + _("Unsupported form value `%s'\n"), + key); + return MHD_YES; +} + + + + +/** + * Continuation called to notify client about result of the + * operation. + * + * @param cls closure + * @param success GNUNET_SYSERR on failure (including timeout/queue drop/failure to validate) + * GNUNET_NO if content was already there + * GNUNET_YES (or other positive value) on success + * @param emsg NULL on success, otherwise an error message + */ +static void +put_continuation (void *cls, + int32_t success, + const char *emsg) +{ + struct Request *request = cls; + + request->qe = NULL; + if (0 >= success) + { + GNUNET_log (GNUNET_ERROR_TYPE_WARNING, + _("Failed to create record for domain `%s': %s\n"), + request->domain_name, + emsg); + request->phase = RP_FAIL; + } + else + request->phase = RP_SUCCESS; + run_httpd_now (); +} + + +/** + * Test if a name mapping was found, if so, refuse. If not, initiate storing of the record. + * + * @param cls closure + * @param zone_key public key of the zone + * @param name name that is being mapped (at most 255 characters long) + * @param rd_count number of entries in 'rd' array + * @param rd array of records with data to store + */ +static void +zone_to_name_cb (void *cls, + const struct GNUNET_CRYPTO_EccPrivateKey *zone_key, + const char *name, + unsigned int rd_count, + const struct GNUNET_NAMESTORE_RecordData *rd) +{ + struct Request *request = cls; + struct GNUNET_NAMESTORE_RecordData r; + struct GNUNET_CRYPTO_ShortHashCode pub; + + request->qe = NULL; + if (NULL != name) + { + GNUNET_log (GNUNET_ERROR_TYPE_INFO, + _("Found existing name `%s' for the given key\n"), + name); + request->phase = RP_FAIL; + run_httpd_now (); + return; + } + r.data = &pub; + r.data_size = sizeof (pub); + r.expiration_time = UINT64_MAX; + r.record_type = GNUNET_NAMESTORE_TYPE_PKEY; + r.flags = GNUNET_NAMESTORE_RF_AUTHORITY; + request->qe = GNUNET_NAMESTORE_records_store (ns, + fcfs_zone_pkey, + request->domain_name, + 1, &r, + &put_continuation, + request); +} + + +/** + * Process a record that was stored in the namestore. Used to check if + * the requested name already exists in the namestore. If not, + * proceed to check if the requested key already exists. + * + * @param cls closure + * @param zone_key private key of the zone + * @param name name that is being mapped (at most 255 characters long) + * @param rd_count number of entries in 'rd' array + * @param rd array of records with data to store + */ +static void +lookup_result_processor (void *cls, + const struct GNUNET_CRYPTO_EccPrivateKey *zone_key, + const char *name, + unsigned int rd_count, + const struct GNUNET_NAMESTORE_RecordData *rd) +{ + struct Request *request = cls; + struct GNUNET_CRYPTO_EccPublicKey pub; + + request->qe = NULL; + if (0 != rd_count) + { + GNUNET_log (GNUNET_ERROR_TYPE_INFO, + _("Found %u existing records for domain `%s'\n"), + rd_count, + request->domain_name); + request->phase = RP_FAIL; + run_httpd_now (); + return; + } + if (GNUNET_OK != + GNUNET_CRYPTO_ecc_public_key_from_string (request->public_key, + strlen (request->public_key), + &pub)) + { + GNUNET_break (0); + request->phase = RP_FAIL; + run_httpd_now (); + return; + } + request->qe = GNUNET_NAMESTORE_zone_to_name (ns, + fcfs_zone_pkey, + &pub, + &zone_to_name_cb, + request); +} + + +/** + * Main MHD callback for handling requests. + * + * @param cls unused + * @param connection MHD connection handle + * @param url the requested url + * @param method the HTTP method used ("GET", "PUT", etc.) + * @param version the HTTP version string (i.e. "HTTP/1.1") + * @param upload_data the data being uploaded (excluding HEADERS, + * for a POST that fits into memory and that is encoded + * with a supported encoding, the POST data will NOT be + * given in upload_data and is instead available as + * part of MHD_get_connection_values; very large POST + * data *will* be made available incrementally in + * upload_data) + * @param upload_data_size set initially to the size of the + * upload_data provided; the method must update this + * value to the number of bytes NOT processed; + * @param ptr pointer to location where we store the 'struct Request' + * @return MHD_YES if the connection was handled successfully, + * MHD_NO if the socket must be closed due to a serious + * error while handling the request + */ +static int +create_response (void *cls, + struct MHD_Connection *connection, + const char *url, + const char *method, + const char *version, + const char *upload_data, + size_t *upload_data_size, + void **ptr) +{ + struct MHD_Response *response; + struct Request *request; + int ret; + struct GNUNET_CRYPTO_EccPublicKey pub; + + if ( (0 == strcmp (method, MHD_HTTP_METHOD_GET)) || + (0 == strcmp (method, MHD_HTTP_METHOD_HEAD)) ) + { + if (0 == strcmp (url, FCFS_ZONEINFO_URL)) + ret = serve_zoneinfo_page (connection); + else + ret = serve_main_page (connection); + if (ret != MHD_YES) + GNUNET_log (GNUNET_ERROR_TYPE_ERROR, + _("Failed to create page for `%s'\n"), + url); + return ret; + } + if (0 == strcmp (method, MHD_HTTP_METHOD_POST)) + { + request = *ptr; + if (NULL == request) + { + request = GNUNET_malloc (sizeof (struct Request)); + *ptr = request; + request->pp = MHD_create_post_processor (connection, 1024, + &post_iterator, request); + if (NULL == request->pp) + { + GNUNET_log (GNUNET_ERROR_TYPE_ERROR, + _("Failed to setup post processor for `%s'\n"), + url); + return MHD_NO; /* internal error */ + } + return MHD_YES; + } + if (NULL != request->pp) + { + /* evaluate POST data */ + MHD_post_process (request->pp, + upload_data, + *upload_data_size); + if (0 != *upload_data_size) + { + *upload_data_size = 0; + return MHD_YES; + } + /* done with POST data, serve response */ + MHD_destroy_post_processor (request->pp); + request->pp = NULL; + } + if (GNUNET_OK != + GNUNET_CRYPTO_ecc_public_key_from_string (request->public_key, + strlen (request->public_key), + &pub)) + { + /* parse error */ + return fill_s_reply ("Failed to parse given public key", + request, connection); + } + switch (request->phase) + { + case RP_START: + if (NULL != strchr (request->domain_name, (int) '.')) + { + GNUNET_log (GNUNET_ERROR_TYPE_INFO, + _("Domain name must not contain `.'\n")); + request->phase = RP_FAIL; + return fill_s_reply ("Domain name must not contain `.', sorry.", + request, connection); + } + if (NULL != strchr (request->domain_name, (int) '+')) + { + GNUNET_log (GNUNET_ERROR_TYPE_INFO, + _("Domain name must not contain `+'\n")); + request->phase = RP_FAIL; + return fill_s_reply ("Domain name must not contain `+', sorry.", + request, connection); + } + request->phase = RP_LOOKUP; + GNUNET_CRYPTO_ecc_key_get_public (fcfs_zone_pkey, + &pub); + request->qe = GNUNET_NAMESTORE_lookup (ns, + &pub, + request->domain_name, + &lookup_result_processor, + request); + break; + case RP_LOOKUP: + break; + case RP_PUT: + break; + case RP_FAIL: + return fill_s_reply ("Request failed, sorry.", + request, connection); + case RP_SUCCESS: + return fill_s_reply ("Success.", + request, connection); + default: + GNUNET_break (0); + return MHD_NO; + } + return MHD_YES; /* will have a reply later... */ + } + /* unsupported HTTP method */ + response = MHD_create_response_from_buffer (strlen (METHOD_ERROR), + (void *) METHOD_ERROR, + MHD_RESPMEM_PERSISTENT); + ret = MHD_queue_response (connection, + MHD_HTTP_METHOD_NOT_ACCEPTABLE, + response); + MHD_destroy_response (response); + return ret; +} + + +/** + * Callback called upon completion of a request. + * Decrements session reference counter. + * + * @param cls not used + * @param connection connection that completed + * @param con_cls session handle + * @param toe status code + */ +static void +request_completed_callback (void *cls, + struct MHD_Connection *connection, + void **con_cls, + enum MHD_RequestTerminationCode toe) +{ + struct Request *request = *con_cls; + + if (NULL == request) + return; + if (NULL != request->pp) + MHD_destroy_post_processor (request->pp); + if (NULL != request->qe) + GNUNET_NAMESTORE_cancel (request->qe); + GNUNET_free (request); +} + + +#define UNSIGNED_MHD_LONG_LONG unsigned MHD_LONG_LONG + + +/** + * Schedule tasks to run MHD server. + */ +static void +run_httpd () +{ + fd_set rs; + fd_set ws; + fd_set es; + struct GNUNET_NETWORK_FDSet *wrs; + struct GNUNET_NETWORK_FDSet *wws; + struct GNUNET_NETWORK_FDSet *wes; + int max; + int haveto; + UNSIGNED_MHD_LONG_LONG timeout; + struct GNUNET_TIME_Relative tv; + + FD_ZERO (&rs); + FD_ZERO (&ws); + FD_ZERO (&es); + wrs = GNUNET_NETWORK_fdset_create (); + wes = GNUNET_NETWORK_fdset_create (); + wws = GNUNET_NETWORK_fdset_create (); + max = -1; + GNUNET_assert (MHD_YES == MHD_get_fdset (httpd, &rs, &ws, &es, &max)); + haveto = MHD_get_timeout (httpd, &timeout); + if (haveto == MHD_YES) + tv.rel_value_us = (uint64_t) timeout * 1000LL; + else + tv = GNUNET_TIME_UNIT_FOREVER_REL; + GNUNET_NETWORK_fdset_copy_native (wrs, &rs, max + 1); + GNUNET_NETWORK_fdset_copy_native (wws, &ws, max + 1); + GNUNET_NETWORK_fdset_copy_native (wes, &es, max + 1); + httpd_task = + GNUNET_SCHEDULER_add_select (GNUNET_SCHEDULER_PRIORITY_HIGH, + tv, wrs, wws, + &do_httpd, NULL); + GNUNET_NETWORK_fdset_destroy (wrs); + GNUNET_NETWORK_fdset_destroy (wws); + GNUNET_NETWORK_fdset_destroy (wes); +} + + +/** + * Task run whenever HTTP server operations are pending. + * + * @param cls unused + * @param tc scheduler context + */ +static void +do_httpd (void *cls, + const struct GNUNET_SCHEDULER_TaskContext *tc) +{ + httpd_task = GNUNET_SCHEDULER_NO_TASK; + MHD_run (httpd); + run_httpd (); +} + + +/** + * Task run on shutdown. Cleans up everything. + * + * @param cls unused + * @param tc scheduler context + */ +static void +do_shutdown (void *cls, + const struct GNUNET_SCHEDULER_TaskContext *tc) +{ + if (GNUNET_SCHEDULER_NO_TASK != httpd_task) + { + GNUNET_SCHEDULER_cancel (httpd_task); + httpd_task = GNUNET_SCHEDULER_NO_TASK; + } + if (NULL != ns) + { + GNUNET_NAMESTORE_disconnect (ns); + ns = NULL; + } + if (NULL != httpd) + { + MHD_stop_daemon (httpd); + httpd = NULL; + } + if (NULL != fcfs_zone_pkey) + { + GNUNET_CRYPTO_ecc_key_free (fcfs_zone_pkey); + fcfs_zone_pkey = NULL; + } +} + + +/** + * Main function that will be run. + * + * @param cls closure + * @param args remaining command-line arguments + * @param cfgfile name of the configuration file used (for saving, can be NULL!) + * @param cfg configuration + */ +static void +run (void *cls, char *const *args, const char *cfgfile, + const struct GNUNET_CONFIGURATION_Handle *cfg) +{ + char *keyfile; + unsigned long long port; + + if (GNUNET_OK != + GNUNET_CONFIGURATION_get_value_number (cfg, + "fcfsd", + "HTTPPORT", + &port)) + { + GNUNET_log_config_missing (GNUNET_ERROR_TYPE_ERROR, + "fcfsd", "HTTPPORT"); + return; + } + if (GNUNET_OK != + GNUNET_CONFIGURATION_get_value_filename (cfg, + "fcfsd", + "ZONEKEY", + &keyfile)) + { + GNUNET_log_config_missing (GNUNET_ERROR_TYPE_ERROR, + "fcfsd", "ZONEKEY"); + return; + } + fcfs_zone_pkey = GNUNET_CRYPTO_ecc_key_create_from_file (keyfile); + GNUNET_free (keyfile); + if (NULL == fcfs_zone_pkey) + { + GNUNET_log (GNUNET_ERROR_TYPE_ERROR, + _("Failed to read or create private zone key\n")); + return; + } + ns = GNUNET_NAMESTORE_connect (cfg); + if (NULL == ns) + { + GNUNET_log (GNUNET_ERROR_TYPE_ERROR, + _("Failed to connect to namestore\n")); + return; + } + httpd = MHD_start_daemon (MHD_USE_DEBUG, + (uint16_t) port, + NULL, NULL, + &create_response, NULL, + MHD_OPTION_CONNECTION_LIMIT, (unsigned int) 128, + MHD_OPTION_PER_IP_CONNECTION_LIMIT, (unsigned int) 1, + MHD_OPTION_CONNECTION_TIMEOUT, (unsigned int) 16, + MHD_OPTION_CONNECTION_MEMORY_LIMIT, (size_t) (4 * 1024), + MHD_OPTION_NOTIFY_COMPLETED, &request_completed_callback, NULL, + MHD_OPTION_END); + if (NULL == httpd) + { + GNUNET_log (GNUNET_ERROR_TYPE_ERROR, + _("Failed to start HTTP server\n")); + GNUNET_NAMESTORE_disconnect (ns); + ns = NULL; + return; + } + run_httpd (); + GNUNET_SCHEDULER_add_delayed (GNUNET_TIME_UNIT_FOREVER_REL, + &do_shutdown, NULL); +} + + +/** + * The main function for the fcfs daemon. + * + * @param argc number of arguments from the command line + * @param argv command line arguments + * @return 0 ok, 1 on error + */ +int +main (int argc, char *const *argv) +{ + static const struct GNUNET_GETOPT_CommandLineOption options[] = { + GNUNET_GETOPT_OPTION_END + }; + + int ret; + + if (GNUNET_OK != GNUNET_STRINGS_get_utf8_args (argc, argv, &argc, &argv)) + return 2; + + GNUNET_log_setup ("fcfsd", "WARNING", NULL); + ret = + (GNUNET_OK == + GNUNET_PROGRAM_run (argc, argv, "fcfsd", + _("GNUnet GNS first come first serve registration service"), + options, + &run, NULL)) ? 0 : 1; + GNUNET_free ((void*) argv); + return ret; +} + +/* end of gnunet-gns-fcfsd.c */ |