asserts
[oweals/gnunet.git] / src / util / connection.c
index 22a75691bead5905575b796a9edb748d8c723f8b..d2d4432c61c5d7f962d1e1078a7cea15ec1a8a1e 100644 (file)
@@ -244,6 +244,11 @@ struct GNUNET_CONNECTION_Handle
    */
   GNUNET_SCHEDULER_TaskIdentifier write_task;
 
+  /**
+   * Destroy task (if already scheduled).
+   */
+  GNUNET_SCHEDULER_TaskIdentifier destroy_task;
+
   /**
    * Handle to a pending DNS lookup request.
    */
@@ -279,8 +284,27 @@ struct GNUNET_CONNECTION_Handle
    */
   uint16_t port;
 
+  /**
+   * When shutdown, do not ever actually close the socket, but
+   * free resources.  Only should ever be set if using program
+   * termination as a signal (because only then will the leaked
+   * socket be freed!)
+   */
+  int persist;
+
 };
 
+/**
+ * Set the persist option on this connection handle.  Indicates
+ * that the underlying socket or fd should never really be closed.
+ * Used for indicating process death.
+ *
+ * @param sock the connection to set persistent
+ */
+void GNUNET_CONNECTION_persist_(struct GNUNET_CONNECTION_Handle *sock)
+{
+  sock->persist = GNUNET_YES;
+}
 
 /**
  * Create a socket handle by boxing an existing OS socket.  The OS
@@ -453,7 +477,8 @@ destroy_continuation (void *cls,
   struct GNUNET_CONNECTION_Handle *sock = cls;
   GNUNET_CONNECTION_TransmitReadyNotify notify;
   struct AddressProbe *pos;
-
+  
+  sock->destroy_task = GNUNET_SCHEDULER_NO_TASK;
   GNUNET_assert (sock->dns_active == NULL);
   if (0 != (sock->ccs & COCO_TRANSMIT_READY))
     {
@@ -470,9 +495,11 @@ destroy_continuation (void *cls,
       GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
                   "Destroy waits for write_task to be done (%p)\n", sock);
 #endif
-      GNUNET_SCHEDULER_add_after (sock->sched,
-                                  sock->write_task,
-                                  &destroy_continuation, sock);
+      GNUNET_assert (GNUNET_SCHEDULER_NO_TASK == sock->destroy_task);
+      sock->destroy_task 
+       = GNUNET_SCHEDULER_add_after (sock->sched,
+                                     sock->write_task,
+                                     &destroy_continuation, sock);
       return;
     }
   if (0 != (sock->ccs & COCO_RECEIVE_AGAIN))
@@ -486,13 +513,16 @@ destroy_continuation (void *cls,
       GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
                   "Shutting down socket (%p)\n", sock);
 #endif
-      GNUNET_NETWORK_socket_shutdown (sock->sock, SHUT_RDWR);
+      if (sock->persist != GNUNET_YES)
+        GNUNET_NETWORK_socket_shutdown (sock->sock, SHUT_RDWR);
     }
   if (sock->read_task != GNUNET_SCHEDULER_NO_TASK)
     {
-      GNUNET_SCHEDULER_add_after (sock->sched,
-                                  sock->read_task,
-                                  &destroy_continuation, sock);
+      GNUNET_assert (GNUNET_SCHEDULER_NO_TASK == sock->destroy_task);
+      sock->destroy_task 
+       = GNUNET_SCHEDULER_add_after (sock->sched,
+                                     sock->read_task,
+                                     &destroy_continuation, sock);
       return;
     }
 #if DEBUG_CONNECTION
@@ -518,10 +548,18 @@ destroy_continuation (void *cls,
       sock->nth.notify_ready = NULL;
       notify (sock->nth.notify_ready_cls, 0, NULL);
     }
-  if (sock->sock != NULL)
-    GNUNET_break (GNUNET_OK == GNUNET_NETWORK_socket_close (sock->sock));
+
+  if (sock->sock != NULL) 
+    {
+      if (sock->persist != GNUNET_YES)
+       GNUNET_break (GNUNET_OK == GNUNET_NETWORK_socket_close (sock->sock));
+      else
+       GNUNET_free (sock->sock); /* at least no memory leak (we deliberately
+                                    leak the socket in this special case) ... */
+    }
   GNUNET_free_non_null (sock->addr);
   GNUNET_free_non_null (sock->hostname);
+  GNUNET_assert (GNUNET_SCHEDULER_NO_TASK == sock->destroy_task);
 #if DEBUG_CONNECTION
   GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
               "Freeing memory of connection %p.\n", sock);
@@ -598,9 +636,11 @@ connect_fail_continuation (struct GNUNET_CONNECTION_Handle *h)
                   h);
 #endif
       h->ccs -= COCO_DESTROY_CONTINUATION;
-      GNUNET_SCHEDULER_add_continuation (h->sched,
-                                         &destroy_continuation,
-                                         h, GNUNET_SCHEDULER_REASON_TIMEOUT);
+      GNUNET_assert (GNUNET_SCHEDULER_NO_TASK == h->destroy_task);
+      h->destroy_task
+       = GNUNET_SCHEDULER_add_now (h->sched,
+                                   &destroy_continuation,
+                                   h);
     }
 }
 
@@ -656,10 +696,11 @@ connect_success_continuation (struct GNUNET_CONNECTION_Handle *h)
                   h);
 #endif
       h->ccs -= COCO_DESTROY_CONTINUATION;
-      GNUNET_SCHEDULER_add_continuation (h->sched,
-                                         &destroy_continuation,
-                                         h,
-                                         GNUNET_SCHEDULER_REASON_PREREQ_DONE);
+      GNUNET_assert (GNUNET_SCHEDULER_NO_TASK == h->destroy_task);
+      h->destroy_task
+       = GNUNET_SCHEDULER_add_now (h->sched,
+                                   &destroy_continuation,
+                                   h);
     }
 }
 
@@ -947,8 +988,10 @@ GNUNET_CONNECTION_destroy (struct GNUNET_CONNECTION_Handle *sock,
       sock->dns_active = NULL;
     }
   GNUNET_assert (sock->sched != NULL);
-  GNUNET_SCHEDULER_add_now (sock->sched,
-                           &destroy_continuation, sock);
+  GNUNET_assert (GNUNET_SCHEDULER_NO_TASK == sock->destroy_task);
+  sock->destroy_task 
+    = GNUNET_SCHEDULER_add_now (sock->sched,
+                               &destroy_continuation, sock);
 }