-remove find() forking, we pretty much should not need this anymore, and it confused...
[oweals/gnunet.git] / src / util / resolver_api.c
index e99cab8de1dc3833bf9d3780132c89ac5d408b6a..46ac52586c752c1bb8baff3f9728d04779a52578 100644 (file)
@@ -1,10 +1,10 @@
 /*
      This file is part of GNUnet.
 /*
      This file is part of GNUnet.
-     (C) 2009 Christian Grothoff (and other contributing authors)
+     (C) 2009-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
  * @author Christian Grothoff
  */
 #include "platform.h"
  * @author Christian Grothoff
  */
 #include "platform.h"
-#include "gnunet_getopt_lib.h"
-#include "gnunet_client_lib.h"
+#include "gnunet_util_lib.h"
 #include "gnunet_protocols.h"
 #include "gnunet_resolver_service.h"
 #include "gnunet_protocols.h"
 #include "gnunet_resolver_service.h"
-#include "gnunet_server_lib.h"
 #include "resolver.h"
 
 #include "resolver.h"
 
+#define LOG(kind,...) GNUNET_log_from (kind, "resolver-api", __VA_ARGS__)
+
+#define LOG_STRERROR(kind,syscall) GNUNET_log_from_strerror (kind, "resolver-api", syscall)
 
 /**
  * Maximum supported length for a hostname
 
 /**
  * Maximum supported length for a hostname
@@ -48,6 +49,44 @@ static const char *loopback[] = {
 };
 
 
 };
 
 
+/**
+ * Configuration.
+ */
+static const struct GNUNET_CONFIGURATION_Handle *resolver_cfg;
+
+/**
+ * Our connection to the resolver service, created on-demand, but then
+ * persists until error or shutdown.
+ */
+static struct GNUNET_CLIENT_Connection *client;
+
+/**
+ * Head of DLL of requests.
+ */
+static struct GNUNET_RESOLVER_RequestHandle *req_head;
+
+/**
+ * Tail of DLL of requests.
+ */
+static struct GNUNET_RESOLVER_RequestHandle *req_tail;
+
+/**
+ * How long should we wait to reconnect?
+ */
+static struct GNUNET_TIME_Relative backoff;
+
+/**
+ * Task for reconnecting.
+ */
+static GNUNET_SCHEDULER_TaskIdentifier r_task;
+
+/**
+ * Task ID of shutdown task; only present while we have a
+ * connection to the resolver service.
+ */
+static GNUNET_SCHEDULER_TaskIdentifier s_task;
+
+
 /**
  * Handle to a request given to the resolver.  Can be used to cancel
  * the request prior to the timeout or successful execution.  Also
 /**
  * Handle to a request given to the resolver.  Can be used to cancel
  * the request prior to the timeout or successful execution.  Also
@@ -56,6 +95,16 @@ static const char *loopback[] = {
 struct GNUNET_RESOLVER_RequestHandle
 {
 
 struct GNUNET_RESOLVER_RequestHandle
 {
 
+  /**
+   * Next entry in DLL of requests.
+   */
+  struct GNUNET_RESOLVER_RequestHandle *next;
+
+  /**
+   * Previous entry in DLL of requests.
+   */
+  struct GNUNET_RESOLVER_RequestHandle *prev;
+
   /**
    * Callback if this is an name resolution request,
    * otherwise NULL.
   /**
    * Callback if this is an name resolution request,
    * otherwise NULL.
@@ -74,40 +123,47 @@ struct GNUNET_RESOLVER_RequestHandle
   void *cls;
 
   /**
   void *cls;
 
   /**
-   * Our connection to the resolver service.
+   * When should this request time out?
+   */
+  struct GNUNET_TIME_Absolute timeout;
+
+  /**
+   * Task handle for numeric lookups.
    */
    */
-  struct GNUNET_CLIENT_Connection *client;
+  GNUNET_SCHEDULER_TaskIdentifier task;
 
   /**
 
   /**
-   * Our scheduler.
+   * Desired address family.
    */
    */
-  struct GNUNET_SCHEDULER_Handle *sched;
+  int af;
 
   /**
 
   /**
-   * Name of the host that we are resolving.
+   * Has this request been transmitted to the service?
+   * GNUNET_YES if transmitted
+   * GNUNET_YES if not transmitted
+   * GNUNET_SYSERR when request was canceled
    */
    */
-  const char *hostname;
+  int was_transmitted;
 
   /**
 
   /**
-   * When should this request time out?
+   * Did we add this request to the queue?
    */
    */
-  struct GNUNET_TIME_Absolute timeout;
+  int was_queued;
 
   /**
 
   /**
-   * Task handle for numeric lookups.
+   * Desired direction (IP to name or name to IP)
    */
    */
-  GNUNET_SCHEDULER_TaskIdentifier task;
+  int direction;
 
   /**
 
   /**
-   * Desired address family.
+   * GNUNET_YES if a response was received
    */
    */
-  int domain;
+  int received_response;
 
   /**
 
   /**
-   * Length of the "struct sockaddr" that follows this
-   * struct (only for reverse lookup).
+   * Length of the data that follows this struct.
    */
    */
-  socklen_t salen;
+  size_t data_len;
 };
 
 
 };
 
 
@@ -116,7 +172,7 @@ struct GNUNET_RESOLVER_RequestHandle
  * (or equivalent).
  */
 static void
  * (or equivalent).
  */
 static void
-check_config (const struct GNUNET_CONFIGURATION_Handle *cfg)
+check_config ()
 {
   char *hostname;
   unsigned int i;
 {
   char *hostname;
   unsigned int i;
@@ -135,153 +191,292 @@ check_config (const struct GNUNET_CONFIGURATION_Handle *cfg)
   v6.sin6_len = sizeof (v6);
 #endif
   if (GNUNET_OK !=
   v6.sin6_len = sizeof (v6);
 #endif
   if (GNUNET_OK !=
-      GNUNET_CONFIGURATION_get_value_string (cfg,
-                                             "resolver",
+      GNUNET_CONFIGURATION_get_value_string (resolver_cfg, "resolver",
                                              "HOSTNAME", &hostname))
                                              "HOSTNAME", &hostname))
-    {
-      GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
-                  _("Must specify `%s' for `%s' in configuration!\n"),
-                  "HOSTNAME", "resolver");
-      GNUNET_assert (0);
-    }
-  if ((1 != inet_pton (AF_INET,
-                       hostname,
-                       &v4)) || (1 != inet_pton (AF_INET6, hostname, &v6)))
+  {
+    LOG (GNUNET_ERROR_TYPE_ERROR,
+         _("Must specify `%s' for `%s' in configuration!\n"), "HOSTNAME",
+         "resolver");
+    GNUNET_assert (0);
+  }
+  if ((1 != inet_pton (AF_INET, hostname, &v4)) ||
+      (1 != inet_pton (AF_INET6, hostname, &v6)))
+  {
+    GNUNET_free (hostname);
+    return;
+  }
+  i = 0;
+  while (NULL != loopback[i])
+    if (0 == strcasecmp (loopback[i++], hostname))
     {
       GNUNET_free (hostname);
       return;
     }
     {
       GNUNET_free (hostname);
       return;
     }
-  i = 0;
-  while (loopback[i] != NULL)
-    if (0 == strcasecmp (loopback[i++], hostname))
-      {
-        GNUNET_free (hostname);
-        return;
-      }
-  GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
-              _
-              ("Must specify `%s' or numeric IP address for `%s' of `%s' in configuration!\n"),
-              "localhost", "HOSTNAME", "resolver");
+  LOG (GNUNET_ERROR_TYPE_ERROR,
+       _("Must specify `%s' or numeric IP address for `%s' of `%s' in configuration!\n"),
+       "localhost", "HOSTNAME", "resolver");
   GNUNET_free (hostname);
   GNUNET_assert (0);
 }
 
 
   GNUNET_free (hostname);
   GNUNET_assert (0);
 }
 
 
+/**
+ * Create the connection to the resolver service.
+ *
+ * @param cfg configuration to use
+ */
+void
+GNUNET_RESOLVER_connect (const struct GNUNET_CONFIGURATION_Handle *cfg)
+{
+  GNUNET_assert (NULL != cfg);
+  backoff = GNUNET_TIME_UNIT_MILLISECONDS;
+  resolver_cfg = cfg;
+  check_config ();
+}
+
+
+/**
+ * Destroy the connection to the resolver service.
+ */
+void
+GNUNET_RESOLVER_disconnect ()
+{
+  GNUNET_assert (NULL == req_head);
+  GNUNET_assert (NULL == req_tail);
+  if (NULL != client)
+  {
+    LOG (GNUNET_ERROR_TYPE_DEBUG, "Disconnecting from DNS service\n");
+    GNUNET_CLIENT_disconnect (client);
+    client = NULL;
+  }
+  if (GNUNET_SCHEDULER_NO_TASK != r_task)
+  {
+    GNUNET_SCHEDULER_cancel (r_task);
+    r_task = GNUNET_SCHEDULER_NO_TASK;
+  }
+  if (GNUNET_SCHEDULER_NO_TASK != s_task)
+  {
+    GNUNET_SCHEDULER_cancel (s_task);
+    s_task = GNUNET_SCHEDULER_NO_TASK;
+  }
+}
+
+
 /**
  * Convert IP address to string without DNS resolution.
  *
 /**
  * Convert IP address to string without DNS resolution.
  *
- * @param sa the address 
- * @param salen number of bytes in sa
+ * @param af address family
+ * @param ip the address
+ * @param ip_len number of bytes in ip
  * @return address as a string, NULL on error
  */
 static char *
  * @return address as a string, NULL on error
  */
 static char *
-no_resolve (const struct sockaddr *sa, socklen_t salen)
+no_resolve (int af,
+           const void *ip, socklen_t ip_len)
 {
 {
-  char *ret;
-  char inet4[INET_ADDRSTRLEN];
-  char inet6[INET6_ADDRSTRLEN];
+  char buf[INET6_ADDRSTRLEN];
 
 
-  if (salen < sizeof (struct sockaddr))
-    return NULL;
-  switch (sa->sa_family)
+  switch (af)
+  {
+  case AF_INET:
+    if (ip_len != sizeof (struct in_addr))
+      return NULL;
+    if (NULL ==
+        inet_ntop (AF_INET, ip, buf, sizeof (buf)))
     {
     {
-    case AF_INET:
-      if (salen != sizeof (struct sockaddr_in))
-        return NULL;
-      inet_ntop (AF_INET,
-                 &((struct sockaddr_in *) sa)->sin_addr,
-                 inet4, INET_ADDRSTRLEN);
-      ret = GNUNET_strdup (inet4);
-      break;
-    case AF_INET6:
-      if (salen != sizeof (struct sockaddr_in6))
-        return NULL;
-      inet_ntop (AF_INET6,
-                 &((struct sockaddr_in6 *) sa)->sin6_addr,
-                 inet6, INET6_ADDRSTRLEN);
-      ret = GNUNET_strdup (inet6);
-      break;
-    default:
-      ret = NULL;
-      break;
+      LOG_STRERROR (GNUNET_ERROR_TYPE_WARNING, "inet_ntop");
+      return NULL;
     }
     }
-  return ret;
+    break;
+  case AF_INET6:
+    if (ip_len != sizeof (struct in6_addr))
+      return NULL;
+    if (NULL ==
+        inet_ntop (AF_INET6, ip, buf, sizeof (buf)))
+    {
+      LOG_STRERROR (GNUNET_ERROR_TYPE_WARNING, "inet_ntop");
+      return NULL;
+    }
+    break;
+  default:
+    GNUNET_break (0);
+    return NULL;
+  }
+  return GNUNET_strdup (buf);
 }
 
 
 /**
 }
 
 
 /**
- * Process the reply from the resolver (which is presumably
- * the numeric IP address for a name resolution request).
+ * Adjust exponential back-off and reconnect to the service.
+ */
+static void
+reconnect ();
+
+
+/**
+ * Process pending requests to the resolver.
+ */
+static void
+process_requests ();
+
+
+/**
+ * Process response with a hostname for a DNS lookup.
  *
  *
- * @param cls the "GNUNET_RESOLVER_RequestHandle" for which this is a reply
- * @param msg reply from the resolver or NULL on error
+ * @param cls our "struct GNUNET_RESOLVER_RequestHandle" context
+ * @param msg message with the hostname, NULL on error
  */
 static void
  */
 static void
-handle_address_response (void *cls, const struct GNUNET_MessageHeader *msg)
+handle_response (void *cls, const struct GNUNET_MessageHeader *msg)
 {
   struct GNUNET_RESOLVER_RequestHandle *rh = cls;
   uint16_t size;
 {
   struct GNUNET_RESOLVER_RequestHandle *rh = cls;
   uint16_t size;
-  const struct sockaddr *sa;
-  socklen_t salen;
 
 
-
-  if (msg == NULL)
+  LOG (GNUNET_ERROR_TYPE_DEBUG,
+       "Receiving response from DNS service\n");
+  if (NULL == msg)
+  {
+    char buf[INET6_ADDRSTRLEN];
+
+    if (NULL != rh->name_callback)
+      LOG (GNUNET_ERROR_TYPE_INFO,
+           _("Timeout trying to resolve IP address `%s'.\n"),
+           inet_ntop (rh->af, (const void *) &rh[1], buf, sizeof(buf)));
+    else
+      LOG (GNUNET_ERROR_TYPE_INFO,
+           _("Timeout trying to resolve hostname `%s'.\n"),
+           (const char *) &rh[1]);
+    /* check if request was canceled */
+    if (GNUNET_SYSERR != rh->was_transmitted)
     {
     {
-      GNUNET_log (GNUNET_ERROR_TYPE_INFO,
-                  _("Timeout trying to resolve hostname.\n"));
-      rh->addr_callback (rh->cls, NULL, 0);
-      GNUNET_CLIENT_disconnect (rh->client);
-      GNUNET_free (rh);
-      return;
+      if (NULL != rh->name_callback)
+      {
+        /* no reverse lookup was successful, return ip as string */
+        if (rh->received_response == GNUNET_NO)
+        {
+          rh->name_callback (rh->cls, no_resolve (rh->af, &rh[1], rh->data_len));
+          rh->name_callback (rh->cls, NULL);
+        }
+        /* at least one reverse lookup was successful */
+        else
+          rh->name_callback (rh->cls, NULL);
+      }
+      if (NULL != rh->addr_callback)
+        rh->addr_callback (rh->cls, NULL, 0);
     }
     }
+    GNUNET_CONTAINER_DLL_remove (req_head, req_tail, rh);
+    GNUNET_free (rh);
+    GNUNET_CLIENT_disconnect (client);
+    client = NULL;
+    reconnect ();
+    return;
+  }
   if (GNUNET_MESSAGE_TYPE_RESOLVER_RESPONSE != ntohs (msg->type))
   if (GNUNET_MESSAGE_TYPE_RESOLVER_RESPONSE != ntohs (msg->type))
+  {
+    GNUNET_break (0);
+    GNUNET_CLIENT_disconnect (client);
+    client = NULL;
+    reconnect ();
+    return;
+  }
+  size = ntohs (msg->size);
+  /* message contains not data, just header */
+  if (size == sizeof (struct GNUNET_MessageHeader))
+  {
+    /* check if request was canceled */
+    if (rh->was_transmitted != GNUNET_SYSERR)
+    {
+      if (NULL != rh->name_callback)
+        rh->name_callback (rh->cls, NULL);
+      if (NULL != rh->addr_callback)
+        rh->addr_callback (rh->cls, NULL, 0);
+    }
+    GNUNET_CONTAINER_DLL_remove (req_head, req_tail, rh);
+    GNUNET_free (rh);
+    process_requests ();
+    return;
+  }
+  /* return reverse lookup results to caller */
+  if (NULL != rh->name_callback)
+  {
+    const char *hostname;
+
+    hostname = (const char *) &msg[1];
+    if (hostname[size - sizeof (struct GNUNET_MessageHeader) - 1] != '\0')
     {
       GNUNET_break (0);
     {
       GNUNET_break (0);
-      rh->addr_callback (rh->cls, NULL, 0);
-      GNUNET_CLIENT_disconnect (rh->client);
+      if (rh->was_transmitted != GNUNET_SYSERR)
+        rh->name_callback (rh->cls, NULL);
+      GNUNET_CONTAINER_DLL_remove (req_head, req_tail, rh);
       GNUNET_free (rh);
       GNUNET_free (rh);
+      GNUNET_CLIENT_disconnect (client);
+      client = NULL;
+      reconnect ();
       return;
     }
       return;
     }
-
-  size = ntohs (msg->size);
-  if (size == sizeof (struct GNUNET_MessageHeader))
+    LOG (GNUNET_ERROR_TYPE_DEBUG, "Resolver returns `%s' for IP `%s'.\n",
+         hostname, GNUNET_a2s ((const void *) &rh[1], rh->data_len));
+    if (rh->was_transmitted != GNUNET_SYSERR)
+      rh->name_callback (rh->cls, hostname);
+    rh->received_response = GNUNET_YES;
+    GNUNET_CLIENT_receive (client, &handle_response, rh,
+                           GNUNET_TIME_absolute_get_remaining (rh->timeout));
+  }
+  /* return lookup results to caller */
+  if (NULL != rh->addr_callback)
+  {
+    struct sockaddr_in v4;
+    struct sockaddr_in6 v6;
+    const struct sockaddr *sa;
+    socklen_t salen;
+    const void *ip;
+    size_t ip_len;
+
+    ip = &msg[1];
+    ip_len = size - sizeof (struct GNUNET_MessageHeader);
+    if (ip_len == sizeof (struct in_addr))
     {
     {
-#if DEBUG_RESOLVER
-      GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
-                  _("Received end message resolving hostname.\n"));
+      memset (&v4, 0, sizeof (v4));
+      v4.sin_family = AF_INET;
+      v4.sin_addr = *(struct in_addr*) ip;
+#if HAVE_SOCKADDR_IN_SIN_LEN
+      v4.sin_len = sizeof (v4);
 #endif
 #endif
-      rh->addr_callback (rh->cls, NULL, 0);
-      GNUNET_CLIENT_disconnect (rh->client);
-      GNUNET_free (rh);
-      return;
+      salen = sizeof (v4);
+      sa = (const struct sockaddr *) &v4;
+    }
+    else if (ip_len == sizeof (struct in6_addr))
+    {
+      memset (&v6, 0, sizeof (v6));
+      v6.sin6_family = AF_INET6;
+      v6.sin6_addr = *(struct in6_addr*) ip;
+#if HAVE_SOCKADDR_IN_SIN_LEN
+      v6.sin6_len = sizeof (v6);
+#endif
+      salen = sizeof (v6);
+      sa = (const struct sockaddr *) &v6;
     }
     }
-  sa = (const struct sockaddr *) &msg[1];
-  salen = size - sizeof (struct GNUNET_MessageHeader);
-  if (salen < sizeof (struct sockaddr))
+    else
     {
       GNUNET_break (0);
     {
       GNUNET_break (0);
-      rh->addr_callback (rh->cls, NULL, 0);
-      GNUNET_CLIENT_disconnect (rh->client);
+      if (rh->was_transmitted != GNUNET_SYSERR)
+        rh->addr_callback (rh->cls, NULL, 0);
+      GNUNET_CONTAINER_DLL_remove (req_head, req_tail, rh);
       GNUNET_free (rh);
       GNUNET_free (rh);
+      GNUNET_CLIENT_disconnect (client);
+      client = NULL;
+      reconnect ();
       return;
     }
       return;
     }
-#if DEBUG_RESOLVER
-  {
-    char *ips = no_resolve (sa, salen);
-    GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "Resolver returns `%s'.\n", ips);
-    GNUNET_free (ips);
+    rh->addr_callback (rh->cls, sa, salen);
+    GNUNET_CLIENT_receive (client, &handle_response, rh,
+                           GNUNET_TIME_absolute_get_remaining (rh->timeout));
   }
   }
-#endif
-  rh->addr_callback (rh->cls, sa, salen);
-  GNUNET_CLIENT_receive (rh->client,
-                         &handle_address_response,
-                         rh,
-                         GNUNET_TIME_absolute_get_remaining (rh->timeout));
 }
 
 
 /**
 }
 
 
 /**
- * We've been asked to lookup the address for a hostname and were 
+ * We've been asked to lookup the address for a hostname and were
  * given a valid numeric string.  Perform the callbacks for the
  * numeric addresses.
  *
  * given a valid numeric string.  Perform the callbacks for the
  * numeric addresses.
  *
@@ -294,6 +489,7 @@ numeric_resolution (void *cls, const struct GNUNET_SCHEDULER_TaskContext *tc)
   struct GNUNET_RESOLVER_RequestHandle *rh = cls;
   struct sockaddr_in v4;
   struct sockaddr_in6 v6;
   struct GNUNET_RESOLVER_RequestHandle *rh = cls;
   struct sockaddr_in v4;
   struct sockaddr_in6 v6;
+  const char *hostname;
 
   memset (&v4, 0, sizeof (v4));
   v4.sin_family = AF_INET;
 
   memset (&v4, 0, sizeof (v4));
   v4.sin_family = AF_INET;
@@ -305,39 +501,37 @@ numeric_resolution (void *cls, const struct GNUNET_SCHEDULER_TaskContext *tc)
 #if HAVE_SOCKADDR_IN_SIN_LEN
   v6.sin6_len = sizeof (v6);
 #endif
 #if HAVE_SOCKADDR_IN_SIN_LEN
   v6.sin6_len = sizeof (v6);
 #endif
-
-  if (((rh->domain == AF_UNSPEC) || (rh->domain == AF_INET)) &&
-      (1 == inet_pton (AF_INET, rh->hostname, &v4.sin_addr)))
-    {
-      rh->addr_callback (rh->cls, (const struct sockaddr *) &v4, sizeof (v4));
-      if ((rh->domain == AF_UNSPEC) &&
-          (1 == inet_pton (AF_INET6, rh->hostname, &v6.sin6_addr)))
-        {
-          /* this can happen on some systems IF "hostname" is "localhost" */
-          rh->addr_callback (rh->cls,
-                             (const struct sockaddr *) &v6, sizeof (v6));
-        }
-      rh->addr_callback (rh->cls, NULL, 0);
-      GNUNET_free (rh);
-      return;
-    }
-  if (((rh->domain == AF_UNSPEC) || (rh->domain == AF_INET6)) &&
-      (1 == inet_pton (AF_INET6, rh->hostname, &v6.sin6_addr)))
+  hostname = (const char *) &rh[1];
+  if (((rh->af == AF_UNSPEC) || (rh->af == AF_INET)) &&
+      (1 == inet_pton (AF_INET, hostname, &v4.sin_addr)))
+  {
+    rh->addr_callback (rh->cls, (const struct sockaddr *) &v4, sizeof (v4));
+    if ((rh->af == AF_UNSPEC) &&
+        (1 == inet_pton (AF_INET6, hostname, &v6.sin6_addr)))
     {
     {
+      /* this can happen on some systems IF "hostname" is "localhost" */
       rh->addr_callback (rh->cls, (const struct sockaddr *) &v6, sizeof (v6));
       rh->addr_callback (rh->cls, (const struct sockaddr *) &v6, sizeof (v6));
-      rh->addr_callback (rh->cls, NULL, 0);
-      GNUNET_free (rh);
-      return;
     }
     }
+    rh->addr_callback (rh->cls, NULL, 0);
+    GNUNET_free (rh);
+    return;
+  }
+  if (((rh->af == AF_UNSPEC) || (rh->af == AF_INET6)) &&
+      (1 == inet_pton (AF_INET6, hostname, &v6.sin6_addr)))
+  {
+    rh->addr_callback (rh->cls, (const struct sockaddr *) &v6, sizeof (v6));
+    rh->addr_callback (rh->cls, NULL, 0);
+    GNUNET_free (rh);
+    return;
+  }
   /* why are we here? this task should not have been scheduled! */
   GNUNET_assert (0);
   GNUNET_free (rh);
 }
 
 
   /* why are we here? this task should not have been scheduled! */
   GNUNET_assert (0);
   GNUNET_free (rh);
 }
 
 
-
 /**
 /**
- * We've been asked to lookup the address for a hostname and were 
+ * We've been asked to lookup the address for a hostname and were
  * given a variant of "loopback".  Perform the callbacks for the
  * respective loopback numeric addresses.
  *
  * given a variant of "loopback".  Perform the callbacks for the
  * respective loopback numeric addresses.
  *
@@ -363,190 +557,227 @@ loopback_resolution (void *cls, const struct GNUNET_SCHEDULER_TaskContext *tc)
   v6.sin6_len = sizeof (v6);
 #endif
   v6.sin6_addr = in6addr_loopback;
   v6.sin6_len = sizeof (v6);
 #endif
   v6.sin6_addr = in6addr_loopback;
-  switch (rh->domain)
+  switch (rh->af)
+  {
+  case AF_INET:
+    rh->addr_callback (rh->cls, (const struct sockaddr *) &v4, sizeof (v4));
+    break;
+  case AF_INET6:
+    rh->addr_callback (rh->cls, (const struct sockaddr *) &v6, sizeof (v6));
+    break;
+  case AF_UNSPEC:
+    rh->addr_callback (rh->cls, (const struct sockaddr *) &v6, sizeof (v6));
+    rh->addr_callback (rh->cls, (const struct sockaddr *) &v4, sizeof (v4));
+    break;
+  default:
+    GNUNET_break (0);
+    break;
+  }
+  rh->addr_callback (rh->cls, NULL, 0);
+  GNUNET_free (rh);
+}
+
+
+/**
+ * Task executed on system shutdown.
+ */
+static void
+shutdown_task (void *cls,
+              const struct GNUNET_SCHEDULER_TaskContext *tc)
+{
+  s_task = GNUNET_SCHEDULER_NO_TASK;
+  GNUNET_RESOLVER_disconnect ();
+  backoff = GNUNET_TIME_UNIT_MILLISECONDS;
+}
+
+
+/**
+ * Process pending requests to the resolver.
+ */
+static void
+process_requests ()
+{
+  struct GNUNET_RESOLVER_GetMessage *msg;
+  char buf[GNUNET_SERVER_MAX_MESSAGE_SIZE - 1] GNUNET_ALIGN;
+  struct GNUNET_RESOLVER_RequestHandle *rh;
+
+  if (NULL == client)
+  {
+    reconnect ();
+    return;
+  }
+  rh = req_head;
+  if (NULL == rh)
+  {
+    /* nothing to do, release socket really soon if there is nothing
+     * else happening... */
+    s_task =
+        GNUNET_SCHEDULER_add_delayed (GNUNET_TIME_UNIT_MILLISECONDS,
+                                      &shutdown_task, NULL);
+    return;
+  }
+  if (GNUNET_YES == rh->was_transmitted)
+    return;                     /* waiting for reply */
+  msg = (struct GNUNET_RESOLVER_GetMessage *) buf;
+  msg->header.size =
+      htons (sizeof (struct GNUNET_RESOLVER_GetMessage) + rh->data_len);
+  msg->header.type = htons (GNUNET_MESSAGE_TYPE_RESOLVER_REQUEST);
+  msg->direction = htonl (rh->direction);
+  msg->af = htonl (rh->af);
+  memcpy (&msg[1], &rh[1], rh->data_len);
+  LOG (GNUNET_ERROR_TYPE_DEBUG,
+       "Transmitting DNS resolution request to DNS service\n");
+  if (GNUNET_OK !=
+      GNUNET_CLIENT_transmit_and_get_response (client, &msg->header,
+                                               GNUNET_TIME_absolute_get_remaining
+                                               (rh->timeout), GNUNET_YES,
+                                               &handle_response, rh))
+  {
+    GNUNET_CLIENT_disconnect (client);
+    client = NULL;
+    GNUNET_break (0);
+    reconnect ();
+    return;
+  }
+  rh->was_transmitted = GNUNET_YES;
+}
+
+
+/**
+ * Now try to reconnect to the resolver service.
+ *
+ * @param cls NULL
+ * @param tc scheduler context
+ */
+static void
+reconnect_task (void *cls, const struct GNUNET_SCHEDULER_TaskContext *tc)
+{
+  r_task = GNUNET_SCHEDULER_NO_TASK;
+  if (NULL == req_head)
+    return;                     /* no work pending */
+  if (0 != (tc->reason & GNUNET_SCHEDULER_REASON_SHUTDOWN))
+    return;
+  LOG (GNUNET_ERROR_TYPE_DEBUG,
+       "Trying to connect to DNS service\n");
+  client = GNUNET_CLIENT_connect ("resolver", resolver_cfg);
+  if (NULL == client)
+  {
+    LOG (GNUNET_ERROR_TYPE_DEBUG,
+        "Failed to connect, will try again later\n");
+    reconnect ();
+    return;
+  }
+  process_requests ();
+}
+
+
+/**
+ * Adjust exponential back-off and reconnect to the service.
+ */
+static void
+reconnect ()
+{
+  struct GNUNET_RESOLVER_RequestHandle *rh;
+
+  if (GNUNET_SCHEDULER_NO_TASK != r_task)
+    return;
+  GNUNET_assert (NULL == client);
+  if (NULL != (rh = req_head))
+  {
+    switch (rh->was_transmitted)
     {
     {
-    case AF_INET:
-      rh->addr_callback (rh->cls, (const struct sockaddr *) &v4, sizeof (v4));
+    case GNUNET_NO:
+      /* nothing more to do */
       break;
       break;
-    case AF_INET6:
-      rh->addr_callback (rh->cls, (const struct sockaddr *) &v6, sizeof (v6));
+    case GNUNET_YES:
+      /* disconnected, transmit again! */
+      rh->was_transmitted = GNUNET_NO;
       break;
       break;
-    case AF_UNSPEC:
-      rh->addr_callback (rh->cls, (const struct sockaddr *) &v6, sizeof (v6));
-      rh->addr_callback (rh->cls, (const struct sockaddr *) &v4, sizeof (v4));
+    case GNUNET_SYSERR:
+      /* request was cancelled, remove entirely */
+      GNUNET_CONTAINER_DLL_remove (req_head, req_tail, rh);
+      GNUNET_free (rh);
       break;
     default:
       break;
     default:
-      GNUNET_break (0);
+      GNUNET_assert (0);
       break;
     }
       break;
     }
-  rh->addr_callback (rh->cls, NULL, 0);
-  GNUNET_free (rh);
+  }
+  LOG (GNUNET_ERROR_TYPE_DEBUG,
+       "Will try to connect to DNS service in %s\n",
+       GNUNET_STRINGS_relative_time_to_string (backoff, GNUNET_YES));
+  GNUNET_assert (NULL != resolver_cfg);
+  r_task = GNUNET_SCHEDULER_add_delayed (backoff, &reconnect_task, NULL);
+  backoff = GNUNET_TIME_STD_BACKOFF (backoff);
 }
 
 
 /**
  * Convert a string to one or more IP addresses.
  *
 }
 
 
 /**
  * Convert a string to one or more IP addresses.
  *
- * @param sched scheduler to use
- * @param cfg configuration to use
  * @param hostname the hostname to resolve
  * @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"
  * @param callback function to call with addresses
  * @param callback_cls closure for callback
  * @param timeout how long to try resolving
  * @return handle that can be used to cancel the request, NULL on error
  */
 struct GNUNET_RESOLVER_RequestHandle *
  * @param callback function to call with addresses
  * @param callback_cls closure for callback
  * @param timeout how long to try resolving
  * @return handle that can be used to cancel the request, NULL on error
  */
 struct GNUNET_RESOLVER_RequestHandle *
-GNUNET_RESOLVER_ip_get (struct GNUNET_SCHEDULER_Handle *sched,
-                        const struct GNUNET_CONFIGURATION_Handle *cfg,
-                        const char *hostname,
-                        int domain,
+GNUNET_RESOLVER_ip_get (const char *hostname, int af,
                         struct GNUNET_TIME_Relative timeout,
                         GNUNET_RESOLVER_AddressCallback callback,
                         void *callback_cls)
 {
                         struct GNUNET_TIME_Relative timeout,
                         GNUNET_RESOLVER_AddressCallback callback,
                         void *callback_cls)
 {
-  struct GNUNET_CLIENT_Connection *client;
-  struct GNUNET_RESOLVER_GetMessage *msg;
   struct GNUNET_RESOLVER_RequestHandle *rh;
   size_t slen;
   unsigned int i;
   struct in_addr v4;
   struct in6_addr v6;
   struct GNUNET_RESOLVER_RequestHandle *rh;
   size_t slen;
   unsigned int i;
   struct in_addr v4;
   struct in6_addr v6;
-  char buf[GNUNET_SERVER_MAX_MESSAGE_SIZE];
 
 
-  check_config (cfg);
   slen = strlen (hostname) + 1;
   slen = strlen (hostname) + 1;
-  if (slen + sizeof (struct GNUNET_RESOLVER_GetMessage) >
+  if (slen + sizeof (struct GNUNET_RESOLVER_GetMessage) >=
       GNUNET_SERVER_MAX_MESSAGE_SIZE)
       GNUNET_SERVER_MAX_MESSAGE_SIZE)
-    {
-      GNUNET_break (0);
-      return NULL;
-    }
+  {
+    GNUNET_break (0);
+    return NULL;
+  }
   rh = GNUNET_malloc (sizeof (struct GNUNET_RESOLVER_RequestHandle) + slen);
   rh = GNUNET_malloc (sizeof (struct GNUNET_RESOLVER_RequestHandle) + slen);
-  rh->sched = sched;
-  rh->domain = domain;
+  rh->af = af;
   rh->addr_callback = callback;
   rh->cls = callback_cls;
   memcpy (&rh[1], hostname, slen);
   rh->addr_callback = callback;
   rh->cls = callback_cls;
   memcpy (&rh[1], hostname, slen);
-  rh->hostname = (const char *) &rh[1];
+  rh->data_len = slen;
   rh->timeout = GNUNET_TIME_relative_to_absolute (timeout);
   rh->timeout = GNUNET_TIME_relative_to_absolute (timeout);
-
+  rh->direction = GNUNET_NO;
   /* first, check if this is a numeric address */
   /* first, check if this is a numeric address */
-  if (((1 == inet_pton (AF_INET,
-                        hostname,
-                        &v4)) &&
-       ((domain == AF_INET) || (domain == AF_UNSPEC))) ||
-      ((1 == inet_pton (AF_INET6,
-                        hostname,
-                        &v6)) &&
-       ((domain == AF_INET6) || (domain == AF_UNSPEC))))
-    {
-      rh->task = GNUNET_SCHEDULER_add_now (sched,
-                                          &numeric_resolution, rh);
-      return rh;
-    }
+  if (((1 == inet_pton (AF_INET, hostname, &v4)) &&
+       ((af == AF_INET) || (af == AF_UNSPEC))) ||
+      ((1 == inet_pton (AF_INET6, hostname, &v6)) &&
+       ((af == AF_INET6) || (af == AF_UNSPEC))))
+  {
+    rh->task = GNUNET_SCHEDULER_add_now (&numeric_resolution, rh);
+    return rh;
+  }
   /* then, check if this is a loopback address */
   i = 0;
   /* then, check if this is a loopback address */
   i = 0;
-  while (loopback[i] != NULL)
+  while (NULL != loopback[i])
     if (0 == strcasecmp (loopback[i++], hostname))
     if (0 == strcasecmp (loopback[i++], hostname))
-      {
-        rh->task = GNUNET_SCHEDULER_add_now (sched,
-                                            &loopback_resolution, rh);
-        return rh;
-      }
-
-  client = GNUNET_CLIENT_connect (sched, "resolver", cfg);
-  if (client == NULL)
     {
     {
-      GNUNET_free (rh);
-      return NULL;
-    }
-  rh->client = client;
-
-  msg = (struct GNUNET_RESOLVER_GetMessage *) buf;
-  msg->header.size =
-    htons (sizeof (struct GNUNET_RESOLVER_GetMessage) + slen);
-  msg->header.type = htons (GNUNET_MESSAGE_TYPE_RESOLVER_REQUEST);
-  msg->direction = htonl (GNUNET_NO);
-  msg->domain = htonl (domain);
-  memcpy (&msg[1], hostname, slen);
-
-#if DEBUG_RESOLVER
-  GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
-              _("Resolver requests DNS resolution of hostname `%s'.\n"),
-              hostname);
-#endif
-  if (GNUNET_OK !=
-      GNUNET_CLIENT_transmit_and_get_response (client,
-                                               &msg->header,
-                                               timeout,
-                                               GNUNET_YES,
-                                               &handle_address_response, rh))
-    {
-      GNUNET_free (rh);
-      GNUNET_CLIENT_disconnect (client);
-      return NULL;
+      rh->task = GNUNET_SCHEDULER_add_now (&loopback_resolution, rh);
+      return rh;
     }
     }
+  GNUNET_CONTAINER_DLL_insert_tail (req_head, req_tail, rh);
+  rh->was_queued = GNUNET_YES;
+  if (s_task != GNUNET_SCHEDULER_NO_TASK)
+  {
+    GNUNET_SCHEDULER_cancel (s_task);
+    s_task = GNUNET_SCHEDULER_NO_TASK;
+  }
+  process_requests ();
   return rh;
 }
 
 
   return rh;
 }
 
 
-/**
- * Process response with a hostname for a reverse DNS lookup.
- *
- * @param cls our "struct GNUNET_RESOLVER_RequestHandle" context
- * @param msg message with the hostname, NULL on error
- */
-static void
-handle_hostname_response (void *cls, const struct GNUNET_MessageHeader *msg)
-{
-  struct GNUNET_RESOLVER_RequestHandle *rh = cls;
-  uint16_t size;
-  const char *hostname;
-
-  if (msg == NULL)
-    {
-      GNUNET_log (GNUNET_ERROR_TYPE_INFO,
-                  _("Timeout trying to resolve IP address.\n"));
-      rh->name_callback (rh->cls, NULL);
-      GNUNET_CLIENT_disconnect (rh->client);
-      GNUNET_free (rh);
-      return;
-    }
-  size = ntohs (msg->size);
-  if (size == sizeof (struct GNUNET_MessageHeader))
-    {
-#if DEBUG_RESOLVER
-      GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
-                  _("Received end message resolving IP address.\n"));
-#endif
-      rh->name_callback (rh->cls, NULL);
-      GNUNET_CLIENT_disconnect (rh->client);
-      GNUNET_free (rh);
-      return;
-    }
-  hostname = (const char *) &msg[1];
-  if (hostname[size - sizeof (struct GNUNET_MessageHeader) - 1] != '\0')
-    {
-      GNUNET_break (0);
-      rh->name_callback (rh->cls, NULL);
-      GNUNET_CLIENT_disconnect (rh->client);
-      GNUNET_free (rh);
-      return;
-    }
-#if DEBUG_RESOLVER
-  GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
-              _("Resolver returns `%s'.\n"), hostname);
-#endif
-  rh->name_callback (rh->cls, hostname);
-  GNUNET_CLIENT_receive (rh->client,
-                         &handle_hostname_response,
-                         rh,
-                         GNUNET_TIME_absolute_get_remaining (rh->timeout));
-}
-
-
-
 /**
  * We've been asked to convert an address to a string without
  * a reverse lookup.  Do it.
 /**
  * We've been asked to convert an address to a string without
  * a reverse lookup.  Do it.
@@ -560,140 +791,138 @@ numeric_reverse (void *cls, const struct GNUNET_SCHEDULER_TaskContext *tc)
   struct GNUNET_RESOLVER_RequestHandle *rh = cls;
   char *result;
 
   struct GNUNET_RESOLVER_RequestHandle *rh = cls;
   char *result;
 
-  result = no_resolve ((const struct sockaddr *) &rh[1], rh->salen);
-#if DEBUG_RESOLVER
-  GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, _("Resolver returns `%s'.\n"), result);
-#endif
+  result = no_resolve (rh->af, &rh[1], rh->data_len);
+  LOG (GNUNET_ERROR_TYPE_DEBUG, "Resolver returns `%s'.\n", result);
   if (result != NULL)
   if (result != NULL)
-    {
-      rh->name_callback (rh->cls, result);
-      GNUNET_free (result);
-    }
+  {
+    rh->name_callback (rh->cls, result);
+    GNUNET_free (result);
+  }
   rh->name_callback (rh->cls, NULL);
   GNUNET_free (rh);
 }
 
 
   rh->name_callback (rh->cls, NULL);
   GNUNET_free (rh);
 }
 
 
-
 /**
  * Get an IP address as a string.
  *
 /**
  * Get an IP address as a string.
  *
- * @param sched scheduler to use
- * @param cfg configuration to use
  * @param sa host address
  * @param salen length of host address
  * @param do_resolve use GNUNET_NO to return numeric hostname
  * @param timeout how long to try resolving
  * @param callback function to call with hostnames
  * @param sa host address
  * @param salen length of host address
  * @param do_resolve use GNUNET_NO to return numeric hostname
  * @param timeout how long to try resolving
  * @param callback function to call with hostnames
+ *        last callback is NULL when finished
  * @param cls closure for callback
  * @return handle that can be used to cancel the request
  */
 struct GNUNET_RESOLVER_RequestHandle *
  * @param cls closure for callback
  * @return handle that can be used to cancel the request
  */
 struct GNUNET_RESOLVER_RequestHandle *
-GNUNET_RESOLVER_hostname_get (struct GNUNET_SCHEDULER_Handle *sched,
-                              const struct GNUNET_CONFIGURATION_Handle *cfg,
-                              const struct sockaddr *sa,
-                              socklen_t salen,
+GNUNET_RESOLVER_hostname_get (const struct sockaddr *sa, socklen_t salen,
                               int do_resolve,
                               struct GNUNET_TIME_Relative timeout,
                               GNUNET_RESOLVER_HostnameCallback callback,
                               void *cls)
 {
                               int do_resolve,
                               struct GNUNET_TIME_Relative timeout,
                               GNUNET_RESOLVER_HostnameCallback callback,
                               void *cls)
 {
-  struct GNUNET_CLIENT_Connection *client;
-  struct GNUNET_RESOLVER_GetMessage *msg;
   struct GNUNET_RESOLVER_RequestHandle *rh;
   struct GNUNET_RESOLVER_RequestHandle *rh;
-  char buf[GNUNET_SERVER_MAX_MESSAGE_SIZE];
+  size_t ip_len;
+  const void *ip;
 
 
-  check_config (cfg);
+  check_config ();
+  switch (sa->sa_family)
+  {
+  case AF_INET:
+    ip_len = sizeof (struct in_addr);
+    ip = &((const struct sockaddr_in*)sa)->sin_addr;
+    break;
+  case AF_INET6:
+    ip_len = sizeof (struct in6_addr);
+    ip = &((const struct sockaddr_in6*)sa)->sin6_addr;
+    break;
+  default:
+    GNUNET_break (0);
+    return NULL;
+  }
   rh = GNUNET_malloc (sizeof (struct GNUNET_RESOLVER_RequestHandle) + salen);
   rh->name_callback = callback;
   rh->cls = cls;
   rh = GNUNET_malloc (sizeof (struct GNUNET_RESOLVER_RequestHandle) + salen);
   rh->name_callback = callback;
   rh->cls = cls;
+  rh->af = sa->sa_family;
   rh->timeout = GNUNET_TIME_relative_to_absolute (timeout);
   rh->timeout = GNUNET_TIME_relative_to_absolute (timeout);
-  rh->sched = sched;
-  rh->salen = salen;
-  memcpy (&rh[1], sa, salen);
-
+  memcpy (&rh[1], ip, ip_len);
+  rh->data_len = ip_len;
+  rh->direction = GNUNET_YES;
+  rh->received_response = GNUNET_NO;
   if (GNUNET_NO == do_resolve)
   if (GNUNET_NO == do_resolve)
-    {
-      rh->task = GNUNET_SCHEDULER_add_now (sched,
-                                          &numeric_reverse, rh);
-      return rh;
-    }
-  if (salen + sizeof (struct GNUNET_RESOLVER_GetMessage) >
-      GNUNET_SERVER_MAX_MESSAGE_SIZE)
-    {
-      GNUNET_break (0);
-      GNUNET_free (rh);
-      return NULL;
-    }
-  client = GNUNET_CLIENT_connect (sched, "resolver", cfg);
-  if (client == NULL)
-    {
-      GNUNET_free (rh);
-      return NULL;
-    }
-  rh->client = client;
-
-  msg = (struct GNUNET_RESOLVER_GetMessage *) buf;
-  msg->header.size =
-    htons (sizeof (struct GNUNET_RESOLVER_GetMessage) + salen);
-  msg->header.type = htons (GNUNET_MESSAGE_TYPE_RESOLVER_REQUEST);
-  msg->direction = htonl (GNUNET_YES);
-  msg->domain = htonl (sa->sa_family);
-  memcpy (&msg[1], sa, salen);
-#if DEBUG_RESOLVER
-  GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
-              _("Resolver requests DNS resolution of IP address.\n"));
-#endif
-  if (GNUNET_OK !=
-      GNUNET_CLIENT_transmit_and_get_response (client,
-                                               &msg->header,
-                                               timeout,
-                                               GNUNET_YES,
-                                               &handle_hostname_response, rh))
-    {
-      GNUNET_CLIENT_disconnect (client);
-      GNUNET_free (rh);
-      return NULL;
-    }
+  {
+    rh->task = GNUNET_SCHEDULER_add_now (&numeric_reverse, rh);
+    return rh;
+  }
+  GNUNET_CONTAINER_DLL_insert_tail (req_head, req_tail, rh);
+  rh->was_queued = GNUNET_YES;
+  if (s_task != GNUNET_SCHEDULER_NO_TASK)
+  {
+    GNUNET_SCHEDULER_cancel (s_task);
+    s_task = GNUNET_SCHEDULER_NO_TASK;
+  }
+  process_requests ();
   return rh;
 }
 
 
 /**
   return rh;
 }
 
 
 /**
- * Perform a reverse DNS lookup.
+ * Get local fully qualified af name
  *
  *
- * @param sched scheduler to use
- * @param cfg configuration to use
- * @param domain AF_INET or AF_INET6; use AF_UNSPEC for "any"
+ * @return fqdn
+ */
+char *
+GNUNET_RESOLVER_local_fqdn_get ()
+{
+  struct hostent *host;
+  char hostname[GNUNET_OS_get_hostname_max_length () + 1];
+
+  if (0 != gethostname (hostname, sizeof (hostname) - 1))
+  {
+    LOG_STRERROR (GNUNET_ERROR_TYPE_ERROR | GNUNET_ERROR_TYPE_BULK,
+                  "gethostname");
+    return NULL;
+  }
+  LOG (GNUNET_ERROR_TYPE_DEBUG, "Resolving our FQDN `%s'\n", hostname);
+  host = gethostbyname (hostname);
+  if (NULL == host)
+  {
+    LOG (GNUNET_ERROR_TYPE_ERROR, _("Could not resolve our FQDN : %s\n"),
+         hstrerror (h_errno));
+    return NULL;
+  }
+  return GNUNET_strdup (host->h_name);
+}
+
+
+/**
+ * Looking our own hostname.
+ *
+ * @param af AF_INET or AF_INET6; use AF_UNSPEC for "any"
  * @param callback function to call with addresses
  * @param cls closure for callback
  * @param timeout how long to try resolving
  * @return handle that can be used to cancel the request, NULL on error
  */
 struct GNUNET_RESOLVER_RequestHandle *
  * @param callback function to call with addresses
  * @param cls closure for callback
  * @param timeout how long to try resolving
  * @return handle that can be used to cancel the request, NULL on error
  */
 struct GNUNET_RESOLVER_RequestHandle *
-GNUNET_RESOLVER_hostname_resolve (struct GNUNET_SCHEDULER_Handle *sched,
-                                  const struct GNUNET_CONFIGURATION_Handle
-                                  *cfg, int domain,
+GNUNET_RESOLVER_hostname_resolve (int af,
                                   struct GNUNET_TIME_Relative timeout,
                                   GNUNET_RESOLVER_AddressCallback callback,
                                   void *cls)
 {
                                   struct GNUNET_TIME_Relative timeout,
                                   GNUNET_RESOLVER_AddressCallback callback,
                                   void *cls)
 {
-  char hostname[MAX_HOSTNAME];
+  char hostname[GNUNET_OS_get_hostname_max_length () + 1];
 
 
-  check_config (cfg);
   if (0 != gethostname (hostname, sizeof (hostname) - 1))
   if (0 != gethostname (hostname, sizeof (hostname) - 1))
-    {
-      GNUNET_log_strerror (GNUNET_ERROR_TYPE_ERROR |
-                           GNUNET_ERROR_TYPE_BULK, "gethostname");
-      return NULL;
-    }
-#if DEBUG_RESOLVER
-  GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
-              _("Resolving our hostname `%s'\n"), hostname);
-#endif
-  return GNUNET_RESOLVER_ip_get (sched,
-                                 cfg, hostname, domain, timeout, callback,
-                                 cls);
+  {
+    LOG_STRERROR (GNUNET_ERROR_TYPE_ERROR | GNUNET_ERROR_TYPE_BULK,
+                  "gethostname");
+    return NULL;
+  }
+  LOG (GNUNET_ERROR_TYPE_DEBUG,
+       "Resolving our hostname `%s'\n",
+       hostname);
+  return GNUNET_RESOLVER_ip_get (hostname, af, timeout, callback, cls);
 }
 
 
 }
 
 
@@ -703,18 +932,26 @@ GNUNET_RESOLVER_hostname_resolve (struct GNUNET_SCHEDULER_Handle *sched,
  * been completed (i.e, the callback has been called to
  * signal timeout or the final result).
  *
  * been completed (i.e, the callback has been called to
  * signal timeout or the final result).
  *
- * @param h handle of request to cancel
+ * @param rh handle of request to cancel
  */
 void
  */
 void
-GNUNET_RESOLVER_request_cancel (struct GNUNET_RESOLVER_RequestHandle *h)
+GNUNET_RESOLVER_request_cancel (struct GNUNET_RESOLVER_RequestHandle *rh)
 {
 {
-  if (h->client != NULL)
-    GNUNET_CLIENT_disconnect (h->client);
-  if (h->task != GNUNET_SCHEDULER_NO_TASK)
-    GNUNET_SCHEDULER_cancel (h->sched, h->task);
-  GNUNET_free (h);
+  if (rh->task != GNUNET_SCHEDULER_NO_TASK)
+  {
+    GNUNET_SCHEDULER_cancel (rh->task);
+    rh->task = GNUNET_SCHEDULER_NO_TASK;
+  }
+  if (rh->was_transmitted == GNUNET_NO)
+  {
+    if (rh->was_queued == GNUNET_YES)
+      GNUNET_CONTAINER_DLL_remove (req_head, req_tail, rh);
+    GNUNET_free (rh);
+    return;
+  }
+  GNUNET_assert (rh->was_transmitted == GNUNET_YES);
+  rh->was_transmitted = GNUNET_SYSERR;  /* mark as cancelled */
 }
 
 
 }
 
 
-
 /* end of resolver_api.c */
 /* end of resolver_api.c */