/*
This file is part of GNUnet.
- (C) 2012-2013 Christian Grothoff (and other contributing authors)
+ 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 General Public License as published
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.
+ Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
+ Boston, MA 02110-1301, USA.
*/
/**
- * @file gnunet-gns-fcfsd.c
+ * @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?)
#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"
/**
/**
* Name of our cookie.
*/
-#define COOKIE_NAME "gns-fcfs"
+#define COOKIE_NAME "namestore-fcfsd"
#define DEFAULT_ZONEINFO_BUFSIZE 2048
/**
* Associated session.
*/
- struct Session *session;
+ // FIXME: struct Session *session;
/**
* Post processor handling form data (IF this is
struct MHD_PostProcessor *pp;
/**
- * URL to serve in response to this POST (if this request
+ * 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 iteration with the namestore.
+ */
+ struct GNUNET_NAMESTORE_ZoneIterator *zi;
+
/**
* Current processing phase.
*/
*/
char public_key[128];
+ struct GNUNET_CRYPTO_EcdsaPublicKey pub;
+
};
/**
* Buffer length
*/
size_t buf_len;
-
+
/**
* Buffer write offset
*/
/**
* Main HTTP task.
*/
-static GNUNET_SCHEDULER_TaskIdentifier httpd_task;
+static struct GNUNET_SCHEDULER_Task * httpd_task;
/**
* Handle to the namestore.
/**
* Private key for the fcfsd zone.
*/
-static struct GNUNET_CRYPTO_EccPrivateKey *fcfs_zone_pkey;
-
+static struct GNUNET_CRYPTO_EcdsaPrivateKey fcfs_zone_pkey;
+
+/**
+ * Connection to identity service.
+ */
+static struct GNUNET_IDENTITY_Handle *identity;
+
+/**
+ * Request for our ego.
+ */
+static struct GNUNET_IDENTITY_Operation *id_op;
+
+/**
+ * Port we use for the HTTP server.
+ */
+static unsigned long long port;
+
/**
* 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);
+do_httpd (void *cls);
/**
static void
run_httpd_now ()
{
- if (GNUNET_SCHEDULER_NO_TASK != httpd_task)
+ if (NULL != httpd_task)
{
GNUNET_SCHEDULER_cancel (httpd_task);
- httpd_task = GNUNET_SCHEDULER_NO_TASK;
+ httpd_task = NULL;
}
httpd_task = GNUNET_SCHEDULER_add_now (&do_httpd, NULL);
}
+/**
+ * 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_EccPrivateKey *zone_key,
+ const struct GNUNET_CRYPTO_EcdsaPrivateKey *zone_key,
const char *name,
unsigned int rd_len,
- const struct GNUNET_NAMESTORE_RecordData *rd)
+ const struct GNUNET_GNSRECORD_Data *rd)
{
struct ZoneinfoRequest *zr = cls;
struct MHD_Response *response;
MHD_add_response_header (response,
MHD_HTTP_HEADER_CONTENT_TYPE,
MIME_HTML);
- MHD_queue_response (zr->connection,
- MHD_HTTP_OK,
+ MHD_queue_response (zr->connection,
+ MHD_HTTP_OK,
response);
MHD_destroy_response (response);
GNUNET_free (zr->zoneinfo);
return;
}
- if (GNUNET_NAMESTORE_TYPE_PKEY != rd->record_type)
+ if (GNUNET_GNSRECORD_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,
+ 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);
+ return;
+ }
if (bytes_free < (strlen (name) + strlen (pkey) + 40))
{
new_buf = GNUNET_malloc (zr->buf_len * 2);
zr->zoneinfo = new_buf;
zr->buf_len *= 2;
}
- sprintf (zr->zoneinfo + zr->write_offset,
- "<tr><td>%s</td><td>%s</td></tr>",
- name,
+ 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);
}
-
/**
* Handler that returns FCFS zoneinfo page.
*
zr->connection = connection;
zr->write_offset = 0;
zr->list_it = GNUNET_NAMESTORE_zone_iteration_start (ns,
- fcfs_zone_pkey,
+ &fcfs_zone_pkey,
&iterate_cb,
zr);
return MHD_YES;
MHD_add_response_header (response,
MHD_HTTP_HEADER_CONTENT_TYPE,
MIME_HTML);
- ret = MHD_queue_response (connection,
- MHD_HTTP_OK,
+ ret = MHD_queue_response (connection,
+ MHD_HTTP_OK,
response);
MHD_destroy_response (response);
return ret;
MHD_add_response_header (response,
MHD_HTTP_HEADER_CONTENT_TYPE,
MIME_HTML);
- ret = MHD_queue_response (connection,
- MHD_HTTP_OK,
+ ret = MHD_queue_response (connection,
+ MHD_HTTP_OK,
response);
MHD_destroy_response (response);
return ret;
}
-
-
/**
* 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 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
+static void
put_continuation (void *cls,
int32_t success,
const char *emsg)
* @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_count number of entries in @a rd array
* @param rd array of records with data to store
*/
-static void
+static void
zone_to_name_cb (void *cls,
- const struct GNUNET_CRYPTO_EccPrivateKey *zone_key,
+ const struct GNUNET_CRYPTO_EcdsaPrivateKey *zone_key,
const char *name,
unsigned int rd_count,
- const struct GNUNET_NAMESTORE_RecordData *rd)
+ const struct GNUNET_GNSRECORD_Data *rd)
{
struct Request *request = cls;
- struct GNUNET_NAMESTORE_RecordData r;
- struct GNUNET_CRYPTO_ShortHashCode pub;
-
+ struct GNUNET_GNSRECORD_Data r;
request->qe = NULL;
- if (NULL != name)
+
+ if (0 != rd_count)
{
GNUNET_log (GNUNET_ERROR_TYPE_INFO,
_("Found existing name `%s' for the given key\n"),
run_httpd_now ();
return;
}
- r.data = &pub;
- r.data_size = sizeof (pub);
+ if (NULL == zone_key)
+ {
+ GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
+ _("Error when mapping zone to name\n"));
+ request->phase = RP_FAIL;
+ run_httpd_now ();
+ return;
+ }
+
+ r.data = &request->pub;
+ r.data_size = sizeof (request->pub);
r.expiration_time = UINT64_MAX;
- r.record_type = GNUNET_NAMESTORE_TYPE_PKEY;
- r.flags = GNUNET_NAMESTORE_RF_AUTHORITY;
+ r.record_type = GNUNET_GNSRECORD_TYPE_PKEY;
+ r.flags = GNUNET_GNSRECORD_RF_NONE;
request->qe = GNUNET_NAMESTORE_records_store (ns,
- fcfs_zone_pkey,
+ &fcfs_zone_pkey,
request->domain_name,
1, &r,
&put_continuation,
}
-/**
- * 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 rd_count number of entries in 'rd' array
- * @param rd array of records with data to store
- */
-static void
-lookup_result_processor (void *cls,
- unsigned int rd_count,
- const struct GNUNET_NAMESTORE_RecordData *rd)
-{
- struct Request *request = cls;
- struct GNUNET_CRYPTO_EccPublicKey pub;
-
- 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);
-}
-
-
/**
* 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 block block returned form namestore, NULL on error
+ * @param zone 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_block_processor (void *cls,
- const struct GNUNET_NAMESTORE_Block *block)
+ const struct GNUNET_CRYPTO_EcdsaPrivateKey *zone,
+ const char *label,
+ unsigned int rd_count,
+ const struct GNUNET_GNSRECORD_Data *rd)
{
struct Request *request = cls;
- struct GNUNET_CRYPTO_EccPublicKey pub;
request->qe = NULL;
- if (NULL == block)
- {
- lookup_result_processor (request, 0, NULL);
- return;
- }
- GNUNET_CRYPTO_ecc_key_get_public (fcfs_zone_pkey,
- &pub);
- if (GNUNET_OK !=
- GNUNET_NAMESTORE_block_decrypt (block,
- &pub,
- request->domain_name,
- &lookup_result_processor,
- request))
+ if (0 == rd_count)
{
- GNUNET_break (0);
- request->phase = RP_FAIL;
- run_httpd_now ();
+
+ 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;
+ run_httpd_now ();
+ return;
+ }
+ request->qe = GNUNET_NAMESTORE_zone_to_name (ns,
+ &fcfs_zone_pkey,
+ &request->pub,
+ &zone_to_name_cb,
+ request);
return;
}
+ 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;
+ run_httpd_now ();
+ return;
}
* 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
+ * @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,
const char *url,
const char *method,
const char *version,
- const char *upload_data,
+ 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;
- struct GNUNET_CRYPTO_EccPublicKey pub;
- struct GNUNET_HashCode query;
if ( (0 == strcmp (method, MHD_HTTP_METHOD_GET)) ||
(0 == strcmp (method, MHD_HTTP_METHOD_HEAD)) )
return ret;
}
if (0 == strcmp (method, MHD_HTTP_METHOD_POST))
- {
+ {
request = *ptr;
if (NULL == request)
{
- request = GNUNET_malloc (sizeof (struct Request));
+ request = GNUNET_new (struct Request);
*ptr = request;
request->pp = MHD_create_post_processor (connection, 1024,
&post_iterator, request);
_("Failed to setup post processor for `%s'\n"),
url);
return MHD_NO; /* internal error */
- }
+ }
return MHD_YES;
}
if (NULL != request->pp)
request->pp = NULL;
}
if (GNUNET_OK !=
- GNUNET_CRYPTO_ecc_public_key_from_string (request->public_key,
- strlen (request->public_key),
- &pub))
+ 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);
}
request->phase = RP_LOOKUP;
- GNUNET_CRYPTO_ecc_key_get_public (fcfs_zone_pkey,
- &pub);
- GNUNET_NAMESTORE_query_from_public_key (&pub,
- request->domain_name,
- &query);
- request->qe = GNUNET_NAMESTORE_lookup_block (ns,
- &query,
- &lookup_block_processor,
- request);
+ request->qe = GNUNET_NAMESTORE_records_lookup (ns,
+ &fcfs_zone_pkey,
+ request->domain_name,
+ &lookup_block_processor,
+ request);
break;
case RP_LOOKUP:
break;
GNUNET_break (0);
return MHD_NO;
}
- return MHD_YES; /* will have a reply later... */
+ 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,
+ ret = MHD_queue_response (connection,
+ MHD_HTTP_NOT_ACCEPTABLE,
response);
MHD_destroy_response (response);
return ret;
* 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)
+do_httpd (void *cls)
{
- httpd_task = GNUNET_SCHEDULER_NO_TASK;
+ httpd_task = NULL;
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)
+do_shutdown (void *cls)
{
- if (GNUNET_SCHEDULER_NO_TASK != httpd_task)
+ if (NULL != httpd_task)
{
GNUNET_SCHEDULER_cancel (httpd_task);
- httpd_task = GNUNET_SCHEDULER_NO_TASK;
+ httpd_task = NULL;
}
if (NULL != ns)
{
MHD_stop_daemon (httpd);
httpd = NULL;
}
- if (NULL != fcfs_zone_pkey)
+ if (NULL != id_op)
+ {
+ GNUNET_IDENTITY_cancel (id_op);
+ id_op = NULL;
+ }
+ if (NULL != identity)
{
- GNUNET_CRYPTO_ecc_key_free (fcfs_zone_pkey);
- fcfs_zone_pkey = NULL;
+ 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;
+
+ id_op = NULL;
+ if (NULL == ego)
+ {
+ GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
+ _("No ego configured for `fcfsd` subsystem\n"));
+ return;
+ }
+ fcfs_zone_pkey = *GNUNET_IDENTITY_ego_get_private_key (ego);
+
+ options = MHD_USE_DUAL_STACK | MHD_USE_DEBUG;
+ 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.
*
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",
"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)
{
_("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)
+ identity = GNUNET_IDENTITY_connect (cfg,
+ NULL, NULL);
+ if (NULL == identity)
{
GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
- _("Failed to start HTTP server\n"));
- GNUNET_NAMESTORE_disconnect (ns);
- ns = NULL;
+ _("Failed to connect to identity\n"));
return;
}
- run_httpd ();
- GNUNET_SCHEDULER_add_delayed (GNUNET_TIME_UNIT_FOREVER_REL,
- &do_shutdown, NULL);
+ id_op = GNUNET_IDENTITY_get (identity, "fcfsd",
+ &identity_cb, NULL);
+ GNUNET_SCHEDULER_add_shutdown (&do_shutdown, NULL);
}
ret =
(GNUNET_OK ==
GNUNET_PROGRAM_run (argc, argv, "fcfsd",
- _("GNUnet GNS first come first serve registration service"),
+ _("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-gns-fcfsd.c */
+/* end of gnunet-namestore-fcfsd.c */