LRN: Fix automake deps to allow -j* builds again
[oweals/gnunet.git] / src / util / connection.c
index 7828dac531264dba3bbba6e26806f562654d29ee..f26130a0689d4ffdbb161f299952e6da4fc6eb5c 100644 (file)
@@ -301,6 +301,23 @@ void GNUNET_CONNECTION_persist_(struct GNUNET_CONNECTION_Handle *sock)
   sock->persist = GNUNET_YES;
 }
 
+
+/**
+ * Disable the "CORK" feature for communication with the given socket,
+ * 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 sock the connection to make flushing and blocking
+ * @return GNUNET_OK on success
+ */
+int GNUNET_CONNECTION_disable_corking (struct GNUNET_CONNECTION_Handle *sock)
+{
+  return GNUNET_NETWORK_socket_disable_corking (sock->sock);
+}
+
 /**
  * Create a socket handle by boxing an existing OS socket.  The OS
  * socket should henceforth be no longer used directly.
@@ -376,6 +393,9 @@ GNUNET_CONNECTION_create_from_accept (GNUNET_CONNECTION_AccessCheck access,
       v4 = GNUNET_malloc (sizeof (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)],
@@ -642,8 +662,7 @@ connect_fail_continuation (struct GNUNET_CONNECTION_Handle *h)
                   h);
 #endif
       h->ccs -= COCO_RECEIVE_AGAIN;
-      h->read_task = GNUNET_SCHEDULER_add_after (GNUNET_SCHEDULER_NO_TASK,
-                                                 &receive_again, h);
+      h->read_task = GNUNET_SCHEDULER_add_now (&receive_again, h);
     }
   if (0 != (h->ccs & COCO_TRANSMIT_READY))
     {
@@ -656,9 +675,9 @@ connect_fail_continuation (struct GNUNET_CONNECTION_Handle *h)
       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_after (GNUNET_SCHEDULER_NO_TASK,
-                                                  &transmit_ready, h);
+      h->write_task = GNUNET_SCHEDULER_add_now (&transmit_ready, h);
     }
   if (0 != (h->ccs & COCO_DESTROY_CONTINUATION))
     {
@@ -698,8 +717,7 @@ connect_success_continuation (struct GNUNET_CONNECTION_Handle *h)
                   h);
 #endif
       h->ccs -= COCO_RECEIVE_AGAIN;
-      h->read_task = GNUNET_SCHEDULER_add_after (GNUNET_SCHEDULER_NO_TASK,
-                                                 &receive_again, h);
+      h->read_task = GNUNET_SCHEDULER_add_now (&receive_again, h);
     }
   if (0 != (h->ccs & COCO_TRANSMIT_READY))
     {
@@ -713,6 +731,7 @@ connect_success_continuation (struct GNUNET_CONNECTION_Handle *h)
       h->nth.timeout_task = GNUNET_SCHEDULER_NO_TASK;
       h->ccs -= COCO_TRANSMIT_READY;
       GNUNET_assert (h->write_task == GNUNET_SCHEDULER_NO_TASK);
+      GNUNET_assert (h->nth.notify_ready != NULL);
       h->write_task =
         GNUNET_SCHEDULER_add_write_net (GNUNET_TIME_absolute_get_remaining
                                         (h->nth.transmit_timeout), h->sock,
@@ -901,8 +920,7 @@ GNUNET_CONNECTION_create_from_connect (const struct
   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,
+  ret->dns_active = GNUNET_RESOLVER_ip_get (ret->hostname,
                                             AF_UNSPEC,
                                             GNUNET_CONNECTION_CONNECT_RETRY_TIMEOUT,
                                             &try_connect_using_address, ret);
@@ -932,17 +950,19 @@ GNUNET_CONNECTION_create_from_connect_to_unixpath (const struct
   GNUNET_assert (0 < strlen (unixpath));        /* sanity check */
   un = GNUNET_malloc (sizeof (struct sockaddr_un));
   un->sun_family = AF_UNIX;
-  slen = strlen (unixpath) + 1;
+  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 (sa_family_t);
+  slen = sizeof (struct sockaddr_un);
+#if HAVE_SOCKADDR_IN_SIN_LEN
+  un->sun_len = (u_char) slen;
+#endif
 #if LINUX
   un->sun_path[0] = '\0';
-  slen = sizeof (struct sockaddr_un);
 #endif
   ret = GNUNET_malloc (sizeof (struct GNUNET_CONNECTION_Handle));
   ret->cfg = cfg;
@@ -966,10 +986,8 @@ GNUNET_CONNECTION_create_from_connect_to_unixpath (const struct
     {
       /* 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;
+      ret->sock = NULL;
+      return ret;
     }
   connect_success_continuation (ret);
   return ret;
@@ -1010,6 +1028,9 @@ GNUNET_CONNECTION_create_from_sockaddr (int af_family,
     {
       /* maybe refused / unsupported address, try next */
       GNUNET_log_strerror (GNUNET_ERROR_TYPE_INFO, "connect");
+      GNUNET_log (GNUNET_ERROR_TYPE_INFO, 
+                 _("Attempt to connect to `%s' failed\n"),
+                 GNUNET_a2s (serv_addr, addrlen));
       GNUNET_break (GNUNET_OK == GNUNET_NETWORK_socket_close (s));
       return NULL;
     }
@@ -1068,6 +1089,7 @@ GNUNET_CONNECTION_destroy (struct GNUNET_CONNECTION_Handle *sock,
          sock->write_task = GNUNET_SCHEDULER_NO_TASK;
          sock->write_buffer_off = 0;
        }
+      sock->nth.notify_ready = NULL;
     }
   if ((sock->write_buffer_off == 0) && (sock->dns_active != NULL))
     {
@@ -1420,16 +1442,13 @@ connect_error (void *cls,
   struct GNUNET_CONNECTION_Handle *sock = cls;
   GNUNET_CONNECTION_TransmitReadyNotify notify;
 
+#if DEBUG_CONNECTION
   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;
@@ -1503,8 +1522,11 @@ transmit_ready (void *cls, const struct GNUNET_SCHEDULER_TaskContext *tc)
                   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);
+      if (NULL != notify)
+       {
+         sock->nth.notify_ready = NULL;
+         notify (sock->nth.notify_ready_cls, 0, NULL);
+       }
       return;
     }
   if (0 != (tc->reason & GNUNET_SCHEDULER_REASON_TIMEOUT))
@@ -1515,6 +1537,7 @@ transmit_ready (void *cls, const struct GNUNET_SCHEDULER_TaskContext *tc)
                   GNUNET_a2s (sock->addr, sock->addrlen), sock);
 #endif
       notify = sock->nth.notify_ready;
+      GNUNET_assert (NULL != notify);
       sock->nth.notify_ready = NULL;
       notify (sock->nth.notify_ready_cls, 0, NULL);
       return;
@@ -1600,11 +1623,15 @@ SCHEDULE_WRITE:
   GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
               "Re-scheduling transmit_ready (more to do) (%p).\n", sock);
 #endif
+  have = sock->write_buffer_off - sock->write_buffer_pos;
+  GNUNET_assert ( (sock->nth.notify_ready != NULL) || (have > 0) );
   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);
+      GNUNET_SCHEDULER_add_write_net ((sock->nth.notify_ready == NULL) 
+                                     ? GNUNET_TIME_UNIT_FOREVER_REL 
+                                     : GNUNET_TIME_absolute_get_remaining (sock->nth.transmit_timeout),
+                                     sock->sock, 
+                                     &transmit_ready, sock);
 }
 
 
@@ -1630,7 +1657,10 @@ GNUNET_CONNECTION_notify_transmit_ready (struct GNUNET_CONNECTION_Handle
                                          notify, void *notify_cls)
 {
   if (sock->nth.notify_ready != NULL)
-    return NULL;
+    {
+      GNUNET_assert (0);
+      return NULL;
+    }
   GNUNET_assert (notify != NULL);
   GNUNET_assert (size < GNUNET_SERVER_MAX_MESSAGE_SIZE);
   GNUNET_assert (sock->write_buffer_off <= sock->write_buffer_size);
@@ -1682,8 +1712,9 @@ GNUNET_CONNECTION_notify_transmit_ready (struct GNUNET_CONNECTION_Handle
 
 
 /**
- * Cancel the specified transmission-ready
- * notification.
+ * Cancel the specified transmission-ready notification.
+ *
+ * @param th notification to cancel
  */
 void
 GNUNET_CONNECTION_notify_transmit_ready_cancel (struct