reducing address size in hello to 16 bit
[oweals/gnunet.git] / src / hello / hello.c
index 5a21bd41f584483a7583bb38f130291e4dfee83a..5b30dc167cb962cf1d052adee3c06b79a1686ba3 100644 (file)
@@ -35,7 +35,7 @@
  * the format:
  *
  * 1) transport-name (0-terminated)
- * 2) address-length (uint32_t, network byte order; possibly
+ * 2) address-length (uint16_t, network byte order; possibly
  *    unaligned!)
  * 3) address expiration (GNUNET_TIME_AbsoluteNBO); possibly
  *    unaligned!)
@@ -78,21 +78,21 @@ size_t
 GNUNET_HELLO_add_address (const char *tname,
                           struct GNUNET_TIME_Absolute expiration,
                           const void *addr,
-                          size_t addr_len, char *target, size_t max)
+                          uint16_t addr_len, char *target, size_t max)
 {
-  uint32_t alen;
+  uint16_t alen;
   size_t slen;
   struct GNUNET_TIME_AbsoluteNBO exp;
 
   slen = strlen (tname) + 1;
-  if (slen + sizeof (uint32_t) + sizeof (struct GNUNET_TIME_AbsoluteNBO) +
+  if (slen + sizeof (uint16_t) + sizeof (struct GNUNET_TIME_AbsoluteNBO) +
       addr_len > max)
     return 0;
   exp = GNUNET_TIME_absolute_hton (expiration);
-  alen = htonl ((uint32_t) addr_len);
+  alen = htons (addr_len);
   memcpy (target, tname, slen);
-  memcpy (&target[slen], &alen, sizeof (uint32_t));
-  slen += sizeof (uint32_t);
+  memcpy (&target[slen], &alen, sizeof (uint16_t));
+  slen += sizeof (uint16_t);
   memcpy (&target[slen], &exp, sizeof (struct GNUNET_TIME_AbsoluteNBO));
   slen += sizeof (struct GNUNET_TIME_AbsoluteNBO);
   memcpy (&target[slen], addr, addr_len);
@@ -110,10 +110,10 @@ GNUNET_HELLO_add_address (const char *tname,
  * @return size of the entry, or 0 if max is not large enough
  */
 static size_t
-get_hello_address_size (const char *buf, size_t max, uint32_t * ralen)
+get_hello_address_size (const char *buf, size_t max, uint16_t * ralen)
 {
   const char *pos;
-  uint32_t alen;
+  uint16_t alen;
   size_t left;
   size_t slen;
 
@@ -130,19 +130,20 @@ get_hello_address_size (const char *buf, size_t max, uint32_t * ralen)
     {
       /* 0-termination not found */
       GNUNET_break_op (0);
+      abort ();
       return 0;
     }
   pos++;
-  if (left < sizeof (uint32_t) + sizeof (struct GNUNET_TIME_AbsoluteNBO))
+  if (left < sizeof (uint16_t) + sizeof (struct GNUNET_TIME_AbsoluteNBO))
     {
       /* not enough space for addrlen */
       GNUNET_break_op (0);
       return 0;
     }
-  memcpy (&alen, pos, sizeof (uint32_t));
-  alen = ntohl (alen);
+  memcpy (&alen, pos, sizeof (uint16_t));
+  alen = ntohs (alen);
   *ralen = alen;
-  slen += alen + sizeof (uint32_t) + sizeof (struct GNUNET_TIME_AbsoluteNBO);
+  slen += alen + sizeof (uint16_t) + sizeof (struct GNUNET_TIME_AbsoluteNBO);
   if (max < slen)
     {
       /* not enough space for addr */
@@ -175,10 +176,13 @@ GNUNET_HELLO_create (const struct GNUNET_CRYPTO_RsaPublicKeyBinaryEncoded
 
   max = sizeof (buffer);
   used = 0;
-  while (0 != (ret = addrgen (addrgen_cls, max, &buffer[used])))
+  if (addrgen != NULL)
     {
-      max -= ret;
-      used += ret;
+      while (0 != (ret = addrgen (addrgen_cls, max, &buffer[used])))
+       {
+         max -= ret;
+         used += ret;
+       }
     }
   hello = GNUNET_malloc (sizeof (struct GNUNET_HELLO_Message) + used);
   hello->header.type = htons (GNUNET_MESSAGE_TYPE_HELLO);
@@ -211,7 +215,7 @@ GNUNET_HELLO_iterate_addresses (const struct GNUNET_HELLO_Message *msg,
   size_t esize;
   size_t wpos;
   char *woff;
-  uint32_t alen;
+  uint16_t alen;
   struct GNUNET_TIME_AbsoluteNBO expire;
   int iret;
 
@@ -270,7 +274,8 @@ GNUNET_HELLO_iterate_addresses (const struct GNUNET_HELLO_Message *msg,
 struct ExpireContext
 {
   const void *addr;
-  size_t addrlen;
+  const char *tname;
+  uint16_t addrlen;
   int found;
   struct GNUNET_TIME_Absolute expiration;
 };
@@ -280,11 +285,13 @@ static int
 get_match_exp (void *cls,
                const char *tname,
                struct GNUNET_TIME_Absolute expiration,
-               const void *addr, size_t addrlen)
+               const void *addr, uint16_t addrlen)
 {
   struct ExpireContext *ec = cls;
 
-  if ((addrlen == ec->addrlen) && (0 == memcmp (addr, ec->addr, addrlen)))
+  if ( (addrlen == ec->addrlen) && 
+       (0 == memcmp (addr, ec->addr, addrlen)) &&
+       (0 == strcmp (tname, ec->tname)) )
     {
       ec->found = GNUNET_YES;
       ec->expiration = expiration;
@@ -311,7 +318,7 @@ static int
 copy_latest (void *cls,
              const char *tname,
              struct GNUNET_TIME_Absolute expiration,
-             const void *addr, size_t addrlen)
+             const void *addr, uint16_t addrlen)
 {
   struct MergeContext *mc = cls;
   struct ExpireContext ec;
@@ -319,17 +326,20 @@ copy_latest (void *cls,
   ec.addr = addr;
   ec.addrlen = addrlen;
   ec.found = GNUNET_NO;
+  ec.tname = tname;
   GNUNET_HELLO_iterate_addresses (mc->other, GNUNET_NO, &get_match_exp, &ec);
-  if ((ec.found == GNUNET_NO) ||
-      ((ec.expiration.value < expiration.value) ||
-       ((ec.expiration.value == expiration.value) &&
-        (mc->take_equal == GNUNET_YES))))
-    mc->ret += GNUNET_HELLO_add_address (tname,
-                                         expiration,
-                                         addr,
-                                         addrlen,
-                                         &mc->buf[mc->ret],
-                                         mc->max - mc->ret);
+  if ( (ec.found == GNUNET_NO) ||
+       (ec.expiration.value < expiration.value) ||
+       ( (ec.expiration.value == expiration.value) &&
+        (mc->take_equal == GNUNET_YES) ) )
+    {
+      mc->ret += GNUNET_HELLO_add_address (tname,
+                                          expiration,
+                                          addr,
+                                          addrlen,
+                                          &mc->buf[mc->ret],
+                                          mc->max - mc->ret);
+    }
   return GNUNET_OK;
 }
 
@@ -390,7 +400,7 @@ static int
 delta_match (void *cls,
              const char *tname,
              struct GNUNET_TIME_Absolute expiration,
-             const void *addr, size_t addrlen)
+             const void *addr, uint16_t addrlen)
 {
   struct DeltaContext *dc = cls;
   int ret;
@@ -399,6 +409,7 @@ delta_match (void *cls,
   ec.addr = addr;
   ec.addrlen = addrlen;
   ec.found = GNUNET_NO;
+  ec.tname = tname;
   GNUNET_HELLO_iterate_addresses (dc->old_hello,
                                   GNUNET_NO, &get_match_exp, &ec);
   if ((ec.found == GNUNET_YES) &&
@@ -478,5 +489,167 @@ GNUNET_HELLO_get_key (const struct GNUNET_HELLO_Message *hello,
 }
 
 
+/**
+ * Get the peer identity from a HELLO message.
+ *
+ * @param hello the hello message
+ * @param peer where to store the peer's identity
+ * @return GNUNET_SYSERR if the HELLO was malformed
+ */
+int
+GNUNET_HELLO_get_id (const struct GNUNET_HELLO_Message *hello,
+                    struct GNUNET_PeerIdentity *peer)
+{
+  uint16_t ret = ntohs (hello->header.size);
+  if ((ret < sizeof (struct GNUNET_HELLO_Message)) ||
+      (ntohs (hello->header.type) != GNUNET_MESSAGE_TYPE_HELLO))
+    return GNUNET_SYSERR;
+  GNUNET_CRYPTO_hash (&hello->publicKey,
+                     sizeof (struct GNUNET_CRYPTO_RsaPublicKeyBinaryEncoded),
+                     &peer->hashPubKey);
+  return GNUNET_OK;
+}
+
+
+/**
+ * Get the header from a HELLO message, used so other code
+ * can correctly send HELLO messages.
+ *
+ * @param hello the hello message
+ *
+ * @return header or NULL if the HELLO was malformed
+ */
+struct GNUNET_MessageHeader *
+GNUNET_HELLO_get_header (struct GNUNET_HELLO_Message *hello)
+{
+  uint16_t ret = ntohs (hello->header.size);
+  if ((ret < sizeof (struct GNUNET_HELLO_Message)) ||
+      (ntohs (hello->header.type) != GNUNET_MESSAGE_TYPE_HELLO))
+    return NULL;
+
+  return &hello->header;
+}
+
+
+struct EqualsContext
+{
+  struct GNUNET_TIME_Absolute expiration_limit;
+
+  struct GNUNET_TIME_Absolute result;
+
+  const struct GNUNET_HELLO_Message *h2;
+  
+  const char *tname;
+  
+  const void *addr;
+  
+  struct GNUNET_TIME_Absolute expiration;
+
+  int found;
+
+  uint16_t addrlen;
+
+};
+
+
+static int
+find_other_matching (void *cls,
+                    const char *tname,
+                    struct GNUNET_TIME_Absolute expiration,
+                    const void *addr, uint16_t addrlen)
+{
+  struct EqualsContext *ec = cls;
+
+  if (expiration.value < ec->expiration_limit.value)
+    return GNUNET_YES;
+  if ( (addrlen == ec->addrlen) && 
+       (0 == strcmp (tname,
+                    ec->tname)) &&
+       (0 == memcmp (addr,
+                    ec->addr,
+                    addrlen)) )
+    {
+      ec->found = GNUNET_YES;
+      if (expiration.value < ec->expiration.value)
+       {
+         ec->result = GNUNET_TIME_absolute_min (expiration,
+                                                ec->result);
+       }
+      return GNUNET_SYSERR;
+    }
+  return GNUNET_YES;
+}
+
+
+static int
+find_matching (void *cls,
+               const char *tname,
+               struct GNUNET_TIME_Absolute expiration,
+               const void *addr, uint16_t addrlen)
+{
+  struct EqualsContext *ec = cls;
+
+  if (expiration.value < ec->expiration_limit.value)
+    return GNUNET_YES;
+  ec->tname = tname;
+  ec->expiration = expiration;
+  ec->addr = addr;
+  ec->addrlen = addrlen;
+  ec->found = GNUNET_NO;
+  GNUNET_HELLO_iterate_addresses (ec->h2,
+                                 GNUNET_NO,
+                                 &find_other_matching,
+                                 ec);
+  if (ec->found == GNUNET_NO)
+    {
+      ec->result = GNUNET_TIME_UNIT_ZERO_ABS;
+      return GNUNET_SYSERR;
+    }
+  return GNUNET_OK;
+}
+
+/**
+ * Test if two HELLO messages contain the same addresses.
+ * If they only differ in expiration time, the lowest
+ * expiration time larger than 'now' where they differ
+ * is returned.
+ *
+ * @param h1 first HELLO message
+ * @param h2 the second HELLO message
+ * @param now time to use for deciding which addresses have
+ *            expired and should not be considered at all
+ * @return absolute time zero if the two HELLOs are 
+ *         totally identical; smallest timestamp >= now if
+ *         they only differ in timestamps; 
+ *         forever if the some addresses with expirations >= now
+ *         do not match at all
+ */
+struct GNUNET_TIME_Absolute 
+GNUNET_HELLO_equals (const struct
+                    GNUNET_HELLO_Message *h1,
+                    const struct
+                    GNUNET_HELLO_Message *h2,
+                    struct GNUNET_TIME_Absolute now)
+{
+  struct EqualsContext ec;
+
+  ec.expiration_limit = now;
+  ec.result = GNUNET_TIME_UNIT_FOREVER_ABS;
+  ec.h2 = h2;
+  GNUNET_HELLO_iterate_addresses (h1,
+                                  GNUNET_NO,
+                                  &find_matching,
+                                  &ec);
+  if (ec.result.value ==
+      GNUNET_TIME_UNIT_ZERO.value)
+    return ec.result; 
+  ec.h2 = h1;
+  GNUNET_HELLO_iterate_addresses (h2,
+                                  GNUNET_NO,
+                                  &find_matching,
+                                  &ec);
+  return ec.result;
+}
+
 
 /* end of hello.c */