Copyright years
[oweals/gnunet.git] / src / util / connection.c
index 9769c3cba08b4852fc8046d61f101ffd55207ab5..5aa277546a3eadf0230e4680fc1293d2cb77c4c0 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)
+     Copyright (C) 2009-2013 GNUnet e.V.
 
      GNUnet is free software; you can redistribute it and/or modify
      it under the terms of the GNU General Public License as published
 
      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
@@ -14,8 +14,8 @@
 
      You should have received a copy of the GNU General Public License
      along with GNUnet; see the file COPYING.  If not, write to the
 
      You should have received a copy of the GNU General Public License
      along with GNUnet; see the file COPYING.  If not, write to the
-     Free Software Foundation, Inc., 59 Temple Place - Suite 330,
-     Boston, MA 02111-1307, USA.
+     Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
+     Boston, MA 02110-1301, USA.
 */
 
 /**
 */
 
 /**
  * These rules should apply in general, but for this
  * module they are VERY, VERY important.
  */
  * These rules should apply in general, but for this
  * module they are VERY, VERY important.
  */
-
 #include "platform.h"
 #include "platform.h"
-#include "gnunet_common.h"
-#include "gnunet_connection_lib.h"
-#include "gnunet_container_lib.h"
+#include "gnunet_util_lib.h"
 #include "gnunet_resolver_service.h"
 #include "gnunet_resolver_service.h"
-#include "gnunet_scheduler_lib.h"
-#include "gnunet_server_lib.h"
 
 
-#define DEBUG_CONNECTION GNUNET_NO
 
 
-/**
- * Possible functions to call after connect failed or succeeded.
- */
-enum ConnectContinuations
-{
-    /**
-     * Call nothing.
-     */
-  COCO_NONE = 0,
-
-    /**
-     * Call "receive_again".
-     */
-  COCO_RECEIVE_AGAIN = 1,
-
-    /**
-     * Call "transmit_ready".
-     */
-  COCO_TRANSMIT_READY = 2,
-
-    /**
-     * Call "destroy_continuation".
-     */
-  COCO_DESTROY_CONTINUATION = 4
-};
+#define LOG(kind,...) GNUNET_log_from (kind, "util", __VA_ARGS__)
+
+#define LOG_STRERROR(kind,syscall) GNUNET_log_from_strerror (kind, "util", syscall)
 
 
 /**
 
 
 /**
@@ -86,9 +58,9 @@ struct GNUNET_CONNECTION_TransmitHandle
   void *notify_ready_cls;
 
   /**
   void *notify_ready_cls;
 
   /**
-   * Our socket handle.
+   * Our connection handle.
    */
    */
-  struct GNUNET_CONNECTION_Handle *sh;
+  struct GNUNET_CONNECTION_Handle *connection;
 
   /**
    * Timeout for receiving (in absolute time).
 
   /**
    * Timeout for receiving (in absolute time).
@@ -98,7 +70,7 @@ struct GNUNET_CONNECTION_TransmitHandle
   /**
    * Task called on timeout.
    */
   /**
    * Task called on timeout.
    */
-  GNUNET_SCHEDULER_TaskIdentifier timeout_task;
+  struct GNUNET_SCHEDULER_Task * timeout_task;
 
   /**
    * At what number of bytes available in the
 
   /**
    * At what number of bytes available in the
@@ -111,7 +83,7 @@ struct GNUNET_CONNECTION_TransmitHandle
 
 /**
  * During connect, we try multiple possible IP addresses
 
 /**
  * During connect, we try multiple possible IP addresses
- * to find out which one might work. 
+ * to find out which one might work.
  */
 struct AddressProbe
 {
  */
 struct AddressProbe
 {
@@ -139,7 +111,7 @@ struct AddressProbe
   /**
    * Connection for which we are probing.
    */
   /**
    * Connection for which we are probing.
    */
-  struct GNUNET_CONNECTION_Handle *h;
+  struct GNUNET_CONNECTION_Handle *connection;
 
   /**
    * Lenth of addr.
 
   /**
    * Lenth of addr.
@@ -147,14 +119,14 @@ struct AddressProbe
   socklen_t addrlen;
 
   /**
   socklen_t addrlen;
 
   /**
-   * Task waiting for the socket to finish connecting.
+   * Task waiting for the connection to finish connecting.
    */
    */
-  GNUNET_SCHEDULER_TaskIdentifier task;
+  struct GNUNET_SCHEDULER_Task * task;
 };
 
 
 /**
 };
 
 
 /**
- * @brief handle for a network socket
+ * @brief handle for a network connection
  */
 struct GNUNET_CONNECTION_Handle
 {
  */
 struct GNUNET_CONNECTION_Handle
 {
@@ -165,13 +137,13 @@ struct GNUNET_CONNECTION_Handle
   const struct GNUNET_CONFIGURATION_Handle *cfg;
 
   /**
   const struct GNUNET_CONFIGURATION_Handle *cfg;
 
   /**
-   * Linked list of sockets we are currently trying out 
+   * Linked list of sockets we are currently trying out
    * (during connect).
    */
   struct AddressProbe *ap_head;
 
   /**
    * (during connect).
    */
   struct AddressProbe *ap_head;
 
   /**
-   * Linked list of sockets we are currently trying out 
+   * Linked list of sockets we are currently trying out
    * (during connect).
    */
   struct AddressProbe *ap_tail;
    * (during connect).
    */
   struct AddressProbe *ap_tail;
@@ -182,7 +154,7 @@ struct GNUNET_CONNECTION_Handle
   struct sockaddr *addr;
 
   /**
   struct sockaddr *addr;
 
   /**
-   * Pointer to the hostname if socket was
+   * Pointer to the hostname if connection was
    * created using DNS lookup, otherwise NULL.
    */
   char *hostname;
    * created using DNS lookup, otherwise NULL.
    */
   char *hostname;
@@ -198,7 +170,7 @@ struct GNUNET_CONNECTION_Handle
   GNUNET_CONNECTION_Receiver receiver;
 
   /**
   GNUNET_CONNECTION_Receiver receiver;
 
   /**
-   * Closure for receiver.
+   * Closure for @e receiver.
    */
   void *receiver_cls;
 
    */
   void *receiver_cls;
 
@@ -208,41 +180,36 @@ struct GNUNET_CONNECTION_Handle
   char *write_buffer;
 
   /**
   char *write_buffer;
 
   /**
-   * Current size of our write buffer.
+   * Current size of our @e write_buffer.
    */
   size_t write_buffer_size;
 
   /**
    */
   size_t write_buffer_size;
 
   /**
-   * Current write-offset in write buffer (where
+   * Current write-offset in @e write_buffer (where
    * would we write next).
    */
   size_t write_buffer_off;
 
   /**
    * would we write next).
    */
   size_t write_buffer_off;
 
   /**
-   * Current read-offset in write buffer (how many
+   * Current read-offset in @e write_buffer (how many
    * bytes have already been sent).
    */
   size_t write_buffer_pos;
 
   /**
    * bytes have already been sent).
    */
   size_t write_buffer_pos;
 
   /**
-   * Length of addr.
+   * Length of @e addr.
    */
   socklen_t addrlen;
 
   /**
    * Read task that we may need to wait for.
    */
    */
   socklen_t addrlen;
 
   /**
    * Read task that we may need to wait for.
    */
-  GNUNET_SCHEDULER_TaskIdentifier read_task;
+  struct GNUNET_SCHEDULER_Task *read_task;
 
   /**
    * Write task that we may need to wait for.
    */
 
   /**
    * Write task that we may need to wait for.
    */
-  GNUNET_SCHEDULER_TaskIdentifier write_task;
-
-  /**
-   * Destroy task (if already scheduled).
-   */
-  GNUNET_SCHEDULER_TaskIdentifier destroy_task;
+  struct GNUNET_SCHEDULER_Task *write_task;
 
   /**
    * Handle to a pending DNS lookup request.
 
   /**
    * Handle to a pending DNS lookup request.
@@ -259,21 +226,11 @@ struct GNUNET_CONNECTION_Handle
    */
   struct GNUNET_TIME_Absolute receive_timeout;
 
    */
   struct GNUNET_TIME_Absolute receive_timeout;
 
-  /**
-   * Functions to call after connect failed or succeeded.
-   */
-  enum ConnectContinuations ccs;
-
   /**
    * Maximum number of bytes to read (for receiving).
    */
   size_t max;
 
   /**
    * Maximum number of bytes to read (for receiving).
    */
   size_t max;
 
-  /**
-   * Ignore GNUNET_SCHEDULER_REASON_SHUTDOWN for this socket.
-   */
-  int ignore_shutdown;
-
   /**
    * Port to connect to.
    */
   /**
    * Port to connect to.
    */
@@ -285,58 +242,91 @@ struct GNUNET_CONNECTION_Handle
    * termination as a signal (because only then will the leaked
    * socket be freed!)
    */
    * termination as a signal (because only then will the leaked
    * socket be freed!)
    */
-  int16_t persist;
+  int8_t persist;
+
+  /**
+   * Usually 0.  Set to 1 if this handle is in use, and should
+   * #GNUNET_CONNECTION_destroy() be called right now, the action needs
+   * to be deferred by setting it to -1.
+   */
+  int8_t destroy_later;
+
+  /**
+   * Handle to subsequent connection after proxy handshake completes,
+   */
+  struct GNUNET_CONNECTION_Handle *proxy_handshake;
 
 };
 
 
 };
 
+
 /**
  * Set the persist option on this connection handle.  Indicates
  * that the underlying socket or fd should never really be closed.
  * Used for indicating process death.
  *
 /**
  * Set the persist option on this connection handle.  Indicates
  * that the underlying socket or fd should never really be closed.
  * Used for indicating process death.
  *
- * @param sock the connection to set persistent
+ * @param connection the connection to set persistent
  */
  */
-void GNUNET_CONNECTION_persist_(struct GNUNET_CONNECTION_Handle *sock)
+void
+GNUNET_CONNECTION_persist_ (struct GNUNET_CONNECTION_Handle *connection)
 {
 {
-  sock->persist = GNUNET_YES;
+  connection->persist = GNUNET_YES;
 }
 
 }
 
+
 /**
 /**
- * Create a socket handle by boxing an existing OS socket.  The OS
+ * Disable the "CORK" feature for communication with the given connection,
+ * forcing the OS to immediately flush the buffer on transmission
+ * instead of potentially buffering multiple messages.  Essentially
+ * reduces the OS send buffers to zero.
+ * Used to make sure that the last messages sent through the connection
+ * reach the other side before the process is terminated.
+ *
+ * @param connection the connection to make flushing and blocking
+ * @return #GNUNET_OK on success
+ */
+int
+GNUNET_CONNECTION_disable_corking (struct GNUNET_CONNECTION_Handle *connection)
+{
+  return GNUNET_NETWORK_socket_disable_corking (connection->sock);
+}
+
+
+/**
+ * Create a connection handle by boxing an existing OS socket.  The OS
  * socket should henceforth be no longer used directly.
  * socket should henceforth be no longer used directly.
- * GNUNET_socket_destroy will close it.
+ * #GNUNET_connection_destroy() will close it.
  *
  * @param osSocket existing socket to box
  *
  * @param osSocket existing socket to box
- * @return the boxed socket handle
+ * @return the boxed connection handle
  */
 struct GNUNET_CONNECTION_Handle *
  */
 struct GNUNET_CONNECTION_Handle *
-GNUNET_CONNECTION_create_from_existing (struct GNUNET_NETWORK_Handle
-                                        *osSocket)
+GNUNET_CONNECTION_create_from_existing (struct GNUNET_NETWORK_Handle *osSocket)
 {
 {
-  struct GNUNET_CONNECTION_Handle *ret;
-  ret = GNUNET_malloc (sizeof (struct GNUNET_CONNECTION_Handle));
-  ret->write_buffer_size = GNUNET_SERVER_MIN_BUFFER_SIZE;
-  ret->write_buffer = GNUNET_malloc(ret->write_buffer_size);
-  ret->sock = osSocket;
-  return ret;
+  struct GNUNET_CONNECTION_Handle *connection;
+
+  connection = GNUNET_new (struct GNUNET_CONNECTION_Handle);
+  connection->write_buffer_size = GNUNET_SERVER_MIN_BUFFER_SIZE;
+  connection->write_buffer = GNUNET_malloc (connection->write_buffer_size);
+  connection->sock = osSocket;
+  return connection;
 }
 
 
 /**
 }
 
 
 /**
- * Create a socket handle by accepting on a listen socket.  This
+ * Create a connection handle by accepting on a listen socket.  This
  * function may block if the listen socket has no connection ready.
  *
  * function may block if the listen socket has no connection ready.
  *
- * @param access function to use to check if access is allowed
- * @param access_cls closure for access
+ * @param access_cb function to use to check if access is allowed
+ * @param access_cb_cls closure for @a access_cb
  * @param lsock listen socket
  * @param lsock listen socket
- * @return the socket handle, NULL on error
+ * @return the connection handle, NULL on error
  */
 struct GNUNET_CONNECTION_Handle *
  */
 struct GNUNET_CONNECTION_Handle *
-GNUNET_CONNECTION_create_from_accept (GNUNET_CONNECTION_AccessCheck access,
-                                      void *access_cls,
+GNUNET_CONNECTION_create_from_accept (GNUNET_CONNECTION_AccessCheck access_cb,
+                                      void *access_cb_cls,
                                       struct GNUNET_NETWORK_Handle *lsock)
 {
                                       struct GNUNET_NETWORK_Handle *lsock)
 {
-  struct GNUNET_CONNECTION_Handle *ret;
+  struct GNUNET_CONNECTION_Handle *connection;
   char addr[128];
   socklen_t addrlen;
   struct GNUNET_NETWORK_Handle *sock;
   char addr[128];
   socklen_t addrlen;
   struct GNUNET_NETWORK_Handle *sock;
@@ -345,8 +335,8 @@ GNUNET_CONNECTION_create_from_accept (GNUNET_CONNECTION_AccessCheck access,
   struct sockaddr_in6 *v6;
   struct sockaddr *sa;
   void *uaddr;
   struct sockaddr_in6 *v6;
   struct sockaddr *sa;
   void *uaddr;
-  struct GNUNET_CONNECTION_Credentials *gcp;  
-  struct GNUNET_CONNECTION_Credentials gc;  
+  struct GNUNET_CONNECTION_Credentials *gcp;
+  struct GNUNET_CONNECTION_Credentials gc;
 #ifdef SO_PEERCRED
   struct ucred uc;
   socklen_t olen;
 #ifdef SO_PEERCRED
   struct ucred uc;
   socklen_t olen;
@@ -354,254 +344,266 @@ GNUNET_CONNECTION_create_from_accept (GNUNET_CONNECTION_AccessCheck access,
 
   addrlen = sizeof (addr);
   sock =
 
   addrlen = sizeof (addr);
   sock =
-    GNUNET_NETWORK_socket_accept (lsock, (struct sockaddr *) &addr, &addrlen);
+      GNUNET_NETWORK_socket_accept (lsock, (struct sockaddr *) &addr, &addrlen);
   if (NULL == sock)
   if (NULL == sock)
-    {
-      GNUNET_log_strerror (GNUNET_ERROR_TYPE_WARNING, "accept");
-      return NULL;
-    }
-  if ( (addrlen > sizeof (addr)) ||
-       (addrlen < sizeof (sa_family_t)) )
-    {
-      GNUNET_break (0);
-      GNUNET_break (GNUNET_OK == GNUNET_NETWORK_socket_close (sock));
-      return NULL;
-    }
+  {
+    if (EAGAIN != errno)
+      LOG_STRERROR (GNUNET_ERROR_TYPE_WARNING, "accept");
+    return NULL;
+  }
+  if ((addrlen > sizeof (addr)) || (addrlen < sizeof (sa_family_t)))
+  {
+    GNUNET_break (0);
+    GNUNET_break (GNUNET_OK == GNUNET_NETWORK_socket_close (sock));
+    return NULL;
+  }
 
   sa = (struct sockaddr *) addr;
   v6 = (struct sockaddr_in6 *) addr;
 
   sa = (struct sockaddr *) addr;
   v6 = (struct sockaddr_in6 *) addr;
-  if ((sa->sa_family == AF_INET6) && (IN6_IS_ADDR_V4MAPPED (&v6->sin6_addr)))
-    {
-      /* convert to V4 address */
-      v4 = GNUNET_malloc (sizeof (struct sockaddr_in));
-      memset (v4, 0, sizeof (struct sockaddr_in));
-      v4->sin_family = AF_INET;
-      memcpy (&v4->sin_addr,
-              &((char *) &v6->sin6_addr)[sizeof (struct in6_addr) -
-                                         sizeof (struct in_addr)],
-              sizeof (struct in_addr));
-      v4->sin_port = v6->sin6_port;
-      uaddr = v4;
-      addrlen = sizeof (struct sockaddr_in);
-    }
+  if ((AF_INET6 == sa->sa_family) && (IN6_IS_ADDR_V4MAPPED (&v6->sin6_addr)))
+  {
+    /* convert to V4 address */
+    v4 = GNUNET_new (struct sockaddr_in);
+    memset (v4, 0, sizeof (struct sockaddr_in));
+    v4->sin_family = AF_INET;
+#if HAVE_SOCKADDR_IN_SIN_LEN
+    v4->sin_len = (u_char) sizeof (struct sockaddr_in);
+#endif
+    memcpy (&v4->sin_addr,
+            &((char *) &v6->sin6_addr)[sizeof (struct in6_addr) -
+                                       sizeof (struct in_addr)],
+            sizeof (struct in_addr));
+    v4->sin_port = v6->sin6_port;
+    uaddr = v4;
+    addrlen = sizeof (struct sockaddr_in);
+  }
   else
   else
-    {
-      uaddr = GNUNET_malloc (addrlen);
-      memcpy (uaddr, addr, addrlen);
-    }
+  {
+    uaddr = GNUNET_malloc (addrlen);
+    memcpy (uaddr, addr, addrlen);
+  }
   gcp = NULL;
   gc.uid = 0;
   gc.gid = 0;
   gcp = NULL;
   gc.uid = 0;
   gc.gid = 0;
-  if (sa->sa_family == AF_UNIX)
-    {
+  if (AF_UNIX == sa->sa_family)
+  {
 #if HAVE_GETPEEREID
 #if HAVE_GETPEEREID
-      /* most BSDs */
-      if (0 == getpeereid (GNUNET_NETWORK_get_fd (sock), 
-                          &gc.uid,
-                          &gc.gid))
-       gcp = &gc;
+    /* most BSDs */
+    if (0 == getpeereid (GNUNET_NETWORK_get_fd (sock), &gc.uid, &gc.gid))
+      gcp = &gc;
 #else
 #ifdef SO_PEERCRED
 #else
 #ifdef SO_PEERCRED
-      /* largely traditional GNU/Linux */
-      olen = sizeof (uc);
-      if ( (0 ==
-           getsockopt (GNUNET_NETWORK_get_fd (sock), 
-                       SOL_SOCKET, SO_PEERCRED, &uc, &olen)) &&
-          (olen == sizeof (uc)) )
-       {
-         gc.uid = uc.uid;
-         gc.gid = uc.gid;
-         gcp = &gc;    
-       }
+    /* largely traditional GNU/Linux */
+    olen = sizeof (uc);
+    if ((0 ==
+         getsockopt (GNUNET_NETWORK_get_fd (sock), SOL_SOCKET, SO_PEERCRED, &uc,
+                     &olen)) && (olen == sizeof (uc)))
+    {
+      gc.uid = uc.uid;
+      gc.gid = uc.gid;
+      gcp = &gc;
+    }
 #else
 #if HAVE_GETPEERUCRED
 #else
 #if HAVE_GETPEERUCRED
-      /* this is for Solaris 10 */
-      ucred_t *uc;
-
-      uc = NULL;
-      if (0 == getpeerucred (GNUNET_NETWORK_get_fd (sock), &uc))
-       {
-         gc.uid = ucred_geteuid (uc);
-         gc.gid = ucred_getegid (uc);
-         gcp = &gc;
-       }
-      ucred_free (uc);
-#endif
-#endif
-#endif
-    }
+    /* this is for Solaris 10 */
+    ucred_t *uc;
 
 
-  if ((access != NULL) &&
-      (GNUNET_YES != (aret = access (access_cls, gcp, uaddr, addrlen))))
+    uc = NULL;
+    if (0 == getpeerucred (GNUNET_NETWORK_get_fd (sock), &uc))
     {
     {
-      if (aret == GNUNET_NO)
-        GNUNET_log (GNUNET_ERROR_TYPE_INFO,
-                    _("Access denied to `%s'\n"),
-                    GNUNET_a2s (uaddr, addrlen));
-      GNUNET_break (GNUNET_OK ==
-                    GNUNET_NETWORK_socket_shutdown (sock, SHUT_RDWR));
-      GNUNET_break (GNUNET_OK == GNUNET_NETWORK_socket_close (sock));
-      GNUNET_free (uaddr);
-      return NULL;
+      gc.uid = ucred_geteuid (uc);
+      gc.gid = ucred_getegid (uc);
+      gcp = &gc;
     }
     }
-  ret = GNUNET_malloc (sizeof (struct GNUNET_CONNECTION_Handle));
-  ret->write_buffer_size = GNUNET_SERVER_MIN_BUFFER_SIZE;
-  ret->write_buffer = GNUNET_malloc(ret->write_buffer_size);
-  ret->addr = uaddr;
-  ret->addrlen = addrlen;
-  ret->sock = sock;
-#if DEBUG_CONNECTION
-  GNUNET_log (GNUNET_ERROR_TYPE_INFO,
-              _("Accepting connection from `%s': %p\n"),
-              GNUNET_a2s (uaddr, addrlen), ret);
+    ucred_free (uc);
+#endif
+#endif
 #endif
 #endif
-  return ret;
+  }
+
+  if ((NULL != access_cb) &&
+      (GNUNET_YES != (aret = access_cb (access_cb_cls, gcp, uaddr, addrlen))))
+  {
+    if (GNUNET_NO == aret)
+      LOG (GNUNET_ERROR_TYPE_INFO,
+           _("Access denied to `%s'\n"),
+           GNUNET_a2s (uaddr,
+                       addrlen));
+    GNUNET_break (GNUNET_OK ==
+                  GNUNET_NETWORK_socket_shutdown (sock,
+                                                  SHUT_RDWR));
+    GNUNET_break (GNUNET_OK == GNUNET_NETWORK_socket_close (sock));
+    GNUNET_free (uaddr);
+    return NULL;
+  }
+  connection = GNUNET_new (struct GNUNET_CONNECTION_Handle);
+  connection->write_buffer_size = GNUNET_SERVER_MIN_BUFFER_SIZE;
+  connection->write_buffer = GNUNET_malloc (connection->write_buffer_size);
+  connection->addr = uaddr;
+  connection->addrlen = addrlen;
+  connection->sock = sock;
+  LOG (GNUNET_ERROR_TYPE_INFO,
+       _("Accepting connection from `%s': %p\n"),
+       GNUNET_a2s (uaddr, addrlen), connection);
+  return connection;
 }
 
 }
 
+
 /**
  * Obtain the network address of the other party.
  *
 /**
  * Obtain the network address of the other party.
  *
- * @param sock the client to get the address for
+ * @param connection the client to get the address for
  * @param addr where to store the address
  * @param addr where to store the address
- * @param addrlen where to store the length of the address
- * @return GNUNET_OK on success
+ * @param addrlen where to store the length of the @a addr
+ * @return #GNUNET_OK on success
  */
 int
  */
 int
-GNUNET_CONNECTION_get_address (struct GNUNET_CONNECTION_Handle *sock,
-                               void **addr, size_t * addrlen)
+GNUNET_CONNECTION_get_address (struct GNUNET_CONNECTION_Handle *connection,
+                               void **addr,
+                               size_t *addrlen)
 {
 {
-  if ((sock->addr == NULL) || (sock->addrlen == 0))
+  if ((NULL == connection->addr) || (0 == connection->addrlen))
     return GNUNET_NO;
     return GNUNET_NO;
-  *addr = GNUNET_malloc (sock->addrlen);
-  memcpy (*addr, sock->addr, sock->addrlen);
-  *addrlen = sock->addrlen;
+  *addr = GNUNET_malloc (connection->addrlen);
+  memcpy (*addr, connection->addr, connection->addrlen);
+  *addrlen = connection->addrlen;
   return GNUNET_OK;
 }
 
 
 /**
   return GNUNET_OK;
 }
 
 
 /**
- * This function is called after establishing a connection either has
- * succeeded or timed out.  Note that it is possible that the attempt
- * timed out and that we're immediately retrying.  If we are retrying,
- * we need to wait again (or timeout); if we succeeded, we need to
- * wait for data (or timeout).
+ * Tell the receiver callback that we had an IO error.
  *
  *
- * @param cls our connection handle
- * @param tc task context describing why we are here
+ * @param connection connection to signal error
+ * @param errcode error code to send
  */
 static void
  */
 static void
-receive_again (void *cls, const struct GNUNET_SCHEDULER_TaskContext *tc);
+signal_receive_error (struct GNUNET_CONNECTION_Handle *connection,
+                      int errcode)
+{
+  GNUNET_CONNECTION_Receiver receiver;
+
+  LOG (GNUNET_ERROR_TYPE_DEBUG,
+       "Receive encounters error (%s), connection closed (%p)\n",
+       STRERROR (errcode),
+       connection);
+  GNUNET_assert (NULL != (receiver = connection->receiver));
+  connection->receiver = NULL;
+  receiver (connection->receiver_cls,
+            NULL,
+            0,
+            connection->addr,
+            connection->addrlen,
+            errcode);
+}
 
 
 /**
 
 
 /**
- * Scheduler let us know that the connect task is finished (or was
- * cancelled due to shutdown).  Now really clean up.
+ * Tell the receiver callback that a timeout was reached.
  *
  *
- * @param cls our "struct GNUNET_CONNECTION_Handle *"
- * @param tc unused
+ * @param connection connection to signal for
  */
 static void
  */
 static void
-destroy_continuation (void *cls,
-                      const struct GNUNET_SCHEDULER_TaskContext *tc)
+signal_receive_timeout (struct GNUNET_CONNECTION_Handle *connection)
 {
 {
-  struct GNUNET_CONNECTION_Handle *sock = cls;
-  GNUNET_CONNECTION_TransmitReadyNotify notify;
-  struct AddressProbe *pos;
+  GNUNET_CONNECTION_Receiver receiver;
 
 
-  sock->destroy_task = GNUNET_SCHEDULER_NO_TASK;
-  GNUNET_assert (sock->dns_active == NULL);
-  if (0 != (sock->ccs & COCO_TRANSMIT_READY))
-    {
-#if DEBUG_CONNECTION
-      GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
-                  "Destroy waits for CCS-TR to be done (%p)\n", sock);
-#endif
-      sock->ccs |= COCO_DESTROY_CONTINUATION;
-      return;
-    }
-  if (sock->write_task != GNUNET_SCHEDULER_NO_TASK)
-    {
-#if DEBUG_CONNECTION
-      GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
-                  "Destroy waits for write_task to be done (%p)\n", sock);
-#endif
-      GNUNET_assert (GNUNET_SCHEDULER_NO_TASK == sock->destroy_task);
-      sock->destroy_task 
-       = GNUNET_SCHEDULER_add_after (sock->write_task,
-                                     &destroy_continuation, sock);
-      return;
-    }
-  if (0 != (sock->ccs & COCO_RECEIVE_AGAIN))
-    {
-      sock->ccs |= COCO_DESTROY_CONTINUATION;
-      return;
-    }
-  if (sock->sock != NULL)
-    {
-#if DEBUG_CONNECTION
-      GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
-                  "Shutting down socket (%p)\n", sock);
-#endif
-      if (sock->persist != GNUNET_YES)
-      {
-        if ( (GNUNET_YES != GNUNET_NETWORK_socket_shutdown (sock->sock, SHUT_RDWR)) &&
-            (errno != ENOTCONN) &&
-             (errno != ECONNRESET) )
-          GNUNET_log_strerror (GNUNET_ERROR_TYPE_WARNING, "shutdown");
-      }
-    }
-  if (sock->read_task != GNUNET_SCHEDULER_NO_TASK)
-    {
-      GNUNET_assert (GNUNET_SCHEDULER_NO_TASK == sock->destroy_task);
-      sock->destroy_task 
-       = GNUNET_SCHEDULER_add_after (sock->read_task,
-                                     &destroy_continuation, sock);
-      return;
-    }
-#if DEBUG_CONNECTION
-  GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, 
-             "Destroy actually runs (%p)!\n", sock);
-#endif
-  while (NULL != (pos = sock->ap_head))
-    {
-      GNUNET_break (GNUNET_OK == GNUNET_NETWORK_socket_close (pos->sock));
-      GNUNET_SCHEDULER_cancel (pos->task);
-      GNUNET_CONTAINER_DLL_remove (sock->ap_head, sock->ap_tail, pos);
-      GNUNET_free (pos);
-    }
-  GNUNET_assert (sock->nth.timeout_task == GNUNET_SCHEDULER_NO_TASK);
-  GNUNET_assert (sock->ccs == COCO_NONE);
-  if (NULL != (notify = sock->nth.notify_ready))
-    {
-      sock->nth.notify_ready = NULL;
-      notify (sock->nth.notify_ready_cls, 0, NULL);
-    }
+  LOG (GNUNET_ERROR_TYPE_DEBUG,
+       "Connection signals timeout to receiver (%p)!\n",
+       connection);
+  GNUNET_assert (NULL != (receiver = connection->receiver));
+  connection->receiver = NULL;
+  receiver (connection->receiver_cls, NULL, 0, NULL, 0, 0);
+}
 
 
-  if (sock->sock != NULL) 
-    {
-      if (sock->persist != GNUNET_YES)
-       GNUNET_break (GNUNET_OK == GNUNET_NETWORK_socket_close (sock->sock));
-      else
-       GNUNET_free (sock->sock); /* at least no memory leak (we deliberately
-                                    leak the socket in this special case) ... */
-    }
-  GNUNET_free_non_null (sock->addr);
-  GNUNET_free_non_null (sock->hostname);
-  GNUNET_assert (GNUNET_SCHEDULER_NO_TASK == sock->destroy_task);
-#if DEBUG_CONNECTION
-  GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
-              "Freeing memory of connection %p.\n", sock);
-#endif
-  GNUNET_free (sock->write_buffer);
-  GNUNET_free (sock);
+
+/**
+ * We failed to transmit data to the service, signal the error.
+ *
+ * @param connection handle that had trouble
+ * @param ecode error code (errno)
+ */
+static void
+signal_transmit_error (struct GNUNET_CONNECTION_Handle *connection,
+                      int ecode)
+{
+  GNUNET_CONNECTION_TransmitReadyNotify notify;
+
+  LOG (GNUNET_ERROR_TYPE_DEBUG,
+       "Transmission encounterd error (%s), connection closed (%p)\n",
+       STRERROR (ecode),
+       connection);
+  if (NULL != connection->sock)
+  {
+    (void) GNUNET_NETWORK_socket_shutdown (connection->sock,
+                                           SHUT_RDWR);
+    GNUNET_break (GNUNET_OK ==
+                  GNUNET_NETWORK_socket_close (connection->sock));
+    connection->sock = NULL;
+    GNUNET_assert (NULL == connection->write_task);
+  }
+  if (NULL != connection->read_task)
+  {
+    /* send errors trigger read errors... */
+    GNUNET_SCHEDULER_cancel (connection->read_task);
+    connection->read_task = NULL;
+    signal_receive_timeout (connection);
+    return;
+  }
+  if (NULL == connection->nth.notify_ready)
+    return;                     /* nobody to tell about it */
+  notify = connection->nth.notify_ready;
+  connection->nth.notify_ready = NULL;
+  notify (connection->nth.notify_ready_cls, 0, NULL);
 }
 
 
 }
 
 
+/**
+ * We've failed for good to establish a connection (timeout or
+ * no more addresses to try).
+ *
+ * @param connection the connection we tried to establish
+ */
+static void
+connect_fail_continuation (struct GNUNET_CONNECTION_Handle *connection)
+{
+  LOG (GNUNET_ERROR_TYPE_INFO,
+       "Failed to establish TCP connection to `%s:%u', no further addresses to try.\n",
+       connection->hostname,
+    connection->port);
+  GNUNET_break (NULL == connection->ap_head);
+  GNUNET_break (NULL == connection->ap_tail);
+  GNUNET_break (GNUNET_NO == connection->dns_active);
+  GNUNET_break (NULL == connection->sock);
+  GNUNET_assert (NULL == connection->write_task);
+  GNUNET_assert (NULL == connection->proxy_handshake);
+
+  /* signal errors for jobs that used to wait on the connection */
+  connection->destroy_later = 1;
+  if (NULL != connection->receiver)
+    signal_receive_error (connection,
+                          ECONNREFUSED);
+  if (NULL != connection->nth.notify_ready)
+  {
+    GNUNET_assert (NULL != connection->nth.timeout_task);
+    GNUNET_SCHEDULER_cancel (connection->nth.timeout_task);
+    connection->nth.timeout_task = NULL;
+    signal_transmit_error (connection,
+                           ECONNREFUSED);
+  }
+  if (-1 == connection->destroy_later)
+  {
+    /* do it now */
+    connection->destroy_later = 0;
+    GNUNET_CONNECTION_destroy (connection);
+    return;
+  }
+  connection->destroy_later = 0;
+}
+
 
 /**
 
 /**
- * See if we are now connected.  If not, wait longer for
- * connect to succeed.  If connected, we should be able
- * to write now as well, unless we timed out.
+ * We are ready to transmit (or got a timeout).
  *
  * @param cls our connection handle
  * @param tc task context describing why we are here
  *
  * @param cls our connection handle
  * @param tc task context describing why we are here
@@ -611,126 +613,54 @@ transmit_ready (void *cls, const struct GNUNET_SCHEDULER_TaskContext *tc);
 
 
 /**
 
 
 /**
- * We've failed for good to establish a connection.
+ * This function is called once we either timeout or have data ready
+ * to read.
  *
  *
- * @param h the connection we tried to establish
+ * @param cls connection to read from
+ * @param tc scheduler context
  */
 static void
  */
 static void
-connect_fail_continuation (struct GNUNET_CONNECTION_Handle *h)
-{
-#if DEBUG_CONNECTION
-  GNUNET_log ((0 != strncmp (h->hostname, 
-                            "localhost:",
-                            10)) 
-             ? GNUNET_ERROR_TYPE_INFO 
-             : GNUNET_ERROR_TYPE_WARNING,
-              _("Failed to establish TCP connection to `%s:%u', no further addresses to try.\n"),
-              h->hostname, h->port);
-#endif
-  /* connect failed / timed out */
-  GNUNET_break (h->ap_head == NULL);
-  GNUNET_break (h->ap_tail == NULL);
-  GNUNET_break (h->dns_active == GNUNET_NO);
-  GNUNET_break (h->sock == NULL);
-
-  /* trigger jobs that used to wait on "connect_task" */
-  if (0 != (h->ccs & COCO_RECEIVE_AGAIN))
-    {
-#if DEBUG_CONNECTION
-      GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
-                  "connect_fail_continuation triggers receive_again (%p)\n",
-                  h);
-#endif
-      h->ccs -= COCO_RECEIVE_AGAIN;
-      h->read_task = GNUNET_SCHEDULER_add_after (GNUNET_SCHEDULER_NO_TASK,
-                                                 &receive_again, h);
-    }
-  if (0 != (h->ccs & COCO_TRANSMIT_READY))
-    {
-#if DEBUG_CONNECTION
-      GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
-                  "connect_fail_continuation cancels timeout_task, triggers transmit_ready (%p)\n",
-                  h);
-#endif
-      GNUNET_assert (h->nth.timeout_task != GNUNET_SCHEDULER_NO_TASK);
-      GNUNET_SCHEDULER_cancel (h->nth.timeout_task);
-      h->nth.timeout_task = GNUNET_SCHEDULER_NO_TASK;
-      h->ccs -= COCO_TRANSMIT_READY;
-      GNUNET_assert (h->write_task == GNUNET_SCHEDULER_NO_TASK);
-      h->write_task = GNUNET_SCHEDULER_add_after (GNUNET_SCHEDULER_NO_TASK,
-                                                  &transmit_ready, h);
-    }
-  if (0 != (h->ccs & COCO_DESTROY_CONTINUATION))
-    {
-#if DEBUG_CONNECTION
-      GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
-                  "connect_fail_continuation runs destroy_continuation (%p)\n",
-                  h);
-#endif
-      h->ccs -= COCO_DESTROY_CONTINUATION;
-      GNUNET_assert (GNUNET_SCHEDULER_NO_TASK == h->destroy_task);
-      h->destroy_task
-       = GNUNET_SCHEDULER_add_now (&destroy_continuation,
-                                   h);
-    }
-}
+receive_ready (void *cls, const struct GNUNET_SCHEDULER_TaskContext *tc);
 
 
 /**
  * We've succeeded in establishing a connection.
  *
 
 
 /**
  * We've succeeded in establishing a connection.
  *
- * @param h the connection we tried to establish
+ * @param connection the connection we tried to establish
  */
 static void
  */
 static void
-connect_success_continuation (struct GNUNET_CONNECTION_Handle *h)
+connect_success_continuation (struct GNUNET_CONNECTION_Handle *connection)
 {
 {
-#if DEBUG_CONNECTION
-  GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
-              "Connection to `%s' succeeded! (%p)\n",
-              GNUNET_a2s (h->addr, h->addrlen), h);
-#endif
+  LOG (GNUNET_ERROR_TYPE_DEBUG,
+       "Connection to `%s' succeeded! (%p)\n",
+       GNUNET_a2s (connection->addr, connection->addrlen),
+       connection);
   /* trigger jobs that waited for the connection */
   /* trigger jobs that waited for the connection */
-  if (0 != (h->ccs & COCO_RECEIVE_AGAIN))
-    {
-#if DEBUG_CONNECTION
-      GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
-                  "connect_success_continuation runs receive_again (%p)\n",
-                  h);
-#endif
-      h->ccs -= COCO_RECEIVE_AGAIN;
-      h->read_task = GNUNET_SCHEDULER_add_after (GNUNET_SCHEDULER_NO_TASK,
-                                                 &receive_again, h);
-    }
-  if (0 != (h->ccs & COCO_TRANSMIT_READY))
-    {
-#if DEBUG_CONNECTION
-      GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
-                  "connect_success_continuation runs transmit_ready, cancels timeout_task (%p)\n",
-                  h);
-#endif
-      GNUNET_assert (h->nth.timeout_task != GNUNET_SCHEDULER_NO_TASK);
-      GNUNET_SCHEDULER_cancel (h->nth.timeout_task);
-      h->nth.timeout_task = GNUNET_SCHEDULER_NO_TASK;
-      h->ccs -= COCO_TRANSMIT_READY;
-      GNUNET_assert (h->write_task == GNUNET_SCHEDULER_NO_TASK);
-      h->write_task =
+  if (NULL != connection->receiver)
+  {
+    LOG (GNUNET_ERROR_TYPE_DEBUG,
+         "Connection succeeded, starting with receiving data (%p)\n",
+        connection);
+    GNUNET_assert (NULL == connection->read_task);
+    connection->read_task =
+      GNUNET_SCHEDULER_add_read_net (GNUNET_TIME_absolute_get_remaining
+                                     (connection->receive_timeout), connection->sock,
+                                     &receive_ready, connection);
+  }
+  if (NULL != connection->nth.notify_ready)
+  {
+    LOG (GNUNET_ERROR_TYPE_DEBUG,
+         "Connection succeeded, starting with sending data (%p)\n",
+         connection);
+    GNUNET_assert (connection->nth.timeout_task != NULL);
+    GNUNET_SCHEDULER_cancel (connection->nth.timeout_task);
+    connection->nth.timeout_task = NULL;
+    GNUNET_assert (connection->write_task == NULL);
+    connection->write_task =
         GNUNET_SCHEDULER_add_write_net (GNUNET_TIME_absolute_get_remaining
         GNUNET_SCHEDULER_add_write_net (GNUNET_TIME_absolute_get_remaining
-                                        (h->nth.transmit_timeout), h->sock,
-                                        &transmit_ready, h);
-    }
-  if (0 != (h->ccs & COCO_DESTROY_CONTINUATION))
-    {
-#if DEBUG_CONNECTION
-      GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
-                  "connect_success_continuation runs destroy_continuation (%p)\n",
-                  h);
-#endif
-      h->ccs -= COCO_DESTROY_CONTINUATION;
-      GNUNET_assert (GNUNET_SCHEDULER_NO_TASK == h->destroy_task);
-      h->destroy_task
-       = GNUNET_SCHEDULER_add_now (&destroy_continuation,
-                                               h);
-    }
+                                        (connection->nth.transmit_timeout), connection->sock,
+                                        &transmit_ready, connection);
+  }
 }
 
 
 }
 
 
@@ -746,233 +676,233 @@ connect_probe_continuation (void *cls,
                             const struct GNUNET_SCHEDULER_TaskContext *tc)
 {
   struct AddressProbe *ap = cls;
                             const struct GNUNET_SCHEDULER_TaskContext *tc)
 {
   struct AddressProbe *ap = cls;
-  struct GNUNET_CONNECTION_Handle *h = ap->h;
+  struct GNUNET_CONNECTION_Handle *connection = ap->connection;
   struct AddressProbe *pos;
   int error;
   socklen_t len;
 
   struct AddressProbe *pos;
   int error;
   socklen_t len;
 
-  GNUNET_assert (ap->sock != NULL);
-  GNUNET_CONTAINER_DLL_remove (h->ap_head, h->ap_tail, ap);
+  GNUNET_assert (NULL != ap->sock);
+  GNUNET_CONTAINER_DLL_remove (connection->ap_head, connection->ap_tail, ap);
   len = sizeof (error);
   errno = 0;
   error = 0;
   len = sizeof (error);
   errno = 0;
   error = 0;
-  if ( (0 == (tc->reason & GNUNET_SCHEDULER_REASON_WRITE_READY)) ||
-       (GNUNET_OK !=
-       GNUNET_NETWORK_socket_getsockopt (ap->sock, SOL_SOCKET, SO_ERROR,
-                                         &error, &len)) ||
-       (error != 0) )
-    {
-      GNUNET_break (GNUNET_OK == GNUNET_NETWORK_socket_close (ap->sock));
-      GNUNET_free (ap);
-      if ((NULL == h->ap_head) && (h->dns_active == GNUNET_NO))
-        connect_fail_continuation (h);
-      return;
-    }
-  GNUNET_assert (h->sock == NULL);
-  h->sock = ap->sock;
-  GNUNET_assert (h->addr == NULL);
-  h->addr = GNUNET_malloc (ap->addrlen);
-  memcpy (h->addr, ap->addr, ap->addrlen);
-  h->addrlen = ap->addrlen;
+  if ((0 == (tc->reason & GNUNET_SCHEDULER_REASON_WRITE_READY)) ||
+      (GNUNET_OK !=
+       GNUNET_NETWORK_socket_getsockopt (ap->sock, SOL_SOCKET, SO_ERROR, &error,
+                                         &len)) || (0 != error))
+  {
+    GNUNET_break (GNUNET_OK == GNUNET_NETWORK_socket_close (ap->sock));
+    GNUNET_free (ap);
+    if ((NULL == connection->ap_head) &&
+        (GNUNET_NO == connection->dns_active) &&
+        (NULL == connection->proxy_handshake))
+      connect_fail_continuation (connection);
+    return;
+  }
+  GNUNET_assert (NULL == connection->sock);
+  connection->sock = ap->sock;
+  GNUNET_assert (NULL == connection->addr);
+  connection->addr = GNUNET_malloc (ap->addrlen);
+  memcpy (connection->addr, ap->addr, ap->addrlen);
+  connection->addrlen = ap->addrlen;
   GNUNET_free (ap);
   /* cancel all other attempts */
   GNUNET_free (ap);
   /* cancel all other attempts */
-  while (NULL != (pos = h->ap_head))
-    {
-      GNUNET_break (GNUNET_OK == GNUNET_NETWORK_socket_close (pos->sock));
-      GNUNET_SCHEDULER_cancel (pos->task);
-      GNUNET_CONTAINER_DLL_remove (h->ap_head, h->ap_tail, pos);
-      GNUNET_free (pos);
-    }
-  connect_success_continuation (h);
+  while (NULL != (pos = connection->ap_head))
+  {
+    GNUNET_break (GNUNET_OK == GNUNET_NETWORK_socket_close (pos->sock));
+    GNUNET_SCHEDULER_cancel (pos->task);
+    GNUNET_CONTAINER_DLL_remove (connection->ap_head, connection->ap_tail, pos);
+    GNUNET_free (pos);
+  }
+  connect_success_continuation (connection);
 }
 
 
 /**
 }
 
 
 /**
- * Try to establish a socket connection given the specified address.
+ * Try to establish a connection given the specified address.
  * This function is called by the resolver once we have a DNS reply.
  *
  * This function is called by the resolver once we have a DNS reply.
  *
- * @param cls our "struct GNUNET_CONNECTION_Handle *"
+ * @param cls our `struct GNUNET_CONNECTION_Handle *`
  * @param addr address to try, NULL for "last call"
  * @param addr address to try, NULL for "last call"
- * @param addrlen length of addr
+ * @param addrlen length of @a addr
  */
 static void
 try_connect_using_address (void *cls,
  */
 static void
 try_connect_using_address (void *cls,
-                           const struct sockaddr *addr, socklen_t addrlen)
+                           const struct sockaddr *addr,
+                           socklen_t addrlen)
 {
 {
-  struct GNUNET_CONNECTION_Handle *h = cls;
+  struct GNUNET_CONNECTION_Handle *connection = cls;
   struct AddressProbe *ap;
   struct GNUNET_TIME_Relative delay;
 
   struct AddressProbe *ap;
   struct GNUNET_TIME_Relative delay;
 
-  if (addr == NULL)
-    {
-      h->dns_active = NULL;
-      if (NULL == h->ap_head)
-        connect_fail_continuation (h);
-      return;
-    }
-  if (h->sock != NULL)
+  if (NULL == addr)
+  {
+    connection->dns_active = NULL;
+    if ((NULL == connection->ap_head) &&
+        (NULL == connection->sock) &&
+        (NULL == connection->proxy_handshake))
+      connect_fail_continuation (connection);
+    return;
+  }
+  if (NULL != connection->sock)
     return;                     /* already connected */
     return;                     /* already connected */
-  GNUNET_assert (h->addr == NULL);
+  GNUNET_assert (NULL == connection->addr);
   /* try to connect */
   /* try to connect */
-#if DEBUG_CONNECTION
-  GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
-              "Trying to connect using address `%s:%u/%s:%u'\n",
-              h->hostname, h->port, GNUNET_a2s (addr, addrlen), h->port);
-#endif
+  LOG (GNUNET_ERROR_TYPE_DEBUG,
+       "Trying to connect using address `%s:%u/%s:%u'\n",
+       connection->hostname,
+       connection->port,
+       GNUNET_a2s (addr, addrlen),
+       connection->port);
   ap = GNUNET_malloc (sizeof (struct AddressProbe) + addrlen);
   ap->addr = (const struct sockaddr *) &ap[1];
   memcpy (&ap[1], addr, addrlen);
   ap->addrlen = addrlen;
   ap = GNUNET_malloc (sizeof (struct AddressProbe) + addrlen);
   ap->addr = (const struct sockaddr *) &ap[1];
   memcpy (&ap[1], addr, addrlen);
   ap->addrlen = addrlen;
-  ap->h = h;
+  ap->connection = connection;
 
   switch (ap->addr->sa_family)
 
   switch (ap->addr->sa_family)
-    {
-    case AF_INET:
-      ((struct sockaddr_in *) ap->addr)->sin_port = htons (h->port);
-      break;
-    case AF_INET6:
-      ((struct sockaddr_in6 *) ap->addr)->sin6_port = htons (h->port);
-      break;
-    default:
-      GNUNET_break (0);
-      GNUNET_free (ap);
-      return;                   /* not supported by us */
-    }
-  ap->sock =
-    GNUNET_NETWORK_socket_create (ap->addr->sa_family, SOCK_STREAM, 0);
-  if (ap->sock == NULL)
-    {
-      GNUNET_free (ap);
-      return;                   /* not supported by OS */
-    }
-#if DEBUG_CONNECTION
-  GNUNET_log (GNUNET_ERROR_TYPE_INFO,
-              _("Trying to connect to `%s' (%p)\n"),
-              GNUNET_a2s (ap->addr, ap->addrlen), h);
-#endif
-  if ((GNUNET_OK != GNUNET_NETWORK_socket_connect (ap->sock,
-                                                   ap->addr,
-                                                   ap->addrlen)) &&
-      (errno != EINPROGRESS))
-    {
-      /* maybe refused / unsupported address, try next */
-      GNUNET_log_strerror (GNUNET_ERROR_TYPE_INFO, "connect");
-      GNUNET_break (GNUNET_OK == GNUNET_NETWORK_socket_close (ap->sock));
-      GNUNET_free (ap);
-      return;
-    }
-  GNUNET_CONTAINER_DLL_insert (h->ap_head, h->ap_tail, ap);
+  {
+  case AF_INET:
+    ((struct sockaddr_in *) ap->addr)->sin_port = htons (connection->port);
+    break;
+  case AF_INET6:
+    ((struct sockaddr_in6 *) ap->addr)->sin6_port = htons (connection->port);
+    break;
+  default:
+    GNUNET_break (0);
+    GNUNET_free (ap);
+    return;                     /* not supported by us */
+  }
+  ap->sock = GNUNET_NETWORK_socket_create (ap->addr->sa_family, SOCK_STREAM, 0);
+  if (NULL == ap->sock)
+  {
+    GNUNET_free (ap);
+    return;                     /* not supported by OS */
+  }
+  LOG (GNUNET_ERROR_TYPE_INFO,
+       "Trying to connect to `%s' (%p)\n",
+       GNUNET_a2s (ap->addr, ap->addrlen),
+       connection);
+  if ((GNUNET_OK !=
+       GNUNET_NETWORK_socket_connect (ap->sock, ap->addr, ap->addrlen)) &&
+      (EINPROGRESS != errno))
+  {
+    /* maybe refused / unsupported address, try next */
+    LOG_STRERROR (GNUNET_ERROR_TYPE_INFO, "connect");
+    GNUNET_break (GNUNET_OK == GNUNET_NETWORK_socket_close (ap->sock));
+    GNUNET_free (ap);
+    return;
+  }
+  GNUNET_CONTAINER_DLL_insert (connection->ap_head, connection->ap_tail, ap);
   delay = GNUNET_CONNECTION_CONNECT_RETRY_TIMEOUT;
   delay = GNUNET_CONNECTION_CONNECT_RETRY_TIMEOUT;
-  if (h->nth.notify_ready != NULL)
-    delay = GNUNET_TIME_relative_min (delay,
-                                      GNUNET_TIME_absolute_get_remaining
-                                      (h->nth.transmit_timeout));
-  if (h->receiver != NULL)
-    delay = GNUNET_TIME_relative_min (delay,
-                                      GNUNET_TIME_absolute_get_remaining
-                                      (h->receive_timeout));
+  if (NULL != connection->nth.notify_ready)
+    delay =
+        GNUNET_TIME_relative_min (delay,
+                                  GNUNET_TIME_absolute_get_remaining (connection->nth.transmit_timeout));
+  if (NULL != connection->receiver)
+    delay =
+        GNUNET_TIME_relative_min (delay,
+                                  GNUNET_TIME_absolute_get_remaining
+                                  (connection->receive_timeout));
   ap->task =
   ap->task =
-    GNUNET_SCHEDULER_add_write_net (delay, ap->sock,
-                                    &connect_probe_continuation, ap);
+      GNUNET_SCHEDULER_add_write_net (delay, ap->sock,
+                                      &connect_probe_continuation, ap);
 }
 
 
 /**
 }
 
 
 /**
- * Create a socket handle by (asynchronously) connecting to a host.
+ * Create a connection handle by (asynchronously) connecting to a host.
  * This function returns immediately, even if the connection has not
  * yet been established.  This function only creates TCP connections.
  *
  * @param cfg configuration to use
  * @param hostname name of the host to connect to
  * @param port port to connect to
  * This function returns immediately, even if the connection has not
  * yet been established.  This function only creates TCP connections.
  *
  * @param cfg configuration to use
  * @param hostname name of the host to connect to
  * @param port port to connect to
- * @return the socket handle
+ * @return the connection handle
  */
 struct GNUNET_CONNECTION_Handle *
  */
 struct GNUNET_CONNECTION_Handle *
-GNUNET_CONNECTION_create_from_connect (const struct
-                                       GNUNET_CONFIGURATION_Handle *cfg,
-                                       const char *hostname, uint16_t port)
+GNUNET_CONNECTION_create_from_connect (const struct GNUNET_CONFIGURATION_Handle *cfg,
+                                       const char *hostname,
+                                       uint16_t port)
 {
 {
-  struct GNUNET_CONNECTION_Handle *ret;
+  struct GNUNET_CONNECTION_Handle *connection;
 
   GNUNET_assert (0 < strlen (hostname));        /* sanity check */
 
   GNUNET_assert (0 < strlen (hostname));        /* sanity check */
-  ret = GNUNET_malloc (sizeof (struct GNUNET_CONNECTION_Handle));
-  ret->cfg = cfg;
-  ret->write_buffer_size = GNUNET_SERVER_MIN_BUFFER_SIZE;
-  ret->write_buffer = GNUNET_malloc(ret->write_buffer_size);
-  ret->port = port;
-  ret->hostname = GNUNET_strdup (hostname);
-  ret->dns_active = GNUNET_RESOLVER_ip_get (cfg,
-                                            ret->hostname,
-                                            AF_UNSPEC,
-                                            GNUNET_CONNECTION_CONNECT_RETRY_TIMEOUT,
-                                            &try_connect_using_address, ret);
-  return ret;
+  connection = GNUNET_new (struct GNUNET_CONNECTION_Handle);
+  connection->cfg = cfg;
+  connection->write_buffer_size = GNUNET_SERVER_MIN_BUFFER_SIZE;
+  connection->write_buffer = GNUNET_malloc (connection->write_buffer_size);
+  connection->port = port;
+  connection->hostname = GNUNET_strdup (hostname);
+  connection->dns_active =
+      GNUNET_RESOLVER_ip_get (connection->hostname, AF_UNSPEC,
+                              GNUNET_CONNECTION_CONNECT_RETRY_TIMEOUT,
+                              &try_connect_using_address, connection);
+  return connection;
 }
 
 
 /**
 }
 
 
 /**
- * Create a socket handle by connecting to a UNIX domain service.
+ * Create a connection handle by connecting to a UNIX domain service.
  * This function returns immediately, even if the connection has not
  * yet been established.  This function only creates UNIX connections.
  *
  * @param cfg configuration to use
  * @param unixpath path to connect to
  * This function returns immediately, even if the connection has not
  * yet been established.  This function only creates UNIX connections.
  *
  * @param cfg configuration to use
  * @param unixpath path to connect to
- * @return the socket handle, NULL on systems without UNIX support
+ * @return the connection handle, NULL on systems without UNIX support
  */
 struct GNUNET_CONNECTION_Handle *
  */
 struct GNUNET_CONNECTION_Handle *
-GNUNET_CONNECTION_create_from_connect_to_unixpath (const struct
-                                                  GNUNET_CONFIGURATION_Handle *cfg,
-                                                  const char *unixpath)
+GNUNET_CONNECTION_create_from_connect_to_unixpath (const struct GNUNET_CONFIGURATION_Handle *cfg,
+                                                   const char *unixpath)
 {
 #ifdef AF_UNIX
 {
 #ifdef AF_UNIX
-  struct GNUNET_CONNECTION_Handle *ret;
+  struct GNUNET_CONNECTION_Handle *connection;
   struct sockaddr_un *un;
   struct sockaddr_un *un;
-  size_t slen;
 
   GNUNET_assert (0 < strlen (unixpath));        /* sanity check */
 
   GNUNET_assert (0 < strlen (unixpath));        /* sanity check */
-  un = GNUNET_malloc (sizeof (struct sockaddr_un));
+  un = GNUNET_new (struct sockaddr_un);
   un->sun_family = AF_UNIX;
   un->sun_family = AF_UNIX;
-  slen = strlen (unixpath) + 1;
-  if (slen >= sizeof (un->sun_path))
-    slen = sizeof (un->sun_path) - 1;
-  memcpy (un->sun_path,
-         unixpath,
-         slen);
-  un->sun_path[slen] = '\0';
-  slen += sizeof (sa_family_t);
-#if LINUX
-  un->sun_path[0] = '\0';
-  slen = sizeof (struct sockaddr_un);
+  strncpy (un->sun_path, unixpath, sizeof (un->sun_path) - 1);
+#ifdef LINUX
+  {
+    int abstract;
+
+    abstract = GNUNET_CONFIGURATION_get_value_yesno (cfg, "TESTING",
+                                                     "USE_ABSTRACT_SOCKETS");
+    if (GNUNET_YES == abstract)
+      un->sun_path[0] = '\0';
+  }
 #endif
 #endif
-  ret = GNUNET_malloc (sizeof (struct GNUNET_CONNECTION_Handle));
-  ret->cfg = cfg;
-  ret->write_buffer_size = GNUNET_SERVER_MIN_BUFFER_SIZE;
-  ret->write_buffer = GNUNET_malloc(ret->write_buffer_size);
-  ret->port = 0;
-  ret->hostname = NULL;
-  ret->addr = (struct sockaddr*) un;
-  ret->addrlen = slen;
-  ret->sock = GNUNET_NETWORK_socket_create (AF_UNIX, SOCK_STREAM, 0);
-  if (NULL == ret->sock)
-    {
-      GNUNET_free (ret->addr);
-      GNUNET_free (ret->write_buffer);
-      GNUNET_free (ret);
-      return NULL;
-    }
-  if (GNUNET_OK != GNUNET_NETWORK_socket_connect (ret->sock,
-                                                 ret->addr,
-                                                 ret->addrlen)) 
-    {
-      /* Just return; we expect everything to work eventually so don't fail HARD */
-      GNUNET_break (GNUNET_OK == GNUNET_NETWORK_socket_close (ret->sock));
-      GNUNET_free (ret->addr);
-      GNUNET_free (ret->write_buffer);
-      GNUNET_free (ret);
-      return NULL;
-    }
-  connect_success_continuation (ret);
-  return ret;
+#if HAVE_SOCKADDR_IN_SIN_LEN
+  un->sun_len = (u_char) sizeof (struct sockaddr_un);
+#endif
+  connection = GNUNET_new (struct GNUNET_CONNECTION_Handle);
+  connection->cfg = cfg;
+  connection->write_buffer_size = GNUNET_SERVER_MIN_BUFFER_SIZE;
+  connection->write_buffer = GNUNET_malloc (connection->write_buffer_size);
+  connection->port = 0;
+  connection->hostname = NULL;
+  connection->addr = (struct sockaddr *) un;
+  connection->addrlen = sizeof (struct sockaddr_un);
+  connection->sock = GNUNET_NETWORK_socket_create (AF_UNIX, SOCK_STREAM, 0);
+  if (NULL == connection->sock)
+  {
+    GNUNET_free (connection->addr);
+    GNUNET_free (connection->write_buffer);
+    GNUNET_free (connection);
+    return NULL;
+  }
+  if ( (GNUNET_OK !=
+       GNUNET_NETWORK_socket_connect (connection->sock, connection->addr, connection->addrlen)) &&
+       (EINPROGRESS != errno) )
+  {
+    /* Just return; we expect everything to work eventually so don't fail HARD */
+    GNUNET_break (GNUNET_OK == GNUNET_NETWORK_socket_close (connection->sock));
+    connection->sock = NULL;
+    return connection;
+  }
+  connect_success_continuation (connection);
+  return connection;
 #else
   return NULL;
 #endif
 #else
   return NULL;
 #endif
@@ -980,14 +910,58 @@ GNUNET_CONNECTION_create_from_connect_to_unixpath (const struct
 
 
 /**
 
 
 /**
- * Create a socket handle by (asynchronously) connecting to a host.
+ * Create a connection handle by (asynchronously) connecting to a host.
  * This function returns immediately, even if the connection has not
  * yet been established.  This function only creates TCP connections.
  *
  * This function returns immediately, even if the connection has not
  * yet been established.  This function only creates TCP connections.
  *
+ * @param s socket to connect
+ * @param serv_addr server address
+ * @param addrlen length of @a serv_addr
+ * @return the connection handle
+ */
+struct GNUNET_CONNECTION_Handle *
+GNUNET_CONNECTION_connect_socket (struct GNUNET_NETWORK_Handle *s,
+                                  const struct sockaddr *serv_addr,
+                                  socklen_t addrlen)
+{
+  struct GNUNET_CONNECTION_Handle *connection;
+
+  if ( (GNUNET_OK !=
+        GNUNET_NETWORK_socket_connect (s, serv_addr, addrlen)) &&
+       (EINPROGRESS != errno) )
+  {
+    /* maybe refused / unsupported address, try next */
+    LOG_STRERROR (GNUNET_ERROR_TYPE_DEBUG,
+                  "connect");
+    LOG (GNUNET_ERROR_TYPE_DEBUG,
+         "Attempt to connect to `%s' failed\n",
+         GNUNET_a2s (serv_addr,
+                     addrlen));
+    GNUNET_break (GNUNET_OK == GNUNET_NETWORK_socket_close (s));
+    return NULL;
+  }
+  connection = GNUNET_CONNECTION_create_from_existing (s);
+  connection->addr = GNUNET_malloc (addrlen);
+  memcpy (connection->addr, serv_addr, addrlen);
+  connection->addrlen = addrlen;
+  LOG (GNUNET_ERROR_TYPE_INFO,
+       "Trying to connect to `%s' (%p)\n",
+       GNUNET_a2s (serv_addr, addrlen),
+       connection);
+  return connection;
+}
+
+
+/**
+ * Create a connection handle by creating a socket and
+ * (asynchronously) connecting to a host.  This function returns
+ * immediately, even if the connection has not yet been established.
+ * This function only creates TCP connections.
+ *
  * @param af_family address family to use
  * @param serv_addr server address
  * @param af_family address family to use
  * @param serv_addr server address
- * @param addrlen length of server address
- * @return the socket handle
+ * @param addrlen length of @a serv_addr
+ * @return the connection handle
  */
 struct GNUNET_CONNECTION_Handle *
 GNUNET_CONNECTION_create_from_sockaddr (int af_family,
  */
 struct GNUNET_CONNECTION_Handle *
 GNUNET_CONNECTION_create_from_sockaddr (int af_family,
@@ -995,332 +969,266 @@ GNUNET_CONNECTION_create_from_sockaddr (int af_family,
                                         socklen_t addrlen)
 {
   struct GNUNET_NETWORK_Handle *s;
                                         socklen_t addrlen)
 {
   struct GNUNET_NETWORK_Handle *s;
-  struct GNUNET_CONNECTION_Handle *ret;
-
 
   s = GNUNET_NETWORK_socket_create (af_family, SOCK_STREAM, 0);
 
   s = GNUNET_NETWORK_socket_create (af_family, SOCK_STREAM, 0);
-  if (s == NULL)
-    {
-      GNUNET_log_strerror (GNUNET_ERROR_TYPE_WARNING |
-                           GNUNET_ERROR_TYPE_BULK, "socket");
-      return NULL;
-    }
-  if ((GNUNET_OK != GNUNET_NETWORK_socket_connect (s, serv_addr, addrlen))
-      && (errno != EINPROGRESS))
-    {
-      /* maybe refused / unsupported address, try next */
-      GNUNET_log_strerror (GNUNET_ERROR_TYPE_INFO, "connect");
-      GNUNET_break (GNUNET_OK == GNUNET_NETWORK_socket_close (s));
-      return NULL;
-    }
-  ret = GNUNET_CONNECTION_create_from_existing (s);
-  ret->addr = GNUNET_malloc (addrlen);
-  memcpy (ret->addr, serv_addr, addrlen);
-  ret->addrlen = addrlen;
-#if DEBUG_CONNECTION
-  GNUNET_log (GNUNET_ERROR_TYPE_INFO,
-              _("Trying to connect to `%s' (%p)\n"),
-              GNUNET_a2s (serv_addr, addrlen), ret);
-#endif
-  return ret;
+  if (NULL == s)
+  {
+    LOG_STRERROR (GNUNET_ERROR_TYPE_WARNING | GNUNET_ERROR_TYPE_BULK, "socket");
+    return NULL;
+  }
+  return GNUNET_CONNECTION_connect_socket (s, serv_addr, addrlen);
 }
 
 
 /**
 }
 
 
 /**
- * Check if socket is valid (no fatal errors have happened so far).
- * Note that a socket that is still trying to connect is considered
+ * Check if connection is valid (no fatal errors have happened so far).
+ * Note that a connection that is still trying to connect is considered
  * valid.
  *
  * valid.
  *
- * @param sock socket to check
- * @return GNUNET_YES if valid, GNUNET_NO otherwise
+ * @param connection connection to check
+ * @return #GNUNET_YES if valid, #GNUNET_NO otherwise
  */
 int
  */
 int
-GNUNET_CONNECTION_check (struct GNUNET_CONNECTION_Handle *sock)
+GNUNET_CONNECTION_check (struct GNUNET_CONNECTION_Handle *connection)
 {
 {
-  if ((sock->ap_head != NULL) || (sock->dns_active != NULL))
+  if ((NULL != connection->ap_head) ||
+      (NULL != connection->dns_active) ||
+      (NULL != connection->proxy_handshake))
     return GNUNET_YES;          /* still trying to connect */
     return GNUNET_YES;          /* still trying to connect */
-  return (sock->sock == NULL) ? GNUNET_NO : GNUNET_YES;
+  if ( (0 != connection->destroy_later) ||
+       (NULL == connection->sock) )
+    return GNUNET_NO;
+  return GNUNET_YES;
 }
 
 
 /**
 }
 
 
 /**
- * Close the socket and free associated resources. Pending
- * transmissions may be completed or dropped depending on the
- * arguments.   If a receive call is pending and should 
- * NOT be completed, 'GNUNET_CONNECTION_receive_cancel'
- * should be called explicitly first.
+ * Close the connection and free associated resources.  There must
+ * not be any pending requests for reading or writing to the
+ * connection at this time.
  *
  *
- * @param sock socket to destroy
- * @param finish_pending_write should pending writes be completed or aborted?
- *        (this applies to transmissions where the data has already been
- *        read from the application; all other transmissions should be
- *        aborted using 'GNUNET_CONNECTION_notify_transmit_ready_cancel').
+ * @param connection connection to destroy
  */
 void
  */
 void
-GNUNET_CONNECTION_destroy (struct GNUNET_CONNECTION_Handle *sock,
-                          int finish_pending_write)
+GNUNET_CONNECTION_destroy (struct GNUNET_CONNECTION_Handle *connection)
 {
 {
-  if (GNUNET_NO == finish_pending_write)
+  struct AddressProbe *pos;
+
+  if (0 != connection->destroy_later)
+  {
+    connection->destroy_later = -1;
+    return;
+  }
+  LOG (GNUNET_ERROR_TYPE_DEBUG,
+       "Shutting down connection (%p)\n",
+       connection);
+  GNUNET_assert (NULL == connection->nth.notify_ready);
+  GNUNET_assert (NULL == connection->receiver);
+  if (NULL != connection->write_task)
+  {
+    GNUNET_SCHEDULER_cancel (connection->write_task);
+    connection->write_task = NULL;
+    connection->write_buffer_off = 0;
+  }
+  if (NULL != connection->read_task)
+  {
+    GNUNET_SCHEDULER_cancel (connection->read_task);
+    connection->read_task = NULL;
+  }
+  if (NULL != connection->nth.timeout_task)
+  {
+    GNUNET_SCHEDULER_cancel (connection->nth.timeout_task);
+    connection->nth.timeout_task = NULL;
+  }
+  connection->nth.notify_ready = NULL;
+  if (NULL != connection->dns_active)
+  {
+    GNUNET_RESOLVER_request_cancel (connection->dns_active);
+    connection->dns_active = NULL;
+  }
+  if (NULL != connection->proxy_handshake)
+  {
+    /* GNUNET_CONNECTION_destroy (connection->proxy_handshake); */
+    connection->proxy_handshake->destroy_later = -1;
+    connection->proxy_handshake = NULL;  /* Not leaked ??? */
+  }
+  while (NULL != (pos = connection->ap_head))
+  {
+    GNUNET_break (GNUNET_OK == GNUNET_NETWORK_socket_close (pos->sock));
+    GNUNET_SCHEDULER_cancel (pos->task);
+    GNUNET_CONTAINER_DLL_remove (connection->ap_head, connection->ap_tail, pos);
+    GNUNET_free (pos);
+  }
+  if ( (NULL != connection->sock) &&
+       (GNUNET_YES != connection->persist) )
+  {
+    if ((GNUNET_OK !=
+         GNUNET_NETWORK_socket_shutdown (connection->sock,
+                                         SHUT_RDWR)) &&
+       (ENOTCONN != errno) &&
+       (ECONNRESET != errno) )
+      LOG_STRERROR (GNUNET_ERROR_TYPE_WARNING,
+                    "shutdown");
+  }
+  if (NULL != connection->sock)
+  {
+    if (GNUNET_YES != connection->persist)
     {
     {
-      if (sock->write_task != GNUNET_SCHEDULER_NO_TASK)
-       {
-         GNUNET_SCHEDULER_cancel (sock->write_task);
-         sock->write_task = GNUNET_SCHEDULER_NO_TASK;
-         sock->write_buffer_off = 0;
-       }
+      GNUNET_break (GNUNET_OK ==
+                    GNUNET_NETWORK_socket_close (connection->sock));
     }
     }
-  if ((sock->write_buffer_off == 0) && (sock->dns_active != NULL))
+    else
     {
     {
-      GNUNET_RESOLVER_request_cancel (sock->dns_active);
-      sock->dns_active = NULL;
+      GNUNET_NETWORK_socket_free_memory_only_ (connection->sock); /* at least no memory leak (we deliberately
+                                                                  * leak the socket in this special case) ... */
     }
     }
-
-  GNUNET_assert (GNUNET_SCHEDULER_NO_TASK == sock->destroy_task);
-  sock->destroy_task 
-    = GNUNET_SCHEDULER_add_now (&destroy_continuation, sock);
-}
-
-
-/**
- * Tell the receiver callback that a timeout was reached.
- */
-static void
-signal_timeout (struct GNUNET_CONNECTION_Handle *sh)
-{
-  GNUNET_CONNECTION_Receiver receiver;
-
-#if DEBUG_CONNECTION
-  GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
-              "Network signals time out to receiver (%p)!\n", sh);
-#endif
-  GNUNET_assert (NULL != (receiver = sh->receiver));
-  sh->receiver = NULL;
-  receiver (sh->receiver_cls, NULL, 0, NULL, 0, 0);
-}
-
-
-/**
- * Tell the receiver callback that we had an IO error.
- */
-static void
-signal_error (struct GNUNET_CONNECTION_Handle *sh, int errcode)
-{
-  GNUNET_CONNECTION_Receiver receiver;
-  GNUNET_assert (NULL != (receiver = sh->receiver));
-  sh->receiver = NULL;
-  receiver (sh->receiver_cls, NULL, 0, sh->addr, sh->addrlen, errcode);
+  }
+  GNUNET_free_non_null (connection->addr);
+  GNUNET_free_non_null (connection->hostname);
+  GNUNET_free (connection->write_buffer);
+  GNUNET_free (connection);
 }
 
 
 /**
  * This function is called once we either timeout
  * or have data ready to read.
 }
 
 
 /**
  * This function is called once we either timeout
  * or have data ready to read.
+ *
+ * @param cls connection to read from
+ * @param tc scheduler context
  */
 static void
  */
 static void
-receive_ready (void *cls, const struct GNUNET_SCHEDULER_TaskContext *tc)
+receive_ready (void *cls,
+               const struct GNUNET_SCHEDULER_TaskContext *tc)
 {
 {
-  struct GNUNET_CONNECTION_Handle *sh = cls;
-  struct GNUNET_TIME_Absolute now;
-  char buffer[sh->max];
+  struct GNUNET_CONNECTION_Handle *connection = cls;
+  char buffer[connection->max];
   ssize_t ret;
   GNUNET_CONNECTION_Receiver receiver;
 
   ssize_t ret;
   GNUNET_CONNECTION_Receiver receiver;
 
-  sh->read_task = GNUNET_SCHEDULER_NO_TASK;
-  if ( (GNUNET_YES == sh->ignore_shutdown) &&
-       (0 != (tc->reason & GNUNET_SCHEDULER_REASON_SHUTDOWN))) 
-    {
-      /* ignore shutdown request, go again immediately */
-#if DEBUG_CONNECTION
-      GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
-                 "Ignoring shutdown signal per configuration\n");
-#endif
-      sh->read_task = GNUNET_SCHEDULER_add_read_net (GNUNET_TIME_absolute_get_remaining
-                                                    (sh->receive_timeout),
-                                                    sh->sock,
-                                                    &receive_ready, sh);
-      return;
-    }
-  now = GNUNET_TIME_absolute_get ();
-  if ((now.abs_value > sh->receive_timeout.abs_value) ||
-      (0 != (tc->reason & GNUNET_SCHEDULER_REASON_TIMEOUT)) ||
-      (0 != (tc->reason & GNUNET_SCHEDULER_REASON_SHUTDOWN)))
-    {
-#if DEBUG_CONNECTION
-      if (0 == (tc->reason & GNUNET_SCHEDULER_REASON_SHUTDOWN))
-        GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
-                    "Receive from `%s' encounters error: time out by %llums... (%p)\n",
-                    GNUNET_a2s (sh->addr, sh->addrlen),
-                    GNUNET_TIME_absolute_get_duration (sh->receive_timeout).
-                    rel_value, sh);
-#endif
-      signal_timeout (sh);
-      return;
-    }
-  if (sh->sock == NULL)
-    {
-      /* connect failed for good */
-#if DEBUG_CONNECTION
-      GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
-                  "Receive encounters error, socket closed... (%p)\n", sh);
-#endif
-      signal_error (sh, ECONNREFUSED);
-      return;
-    }
-  GNUNET_assert (GNUNET_NETWORK_fdset_isset (tc->read_ready, sh->sock));
+  connection->read_task = NULL;
+  if (0 != (tc->reason & GNUNET_SCHEDULER_REASON_SHUTDOWN))
+  {
+    /* ignore shutdown request, go again immediately */
+    connection->read_task =
+        GNUNET_SCHEDULER_add_read_net (GNUNET_TIME_absolute_get_remaining
+                                       (connection->receive_timeout), connection->sock,
+                                       &receive_ready, connection);
+    return;
+  }
+  if (0 != (tc->reason & GNUNET_SCHEDULER_REASON_TIMEOUT))
+  {
+    LOG (GNUNET_ERROR_TYPE_DEBUG,
+        "Receive from `%s' encounters error: timeout (%s, %p)\n",
+        GNUNET_a2s (connection->addr, connection->addrlen),
+        GNUNET_STRINGS_relative_time_to_string (GNUNET_TIME_absolute_get_duration (connection->receive_timeout), GNUNET_YES),
+        connection);
+    signal_receive_timeout (connection);
+    return;
+  }
+  if (NULL == connection->sock)
+  {
+    /* connect failed for good */
+    signal_receive_error (connection, ECONNREFUSED);
+    return;
+  }
+  GNUNET_assert (GNUNET_NETWORK_fdset_isset (tc->read_ready, connection->sock));
 RETRY:
 RETRY:
-  ret = GNUNET_NETWORK_socket_recv (sh->sock, buffer, sh->max);
-  if (ret == -1)
-    {
-      if (errno == EINTR)
-        goto RETRY;
-#if DEBUG_CONNECTION
-      GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
-                  "Error receiving: %s\n", STRERROR (errno));
-#endif
-      signal_error (sh, errno);
-      return;
-    }
-#if DEBUG_CONNECTION
-  GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
-              "receive_ready read %u/%u bytes from `%s' (%p)!\n",
-              (unsigned int) ret,
-              sh->max, GNUNET_a2s (sh->addr, sh->addrlen), sh);
-#endif
-  GNUNET_assert (NULL != (receiver = sh->receiver));
-  sh->receiver = NULL;
-  receiver (sh->receiver_cls, buffer, ret, sh->addr, sh->addrlen, 0);
+  ret = GNUNET_NETWORK_socket_recv (connection->sock,
+                                    buffer,
+                                    connection->max);
+  if (-1 == ret)
+  {
+    if (EINTR == errno)
+      goto RETRY;
+    signal_receive_error (connection, errno);
+    return;
+  }
+  LOG (GNUNET_ERROR_TYPE_DEBUG,
+       "receive_ready read %u/%u bytes from `%s' (%p)!\n",
+       (unsigned int) ret,
+       connection->max,
+       GNUNET_a2s (connection->addr,
+                   connection->addrlen),
+       connection);
+  GNUNET_assert (NULL != (receiver = connection->receiver));
+  connection->receiver = NULL;
+  receiver (connection->receiver_cls,
+            buffer,
+            ret,
+            connection->addr,
+            connection->addrlen,
+            0);
 }
 
 
 /**
 }
 
 
 /**
- * This function is called after establishing a connection either has
- * succeeded or timed out.  Note that it is possible that the attempt
- * timed out and that we're immediately retrying.  If we are retrying,
- * we need to wait again (or timeout); if we succeeded, we need to
- * wait for data (or timeout).
- *
- * @param cls our connection handle
- * @param tc task context describing why we are here
- */
-static void
-receive_again (void *cls, const struct GNUNET_SCHEDULER_TaskContext *tc)
-{
-  struct GNUNET_CONNECTION_Handle *sh = cls;
-  struct GNUNET_TIME_Absolute now;
-
-  sh->read_task = GNUNET_SCHEDULER_NO_TASK;
-  if (sh->sock == NULL)
-    {
-      /* not connected and no longer trying */
-#if DEBUG_CONNECTION
-      GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
-                  "Receive encounters error, socket closed (%p)...\n", sh);
-#endif
-      signal_error (sh, ECONNREFUSED);
-      return;
-    }
-  now = GNUNET_TIME_absolute_get ();
-  if ((now.abs_value > sh->receive_timeout.abs_value) ||
-      (0 != (tc->reason & GNUNET_SCHEDULER_REASON_SHUTDOWN)))
-    {
-#if DEBUG_CONNECTION
-      GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
-                  "Receive encounters error: time out (%p)...\n", sh);
-#endif
-      signal_timeout (sh);
-      return;
-    }
-  GNUNET_assert (sh->sock != NULL);
-  /* connect succeeded, wait for data! */
-  sh->read_task = GNUNET_SCHEDULER_add_read_net (GNUNET_TIME_absolute_get_remaining
-                                                 (sh->receive_timeout),
-                                                 sh->sock,
-                                                 &receive_ready, sh);
-}
-
-
-/**
- * Receive data from the given socket.  Note that this function will
- * call "receiver" asynchronously using the scheduler.  It will
+ * Receive data from the given connection.  Note that this function will
+ * call @a receiver asynchronously using the scheduler.  It will
  * "immediately" return.  Note that there MUST only be one active
  * "immediately" return.  Note that there MUST only be one active
- * receive call per socket at any given point in time (so do not
+ * receive call per connection at any given point in time (so do not
  * call receive again until the receiver callback has been invoked).
  *
  * call receive again until the receiver callback has been invoked).
  *
- * @param sock socket handle
+ * @param connection connection handle
  * @param max maximum number of bytes to read
  * @param max maximum number of bytes to read
- * @param timeout maximum amount of time to wait (use -1 for "forever")
+ * @param timeout maximum amount of time to wait
  * @param receiver function to call with received data
  * @param receiver function to call with received data
- * @param receiver_cls closure for receiver
+ * @param receiver_cls closure for @a receiver
  */
 void
  */
 void
-GNUNET_CONNECTION_receive (struct GNUNET_CONNECTION_Handle *sock,
+GNUNET_CONNECTION_receive (struct GNUNET_CONNECTION_Handle *connection,
                            size_t max,
                            struct GNUNET_TIME_Relative timeout,
                            GNUNET_CONNECTION_Receiver receiver,
                            void *receiver_cls)
 {
                            size_t max,
                            struct GNUNET_TIME_Relative timeout,
                            GNUNET_CONNECTION_Receiver receiver,
                            void *receiver_cls)
 {
-  struct GNUNET_SCHEDULER_TaskContext tc;
-
-  GNUNET_assert ((sock->read_task == GNUNET_SCHEDULER_NO_TASK) &&
-                 (0 == (sock->ccs & COCO_RECEIVE_AGAIN)) &&
-                 (sock->receiver == NULL));
-  sock->receiver = receiver;
-  sock->receiver_cls = receiver_cls;
-  sock->receive_timeout = GNUNET_TIME_relative_to_absolute (timeout);
-  sock->max = max;
-  if (sock->sock != NULL)
-    {
-      memset (&tc, 0, sizeof (tc));
-      tc.reason = GNUNET_SCHEDULER_REASON_PREREQ_DONE;
-      receive_again (sock, &tc);
-      return;
-    }
-  if ((sock->dns_active == NULL) && (sock->ap_head == NULL))
-    {
-      receiver (receiver_cls, NULL, 0, NULL, 0, ETIMEDOUT);
-      return;
-    }
-  sock->ccs += COCO_RECEIVE_AGAIN;
+  GNUNET_assert ((NULL == connection->read_task) &&
+                 (NULL == connection->receiver));
+  GNUNET_assert (NULL != receiver);
+  connection->receiver = receiver;
+  connection->receiver_cls = receiver_cls;
+  connection->receive_timeout = GNUNET_TIME_relative_to_absolute (timeout);
+  connection->max = max;
+  if (NULL != connection->sock)
+  {
+    connection->read_task =
+      GNUNET_SCHEDULER_add_read_net (GNUNET_TIME_absolute_get_remaining
+                                     (connection->receive_timeout),
+                                     connection->sock,
+                                     &receive_ready,
+                                     connection);
+    return;
+  }
+  if ((NULL == connection->dns_active) &&
+      (NULL == connection->ap_head) &&
+      (NULL == connection->proxy_handshake))
+  {
+    connection->receiver = NULL;
+    receiver (receiver_cls, NULL, 0, NULL, 0, ETIMEDOUT);
+    return;
+  }
 }
 
 
 /**
 }
 
 
 /**
- * Configure this connection to ignore shutdown signals.
- *
- * @param sock socket handle
- * @param do_ignore GNUNET_YES to ignore, GNUNET_NO to restore default
- */
-void
-GNUNET_CONNECTION_ignore_shutdown (struct GNUNET_CONNECTION_Handle *sock,
-                                  int do_ignore)
-{
-  sock->ignore_shutdown = do_ignore;
-}
-
-
-/**
- * Cancel receive job on the given socket.  Note that the
+ * Cancel receive job on the given connection.  Note that the
  * receiver callback must not have been called yet in order
  * for the cancellation to be valid.
  *
  * receiver callback must not have been called yet in order
  * for the cancellation to be valid.
  *
- * @param sock socket handle
+ * @param connection connection handle
  * @return closure of the original receiver callback closure
  */
 void *
  * @return closure of the original receiver callback closure
  */
 void *
-GNUNET_CONNECTION_receive_cancel (struct GNUNET_CONNECTION_Handle *sock)
+GNUNET_CONNECTION_receive_cancel (struct GNUNET_CONNECTION_Handle *connection)
 {
 {
-  if (sock->read_task != GNUNET_SCHEDULER_NO_TASK)
-    {
-      GNUNET_assert (sock == GNUNET_SCHEDULER_cancel (sock->read_task));
-      sock->read_task = GNUNET_SCHEDULER_NO_TASK;
-    }
-  else
-    {
-      GNUNET_assert (0 != (sock->ccs & COCO_RECEIVE_AGAIN));
-      sock->ccs -= COCO_RECEIVE_AGAIN;
-    }
-  sock->receiver = NULL;
-  return sock->receiver_cls;
+  if (NULL != connection->read_task)
+  {
+    GNUNET_assert (connection ==
+                   GNUNET_SCHEDULER_cancel (connection->read_task));
+    connection->read_task = NULL;
+  }
+  connection->receiver = NULL;
+  return connection->receiver_cls;
 }
 
 
 }
 
 
@@ -1328,41 +1236,53 @@ GNUNET_CONNECTION_receive_cancel (struct GNUNET_CONNECTION_Handle *sock)
  * Try to call the transmit notify method (check if we do
  * have enough space available first)!
  *
  * Try to call the transmit notify method (check if we do
  * have enough space available first)!
  *
- * @param sock socket for which we should do this processing
- * @return GNUNET_YES if we were able to call notify
+ * @param connection connection for which we should do this processing
+ * @return #GNUNET_YES if we were able to call notify
  */
 static int
  */
 static int
-process_notify (struct GNUNET_CONNECTION_Handle *sock)
+process_notify (struct GNUNET_CONNECTION_Handle *connection)
 {
   size_t used;
   size_t avail;
   size_t size;
   GNUNET_CONNECTION_TransmitReadyNotify notify;
 
 {
   size_t used;
   size_t avail;
   size_t size;
   GNUNET_CONNECTION_TransmitReadyNotify notify;
 
-  GNUNET_assert (sock->write_task == GNUNET_SCHEDULER_NO_TASK);
-  if (NULL == (notify = sock->nth.notify_ready))
+  LOG (GNUNET_ERROR_TYPE_DEBUG,
+       "process_notify is running\n");
+  GNUNET_assert (NULL == connection->write_task);
+  if (NULL == (notify = connection->nth.notify_ready))
+  {
+    LOG (GNUNET_ERROR_TYPE_DEBUG,
+         "No one to notify\n");
     return GNUNET_NO;
     return GNUNET_NO;
-  used = sock->write_buffer_off - sock->write_buffer_pos;
-  avail = sock->write_buffer_size - used;
-  size = sock->nth.notify_size;
+  }
+  used = connection->write_buffer_off - connection->write_buffer_pos;
+  avail = connection->write_buffer_size - used;
+  size = connection->nth.notify_size;
   if (size > avail)
   if (size > avail)
+  {
+    LOG (GNUNET_ERROR_TYPE_DEBUG,
+         "Not enough buffer\n");
     return GNUNET_NO;
     return GNUNET_NO;
-  sock->nth.notify_ready = NULL;
-  if (sock->write_buffer_size - sock->write_buffer_off < size)
-    {
-      /* need to compact */
-      memmove (sock->write_buffer,
-               &sock->write_buffer[sock->write_buffer_pos], used);
-      sock->write_buffer_off -= sock->write_buffer_pos;
-      sock->write_buffer_pos = 0;
-    }
-  avail = sock->write_buffer_size - sock->write_buffer_off;
+  }
+  connection->nth.notify_ready = NULL;
+  if (connection->write_buffer_size - connection->write_buffer_off < size)
+  {
+    /* need to compact */
+    memmove (connection->write_buffer,
+             &connection->write_buffer[connection->write_buffer_pos],
+             used);
+    connection->write_buffer_off -= connection->write_buffer_pos;
+    connection->write_buffer_pos = 0;
+  }
+  avail = connection->write_buffer_size - connection->write_buffer_off;
   GNUNET_assert (avail >= size);
   GNUNET_assert (avail >= size);
-  size = notify (sock->nth.notify_ready_cls,
-                 avail,
-                 &sock->write_buffer[sock->write_buffer_off]);
+  size =
+      notify (connection->nth.notify_ready_cls, avail,
+              &connection->write_buffer[connection->write_buffer_off]);
   GNUNET_assert (size <= avail);
   GNUNET_assert (size <= avail);
-  sock->write_buffer_off += size;
+  if (0 != size)
+    connection->write_buffer_off += size;
   return GNUNET_YES;
 }
 
   return GNUNET_YES;
 }
 
@@ -1375,32 +1295,28 @@ process_notify (struct GNUNET_CONNECTION_Handle *sock)
  *
  * This task notifies the client about the timeout.
  *
  *
  * This task notifies the client about the timeout.
  *
- * @param cls the 'struct GNUNET_CONNECTION_Handle'
+ * @param cls the `struct GNUNET_CONNECTION_Handle`
  * @param tc scheduler context
  */
 static void
  * @param tc scheduler context
  */
 static void
-transmit_timeout (void *cls, 
-                 const struct GNUNET_SCHEDULER_TaskContext *tc)
+transmit_timeout (void *cls,
+                  const struct GNUNET_SCHEDULER_TaskContext *tc)
 {
 {
-  struct GNUNET_CONNECTION_Handle *sock = cls;
+  struct GNUNET_CONNECTION_Handle *connection = cls;
   GNUNET_CONNECTION_TransmitReadyNotify notify;
 
   GNUNET_CONNECTION_TransmitReadyNotify notify;
 
-#if DEBUG_CONNECTION
-  GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
-              "transmit_timeout running (%p)\n", sock);
-#endif
-  sock->nth.timeout_task = GNUNET_SCHEDULER_NO_TASK;
-#if DEBUG_CONNECTION
-  GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
-              "Transmit to `%s:%u/%s' fails, time out reached (%p).\n",
-              sock->hostname,
-              sock->port, GNUNET_a2s (sock->addr, sock->addrlen), sock);
-#endif
-  GNUNET_assert (0 != (sock->ccs & COCO_TRANSMIT_READY));
-  sock->ccs -= COCO_TRANSMIT_READY;     /* remove request */
-  notify = sock->nth.notify_ready;
-  sock->nth.notify_ready = NULL;
-  notify (sock->nth.notify_ready_cls, 0, NULL);
+  connection->nth.timeout_task = NULL;
+  LOG (GNUNET_ERROR_TYPE_DEBUG,
+       "Transmit to `%s:%u/%s' fails, time out reached (%p).\n",
+       connection->hostname,
+       connection->port,
+       GNUNET_a2s (connection->addr,
+                   connection->addrlen),
+       connection);
+  notify = connection->nth.notify_ready;
+  GNUNET_assert (NULL != notify);
+  connection->nth.notify_ready = NULL;
+  notify (connection->nth.notify_ready_cls, 0, NULL);
 }
 
 
 }
 
 
@@ -1410,310 +1326,286 @@ transmit_timeout (void *cls,
  *
  * This task notifies the client about the error.
  *
  *
  * This task notifies the client about the error.
  *
- * @param cls the 'struct GNUNET_CONNECTION_Handle'
+ * @param cls the `struct GNUNET_CONNECTION_Handle`
  * @param tc scheduler context
  */
 static void
  * @param tc scheduler context
  */
 static void
-connect_error (void *cls, 
-              const struct GNUNET_SCHEDULER_TaskContext *tc)
+connect_error (void *cls,
+               const struct GNUNET_SCHEDULER_TaskContext *tc)
 {
 {
-  struct GNUNET_CONNECTION_Handle *sock = cls;
+  struct GNUNET_CONNECTION_Handle *connection = cls;
   GNUNET_CONNECTION_TransmitReadyNotify notify;
 
   GNUNET_CONNECTION_TransmitReadyNotify notify;
 
-  GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
-              "Transmission request of size %u fails (%s/%u), connection failed (%p).\n",
-              sock->nth.notify_size, 
-             sock->hostname,
-             sock->port,
-             sock);
-#if DEBUG_CONNECTION
-  GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
-              "Transmission request of size %u fails, connection failed (%p).\n",
-              sock->nth.notify_size, sock);
-#endif
-  sock->write_task = GNUNET_SCHEDULER_NO_TASK;
-  notify = sock->nth.notify_ready;
-  sock->nth.notify_ready = NULL;
-  notify (sock->nth.notify_ready_cls, 0, NULL);
+  LOG (GNUNET_ERROR_TYPE_DEBUG,
+       "Transmission request of size %u fails (%s/%u), connection failed (%p).\n",
+       connection->nth.notify_size,
+       connection->hostname,
+       connection->port,
+       connection);
+  connection->write_task = NULL;
+  notify = connection->nth.notify_ready;
+  connection->nth.notify_ready = NULL;
+  notify (connection->nth.notify_ready_cls, 0, NULL);
 }
 
 
 /**
 }
 
 
 /**
- * FIXME
- *
- * @param sock FIXME
- */
-static void
-transmit_error (struct GNUNET_CONNECTION_Handle *sock)
-{
-  GNUNET_CONNECTION_TransmitReadyNotify notify;
-
-  if (NULL != sock->sock)
-    {
-      GNUNET_NETWORK_socket_shutdown (sock->sock, SHUT_RDWR);
-      GNUNET_break (GNUNET_OK ==
-                   GNUNET_NETWORK_socket_close (sock->sock));
-      sock->sock = NULL;
-    }
-  if (sock->read_task != GNUNET_SCHEDULER_NO_TASK)
-    {
-      GNUNET_SCHEDULER_cancel (sock->read_task);
-      sock->read_task = GNUNET_SCHEDULER_NO_TASK;
-      signal_timeout (sock);
-      return;
-    }
-  if (sock->nth.notify_ready == NULL)
-    return;                     /* nobody to tell about it */
-  notify = sock->nth.notify_ready;
-  sock->nth.notify_ready = NULL;
-  notify (sock->nth.notify_ready_cls, 0, NULL);
-}
-
-
-/**
- * See if we are now connected.  If not, wait longer for
- * connect to succeed.  If connected, we should be able
- * to write now as well, unless we timed out.
+ * We are ready to transmit (or got a timeout).
  *
  * @param cls our connection handle
  * @param tc task context describing why we are here
  */
 static void
  *
  * @param cls our connection handle
  * @param tc task context describing why we are here
  */
 static void
-transmit_ready (void *cls, const struct GNUNET_SCHEDULER_TaskContext *tc)
+transmit_ready (void *cls,
+                const struct GNUNET_SCHEDULER_TaskContext *tc)
 {
 {
-  struct GNUNET_CONNECTION_Handle *sock = cls;
+  struct GNUNET_CONNECTION_Handle *connection = cls;
   GNUNET_CONNECTION_TransmitReadyNotify notify;
   ssize_t ret;
   size_t have;
 
   GNUNET_CONNECTION_TransmitReadyNotify notify;
   ssize_t ret;
   size_t have;
 
-#if DEBUG_CONNECTION
-  GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
-              "transmit_ready running (%p).\n", sock);
-#endif
-  GNUNET_assert (sock->write_task != GNUNET_SCHEDULER_NO_TASK);
-  sock->write_task = GNUNET_SCHEDULER_NO_TASK;
-  GNUNET_assert (sock->nth.timeout_task == GNUNET_SCHEDULER_NO_TASK);
-  if (0 != (tc->reason & GNUNET_SCHEDULER_REASON_SHUTDOWN)) 
+  LOG (GNUNET_ERROR_TYPE_DEBUG,
+       "transmit_ready running (%p).\n",
+       connection);
+  GNUNET_assert (NULL != connection->write_task);
+  connection->write_task = NULL;
+  GNUNET_assert (NULL == connection->nth.timeout_task);
+  if (0 != (tc->reason & GNUNET_SCHEDULER_REASON_SHUTDOWN))
+  {
+    if (NULL != connection->sock)
+      goto SCHEDULE_WRITE;      /* ignore shutdown, go again immediately */
+    LOG (GNUNET_ERROR_TYPE_DEBUG,
+         "Transmit to `%s' fails, shutdown happened (%p).\n",
+         GNUNET_a2s (connection->addr, connection->addrlen), connection);
+    notify = connection->nth.notify_ready;
+    if (NULL != notify)
     {
     {
-      if (sock->ignore_shutdown == GNUNET_YES)
-       goto SCHEDULE_WRITE;    /* ignore shutdown, go again immediately */
-#if DEBUG_CONNECTION
-      GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
-                  "Transmit to `%s' fails, shutdown happened (%p).\n",
-                  GNUNET_a2s (sock->addr, sock->addrlen), sock);
-#endif
-      notify = sock->nth.notify_ready;
-      sock->nth.notify_ready = NULL;
-      notify (sock->nth.notify_ready_cls, 0, NULL);
-      return;
+      connection->nth.notify_ready = NULL;
+      notify (connection->nth.notify_ready_cls, 0, NULL);
     }
     }
+    return;
+  }
   if (0 != (tc->reason & GNUNET_SCHEDULER_REASON_TIMEOUT))
   if (0 != (tc->reason & GNUNET_SCHEDULER_REASON_TIMEOUT))
-    {
-#if DEBUG_CONNECTION
-      GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
-                  "Transmit to `%s' fails, time out reached (%p).\n",
-                  GNUNET_a2s (sock->addr, sock->addrlen), sock);
-#endif
-      notify = sock->nth.notify_ready;
-      sock->nth.notify_ready = NULL;
-      notify (sock->nth.notify_ready_cls, 0, NULL);
-      return;
-    }
-  GNUNET_assert (NULL != sock->sock);
-  if (tc->write_ready == NULL)
-    {
-      /* special circumstances (in particular,
-         PREREQ_DONE after connect): not yet ready to write,
-         but no "fatal" error either.  Hence retry.  */
-      goto SCHEDULE_WRITE;
-    }
-  if (!GNUNET_NETWORK_fdset_isset (tc->write_ready, sock->sock))
-    {
-#if DEBUG_CONNECTION
-      GNUNET_log (GNUNET_ERROR_TYPE_INFO,
-                  _
-                  ("Could not satisfy pending transmission request, socket closed or connect failed (%p).\n"),
-                  sock);
-#endif
-      transmit_error (sock);
-      return;                   /* connect failed for good, we're finished */
-    }
-  GNUNET_assert (sock->write_buffer_off >= sock->write_buffer_pos);
-  if ( (sock->nth.notify_ready != NULL) &&
-       (sock->write_buffer_size < sock->nth.notify_size) )
-    {
-      sock->write_buffer = GNUNET_realloc(sock->write_buffer, 
-                                         sock->nth.notify_size);
-      sock->write_buffer_size = sock->nth.notify_size;
-    }    
-  process_notify (sock);
-  have = sock->write_buffer_off - sock->write_buffer_pos;
-  if (have == 0)
-    {
-      /* no data ready for writing, terminate write loop */
-      return;
-    }
-  GNUNET_assert (have <= sock->write_buffer_size);
-  GNUNET_assert (have + sock->write_buffer_pos <= sock->write_buffer_size);
-  GNUNET_assert (sock->write_buffer_pos <= sock->write_buffer_size);
+  {
+    LOG (GNUNET_ERROR_TYPE_DEBUG,
+         "Transmit to `%s' fails, time out reached (%p).\n",
+         GNUNET_a2s (connection->addr,
+                     connection->addrlen),
+         connection);
+    notify = connection->nth.notify_ready;
+    GNUNET_assert (NULL != notify);
+    connection->nth.notify_ready = NULL;
+    notify (connection->nth.notify_ready_cls, 0, NULL);
+    return;
+  }
+  GNUNET_assert (NULL != connection->sock);
+  if (NULL == tc->write_ready)
+  {
+    /* special circumstances (in particular, PREREQ_DONE after
+     * connect): not yet ready to write, but no "fatal" error either.
+     * Hence retry.  */
+    goto SCHEDULE_WRITE;
+  }
+  if (!GNUNET_NETWORK_fdset_isset (tc->write_ready, connection->sock))
+  {
+    GNUNET_assert (NULL == connection->write_task);
+    /* special circumstances (in particular, shutdown): not yet ready
+     * to write, but no "fatal" error either.  Hence retry.  */
+    goto SCHEDULE_WRITE;
+  }
+  GNUNET_assert (connection->write_buffer_off >= connection->write_buffer_pos);
+  if ((NULL != connection->nth.notify_ready) &&
+      (connection->write_buffer_size < connection->nth.notify_size))
+  {
+    connection->write_buffer =
+        GNUNET_realloc (connection->write_buffer, connection->nth.notify_size);
+    connection->write_buffer_size = connection->nth.notify_size;
+  }
+  process_notify (connection);
+  have = connection->write_buffer_off - connection->write_buffer_pos;
+  if (0 == have)
+  {
+    /* no data ready for writing, terminate write loop */
+    return;
+  }
+  GNUNET_assert (have <= connection->write_buffer_size);
+  GNUNET_assert (have + connection->write_buffer_pos <= connection->write_buffer_size);
+  GNUNET_assert (connection->write_buffer_pos <= connection->write_buffer_size);
 RETRY:
 RETRY:
-  ret = GNUNET_NETWORK_socket_send (sock->sock,
-                                    &sock->write_buffer[sock->
-                                                        write_buffer_pos],
-                                    have);
-  if (ret == -1)
+  ret =
+      GNUNET_NETWORK_socket_send (connection->sock,
+                                 &connection->write_buffer[connection->write_buffer_pos],
+                                 have);
+  if (-1 == ret)
+  {
+    if (EINTR == errno)
+      goto RETRY;
+    if (NULL != connection->write_task)
     {
     {
-      if (errno == EINTR)
-        goto RETRY;
-#if 0
-      int en = errno;
-      GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
-                 _("Failed to send to `%s': %s\n"),
-                 GNUNET_a2s (sock->addr,
-                             sock->addrlen),
-                 STRERROR (en));
-#endif
-#if DEBUG_CONNECTION
-      GNUNET_log_strerror (GNUNET_ERROR_TYPE_DEBUG, "send");
-#endif
-      transmit_error (sock);
-      return;
+      GNUNET_SCHEDULER_cancel (connection->write_task);
+      connection->write_task = NULL;
     }
     }
-#if DEBUG_CONNECTION
-  GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
-              "transmit_ready transmitted %u/%u bytes to `%s' (%p)\n",
-              (unsigned int) ret,
-              have, GNUNET_a2s (sock->addr, sock->addrlen), sock);
-#endif
-  sock->write_buffer_pos += ret;
-  if (sock->write_buffer_pos == sock->write_buffer_off)
-    {
-      /* transmitted all pending data */
-      sock->write_buffer_pos = 0;
-      sock->write_buffer_off = 0;
-    }
-  if ((sock->write_buffer_off == 0) && (NULL == sock->nth.notify_ready))
+    signal_transmit_error (connection, errno);
+    return;
+  }
+  LOG (GNUNET_ERROR_TYPE_DEBUG,
+       "Connection transmitted %u/%u bytes to `%s' (%p)\n",
+       (unsigned int) ret, have, GNUNET_a2s (connection->addr, connection->addrlen), connection);
+  connection->write_buffer_pos += ret;
+  if (connection->write_buffer_pos == connection->write_buffer_off)
+  {
+    /* transmitted all pending data */
+    connection->write_buffer_pos = 0;
+    connection->write_buffer_off = 0;
+  }
+  if ((0 == connection->write_buffer_off) && (NULL == connection->nth.notify_ready))
     return;                     /* all data sent! */
   /* not done writing, schedule more */
 SCHEDULE_WRITE:
     return;                     /* all data sent! */
   /* not done writing, schedule more */
 SCHEDULE_WRITE:
-#if DEBUG_CONNECTION
-  GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
-              "Re-scheduling transmit_ready (more to do) (%p).\n", sock);
-#endif
-  if (sock->write_task == GNUNET_SCHEDULER_NO_TASK)
-    sock->write_task =
-      GNUNET_SCHEDULER_add_write_net (GNUNET_TIME_absolute_get_remaining
-                                      (sock->nth.transmit_timeout),
-                                      sock->sock, &transmit_ready, sock);
+  LOG (GNUNET_ERROR_TYPE_DEBUG,
+       "Re-scheduling transmit_ready (more to do) (%p).\n", connection);
+  have = connection->write_buffer_off - connection->write_buffer_pos;
+  GNUNET_assert ((NULL != connection->nth.notify_ready) || (have > 0));
+  if (NULL == connection->write_task)
+    connection->write_task =
+        GNUNET_SCHEDULER_add_write_net ((connection->nth.notify_ready ==
+                                         NULL) ? GNUNET_TIME_UNIT_FOREVER_REL :
+                                        GNUNET_TIME_absolute_get_remaining
+                                        (connection->nth.transmit_timeout),
+                                        connection->sock, &transmit_ready, connection);
 }
 
 
 /**
 }
 
 
 /**
- * Ask the socket to call us once the specified number of bytes
- * are free in the transmission buffer.  May call the notify
- * method immediately if enough space is available.
+ * Ask the connection to call us once the specified number of bytes
+ * are free in the transmission buffer.  Will never call the @a notify
+ * callback in this task, but always first go into the scheduler.
  *
  *
- * @param sock socket
+ * @param connection connection
  * @param size number of bytes to send
  * @param timeout after how long should we give up (and call
  * @param size number of bytes to send
  * @param timeout after how long should we give up (and call
- *        notify with buf NULL and size 0)?
+ *        @a notify with buf NULL and size 0)?
  * @param notify function to call
  * @param notify function to call
- * @param notify_cls closure for notify
+ * @param notify_cls closure for @a notify
  * @return non-NULL if the notify callback was queued,
  *         NULL if we are already going to notify someone else (busy)
  */
 struct GNUNET_CONNECTION_TransmitHandle *
  * @return non-NULL if the notify callback was queued,
  *         NULL if we are already going to notify someone else (busy)
  */
 struct GNUNET_CONNECTION_TransmitHandle *
-GNUNET_CONNECTION_notify_transmit_ready (struct GNUNET_CONNECTION_Handle
-                                         *sock, size_t size,
+GNUNET_CONNECTION_notify_transmit_ready (struct GNUNET_CONNECTION_Handle *connection,
+                                         size_t size,
                                          struct GNUNET_TIME_Relative timeout,
                                          GNUNET_CONNECTION_TransmitReadyNotify
                                          notify, void *notify_cls)
 {
                                          struct GNUNET_TIME_Relative timeout,
                                          GNUNET_CONNECTION_TransmitReadyNotify
                                          notify, void *notify_cls)
 {
-  if (sock->nth.notify_ready != NULL)
-    {
-      GNUNET_break (0);
-      return NULL;
-    }
-  GNUNET_assert (notify != NULL);
+  if (NULL != connection->nth.notify_ready)
+  {
+    GNUNET_assert (0);
+    return NULL;
+  }
+  GNUNET_assert (NULL != notify);
   GNUNET_assert (size < GNUNET_SERVER_MAX_MESSAGE_SIZE);
   GNUNET_assert (size < GNUNET_SERVER_MAX_MESSAGE_SIZE);
-  GNUNET_assert (sock->write_buffer_off <= sock->write_buffer_size);
-  GNUNET_assert (sock->write_buffer_pos <= sock->write_buffer_size);
-  GNUNET_assert (sock->write_buffer_pos <= sock->write_buffer_off);
-  sock->nth.notify_ready = notify;
-  sock->nth.notify_ready_cls = notify_cls;
-  sock->nth.sh = sock;
-  sock->nth.notify_size = size;
-  sock->nth.transmit_timeout = GNUNET_TIME_relative_to_absolute (timeout);
-  GNUNET_assert (GNUNET_SCHEDULER_NO_TASK == sock->nth.timeout_task);
-  if ((sock->sock == NULL) &&
-      (sock->ap_head == NULL) && (sock->dns_active == NULL))
-    {
-      if (sock->write_task != GNUNET_SCHEDULER_NO_TASK)
-       GNUNET_SCHEDULER_cancel (sock->write_task);
-      sock->write_task = GNUNET_SCHEDULER_add_now (&connect_error, sock);
-      return &sock->nth;
-    }
-  if (GNUNET_SCHEDULER_NO_TASK != sock->write_task)
-    return &sock->nth;
-  if (sock->sock != NULL)
-    {
-#if DEBUG_CONNECTION
-      GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
-                  "Scheduling transmit_ready (%p).\n", sock);
-#endif
-      sock->write_task = GNUNET_SCHEDULER_add_write_net (GNUNET_TIME_absolute_get_remaining
-                                                         (sock->nth.
-                                                          transmit_timeout),
-                                                         sock->sock,
-                                                         &transmit_ready,
-                                                         sock);
-    }
-  else
-    {
-#if DEBUG_CONNECTION
-      GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
-                  "CCS-Scheduling transmit_ready, adding timeout task (%p).\n",
-                  sock);
-#endif
-      sock->ccs |= COCO_TRANSMIT_READY;
-      sock->nth.timeout_task = GNUNET_SCHEDULER_add_delayed (timeout,
-                                                             &transmit_timeout,
-                                                             sock);
-    }
-  return &sock->nth;
+  GNUNET_assert (connection->write_buffer_off <= connection->write_buffer_size);
+  GNUNET_assert (connection->write_buffer_pos <= connection->write_buffer_size);
+  GNUNET_assert (connection->write_buffer_pos <= connection->write_buffer_off);
+  connection->nth.notify_ready = notify;
+  connection->nth.notify_ready_cls = notify_cls;
+  connection->nth.connection = connection;
+  connection->nth.notify_size = size;
+  connection->nth.transmit_timeout = GNUNET_TIME_relative_to_absolute (timeout);
+  GNUNET_assert (NULL == connection->nth.timeout_task);
+  if ((NULL == connection->sock) &&
+      (NULL == connection->ap_head) &&
+      (NULL == connection->dns_active) &&
+      (NULL == connection->proxy_handshake))
+  {
+    if (NULL != connection->write_task)
+      GNUNET_SCHEDULER_cancel (connection->write_task);
+    connection->write_task = GNUNET_SCHEDULER_add_now (&connect_error,
+                                                       connection);
+    return &connection->nth;
+  }
+  if (NULL != connection->write_task)
+    return &connection->nth; /* previous transmission still in progress */
+  if (NULL != connection->sock)
+  {
+    /* connected, try to transmit now */
+    LOG (GNUNET_ERROR_TYPE_DEBUG,
+         "Scheduling transmission (%p).\n",
+         connection);
+    connection->write_task =
+        GNUNET_SCHEDULER_add_write_net (GNUNET_TIME_absolute_get_remaining
+                                        (connection->nth.transmit_timeout),
+                                        connection->sock, &transmit_ready, connection);
+    return &connection->nth;
+  }
+  /* not yet connected, wait for connection */
+  LOG (GNUNET_ERROR_TYPE_DEBUG,
+       "Need to wait to schedule transmission for connection, adding timeout task (%p).\n",
+       connection);
+  connection->nth.timeout_task =
+    GNUNET_SCHEDULER_add_delayed (timeout,
+                                  &transmit_timeout, connection);
+  return &connection->nth;
 }
 
 
 /**
 }
 
 
 /**
- * Cancel the specified transmission-ready
- * notification.
+ * Cancel the specified transmission-ready notification.
+ *
+ * @param th notification to cancel
  */
 void
  */
 void
-GNUNET_CONNECTION_notify_transmit_ready_cancel (struct
-                                                GNUNET_CONNECTION_TransmitHandle
-                                                *h)
+GNUNET_CONNECTION_notify_transmit_ready_cancel (struct GNUNET_CONNECTION_TransmitHandle *th)
 {
 {
-  GNUNET_assert (h->notify_ready != NULL);
-  if (0 != (h->sh->ccs & COCO_TRANSMIT_READY))
-    {
-#if DEBUG_CONNECTION
-      GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
-                  "notify_transmit_ready_cancel cancels timeout_task (%p)\n",
-                  h);
-#endif
-      GNUNET_SCHEDULER_cancel (h->timeout_task);
-      h->timeout_task = GNUNET_SCHEDULER_NO_TASK;
-      h->sh->ccs -= COCO_TRANSMIT_READY;
-    }
-  else
-    {
-      if (h->sh->write_task != GNUNET_SCHEDULER_NO_TASK)
-       {
-         GNUNET_SCHEDULER_cancel (h->sh->write_task);
-         h->sh->write_task = GNUNET_SCHEDULER_NO_TASK;
-       }
-    }
-  h->notify_ready = NULL;
+  GNUNET_assert (NULL != th->notify_ready);
+  th->notify_ready = NULL;
+  if (NULL != th->timeout_task)
+  {
+    GNUNET_SCHEDULER_cancel (th->timeout_task);
+    th->timeout_task = NULL;
+  }
+  if (NULL != th->connection->write_task)
+  {
+    GNUNET_SCHEDULER_cancel (th->connection->write_task);
+    th->connection->write_task = NULL;
+  }
+}
+
+
+/**
+ * Create a connection to be proxied using a given connection.
+ *
+ * @param cph connection to proxy server
+ * @return connection to be proxied
+ */
+struct GNUNET_CONNECTION_Handle *
+GNUNET_CONNECTION_create_proxied_from_handshake (struct GNUNET_CONNECTION_Handle *cph)
+{
+  struct GNUNET_CONNECTION_Handle * proxied = GNUNET_CONNECTION_create_from_existing(NULL);
+  proxied->proxy_handshake = cph;
+  return proxied;
 }
 
 }
 
+
+/**
+ * Activate proxied connection and destroy initial proxy handshake connection.
+ * There must not be any pending requests for reading or writing to the
+ * proxy hadshake connection at this time.
+ *
+ * @param proxied connection connection to proxy server
+ */
+void
+GNUNET_CONNECTION_acivate_proxied (struct GNUNET_CONNECTION_Handle *proxied)
+{
+  struct GNUNET_CONNECTION_Handle *cph = proxied->proxy_handshake;
+  GNUNET_assert (NULL != cph);
+  GNUNET_assert (NULL == proxied->sock);
+  GNUNET_assert (NULL != cph->sock);
+  proxied->sock=cph->sock;
+  cph->sock=NULL;
+  GNUNET_CONNECTION_destroy (cph);
+  connect_success_continuation (proxied);
+}
+
+
 /* end of connection.c */
 /* end of connection.c */