123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814815816817818819820821822823824825826827828829830831832833834835836837838839840841842843844845846847848849850851852853854855856857858859860861862863864865866867868869870871872873874875876877878879880881882883884885886887888889890891892893894895896897898899900901902903904905906907908909910911912913914915916917918919920921922923924925926927928929930931932933934935936937938939940941942943944945946947948949950951952953954955956957958959960961962963964965966967968969970971972973974975976977978979980981982983984985986987988989990991992993994995996997998999100010011002100310041005100610071008100910101011101210131014101510161017101810191020102110221023102410251026102710281029103010311032103310341035103610371038103910401041104210431044104510461047104810491050105110521053105410551056105710581059106010611062106310641065106610671068106910701071107210731074107510761077107810791080108110821083108410851086108710881089109010911092109310941095109610971098109911001101110211031104110511061107110811091110111111121113111411151116111711181119112011211122112311241125112611271128112911301131113211331134113511361137113811391140114111421143114411451146114711481149115011511152115311541155115611571158115911601161116211631164116511661167116811691170117111721173117411751176117711781179118011811182118311841185118611871188118911901191119211931194119511961197119811991200 |
- /*
- This file is part of GNUnet.
- Copyright (C) 2012-2014 GNUnet e.V.
- GNUnet is free software: you can redistribute it and/or modify it
- under the terms of the GNU Affero General Public License as published
- by the Free Software Foundation, either version 3 of the License,
- 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
- Affero General Public License for more details.
-
- You should have received a copy of the GNU Affero General Public License
- along with this program. If not, see <http://www.gnu.org/licenses/>.
- SPDX-License-Identifier: AGPL3.0-or-later
- */
- /**
- * @file gnunet-namestore-fcfsd.c
- * @brief HTTP daemon that offers first-come-first-serve GNS domain registration
- * @author Christian Grothoff
- *
- * TODO:
- * - need to track active zone info requests so we can cancel them
- * during shutdown, right?
- * - 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_identity_service.h"
- #include "gnunet_gnsrecord_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 "namestore-fcfsd"
- #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.
- */
- // FIXME: struct Session *session;
- /**
- * Post processor handling form data (IF this is
- * a POST request).
- */
- struct MHD_PostProcessor *pp;
-
- /**
- * MHD Connection
- */
- struct MHD_Connection *con;
- /**
- * 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;
- /**
- * Active lookup iterator
- * TODO: deprecate or fix lookup by label and use above member
- */
- struct GNUNET_NAMESTORE_ZoneIterator *lookup_it;
- /**
- * Active iteration with the namestore.
- */
- struct GNUNET_NAMESTORE_ZoneIterator *zi;
- /**
- * Current processing phase.
- */
- enum Phase phase;
- /**
- * Domain name submitted via form.
- */
- char domain_name[64];
- /**
- * Public key submitted via form.
- */
- char public_key[128];
- struct GNUNET_CRYPTO_EcdsaPublicKey pub;
- };
- /**
- * Zoneinfo request
- */
- struct ZoneinfoRequest
- {
- /**
- * 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 struct GNUNET_SCHEDULER_Task * httpd_task;
- /**
- * Handle to the namestore.
- */
- static struct GNUNET_NAMESTORE_Handle *ns;
- /**
- * Private key for the fcfsd zone.
- */
- static struct GNUNET_CRYPTO_EcdsaPrivateKey fcfs_zone_pkey;
- /**
- * Connection to identity service.
- */
- static struct GNUNET_IDENTITY_Handle *identity;
- /**
- * Zoneinfo page we currently use.
- */
- static struct MHD_Response *info_page;
- /**
- * Task that runs #update_zoneinfo_page peridicially.
- */
- static struct GNUNET_SCHEDULER_Task *uzp_task;
- /**
- * Request for our ego.
- */
- static struct GNUNET_IDENTITY_Operation *id_op;
- /**
- * Port we use for the HTTP server.
- */
- static unsigned long long port;
- /**
- * Name of the zone we manage.
- */
- static char *zone;
- /**
- * Task run whenever HTTP server operations are pending.
- *
- * @param cls unused
- */
- static void
- do_httpd (void *cls);
- /**
- * Schedule task to run MHD server now.
- */
- static void
- run_httpd_now ()
- {
- if (NULL != httpd_task)
- {
- GNUNET_SCHEDULER_cancel (httpd_task);
- httpd_task = NULL;
- }
- httpd_task = GNUNET_SCHEDULER_add_now (&do_httpd, NULL);
- }
- /**
- * Create fresh version of zone information.
- */
- static void
- update_zoneinfo_page (void *cls);
-
- /**
- * Function called on error in zone iteration.
- */
- static void
- zone_iteration_error (void *cls)
- {
- struct ZoneinfoRequest *zr = cls;
- zr->list_it = NULL;
- GNUNET_free (zr->zoneinfo);
- GNUNET_SCHEDULER_cancel (uzp_task);
- uzp_task = GNUNET_SCHEDULER_add_now (&update_zoneinfo_page,
- NULL);
- }
- /**
- * Function called once the zone iteration is done.
- */
- static void
- zone_iteration_end (void *cls)
- {
- struct ZoneinfoRequest *zr = cls;
- struct MHD_Response *response;
- char* full_page;
- 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_destroy_response (info_page);
- info_page = response;
- GNUNET_free (zr->zoneinfo);
- }
- /**
- * Process a record that was stored in the namestore, adding
- * the information to the HTML.
- *
- * @param cls closure with the `struct ZoneinfoRequest *`
- * @param zone_key private key of the zone; NULL on disconnect
- * @param name label of the records; NULL on disconnect
- * @param rd_len number of entries in @a rd array, 0 if label was deleted
- * @param rd array of records with data to store
- */
- static void
- iterate_cb (void *cls,
- const struct GNUNET_CRYPTO_EcdsaPrivateKey *zone_key,
- const char *name,
- unsigned int rd_len,
- const struct GNUNET_GNSRECORD_Data *rd)
- {
- struct ZoneinfoRequest *zr = cls;
- size_t bytes_free;
- char* pkey;
- char* new_buf;
- (void) zone_key;
- if (1 != rd_len)
- {
- GNUNET_NAMESTORE_zone_iterator_next (zr->list_it,
- 1);
- return;
- }
- if (GNUNET_GNSRECORD_TYPE_PKEY != rd->record_type)
- {
- GNUNET_NAMESTORE_zone_iterator_next (zr->list_it,
- 1);
- return;
- }
- bytes_free = zr->buf_len - zr->write_offset;
- pkey = GNUNET_GNSRECORD_value_to_string (rd->record_type,
- rd->data,
- rd->data_size);
- if (NULL == pkey)
- {
- GNUNET_break (0);
- GNUNET_NAMESTORE_zone_iterator_next (zr->list_it,
- 1);
- return;
- }
- if (bytes_free < (strlen (name) + strlen (pkey) + 40))
- {
- new_buf = GNUNET_malloc (zr->buf_len * 2);
- GNUNET_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,
- 1);
- GNUNET_free (pkey);
- }
- /**
- * Handler that returns FCFS zoneinfo page.
- *
- * @param connection connection to use
- */
- static int
- serve_zoneinfo_page (struct MHD_Connection *connection)
- {
- return MHD_queue_response (connection,
- MHD_HTTP_OK,
- info_page);
- }
- /**
- * Create fresh version of zone information.
- */
- static void
- update_zoneinfo_page (void *cls)
- {
- static struct ZoneinfoRequest zr;
- (void) cls;
- uzp_task = GNUNET_SCHEDULER_add_delayed (GNUNET_TIME_UNIT_MINUTES,
- &update_zoneinfo_page,
- NULL);
- if (NULL != zr.list_it)
- return;
- zr.zoneinfo = GNUNET_malloc (DEFAULT_ZONEINFO_BUFSIZE);
- zr.buf_len = DEFAULT_ZONEINFO_BUFSIZE;
- zr.write_offset = 0;
- zr.list_it = GNUNET_NAMESTORE_zone_iteration_start (ns,
- &fcfs_zone_pkey,
- &zone_iteration_error,
- &zr,
- &iterate_cb,
- &zr,
- &zone_iteration_end,
- &zr);
- }
- /**
- * 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;
- (void) request;
- 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;
- (void) kind;
- (void) filename;
- (void) content_type;
- (void) transfer_encoding;
- if (0 == strcmp ("domain", key))
- {
- if (size + off >= sizeof(request->domain_name))
- size = sizeof (request->domain_name) - off - 1;
- GNUNET_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;
- GNUNET_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;
- MHD_resume_connection (request->con);
- run_httpd_now ();
- }
- /**
- * Function called if we had an error in zone-to-name mapping.
- */
- static void
- zone_to_name_error (void *cls)
- {
- struct Request *request = cls;
- GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
- _("Error when mapping zone to name\n"));
- request->phase = RP_FAIL;
- MHD_resume_connection (request->con);
- 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 @a rd array
- * @param rd array of records with data to store
- */
- static void
- zone_to_name_cb (void *cls,
- const struct GNUNET_CRYPTO_EcdsaPrivateKey *zone_key,
- const char *name,
- unsigned int rd_count,
- const struct GNUNET_GNSRECORD_Data *rd)
- {
- struct Request *request = cls;
- struct GNUNET_GNSRECORD_Data r;
- (void) rd;
- (void) zone_key;
- request->qe = NULL;
- if (0 != rd_count)
- {
- GNUNET_log (GNUNET_ERROR_TYPE_INFO,
- _("Found existing name `%s' for the given key\n"),
- name);
- request->phase = RP_FAIL;
- MHD_resume_connection (request->con);
- run_httpd_now ();
- return;
- }
- r.data = &request->pub;
- r.data_size = sizeof (request->pub);
- r.expiration_time = UINT64_MAX;
- r.record_type = GNUNET_GNSRECORD_TYPE_PKEY;
- r.flags = GNUNET_GNSRECORD_RF_NONE;
- request->qe = GNUNET_NAMESTORE_records_store (ns,
- &fcfs_zone_pkey,
- request->domain_name,
- 1, &r,
- &put_continuation,
- request);
- }
- /**
- * We encountered an error in the name lookup.
- */
- static void
- lookup_it_error (void *cls)
- {
- struct Request *request = cls;
- MHD_resume_connection (request->con);
- request->qe = NULL;
- request->phase = RP_FAIL;
- run_httpd_now ();
- }
- /**
- * We got a block back from the namestore. Decrypt it
- * and continue to process the result.
- *
- * @param cls the 'struct Request' we are processing
- * @param zonekey private key of the zone; NULL on disconnect
- * @param label label of the records; NULL on disconnect
- * @param rd_count number of entries in @a rd array, 0 if label was deleted
- * @param rd array of records with data to store
- */
- static void
- lookup_it_processor (void *cls,
- const struct GNUNET_CRYPTO_EcdsaPrivateKey *zonekey,
- const char *label,
- unsigned int rd_count,
- const struct GNUNET_GNSRECORD_Data *rd)
- {
- struct Request *request = cls;
- (void) label;
- (void) rd;
- (void) zonekey;
- if (0 == strcmp (label, request->domain_name)) {
- GNUNET_break (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;
- }
- GNUNET_NAMESTORE_zone_iterator_next (request->lookup_it, 1);
- }
- static void
- lookup_it_finished (void *cls)
- {
- struct Request *request = cls;
-
- if (RP_FAIL == request->phase)
- {
- MHD_resume_connection (request->con);
- run_httpd_now ();
- return;
- }
- if (GNUNET_OK !=
- GNUNET_CRYPTO_ecdsa_public_key_from_string (request->public_key,
- strlen (request->public_key),
- &request->pub))
- {
- GNUNET_break (0);
- request->phase = RP_FAIL;
- MHD_resume_connection (request->con);
- run_httpd_now ();
- return;
- }
- request->qe = GNUNET_NAMESTORE_zone_to_name (ns,
- &fcfs_zone_pkey,
- &request->pub,
- &zone_to_name_error,
- request,
- &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
- * @a 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;
- struct GNUNET_CRYPTO_EcdsaPublicKey pub;
- int ret;
- (void) cls;
- (void) version;
- 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_new (struct Request);
- request->con = connection;
- *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_ecdsa_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;
- MHD_suspend_connection (request->con);
- request->lookup_it
- = GNUNET_NAMESTORE_zone_iteration_start (ns,
- &fcfs_zone_pkey,
- &lookup_it_error,
- request,
- &lookup_it_processor,
- request,
- &lookup_it_finished,
- 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_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;
- (void) cls;
- (void) connection;
- (void) toe;
- 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
- */
- static void
- do_httpd (void *cls)
- {
- (void) cls;
- httpd_task = NULL;
- MHD_run (httpd);
- run_httpd ();
- }
- /**
- * Task run on shutdown. Cleans up everything.
- *
- * @param cls unused
- */
- static void
- do_shutdown (void *cls)
- {
- (void) cls;
- if (NULL != httpd_task)
- {
- GNUNET_SCHEDULER_cancel (httpd_task);
- httpd_task = NULL;
- }
- if (NULL != uzp_task)
- {
- GNUNET_SCHEDULER_cancel (uzp_task);
- uzp_task = NULL;
- }
- if (NULL != ns)
- {
- GNUNET_NAMESTORE_disconnect (ns);
- ns = NULL;
- }
- if (NULL != httpd)
- {
- MHD_stop_daemon (httpd);
- httpd = NULL;
- }
- if (NULL != id_op)
- {
- GNUNET_IDENTITY_cancel (id_op);
- id_op = NULL;
- }
- if (NULL != identity)
- {
- GNUNET_IDENTITY_disconnect (identity);
- identity = NULL;
- }
- }
- /**
- * Method called to inform about the egos of this peer.
- *
- * When used with #GNUNET_IDENTITY_create or #GNUNET_IDENTITY_get,
- * this function is only called ONCE, and 'NULL' being passed in
- * @a ego does indicate an error (i.e. name is taken or no default
- * value is known). If @a ego is non-NULL and if '*ctx'
- * is set in those callbacks, the value WILL be passed to a subsequent
- * call to the identity callback of #GNUNET_IDENTITY_connect (if
- * that one was not NULL).
- *
- * @param cls closure, NULL
- * @param ego ego handle
- * @param ctx context for application to store data for this ego
- * (during the lifetime of this process, initially NULL)
- * @param name name assigned by the user for this ego,
- * NULL if the user just deleted the ego and it
- * must thus no longer be used
- */
- static void
- identity_cb (void *cls,
- struct GNUNET_IDENTITY_Ego *ego,
- void **ctx,
- const char *name)
- {
- int options;
- (void) cls;
- (void) ctx;
- if (NULL == name)
- return;
- if (0 != strcmp (name,
- zone))
- return;
- if (NULL == ego)
- {
- GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
- _("No ego configured for `fcfsd` subsystem\n"));
- GNUNET_SCHEDULER_shutdown ();
- return;
- }
- fcfs_zone_pkey = *GNUNET_IDENTITY_ego_get_private_key (ego);
- options = MHD_USE_DUAL_STACK | MHD_USE_DEBUG | MHD_ALLOW_SUSPEND_RESUME;
- do
- {
- httpd = MHD_start_daemon (options,
- (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 (MHD_USE_DEBUG == options)
- break;
- options = MHD_USE_DEBUG;
- }
- while (NULL == httpd);
- if (NULL == httpd)
- {
- GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
- _("Failed to start HTTP server\n"));
- GNUNET_SCHEDULER_shutdown ();
- return;
- }
- run_httpd ();
- }
- /**
- * 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)
- {
- (void) cls;
- (void) args;
- (void) cfgfile;
- if (GNUNET_OK !=
- GNUNET_CONFIGURATION_get_value_number (cfg,
- "fcfsd",
- "HTTPPORT",
- &port))
- {
- GNUNET_log_config_missing (GNUNET_ERROR_TYPE_ERROR,
- "fcfsd", "HTTPPORT");
- return;
- }
- ns = GNUNET_NAMESTORE_connect (cfg);
- if (NULL == ns)
- {
- GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
- _("Failed to connect to namestore\n"));
- return;
- }
- identity = GNUNET_IDENTITY_connect (cfg,
- &identity_cb,
- NULL);
- if (NULL == identity)
- {
- GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
- _("Failed to connect to identity\n"));
- return;
- }
- uzp_task = GNUNET_SCHEDULER_add_now (&update_zoneinfo_page,
- NULL);
- GNUNET_SCHEDULER_add_shutdown (&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)
- {
- struct GNUNET_GETOPT_CommandLineOption options[] = {
- GNUNET_GETOPT_option_mandatory
- (GNUNET_GETOPT_option_string ('z',
- "zone",
- "EGO",
- gettext_noop ("name of the zone that is to be managed by FCFSD"),
- &zone)),
- 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,
- "gnunet-namestore-fcfsd",
- _("GNU Name System First Come First Serve name registration service"),
- options,
- &run, NULL)) ? 0 : 1;
- GNUNET_free ((void*) argv);
- GNUNET_CRYPTO_ecdsa_key_clear (&fcfs_zone_pkey);
- return ret;
- }
- /* end of gnunet-namestore-fcfsd.c */
|