-doxygen and style fixes
[oweals/gnunet.git] / src / util / gnunet-service-resolver.c
index f8dd2e1669250616b97d876023451317e0b8aa76..c8d51077047ff5abedc9284606d71dabb6ab9f0a 100644 (file)
@@ -1,10 +1,10 @@
 /*
      This file is part of GNUnet.
 /*
      This file is part of GNUnet.
-     (C) 2007, 2008, 2009 Christian Grothoff (and other contributing authors)
+     (C) 2007-2013 Christian Grothoff (and other contributing authors)
 
      GNUnet is free software; you can redistribute it and/or modify
      it under the terms of the GNU General Public License as published
 
      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 2, or (at your
+     by the Free Software Foundation; either version 3, or (at your
      option) any later version.
 
      GNUnet is distributed in the hope that it will be useful, but
      option) any later version.
 
      GNUnet is distributed in the hope that it will be useful, but
  * @brief code to do DNS resolution
  * @author Christian Grothoff
  */
  * @brief code to do DNS resolution
  * @author Christian Grothoff
  */
-
-#include <stdlib.h>
 #include "platform.h"
 #include "platform.h"
-#include "gnunet_disk_lib.h"
-#include "gnunet_getopt_lib.h"
+#include "gnunet_util_lib.h"
 #include "gnunet_protocols.h"
 #include "gnunet_protocols.h"
-#include "gnunet_service_lib.h"
 #include "gnunet_statistics_service.h"
 #include "gnunet_statistics_service.h"
-#include "gnunet_strings_lib.h"
-#include "gnunet_time_lib.h"
 #include "resolver.h"
 
 /**
 #include "resolver.h"
 
 /**
 struct IPCache
 {
   /**
 struct IPCache
 {
   /**
-   * This is a linked list.
+   * This is a doubly linked list.
    */
   struct IPCache *next;
 
    */
   struct IPCache *next;
 
+  /**
+   * This is a doubly linked list.
+   */
+  struct IPCache *prev;
+
   /**
    * Hostname in human-readable form.
    */
   char *addr;
 
   /**
   /**
    * Hostname in human-readable form.
    */
   char *addr;
 
   /**
-   * Hostname in binary format.
+   * Binary IP address, allocated at the end of this struct.
    */
    */
-  struct sockaddr *sa;
+  const void *ip;
 
   /**
    * Last time this entry was updated.
 
   /**
    * Last time this entry was updated.
@@ -66,16 +65,26 @@ struct IPCache
   struct GNUNET_TIME_Absolute last_request;
 
   /**
   struct GNUNET_TIME_Absolute last_request;
 
   /**
-   * Number of bytes in sa.
+   * Number of bytes in ip.
    */
    */
-  socklen_t salen;
+  size_t ip_len;
+
+  /**
+   * Address family of the IP.
+   */
+  int af;
 };
 
 
 /**
  * Start of the linked list of cached DNS lookup results.
  */
 };
 
 
 /**
  * Start of the linked list of cached DNS lookup results.
  */
-static struct IPCache *head;
+static struct IPCache *cache_head;
+
+/**
+ * Tail of the linked list of cached DNS lookup results.
+ */
+static struct IPCache *cache_tail;
 
 
 #if HAVE_GETNAMEINFO
 
 
 #if HAVE_GETNAMEINFO
@@ -88,10 +97,42 @@ static void
 getnameinfo_resolve (struct IPCache *cache)
 {
   char hostname[256];
 getnameinfo_resolve (struct IPCache *cache)
 {
   char hostname[256];
-
-  if (0 == getnameinfo (cache->sa,
-                        cache->salen,
-                        hostname, sizeof (hostname), NULL, 0, 0))
+  const struct sockaddr *sa;
+  struct sockaddr_in v4;
+  struct sockaddr_in6 v6;
+  size_t salen;
+
+  switch (cache->af)
+  {
+  case AF_INET:
+    GNUNET_assert (cache->ip_len == sizeof (struct in_addr));
+    sa = (const struct sockaddr*) &v4;
+    memset (&v4, 0, sizeof (v4));
+    v4.sin_addr = * (const struct in_addr*) cache->ip;
+    v4.sin_family = AF_INET;
+#if HAVE_SOCKADDR_IN_SIN_LEN
+    v4.sin_len = sizeof (v4);
+#endif
+    salen = sizeof (v4);
+    break;
+  case AF_INET6:
+    GNUNET_assert (cache->ip_len == sizeof (struct in6_addr));
+    sa = (const struct sockaddr*) &v6;
+    memset (&v6, 0, sizeof (v6));
+    v6.sin6_addr = * (const struct in6_addr*) cache->ip;
+    v6.sin6_family = AF_INET6;
+#if HAVE_SOCKADDR_IN_SIN_LEN
+    v6.sin6_len = sizeof (v6);
+#endif
+    salen = sizeof (v6);
+    break;
+  default:
+    GNUNET_assert (0);
+  }
+
+  if (0 ==
+      getnameinfo (sa, salen, hostname, sizeof (hostname), NULL,
+                   0, 0))
     cache->addr = GNUNET_strdup (hostname);
 }
 #endif
     cache->addr = GNUNET_strdup (hostname);
 }
 #endif
@@ -108,24 +149,15 @@ gethostbyaddr_resolve (struct IPCache *cache)
 {
   struct hostent *ent;
 
 {
   struct hostent *ent;
 
-  switch (cache->sa->sa_family)
-    {
-    case AF_INET:
-      ent = gethostbyaddr (&((struct sockaddr_in *) cache->sa)->sin_addr,
-                           sizeof (struct in_addr), AF_INET);
-      break;
-    case AF_INET6:
-      ent = gethostbyaddr (&((struct sockaddr_in6 *) cache->sa)->sin6_addr,
-                           sizeof (struct in6_addr), AF_INET6);
-      break;
-    default:
-      ent = NULL;
-    }
+  ent = gethostbyaddr (cache->ip,
+                      cache->ip_len,
+                      cache->af);
   if (ent != NULL)
     cache->addr = GNUNET_strdup (ent->h_name);
 }
 #endif
 
   if (ent != NULL)
     cache->addr = GNUNET_strdup (ent->h_name);
 }
 #endif
 
+
 /**
  * Resolve the given request using the available methods.
  *
 /**
  * Resolve the given request using the available methods.
  *
@@ -145,7 +177,6 @@ cache_resolve (struct IPCache *cache)
 }
 
 
 }
 
 
-
 /**
  * Get an IP address as a string (works for both IPv4 and IPv6).  Note
  * that the resolution happens asynchronously and that the first call
 /**
  * Get an IP address as a string (works for both IPv4 and IPv6).  Note
  * that the resolution happens asynchronously and that the first call
@@ -153,86 +184,82 @@ cache_resolve (struct IPCache *cache)
  * human-readable IP address).
  *
  * @param client handle to the client making the request (for sending the reply)
  * human-readable IP address).
  *
  * @param client handle to the client making the request (for sending the reply)
- * @param sa should be of type "struct sockaddr*"
- * @param salen number of bytes in sa
+ * @param af AF_INET or AF_INET6
+ * @param ip 'struct in_addr' or 'struct in6_addr'
  */
 static void
 get_ip_as_string (struct GNUNET_SERVER_Client *client,
  */
 static void
 get_ip_as_string (struct GNUNET_SERVER_Client *client,
-                  const struct sockaddr *sa, socklen_t salen)
+                  int af,
+                 const void *ip)
 {
 {
-  struct IPCache *cache;
-  struct IPCache *prev;
+  struct IPCache *pos;
+  struct IPCache *next;
   struct GNUNET_TIME_Absolute now;
   struct GNUNET_SERVER_TransmitContext *tc;
   struct GNUNET_TIME_Absolute now;
   struct GNUNET_SERVER_TransmitContext *tc;
-
-  if (salen < sizeof (struct sockaddr))
-    {
-      GNUNET_break (0);
-      return;
-    }
+  size_t ip_len;
+
+  switch (af)
+  {
+  case AF_INET:
+    ip_len = sizeof (struct in_addr);
+    break;
+  case AF_INET6:
+    ip_len = sizeof (struct in6_addr);
+    break;
+  default:
+    GNUNET_assert (0);
+  }
   now = GNUNET_TIME_absolute_get ();
   now = GNUNET_TIME_absolute_get ();
-  cache = head;
-  prev = NULL;
-  while ((cache != NULL) &&
-         ((cache->salen != salen) || (0 != memcmp (cache->sa, sa, salen))))
+  next = cache_head;
+  while ( (NULL != (pos = next)) &&
+         ( (pos->af != af) ||
+           (pos->ip_len != ip_len) ||
+           (0 != memcmp (pos->ip, ip, ip_len))) )
+  {
+    next = pos->next;
+    if (GNUNET_TIME_absolute_get_duration (pos->last_request).rel_value_us <
+        60 * 60 * 1000 * 1000LL)
     {
     {
-      if (GNUNET_TIME_absolute_get_duration (cache->last_request).value <
-          60 * 60 * 1000)
-        {
-          if (prev != NULL)
-            {
-              prev->next = cache->next;
-              GNUNET_free_non_null (cache->addr);
-              GNUNET_free (cache->sa);
-              GNUNET_free (cache);
-              cache = prev->next;
-            }
-          else
-            {
-              head = cache->next;
-              GNUNET_free_non_null (cache->addr);
-              GNUNET_free (cache->sa);
-              GNUNET_free (cache);
-              cache = head;
-            }
-          continue;
-        }
-      prev = cache;
-      cache = cache->next;
+      GNUNET_CONTAINER_DLL_remove (cache_head,
+                                  cache_tail,
+                                  pos);
+      GNUNET_free_non_null (pos->addr);
+      GNUNET_free (pos);
+      continue;
     }
     }
-  if (cache != NULL)
+  }
+  if (pos != NULL)
+  {
+    pos->last_request = now;
+    if (GNUNET_TIME_absolute_get_duration (pos->last_request).rel_value_us <
+        60 * 60 * 1000 * 1000LL)
     {
     {
-      cache->last_request = now;
-      if (GNUNET_TIME_absolute_get_duration (cache->last_request).value <
-          60 * 60 * 1000)
-        {
-          GNUNET_free_non_null (cache->addr);
-          cache->addr = NULL;
-          cache->salen = 0;
-          cache_resolve (cache);
-        }
+      GNUNET_free_non_null (pos->addr);
+      pos->addr = NULL;
+      cache_resolve (pos);
     }
     }
+  }
   else
   else
-    {
-      cache = GNUNET_malloc (sizeof (struct IPCache));
-      cache->next = head;
-      cache->salen = salen;
-      cache->sa = GNUNET_malloc (salen);
-      memcpy (cache->sa, sa, salen);
-      cache->last_request = GNUNET_TIME_absolute_get ();
-      cache->last_refresh = GNUNET_TIME_absolute_get ();
-      cache->addr = NULL;
-      cache_resolve (cache);
-      head = cache;
-    }
+  {
+    pos = GNUNET_malloc (sizeof (struct IPCache) + ip_len);
+    pos->ip = &pos[1];
+    memcpy (&pos[1], ip, ip_len);
+    pos->last_request = now;
+    pos->last_refresh = now;
+    pos->ip_len = ip_len;
+    pos->af = af;
+    GNUNET_CONTAINER_DLL_insert (cache_head,
+                                cache_tail,
+                                pos);
+    cache_resolve (pos);
+  }
   tc = GNUNET_SERVER_transmit_context_create (client);
   tc = GNUNET_SERVER_transmit_context_create (client);
-  if (cache->addr != NULL)
-    GNUNET_SERVER_transmit_context_append (tc,
-                                           cache->addr,
-                                           strlen (cache->addr) + 1,
-                                           GNUNET_MESSAGE_TYPE_RESOLVER_RESPONSE);
-  GNUNET_SERVER_transmit_context_append (tc, NULL, 0,
-                                         GNUNET_MESSAGE_TYPE_RESOLVER_RESPONSE);
+  if (pos->addr != NULL)
+    GNUNET_SERVER_transmit_context_append_data (tc, pos->addr,
+                                                strlen (pos->addr) + 1,
+                                                GNUNET_MESSAGE_TYPE_RESOLVER_RESPONSE);
+  GNUNET_SERVER_transmit_context_append_data (tc, NULL, 0,
+                                              GNUNET_MESSAGE_TYPE_RESOLVER_RESPONSE);
   GNUNET_SERVER_transmit_context_run (tc, GNUNET_TIME_UNIT_FOREVER_REL);
 }
 
   GNUNET_SERVER_transmit_context_run (tc, GNUNET_TIME_UNIT_FOREVER_REL);
 }
 
@@ -240,7 +267,7 @@ get_ip_as_string (struct GNUNET_SERVER_Client *client,
 #if HAVE_GETADDRINFO
 static int
 getaddrinfo_resolve (struct GNUNET_SERVER_TransmitContext *tc,
 #if HAVE_GETADDRINFO
 static int
 getaddrinfo_resolve (struct GNUNET_SERVER_TransmitContext *tc,
-                     const char *hostname, int domain)
+                     const char *hostname, int af)
 {
   int s;
   struct addrinfo hints;
 {
   int s;
   struct addrinfo hints;
@@ -250,132 +277,139 @@ getaddrinfo_resolve (struct GNUNET_SERVER_TransmitContext *tc,
   memset (&hints, 0, sizeof (struct addrinfo));
 // FIXME in PlibC
 #ifndef MINGW
   memset (&hints, 0, sizeof (struct addrinfo));
 // FIXME in PlibC
 #ifndef MINGW
-  hints.ai_family = domain;
+  hints.ai_family = af;
 #else
   hints.ai_family = AF_INET;
 #endif
   hints.ai_socktype = SOCK_STREAM;      /* go for TCP */
 
   if (0 != (s = getaddrinfo (hostname, NULL, &hints, &result)))
 #else
   hints.ai_family = AF_INET;
 #endif
   hints.ai_socktype = SOCK_STREAM;      /* go for TCP */
 
   if (0 != (s = getaddrinfo (hostname, NULL, &hints, &result)))
-    {
-      GNUNET_log (GNUNET_ERROR_TYPE_INFO,
-                  _("Could not resolve `%s' (%s): %s\n"), hostname,
-                  (domain ==
-                   AF_INET) ? "IPv4" : ((domain ==
-                                         AF_INET6) ? "IPv6" : "any"),
-                  gai_strerror (s));
-      if ((s == EAI_BADFLAGS) || (s == EAI_MEMORY) ||
+  {
+    GNUNET_log (GNUNET_ERROR_TYPE_INFO, _("Could not resolve `%s' (%s): %s\n"),
+                hostname,
+                (af ==
+                 AF_INET) ? "IPv4" : ((af == AF_INET6) ? "IPv6" : "any"),
+                gai_strerror (s));
+    if ((s == EAI_BADFLAGS) || (s == EAI_MEMORY)
 #ifndef MINGW
 #ifndef MINGW
-          (s == EAI_SYSTEM)
+        || (s == EAI_SYSTEM)
 #else
 #else
-          // FIXME NILS
-          1
+        // FIXME NILS
+        || 1
 #endif
         )
 #endif
         )
-        return GNUNET_NO;       /* other function may still succeed */
-      return GNUNET_SYSERR;
-    }
+      return GNUNET_NO;         /* other function may still succeed */
+    return GNUNET_SYSERR;
+  }
   if (result == NULL)
     return GNUNET_SYSERR;
   pos = result;
   while (pos != NULL)
   if (result == NULL)
     return GNUNET_SYSERR;
   pos = result;
   while (pos != NULL)
+  {
+    switch (pos->ai_family)
     {
     {
-      GNUNET_SERVER_transmit_context_append (tc,
-                                             result->ai_addr,
-                                             result->ai_addrlen,
-                                             GNUNET_MESSAGE_TYPE_RESOLVER_RESPONSE);
-      pos = pos->ai_next;
+    case AF_INET:
+      GNUNET_SERVER_transmit_context_append_data (tc,
+                                                 &((struct sockaddr_in*) pos->ai_addr)->sin_addr,
+                                                 sizeof (struct in_addr),
+                                                 GNUNET_MESSAGE_TYPE_RESOLVER_RESPONSE);
+      break;
+    case AF_INET6:
+      GNUNET_SERVER_transmit_context_append_data (tc,
+                                                 &((struct sockaddr_in6*) pos->ai_addr)->sin6_addr,
+                                                 sizeof (struct in6_addr),
+                                                 GNUNET_MESSAGE_TYPE_RESOLVER_RESPONSE);
+      break;
+    default:
+      /* unsupported, skip */
+      break;
     }
     }
+    pos = pos->ai_next;
+  }
   freeaddrinfo (result);
   return GNUNET_OK;
 }
 #endif
 
   freeaddrinfo (result);
   return GNUNET_OK;
 }
 #endif
 
+
 #if HAVE_GETHOSTBYNAME2
 static int
 gethostbyname2_resolve (struct GNUNET_SERVER_TransmitContext *tc,
 #if HAVE_GETHOSTBYNAME2
 static int
 gethostbyname2_resolve (struct GNUNET_SERVER_TransmitContext *tc,
-                        const char *hostname, int domain)
+                        const char *hostname, int af)
 {
   struct hostent *hp;
 {
   struct hostent *hp;
-  struct sockaddr_in a4;
-  struct sockaddr_in6 a6;
   int ret1;
   int ret2;
 
   int ret1;
   int ret2;
 
-  if (domain == AF_UNSPEC)
-    {
-      ret1 = gethostbyname2_resolve (tc, hostname, AF_INET);
-      ret2 = gethostbyname2_resolve (tc, hostname, AF_INET6);
-      if ((ret1 == GNUNET_OK) || (ret2 == GNUNET_OK))
-        return GNUNET_OK;
-      if ((ret1 == GNUNET_SYSERR) || (ret2 == GNUNET_SYSERR))
-        return GNUNET_SYSERR;
-      return GNUNET_NO;
-    }
-  hp = gethostbyname2 (hostname, domain);
-  if (hp == NULL)
-    {
-      GNUNET_log (GNUNET_ERROR_TYPE_INFO,
-                  _("Could not find IP of host `%s': %s\n"),
-                  hostname, hstrerror (h_errno));
+  if (af == AF_UNSPEC)
+  {
+    ret1 = gethostbyname2_resolve (tc, hostname, AF_INET);
+    ret2 = gethostbyname2_resolve (tc, hostname, AF_INET6);
+    if ((ret1 == GNUNET_OK) || (ret2 == GNUNET_OK))
+      return GNUNET_OK;
+    if ((ret1 == GNUNET_SYSERR) || (ret2 == GNUNET_SYSERR))
       return GNUNET_SYSERR;
       return GNUNET_SYSERR;
-    }
-  GNUNET_assert (hp->h_addrtype == domain);
-  if (domain == AF_INET)
-    {
-      GNUNET_assert (hp->h_length == sizeof (struct in_addr));
-      memset (&a4, 0, sizeof (a4));
-      a4.sin_family = AF_INET;
-      memcpy (&a4.sin_addr, hp->h_addr_list[0], hp->h_length);
-      GNUNET_SERVER_transmit_context_append (tc,
-                                             &a4,
-                                             sizeof (a4),
-                                             GNUNET_MESSAGE_TYPE_RESOLVER_RESPONSE);
-    }
-  else
-    {
-      GNUNET_assert (hp->h_length == sizeof (struct in6_addr));
-      memset (&a6, 0, sizeof (a6));
-      a6.sin6_family = AF_INET6;
-      memcpy (&a6.sin6_addr, hp->h_addr_list[0], hp->h_length);
-      GNUNET_SERVER_transmit_context_append (tc,
-                                             &a6,
-                                             sizeof (a6),
-                                             GNUNET_MESSAGE_TYPE_RESOLVER_RESPONSE);
-    }
+    return GNUNET_NO;
+  }
+  hp = gethostbyname2 (hostname, af);
+  if (hp == NULL)
+  {
+    GNUNET_log (GNUNET_ERROR_TYPE_INFO,
+                _("Could not find IP of host `%s': %s\n"), hostname,
+                hstrerror (h_errno));
+    return GNUNET_SYSERR;
+  }
+  GNUNET_assert (hp->h_addrtype == af);
+  switch (af)
+  {
+  case AF_INET:
+    GNUNET_assert (hp->h_length == sizeof (struct in_addr));
+    GNUNET_SERVER_transmit_context_append_data (tc,
+                                               hp->h_addr_list[0],
+                                               hp->h_length,
+                                                GNUNET_MESSAGE_TYPE_RESOLVER_RESPONSE);
+    break;
+  case AF_INET6:
+    GNUNET_assert (hp->h_length == sizeof (struct in6_addr));
+    GNUNET_SERVER_transmit_context_append_data (tc,
+                                               hp->h_addr_list[0],
+                                               hp->h_length,
+                                                GNUNET_MESSAGE_TYPE_RESOLVER_RESPONSE);
+    break;
+  default:
+    GNUNET_break (0);
+    return GNUNET_SYSERR;
+  }
   return GNUNET_OK;
 }
 #endif
 
   return GNUNET_OK;
 }
 #endif
 
+
 #if HAVE_GETHOSTBYNAME
 static int
 gethostbyname_resolve (struct GNUNET_SERVER_TransmitContext *tc,
                        const char *hostname)
 {
   struct hostent *hp;
 #if HAVE_GETHOSTBYNAME
 static int
 gethostbyname_resolve (struct GNUNET_SERVER_TransmitContext *tc,
                        const char *hostname)
 {
   struct hostent *hp;
-  struct sockaddr_in addr;
 
   hp = GETHOSTBYNAME (hostname);
   if (hp == NULL)
 
   hp = GETHOSTBYNAME (hostname);
   if (hp == NULL)
-    {
-      GNUNET_log (GNUNET_ERROR_TYPE_INFO,
-                  _("Could not find IP of host `%s': %s\n"),
-                  hostname, hstrerror (h_errno));
-      return GNUNET_SYSERR;
-    }
+  {
+    GNUNET_log (GNUNET_ERROR_TYPE_INFO,
+                _("Could not find IP of host `%s': %s\n"), hostname,
+                hstrerror (h_errno));
+    return GNUNET_SYSERR;
+  }
   if (hp->h_addrtype != AF_INET)
   if (hp->h_addrtype != AF_INET)
-    {
-      GNUNET_break (0);
-      return GNUNET_SYSERR;
-    }
+  {
+    GNUNET_break (0);
+    return GNUNET_SYSERR;
+  }
   GNUNET_assert (hp->h_length == sizeof (struct in_addr));
   GNUNET_assert (hp->h_length == sizeof (struct in_addr));
-  memset (&addr, 0, sizeof (addr));
-  addr.sin_family = AF_INET;
-  memcpy (&addr.sin_addr, hp->h_addr_list[0], hp->h_length);
-  GNUNET_SERVER_transmit_context_append (tc,
-                                         &addr,
-                                         sizeof (addr),
-                                         GNUNET_MESSAGE_TYPE_RESOLVER_RESPONSE);
+  GNUNET_SERVER_transmit_context_append_data (tc,
+                                             hp->h_addr_list[0],
+                                             hp->h_length,
+                                              GNUNET_MESSAGE_TYPE_RESOLVER_RESPONSE);
   return GNUNET_OK;
 }
 #endif
   return GNUNET_OK;
 }
 #endif
@@ -386,11 +420,11 @@ gethostbyname_resolve (struct GNUNET_SERVER_TransmitContext *tc,
  *
  * @param client where to send the IP address
  * @param hostname the hostname to resolve
  *
  * @param client where to send the IP address
  * @param hostname the hostname to resolve
- * @param domain AF_INET or AF_INET6; use AF_UNSPEC for "any"
+ * @param af AF_INET or AF_INET6; use AF_UNSPEC for "any"
  */
 static void
  */
 static void
-get_ip_from_hostname (struct GNUNET_SERVER_Client *client,
-                      const char *hostname, int domain)
+get_ip_from_hostname (struct GNUNET_SERVER_Client *client, const char *hostname,
+                      int af)
 {
   int ret;
   struct GNUNET_SERVER_TransmitContext *tc;
 {
   int ret;
   struct GNUNET_SERVER_TransmitContext *tc;
@@ -399,18 +433,18 @@ get_ip_from_hostname (struct GNUNET_SERVER_Client *client,
   ret = GNUNET_NO;
 #if HAVE_GETADDRINFO
   if (ret == GNUNET_NO)
   ret = GNUNET_NO;
 #if HAVE_GETADDRINFO
   if (ret == GNUNET_NO)
-    ret = getaddrinfo_resolve (tc, hostname, domain);
+    ret = getaddrinfo_resolve (tc, hostname, af);
 #endif
 #if HAVE_GETHOSTBYNAME2
   if (ret == GNUNET_NO)
 #endif
 #if HAVE_GETHOSTBYNAME2
   if (ret == GNUNET_NO)
-    ret = gethostbyname2_resolve (tc, hostname, domain);
+    ret = gethostbyname2_resolve (tc, hostname, af);
 #endif
 #if HAVE_GETHOSTBYNAME
 #endif
 #if HAVE_GETHOSTBYNAME
-  if ((ret == GNUNET_NO) && ((domain == AF_UNSPEC) || (domain == PF_INET)))
+  if ((ret == GNUNET_NO) && ((af == AF_UNSPEC) || (af == PF_INET)))
     gethostbyname_resolve (tc, hostname);
 #endif
     gethostbyname_resolve (tc, hostname);
 #endif
-  GNUNET_SERVER_transmit_context_append (tc, NULL, 0,
-                                         GNUNET_MESSAGE_TYPE_RESOLVER_RESPONSE);
+  GNUNET_SERVER_transmit_context_append_data (tc, NULL, 0,
+                                              GNUNET_MESSAGE_TYPE_RESOLVER_RESPONSE);
   GNUNET_SERVER_transmit_context_run (tc, GNUNET_TIME_UNIT_FOREVER_REL);
 }
 
   GNUNET_SERVER_transmit_context_run (tc, GNUNET_TIME_UNIT_FOREVER_REL);
 }
 
@@ -423,79 +457,94 @@ get_ip_from_hostname (struct GNUNET_SERVER_Client *client,
  * @param message the actual message
  */
 static void
  * @param message the actual message
  */
 static void
-handle_get (void *cls,
-            struct GNUNET_SERVER_Client *client,
+handle_get (void *cls, struct GNUNET_SERVER_Client *client,
             const struct GNUNET_MessageHeader *message)
 {
   uint16_t msize;
   const struct GNUNET_RESOLVER_GetMessage *msg;
             const struct GNUNET_MessageHeader *message)
 {
   uint16_t msize;
   const struct GNUNET_RESOLVER_GetMessage *msg;
-  const char *hostname;
+  const void *ip;
   uint16_t size;
   int direction;
   uint16_t size;
   int direction;
-  int domain;
+  int af;
 
   msize = ntohs (message->size);
   if (msize < sizeof (struct GNUNET_RESOLVER_GetMessage))
 
   msize = ntohs (message->size);
   if (msize < sizeof (struct GNUNET_RESOLVER_GetMessage))
+  {
+    GNUNET_break (0);
+    GNUNET_SERVER_receive_done (client, GNUNET_SYSERR);
+    return;
+  }
+  msg = (const struct GNUNET_RESOLVER_GetMessage *) message;
+  size = msize - sizeof (struct GNUNET_RESOLVER_GetMessage);
+  direction = ntohl (msg->direction);
+  af = ntohl (msg->af);
+  if (direction == GNUNET_NO)
+  {
+    /* IP from hostname */
+    const char *hostname;
+
+    hostname = (const char *) &msg[1];
+    if (hostname[size - 1] != '\0')
     {
       GNUNET_break (0);
       GNUNET_SERVER_receive_done (client, GNUNET_SYSERR);
       return;
     }
     {
       GNUNET_break (0);
       GNUNET_SERVER_receive_done (client, GNUNET_SYSERR);
       return;
     }
-  msg = (const struct GNUNET_RESOLVER_GetMessage *) message;
-  size = msize - sizeof (struct GNUNET_RESOLVER_GetMessage);
-  direction = ntohl (msg->direction);
-  domain = ntohl (msg->domain);
-  if (direction == GNUNET_NO)
+    GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "Resolver asked to look up `%s'.\n",
+                hostname);
+    get_ip_from_hostname (client, hostname, af);
+    return;
+  }
+  ip = &msg[1];
+  switch (af)
+  {
+  case AF_INET:
+    if (size != sizeof (struct in_addr))
     {
     {
-      /* IP from hostname */
-      hostname = (const char *) &msg[1];
-      if (hostname[size - 1] != '\0')
-        {
-          GNUNET_break (0);
-          GNUNET_SERVER_receive_done (client, GNUNET_SYSERR);
-          return;
-        }
-#if DEBUG_RESOLVER
-      GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
-                  _("Resolver asked to look up `%s'.\n"), hostname);
-#endif
-      get_ip_from_hostname (client, hostname, domain);
+      GNUNET_break (0);
+      GNUNET_SERVER_receive_done (client, GNUNET_SYSERR);
+      return;
     }
     }
-  else
+    break;
+  case AF_INET6:
+    if (size != sizeof (struct in6_addr))
     {
     {
-#if DEBUG_RESOLVER
-      GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
-                  _("Resolver asked to look up IP address.\n"));
-#endif
-      get_ip_as_string (client, (const struct sockaddr *) &msg[1], size);
+      GNUNET_break (0);
+      GNUNET_SERVER_receive_done (client, GNUNET_SYSERR);
+      return;
     }
     }
+    break;
+  default:
+    GNUNET_break (0);
+    GNUNET_SERVER_receive_done (client, GNUNET_SYSERR);
+    return;
+  }
+  {
+    char buf[INET6_ADDRSTRLEN];
+
+    GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
+               "Resolver asked to look up IP address `%s'.\n",
+               inet_ntop (af, ip, buf, sizeof (buf)));
+  }
+  get_ip_as_string (client, af, ip);
 }
 
 
 }
 
 
-/**
- * List of handlers for the messages understood by this
- * service.
- */
-static struct GNUNET_SERVER_MessageHandler handlers[] = {
-  {&handle_get, NULL, GNUNET_MESSAGE_TYPE_RESOLVER_REQUEST, 0},
-  {NULL, NULL, 0, 0}
-};
-
-
 /**
  * Process resolver requests.
  *
  * @param cls closure
 /**
  * Process resolver requests.
  *
  * @param cls closure
- * @param sched scheduler to use
  * @param server the initialized server
  * @param cfg configuration to use
  */
 static void
  * @param server the initialized server
  * @param cfg configuration to use
  */
 static void
-run (void *cls,
-     struct GNUNET_SCHEDULER_Handle *sched,
-     struct GNUNET_SERVER_Handle *server,
+run (void *cls, struct GNUNET_SERVER_Handle *server,
      const struct GNUNET_CONFIGURATION_Handle *cfg)
 {
      const struct GNUNET_CONFIGURATION_Handle *cfg)
 {
+  static const struct GNUNET_SERVER_MessageHandler handlers[] = {
+    {&handle_get, NULL, GNUNET_MESSAGE_TYPE_RESOLVER_REQUEST, 0},
+    {NULL, NULL, 0, 0}
+  };
   GNUNET_SERVER_add_handlers (server, handlers);
 }
 
   GNUNET_SERVER_add_handlers (server, handlers);
 }
 
@@ -510,23 +559,37 @@ run (void *cls,
 int
 main (int argc, char *const *argv)
 {
 int
 main (int argc, char *const *argv)
 {
-  int ret;
   struct IPCache *pos;
   struct IPCache *pos;
+  int ret;
 
 
-  ret = (GNUNET_OK ==
-         GNUNET_SERVICE_run (argc,
-                             argv,
-                             "resolver", &run, NULL, NULL, NULL)) ? 0 : 1;
-
-  while (head != NULL)
-    {
-      pos = head->next;
-      GNUNET_free_non_null (head->addr);
-      GNUNET_free (head->sa);
-      GNUNET_free (head);
-      head = pos;
-    }
+  ret =
+      (GNUNET_OK ==
+       GNUNET_SERVICE_run (argc, argv, "resolver", GNUNET_SERVICE_OPTION_NONE,
+                           &run, NULL)) ? 0 : 1;
+  while (NULL != (pos = cache_head))
+  {
+    GNUNET_CONTAINER_DLL_remove (cache_head,
+                                cache_tail,
+                                pos);
+    GNUNET_free_non_null (pos->addr);
+    GNUNET_free (pos);
+  }
   return ret;
 }
 
   return ret;
 }
 
+#ifdef LINUX
+#include <malloc.h>
+
+/**
+ * MINIMIZE heap size (way below 128k) since this process doesn't need much.
+ */
+void __attribute__ ((constructor)) GNUNET_ARM_memory_init ()
+{
+  mallopt (M_TRIM_THRESHOLD, 4 * 1024);
+  mallopt (M_TOP_PAD, 1 * 1024);
+  malloc_trim (0);
+}
+#endif
+
+
 /* end of gnunet-service-resolver.c */
 /* end of gnunet-service-resolver.c */