integrate dnsparser and dnsstub and tun with libgnunetutil
[oweals/gnunet.git] / src / namestore / namestore_api.c
index 6dc0df6fdb3d011e52b4602b691b72df6e8e8e48..55745d83d8c816ad415faba37f3c22c94cc3067f 100644 (file)
@@ -2,20 +2,18 @@
      This file is part of GNUnet.
      Copyright (C) 2010-2013, 2016 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
-     by the Free Software Foundation; either version 3, or (at your
-     option) any later version.
+     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
-     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., 51 Franklin Street, Fifth Floor,
-     Boston, MA 02110-1301, USA.
+     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/>.
 */
 
 /**
 
 #define LOG(kind,...) GNUNET_log_from (kind, "namestore-api",__VA_ARGS__)
 
+/**
+ * We grant the namestore up to 1 minute of latency, if it is slower than
+ * that, store queries will fail.
+ */
+#define NAMESTORE_DELAY_TOLERANCE GNUNET_TIME_UNIT_MINUTES
 
 /**
  * An QueueEntry used to store information for a pending
@@ -99,6 +102,11 @@ struct GNUNET_NAMESTORE_QueueEntry
    */
   struct GNUNET_MQ_Envelope *env;
 
+  /**
+   * Task scheduled to warn us if the namestore is way too slow.
+   */
+  struct GNUNET_SCHEDULER_Task *timeout_task;
+
   /**
    * The operation id this zone iteration operation has
    */
@@ -300,6 +308,8 @@ free_qe (struct GNUNET_NAMESTORE_QueueEntry *qe)
                                qe);
   if (NULL != qe->env)
     GNUNET_MQ_discard (qe->env);
+  if (NULL != qe->timeout_task)
+    GNUNET_SCHEDULER_cancel (qe->timeout_task);
   GNUNET_free (qe);
 }
 
@@ -405,6 +415,7 @@ check_lookup_result (void *cls,
   size_t name_len;
   size_t rd_len;
 
+  (void) cls;
   rd_len = ntohs (msg->rd_len);
   msg_len = ntohs (msg->gns_header.header.size);
   name_len = ntohs (msg->name_len);
@@ -517,6 +528,7 @@ check_record_result (void *cls,
   size_t name_len;
   size_t rd_len;
 
+  (void) cls;
   rd_len = ntohs (msg->rd_len);
   msg_len = ntohs (msg->gns_header.header.size);
   name_len = ntohs (msg->name_len);
@@ -656,6 +668,7 @@ check_zone_to_name_response (void *cls,
   size_t rd_ser_len;
   const char *name_tmp;
 
+  (void) cls;
   if (GNUNET_OK != ntohs (msg->res))
     return GNUNET_OK;
   name_len = ntohs (msg->name_len);
@@ -771,6 +784,7 @@ mq_error_handler (void *cls,
 {
   struct GNUNET_NAMESTORE_Handle *h = cls;
 
+  (void) error;
   force_reconnect (h);
 }
 
@@ -806,7 +820,7 @@ reconnect (struct GNUNET_NAMESTORE_Handle *h)
   struct GNUNET_NAMESTORE_QueueEntry *qe;
 
   GNUNET_assert (NULL == h->mq);
-  h->mq = GNUNET_CLIENT_connecT (h->cfg,
+  h->mq = GNUNET_CLIENT_connect (h->cfg,
                                  "namestore",
                                  handlers,
                                  &mq_error_handler,
@@ -963,6 +977,33 @@ GNUNET_NAMESTORE_disconnect (struct GNUNET_NAMESTORE_Handle *h)
 }
 
 
+/**
+ * Task launched to warn the user that the namestore is
+ * excessively slow and that a query was thus dropped.
+ *
+ * @param cls a `struct GNUNET_NAMESTORE_QueueEntry *`
+ */
+static void
+warn_delay (void *cls)
+{
+  struct GNUNET_NAMESTORE_QueueEntry *qe = cls;
+
+  qe->timeout_task = NULL;
+  LOG (GNUNET_ERROR_TYPE_WARNING,
+       "Did not receive response from namestore after %s!\n",
+       GNUNET_STRINGS_relative_time_to_string (NAMESTORE_DELAY_TOLERANCE,
+                                               GNUNET_YES));
+  if (NULL != qe->cont)
+  {
+    qe->cont (qe->cont_cls,
+              GNUNET_SYSERR,
+              "timeout");
+    qe->cont = NULL;
+  }
+  GNUNET_NAMESTORE_cancel (qe);
+}
+
+
 /**
  * Store an item in the namestore.  If the item is already present,
  * it is replaced with the new record.  Use an empty array to
@@ -990,10 +1031,11 @@ GNUNET_NAMESTORE_records_store (struct GNUNET_NAMESTORE_Handle *h,
   struct GNUNET_MQ_Envelope *env;
   char *name_tmp;
   char *rd_ser;
-  size_t rd_ser_len;
+  ssize_t rd_ser_len;
   size_t name_len;
   uint32_t rid;
   struct RecordStoreMessage *msg;
+  ssize_t sret;
 
   name_len = strlen (label) + 1;
   if (name_len > MAX_NAME_LEN)
@@ -1001,6 +1043,18 @@ GNUNET_NAMESTORE_records_store (struct GNUNET_NAMESTORE_Handle *h,
     GNUNET_break (0);
     return NULL;
   }
+  rd_ser_len = GNUNET_GNSRECORD_records_get_size (rd_count,
+                                                  rd);
+  if (rd_ser_len < 0)
+  {
+    GNUNET_break (0);
+    return NULL;
+  }
+  if (rd_ser_len > UINT16_MAX)
+  {
+    GNUNET_break (0);
+    return NULL;
+  }
   rid = get_op_id (h);
   qe = GNUNET_new (struct GNUNET_NAMESTORE_QueueEntry);
   qe->h = h;
@@ -1012,8 +1066,6 @@ GNUNET_NAMESTORE_records_store (struct GNUNET_NAMESTORE_Handle *h,
                                     qe);
 
   /* setup msg */
-  rd_ser_len = GNUNET_GNSRECORD_records_get_size (rd_count,
-                                                  rd);
   env = GNUNET_MQ_msg_extra (msg,
                              name_len + rd_ser_len,
                              GNUNET_MESSAGE_TYPE_NAMESTORE_RECORD_STORE);
@@ -1026,24 +1078,39 @@ GNUNET_NAMESTORE_records_store (struct GNUNET_NAMESTORE_Handle *h,
 
   name_tmp = (char *) &msg[1];
   GNUNET_memcpy (name_tmp,
-          label,
-          name_len);
+                 label,
+                 name_len);
   rd_ser = &name_tmp[name_len];
-  GNUNET_assert (rd_ser_len ==
-                 GNUNET_GNSRECORD_records_serialize (rd_count,
-                                                     rd,
-                                                     rd_ser_len,
-                                                     rd_ser));
+  sret = GNUNET_GNSRECORD_records_serialize (rd_count,
+                                            rd,
+                                            rd_ser_len,
+                                            rd_ser);
+  if ( (0 > sret) ||
+       (sret != rd_ser_len) )
+  {
+    GNUNET_break (0);
+    GNUNET_free (env);
+    return NULL;
+  }
+  GNUNET_assert (rd_ser_len == (size_t) sret);
   LOG (GNUNET_ERROR_TYPE_DEBUG,
        "Sending NAMESTORE_RECORD_STORE message for name `%s' with %u records\n",
        label,
        rd_count);
-
+  qe->timeout_task = GNUNET_SCHEDULER_add_delayed (NAMESTORE_DELAY_TOLERANCE,
+                                                   &warn_delay,
+                                                   qe);
   if (NULL == h->mq)
+  {
     qe->env = env;
+    LOG (GNUNET_ERROR_TYPE_WARNING,
+         "Delaying NAMESTORE_RECORD_STORE message as namestore is not ready!\n");
+  }
   else
+  {
     GNUNET_MQ_send (h->mq,
                     env);
+  }
   return qe;
 }
 
@@ -1077,7 +1144,7 @@ GNUNET_NAMESTORE_set_nick (struct GNUNET_NAMESTORE_Handle *h,
   rd.flags |= GNUNET_GNSRECORD_RF_PRIVATE;
   return GNUNET_NAMESTORE_records_store (h,
                                          pkey,
-                                         GNUNET_GNS_MASTERZONE_STR,
+                                         GNUNET_GNS_EMPTY_LABEL_AT,
                                          1,
                                          &rd,
                                          cont,
@@ -1271,19 +1338,24 @@ GNUNET_NAMESTORE_zone_iteration_start (struct GNUNET_NAMESTORE_Handle *h,
  * for the next record.
  *
  * @param it the iterator
+ * @param limit number of records to return to the iterator in one shot
+ *         (before #GNUNET_NAMESTORE_zone_iterator_next is to be called again)
  */
 void
-GNUNET_NAMESTORE_zone_iterator_next (struct GNUNET_NAMESTORE_ZoneIterator *it)
+GNUNET_NAMESTORE_zone_iterator_next (struct GNUNET_NAMESTORE_ZoneIterator *it,
+                                     uint64_t limit)
 {
   struct GNUNET_NAMESTORE_Handle *h = it->h;
   struct ZoneIterationNextMessage *msg;
   struct GNUNET_MQ_Envelope *env;
 
   LOG (GNUNET_ERROR_TYPE_DEBUG,
-       "Sending ZONE_ITERATION_NEXT message\n");
+       "Sending ZONE_ITERATION_NEXT message with limit %llu\n",
+       (unsigned long long) limit);
   env = GNUNET_MQ_msg (msg,
                        GNUNET_MESSAGE_TYPE_NAMESTORE_ZONE_ITERATION_NEXT);
   msg->gns_header.r_id = htonl (it->op_id);
+  msg->limit = GNUNET_htonll (limit);
   GNUNET_MQ_send (h->mq,
                   env);
 }
@@ -1303,11 +1375,14 @@ GNUNET_NAMESTORE_zone_iteration_stop (struct GNUNET_NAMESTORE_ZoneIterator *it)
 
   GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
              "Sending ZONE_ITERATION_STOP message\n");
-  env = GNUNET_MQ_msg (msg,
-                       GNUNET_MESSAGE_TYPE_NAMESTORE_ZONE_ITERATION_STOP);
-  msg->gns_header.r_id = htonl (it->op_id);
-  GNUNET_MQ_send (h->mq,
-                  env);
+  if (NULL != h->mq)
+  {
+    env = GNUNET_MQ_msg (msg,
+                        GNUNET_MESSAGE_TYPE_NAMESTORE_ZONE_ITERATION_STOP);
+    msg->gns_header.r_id = htonl (it->op_id);
+    GNUNET_MQ_send (h->mq,
+                   env);
+  }
   free_ze (it);
 }