-LCFContext
authorSree Harsha Totakura <totakura@in.tum.de>
Tue, 3 Jul 2012 13:14:15 +0000 (13:14 +0000)
committerSree Harsha Totakura <totakura@in.tum.de>
Tue, 3 Jul 2012 13:14:15 +0000 (13:14 +0000)
src/testbed/gnunet-service-testbed.c
src/testbed/testbed_api.c
src/testbed/testbed_api_hosts.c
src/testbed/testbed_api_hosts.h

index 63d28d97bf2bf19eae8f5ce815d6f73367ba040e..5c95a9a4f8c809919fd6a9dd1ac2bf612df1281d 100644 (file)
@@ -119,20 +119,108 @@ struct SharedService
 struct Route
 {
   /**
-   * The destination host
+   * The forwarding (next hop) host id
    */
-  const struct GNUNET_TESTBED_Host *dest;
+  uint32_t next_hop;
 
   /**
-   * The forwarding (next hop) host
+   * The controller handle if we have started the controller at the next hop
+   * host 
    */
-  const struct GNUNET_TESTBED_Host *fhost;
+  struct GNUNET_TESTBED_Controller *fcontroller;
+};
 
+
+/**
+ * States of LCFContext
+ */
+enum LCFContextState
+  {
+    /**
+     * The Context has been initialized; Nothing has been done on it
+     */
+    INIT,
+
+    /**
+     * Delegated host has been registered at the forwarding controller
+     */
+    DELEGATED_HOST_REGISTERED,
+    
+    /**
+     * The slave host has been registred at the forwarding controller
+     */
+    SLAVE_HOST_REGISTERED,
+
+    /**
+     * The context has been finished (may have error)
+     */
+    FINISHED
+
+  };
+
+
+/**
+ * Link controllers request forwarding context
+ */
+struct LCFContext
+{
   /**
-   * The controller handle if we have started the controller at the next hop
-   * host 
+   * The configuration
+   */
+  struct GNUNET_CONFIGURATION_Handle *cfg;
+
+  /**
+   * The handle of the controller this request has to be forwarded to
    */
   struct GNUNET_TESTBED_Controller *fcontroller;
+
+  /**
+   * The host registration handle while registered hosts in this context
+   */
+  struct GNUNET_TESTBED_HostRegistrationHandle *rhandle;
+
+  /**
+   * Should the delegated host be started by the slave host?
+   */
+  int is_subordinate;
+
+  /**
+   * The state of this context
+   */
+  enum LCFContextState state;
+
+  /**
+   * The delegated host
+   */
+  uint32_t delegated_host_id;
+
+  /**
+   * The slave host
+   */
+  uint32_t slave_host_id;
+
+};
+
+
+/**
+ * Structure of a queue entry in LCFContext request queue
+ */
+struct LCFContextQueue
+{
+  /**
+   * The LCFContext
+   */
+  struct LCFContext *lcf;
+
+  /**
+   * Head prt for DLL
+   */
+  struct LCFContextQueue *next;
+
+  /**
+   * Tail ptr for DLL
+   */
+  struct LCFContextQueue *prev;
 };
 
 
@@ -181,6 +269,16 @@ static struct MessageQueue *mq_head;
  */
 static struct MessageQueue *mq_tail;
 
+/**
+ * The head for the LCF queue
+ */
+static struct LCFContextQueue *lcfq_head;
+
+/**
+ * The tail for the LCF queue
+ */
+static struct LCFContextQueue *lcfq_tail;
+
 /**
  * Current Transmit Handle; NULL if no notify transmit exists currently
  */
@@ -304,6 +402,120 @@ route_message (uint32_t host_id, const struct GNUNET_MessageHeader *msg)
 }
 
 
+/**
+ * The  Link Controller forwarding task
+ *
+ * @param cls the LCFContext
+ * @param tc the Task context from scheduler
+ */
+static void
+lcf_proc_task (void *cls, const struct GNUNET_SCHEDULER_TaskContext *tc);
+
+
+/**
+ * Completion callback for host registrations while forwarding Link Controller messages
+ *
+ * @param cls the LCFContext
+ * @param emsg the error message; NULL if host registration is successful
+ */
+static void
+lcf_proc_cc (void *cls, const char *emsg)
+{
+  struct LCFContext *lcf = cls;
+
+  lcf->rhandle = NULL;
+  switch (lcf->state)
+  {
+  case INIT:
+    if (NULL != emsg)
+      goto registration_error;
+    lcf->state = DELEGATED_HOST_REGISTERED;
+    (void) GNUNET_SCHEDULER_add_now (&lcf_proc_task, lcf);
+    break;
+  case DELEGATED_HOST_REGISTERED:
+     if (NULL != emsg)
+      goto registration_error;
+     lcf->state = SLAVE_HOST_REGISTERED;
+     (void) GNUNET_SCHEDULER_add_now (&lcf_proc_task, lcf);
+     break;
+  default:
+    GNUNET_assert (0);                 /* Shouldn't reach here */
+  }  
+  return;
+
+ registration_error:
+  LOG (GNUNET_ERROR_TYPE_WARNING, 
+       "Host registration failed with message: %s\n", emsg);
+  lcf->state = FINISHED;
+  (void) GNUNET_SCHEDULER_add_now (&lcf_proc_task, lcf);
+}
+
+
+/**
+ * The  Link Controller forwarding task
+ *
+ * @param cls the LCFContext
+ * @param tc the Task context from scheduler
+ */
+static void
+lcf_proc_task (void *cls, const struct GNUNET_SCHEDULER_TaskContext *tc)
+{
+  struct LCFContext *lcf = cls;
+  struct LCFContextQueue *lcfq;
+
+  switch (lcf->state)
+  {
+  case INIT:
+    if (GNUNET_NO ==
+       GNUNET_TESTBED_is_host_registered_ (host_list[lcf->delegated_host_id],
+                                           lcf->fcontroller))
+    {
+      lcf->rhandle =
+       GNUNET_TESTBED_register_host (lcf->fcontroller,
+                                     host_list[lcf->delegated_host_id],
+                                     lcf_proc_cc, lcf);                                                   
+    }
+    else
+    {
+      lcf->state = DELEGATED_HOST_REGISTERED;
+      (void) GNUNET_SCHEDULER_add_now (&lcf_proc_task, lcf);
+    }
+    break;
+  case DELEGATED_HOST_REGISTERED:
+    if (GNUNET_NO ==
+       GNUNET_TESTBED_is_host_registered_ (host_list[lcf->slave_host_id],
+                                           lcf->fcontroller))
+    {
+      lcf->rhandle =
+       GNUNET_TESTBED_register_host (lcf->fcontroller,
+                                     host_list[lcf->slave_host_id],
+                                     lcf_proc_cc, lcf);                                                   
+    }
+    else
+    {
+      lcf->state = SLAVE_HOST_REGISTERED;
+      (void) GNUNET_SCHEDULER_add_now (&lcf_proc_task, lcf);
+    }
+    break;
+  case SLAVE_HOST_REGISTERED:
+    GNUNET_TESTBED_controller_link (lcf->fcontroller,
+                                   host_list[lcf->delegated_host_id],
+                                   host_list[lcf->slave_host_id],
+                                   lcf->cfg, lcf->is_subordinate);
+    lcf->state = FINISHED;
+    break;
+  case FINISHED:
+    lcfq = lcfq_head;
+    GNUNET_CONFIGURATION_destroy (lcfq->lcf->cfg);
+    GNUNET_free (lcfq->lcf);
+    GNUNET_CONTAINER_DLL_remove (lcfq_head, lcfq_tail, lcfq);
+    GNUNET_free (lcfq);
+    if (NULL != lcfq_head)
+      (void) GNUNET_SCHEDULER_add_now (&lcf_proc_task, lcfq_head->lcf);
+  }
+}
+
+
 /**
  * Message handler for GNUNET_MESSAGE_TYPE_TESTBED_INIT messages
  *
@@ -514,6 +726,8 @@ handle_link_controllers (void *cls,
 {
   const struct GNUNET_TESTBED_ControllerLinkMessage *msg;
   struct GNUNET_CONFIGURATION_Handle *cfg;
+  struct LCFContextQueue *lcfq;
+  struct Route *route;
   char *config;  
   uLongf dest_size;
   size_t config_size;
@@ -537,14 +751,6 @@ handle_link_controllers (void *cls,
     GNUNET_SERVER_receive_done (client, GNUNET_SYSERR);
     return;
   }
-  if ((delegated_host_id < route_list_size) &&
-      (NULL != route_list[delegated_host_id]))
-  {
-    LOG (GNUNET_ERROR_TYPE_WARNING,
-         "Delegated host has already been linked\n");
-    GNUNET_SERVER_receive_done (client, GNUNET_SYSERR);
-    return;
-  }
   if ((delegated_host_id >= host_list_size) || 
       (NULL == host_list[delegated_host_id]))
   {
@@ -559,6 +765,7 @@ handle_link_controllers (void *cls,
     GNUNET_SERVER_receive_done (client, GNUNET_SYSERR);
     return;
   }
+
   config_size = ntohs (msg->config_size);
   config = GNUNET_malloc (config_size);
   dest_size = (uLongf) config_size;
@@ -582,7 +789,45 @@ handle_link_controllers (void *cls,
     return;
   }
   GNUNET_free (config);
-  GNUNET_SERVER_receive_done (client, GNUNET_SYSERR);
+
+  /* If delegated host and slave host are not same we have to forward
+     towards delegated host */
+  if (slave_host_id != delegated_host_id)
+  {
+    if ((slave_host_id >= route_list_size) ||
+       (NULL == (route = route_list[slave_host_id])) ||
+       (NULL == route->fcontroller))
+    {
+      LOG (GNUNET_ERROR_TYPE_WARNING, "Not route towards slave host");
+      GNUNET_SERVER_receive_done (client, GNUNET_SYSERR);
+      return;
+    }
+    if (slave_host_id == route->next_hop) /* Slave directly connected */
+    {
+      /* Then make slave host and delegated host same so that slave
+        will startup directly link to the delegated host */
+      slave_host_id = delegated_host_id;
+    }
+    lcfq = GNUNET_malloc (sizeof (struct LCFContextQueue));
+    lcfq->lcf = GNUNET_malloc (sizeof (struct LCFContext));
+    lcfq->lcf->delegated_host_id = delegated_host_id;
+    lcfq->lcf->slave_host_id = slave_host_id;
+    lcfq->lcf->is_subordinate =
+      (1 == msg->is_subordinate) ? GNUNET_YES : GNUNET_NO;
+    lcfq->lcf->state = INIT;
+    lcfq->lcf->fcontroller = route->fcontroller;
+    lcfq->lcf->cfg = cfg;
+    if (NULL == lcfq_head)
+    {
+      GNUNET_CONTAINER_DLL_insert_tail (lcfq_head, lcfq_tail, lcfq);
+      (void) GNUNET_SCHEDULER_add_now (&lcf_proc_task, lcfq);
+    }
+    else
+      GNUNET_CONTAINER_DLL_insert_tail (lcfq_head, lcfq_tail, lcfq);
+    GNUNET_SERVER_receive_done (client, GNUNET_OK);
+    return;
+  }
+  GNUNET_SERVER_receive_done (client, GNUNET_OK);
   /* If we are not the slave controller then we have to route the request
      towards the slave controller */
   if (1 == msg->is_subordinate)
index 6e9fc491f8f43bf6a2ffa64b06ccea3c438c787e..c61f10563bd9b80399dcf2ca45ef03c19470cdb6 100644 (file)
@@ -255,7 +255,7 @@ handle_addhostconfirm (struct GNUNET_TESTBED_Controller *c,
   if (sizeof (struct GNUNET_TESTBED_HostConfirmedMessage) == msg_size)
   {
     LOG_DEBUG ("Host %u successfully registered\n", ntohl (msg->host_id));
-    GNUNET_TESTBED_mark_host_as_registered_  (rh->host, c);
+    GNUNET_TESTBED_mark_host_registered_at_  (rh->host, c);
     rh->cc (rh->cc_cls, NULL);
     GNUNET_free (rh);
     return GNUNET_OK;
index 3df6e14fed4b02ac7ffd0586b3724ea18355f91a..6c0877cea7b9049b38d41a7ee39de4cd86f1872a 100644 (file)
 #include "gnunet_hello_lib.h"
 #include "gnunet_container_lib.h"
 
+/**
+ * A list entry for registered controllers list
+ */
+struct RegisteredController
+{
+  /**
+   * The controller at which this host is registered
+   */
+  const struct GNUNET_TESTBED_Controller *controller;
+  
+  /**
+   * The next ptr for DLL
+   */
+  struct RegisteredController *next;
 
+  /**
+   * The prev ptr for DLL
+   */
+  struct RegisteredController *prev;
+};
 
 /**
  * Opaque handle to a host running experiments managed by the testing framework.
@@ -64,9 +83,14 @@ struct GNUNET_TESTBED_Host
   const char *username;
 
   /**
-   * The controller at which this host is registered
+   * The head for the list of controllers where this host is registered
    */
-  const struct GNUNET_TESTBED_Controller *controller;
+  struct RegisteredController *rc_head;
+
+  /**
+   * The tail for the list of controllers where this host is registered
+   */
+  struct RegisteredController *rc_tail;
 
   /**
    * Global ID we use to refer to a host on the network
@@ -261,7 +285,15 @@ GNUNET_TESTBED_hosts_load_from_file (const char *filename,
 void
 GNUNET_TESTBED_host_destroy (struct GNUNET_TESTBED_Host *host)
 {  
-  GNUNET_CONTAINER_DLL_remove (host_list_head, host_list_tail, host);
+  struct RegisteredController *rc;
+  
+  GNUNET_CONTAINER_DLL_remove (host_list_head, host_list_tail, host);  
+  /* clear registered controllers list */
+  for (rc=host->rc_head; NULL != rc; rc=host->rc_head)
+  {
+    GNUNET_CONTAINER_DLL_remove (host->rc_head, host->rc_tail, rc);
+    GNUNET_free (rc);
+  }
   GNUNET_free (host);
 }
 
@@ -389,11 +421,24 @@ GNUNET_TESTBED_host_stop_ (struct GNUNET_TESTBED_HelperHandle *handle)
  * @param controller the controller at which this host is registered
  */
 void
-GNUNET_TESTBED_mark_host_as_registered_ (struct GNUNET_TESTBED_Host *host,
+GNUNET_TESTBED_mark_host_registered_at_ (struct GNUNET_TESTBED_Host *host,
                                         const struct GNUNET_TESTBED_Controller
-                                        *controller)
+                                        * const controller)
 {
-  host->controller = controller;
+  struct RegisteredController *rc;
+  
+  for (rc=host->rc_head; NULL != rc; rc=rc->next)
+  {
+    if (controller == rc->controller) /* already registered at controller */
+    {
+      GNUNET_break (0);
+      return;
+    }
+  }
+  rc = GNUNET_malloc (sizeof (struct RegisteredController));
+  rc->controller = controller;
+  //host->controller = controller;
+  GNUNET_CONTAINER_DLL_insert_tail (host->rc_head, host->rc_tail, rc);
 }
 
 
@@ -407,9 +452,18 @@ GNUNET_TESTBED_mark_host_as_registered_ (struct GNUNET_TESTBED_Host *host,
 int
 GNUNET_TESTBED_is_host_registered_ (const struct GNUNET_TESTBED_Host *host,
                                    const struct GNUNET_TESTBED_Controller
-                                   *controller)
+                                   *const controller)
 {
-  return (controller == host->controller) ? GNUNET_YES : GNUNET_NO;
+  struct RegisteredController *rc;
+  
+  for (rc=host->rc_head; NULL != rc; rc=rc->next)
+  {
+    if (controller == rc->controller) /* already registered at controller */
+    {
+      return GNUNET_YES;
+    }
+  }
+  return GNUNET_NO;
 }
 
 
index c941608f4a2cd048ae4017b95bc6668480b80b59..1eab193635bdd383f2b35176d149073361f41dbb 100644 (file)
@@ -132,7 +132,7 @@ GNUNET_TESTBED_host_stop_ (struct GNUNET_TESTBED_HelperHandle *handle);
  * @param controller the controller at which this host is registered
  */
 void
-GNUNET_TESTBED_mark_host_as_registered_ (struct GNUNET_TESTBED_Host *host,
+GNUNET_TESTBED_mark_host_registered_at_ (struct GNUNET_TESTBED_Host *host,
                                         const struct GNUNET_TESTBED_Controller
                                         *controller);