fixes
[oweals/gnunet.git] / src / testbed / gnunet-service-testbed.c
index 56fff6450d6e21cd45def338f7ac3de989355149..ea28af8d9bc2631ddb981d742f65f7ae7255aab4 100644 (file)
@@ -558,6 +558,26 @@ struct ForwardedOverlayConnectContext
    */
   struct GNUNET_TESTBED_Operation *sub_op;
 
+  /**
+   * The client which initiated the link controller operation
+   */
+  struct GNUNET_SERVER_Client *client;
+
+  /**
+   * A copy of the original overlay connect message
+   */
+  struct GNUNET_MessageHeader *orig_msg;
+
+  /**
+   * The host registration handle while registered hosts in this context
+   */
+  struct GNUNET_TESTBED_HostRegistrationHandle *rhandle;
+
+  /**
+   * The id of the operation which created this context information
+   */
+  uint64_t operation_id;
+
   /**
    * Enumeration of states for this context
    */
@@ -568,6 +588,11 @@ struct ForwardedOverlayConnectContext
      */
     FOCC_INIT = 0,
 
+    /**
+     * State where we attempt to register peer2's controller with peer1's controller
+     */
+    FOCC_REGISTER,
+
     /**
      * State where we attempt to get peer2's controller configuration
      */
@@ -614,10 +639,16 @@ static struct Context *master_context;
  */
 static char *hostname;
 
+
 /***********/
 /* Handles */
 /***********/
 
+/**
+ * Our configuration
+ */
+static struct GNUNET_CONFIGURATION_Handle *our_config;
+
 /**
  * Current Transmit Handle; NULL if no notify transmit exists currently
  */
@@ -648,7 +679,7 @@ static struct MessageQueue *mq_head;
 static struct MessageQueue *mq_tail;
 
 /**
- * Array of host list
+ * Array of hosts
  */
 static struct GNUNET_TESTBED_Host **host_list;
 
@@ -1198,6 +1229,35 @@ lcf_proc_task (void *cls, const struct GNUNET_SCHEDULER_TaskContext *tc)
 }
 
 
+/**
+ * Callback to be called when forwarded overlay connection operation has a reply
+ * from the sub-controller successfull. We have to relay the reply msg back to
+ * the client
+ *
+ * @param cls ForwardedOperationContext
+ * @param msg the peer create success message
+ */
+static void
+forwarded_overlay_connect_listener (void *cls,
+                                    const struct GNUNET_MessageHeader *msg);
+
+
+/**
+ * Cleans up ForwardedOverlayConnectContext
+ *
+ * @param focc the ForwardedOverlayConnectContext to cleanup
+ */
+static void
+cleanup_focc (struct ForwardedOverlayConnectContext *focc)
+{
+  if (NULL != focc->sub_op)
+    GNUNET_TESTBED_operation_done (focc->sub_op);
+  if (NULL != focc->client)
+    GNUNET_SERVER_client_drop (focc->client);
+  GNUNET_free_non_null (focc->orig_msg);
+  GNUNET_free (focc);
+}
+
 /**
  * Callback for event from slave controllers
  *
@@ -1209,22 +1269,66 @@ slave_event_callback (void *cls,
                       const struct GNUNET_TESTBED_EventInformation *event)
 {
   struct ForwardedOverlayConnectContext *focc;
+  struct ForwardedOperationContext *fopc;
   struct GNUNET_CONFIGURATION_Handle *slave_cfg;
+  struct GNUNET_TESTBED_Operation *old_op;
+  char *emsg;
 
   /* We currently only get here when doing overlay connect operations and that
      too while trying out sub operations */
-  if (GNUNET_TESTBED_ET_OPERATION_FINISHED != event->type)
-    return;
+  GNUNET_assert (GNUNET_TESTBED_ET_OPERATION_FINISHED == event->type);
   focc = event->details.operation_finished.op_cls;
+  LOG_DEBUG ("Operation successful\n");
+  if (NULL != event->details.operation_finished.emsg)
+  {
+    GNUNET_asprintf (&emsg, "Failure executing suboperation: %s",
+                     event->details.operation_finished.emsg);
+    send_operation_fail_msg (focc->client, focc->operation_id,
+                             emsg);
+    GNUNET_free (emsg);
+    cleanup_focc (focc);
+    return;
+  }
   switch (focc->state)
   {
   case FOCC_GET_CFG:
     slave_cfg = event->details.operation_finished.generic;
-    GNUNET_break (0);           /* FIXME */
-    GNUNET_CONFIGURATION_destroy (slave_cfg);
-  default:  
+    old_op = focc->sub_op;
+    focc->state = FOCC_LINK;
+    focc->sub_op = GNUNET_TESTBED_controller_link_ (focc,
+                                                    focc->gateway,
+                                                    focc->peer2_host_id,
+                                                    peer_list[focc->peer1]->details.remote.remote_host_id,
+                                                    slave_cfg,
+                                                    GNUNET_NO);
+    GNUNET_TESTBED_operation_done (old_op);
+    break;
+  case FOCC_LINK:
+    LOG_DEBUG ("OL: Linking controllers successfull\n");
+    GNUNET_TESTBED_operation_done (focc->sub_op);
+    focc->sub_op = NULL;
+    focc->state = FOCC_OL_CONNECT;
+    fopc = GNUNET_malloc (sizeof (struct ForwardedOperationContext));
+    fopc->client = focc->client;
+    focc->client = NULL;
+    fopc->operation_id = focc->operation_id;
+    fopc->cls = NULL;
+    fopc->opc =
+        GNUNET_TESTBED_forward_operation_msg_ (focc->gateway,
+                                               focc->operation_id, focc->orig_msg,
+                                               &forwarded_operation_reply_relay,
+                                               fopc);
+    GNUNET_free (focc->orig_msg);
+    focc->orig_msg = NULL;
+    fopc->timeout_task =
+       GNUNET_SCHEDULER_add_delayed (TIMEOUT, &forwarded_operation_timeout,
+                                     fopc);
+    cleanup_focc (focc);
+    break;
+  default:
     GNUNET_assert (0);
   }
+  return;
 }
 
 
@@ -1338,7 +1442,9 @@ handle_init (void *cls, struct GNUNET_SERVER_Client *client,
   master_context->system =
       GNUNET_TESTING_system_create ("testbed", master_context->master_ip, hostname);
   host =
-      GNUNET_TESTBED_host_create_with_id (master_context->host_id, NULL, NULL,
+      GNUNET_TESTBED_host_create_with_id (master_context->host_id,
+                                          master_context->master_ip,
+                                          NULL,
                                           0);
   host_list_add (host);
   GNUNET_SERVER_client_keep (client);
@@ -1373,12 +1479,15 @@ handle_add_host (void *cls, struct GNUNET_SERVER_Client *client,
 
   msg = (const struct GNUNET_TESTBED_AddHostMessage *) message;
   msize = ntohs (msg->header.size);
-  username = (char *) &(msg[1]);
+  username = (char *) &msg[1];
   username_length = ntohs (msg->user_name_length);
-  GNUNET_assert (msize > (sizeof (struct GNUNET_TESTBED_AddHostMessage) + username_length + 1));        /* msg must contain hostname */
   if (0 != username_length)
-    GNUNET_assert ('\0' == username[username_length]);
-  username_length = (0 == username_length) ? 0 : username_length + 1;
+    username_length++;
+  /* msg must contain hostname */
+  GNUNET_assert (msize > (sizeof (struct GNUNET_TESTBED_AddHostMessage) +
+                         username_length + 1));
+  if (0 != username_length)
+    GNUNET_assert ('\0' == username[username_length - 1]);
   hostname = username + username_length;
   hostname_length =
       msize - (sizeof (struct GNUNET_TESTBED_AddHostMessage) + username_length);
@@ -1564,7 +1673,8 @@ handle_link_controllers (void *cls, struct GNUNET_SERVER_Client *client,
   slave_host_id = ntohl (msg->slave_host_id);
   if ((slave_host_id >= host_list_size) || (NULL == host_list[slave_host_id]))
   {
-    LOG (GNUNET_ERROR_TYPE_WARNING, "Slave host not registered with us\n");
+    LOG (GNUNET_ERROR_TYPE_WARNING, "Slave host %u not registered with us\n",
+        slave_host_id);
     GNUNET_SERVER_receive_done (client, GNUNET_SYSERR);
     return;
   }
@@ -1586,7 +1696,7 @@ handle_link_controllers (void *cls, struct GNUNET_SERVER_Client *client,
     {
       LOG (GNUNET_ERROR_TYPE_WARNING, "Host %u already connected\n",
            delegated_host_id);
-      GNUNET_SERVER_receive_done (client, GNUNET_SYSERR);
+      GNUNET_SERVER_receive_done (client, GNUNET_OK);
       return;
     }
     config = GNUNET_malloc (config_size);
@@ -2502,6 +2612,47 @@ overlay_connect_get_config (void *cls, const struct GNUNET_MessageHeader *msg)
 }
 
 
+/**
+ * This callback is a part of overlay connect operation. This will be run when
+ * the registration operation of peer2's controller is completed at peer1's
+ * controller
+ *
+ * @param cls the ForwardedOverlayConnectContext
+ * @param emsg the error message in case of any failure; NULL if host
+ *          registration is successfull.
+ */
+static void
+focc_reg_completion_cc (void *cls, const char *emsg)
+{
+  struct ForwardedOverlayConnectContext *focc = cls;
+  struct GNUNET_CONFIGURATION_Handle *cfg;
+
+  GNUNET_assert (FOCC_REGISTER == focc->state);
+  focc->rhandle = NULL;
+  GNUNET_assert (NULL == focc->sub_op);
+  LOG_DEBUG ("Registering peer2's host successful\n");
+  if ((NULL == focc->gateway2)
+      || ((focc->peer2_host_id < slave_list_size) /* Check if we have the needed config */
+          && (NULL != slave_list[focc->peer2_host_id])))
+  {
+    focc->state = FOCC_LINK;
+    cfg = (NULL == focc->gateway2) ? 
+        our_config : slave_list[focc->peer2_host_id]->cfg;
+    focc->sub_op = 
+        GNUNET_TESTBED_controller_link_ (focc,
+                                         focc->gateway,
+                                         focc->peer2_host_id,
+                                         peer_list[focc->peer1]->details.remote.remote_host_id,
+                                         cfg,
+                                         GNUNET_NO);
+    return;
+  }
+  focc->state = FOCC_GET_CFG;
+  focc->sub_op = GNUNET_TESTBED_get_slave_config_ (focc, focc->gateway2,
+                                                   focc->peer2_host_id);
+}
+
+
 /**
  * Callback to be called when forwarded overlay connection operation has a reply
  * from the sub-controller successfull. We have to relay the reply msg back to
@@ -2528,26 +2679,26 @@ forwarded_overlay_connect_listener (void *cls,
   case FOCC_INIT:
     if (GNUNET_MESSAGE_TYPE_TESTBED_NEEDCONTROLLERCONFIG != ntohs (msg->type))
     {
-      GNUNET_break (0);  /* Something failed; you may check output of sub-controllers */
+      GNUNET_break (0);  /* Something failed; you may check output of
+                            sub-controllers */
+      cleanup_focc (focc);
       forwarded_operation_reply_relay (cls, msg);
       return;
     }
-    GNUNET_assert (NULL == focc->sub_op);
-    focc->state = FOCC_GET_CFG;
-    focc->sub_op = GNUNET_TESTBED_get_slave_config_ (focc, focc->gateway2,
-                                                 focc->peer2_host_id);
-    /* FIXME */
-    GNUNET_break (0);
+    LOG_DEBUG ("Registering peer2's host\n");
+    focc->state = FOCC_REGISTER;
+    focc->rhandle =
+        GNUNET_TESTBED_register_host (focc->gateway,
+                                      host_list[focc->peer2_host_id],
+                                      focc_reg_completion_cc, focc);
     break;
-    /* focc->op = GNUNET_TESTBED_controller_link (focc, */
-    /*                                            focc->gateway, */
-    /*                                            slave_list[peer2_host_id], */
-    /*                                            slave_list[peer_list[focc->peer1]->remote_host_id], */
-    /*                                            slave_list */
-                                               
   default:
     GNUNET_assert (0);
   }
+  GNUNET_SERVER_client_drop (fopc->client);
+  GNUNET_SCHEDULER_cancel (fopc->timeout_task);
+  fopc->timeout_task = GNUNET_SCHEDULER_NO_TASK;
+  GNUNET_free (fopc);
 }
 
 
@@ -2573,7 +2724,6 @@ handle_overlay_connect (void *cls, struct GNUNET_SERVER_Client *client,
   uint32_t p2; 
   uint32_t peer2_host_id;
 
-  
   msg = (const struct GNUNET_TESTBED_OverlayConnectMessage *) message;
   p1 = ntohl (msg->peer1);
   p2 = ntohl (msg->peer2);
@@ -2596,22 +2746,32 @@ handle_overlay_connect (void *cls, struct GNUNET_SERVER_Client *client,
     route_to_peer2_host = NULL;
     route_to_peer1_host = NULL;
     route_to_peer2_host = find_dest_route (peer2_host_id);
-    if (NULL != route_to_peer2_host)
+    if ((NULL != route_to_peer2_host) 
+        || (peer2_host_id == master_context->host_id))
     {
       route_to_peer1_host = 
           find_dest_route (peer_list[p1]->details.remote.remote_host_id);
       GNUNET_assert (NULL != route_to_peer1_host);
-      if (route_to_peer2_host->dest != route_to_peer1_host->dest)
+      if ((peer2_host_id == master_context->host_id) 
+          || (route_to_peer2_host->dest != route_to_peer1_host->dest))
       {
         struct ForwardedOverlayConnectContext *focc;
-        
+        uint16_t msize;
+
+        msize = sizeof (struct GNUNET_TESTBED_OverlayConnectMessage);
         focc = GNUNET_malloc (sizeof (struct ForwardedOverlayConnectContext));
         focc->gateway = peer->details.remote.controller;
-        focc->gateway2 = slave_list[route_to_peer2_host->dest]->controller;
+        focc->gateway2 = (NULL == route_to_peer2_host) ? NULL :
+            slave_list[route_to_peer2_host->dest]->controller;
         focc->peer1 = p1;
         focc->peer2 = p2;
         focc->peer2_host_id = peer2_host_id;
         focc->state = FOCC_INIT;
+        focc->orig_msg = GNUNET_malloc (msize);
+        (void) memcpy (focc->orig_msg, message, msize);
+        GNUNET_SERVER_client_keep (client);
+        focc->client = client;
+        focc->operation_id = operation_id;
         fopc->cls = focc;
       }
     }
@@ -3037,6 +3197,7 @@ shutdown_task (void *cls, const struct GNUNET_SCHEDULER_TaskContext *tc)
     master_context = NULL;
   }
   GNUNET_free_non_null (hostname);
+  GNUNET_CONFIGURATION_destroy (our_config);
 }
 
 
@@ -3103,6 +3264,7 @@ testbed_run (void *cls, struct GNUNET_SERVER_Handle *server,
 
   GNUNET_assert (GNUNET_OK == GNUNET_CONFIGURATION_get_value_string 
                 (cfg, "testbed", "HOSTNAME", &hostname));
+  our_config = GNUNET_CONFIGURATION_dup (cfg);
   GNUNET_SERVER_add_handlers (server, message_handlers);
   GNUNET_SERVER_disconnect_notify (server, &client_disconnect_cb, NULL);
   ss_map = GNUNET_CONTAINER_multihashmap_create (5, GNUNET_NO);
@@ -3110,7 +3272,7 @@ testbed_run (void *cls, struct GNUNET_SERVER_Handle *server,
       GNUNET_SCHEDULER_add_delayed (GNUNET_TIME_UNIT_FOREVER_REL,
                                     &shutdown_task, NULL);
   LOG_DEBUG ("Testbed startup complete\n");
-  event_mask = GNUNET_TESTBED_ET_OPERATION_FINISHED;
+  event_mask = 1LL << GNUNET_TESTBED_ET_OPERATION_FINISHED;
 }