gnunet-svn
[Top][All Lists]
Advanced

[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]

[GNUnet-SVN] r11215 - gnunet/src/util


From: gnunet
Subject: [GNUnet-SVN] r11215 - gnunet/src/util
Date: Thu, 6 May 2010 11:59:08 +0200

Author: nevans
Date: 2010-05-06 11:59:08 +0200 (Thu, 06 May 2010)
New Revision: 11215

Modified:
   gnunet/src/util/client.c
   gnunet/src/util/connection.c
   gnunet/src/util/server.c
   gnunet/src/util/service.c
   gnunet/src/util/test_server.c
   gnunet/src/util/test_service.c
Log:
arm related changes to util things, enabling leaky sockets and shutdown 
messages from services

Modified: gnunet/src/util/client.c
===================================================================
--- gnunet/src/util/client.c    2010-05-06 09:55:53 UTC (rev 11214)
+++ gnunet/src/util/client.c    2010-05-06 09:59:08 UTC (rev 11215)
@@ -136,7 +136,47 @@
   void *rn_cls;
 };
 
+/**
+ * Context for handling the shutdown of a service.
+ */
+struct ShutdownContext
+{
+  /**
+   * Scheduler to be used to call continuation
+   */
+  struct GNUNET_SCHEDULER_Handle *sched;
+  /**
+   * Connection to the service that is being shutdown.
+   */
+  struct GNUNET_CLIENT_Connection *sock;
 
+  /**
+   * Time allowed for shutdown to happen.
+   */
+  struct GNUNET_TIME_Absolute timeout;
+
+  /**
+   * Task set up to cancel the shutdown request on timeout.
+   */
+  GNUNET_SCHEDULER_TaskIdentifier cancel_task;
+
+  /**
+   * Task to call once shutdown complete
+   */
+  GNUNET_CLIENT_ShutdownTask cont;
+
+  /**
+   * Closure for shutdown continuation
+   */
+  void *cont_cls;
+
+  /**
+   * We received a confirmation that the service will shut down.
+   */
+  int confirmed;
+
+};
+
 /**
  * Struct to refer to a GNUnet TCP connection.
  * This is more than just a socket because if the server
@@ -541,6 +581,85 @@
 
 
 /**
+ * Handler receiving response to service shutdown requests.
+ * First call with NULL: service misbehaving, or something.
+ * First call with GNUNET_MESSAGE_TYPE_SHUTDOWN_ACK:
+ *   - service will shutdown
+ * First call with GNUNET_MESSAGE_TYPE_SHUTDOWN_REFUSE:
+ *   - service will not be stopped!
+ *
+ * Second call with NULL:
+ *   - service has now really shut down.
+ *
+ * @param cls closure
+ * @param msg NULL, indicating socket closure.
+ */
+static void
+service_shutdown_handler (void *cls, const struct GNUNET_MessageHeader *msg)
+{
+  struct ShutdownContext *shutdown_ctx = cls;
+
+  if ((msg == NULL) && (shutdown_ctx->confirmed != GNUNET_YES)) /* Means the 
other side closed the connection and never confirmed a shutdown */
+    {
+      GNUNET_log(GNUNET_ERROR_TYPE_DEBUG, "Service handle shutdown before 
ACK!\n");
+      if (shutdown_ctx->cont != NULL)
+        shutdown_ctx->cont(shutdown_ctx->cont_cls, GNUNET_SYSERR);
+
+      GNUNET_SCHEDULER_cancel(shutdown_ctx->sched, shutdown_ctx->cancel_task);
+      GNUNET_CLIENT_disconnect (shutdown_ctx->sock, GNUNET_NO);
+      GNUNET_free(shutdown_ctx);
+    }
+  else if ((msg == NULL) && (shutdown_ctx->confirmed == GNUNET_YES))
+    {
+      GNUNET_log(GNUNET_ERROR_TYPE_DEBUG, "Service shutdown complete.\n");
+      if (shutdown_ctx->cont != NULL)
+        shutdown_ctx->cont(shutdown_ctx->cont_cls, GNUNET_NO);
+
+      GNUNET_SCHEDULER_cancel(shutdown_ctx->sched, shutdown_ctx->cancel_task);
+      GNUNET_CLIENT_disconnect (shutdown_ctx->sock, GNUNET_NO);
+      GNUNET_free(shutdown_ctx);
+    }
+  else
+    {
+      GNUNET_assert(ntohs(msg->size) == sizeof(struct GNUNET_MessageHeader));
+
+      switch (ntohs(msg->type))
+      {
+      case GNUNET_MESSAGE_TYPE_SHUTDOWN_ACK:
+        GNUNET_log(GNUNET_ERROR_TYPE_DEBUG, "Received confirmation for service 
shutdown.\n");
+        shutdown_ctx->confirmed = GNUNET_YES;
+        GNUNET_CLIENT_receive (shutdown_ctx->sock, &service_shutdown_handler, 
shutdown_ctx, GNUNET_TIME_UNIT_FOREVER_REL);
+        break;
+      case GNUNET_MESSAGE_TYPE_SHUTDOWN_REFUSE:
+      default: /* Fall through */
+        GNUNET_log(GNUNET_ERROR_TYPE_WARNING, "Service shutdown refused!\n");
+        if (shutdown_ctx->cont != NULL)
+          shutdown_ctx->cont(shutdown_ctx->cont_cls, GNUNET_YES);
+
+        GNUNET_SCHEDULER_cancel(shutdown_ctx->sched, 
shutdown_ctx->cancel_task);
+        GNUNET_CLIENT_disconnect (shutdown_ctx->sock, GNUNET_NO);
+        GNUNET_free(shutdown_ctx);
+        break;
+      }
+    }
+}
+
+/**
+ * Shutting down took too long, cancel receive and return error.
+ *
+ * @param cls closure
+ * @param tc context information (why was this task triggered now)
+ */
+void service_shutdown_cancel (void *cls,
+                              const struct GNUNET_SCHEDULER_TaskContext * tc)
+{
+  struct ShutdownContext *shutdown_ctx = cls;
+  fprintf(stderr, "service_shutdown_cancel called!\n");
+  shutdown_ctx->cont(shutdown_ctx->cont_cls, GNUNET_SYSERR);
+  GNUNET_CLIENT_disconnect (shutdown_ctx->sock, GNUNET_NO);
+  GNUNET_free(shutdown_ctx);
+}
+/**
  * If possible, write a shutdown message to the target
  * buffer and destroy the client connection.
  *
@@ -553,15 +672,21 @@
 write_shutdown (void *cls, size_t size, void *buf)
 {
   struct GNUNET_MessageHeader *msg;
-  struct GNUNET_CLIENT_Connection *sock = cls;
+  struct ShutdownContext *shutdown_ctx = cls;
 
-  GNUNET_CLIENT_disconnect (sock, GNUNET_YES);
   if (size < sizeof (struct GNUNET_MessageHeader))
     {
       GNUNET_log (GNUNET_ERROR_TYPE_INFO,
                   _("Failed to transmit shutdown request to client.\n"));
+
+      shutdown_ctx->cont(shutdown_ctx->cont_cls, GNUNET_SYSERR);
+      GNUNET_CLIENT_disconnect (shutdown_ctx->sock, GNUNET_NO);
+      GNUNET_free(shutdown_ctx);
       return 0;                 /* client disconnected */
     }
+
+  GNUNET_CLIENT_receive (shutdown_ctx->sock, &service_shutdown_handler, 
shutdown_ctx, GNUNET_TIME_UNIT_FOREVER_REL);
+  shutdown_ctx->cancel_task = GNUNET_SCHEDULER_add_delayed 
(shutdown_ctx->sched, 
GNUNET_TIME_absolute_get_remaining(shutdown_ctx->timeout), 
&service_shutdown_cancel, shutdown_ctx);
   msg = (struct GNUNET_MessageHeader *) buf;
   msg->type = htons (GNUNET_MESSAGE_TYPE_SHUTDOWN);
   msg->size = htons (sizeof (struct GNUNET_MessageHeader));
@@ -576,16 +701,33 @@
  * be used by the caller after this call
  * (calling this function frees "sock" after a while).
  *
+ * @param sched the scheduler to use for calling shutdown continuation
  * @param sock the socket connected to the service
+ * @param timeout how long to wait before giving up on transmission
+ * @param cont continuation to call once the service is really down
+ * @param cont_cls closure for continuation
+ *
  */
 void
-GNUNET_CLIENT_service_shutdown (struct GNUNET_CLIENT_Connection *sock)
+GNUNET_CLIENT_service_shutdown (struct GNUNET_SCHEDULER_Handle *sched,
+                                struct GNUNET_CLIENT_Connection *sock,
+                                struct GNUNET_TIME_Relative timeout,
+                                GNUNET_CLIENT_ShutdownTask cont,
+                                void *cont_cls)
 {
+  struct ShutdownContext *shutdown_ctx;
+  shutdown_ctx = GNUNET_malloc(sizeof(struct ShutdownContext));
+  shutdown_ctx->sched = sched;
+  shutdown_ctx->cont = cont;
+  shutdown_ctx->cont_cls = cont_cls;
+  shutdown_ctx->sock = sock;
+  shutdown_ctx->timeout = GNUNET_TIME_relative_to_absolute(timeout);
+
   GNUNET_CONNECTION_notify_transmit_ready (sock->sock,
                                            sizeof (struct
                                                    GNUNET_MessageHeader),
-                                           GNUNET_TIME_UNIT_FOREVER_REL,
-                                           &write_shutdown, sock);
+                                           timeout,
+                                           &write_shutdown, shutdown_ctx);
 }
 
 

Modified: gnunet/src/util/connection.c
===================================================================
--- gnunet/src/util/connection.c        2010-05-06 09:55:53 UTC (rev 11214)
+++ gnunet/src/util/connection.c        2010-05-06 09:59:08 UTC (rev 11215)
@@ -279,8 +279,27 @@
    */
   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
@@ -486,7 +505,8 @@
       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)
     {
@@ -518,8 +538,10 @@
       sock->nth.notify_ready = NULL;
       notify (sock->nth.notify_ready_cls, 0, NULL);
     }
-  if (sock->sock != NULL)
+
+  if ((sock->sock != NULL) && (sock->persist != GNUNET_YES))
     GNUNET_break (GNUNET_OK == GNUNET_NETWORK_socket_close (sock->sock));
+
   GNUNET_free_non_null (sock->addr);
   GNUNET_free_non_null (sock->hostname);
 #if DEBUG_CONNECTION

Modified: gnunet/src/util/server.c
===================================================================
--- gnunet/src/util/server.c    2010-05-06 09:55:53 UTC (rev 11214)
+++ gnunet/src/util/server.c    2010-05-06 09:59:08 UTC (rev 11215)
@@ -269,6 +269,13 @@
    * Are we currently trying to receive?
    */
   int receive_pending;
+
+  /**
+   * Persist the file handle for this client no matter what happens,
+   * force the OS to close once the process actually dies.  Should only
+   * be used in special cases!
+   */
+  int persist;
 };
 
 
@@ -933,11 +940,16 @@
  * Destroy this socket (free resources).
  *
  * @param cls the socket
+ * @param persist set the socket to be persisted
  */
 static void
-sock_destroy (void *cls)
+sock_destroy (void *cls, int persist)
 {
-  GNUNET_CONNECTION_destroy (cls, GNUNET_NO);
+  struct GNUNET_CONNECTION_Handle *sock = cls;
+  if (persist == GNUNET_YES)
+    GNUNET_CONNECTION_persist_ (sock);
+
+  GNUNET_CONNECTION_destroy (sock, GNUNET_NO);
 }
 
 
@@ -1168,6 +1180,7 @@
       client->receive_cancel (client->client_closure);
       client->receive_pending = GNUNET_NO;
     }
+
   rc = client->reference_count;  
   if (client->server != NULL)
     {
@@ -1200,7 +1213,7 @@
     return;
   if (client->in_process_client_buffer == GNUNET_YES)
     return;
-  client->destroy (client->client_closure);
+  client->destroy (client->client_closure, client->persist);
   GNUNET_free (client);  
 }
 
@@ -1232,6 +1245,17 @@
                                         timeout, callback, callback_cls);
 }
 
+/**
+ * Set the persistent flag on this client, used to setup client connection
+ * to only be killed when the service it's connected to is actually dead.
+ *
+ * @param client the client to set the persistent flag on
+ */
+void
+GNUNET_SERVER_client_persist_ (struct GNUNET_SERVER_Client *client)
+{
+  client->persist = GNUNET_YES;
+}
 
 /**
  * Resume receiving from this client, we are done processing the

Modified: gnunet/src/util/service.c
===================================================================
--- gnunet/src/util/service.c   2010-05-06 09:55:53 UTC (rev 11214)
+++ gnunet/src/util/service.c   2010-05-06 09:59:08 UTC (rev 11215)
@@ -570,6 +570,45 @@
 }
 
 
+static size_t
+transmit_shutdown_deny (void *cls, size_t size, void *buf)
+{
+  struct GNUNET_SERVER_Client *client = cls;
+  struct GNUNET_MessageHeader *msg;
+
+  if (size < sizeof (struct GNUNET_MessageHeader))
+    {
+      return 0;                 /* client disconnected */
+      GNUNET_SERVER_receive_done (client, GNUNET_SYSERR);
+    }
+  msg = (struct GNUNET_MessageHeader *) buf;
+  msg->type = htons (GNUNET_MESSAGE_TYPE_SHUTDOWN_REFUSE);
+  msg->size = htons (sizeof (struct GNUNET_MessageHeader));
+  GNUNET_SERVER_receive_done (client, GNUNET_OK);
+  GNUNET_SERVER_client_drop(client);
+  return sizeof (struct GNUNET_MessageHeader);
+}
+
+static size_t
+transmit_shutdown_ack (void *cls, size_t size, void *buf)
+{
+  struct GNUNET_SERVER_Client *client = cls;
+  struct GNUNET_MessageHeader *msg;
+
+  if (size < sizeof (struct GNUNET_MessageHeader))
+    {
+      return 0;                 /* client disconnected */
+      GNUNET_SERVER_receive_done (client, GNUNET_SYSERR);
+    }
+
+  msg = (struct GNUNET_MessageHeader *) buf;
+  msg->type = htons (GNUNET_MESSAGE_TYPE_SHUTDOWN_ACK);
+  msg->size = htons (sizeof (struct GNUNET_MessageHeader));
+  GNUNET_SERVER_receive_done (client, GNUNET_OK);
+  GNUNET_SERVER_client_drop(client);
+  return sizeof (struct GNUNET_MessageHeader);
+}
+
 /**
  * Handler for SHUTDOWN message.
  *
@@ -583,19 +622,31 @@
                  const struct GNUNET_MessageHeader *message)
 {
   struct GNUNET_SERVICE_Context *service = cls;
+
+  /* FIXME: why is this call necessary???? */
+  GNUNET_SERVER_client_keep(client);
   if (!service->allow_shutdown)
     {
       GNUNET_log (GNUNET_ERROR_TYPE_WARNING,
                   _
                   ("Received shutdown request, but configured to ignore!\n"));
-      GNUNET_SERVER_receive_done (client, GNUNET_SYSERR);
+      GNUNET_SERVER_notify_transmit_ready (client,
+                                           sizeof(struct GNUNET_MessageHeader),
+                                           GNUNET_TIME_UNIT_FOREVER_REL,
+                                           &transmit_shutdown_deny, client);
       return;
     }
   GNUNET_log (GNUNET_ERROR_TYPE_INFO,
               _("Initiating shutdown as requested by client.\n"));
+
+  GNUNET_SERVER_notify_transmit_ready (client,
+                                       sizeof(struct GNUNET_MessageHeader),
+                                       GNUNET_TIME_UNIT_FOREVER_REL,
+                                       &transmit_shutdown_ack, client);
+
   GNUNET_assert (service->sched != NULL);
+  GNUNET_SERVER_client_persist_ (client);
   GNUNET_SCHEDULER_shutdown (service->sched);
-  GNUNET_SERVER_receive_done (client, GNUNET_OK);
 }
 
 

Modified: gnunet/src/util/test_server.c
===================================================================
--- gnunet/src/util/test_server.c       2010-05-06 09:55:53 UTC (rev 11214)
+++ gnunet/src/util/test_server.c       2010-05-06 09:59:08 UTC (rev 11215)
@@ -152,7 +152,7 @@
 }
 
 
-static void my_destroy (void *cls);
+static void my_destroy (void *cls, int persist);
 
 
 struct CopyContext
@@ -217,7 +217,7 @@
 
 
 static void
-my_destroy (void *cls)
+my_destroy (void *cls, int persist)
 {
   int *ok = cls;
   GNUNET_assert (5 == *ok);

Modified: gnunet/src/util/test_service.c
===================================================================
--- gnunet/src/util/test_service.c      2010-05-06 09:55:53 UTC (rev 11214)
+++ gnunet/src/util/test_service.c      2010-05-06 09:59:08 UTC (rev 11215)
@@ -43,6 +43,16 @@
 
 static int ok = 1;
 
+void
+end_cont (void *cls,
+          int reason)
+{
+  if (sctx != NULL)
+    GNUNET_SERVICE_stop (sctx);
+  else
+    GNUNET_SCHEDULER_shutdown (sched);
+  ok = 0;
+}
 
 static void
 end_it (void *cls, const struct GNUNET_SCHEDULER_TaskContext *tc)
@@ -50,12 +60,7 @@
   struct GNUNET_CLIENT_Connection *client = cls;
 
   GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "Shutting down service\n");
-  GNUNET_CLIENT_service_shutdown (client);
-  if (sctx != NULL)
-    GNUNET_SERVICE_stop (sctx);
-  else
-    GNUNET_SCHEDULER_shutdown (sched);
-  ok = 0;
+  GNUNET_CLIENT_service_shutdown (sched, client, GNUNET_TIME_UNIT_FOREVER_REL, 
&end_cont, NULL);
 }
 
 





reply via email to

[Prev in Thread] Current Thread [Next in Thread]