-LRN: experimental HELLO URIs
authorChristian Grothoff <christian@grothoff.org>
Mon, 5 Mar 2012 19:56:16 +0000 (19:56 +0000)
committerChristian Grothoff <christian@grothoff.org>
Mon, 5 Mar 2012 19:56:16 +0000 (19:56 +0000)
src/hello/hello.c
src/include/gnunet_transport_plugin.h
src/peerinfo-tool/Makefile.am
src/peerinfo-tool/gnunet-peerinfo.c
src/transport/plugin_transport_tcp.c
src/transport/transport.h

index 7aa9740089a8280b84ae0a36c8600a7ece50a089..6529c933371028e350fd32b07e6514e3801ef485 100644 (file)
@@ -641,5 +641,46 @@ GNUNET_HELLO_get_last_expiration (const struct GNUNET_HELLO_Message *msg)
   return ret;
 }
 
+/**
+ * GNUnet URIs are of the general form "gnunet://MODULE/IDENTIFIER".
+ * The specific structure of "IDENTIFIER" depends on the module and
+ * maybe differenciated into additional subcategories if applicable.
+ * This module only deals with hello identifiers (MODULE = "hello").
+ * <p>
+ * 
+ * The concrete URI format is:
+ * 
+ * "gnunet://hello/PEER[!YYYYMMDDHHNNSS!<TYPE>!<ADDRESS>]...".
+ * These URIs can be used to add a peer record to peerinfo service.
+ * PEER is the string representation of peer's public key.
+ * YYYYMMDDHHNNSS is the expiration date.
+ * TYPE is a transport type.
+ * ADDRESS is the address, its format depends upon the transport type.
+ * The concrete transport types and corresponding address formats are:
+ * 
+ * <ul><li>
+ * 
+ * <TCP|UDP>!IPADDRESS
+ * IPVDDRESS is either IPV4 .-delimited address in form of XXX.XXX.XXX.XXX:PPPPP
+ * or IPV6 :-delimited address, but with '(' and ')' instead of '[' and ']' (RFC2396 advises against using square brackets in URIs):
+ * (XXXX:XXXX:XXXX:XXXX:XXXX:XXXX:XXXX:XXXX):PPPPP
+ * PPPPP is the port number. May be 0.
+ * 
+ * </li><li>
+ * 
+ * [add SMTP, HTTP and other addresses here]
+ * 
+ * </li></ul>
+ * 
+ * The encoding for hexadecimal values is defined in the crypto_hash.c
+ * module in the gnunetutil library and discussed there.
+ * 
+ * Examples:
+ * 
+ * gnunet://hello/0430205UC7D56PTQK8NV05776671CNN44FK4TL6D0GQ35OMF8MEN4RNMKA5UF6AL3DQO8B1SC5AQF50SQ2MABIRU4HC8H2HAJKJ59JL1JVRJAK308F9GASRFLMGUBB5TQ5AKR94AS5T3MDG8B9O1EMPRKB0HVCG7T6QPP4CDJ913LAEHVJ2DI1TOBB15Q1JIT5ARBOD12U4SIGRFDV3Q7T66G4TBVSJJ90UQF1BG29TGJJKLGEIMSPHHKO544D6EALQ4F2K0416311JC22GVAD48R616I7VK03K7MP7N0RS2MBV1TE9JV8CK1LSQMR7KCDRTLDA6917UGA67DHTGHERIACCGQ54TGSR48RMSGS9BA5HLMOKASFC1I6V4TT09TUGCU8GNDHQF0JF3H7LPV59UL5I38QID040G000!20120302010059!TCP!192.168.0.1:2086!TCP!64.23.8.174:0
+ * gnunet://hello/0430205UC7D56PTQK8NV05776671CNN44FK4TL6D0GQ35OMF8MEN4RNMKA5UF6AL3DQO8B1SC5AQF50SQ2MABIRU4HC8H2HAJKJ59JL1JVRJAK308F9GASRFLMGUBB5TQ5AKR94AS5T3MDG8B9O1EMPRKB0HVCG7T6QPP4CDJ913LAEHVJ2DI1TOBB15Q1JIT5ARBOD12U4SIGRFDV3Q7T66G4TBVSJJ90UQF1BG29TGJJKLGEIMSPHHKO544D6EALQ4F2K0416311JC22GVAD48R616I7VK03K7MP7N0RS2MBV1TE9JV8CK1LSQMR7KCDRTLDA6917UGA67DHTGHERIACCGQ54TGSR48RMSGS9BA5HLMOKASFC1I6V4TT09TUGCU8GNDHQF0JF3H7LPV59UL5I38QID040G000!20120302010059!TCP!(2001:db8:85a3:8d3:1319:8a2e:370:7348):2086
+ * 
+ * <p>
+ */
 
 /* end of hello.c */
index 9b39a4190cbfc96a4d71ce3406ee444b6c798236..194d4d214b789473e1891f1cfb89ccdd04a49f4d 100644 (file)
@@ -423,6 +423,26 @@ typedef const char *(*GNUNET_TRANSPORT_AddressToString) (void *cls,
                                                          const void *addr,
                                                          size_t addrlen);
 
+/**
+ * Function called to convert a string address to
+ * a binary address.
+ *
+ * @param cls closure ('struct Plugin*')
+ * @param addr string address
+ * @param addrlen length of the address
+ * @param buf location to store a buffer pointer
+ *        If the function returns GNUNET_SYSERR, its contents are undefined.
+ * @param max size of the buffer
+ * @param buf_len location to store buffer size.
+ *        If the function returns GNUNET_SYSERR, its contents are undefined.
+ * @return GNUNET_OK on success, GNUNET_SYSERR on failure
+ */
+typedef int (*GNUNET_TRANSPORT_StringToAddress) (void *cls,
+                                                 const char *addr,
+                                                 uint16_t addrlen,
+                                                 void **buf,
+                                                 size_t *added);
+
 
 /**
  * Each plugin is required to return a pointer to a struct of this
@@ -476,6 +496,12 @@ struct GNUNET_TRANSPORT_PluginFunctions
    */
   GNUNET_TRANSPORT_AddressToString address_to_string;
 
+  /**
+   * Function that will be called to convert a string address
+   * to binary (numeric conversion only).
+   */
+  GNUNET_TRANSPORT_StringToAddress string_to_address;
+
   /**
    * Function that will be called tell the plugin to create a session
    * object
index 8c5fd8fbb5f7d88d38b1907e80c7f4699aed88b1..7270bfb51e3dbfeab5217917d41f8cace0ce47ff 100644 (file)
@@ -13,11 +13,14 @@ bin_PROGRAMS = \
  gnunet-peerinfo 
 
 gnunet_peerinfo_SOURCES = \
- gnunet-peerinfo.c         
+ gnunet-peerinfo.c \
+ ../transport/gnunet-service-transport_plugins.c
+
 gnunet_peerinfo_LDADD = \
   $(top_builddir)/src/peerinfo/libgnunetpeerinfo.la \
   $(top_builddir)/src/transport/libgnunettransport.la \
   $(top_builddir)/src/hello/libgnunethello.la \
+  $(top_builddir)/src/statistics/libgnunetstatistics.la \
   $(top_builddir)/src/util/libgnunetutil.la 
 
 if HAVE_PYTHON_PEXPECT
index 21c996661077d6e688da8f63e5d6cf1367aa8a9c..1e93a5ee84e20fa3787131b2961bdba322356bd6 100644 (file)
@@ -30,6 +30,8 @@
 #include "gnunet_peerinfo_service.h"
 #include "gnunet_transport_service.h"
 #include "gnunet_program_lib.h"
+#include "gnunet_transport_plugin.h"
+#include "../transport/gnunet-service-transport_plugins.h"
 
 static int no_resolve;
 
@@ -37,8 +39,29 @@ static int be_quiet;
 
 static int get_self;
 
+static int get_uri;
+
+static char *put_uri;
+
 static struct GNUNET_PEERINFO_Handle *peerinfo;
 
+/**
+ * Configuration handle.
+ */
+const struct GNUNET_CONFIGURATION_Handle *GST_cfg;
+
+/**
+ * Statistics handle.
+ */
+struct GNUNET_STATISTICS_Handle *GST_stats;
+
+/**
+ * Configuration handle.
+ */
+struct GNUNET_PeerIdentity GST_my_identity;
+
+struct GNUNET_MessageHeader *our_hello = NULL;
+
 static const struct GNUNET_CONFIGURATION_Handle *cfg;
 
 struct PrintContext
@@ -47,8 +70,20 @@ struct PrintContext
   char **address_list;
   unsigned int num_addresses;
   uint32_t off;
+  char *uri;
+  size_t uri_len;
 };
 
+/**
+ * Obtain this peers HELLO message.
+ *
+ * @return our HELLO message
+ */
+const struct GNUNET_MessageHeader *
+GST_hello_get ()
+{
+  return (struct GNUNET_MessageHeader *) our_hello;
+}
 
 static void
 dump_pc (struct PrintContext *pc)
@@ -150,6 +185,8 @@ print_peer_info (void *cls, const struct GNUNET_PeerIdentity *peer,
     if (err_msg != NULL)
       FPRINTF (stderr, "%s",  _("Error in communication with PEERINFO service\n"));
     GNUNET_PEERINFO_disconnect (peerinfo);
+    GST_plugins_unload ();
+    GNUNET_STATISTICS_destroy (GST_stats, GNUNET_NO);
     return;
   }
   if ((be_quiet) || (NULL == hello))
@@ -169,6 +206,310 @@ print_peer_info (void *cls, const struct GNUNET_PeerIdentity *peer,
   GNUNET_HELLO_iterate_addresses (hello, GNUNET_NO, &print_address, pc);
 }
 
+static int
+compose_uri (void *cls, const struct GNUNET_HELLO_Address *address,
+             struct GNUNET_TIME_Absolute expiration)
+{
+  struct PrintContext *pc = cls;
+  struct GNUNET_TRANSPORT_PluginFunctions *papi;
+  static const char *addr;
+
+  papi = GST_plugins_find (address->transport_name);
+  if (papi == NULL)
+  {
+    /* Not an error - we might just not have the right plugin. */
+    return GNUNET_OK;
+  }
+
+  addr = papi->address_to_string (papi->cls, address->address, address->address_length);
+  if (addr != NULL)
+  {
+    ssize_t l = strlen (addr);
+    if (l > 0)
+    {
+      struct tm *t;
+      time_t seconds;
+      int s;
+      seconds = expiration.abs_value / 1000;
+      t = gmtime(&seconds);
+      pc->uri = GNUNET_realloc (pc->uri, pc->uri_len + 1 + 14 + 1 + strlen (address->transport_name) + 1 + l + 1 /* 0 */);
+      s = sprintf (&pc->uri[pc->uri_len], "!%04u%02u%02u%02u%02u%02u!%s!%s",
+          t->tm_year, t->tm_mon, t->tm_mday, t->tm_hour, t->tm_min, t->tm_sec,
+          address->transport_name, addr);
+      if (s > 0)
+        pc->uri_len += s;
+    }
+  }
+  return GNUNET_OK;
+}
+
+/**
+ * Print information about the peer.
+ */
+static void
+print_my_uri (void *cls, const struct GNUNET_PeerIdentity *peer,
+              const struct GNUNET_HELLO_Message *hello, const char *err_msg)
+{
+  struct GNUNET_CRYPTO_HashAsciiEncoded enc;
+  struct PrintContext *pc = cls;
+  char *pkey;
+
+  if (peer == NULL)
+  {
+    if (err_msg != NULL)
+      FPRINTF (stderr, "%s",  _("Error in communication with PEERINFO service\n"));
+    GNUNET_PEERINFO_disconnect (peerinfo);
+    GST_plugins_unload ();
+    GNUNET_STATISTICS_destroy (GST_stats, GNUNET_NO);
+    return;
+  }
+  if ((be_quiet) || (NULL == hello))
+  {
+    GNUNET_CRYPTO_hash_to_enc (&peer->hashPubKey, &enc);
+    printf ("%s\n", (const char *) &enc);
+    if (be_quiet && get_uri != GNUNET_YES)
+      return;
+  }
+  pc->peer = *peer;
+  GNUNET_HELLO_iterate_addresses (hello, GNUNET_NO, &count_address, pc);
+  GNUNET_HELLO_iterate_addresses (hello, GNUNET_NO, &compose_uri, pc);
+  printf ("%s\n", pc->uri);
+  GNUNET_free (pc->uri);
+  GNUNET_free (pc);
+}
+
+struct GNUNET_PEERINFO_HelloAddressParsingContext
+{
+  char *tmp;
+  char *pos;
+  size_t tmp_len;
+};
+
+static size_t
+add_addr_to_hello (void *cls, size_t max, void *buffer)
+{
+  struct tm expiration_time;
+  char buf[5];
+  long l;
+  time_t expiration_seconds;
+  struct GNUNET_TIME_Absolute expire;
+
+  struct GNUNET_PEERINFO_HelloAddressParsingContext *ctx = cls;
+  char *exp1, *exp2;
+  struct GNUNET_TRANSPORT_PluginFunctions *papi;
+  void *addr;
+  size_t addr_len;
+
+  /* End of string */
+  if (ctx->pos - ctx->tmp == ctx->tmp_len)
+    return 0;
+
+  /* Parsed past the end of string, OR wrong format */
+  if ((ctx->pos - ctx->tmp > ctx->tmp_len) || ctx->pos[0] != '!')
+  {
+    GNUNET_break (0);
+    return 0;
+  }
+
+  /* Not enough bytes (3 for three '!', 14 for expiration date, and
+   * at least 1 for type and 1 for address (1-byte long address is a joke,
+   * but it is not completely unrealistic. Zero-length address is.
+   */
+  if (ctx->tmp_len - (ctx->pos - ctx->tmp) < 1 /*!*/ * 3 + 14 + /* at least */ 2)
+  {
+    GNUNET_break (0);
+    return 0;
+  }
+  /* Go past the first '!', now we're on expiration date */
+  ctx->pos += 1;
+  /* Its length is known, so check for the next '!' right away */
+  if (ctx->pos[14] != '!')
+  {
+    GNUNET_break (0);
+    return 0;
+  }
+
+  memset (&expiration_time, 0, sizeof (struct tm));
+
+  /* This is FAR more strict than strptime(ctx->pos, "%Y%m%d%H%M%S", ...); */
+  /* FIXME: make it a separate function, since expiration is specified to every address */
+#define GETNDIGITS(n,cond) \
+  strncpy (buf, &ctx->pos[0], n); \
+  buf[n] = '\0'; \
+  errno = 0; \
+  l = strtol (buf, NULL, 10); \
+  if (errno != 0 || cond) \
+  { \
+    GNUNET_break (0); \
+    return 0; \
+  } \
+  ctx->pos += n;
+
+  GETNDIGITS (4, l < 1900)
+  expiration_time.tm_year = l - 1900;
+
+  GETNDIGITS (2, l < 1 || l > 12)
+  expiration_time.tm_mon = l;
+
+  GETNDIGITS (2, l < 1 || l > 31)
+  expiration_time.tm_mday = l;
+
+  GETNDIGITS (2, l < 0 || l > 23)
+  expiration_time.tm_hour = l;
+
+  GETNDIGITS (2, l < 0 || l > 59)
+  expiration_time.tm_min = l;
+
+  /* 60 - with a leap second */
+  GETNDIGITS (2, l < 0 || l > 60)
+  expiration_time.tm_sec = l;
+
+  expiration_time.tm_isdst = -1;
+
+#undef GETNDIGITS
+
+  expiration_seconds = mktime (&expiration_time);
+  if (expiration_seconds == (time_t) -1)
+  {
+    GNUNET_break (0);
+    return 0;
+  }
+  expire.abs_value = expiration_seconds * 1000;
+
+  /* Now we're at '!', advance to the transport type */
+  ctx->pos += 1;
+
+  /* Find the next '!' that separates transport type from
+   * the address
+   */
+  exp1 = strstr (ctx->pos, "!");
+  if (exp1 == NULL)
+  {
+    GNUNET_break (0);
+    return 0;
+  }
+  /* We need it 0-terminated */
+  exp1[0] = '\0';
+  /* Find the '!' that separates address from the next record.
+   * It might not be there, if this is the last record.
+   */
+  exp2 = strstr (&exp1[1], "!");
+  if (exp2 == NULL)
+    exp2 = &ctx->tmp[ctx->tmp_len];
+
+  papi = GST_plugins_find (ctx->pos);
+  if (papi == NULL)
+  {
+    /* Not an error - we might just not have the right plugin.
+     * Skip this part, advance to the next one and recurse.
+     * But only if this is not the end of string.
+     */
+    ctx->pos = exp2 + 1;
+    if (ctx->pos - ctx->tmp >= ctx->tmp_len)
+      return 0;
+    return add_addr_to_hello (cls, max, buffer);
+  }
+
+  if (GNUNET_OK == papi->string_to_address (papi->cls, &exp1[1], exp2 - &exp1[1], &addr, &addr_len))
+  {
+    struct GNUNET_HELLO_Address address;
+    int ret;
+
+    /* address.peer is unset - not used by add_address() */
+    address.address_length = addr_len;
+    address.address = addr;
+    address.transport_name = ctx->pos;
+    ret = GNUNET_HELLO_add_address (&address, expire, buffer, max);
+    GNUNET_free (addr);
+    ctx->pos = exp2;
+    return ret;
+  }
+  return 0;
+}
+
+void
+parse_hello (const struct GNUNET_CONFIGURATION_Handle *c,
+             const char *put_uri)
+{
+  int r;
+  char *scheme_part = NULL;
+  char *path_part = NULL;
+  char *exc;
+  struct GNUNET_CRYPTO_RsaPublicKeyBinaryEncoded pub;
+  int std_result;
+  struct GNUNET_HELLO_Message *hello;
+  struct GNUNET_PEERINFO_HelloAddressParsingContext ctx;
+
+  r = GNUNET_STRINGS_parse_uri (put_uri, &scheme_part, (const char **) &path_part);
+  if (r == GNUNET_NO)
+    return;
+  if (scheme_part == NULL || strcmp (scheme_part, "gnunet://") != 0)
+  {
+    GNUNET_free_non_null (scheme_part);
+    return;
+  }
+  GNUNET_free (scheme_part);
+
+  if (strncmp (path_part, "hello/", 6) != 0)
+    return;
+
+  path_part = &path_part[6];
+  ctx.tmp = GNUNET_strdup (path_part);
+  ctx.tmp_len = strlen (path_part);
+  exc = strstr (ctx.tmp, "!");
+  if (exc == NULL)
+    exc = ctx.pos + ctx.tmp_len;
+  ctx.pos = exc;
+
+  std_result = GNUNET_STRINGS_string_to_data (ctx.tmp, exc - ctx.tmp,
+      (unsigned char *) &pub, sizeof (pub));
+  if (std_result != GNUNET_OK)
+  {
+    GNUNET_free (ctx.tmp);
+    return;
+  }
+
+  hello = GNUNET_HELLO_create (&pub, add_addr_to_hello, &ctx);
+  GNUNET_free (ctx.tmp);
+
+  /* WARNING: this adds the address from URI WITHOUT verification! */
+  GNUNET_PEERINFO_add_peer (peerinfo, hello);
+}
+
+static struct GNUNET_TIME_Relative
+receive_stub (void *cls, const struct GNUNET_PeerIdentity *peer,
+    const struct GNUNET_MessageHeader *message,
+    const struct GNUNET_ATS_Information *ats, uint32_t ats_count,
+    struct Session *session, const char *sender_address,
+    uint16_t sender_address_len)
+{
+  struct GNUNET_TIME_Relative t;
+  t.rel_value = 0;
+  return t;
+}
+
+static void
+address_notification_stub (void *cls, int add_remove,
+    const void *addr, size_t addrlen)
+{
+}
+
+static void
+session_end_stub (void *cls, const struct GNUNET_PeerIdentity *peer,
+    struct Session * session)
+{
+}
+
+static const struct GNUNET_ATS_Information
+address_to_type_stub (void *cls, const struct sockaddr *addr,
+    size_t addrlen)
+{
+  struct GNUNET_ATS_Information t;
+  t.type = 0;
+  t.value = 0;
+  return t;
+}
+
 
 /**
  * Main function that will be run by the scheduler.
@@ -194,7 +535,12 @@ run (void *cls, char *const *args, const char *cfgfile,
     FPRINTF (stderr, _("Invalid command line argument `%s'\n"), args[0]);
     return;
   }
-  if (get_self != GNUNET_YES)
+  if (put_uri != NULL && get_uri == GNUNET_YES)
+  {
+    FPRINTF (stderr, "%s", _("--put-uri and --get-uri are mutually exclusive\n"));
+    return;
+  }
+  if (put_uri != NULL || get_uri == GNUNET_YES)
   {
     peerinfo = GNUNET_PEERINFO_connect (cfg);
     if (peerinfo == NULL)
@@ -202,6 +548,21 @@ run (void *cls, char *const *args, const char *cfgfile,
       FPRINTF (stderr, "%s",  _("Could not access PEERINFO service.  Exiting.\n"));
       return;
     }
+    GST_cfg = c;
+    GST_stats = GNUNET_STATISTICS_create ("transport", c);
+    /* FIXME: shouldn't we free GST_stats somewhere? */
+    GST_plugins_load (receive_stub, address_notification_stub,
+        session_end_stub, address_to_type_stub);
+  }
+  if (put_uri != NULL)
+  {
+    parse_hello (c, put_uri);
+    GST_plugins_unload ();
+    GNUNET_STATISTICS_destroy (GST_stats, GNUNET_NO);
+    return;
+  }
+  if (get_self != GNUNET_YES)
+  {
     GNUNET_PEERINFO_iterate (peerinfo, NULL,
                              GNUNET_TIME_relative_multiply
                              (GNUNET_TIME_UNIT_SECONDS, 5), &print_peer_info,
@@ -233,6 +594,23 @@ run (void *cls, char *const *args, const char *cfgfile,
       printf ("%s\n", (char *) &enc);
     else
       printf (_("I am peer `%s'.\n"), (const char *) &enc);
+    if (get_uri == GNUNET_YES)
+    {
+      struct PrintContext *pc;
+      char *pkey;
+      ssize_t l, pl;
+      pc = GNUNET_malloc (sizeof (struct PrintContext));
+      pkey = GNUNET_CRYPTO_rsa_public_key_to_string (&pub);
+      pl = strlen ("gnunet://hello/");
+      l = strlen (pkey) + pl;
+      pc->uri = GNUNET_malloc (l + 1);
+      strcpy (pc->uri, "gnunet://hello/");
+      strcpy (&pc->uri[pl], pkey);
+      pc->uri_len = l;
+      GNUNET_PEERINFO_iterate (peerinfo, &pid,
+          GNUNET_TIME_relative_multiply (GNUNET_TIME_UNIT_SECONDS, 5),
+          print_my_uri, pc);
+    }
   }
 }
 
@@ -257,6 +635,12 @@ main (int argc, char *const *argv)
     {'s', "self", NULL,
      gettext_noop ("output our own identity only"),
      0, &GNUNET_GETOPT_set_one, &get_self},
+    {'g', "get-hello", NULL,
+     gettext_noop ("also output HELLO uri(s)"),
+     0, &GNUNET_GETOPT_set_one, &get_uri},
+    {'p', "put-hello", "HELLO",
+     gettext_noop ("add given HELLO uri to the database"),
+     1, &GNUNET_GETOPT_set_string, &put_uri},
     GNUNET_GETOPT_OPTION_END
   };
   return (GNUNET_OK ==
index 52efd4d4e98ee33a4136c343cffb4c4e77cbb8e9..628a0ff4216931e1fab71c5ffefdadac82c1c0a7 100644 (file)
@@ -537,6 +537,109 @@ tcp_address_to_string (void *cls, const void *addr, size_t addrlen)
   return rbuf;
 }
 
+#define MAX_IPV6_ADDRLEN 47
+
+int
+tcp_string_to_address_ipv6 (void *cls, const char *addr, uint16_t addrlen,
+    void **buf, size_t *added)
+{
+  char zt_addr[MAX_IPV6_ADDRLEN + 1];
+  int ret;
+  char *port_colon;
+  unsigned int port;
+  struct IPv6TcpAddress *ipv6addr;
+
+  if (addrlen < 6)
+    return GNUNET_SYSERR;
+
+  memset (zt_addr, 0, MAX_IPV6_ADDRLEN + 1);
+  strncpy (zt_addr, addr, addrlen <= MAX_IPV6_ADDRLEN ? addrlen : MAX_IPV6_ADDRLEN);
+
+  port_colon = strrchr (zt_addr, ':');
+  if (port_colon == NULL)
+    return GNUNET_SYSERR;
+  ret = sscanf (port_colon, ":%u", &port);
+  if (ret != 1 || port > 65535)
+    return GNUNET_SYSERR;
+  port_colon[0] = '\0';
+
+  ipv6addr = GNUNET_malloc (sizeof (struct IPv6TcpAddress));
+  ret = inet_pton (AF_INET6, zt_addr, &ipv6addr->ipv6_addr);
+  if (ret <= 0)
+  {
+    GNUNET_free (ipv6addr);
+    return GNUNET_SYSERR;
+  }
+  ipv6addr->t6_port = port;
+  *buf = ipv6addr;
+  *added = sizeof (struct IPv6TcpAddress);
+  return GNUNET_OK;
+}
+
+#define MAX_IPV4_ADDRLEN 21
+
+int
+tcp_string_to_address_ipv4 (void *cls, const char *addr, uint16_t addrlen,
+    void **buf, size_t *added)
+{
+  unsigned int temps[5];
+  unsigned int port;
+  int cnt;
+  char zt_addr[MAX_IPV4_ADDRLEN + 1];
+  struct IPv4TcpAddress *ipv4addr;
+
+  if (addrlen < 9)
+    return GNUNET_SYSERR;
+
+  memset (zt_addr, 0, MAX_IPV4_ADDRLEN + 1);
+  strncpy (zt_addr, addr, addrlen <= MAX_IPV4_ADDRLEN ? addrlen : MAX_IPV4_ADDRLEN);
+
+  cnt = sscanf (zt_addr, "%u.%u.%u.%u:%u", &temps[0], &temps[1], &temps[2], &temps[3], &port);
+  if (cnt != 5)
+    return GNUNET_SYSERR;
+
+  for (cnt = 0; cnt < 4; cnt++)
+    if (temps[cnt] > 0xFF)
+      return GNUNET_SYSERR;
+  if (port > 65535)
+    return GNUNET_SYSERR;
+
+  ipv4addr = GNUNET_malloc (sizeof (struct IPv4TcpAddress));
+  ipv4addr->ipv4_addr = 
+      htonl ((temps[0] << 24) + (temps[1] << 16) + (temps[2] << 8) +
+             temps[3]);
+  ipv4addr->t4_port = htonl (port);
+  *buf = ipv4addr;
+  *added = sizeof (struct IPv4TcpAddress);
+  return GNUNET_OK;
+}
+
+/**
+ * Function called to convert a string address to
+ * a binary address.
+ *
+ * @param cls closure ('struct Plugin*')
+ * @param addr string address
+ * @param addrlen length of the address
+ * @param buf location to store the buffer
+ * @param max size of the buffer
+ * @param added location to store the number of bytes in the buffer.
+ *        If the function returns GNUNET_SYSERR, its contents are undefined.
+ * @return GNUNET_OK on success, GNUNET_SYSERR on failure
+ */
+int
+tcp_string_to_address (void *cls, const char *addr, uint16_t addrlen,
+    void **buf, size_t *added)
+{
+  if (addrlen < 1)
+    return GNUNET_SYSERR;
+
+  if (addr[0] == '(')
+    return tcp_string_to_address_ipv6 (cls, addr, addrlen, buf, added);
+  else
+    return tcp_string_to_address_ipv4 (cls, addr, addrlen, buf, added);
+}
+
 
 struct SessionClientCtx
 {
@@ -2084,6 +2187,7 @@ libgnunet_plugin_transport_tcp_init (void *cls)
   api->address_pretty_printer = &tcp_plugin_address_pretty_printer;
   api->check_address = &tcp_plugin_check_address;
   api->address_to_string = &tcp_address_to_string;
+  api->string_to_address = &tcp_string_to_address;
   plugin->service = service;
   if (service != NULL)
   {
index ff6818813f318213a06f766693e5a8bb51582b27..0277202717729ce2c00f365ffc90f58081b1c68b 100644 (file)
@@ -289,7 +289,7 @@ struct AddressLookupMessage
 {
 
   /**
-   * Type will be GNUNET_MESSAGE_TYPE_TRANSPORT_ADDRESS_LOOKUP
+   * Type will be GNUNET_MESSAGE_TYPE_TRANSPORT_ADDRESS_TO_STRING
    */
   struct GNUNET_MessageHeader header;