- relaxed to accommodate overlay linking timeouts
[oweals/gnunet.git] / src / testbed / gnunet-service-testbed.c
index 42a15c627bcb6a1295965cc3f018608506f48dd2..2371d28257c1f7f9afced94158e0606b756e75ce 100644 (file)
@@ -496,6 +496,16 @@ struct Peer
  */
 struct OverlayConnectContext
 {
+  /**
+   * The next pointer for maintaining a DLL
+   */
+  struct OverlayConnectContext *next;
+
+  /**
+   * The prev pointer for maintaining a DLL
+   */
+  struct OverlayConnectContext *prev;
+  
   /**
    * The client which has requested for overlay connection
    */
@@ -572,6 +582,11 @@ struct OverlayConnectContext
    */
   GNUNET_SCHEDULER_TaskIdentifier timeout_task;
 
+  /**
+   * The id of the cleanup task
+   */
+  GNUNET_SCHEDULER_TaskIdentifier cleanup_task;
+
   /**
    * The id of peer A
    */
@@ -776,6 +791,16 @@ static struct MessageQueue *mq_head;
  */
 static struct MessageQueue *mq_tail;
 
+/**
+ * DLL head for OverlayConnectContext DLL - to be used to clean up during shutdown
+ */
+static struct OverlayConnectContext *occq_head;
+
+/**
+ * DLL tail for OverlayConnectContext DLL
+ */
+static struct OverlayConnectContext *occq_tail;
+
 /**
  * Array of hosts
  */
@@ -865,6 +890,7 @@ transmit_ready_notify (void *cls, size_t size, void *buf)
   size = ntohs (mq_entry->msg->size);
   memcpy (buf, mq_entry->msg, size);
   GNUNET_free (mq_entry->msg);
+  GNUNET_SERVER_client_drop (mq_entry->client);
   GNUNET_CONTAINER_DLL_remove (mq_head, mq_tail, mq_entry);
   GNUNET_free (mq_entry);
   mq_entry = mq_head;
@@ -899,6 +925,7 @@ queue_message (struct GNUNET_SERVER_Client *client,
   mq_entry = GNUNET_malloc (sizeof (struct MessageQueue));
   mq_entry->msg = msg;
   mq_entry->client = client;
+  GNUNET_SERVER_client_keep (client);
   LOG_DEBUG ("Queueing message of type %u, size %u for sending\n", type,
              ntohs (msg->size));
   GNUNET_CONTAINER_DLL_insert_tail (mq_head, mq_tail, mq_entry);
@@ -996,13 +1023,16 @@ route_list_add (struct Route *route)
 static void
 slave_list_add (struct Slave *slave)
 {
+  uint32_t orig_size;
+
+  orig_size = slave_list_size;  
   if (slave->host_id >= slave_list_size)
   {
+    while (slave->host_id >= slave_list_size)
+      slave_list_size += LIST_GROW_STEP;
     slave_list =
-        TESTBED_realloc (slave_list, sizeof (struct Slave *) * slave_list_size,
-                         sizeof (struct Slave *) * (slave_list_size +
-                                                    LIST_GROW_STEP));
-    slave_list_size += LIST_GROW_STEP;
+        TESTBED_realloc (slave_list, sizeof (struct Slave *) * orig_size,
+                         sizeof (struct Slave *) * slave_list_size);
   }
   GNUNET_assert (NULL == slave_list[slave->host_id]);
   slave_list[slave->host_id] = slave;
@@ -2318,6 +2348,11 @@ handle_peer_destroy (void *cls, struct GNUNET_SERVER_Client *client,
     GNUNET_SERVER_receive_done (client, GNUNET_OK);
     return;
   }
+  if (GNUNET_YES == peer->details.local.is_running)
+  {
+    GNUNET_TESTING_peer_stop (peer->details.local.peer);
+    peer->details.local.is_running = GNUNET_NO;
+  }
   GNUNET_TESTING_peer_destroy (peer->details.local.peer);
   GNUNET_CONFIGURATION_destroy (peer->details.local.cfg);
   peer_list_remove (peer);
@@ -2529,16 +2564,13 @@ handle_peer_get_config (void *cls, struct GNUNET_SERVER_Client *client,
 
 
 /**
- * Task for cleaing up overlay connect context structure
+ * Cleanup overlay connect context structure
  *
- * @param cls the overlay connect context
- * @param tc the task context
+ * @param occ the overlay connect context
  */
 static void
-occ_cleanup (void *cls, const struct GNUNET_SCHEDULER_TaskContext *tc)
+cleanup_occ (struct OverlayConnectContext *occ)
 {
-  struct OverlayConnectContext *occ = cls;
-
   LOG_DEBUG ("Cleaning up occ\n");
   GNUNET_free_non_null (occ->emsg);
   GNUNET_free_non_null (occ->hello);
@@ -2547,6 +2579,10 @@ occ_cleanup (void *cls, const struct GNUNET_SCHEDULER_TaskContext *tc)
     GNUNET_TESTBED_forward_operation_msg_cancel_ (occ->opc);
   if (GNUNET_SCHEDULER_NO_TASK != occ->send_hello_task)
     GNUNET_SCHEDULER_cancel (occ->send_hello_task);
+  if (GNUNET_SCHEDULER_NO_TASK != occ->cleanup_task)
+    GNUNET_SCHEDULER_cancel (occ->cleanup_task);
+  if (GNUNET_SCHEDULER_NO_TASK != occ->timeout_task)
+    GNUNET_SCHEDULER_cancel (occ->timeout_task);
   if (NULL != occ->ch)
     GNUNET_CORE_disconnect (occ->ch);
   if (NULL != occ->ghh)
@@ -2555,10 +2591,27 @@ occ_cleanup (void *cls, const struct GNUNET_SCHEDULER_TaskContext *tc)
     GNUNET_TRANSPORT_disconnect (occ->p1th);
   if (NULL != occ->p2th)
     GNUNET_TRANSPORT_disconnect (occ->p2th);
+  GNUNET_CONTAINER_DLL_remove (occq_head, occq_tail, occ);
   GNUNET_free (occ);
 }
 
 
+/**
+ * Task for cleaing up overlay connect context structure
+ *
+ * @param cls the overlay connect context
+ * @param tc the task context
+ */
+static void
+do_cleanup_occ (void *cls, const struct GNUNET_SCHEDULER_TaskContext *tc)
+{
+  struct OverlayConnectContext *occ = cls;
+  
+  occ->cleanup_task = GNUNET_SCHEDULER_NO_TASK;
+  cleanup_occ (occ);
+}
+
+
 /**
  * Task which will be run when overlay connect request has been timed out
  *
@@ -2576,7 +2629,7 @@ timeout_overlay_connect (void *cls,
        "Timeout while connecting peers %u and %u\n",
        occ->peer_id, occ->other_peer_id);
   send_operation_fail_msg (occ->client, occ->op_id, occ->emsg);
-  occ_cleanup (occ, tc);
+  cleanup_occ (occ);
 }
 
 
@@ -2644,7 +2697,8 @@ overlay_connect_notify (void *cls, const struct GNUNET_PeerIdentity *new_peer,
   msg->peer2 = htonl (occ->other_peer_id);
   msg->operation_id = GNUNET_htonll (occ->op_id);
   queue_message (occ->client, &msg->header);
-  GNUNET_SCHEDULER_add_now (&occ_cleanup, occ);
+  occ->cleanup_task = GNUNET_SCHEDULER_add_now (&do_cleanup_occ, occ);
+  //cleanup_occ (occ);
 }
 
 
@@ -2941,11 +2995,12 @@ handle_overlay_connect (void *cls, struct GNUNET_SERVER_Client *client,
                         const struct GNUNET_MessageHeader *message)
 {
   const struct GNUNET_TESTBED_OverlayConnectMessage *msg;
-  struct OverlayConnectContext *occ;
   const struct GNUNET_CORE_MessageHandler no_handlers[] = {
     {NULL, 0, 0}
   };
   struct Peer *peer;
+  struct OverlayConnectContext *occ;
+  struct GNUNET_TESTBED_Controller *peer2_controller;
   uint64_t operation_id;
   uint32_t p1;
   uint32_t p2; 
@@ -3061,13 +3116,8 @@ handle_overlay_connect (void *cls, struct GNUNET_SERVER_Client *client,
     GNUNET_SERVER_receive_done (client, GNUNET_OK);
     return;
   }
-  occ = GNUNET_malloc (sizeof (struct OverlayConnectContext));
-  GNUNET_SERVER_client_keep (client);
-  occ->client = client;
-  occ->peer_id = p1;
-  occ->other_peer_id = p2;
-  occ->peer = peer_list[p1];
-  occ->op_id = GNUNET_ntohll (msg->operation_id);  
+
+  peer2_controller = NULL;
   if ((p2 >= peer_list_size) || (NULL == peer_list[p2]))
   {   
     if ((peer2_host_id >= slave_list_size)
@@ -3076,8 +3126,7 @@ handle_overlay_connect (void *cls, struct GNUNET_SERVER_Client *client,
       struct GNUNET_TESTBED_NeedControllerConfig *reply;
 
       LOG_DEBUG ("Need controller configuration for connecting peers %u and %u\n",
-                occ->peer_id, occ->other_peer_id);
-      GNUNET_free (occ);
+                p1, p2);
       reply = GNUNET_malloc (sizeof (struct
                                      GNUNET_TESTBED_NeedControllerConfig)); 
       reply->header.size = htons (sizeof (struct
@@ -3091,12 +3140,11 @@ handle_overlay_connect (void *cls, struct GNUNET_SERVER_Client *client,
     }
     else
     {
-      occ->peer2_controller = slave_list[peer2_host_id]->controller;
-      if (NULL == occ->peer2_controller)
+      //occ->peer2_controller = slave_list[peer2_host_id]->controller;
+      peer2_controller = slave_list[peer2_host_id]->controller;
+      if (NULL == peer2_controller)
       {
         GNUNET_break (0);       /* What's going on? */
-        GNUNET_SERVER_client_drop (client);
-        GNUNET_free (occ);
         GNUNET_SERVER_receive_done (client, GNUNET_SYSERR);
         return;
       }
@@ -3104,9 +3152,18 @@ handle_overlay_connect (void *cls, struct GNUNET_SERVER_Client *client,
   }
   else
   {
-    if (GNUNET_YES == peer_list[occ->other_peer_id]->is_remote)
-      occ->peer2_controller = peer_list[occ->other_peer_id]->details.remote.slave->controller;
+    if (GNUNET_YES == peer_list[p2]->is_remote)
+      peer2_controller = peer_list[p2]->details.remote.slave->controller;
   }
+  occ = GNUNET_malloc (sizeof (struct OverlayConnectContext));
+  GNUNET_CONTAINER_DLL_insert_tail (occq_head, occq_tail, occ);
+  GNUNET_SERVER_client_keep (client);
+  occ->client = client;
+  occ->peer_id = p1;
+  occ->other_peer_id = p2;
+  occ->peer = peer_list[p1];
+  occ->op_id = GNUNET_ntohll (msg->operation_id);
+  occ->peer2_controller = peer2_controller;
   /* Get the identity of the second peer */
   if (NULL != occ->peer2_controller)
   {
@@ -3441,6 +3498,7 @@ static void
 shutdown_task (void *cls, const struct GNUNET_SCHEDULER_TaskContext *tc)
 {
   struct LCFContextQueue *lcfq;
+  struct OverlayConnectContext *occ;
   uint32_t id;
 
   shutdown_task_id = GNUNET_SCHEDULER_NO_TASK;
@@ -3464,6 +3522,8 @@ shutdown_task (void *cls, const struct GNUNET_SCHEDULER_TaskContext *tc)
     GNUNET_CONTAINER_DLL_remove (lcfq_head, lcfq_tail, lcfq);
     GNUNET_free (lcfq);
   }
+  while (NULL != (occ = occq_head))
+    cleanup_occ (occ);
   /* Clear peer list */
   for (id = 0; id < peer_list_size; id++)
     if (NULL != peer_list[id])
@@ -3597,8 +3657,9 @@ testbed_run (void *cls, struct GNUNET_SERVER_Handle *server,
   GNUNET_SERVER_disconnect_notify (server, &client_disconnect_cb, NULL);
   ss_map = GNUNET_CONTAINER_multihashmap_create (5, GNUNET_NO);
   shutdown_task_id =
-      GNUNET_SCHEDULER_add_delayed (GNUNET_TIME_UNIT_FOREVER_REL,
-                                    &shutdown_task, NULL);
+      GNUNET_SCHEDULER_add_delayed_with_priority (GNUNET_TIME_UNIT_FOREVER_REL,
+                                                  GNUNET_SCHEDULER_PRIORITY_IDLE,
+                                                  &shutdown_task, NULL);
   LOG_DEBUG ("Testbed startup complete\n");
   event_mask = 1LL << GNUNET_TESTBED_ET_OPERATION_FINISHED;
 }