-testbed service reply queue and host success reply
authorSree Harsha Totakura <totakura@in.tum.de>
Tue, 19 Jun 2012 22:24:51 +0000 (22:24 +0000)
committerSree Harsha Totakura <totakura@in.tum.de>
Tue, 19 Jun 2012 22:24:51 +0000 (22:24 +0000)
src/testbed/gnunet-service-testbed.c
src/testbed/testbed_api.c

index 327daf58462ed500c2730dcf4d127da67a454e1d..1c1dc3583afe9ab95b4b3da66a14f7c791b435b6 100644 (file)
 
 #include "testbed.h"
 #include "gnunet_testbed_service.h"
+#include "testbed_api_hosts.h"
 
+/**
+ * Generic logging
+ */
 #define LOG(kind,...)                           \
   GNUNET_log (kind, __VA_ARGS__)
 
+/**
+ * Debug logging
+ */
+#define LOG_DEBUG(...)                          \
+  LOG (GNUNET_ERROR_TYPE_DEBUG, __VA_ARGS__)
 
 struct Context
 {
@@ -54,6 +63,34 @@ struct Context
 };
 
 
+/**
+ * The message queue for sending messages to clients
+ */
+struct MessageQueue
+{
+  /**
+   * The message to be sent
+   */
+  struct GNUNET_MessageHeader *msg;
+
+  /**
+   * The client to send the message to
+   */
+  struct GNUNET_SERVER_Client *client;
+  
+  /**
+   * next pointer for DLL
+   */
+  struct MessageQueue *next;
+  
+  /**
+   * prev pointer for DLL
+   */
+  struct MessageQueue *prev;
+};
+
+
+
 /**
  * Wrapped stdin.
  */
@@ -69,6 +106,130 @@ static struct Context *master_context;
  */
 static GNUNET_SCHEDULER_TaskIdentifier shutdown_task_id;
 
+/**
+ * Array of host list
+ */
+static struct GNUNET_TESTBED_Host **host_list;
+
+/**
+ * The size of the host list
+ */
+static uint32_t host_list_size;
+
+/**
+ * The message queue head
+ */
+static struct MessageQueue *mq_head;
+
+/**
+ * The message queue tail
+ */
+static struct MessageQueue *mq_tail;
+
+/**
+ * Current Transmit Handle; NULL if no notify transmit exists currently
+ */
+struct GNUNET_SERVER_TransmitHandle *transmit_handle;
+
+
+/**
+ * Function called to notify a client about the connection begin ready to queue
+ * more data.  "buf" will be NULL and "size" zero if the connection was closed
+ * for writing in the meantime.
+ *
+ * @param cls NULL
+ * @param size number of bytes available in buf
+ * @param buf where the callee should write the message
+ * @return number of bytes written to buf
+ */
+static size_t
+transmit_ready_notify (void *cls, size_t size, void *buf)
+{
+  struct MessageQueue *mq_entry;
+
+  transmit_handle = NULL;
+  mq_entry = mq_head;
+  GNUNET_assert (NULL != mq_entry);
+  if (0 == size)
+    return 0;
+  GNUNET_assert (ntohs (mq_entry->msg->size) <= size);
+  size = ntohs (mq_entry->msg->size);
+  memcpy (buf, mq_entry->msg, size);
+  GNUNET_free (mq_entry->msg);
+  GNUNET_CONTAINER_DLL_remove (mq_head, mq_tail, mq_entry);
+  GNUNET_free (mq_entry);
+  mq_entry = mq_head;
+  if (NULL != mq_entry)
+    transmit_handle = 
+      GNUNET_SERVER_notify_transmit_ready (mq_entry->client,
+                                           ntohs (mq_entry->msg->size),
+                                           GNUNET_TIME_UNIT_FOREVER_REL,
+                                           &transmit_ready_notify, NULL);
+  return size;
+}
+
+
+/**
+ * Queues a message in send queue for sending to the service
+ *
+ * @param controller the handle to the controller
+ * @param msg the message to queue
+ */
+static void
+queue_message (struct GNUNET_SERVER_Client *client,
+               struct GNUNET_MessageHeader *msg)
+{
+  struct MessageQueue *mq_entry;
+  uint16_t type;
+  uint16_t size;
+
+  type = ntohs (msg->type);
+  size = ntohs (msg->size);
+  GNUNET_assert ((GNUNET_MESSAGE_TYPE_TESTBED_INIT <= type) &&
+                 (GNUNET_MESSAGE_TYPE_TESTBED_MAX > type));                 
+  mq_entry = GNUNET_malloc (sizeof (struct MessageQueue));
+  mq_entry->msg = msg;
+  mq_entry->client = 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);
+  if (NULL == transmit_handle)
+    transmit_handle = 
+      GNUNET_SERVER_notify_transmit_ready (client, size,
+                                           GNUNET_TIME_UNIT_FOREVER_REL,
+                                           &transmit_ready_notify, NULL);
+}
+
+
+/**
+ * Function to add a host to the current list of known hosts
+ *
+ * @param host the host to add 
+ * @return GNUNET_OK on success; GNUNET_SYSERR on failure due to host-id
+ *           already in use
+ */
+static int
+host_list_add (struct GNUNET_TESTBED_Host *host)
+{
+  uint32_t host_id;
+  
+  host_id = GNUNET_TESTBED_host_get_id_ (host);
+  if (host_list_size <= host_id)
+  {
+    host_list = GNUNET_realloc (host_list, 
+                                sizeof (struct GNUNET_TESTBED_Host *)
+                                * (host_id + 10));
+    host_list_size += (host_id + 10);
+  }
+  if (NULL != host_list[host_id])
+  {
+    LOG_DEBUG ("A host with id: %u already exists\n", host_id);
+    return GNUNET_SYSERR;
+  }
+  host_list[host_id] = host;
+  return GNUNET_OK;
+}
+
 
 /**
  * Message handler for GNUNET_MESSAGE_TYPE_TESTBED_INIT messages
@@ -83,6 +244,7 @@ handle_init (void *cls,
              const struct GNUNET_MessageHeader *message)
 {
   const struct GNUNET_TESTBED_InitMessage *msg;
+  struct GNUNET_TESTBED_Host *host;
 
   if (NULL != master_context)
   {
@@ -94,10 +256,13 @@ handle_init (void *cls,
   master_context = GNUNET_malloc (sizeof (struct Context));
   master_context->client = client;
   master_context->host_id = ntohl (msg->host_id);
+  host = GNUNET_TESTBED_host_create_with_id (master_context->host_id,
+                                             NULL, NULL, 0);
+  host_list_add (host);
   master_context->event_mask = GNUNET_ntohll (msg->event_mask);
   GNUNET_SERVER_client_keep (client);
-  LOG (GNUNET_ERROR_TYPE_DEBUG,
-       "Created master context with host ID: %u\n", master_context->host_id);
+  LOG_DEBUG ("Created master context with host ID: %u\n",
+             master_context->host_id);
   GNUNET_SERVER_receive_done (client, GNUNET_OK);
 }
 
@@ -116,10 +281,14 @@ handle_addhost (void *cls,
 {
   struct GNUNET_TESTBED_Host *host;
   const struct GNUNET_TESTBED_AddHostMessage *msg;
+  struct GNUNET_TESTBED_HostConfirmedMessage *reply;
   char *username;
   char *hostname;
+  char *emsg;
+  uint32_t host_id;
   uint16_t username_length;
   uint16_t hostname_length;
+  uint16_t reply_size;
   
   msg = (const struct GNUNET_TESTBED_AddHostMessage *) message;
   username_length = ntohs (msg->user_name_length);
@@ -141,13 +310,28 @@ handle_addhost (void *cls,
     GNUNET_SERVER_receive_done (client, GNUNET_SYSERR);
     return;
   }
-  host = GNUNET_TESTBED_host_create (hostname, username, ntohs
-                                     (msg->ssh_port));
-  /* Store host in a hashmap? But the host_id will be different */
-  /* hashmap? maybe array? 4-8 bytes/host and O(1) lookup vs.
-     > 80 bytes for hash map with slightly worse lookup; only
-     if we really get a tiny fraction of the hosts, the hash
-     map would result in any savings... (GNUNET_array_grow) */
+  host_id = ntohl (msg->host_id);
+  LOG_DEBUG ("Received ADDHOST message\n");
+  LOG_DEBUG ("-------host id: %u\n", host_id);
+  if (NULL != hostname) LOG_DEBUG ("-------hostname: %s\n", hostname);
+  if (NULL != username) LOG_DEBUG ("-------username: %s\n", username);
+  LOG_DEBUG ("-------ssh port: %u\n", ntohs (msg->ssh_port));
+  host = GNUNET_TESTBED_host_create_with_id (host_id, hostname, username,
+                                             ntohs (msg->ssh_port));
+  GNUNET_SERVER_receive_done (client, GNUNET_OK);
+  if (GNUNET_OK == host_list_add (host))
+    return;
+  /* We are unable to add a host */
+  emsg = "A host exists with given host-id";
+  GNUNET_TESTBED_host_destroy (host);
+  reply_size = sizeof (struct GNUNET_TESTBED_HostConfirmedMessage)
+    + strlen (emsg) + 1;
+  reply = GNUNET_malloc (reply_size);
+  reply->header.type = htons (GNUNET_MESSAGE_TYPE_TESTBED_ADDHOSTSUCCESS);
+  reply->header.size = htons (reply_size);
+  reply->host_id = htonl (host_id);
+  memcpy (&reply[1], emsg, strlen (emsg) + 1);
+  queue_message (client, (struct GNUNET_MessageHeader *) reply);
 }
 
 
@@ -161,6 +345,8 @@ static void
 shutdown_task (void *cls,
                const struct GNUNET_SCHEDULER_TaskContext *tc)
 {
+  uint32_t host_id;
+
   shutdown_task_id = GNUNET_SCHEDULER_NO_TASK;
   GNUNET_SCHEDULER_shutdown ();
   LOG (GNUNET_ERROR_TYPE_DEBUG, "Shutting down testbed service\n");
@@ -169,6 +355,9 @@ shutdown_task (void *cls,
     GNUNET_DISK_file_close (fh);
     fh = NULL;
   }
+  for (host_id = 0; host_id < host_list_size; host_id++)
+    if (NULL != host_list[host_id])
+      GNUNET_TESTBED_host_destroy (host_list[host_id]);
   GNUNET_free_non_null (master_context);
   master_context = NULL;
 }
index 3f49890c43f225e8e0b97e3bd61aa0c6b576c409..fc4b86603ba650225b4e9e98b9f860e7c8501f10 100644 (file)
@@ -229,7 +229,7 @@ queue_message (struct GNUNET_TESTBED_Controller *controller,
                                            GNUNET_TIME_UNIT_FOREVER_REL,
                                            GNUNET_NO, &transmit_ready_notify,
                                            controller);
- }
+}
 
 
 /**