Copyright years
[oweals/gnunet.git] / src / util / connection.c
index 4473b7bb581f7647a217968583f62de01ed793c6..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 LOG(kind,...) GNUNET_log_from (kind, "util", __VA_ARGS__)
 
 #define LOG_STRERROR(kind,syscall) GNUNET_log_from_strerror (kind, "util", syscall)
 
 
 
 #define LOG(kind,...) GNUNET_log_from (kind, "util", __VA_ARGS__)
 
 #define LOG_STRERROR(kind,syscall) GNUNET_log_from_strerror (kind, "util", syscall)
 
-/**
- * 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
-
-};
-
 
 /**
  * Transmission handle.  There can only be one for each connection.
 
 /**
  * Transmission handle.  There can only be one for each connection.
@@ -97,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
@@ -148,7 +121,7 @@ struct AddressProbe
   /**
    * Task waiting for the connection to finish connecting.
    */
   /**
    * Task waiting for the connection to finish connecting.
    */
-  GNUNET_SCHEDULER_TaskIdentifier task;
+  struct GNUNET_SCHEDULER_Task * task;
 };
 
 
 };
 
 
@@ -197,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;
 
@@ -207,36 +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;
+  struct GNUNET_SCHEDULER_Task *write_task;
 
   /**
    * Handle to a pending DNS lookup request.
 
   /**
    * Handle to a pending DNS lookup request.
@@ -253,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 connection.
-   */
-  int ignore_shutdown;
-
   /**
    * Port to connect to.
    */
   /**
    * Port to connect to.
    */
@@ -279,10 +242,23 @@ 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.
 /**
  * Set the persist option on this connection handle.  Indicates
  * that the underlying socket or fd should never really be closed.
@@ -306,7 +282,7 @@ GNUNET_CONNECTION_persist_ (struct GNUNET_CONNECTION_Handle *connection)
  * reach the other side before the process is terminated.
  *
  * @param connection the connection to make flushing and blocking
  * reach the other side before the process is terminated.
  *
  * @param connection the connection to make flushing and blocking
- * @return GNUNET_OK on success
+ * @return #GNUNET_OK on success
  */
 int
 GNUNET_CONNECTION_disable_corking (struct GNUNET_CONNECTION_Handle *connection)
  */
 int
 GNUNET_CONNECTION_disable_corking (struct GNUNET_CONNECTION_Handle *connection)
@@ -318,7 +294,7 @@ GNUNET_CONNECTION_disable_corking (struct GNUNET_CONNECTION_Handle *connection)
 /**
  * Create a connection handle by boxing an existing OS socket.  The OS
  * socket should henceforth be no longer used directly.
 /**
  * Create a connection handle by boxing an existing OS socket.  The OS
  * socket should henceforth be no longer used directly.
- * GNUNET_connection_destroy will close it.
+ * #GNUNET_connection_destroy() will close it.
  *
  * @param osSocket existing socket to box
  * @return the boxed connection handle
  *
  * @param osSocket existing socket to box
  * @return the boxed connection handle
@@ -328,7 +304,7 @@ GNUNET_CONNECTION_create_from_existing (struct GNUNET_NETWORK_Handle *osSocket)
 {
   struct GNUNET_CONNECTION_Handle *connection;
 
 {
   struct GNUNET_CONNECTION_Handle *connection;
 
-  connection = GNUNET_malloc (sizeof (struct GNUNET_CONNECTION_Handle));
+  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;
   connection->write_buffer_size = GNUNET_SERVER_MIN_BUFFER_SIZE;
   connection->write_buffer = GNUNET_malloc (connection->write_buffer_size);
   connection->sock = osSocket;
@@ -340,14 +316,14 @@ GNUNET_CONNECTION_create_from_existing (struct GNUNET_NETWORK_Handle *osSocket)
  * Create a connection handle by accepting on a listen socket.  This
  * function may block if the listen socket has no connection ready.
  *
  * Create a connection handle by accepting on a listen socket.  This
  * 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
  * @return the connection handle, NULL on error
  */
 struct GNUNET_CONNECTION_Handle *
  * @param lsock listen socket
  * @return the connection handle, NULL on error
  */
 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_CONNECTION_Handle *connection;
                                       struct GNUNET_NETWORK_Handle *lsock)
 {
   struct GNUNET_CONNECTION_Handle *connection;
@@ -361,7 +337,6 @@ GNUNET_CONNECTION_create_from_accept (GNUNET_CONNECTION_AccessCheck access,
   void *uaddr;
   struct GNUNET_CONNECTION_Credentials *gcp;
   struct GNUNET_CONNECTION_Credentials gc;
   void *uaddr;
   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;
@@ -372,7 +347,8 @@ GNUNET_CONNECTION_create_from_accept (GNUNET_CONNECTION_AccessCheck access,
       GNUNET_NETWORK_socket_accept (lsock, (struct sockaddr *) &addr, &addrlen);
   if (NULL == sock)
   {
       GNUNET_NETWORK_socket_accept (lsock, (struct sockaddr *) &addr, &addrlen);
   if (NULL == sock)
   {
-    LOG_STRERROR (GNUNET_ERROR_TYPE_WARNING, "accept");
+    if (EAGAIN != errno)
+      LOG_STRERROR (GNUNET_ERROR_TYPE_WARNING, "accept");
     return NULL;
   }
   if ((addrlen > sizeof (addr)) || (addrlen < sizeof (sa_family_t)))
     return NULL;
   }
   if ((addrlen > sizeof (addr)) || (addrlen < sizeof (sa_family_t)))
@@ -384,10 +360,10 @@ GNUNET_CONNECTION_create_from_accept (GNUNET_CONNECTION_AccessCheck access,
 
   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)))
+  if ((AF_INET6 == sa->sa_family) && (IN6_IS_ADDR_V4MAPPED (&v6->sin6_addr)))
   {
     /* convert to V4 address */
   {
     /* convert to V4 address */
-    v4 = GNUNET_malloc (sizeof (struct sockaddr_in));
+    v4 = GNUNET_new (struct sockaddr_in);
     memset (v4, 0, sizeof (struct sockaddr_in));
     v4->sin_family = AF_INET;
 #if HAVE_SOCKADDR_IN_SIN_LEN
     memset (v4, 0, sizeof (struct sockaddr_in));
     v4->sin_family = AF_INET;
 #if HAVE_SOCKADDR_IN_SIN_LEN
@@ -409,7 +385,7 @@ GNUNET_CONNECTION_create_from_accept (GNUNET_CONNECTION_AccessCheck access,
   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
     /* most BSDs */
   {
 #if HAVE_GETPEEREID
     /* most BSDs */
@@ -445,25 +421,28 @@ GNUNET_CONNECTION_create_from_accept (GNUNET_CONNECTION_AccessCheck access,
 #endif
   }
 
 #endif
   }
 
-  if ((access != NULL) &&
-      (GNUNET_YES != (aret = access (access_cls, gcp, uaddr, addrlen))))
+  if ((NULL != access_cb) &&
+      (GNUNET_YES != (aret = access_cb (access_cb_cls, gcp, uaddr, addrlen))))
   {
   {
-    if (aret == GNUNET_NO)
-      LOG (GNUNET_ERROR_TYPE_INFO, _("Access denied to `%s'\n"),
-           GNUNET_a2s (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_break (GNUNET_OK ==
-                  GNUNET_NETWORK_socket_shutdown (sock, SHUT_RDWR));
+                  GNUNET_NETWORK_socket_shutdown (sock,
+                                                  SHUT_RDWR));
     GNUNET_break (GNUNET_OK == GNUNET_NETWORK_socket_close (sock));
     GNUNET_free (uaddr);
     return NULL;
   }
     GNUNET_break (GNUNET_OK == GNUNET_NETWORK_socket_close (sock));
     GNUNET_free (uaddr);
     return NULL;
   }
-  connection = GNUNET_malloc (sizeof (struct GNUNET_CONNECTION_Handle));
+  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;
   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, 
+  LOG (GNUNET_ERROR_TYPE_INFO,
        _("Accepting connection from `%s': %p\n"),
        GNUNET_a2s (uaddr, addrlen), connection);
   return connection;
        _("Accepting connection from `%s': %p\n"),
        GNUNET_a2s (uaddr, addrlen), connection);
   return connection;
@@ -475,14 +454,15 @@ GNUNET_CONNECTION_create_from_accept (GNUNET_CONNECTION_AccessCheck access,
  *
  * @param connection the client to get the address for
  * @param addr where to store the address
  *
  * @param connection the client to get the address for
  * @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
 GNUNET_CONNECTION_get_address (struct GNUNET_CONNECTION_Handle *connection,
  */
 int
 GNUNET_CONNECTION_get_address (struct GNUNET_CONNECTION_Handle *connection,
-                               void **addr, size_t * addrlen)
+                               void **addr,
+                               size_t *addrlen)
 {
 {
-  if ((connection->addr == NULL) || (connection->addrlen == 0))
+  if ((NULL == connection->addr) || (0 == connection->addrlen))
     return GNUNET_NO;
   *addr = GNUNET_malloc (connection->addrlen);
   memcpy (*addr, connection->addr, connection->addrlen);
     return GNUNET_NO;
   *addr = GNUNET_malloc (connection->addrlen);
   memcpy (*addr, connection->addr, connection->addrlen);
@@ -492,72 +472,157 @@ GNUNET_CONNECTION_get_address (struct GNUNET_CONNECTION_Handle *connection,
 
 
 /**
 
 
 /**
- * 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);
+}
 
 
 /**
 
 
 /**
- * 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.
+ * Tell the receiver callback that a timeout was reached.
  *
  *
- * @param cls our connection handle
- * @param tc task context describing why we are here
+ * @param connection connection to signal for
  */
 static void
  */
 static void
-transmit_ready (void *cls, const struct GNUNET_SCHEDULER_TaskContext *tc);
+signal_receive_timeout (struct GNUNET_CONNECTION_Handle *connection)
+{
+  GNUNET_CONNECTION_Receiver receiver;
+
+  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);
+}
+
+
+/**
+ * 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.
+ * We've failed for good to establish a connection (timeout or
+ * no more addresses to try).
  *
  *
- * @param h the connection we tried to establish
+ * @param connection the connection we tried to establish
  */
 static void
  */
 static void
-connect_fail_continuation (struct GNUNET_CONNECTION_Handle *h)
+connect_fail_continuation (struct GNUNET_CONNECTION_Handle *connection)
 {
   LOG (GNUNET_ERROR_TYPE_INFO,
 {
   LOG (GNUNET_ERROR_TYPE_INFO,
-       _("Failed to establish TCP connection to `%s:%u', no further addresses to try.\n"),
-       h->hostname, h->port);
-  /* 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))
+       "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)
   {
   {
-    LOG (GNUNET_ERROR_TYPE_DEBUG,
-         "connect_fail_continuation triggers receive_again (%p)\n", h);
-    h->ccs -= COCO_RECEIVE_AGAIN;
-    h->read_task = GNUNET_SCHEDULER_add_now (&receive_again, h);
+    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 (0 != (h->ccs & COCO_TRANSMIT_READY))
+  if (-1 == connection->destroy_later)
   {
   {
-    LOG (GNUNET_ERROR_TYPE_DEBUG,
-         "connect_fail_continuation cancels timeout_task, triggers transmit_ready (%p)\n",
-         h);
-    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->nth.notify_ready != NULL);
-    GNUNET_assert (h->write_task == GNUNET_SCHEDULER_NO_TASK);
-    h->write_task = GNUNET_SCHEDULER_add_now (&transmit_ready, h);
+    /* do it now */
+    connection->destroy_later = 0;
+    GNUNET_CONNECTION_destroy (connection);
+    return;
   }
   }
+  connection->destroy_later = 0;
 }
 
 
 }
 
 
+/**
+ * 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
+transmit_ready (void *cls, const struct GNUNET_SCHEDULER_TaskContext *tc);
+
+
+/**
+ * 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
+receive_ready (void *cls, const struct GNUNET_SCHEDULER_TaskContext *tc);
+
+
 /**
  * We've succeeded in establishing a connection.
  *
 /**
  * We've succeeded in establishing a connection.
  *
@@ -566,27 +631,31 @@ connect_fail_continuation (struct GNUNET_CONNECTION_Handle *h)
 static void
 connect_success_continuation (struct GNUNET_CONNECTION_Handle *connection)
 {
 static void
 connect_success_continuation (struct GNUNET_CONNECTION_Handle *connection)
 {
-  LOG (GNUNET_ERROR_TYPE_DEBUG, "Connection to `%s' succeeded! (%p)\n",
-       GNUNET_a2s (connection->addr, connection->addrlen), connection);
+  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 != (connection->ccs & COCO_RECEIVE_AGAIN))
+  if (NULL != connection->receiver)
   {
     LOG (GNUNET_ERROR_TYPE_DEBUG,
   {
     LOG (GNUNET_ERROR_TYPE_DEBUG,
-         "connect_success_continuation runs receive_again (%p)\n", connection);
-    connection->ccs -= COCO_RECEIVE_AGAIN;
-    connection->read_task = GNUNET_SCHEDULER_add_now (&receive_again, connection);
+         "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 (0 != (connection->ccs & COCO_TRANSMIT_READY))
+  if (NULL != connection->nth.notify_ready)
   {
     LOG (GNUNET_ERROR_TYPE_DEBUG,
   {
     LOG (GNUNET_ERROR_TYPE_DEBUG,
-         "connect_success_continuation runs transmit_ready, cancels timeout_task (%p)\n",
+         "Connection succeeded, starting with sending data (%p)\n",
          connection);
          connection);
-    GNUNET_assert (connection->nth.timeout_task != GNUNET_SCHEDULER_NO_TASK);
+    GNUNET_assert (connection->nth.timeout_task != NULL);
     GNUNET_SCHEDULER_cancel (connection->nth.timeout_task);
     GNUNET_SCHEDULER_cancel (connection->nth.timeout_task);
-    connection->nth.timeout_task = GNUNET_SCHEDULER_NO_TASK;
-    connection->ccs -= COCO_TRANSMIT_READY;
-    GNUNET_assert (connection->write_task == GNUNET_SCHEDULER_NO_TASK);
-    GNUNET_assert (connection->nth.notify_ready != NULL);
+    connection->nth.timeout_task = NULL;
+    GNUNET_assert (connection->write_task == NULL);
     connection->write_task =
         GNUNET_SCHEDULER_add_write_net (GNUNET_TIME_absolute_get_remaining
                                         (connection->nth.transmit_timeout), connection->sock,
     connection->write_task =
         GNUNET_SCHEDULER_add_write_net (GNUNET_TIME_absolute_get_remaining
                                         (connection->nth.transmit_timeout), connection->sock,
@@ -612,7 +681,7 @@ connect_probe_continuation (void *cls,
   int error;
   socklen_t len;
 
   int error;
   socklen_t len;
 
-  GNUNET_assert (ap->sock != NULL);
+  GNUNET_assert (NULL != ap->sock);
   GNUNET_CONTAINER_DLL_remove (connection->ap_head, connection->ap_tail, ap);
   len = sizeof (error);
   errno = 0;
   GNUNET_CONTAINER_DLL_remove (connection->ap_head, connection->ap_tail, ap);
   len = sizeof (error);
   errno = 0;
@@ -620,17 +689,19 @@ connect_probe_continuation (void *cls,
   if ((0 == (tc->reason & GNUNET_SCHEDULER_REASON_WRITE_READY)) ||
       (GNUNET_OK !=
        GNUNET_NETWORK_socket_getsockopt (ap->sock, SOL_SOCKET, SO_ERROR, &error,
   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))
+                                         &len)) || (0 != error))
   {
     GNUNET_break (GNUNET_OK == GNUNET_NETWORK_socket_close (ap->sock));
     GNUNET_free (ap);
   {
     GNUNET_break (GNUNET_OK == GNUNET_NETWORK_socket_close (ap->sock));
     GNUNET_free (ap);
-    if ((NULL == connection->ap_head) && (connection->dns_active == GNUNET_NO))
+    if ((NULL == connection->ap_head) &&
+        (GNUNET_NO == connection->dns_active) &&
+        (NULL == connection->proxy_handshake))
       connect_fail_continuation (connection);
     return;
   }
       connect_fail_continuation (connection);
     return;
   }
-  GNUNET_assert (connection->sock == NULL);
+  GNUNET_assert (NULL == connection->sock);
   connection->sock = ap->sock;
   connection->sock = ap->sock;
-  GNUNET_assert (connection->addr == NULL);
+  GNUNET_assert (NULL == connection->addr);
   connection->addr = GNUNET_malloc (ap->addrlen);
   memcpy (connection->addr, ap->addr, ap->addrlen);
   connection->addrlen = ap->addrlen;
   connection->addr = GNUNET_malloc (ap->addrlen);
   memcpy (connection->addr, ap->addr, ap->addrlen);
   connection->addrlen = ap->addrlen;
@@ -651,32 +722,38 @@ connect_probe_continuation (void *cls,
  * Try to establish a connection given the specified address.
  * This function is called by the resolver once we have a DNS reply.
  *
  * Try to establish a connection given the specified address.
  * 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
  */
 static void
-try_connect_using_address (void *cls, const struct sockaddr *addr,
+try_connect_using_address (void *cls,
+                           const struct sockaddr *addr,
                            socklen_t addrlen)
 {
   struct GNUNET_CONNECTION_Handle *connection = cls;
   struct AddressProbe *ap;
   struct GNUNET_TIME_Relative delay;
 
                            socklen_t addrlen)
 {
   struct GNUNET_CONNECTION_Handle *connection = cls;
   struct AddressProbe *ap;
   struct GNUNET_TIME_Relative delay;
 
-  if (addr == NULL)
+  if (NULL == addr)
   {
     connection->dns_active = NULL;
   {
     connection->dns_active = NULL;
-    if ((NULL == connection->ap_head) && (NULL == connection->sock))
+    if ((NULL == connection->ap_head) &&
+        (NULL == connection->sock) &&
+        (NULL == connection->proxy_handshake))
       connect_fail_continuation (connection);
     return;
   }
       connect_fail_continuation (connection);
     return;
   }
-  if (connection->sock != NULL)
+  if (NULL != connection->sock)
     return;                     /* already connected */
     return;                     /* already connected */
-  GNUNET_assert (connection->addr == NULL);
+  GNUNET_assert (NULL == connection->addr);
   /* try to connect */
   LOG (GNUNET_ERROR_TYPE_DEBUG,
   /* try to connect */
   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);
+       "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 = GNUNET_malloc (sizeof (struct AddressProbe) + addrlen);
   ap->addr = (const struct sockaddr *) &ap[1];
   memcpy (&ap[1], addr, addrlen);
@@ -697,35 +774,32 @@ try_connect_using_address (void *cls, const struct sockaddr *addr,
     return;                     /* not supported by us */
   }
   ap->sock = GNUNET_NETWORK_socket_create (ap->addr->sa_family, SOCK_STREAM, 0);
     return;                     /* not supported by us */
   }
   ap->sock = GNUNET_NETWORK_socket_create (ap->addr->sa_family, SOCK_STREAM, 0);
-  if (ap->sock == NULL)
+  if (NULL == ap->sock)
   {
     GNUNET_free (ap);
     return;                     /* not supported by OS */
   }
   {
     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);
+  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)) &&
   if ((GNUNET_OK !=
        GNUNET_NETWORK_socket_connect (ap->sock, ap->addr, ap->addrlen)) &&
-      (errno != EINPROGRESS))
+      (EINPROGRESS != errno))
   {
     /* maybe refused / unsupported address, try next */
     LOG_STRERROR (GNUNET_ERROR_TYPE_INFO, "connect");
   {
     /* maybe refused / unsupported address, try next */
     LOG_STRERROR (GNUNET_ERROR_TYPE_INFO, "connect");
-#if 0
-    LOG (GNUNET_ERROR_TYPE_INFO, _("Failed to connect to `%s' (%p)\n"),
-         GNUNET_a2s (ap->addr, ap->addrlen), connection);
-#endif
     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;
     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;
-  if (connection->nth.notify_ready != NULL)
+  if (NULL != connection->nth.notify_ready)
     delay =
         GNUNET_TIME_relative_min (delay,
     delay =
         GNUNET_TIME_relative_min (delay,
-                                  GNUNET_TIME_absolute_get_remaining (connection->
-                                                                      nth.transmit_timeout));
-  if (connection->receiver != NULL)
+                                  GNUNET_TIME_absolute_get_remaining (connection->nth.transmit_timeout));
+  if (NULL != connection->receiver)
     delay =
         GNUNET_TIME_relative_min (delay,
                                   GNUNET_TIME_absolute_get_remaining
     delay =
         GNUNET_TIME_relative_min (delay,
                                   GNUNET_TIME_absolute_get_remaining
@@ -747,14 +821,14 @@ try_connect_using_address (void *cls, const struct sockaddr *addr,
  * @return the connection handle
  */
 struct GNUNET_CONNECTION_Handle *
  * @return the connection handle
  */
 struct GNUNET_CONNECTION_Handle *
-GNUNET_CONNECTION_create_from_connect (const struct GNUNET_CONFIGURATION_Handle
-                                       *cfg, const char *hostname,
+GNUNET_CONNECTION_create_from_connect (const struct GNUNET_CONFIGURATION_Handle *cfg,
+                                       const char *hostname,
                                        uint16_t port)
 {
   struct GNUNET_CONNECTION_Handle *connection;
 
   GNUNET_assert (0 < strlen (hostname));        /* sanity check */
                                        uint16_t port)
 {
   struct GNUNET_CONNECTION_Handle *connection;
 
   GNUNET_assert (0 < strlen (hostname));        /* sanity check */
-  connection = GNUNET_malloc (sizeof (struct GNUNET_CONNECTION_Handle));
+  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->cfg = cfg;
   connection->write_buffer_size = GNUNET_SERVER_MIN_BUFFER_SIZE;
   connection->write_buffer = GNUNET_malloc (connection->write_buffer_size);
@@ -778,38 +852,38 @@ GNUNET_CONNECTION_create_from_connect (const struct GNUNET_CONFIGURATION_Handle
  * @return the connection handle, NULL on systems without UNIX support
  */
 struct GNUNET_CONNECTION_Handle *
  * @return the connection handle, NULL on systems without UNIX support
  */
 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
   struct GNUNET_CONNECTION_Handle *connection;
   struct sockaddr_un *un;
 {
 #ifdef AF_UNIX
   struct GNUNET_CONNECTION_Handle *connection;
   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);
-  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 (struct sockaddr_un);
-#if HAVE_SOCKADDR_IN_SIN_LEN
-  un->sun_len = (u_char) slen;
+  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
-#if LINUX
-  un->sun_path[0] = '\0';
+#if HAVE_SOCKADDR_IN_SIN_LEN
+  un->sun_len = (u_char) sizeof (struct sockaddr_un);
 #endif
 #endif
-  connection = GNUNET_malloc (sizeof (struct GNUNET_CONNECTION_Handle));
+  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->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 = slen;
+  connection->addrlen = sizeof (struct sockaddr_un);
   connection->sock = GNUNET_NETWORK_socket_create (AF_UNIX, SOCK_STREAM, 0);
   if (NULL == connection->sock)
   {
   connection->sock = GNUNET_NETWORK_socket_create (AF_UNIX, SOCK_STREAM, 0);
   if (NULL == connection->sock)
   {
@@ -818,8 +892,9 @@ GNUNET_CONNECTION_create_from_connect_to_unixpath (const struct
     GNUNET_free (connection);
     return NULL;
   }
     GNUNET_free (connection);
     return NULL;
   }
-  if (GNUNET_OK !=
-      GNUNET_NETWORK_socket_connect (connection->sock, connection->addr, connection->addrlen))
+  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));
   {
     /* Just return; we expect everything to work eventually so don't fail HARD */
     GNUNET_break (GNUNET_OK == GNUNET_NETWORK_socket_close (connection->sock));
@@ -839,33 +914,29 @@ GNUNET_CONNECTION_create_from_connect_to_unixpath (const struct
  * 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 af_family address family to use
+ * @param s socket to connect
  * @param serv_addr server address
  * @param serv_addr server address
- * @param addrlen length of server address
+ * @param addrlen length of @a serv_addr
  * @return the connection handle
  */
 struct GNUNET_CONNECTION_Handle *
  * @return the connection handle
  */
 struct GNUNET_CONNECTION_Handle *
-GNUNET_CONNECTION_create_from_sockaddr (int af_family,
-                                        const struct sockaddr *serv_addr,
-                                        socklen_t addrlen)
+GNUNET_CONNECTION_connect_socket (struct GNUNET_NETWORK_Handle *s,
+                                  const struct sockaddr *serv_addr,
+                                  socklen_t addrlen)
 {
 {
-  struct GNUNET_NETWORK_Handle *s;
   struct GNUNET_CONNECTION_Handle *connection;
 
   struct GNUNET_CONNECTION_Handle *connection;
 
-
-  s = GNUNET_NETWORK_socket_create (af_family, SOCK_STREAM, 0);
-  if (s == NULL)
-  {
-    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))
+  if ( (GNUNET_OK !=
+        GNUNET_NETWORK_socket_connect (s, serv_addr, addrlen)) &&
+       (EINPROGRESS != errno) )
   {
     /* maybe refused / unsupported address, try next */
   {
     /* maybe refused / unsupported address, try next */
-    LOG_STRERROR (GNUNET_ERROR_TYPE_INFO, "connect");
-    LOG (GNUNET_ERROR_TYPE_INFO, _("Attempt to connect to `%s' failed\n"),
-         GNUNET_a2s (serv_addr, addrlen));
+    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;
   }
     GNUNET_break (GNUNET_OK == GNUNET_NETWORK_socket_close (s));
     return NULL;
   }
@@ -873,26 +944,61 @@ GNUNET_CONNECTION_create_from_sockaddr (int af_family,
   connection->addr = GNUNET_malloc (addrlen);
   memcpy (connection->addr, serv_addr, addrlen);
   connection->addrlen = addrlen;
   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);
+  LOG (GNUNET_ERROR_TYPE_INFO,
+       "Trying to connect to `%s' (%p)\n",
+       GNUNET_a2s (serv_addr, addrlen),
+       connection);
   return 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 addrlen length of @a serv_addr
+ * @return the connection handle
+ */
+struct GNUNET_CONNECTION_Handle *
+GNUNET_CONNECTION_create_from_sockaddr (int af_family,
+                                        const struct sockaddr *serv_addr,
+                                        socklen_t addrlen)
+{
+  struct GNUNET_NETWORK_Handle *s;
+
+  s = GNUNET_NETWORK_socket_create (af_family, SOCK_STREAM, 0);
+  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 connection is valid (no fatal errors have happened so far).
  * Note that a connection that is still trying to connect is considered
  * valid.
  *
 /**
  * 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.
  *
- * @param sock connection 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;
 }
 
 
 }
 
 
@@ -908,25 +1014,31 @@ GNUNET_CONNECTION_destroy (struct GNUNET_CONNECTION_Handle *connection)
 {
   struct AddressProbe *pos;
 
 {
   struct AddressProbe *pos;
 
-  LOG (GNUNET_ERROR_TYPE_DEBUG, "Shutting down connection (%p)\n", connection);
+  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);
   GNUNET_assert (NULL == connection->nth.notify_ready);
   GNUNET_assert (NULL == connection->receiver);
-  GNUNET_assert (GNUNET_SCHEDULER_NO_TASK == connection->read_task);
-  if (connection->write_task != GNUNET_SCHEDULER_NO_TASK)
+  if (NULL != connection->write_task)
   {
     GNUNET_SCHEDULER_cancel (connection->write_task);
   {
     GNUNET_SCHEDULER_cancel (connection->write_task);
-    connection->write_task = GNUNET_SCHEDULER_NO_TASK;
+    connection->write_task = NULL;
     connection->write_buffer_off = 0;
   }
     connection->write_buffer_off = 0;
   }
-  if (connection->read_task != GNUNET_SCHEDULER_NO_TASK)
+  if (NULL != connection->read_task)
   {
     GNUNET_SCHEDULER_cancel (connection->read_task);
   {
     GNUNET_SCHEDULER_cancel (connection->read_task);
-    connection->read_task = GNUNET_SCHEDULER_NO_TASK;
+    connection->read_task = NULL;
   }
   }
-  if (connection->nth.timeout_task != GNUNET_SCHEDULER_NO_TASK)
+  if (NULL != connection->nth.timeout_task)
   {
     GNUNET_SCHEDULER_cancel (connection->nth.timeout_task);
   {
     GNUNET_SCHEDULER_cancel (connection->nth.timeout_task);
-    connection->nth.timeout_task = GNUNET_SCHEDULER_NO_TASK;
+    connection->nth.timeout_task = NULL;
   }
   connection->nth.notify_ready = NULL;
   if (NULL != connection->dns_active)
   }
   connection->nth.notify_ready = NULL;
   if (NULL != connection->dns_active)
@@ -934,6 +1046,12 @@ GNUNET_CONNECTION_destroy (struct GNUNET_CONNECTION_Handle *connection)
     GNUNET_RESOLVER_request_cancel (connection->dns_active);
     connection->dns_active = NULL;
   }
     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));
   while (NULL != (pos = connection->ap_head))
   {
     GNUNET_break (GNUNET_OK == GNUNET_NETWORK_socket_close (pos->sock));
@@ -942,20 +1060,28 @@ GNUNET_CONNECTION_destroy (struct GNUNET_CONNECTION_Handle *connection)
     GNUNET_free (pos);
   }
   if ( (NULL != connection->sock) &&
     GNUNET_free (pos);
   }
   if ( (NULL != connection->sock) &&
-       (connection->persist != GNUNET_YES) )
+       (GNUNET_YES != connection->persist) )
   {
   {
-    if ((GNUNET_YES != GNUNET_NETWORK_socket_shutdown (connection->sock, SHUT_RDWR)) && 
-       (errno != ENOTCONN) && 
-       (errno != ECONNRESET) )
-      LOG_STRERROR (GNUNET_ERROR_TYPE_WARNING, "shutdown");    
+    if ((GNUNET_OK !=
+         GNUNET_NETWORK_socket_shutdown (connection->sock,
+                                         SHUT_RDWR)) &&
+       (ENOTCONN != errno) &&
+       (ECONNRESET != errno) )
+      LOG_STRERROR (GNUNET_ERROR_TYPE_WARNING,
+                    "shutdown");
   }
   }
-  if (connection->sock != NULL)
+  if (NULL != connection->sock)
   {
   {
-    if (connection->persist != GNUNET_YES)
-      GNUNET_break (GNUNET_OK == GNUNET_NETWORK_socket_close (connection->sock));
+    if (GNUNET_YES != connection->persist)
+    {
+      GNUNET_break (GNUNET_OK ==
+                    GNUNET_NETWORK_socket_close (connection->sock));
+    }
     else
     else
-      GNUNET_free (connection->sock); /* at least no memory leak (we deliberately
-                                      * leak the socket in this special case) ... */
+    {
+      GNUNET_NETWORK_socket_free_memory_only_ (connection->sock); /* at least no memory leak (we deliberately
+                                                                  * leak the socket in this special case) ... */
+    }
   }
   GNUNET_free_non_null (connection->addr);
   GNUNET_free_non_null (connection->hostname);
   }
   GNUNET_free_non_null (connection->addr);
   GNUNET_free_non_null (connection->hostname);
@@ -964,202 +1090,123 @@ GNUNET_CONNECTION_destroy (struct GNUNET_CONNECTION_Handle *connection)
 }
 
 
 }
 
 
-/**
- * Tell the receiver callback that a timeout was reached.
- */
-static void
-signal_timeout (struct GNUNET_CONNECTION_Handle *connection)
-{
-  GNUNET_CONNECTION_Receiver receiver;
-
-  LOG (GNUNET_ERROR_TYPE_DEBUG, "Network signals time out to receiver (%p)!\n",
-       connection);
-  GNUNET_assert (NULL != (receiver = connection->receiver));
-  connection->receiver = NULL;
-  receiver (connection->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 *connection, int errcode)
-{
-  GNUNET_CONNECTION_Receiver receiver;
-
-  GNUNET_assert (NULL != (receiver = connection->receiver));
-  connection->receiver = NULL;
-  receiver (connection->receiver_cls, NULL, 0, connection->addr, connection->addrlen, errcode);
-}
-
-
 /**
  * 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 *connection = cls;
 {
   struct GNUNET_CONNECTION_Handle *connection = cls;
-  struct GNUNET_TIME_Absolute now;
   char buffer[connection->max];
   ssize_t ret;
   GNUNET_CONNECTION_Receiver receiver;
 
   char buffer[connection->max];
   ssize_t ret;
   GNUNET_CONNECTION_Receiver receiver;
 
-  connection->read_task = GNUNET_SCHEDULER_NO_TASK;
-  if ((GNUNET_YES == connection->ignore_shutdown) &&
-      (0 != (tc->reason & GNUNET_SCHEDULER_REASON_SHUTDOWN)))
+  connection->read_task = NULL;
+  if (0 != (tc->reason & GNUNET_SCHEDULER_REASON_SHUTDOWN))
   {
     /* ignore shutdown request, go again immediately */
   {
     /* ignore shutdown request, go again immediately */
-    LOG (GNUNET_ERROR_TYPE_DEBUG,
-         "Ignoring shutdown signal per configuration\n");
     connection->read_task =
         GNUNET_SCHEDULER_add_read_net (GNUNET_TIME_absolute_get_remaining
                                        (connection->receive_timeout), connection->sock,
                                        &receive_ready, connection);
     return;
   }
     connection->read_task =
         GNUNET_SCHEDULER_add_read_net (GNUNET_TIME_absolute_get_remaining
                                        (connection->receive_timeout), connection->sock,
                                        &receive_ready, connection);
     return;
   }
-  now = GNUNET_TIME_absolute_get ();
-  if ((now.abs_value > connection->receive_timeout.abs_value) ||
-      (0 != (tc->reason & GNUNET_SCHEDULER_REASON_TIMEOUT)) ||
-      (0 != (tc->reason & GNUNET_SCHEDULER_REASON_SHUTDOWN)))
+  if (0 != (tc->reason & GNUNET_SCHEDULER_REASON_TIMEOUT))
   {
   {
-    if (0 == (tc->reason & GNUNET_SCHEDULER_REASON_SHUTDOWN))
-      LOG (GNUNET_ERROR_TYPE_DEBUG,
-           "Receive from `%s' encounters error: time out by %llums... (%p)\n",
-           GNUNET_a2s (connection->addr, connection->addrlen),
-           GNUNET_TIME_absolute_get_duration (connection->receive_timeout).rel_value,
-           connection);
-    signal_timeout (connection);
+    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;
   }
     return;
   }
-  if (connection->sock == NULL)
+  if (NULL == connection->sock)
   {
     /* connect failed for good */
   {
     /* connect failed for good */
-    LOG (GNUNET_ERROR_TYPE_DEBUG,
-         "Receive encounters error, connection closed... (%p)\n", connection);
-    signal_error (connection, ECONNREFUSED);
+    signal_receive_error (connection, ECONNREFUSED);
     return;
   }
   GNUNET_assert (GNUNET_NETWORK_fdset_isset (tc->read_ready, connection->sock));
 RETRY:
     return;
   }
   GNUNET_assert (GNUNET_NETWORK_fdset_isset (tc->read_ready, connection->sock));
 RETRY:
-  ret = GNUNET_NETWORK_socket_recv (connection->sock, buffer, connection->max);
-  if (ret == -1)
+  ret = GNUNET_NETWORK_socket_recv (connection->sock,
+                                    buffer,
+                                    connection->max);
+  if (-1 == ret)
   {
   {
-    if (errno == EINTR)
+    if (EINTR == errno)
       goto RETRY;
       goto RETRY;
-    LOG (GNUNET_ERROR_TYPE_DEBUG, "Error receiving: %s\n", STRERROR (errno));
-    signal_error (connection, errno);
+    signal_receive_error (connection, errno);
     return;
   }
   LOG (GNUNET_ERROR_TYPE_DEBUG,
     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);
+       "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;
   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 *connection = cls;
-  struct GNUNET_TIME_Absolute now;
-
-  connection->read_task = GNUNET_SCHEDULER_NO_TASK;
-  if (connection->sock == NULL)
-  {
-    /* not connected and no longer trying */
-    LOG (GNUNET_ERROR_TYPE_DEBUG,
-         "Receive encounters error, connection closed (%p)...\n", connection);
-    signal_error (connection, ECONNREFUSED);
-    return;
-  }
-  now = GNUNET_TIME_absolute_get ();
-  if ((now.abs_value > connection->receive_timeout.abs_value) ||
-      (0 != (tc->reason & GNUNET_SCHEDULER_REASON_SHUTDOWN)))
-  {
-    LOG (GNUNET_ERROR_TYPE_DEBUG,
-         "Receive encounters error: time out (%p)...\n", connection);
-    signal_timeout (connection);
-    return;
-  }
-  GNUNET_assert (connection->sock != NULL);
-  /* connect succeeded, wait for data! */
-  connection->read_task =
-      GNUNET_SCHEDULER_add_read_net (GNUNET_TIME_absolute_get_remaining
-                                     (connection->receive_timeout), connection->sock,
-                                     &receive_ready, connection);
+  receiver (connection->receiver_cls,
+            buffer,
+            ret,
+            connection->addr,
+            connection->addrlen,
+            0);
 }
 
 
 /**
  * Receive data from the given connection.  Note that this function will
 }
 
 
 /**
  * Receive data from the given connection.  Note that this function will
- * call "receiver" asynchronously using the scheduler.  It will
+ * call @a receiver asynchronously using the scheduler.  It will
  * "immediately" return.  Note that there MUST only be one active
  * receive call per connection at any given point in time (so do not
  * call receive again until the receiver callback has been invoked).
  *
  * @param connection connection handle
  * @param max maximum number of bytes to read
  * "immediately" return.  Note that there MUST only be one active
  * receive call per connection at any given point in time (so do not
  * call receive again until the receiver callback has been invoked).
  *
  * @param connection connection handle
  * @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 *connection, size_t max,
+GNUNET_CONNECTION_receive (struct GNUNET_CONNECTION_Handle *connection,
+                           size_t max,
                            struct GNUNET_TIME_Relative timeout,
                            GNUNET_CONNECTION_Receiver receiver,
                            void *receiver_cls)
 {
                            struct GNUNET_TIME_Relative timeout,
                            GNUNET_CONNECTION_Receiver receiver,
                            void *receiver_cls)
 {
-  struct GNUNET_SCHEDULER_TaskContext tc;
-
-  GNUNET_assert ((connection->read_task == GNUNET_SCHEDULER_NO_TASK) &&
-                 (0 == (connection->ccs & COCO_RECEIVE_AGAIN)) &&
-                 (connection->receiver == NULL));
+  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;
   connection->receiver = receiver;
   connection->receiver_cls = receiver_cls;
   connection->receive_timeout = GNUNET_TIME_relative_to_absolute (timeout);
   connection->max = max;
-  if (connection->sock != NULL)
+  if (NULL != connection->sock)
   {
   {
-    memset (&tc, 0, sizeof (tc));
-    tc.reason = GNUNET_SCHEDULER_REASON_PREREQ_DONE;
-    receive_again (connection, &tc);
+    connection->read_task =
+      GNUNET_SCHEDULER_add_read_net (GNUNET_TIME_absolute_get_remaining
+                                     (connection->receive_timeout),
+                                     connection->sock,
+                                     &receive_ready,
+                                     connection);
     return;
   }
     return;
   }
-  if ((connection->dns_active == NULL) && (connection->ap_head == NULL))
+  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;
   }
     receiver (receiver_cls, NULL, 0, NULL, 0, ETIMEDOUT);
     return;
   }
-  connection->ccs += COCO_RECEIVE_AGAIN;
-}
-
-
-/**
- * Configure this connection to ignore shutdown signals.
- *
- * @param connection connection handle
- * @param do_ignore GNUNET_YES to ignore, GNUNET_NO to restore default
- */
-void
-GNUNET_CONNECTION_ignore_shutdown (struct GNUNET_CONNECTION_Handle *connection,
-                                   int do_ignore)
-{
-  connection->ignore_shutdown = do_ignore;
 }
 
 
 }
 
 
@@ -1174,15 +1221,11 @@ GNUNET_CONNECTION_ignore_shutdown (struct GNUNET_CONNECTION_Handle *connection,
 void *
 GNUNET_CONNECTION_receive_cancel (struct GNUNET_CONNECTION_Handle *connection)
 {
 void *
 GNUNET_CONNECTION_receive_cancel (struct GNUNET_CONNECTION_Handle *connection)
 {
-  if (connection->read_task != GNUNET_SCHEDULER_NO_TASK)
+  if (NULL != connection->read_task)
   {
   {
-    GNUNET_assert (connection == GNUNET_SCHEDULER_cancel (connection->read_task));
-    connection->read_task = GNUNET_SCHEDULER_NO_TASK;
-  }
-  else
-  {
-    GNUNET_assert (0 != (connection->ccs & COCO_RECEIVE_AGAIN));
-    connection->ccs -= COCO_RECEIVE_AGAIN;
+    GNUNET_assert (connection ==
+                   GNUNET_SCHEDULER_cancel (connection->read_task));
+    connection->read_task = NULL;
   }
   connection->receiver = NULL;
   return connection->receiver_cls;
   }
   connection->receiver = NULL;
   return connection->receiver_cls;
@@ -1194,7 +1237,7 @@ GNUNET_CONNECTION_receive_cancel (struct GNUNET_CONNECTION_Handle *connection)
  * have enough space available first)!
  *
  * @param connection connection for which we should do this processing
  * have enough space available first)!
  *
  * @param connection connection for which we should do this processing
- * @return GNUNET_YES if we were able to call notify
+ * @return #GNUNET_YES if we were able to call notify
  */
 static int
 process_notify (struct GNUNET_CONNECTION_Handle *connection)
  */
 static int
 process_notify (struct GNUNET_CONNECTION_Handle *connection)
@@ -1204,19 +1247,30 @@ process_notify (struct GNUNET_CONNECTION_Handle *connection)
   size_t size;
   GNUNET_CONNECTION_TransmitReadyNotify notify;
 
   size_t size;
   GNUNET_CONNECTION_TransmitReadyNotify notify;
 
-  GNUNET_assert (connection->write_task == GNUNET_SCHEDULER_NO_TASK);
+  LOG (GNUNET_ERROR_TYPE_DEBUG,
+       "process_notify is running\n");
+  GNUNET_assert (NULL == connection->write_task);
   if (NULL == (notify = connection->nth.notify_ready))
   if (NULL == (notify = connection->nth.notify_ready))
+  {
+    LOG (GNUNET_ERROR_TYPE_DEBUG,
+         "No one to notify\n");
     return GNUNET_NO;
     return GNUNET_NO;
+  }
   used = connection->write_buffer_off - connection->write_buffer_pos;
   avail = connection->write_buffer_size - used;
   size = connection->nth.notify_size;
   if (size > avail)
   used = connection->write_buffer_off - connection->write_buffer_pos;
   avail = connection->write_buffer_size - used;
   size = connection->nth.notify_size;
   if (size > avail)
+  {
+    LOG (GNUNET_ERROR_TYPE_DEBUG,
+         "Not enough buffer\n");
     return GNUNET_NO;
     return GNUNET_NO;
+  }
   connection->nth.notify_ready = NULL;
   if (connection->write_buffer_size - connection->write_buffer_off < size)
   {
     /* need to compact */
   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],
+    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;
              used);
     connection->write_buffer_off -= connection->write_buffer_pos;
     connection->write_buffer_pos = 0;
@@ -1227,7 +1281,8 @@ process_notify (struct GNUNET_CONNECTION_Handle *connection)
       notify (connection->nth.notify_ready_cls, avail,
               &connection->write_buffer[connection->write_buffer_off]);
   GNUNET_assert (size <= avail);
       notify (connection->nth.notify_ready_cls, avail,
               &connection->write_buffer[connection->write_buffer_off]);
   GNUNET_assert (size <= avail);
-  connection->write_buffer_off += size;
+  if (0 != size)
+    connection->write_buffer_off += size;
   return GNUNET_YES;
 }
 
   return GNUNET_YES;
 }
 
@@ -1240,23 +1295,26 @@ process_notify (struct GNUNET_CONNECTION_Handle *connection)
  *
  * 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 *connection = cls;
   GNUNET_CONNECTION_TransmitReadyNotify notify;
 
 {
   struct GNUNET_CONNECTION_Handle *connection = cls;
   GNUNET_CONNECTION_TransmitReadyNotify notify;
 
-  connection->nth.timeout_task = GNUNET_SCHEDULER_NO_TASK;
+  connection->nth.timeout_task = NULL;
   LOG (GNUNET_ERROR_TYPE_DEBUG,
        "Transmit to `%s:%u/%s' fails, time out reached (%p).\n",
        connection->hostname,
   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);
-  GNUNET_assert (0 != (connection->ccs & COCO_TRANSMIT_READY));
-  connection->ccs -= COCO_TRANSMIT_READY;     /* remove request */
+       connection->port,
+       GNUNET_a2s (connection->addr,
+                   connection->addrlen),
+       connection);
   notify = connection->nth.notify_ready;
   notify = connection->nth.notify_ready;
+  GNUNET_assert (NULL != notify);
   connection->nth.notify_ready = NULL;
   notify (connection->nth.notify_ready_cls, 0, NULL);
 }
   connection->nth.notify_ready = NULL;
   notify (connection->nth.notify_ready_cls, 0, NULL);
 }
@@ -1268,51 +1326,23 @@ transmit_timeout (void *cls, const struct GNUNET_SCHEDULER_TaskContext *tc)
  *
  * 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 *connection = cls;
   GNUNET_CONNECTION_TransmitReadyNotify notify;
 
   LOG (GNUNET_ERROR_TYPE_DEBUG,
        "Transmission request of size %u fails (%s/%u), connection failed (%p).\n",
 {
   struct GNUNET_CONNECTION_Handle *connection = cls;
   GNUNET_CONNECTION_TransmitReadyNotify notify;
 
   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 = GNUNET_SCHEDULER_NO_TASK;
-  notify = connection->nth.notify_ready;
-  connection->nth.notify_ready = NULL;
-  notify (connection->nth.notify_ready_cls, 0, NULL);
-}
-
-
-/**
- * FIXME
- *
- * @param connection FIXME
- */
-static void
-transmit_error (struct GNUNET_CONNECTION_Handle *connection)
-{
-  GNUNET_CONNECTION_TransmitReadyNotify notify;
-
-  if (NULL != connection->sock)
-  {
-    GNUNET_NETWORK_socket_shutdown (connection->sock, SHUT_RDWR);
-    GNUNET_break (GNUNET_OK == GNUNET_NETWORK_socket_close (connection->sock));
-    connection->sock = NULL;
-    GNUNET_assert (GNUNET_SCHEDULER_NO_TASK == connection->write_task);
-  }
-  if (connection->read_task != GNUNET_SCHEDULER_NO_TASK)
-  {
-    GNUNET_SCHEDULER_cancel (connection->read_task);
-    connection->read_task = GNUNET_SCHEDULER_NO_TASK;
-    signal_timeout (connection);
-    return;
-  }
-  if (connection->nth.notify_ready == NULL)
-    return;                     /* nobody to tell about it */
+       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);
   notify = connection->nth.notify_ready;
   connection->nth.notify_ready = NULL;
   notify (connection->nth.notify_ready_cls, 0, NULL);
@@ -1320,28 +1350,29 @@ transmit_error (struct GNUNET_CONNECTION_Handle *connection)
 
 
 /**
 
 
 /**
- * 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 *connection = cls;
   GNUNET_CONNECTION_TransmitReadyNotify notify;
   ssize_t ret;
   size_t have;
 
 {
   struct GNUNET_CONNECTION_Handle *connection = cls;
   GNUNET_CONNECTION_TransmitReadyNotify notify;
   ssize_t ret;
   size_t have;
 
-  LOG (GNUNET_ERROR_TYPE_DEBUG, "transmit_ready running (%p).\n", connection);
-  GNUNET_assert (connection->write_task != GNUNET_SCHEDULER_NO_TASK);
-  connection->write_task = GNUNET_SCHEDULER_NO_TASK;
-  GNUNET_assert (connection->nth.timeout_task == GNUNET_SCHEDULER_NO_TASK);
+  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 (0 != (tc->reason & GNUNET_SCHEDULER_REASON_SHUTDOWN))
   {
-    if ((connection->ignore_shutdown == GNUNET_YES) && (NULL != connection->sock))
+    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",
       goto SCHEDULE_WRITE;      /* ignore shutdown, go again immediately */
     LOG (GNUNET_ERROR_TYPE_DEBUG,
          "Transmit to `%s' fails, shutdown happened (%p).\n",
@@ -1358,7 +1389,9 @@ transmit_ready (void *cls, const struct GNUNET_SCHEDULER_TaskContext *tc)
   {
     LOG (GNUNET_ERROR_TYPE_DEBUG,
          "Transmit to `%s' fails, time out reached (%p).\n",
   {
     LOG (GNUNET_ERROR_TYPE_DEBUG,
          "Transmit to `%s' fails, time out reached (%p).\n",
-         GNUNET_a2s (connection->addr, connection->addrlen), connection);
+         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;
     GNUNET_assert (NULL != notify);
     connection->nth.notify_ready = NULL;
@@ -1366,25 +1399,22 @@ transmit_ready (void *cls, const struct GNUNET_SCHEDULER_TaskContext *tc)
     return;
   }
   GNUNET_assert (NULL != connection->sock);
     return;
   }
   GNUNET_assert (NULL != connection->sock);
-  if (tc->write_ready == NULL)
+  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.  */
+    /* 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))
   {
     goto SCHEDULE_WRITE;
   }
   if (!GNUNET_NETWORK_fdset_isset (tc->write_ready, connection->sock))
   {
-    LOG (GNUNET_ERROR_TYPE_INFO,
-         _
-         ("Could not satisfy pending transmission request, socket closed or connect failed (%p).\n"),
-         connection);
-    GNUNET_assert (GNUNET_SCHEDULER_NO_TASK == connection->write_task);
-    transmit_error (connection);
-    return;                     /* connect failed for good, we're finished */
+    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);
   }
   GNUNET_assert (connection->write_buffer_off >= connection->write_buffer_pos);
-  if ((connection->nth.notify_ready != NULL) &&
+  if ((NULL != connection->nth.notify_ready) &&
       (connection->write_buffer_size < connection->nth.notify_size))
   {
     connection->write_buffer =
       (connection->write_buffer_size < connection->nth.notify_size))
   {
     connection->write_buffer =
@@ -1393,7 +1423,7 @@ transmit_ready (void *cls, const struct GNUNET_SCHEDULER_TaskContext *tc)
   }
   process_notify (connection);
   have = connection->write_buffer_off - connection->write_buffer_pos;
   }
   process_notify (connection);
   have = connection->write_buffer_off - connection->write_buffer_pos;
-  if (have == 0)
+  if (0 == have)
   {
     /* no data ready for writing, terminate write loop */
     return;
   {
     /* no data ready for writing, terminate write loop */
     return;
@@ -1406,21 +1436,20 @@ RETRY:
       GNUNET_NETWORK_socket_send (connection->sock,
                                  &connection->write_buffer[connection->write_buffer_pos],
                                  have);
       GNUNET_NETWORK_socket_send (connection->sock,
                                  &connection->write_buffer[connection->write_buffer_pos],
                                  have);
-  if (ret == -1)
+  if (-1 == ret)
   {
   {
-    if (errno == EINTR)
+    if (EINTR == errno)
       goto RETRY;
       goto RETRY;
-    LOG_STRERROR (GNUNET_ERROR_TYPE_DEBUG, "send");
-    if (GNUNET_SCHEDULER_NO_TASK != connection->write_task)
+    if (NULL != connection->write_task)
     {
       GNUNET_SCHEDULER_cancel (connection->write_task);
     {
       GNUNET_SCHEDULER_cancel (connection->write_task);
-      connection->write_task = GNUNET_SCHEDULER_NO_TASK;
+      connection->write_task = NULL;
     }
     }
-    transmit_error (connection);
+    signal_transmit_error (connection, errno);
     return;
   }
   LOG (GNUNET_ERROR_TYPE_DEBUG,
     return;
   }
   LOG (GNUNET_ERROR_TYPE_DEBUG,
-       "transmit_ready transmitted %u/%u bytes to `%s' (%p)\n",
+       "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)
        (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)
@@ -1429,15 +1458,15 @@ RETRY:
     connection->write_buffer_pos = 0;
     connection->write_buffer_off = 0;
   }
     connection->write_buffer_pos = 0;
     connection->write_buffer_off = 0;
   }
-  if ((connection->write_buffer_off == 0) && (NULL == connection->nth.notify_ready))
+  if ((0 == connection->write_buffer_off) && (NULL == connection->nth.notify_ready))
     return;                     /* all data sent! */
   /* not done writing, schedule more */
 SCHEDULE_WRITE:
   LOG (GNUNET_ERROR_TYPE_DEBUG,
        "Re-scheduling transmit_ready (more to do) (%p).\n", connection);
   have = connection->write_buffer_off - connection->write_buffer_pos;
     return;                     /* all data sent! */
   /* not done writing, schedule more */
 SCHEDULE_WRITE:
   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 ((connection->nth.notify_ready != NULL) || (have > 0));
-  if (connection->write_task == GNUNET_SCHEDULER_NO_TASK)
+  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 :
     connection->write_task =
         GNUNET_SCHEDULER_add_write_net ((connection->nth.notify_ready ==
                                          NULL) ? GNUNET_TIME_UNIT_FOREVER_REL :
@@ -1449,15 +1478,15 @@ SCHEDULE_WRITE:
 
 /**
  * Ask the connection to call us once the specified number of bytes
 
 /**
  * Ask the connection 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.
+ * are free in the transmission buffer.  Will never call the @a notify
+ * callback in this task, but always first go into the scheduler.
  *
  * @param connection connection
  * @param size number of bytes to send
  * @param timeout after how long should we give up (and call
  *
  * @param connection connection
  * @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)
  */
  * @return non-NULL if the notify callback was queued,
  *         NULL if we are already going to notify someone else (busy)
  */
@@ -1468,12 +1497,12 @@ GNUNET_CONNECTION_notify_transmit_ready (struct GNUNET_CONNECTION_Handle *connec
                                          GNUNET_CONNECTION_TransmitReadyNotify
                                          notify, void *notify_cls)
 {
                                          GNUNET_CONNECTION_TransmitReadyNotify
                                          notify, void *notify_cls)
 {
-  if (connection->nth.notify_ready != NULL)
+  if (NULL != connection->nth.notify_ready)
   {
     GNUNET_assert (0);
     return NULL;
   }
   {
     GNUNET_assert (0);
     return NULL;
   }
-  GNUNET_assert (notify != NULL);
+  GNUNET_assert (NULL != notify);
   GNUNET_assert (size < GNUNET_SERVER_MAX_MESSAGE_SIZE);
   GNUNET_assert (connection->write_buffer_off <= connection->write_buffer_size);
   GNUNET_assert (connection->write_buffer_pos <= connection->write_buffer_size);
   GNUNET_assert (size < GNUNET_SERVER_MAX_MESSAGE_SIZE);
   GNUNET_assert (connection->write_buffer_off <= connection->write_buffer_size);
   GNUNET_assert (connection->write_buffer_pos <= connection->write_buffer_size);
@@ -1483,33 +1512,39 @@ GNUNET_CONNECTION_notify_transmit_ready (struct GNUNET_CONNECTION_Handle *connec
   connection->nth.connection = connection;
   connection->nth.notify_size = size;
   connection->nth.transmit_timeout = GNUNET_TIME_relative_to_absolute (timeout);
   connection->nth.connection = connection;
   connection->nth.notify_size = size;
   connection->nth.transmit_timeout = GNUNET_TIME_relative_to_absolute (timeout);
-  GNUNET_assert (GNUNET_SCHEDULER_NO_TASK == connection->nth.timeout_task);
-  if ((connection->sock == NULL) && (connection->ap_head == NULL) &&
-      (connection->dns_active == NULL))
+  GNUNET_assert (NULL == connection->nth.timeout_task);
+  if ((NULL == connection->sock) &&
+      (NULL == connection->ap_head) &&
+      (NULL == connection->dns_active) &&
+      (NULL == connection->proxy_handshake))
   {
   {
-    if (connection->write_task != GNUNET_SCHEDULER_NO_TASK)
+    if (NULL != connection->write_task)
       GNUNET_SCHEDULER_cancel (connection->write_task);
       GNUNET_SCHEDULER_cancel (connection->write_task);
-    connection->write_task = GNUNET_SCHEDULER_add_now (&connect_error, connection);
+    connection->write_task = GNUNET_SCHEDULER_add_now (&connect_error,
+                                                       connection);
     return &connection->nth;
   }
     return &connection->nth;
   }
-  if (GNUNET_SCHEDULER_NO_TASK != connection->write_task)
-    return &connection->nth;
-  if (connection->sock != NULL)
+  if (NULL != connection->write_task)
+    return &connection->nth; /* previous transmission still in progress */
+  if (NULL != connection->sock)
   {
   {
-    LOG (GNUNET_ERROR_TYPE_DEBUG, "Scheduling transmit_ready (%p).\n", connection);
+    /* 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);
     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;
   }
   }
-  else
-  {
-    LOG (GNUNET_ERROR_TYPE_DEBUG,
-         "CCS-Scheduling transmit_ready, adding timeout task (%p).\n", connection);
-    connection->ccs |= COCO_TRANSMIT_READY;
-    connection->nth.timeout_task =
-        GNUNET_SCHEDULER_add_delayed (timeout, &transmit_timeout, connection);
-  }
+  /* 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;
 }
 
   return &connection->nth;
 }
 
@@ -1520,28 +1555,57 @@ GNUNET_CONNECTION_notify_transmit_ready (struct GNUNET_CONNECTION_Handle *connec
  * @param th notification to cancel
  */
 void
  * @param th notification to cancel
  */
 void
-GNUNET_CONNECTION_notify_transmit_ready_cancel (struct
-                                                GNUNET_CONNECTION_TransmitHandle
-                                                *th)
+GNUNET_CONNECTION_notify_transmit_ready_cancel (struct GNUNET_CONNECTION_TransmitHandle *th)
 {
 {
-  GNUNET_assert (th->notify_ready != NULL);
-  if (0 != (th->connection->ccs & COCO_TRANSMIT_READY))
+  GNUNET_assert (NULL != th->notify_ready);
+  th->notify_ready = NULL;
+  if (NULL != th->timeout_task)
   {
   {
-    LOG (GNUNET_ERROR_TYPE_DEBUG,
-         "notify_transmit_ready_cancel cancels timeout_task (%p)\n", th);
     GNUNET_SCHEDULER_cancel (th->timeout_task);
     GNUNET_SCHEDULER_cancel (th->timeout_task);
-    th->timeout_task = GNUNET_SCHEDULER_NO_TASK;
-    th->connection->ccs -= COCO_TRANSMIT_READY;
+    th->timeout_task = NULL;
   }
   }
-  else
+  if (NULL != th->connection->write_task)
   {
   {
-    if (th->connection->write_task != GNUNET_SCHEDULER_NO_TASK)
-    {
-      GNUNET_SCHEDULER_cancel (th->connection->write_task);
-      th->connection->write_task = GNUNET_SCHEDULER_NO_TASK;
-    }
+    GNUNET_SCHEDULER_cancel (th->connection->write_task);
+    th->connection->write_task = NULL;
   }
   }
-  th->notify_ready = 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 */