-fix uninit and fix leak
[oweals/gnunet.git] / src / gns / gnunet-gns-fcfsd.c
index b52d8473b8d004ed01e7a4e76436d789f2604d55..25fde90ec99727e08c9ade5897bf129fa9b662da 100644 (file)
 /**
  * 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? <input type=\"text\" name=\"domain\" /> <p> What is your public key? <input type=\"text\" name=\"pkey\" /> <input type=\"submit\" value=\"Next\" /></body></html>"
+#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.
  */
@@ -59,6 +66,7 @@
  */
 #define COOKIE_NAME "gns-fcfs"
 
+#define DEFAULT_ZONEINFO_BUFSIZE 2048
 
 /**
  * Phases a request goes through.
@@ -133,10 +141,40 @@ struct Request
   /**
    * Public key submitted via form.
    */
-  char public_key[1024];
+  char public_key[64];
 
 };
 
+/**
+ * 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.
@@ -156,14 +194,147 @@ static struct GNUNET_NAMESTORE_Handle *ns;
 /**
  * Hash of the public key of the fcfsd zone.
  */
-static GNUNET_HashCode fcfsd_zone;
+static struct GNUNET_CRYPTO_ShortHashCode fcfsd_zone;
 
 /**
  * Private key for the fcfsd zone.
  */
-static struct GNUNET_CRYPTO_RsaPrivateKey *fcfs_zone_pkey;
+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_EccPublicKeyBinaryEncoded *zone_key,
+                struct GNUNET_TIME_Absolute expire,
+                const char *name,
+                unsigned int rd_len,
+                const struct GNUNET_NAMESTORE_RecordData *rd,
+                const struct GNUNET_CRYPTO_EccSignature *signature)
+{
+  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_malloc (sizeof (struct ZoneinfoRequest));
+
+  zr->zoneinfo = GNUNET_malloc (DEFAULT_ZONEINFO_BUFSIZE);
+  zr->buf_len = DEFAULT_ZONEINFO_BUFSIZE;
+  zr->connection = connection;
+  zr->write_offset = 0;
+
+  printf ("adsadad1!\n");
+  zr->list_it = GNUNET_NAMESTORE_zone_iteration_start (ns,
+                                                   &fcfsd_zone,
+                                                   GNUNET_NAMESTORE_RF_RELATIVE_EXPIRATION,
+                                                   GNUNET_NAMESTORE_RF_PRIVATE,
+                                                   &iterate_cb,
+                                                   zr);
+
+  return MHD_YES;
+}
+
+
 /**
  * Handler that returns a simple static HTTP page.
  *
@@ -283,30 +454,6 @@ post_iterator (void *cls,
 }
 
 
-/**
- * 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);
-}
 
 
 /**
@@ -342,7 +489,67 @@ put_continuation (void *cls,
 
 
 /**
- * Process a record that was stored in the namestore.
+ * 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 expire when does the corresponding block in the DHT expire (until
+ *               when should we never do a DHT lookup for the same name again)?; 
+ *               GNUNET_TIME_UNIT_ZERO_ABS if there are no records of any type in the namestore,
+ *               or the expiration time of the block in the namestore (even if there are zero
+ *               records matching the desired record type)
+ * @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
+ * @param signature signature of the record block, NULL if signature is unavailable (i.e. 
+ *        because the user queried for a particular record type only)
+ */
+static void 
+zone_to_name_cb (void *cls,
+                const struct GNUNET_CRYPTO_EccPublicKeyBinaryEncoded *zone_key,
+                struct GNUNET_TIME_Absolute expire,                        
+                const char *name,
+                unsigned int rd_count,
+                const struct GNUNET_NAMESTORE_RecordData *rd,
+                const struct GNUNET_CRYPTO_EccSignature *signature)
+{
+  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;
+  }
+  GNUNET_assert (GNUNET_OK ==
+                GNUNET_CRYPTO_short_hash_from_string2 (request->public_key,
+                                                       strlen (request->public_key),
+                                                       &pub));
+  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_record_put_by_authority (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 public key of the zone
@@ -359,22 +566,21 @@ put_continuation (void *cls,
  */
 static void 
 lookup_result_processor (void *cls,
-                        const struct GNUNET_CRYPTO_RsaPublicKeyBinaryEncoded *zone_key,
+                        const struct GNUNET_CRYPTO_EccPublicKeyBinaryEncoded *zone_key,
                         struct GNUNET_TIME_Absolute expire,                        
                         const char *name,
                         unsigned int rd_count,
                         const struct GNUNET_NAMESTORE_RecordData *rd,
-                        const struct GNUNET_CRYPTO_RsaSignature *signature)
+                        const struct GNUNET_CRYPTO_EccSignature *signature)
 {
   struct Request *request = cls;
-  struct GNUNET_NAMESTORE_RecordData r;
-  GNUNET_HashCode pub;
+  struct GNUNET_CRYPTO_ShortHashCode pub;
   
-  GNUNET_assert (GNUNET_OK ==
-                GNUNET_CRYPTO_hash_from_string2 (request->public_key,
-                                                 strlen (request->public_key),
-                                                 &pub));
   request->qe = NULL;
+  GNUNET_assert (GNUNET_OK ==
+                GNUNET_CRYPTO_short_hash_from_string2 (request->public_key,
+                                                       strlen (request->public_key),
+                                                       &pub));
   if (0 != rd_count)
   {
     GNUNET_log (GNUNET_ERROR_TYPE_INFO,
@@ -385,17 +591,11 @@ lookup_result_processor (void *cls,
     run_httpd_now ();
     return;
   }
-  r.data = &pub;
-  r.data_size = sizeof (pub);
-  r.expiration = GNUNET_TIME_UNIT_FOREVER_ABS;
-  r.record_type = GNUNET_NAMESTORE_TYPE_PKEY;
-  r.flags = GNUNET_NAMESTORE_RF_AUTHORITY;
-  request->qe = GNUNET_NAMESTORE_record_create (ns,
-                                               fcfs_zone_pkey,
-                                               request->domain_name,
-                                               &r,
-                                               &put_continuation,
-                                               request);
+  request->qe = GNUNET_NAMESTORE_zone_to_name (ns,
+                                              &fcfsd_zone,
+                                              &pub,
+                                              &zone_to_name_cb,
+                                              request);
 }
 
 
@@ -418,8 +618,8 @@ lookup_result_processor (void *cls,
  *        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 MHS_YES if the connection was handled successfully,
- *         MHS_NO if the socket must be closed due to a serios
+ * @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
@@ -435,12 +635,15 @@ create_response (void *cls,
   struct MHD_Response *response;
   struct Request *request;
   int ret;
-  GNUNET_HashCode pub;
+  struct GNUNET_CRYPTO_ShortHashCode pub;
 
   if ( (0 == strcmp (method, MHD_HTTP_METHOD_GET)) ||
        (0 == strcmp (method, MHD_HTTP_METHOD_HEAD)) )
     {
-      ret = serve_main_page (connection);
+      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"),
@@ -481,9 +684,9 @@ create_response (void *cls,
        request->pp = NULL;
       }
       if (GNUNET_OK !=
-         GNUNET_CRYPTO_hash_from_string2 (request->public_key,
-                                          strlen (request->public_key),
-                                          &pub))
+         GNUNET_CRYPTO_short_hash_from_string2 (request->public_key,
+                                                strlen (request->public_key),
+                                                &pub))
       {
        /* parse error */
        return fill_s_reply ("Failed to parse given public key",
@@ -492,6 +695,22 @@ create_response (void *cls,
       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;
          request->qe = GNUNET_NAMESTORE_lookup_record (ns,
                                                        &fcfsd_zone,
@@ -555,6 +774,9 @@ request_completed_callback (void *cls,
 }
 
 
+#define UNSIGNED_MHD_LONG_LONG unsigned MHD_LONG_LONG
+
+
 /**
  * Schedule tasks to run MHD server.
  */
@@ -569,7 +791,7 @@ run_httpd ()
   struct GNUNET_NETWORK_FDSet *wes;
   int max;
   int haveto;
-  unsigned MHD_LONG_LONG timeout;
+  UNSIGNED_MHD_LONG_LONG timeout;
   struct GNUNET_TIME_Relative tv;
 
   FD_ZERO (&rs);
@@ -590,7 +812,7 @@ run_httpd ()
   GNUNET_NETWORK_fdset_copy_native (wes, &es, max + 1);
   httpd_task =
       GNUNET_SCHEDULER_add_select (GNUNET_SCHEDULER_PRIORITY_HIGH,
-                                   GNUNET_SCHEDULER_NO_TASK, tv, wrs, wws,
+                                   tv, wrs, wws,
                                    &do_httpd, NULL);
   GNUNET_NETWORK_fdset_destroy (wrs);
   GNUNET_NETWORK_fdset_destroy (wws);
@@ -631,7 +853,7 @@ do_shutdown (void *cls,
   }
   if (NULL != ns)
   {
-    GNUNET_NAMESTORE_disconnect (ns, GNUNET_NO);
+    GNUNET_NAMESTORE_disconnect (ns);
     ns = NULL;
   }
   if (NULL != httpd)
@@ -641,7 +863,7 @@ do_shutdown (void *cls,
   }
   if (NULL != fcfs_zone_pkey)
   {
-    GNUNET_CRYPTO_rsa_key_free (fcfs_zone_pkey);
+    GNUNET_CRYPTO_ecc_key_free (fcfs_zone_pkey);
     fcfs_zone_pkey = NULL;
   }
 }
@@ -661,7 +883,7 @@ run (void *cls, char *const *args, const char *cfgfile,
 {
   char *keyfile;
   unsigned long long port;
-  struct GNUNET_CRYPTO_RsaPublicKeyBinaryEncoded pub;
+  struct GNUNET_CRYPTO_EccPublicKeyBinaryEncoded pub;
 
   if (GNUNET_OK !=
       GNUNET_CONFIGURATION_get_value_number (cfg,
@@ -669,11 +891,9 @@ run (void *cls, char *const *args, const char *cfgfile,
                                             "HTTPPORT",
                                             &port))
   {
-      GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
-                 _("Option `%s' not specified in configuration section `%s'\n"),
-                 "HTTPPORT",
-                 "fcfsd");
-      return;
+    GNUNET_log_config_missing (GNUNET_ERROR_TYPE_ERROR,
+                              "fcfsd", "HTTPPORT");
+    return;
   }
   if (GNUNET_OK !=
       GNUNET_CONFIGURATION_get_value_filename (cfg,
@@ -681,13 +901,11 @@ run (void *cls, char *const *args, const char *cfgfile,
                                               "ZONEKEY",
                                               &keyfile))
   {
-    GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
-               _("Option `%s' not specified in configuration section `%s'\n"),
-               "ZONEKEY",
-               "fcfsd");
+    GNUNET_log_config_missing (GNUNET_ERROR_TYPE_ERROR,
+                              "fcfsd", "ZONEKEY");
     return;
   }
-  fcfs_zone_pkey = GNUNET_CRYPTO_rsa_key_create_from_file (keyfile);
+  fcfs_zone_pkey = GNUNET_CRYPTO_ecc_key_create_from_file (keyfile);
   GNUNET_free (keyfile);
   if (NULL == fcfs_zone_pkey)
   {
@@ -695,13 +913,9 @@ run (void *cls, char *const *args, const char *cfgfile,
                _("Failed to read or create private zone key\n"));
     return;
   }
-  GNUNET_CRYPTO_rsa_key_get_public (fcfs_zone_pkey,
+  GNUNET_CRYPTO_ecc_key_get_public (fcfs_zone_pkey,
                                    &pub);
-  GNUNET_CRYPTO_hash (&pub, sizeof (pub), &fcfsd_zone);
-  GNUNET_log (GNUNET_ERROR_TYPE_INFO,
-             _("Managing `%s' as FCFS zone on port %llu\n"),
-             GNUNET_h2s_full (&fcfsd_zone),
-             port);
+  GNUNET_CRYPTO_short_hash (&pub, sizeof (pub), &fcfsd_zone);
   ns = GNUNET_NAMESTORE_connect (cfg);
   if (NULL == ns)
     {
@@ -723,7 +937,7 @@ run (void *cls, char *const *args, const char *cfgfile,
   {
     GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
                _("Failed to start HTTP server\n"));
-    GNUNET_NAMESTORE_disconnect (ns, GNUNET_NO);
+    GNUNET_NAMESTORE_disconnect (ns);
     ns = NULL;
     return;
   }
@@ -749,6 +963,9 @@ main (int argc, char *const *argv)
 
   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 ==
@@ -756,7 +973,7 @@ main (int argc, char *const *argv)
                            _("GNUnet GNS first come first serve registration service"), 
                           options,
                            &run, NULL)) ? 0 : 1;
-
+  GNUNET_free ((void*) argv);
   return ret;
 }