gnunet-svn
[Top][All Lists]
Advanced

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

[GNUnet-SVN] r28921 - in gnunet/src: include testbed


From: gnunet
Subject: [GNUnet-SVN] r28921 - in gnunet/src: include testbed
Date: Fri, 30 Aug 2013 16:55:14 +0200

Author: harsha
Date: 2013-08-30 16:55:13 +0200 (Fri, 30 Aug 2013)
New Revision: 28921

Added:
   gnunet/src/testbed/gnunet-service-testbed_barriers.c
   gnunet/src/testbed/testbed_api_barriers.c
Modified:
   gnunet/src/include/gnunet_protocols.h
   gnunet/src/include/gnunet_testbed_service.h
   gnunet/src/testbed/Makefile.am
   gnunet/src/testbed/gnunet-service-testbed.c
   gnunet/src/testbed/gnunet-service-testbed.h
   gnunet/src/testbed/gnunet-service-testbed_peers.c
   gnunet/src/testbed/testbed.h
   gnunet/src/testbed/testbed_api.c
   gnunet/src/testbed/testbed_api.h
Log:
- towards testbed barriers


Modified: gnunet/src/include/gnunet_protocols.h
===================================================================
--- gnunet/src/include/gnunet_protocols.h       2013-08-30 13:55:21 UTC (rev 
28920)
+++ gnunet/src/include/gnunet_protocols.h       2013-08-30 14:55:13 UTC (rev 
28921)
@@ -1566,10 +1566,27 @@
 #define GNUNET_MESSAGE_TYPE_TESTBED_MANAGE_PEER_SERVICE 483
 
 /**
+ * Message to initialise a barrier.  Messages of these type are flooded to all
+ * sub-controllers
+ */
+#define GNUNET_MESSAGE_TYPE_TESTBED_BARRIER_INIT 484
+
+/**
+ * Message for signalling status of a barrier
+ */
+#define GNUNET_MESSAGE_TYPE_TESTBED_BARRIER_STATUS 485
+
+/**
+ * Message sent by a peer when it has reached a barrier and is waiting for it 
to
+ * be crossed
+ */
+#define GNUNET_MESSAGE_TYPE_TESTBED_BARRIER_WAIT 486
+
+/**
  * Not really a message, but for careful checks on the testbed messages; Should
  * always be the maximum and never be used to send messages with this type
  */
-#define GNUNET_MESSAGE_TYPE_TESTBED_MAX 484
+#define GNUNET_MESSAGE_TYPE_TESTBED_MAX 487
 
 /**
  * The initialization message towards gnunet-testbed-helper

Modified: gnunet/src/include/gnunet_testbed_service.h
===================================================================
--- gnunet/src/include/gnunet_testbed_service.h 2013-08-30 13:55:21 UTC (rev 
28920)
+++ gnunet/src/include/gnunet_testbed_service.h 2013-08-30 14:55:13 UTC (rev 
28921)
@@ -1471,6 +1471,63 @@
                          void *test_master_cls);
 
 
+/**
+ * Opaque handle for barrier
+ */
+struct GNUNET_TESTBED_Barrier;
+
+
+/**
+ * Functions of this type are to be given as callback argument to
+ * GNUNET_TESTBED_barrier_init().  The callback will be called when status
+ * information is available for the barrier.
+ *
+ * @param cls the closure given to GNUNET_TESTBED_barrier_init()
+ * @param name the name of the barrier
+ * @param barrier the barrier handle
+ * @param status status of the barrier; GNUNET_OK if the barrier is crossed;
+ *   GNUNET_SYSERR upon error
+ * @param emsg if the status were to be GNUNET_SYSERR, this parameter has the
+ *   error messsage
+ */
+typedef void (*GNUNET_TESTBED_barrier_status_cb) (void *cls,
+                                                  const char *name,
+                                                  struct GNUNET_TESTBED_Barrier
+                                                  *barrier,
+                                                  int status,
+                                                  const char *emsg);
+
+
+/**
+ * Initialise a barrier and call the given callback when the required 
percentage
+ * of peers (quorum) reach the barrier.  
+ *
+ * @param controller the handle to the controller
+ * @param name identification name of the barrier
+ * @param quorum the percentage of peers that is required to reach the barrier.
+ *   Peers signal reaching a barrier by calling
+ *   GNUNET_TESTBED_barrier_reached().
+ * @param cb the callback to call when the barrier is reached or upon error.
+ *   Cannot be NULL.
+ * @param cls closure for the above callback
+ * @return barrier handle
+ */
+struct GNUNET_TESTBED_Barrier *
+GNUNET_TESTBED_barrier_init (struct GNUNET_TESTBED_Controller *controller,
+                             const char *name,
+                             unsigned int quorum,
+                             GNUNET_TESTBED_barrier_status_cb cb, void *cls);
+
+
+/**
+ * Cancel a barrier.
+ *
+ * @param barrier the barrier handle
+ */
+void
+GNUNET_TESTBED_barrier_cancel (struct GNUNET_TESTBED_Barrier *barrier);
+
+
 #if 0                           /* keep Emacsens' auto-indent happy */
 {
 #endif

Modified: gnunet/src/testbed/Makefile.am
===================================================================
--- gnunet/src/testbed/Makefile.am      2013-08-30 13:55:21 UTC (rev 28920)
+++ gnunet/src/testbed/Makefile.am      2013-08-30 14:55:13 UTC (rev 28921)
@@ -39,7 +39,8 @@
   gnunet-service-testbed_oc.c \
   gnunet-service-testbed_cpustatus.c \
   gnunet-service-testbed_meminfo.c \
-  gnunet-service-testbed_meminfo.h
+  gnunet-service-testbed_meminfo.h \
+  gnunet-service-testbed_barriers.c
 gnunet_service_testbed_LDADD = $(XLIB) \
  $(top_builddir)/src/util/libgnunetutil.la \
  $(top_builddir)/src/core/libgnunetcore.la \
@@ -98,7 +99,8 @@
   testbed_api_testbed.c \
   testbed_api_test.c \
   testbed_api_topology.c testbed_api_topology.h \
-  testbed_api_sd.c testbed_api_sd.h
+  testbed_api_sd.c testbed_api_sd.h \
+  testbed_api_barriers.c 
 libgnunettestbed_la_LIBADD = $(XLIB) \
  $(top_builddir)/src/core/libgnunetcore.la \
  $(top_builddir)/src/statistics/libgnunetstatistics.la \

Modified: gnunet/src/testbed/gnunet-service-testbed.c
===================================================================
--- gnunet/src/testbed/gnunet-service-testbed.c 2013-08-30 13:55:21 UTC (rev 
28920)
+++ gnunet/src/testbed/gnunet-service-testbed.c 2013-08-30 14:55:13 UTC (rev 
28921)
@@ -34,7 +34,7 @@
 /**
  * Our configuration
  */
-struct GNUNET_CONFIGURATION_Handle *our_config;
+struct GNUNET_CONFIGURATION_Handle *GST_config;
 
 /**
  * The master context; generated with the first INIT message
@@ -516,11 +516,11 @@
   }
   ss_str = NULL;
   ss = NULL;
-  if (GNUNET_OK == GNUNET_CONFIGURATION_get_value_string (our_config, 
"TESTBED",
+  if (GNUNET_OK == GNUNET_CONFIGURATION_get_value_string (GST_config, 
"TESTBED",
                                                           "SHARED_SERVICES",
                                                           &ss_str))
   {
-    ss = parse_shared_services (ss_str, our_config);
+    ss = parse_shared_services (ss_str, GST_config);
     GNUNET_free (ss_str);
     ss_str = NULL;
   }
@@ -546,7 +546,7 @@
   host =
       GNUNET_TESTBED_host_create_with_id (GST_context->host_id,
                                           GST_context->master_ip, NULL,
-                                          our_config, 0);
+                                          GST_config, 0);
   host_list_add (host);
   LOG_DEBUG ("Created master context with host ID: %u\n", 
GST_context->host_id);
   GNUNET_SERVER_receive_done (client, GNUNET_OK);
@@ -824,7 +824,7 @@
     GNUNET_free (mq_entry);
   }
   GNUNET_free_non_null (hostname);
-  GNUNET_CONFIGURATION_destroy (our_config);
+  GNUNET_CONFIGURATION_destroy (GST_config);
   /* Free hello cache */
   GST_cache_clear ();
   GNUNET_TESTBED_operation_queue_destroy_ (GST_opq_openfds);
@@ -929,7 +929,7 @@
   GNUNET_assert (GNUNET_OK ==
                  GNUNET_CONFIGURATION_get_value_string (cfg, "testbed",
                                                         "HOSTNAME", 
&hostname));
-  our_config = GNUNET_CONFIGURATION_dup (cfg);
+  GST_config = GNUNET_CONFIGURATION_dup (cfg);
   GNUNET_SERVER_add_handlers (server, message_handlers);
   GNUNET_SERVER_disconnect_notify (server, &client_disconnect_cb, NULL);
   shutdown_task_id =
@@ -937,7 +937,7 @@
                                                   
GNUNET_SCHEDULER_PRIORITY_IDLE,
                                                   &shutdown_task, NULL);
   LOG_DEBUG ("Testbed startup complete\n");
-  GST_stats_init (our_config);
+  GST_stats_init (GST_config);
 }
 
 

Modified: gnunet/src/testbed/gnunet-service-testbed.h
===================================================================
--- gnunet/src/testbed/gnunet-service-testbed.h 2013-08-30 13:55:21 UTC (rev 
28920)
+++ gnunet/src/testbed/gnunet-service-testbed.h 2013-08-30 14:55:13 UTC (rev 
28921)
@@ -412,7 +412,7 @@
 /**
  * Our configuration
  */
-extern struct GNUNET_CONFIGURATION_Handle *our_config;
+extern struct GNUNET_CONFIGURATION_Handle *GST_config;
 
 /**
  * The master context; generated with the first INIT message
@@ -455,6 +455,11 @@
 extern unsigned int GST_peer_list_size;
 
 /**
+ * The current number of peers running locally under this controller
+ */
+extern unsigned int GST_num_local_peers;
+
+/**
  * The size of the host list
  */
 extern unsigned int GST_host_list_size;

Added: gnunet/src/testbed/gnunet-service-testbed_barriers.c
===================================================================
--- gnunet/src/testbed/gnunet-service-testbed_barriers.c                        
        (rev 0)
+++ gnunet/src/testbed/gnunet-service-testbed_barriers.c        2013-08-30 
14:55:13 UTC (rev 28921)
@@ -0,0 +1,512 @@
+/*
+  This file is part of GNUnet.
+  (C) 2008--2013 Christian Grothoff (and other contributing authors)
+
+  GNUnet is free software; you can redistribute it and/or modify
+  it under the terms of the GNU General Public License as published
+  by the Free Software Foundation; either version 3, or (at your
+  option) any later version.
+
+  GNUnet is distributed in the hope that it will be useful, but
+  WITHOUT ANY WARRANTY; without even the implied warranty of
+  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+  General Public License for more details.
+
+  You should have received a copy of the GNU General Public License
+  along with GNUnet; see the file COPYING.  If not, write to the
+  Free Software Foundation, Inc., 59 Temple Place - Suite 330,
+  Boston, MA 02111-1307, USA.
+*/
+
+/**
+ * @file testbed/gnunet-service-testbed_barriers.c
+ * @brief barrier handling at the testbed controller
+ * @author Sree Harsha Totakura <address@hidden> 
+ */
+
+#include "gnunet-service-testbed.h"
+
+/**
+ * timeout for outgoing message transmissions in seconds
+ */
+#define MESSAGE_SEND_TIMEOUT(s) \
+  GNUNET_TIME_relative_multiply (GNUNET_TIME_UNIT_SECONDS, s)
+
+
+/**
+ * Barrier
+ */
+struct Barrier;
+
+
+/**
+ * Message queue for transmitting messages
+ */
+struct MessageQueue
+{
+  /**
+   * next pointer for DLL
+   */
+  struct MessageQueue *next;
+
+  /**
+   * prev pointer for DLL
+   */
+  struct MessageQueue *prev;
+
+  /**
+   * The message to be sent
+   */
+  struct GNUNET_MessageHeader *msg;
+};
+
+/**
+ * Context to be associated with each client
+ */
+struct ClientCtx
+{
+  /**
+   * The barrier this client is waiting for
+   */
+  struct Barrier *barrier;
+
+  /**
+   * DLL next ptr
+   */
+  struct ClientCtx *next;
+
+  /**
+   * DLL prev ptr
+   */
+  struct ClientCtx *prev;
+
+  /**
+   * The client handle
+   */
+  struct GNUNET_SERVER_Client *client;
+
+  /**
+   * the transmission handle
+   */
+  struct GNUNET_SERVER_TransmitHandle *tx;
+
+  /**
+   * message queue head
+   */
+  struct MessageQueue *mq_head;
+
+  /**
+   * message queue tail
+   */
+  struct MessageQueue *mq_tail;
+};
+
+
+/**
+ * Barrier
+ */
+struct Barrier
+{
+  /**
+   * The hashcode of the barrier name
+   */
+  struct GNUNET_HashCode hash;
+
+  /**
+   * The name of the barrier
+   */
+  char *name;
+
+  /**
+   * DLL head for the list of clients waiting for this barrier
+   */
+  struct ClientCtx *head;
+
+  /**
+   * DLL tail for the list of clients waiting for this barrier
+   */
+  struct ClientCtx *tail;
+
+  /**
+   * Number of peers which have reached this barrier
+   */
+  unsigned int nreached;
+
+  /**
+   * Number of slaves we have initialised this barrier
+   */
+  unsigned int nslaves;
+
+  /**
+   * Quorum percentage to be reached
+   */
+  uint8_t quorum;
+  
+  /**
+   * Was there a timeout while propagating initialisation
+   */
+  uint8_t timedout;
+};
+
+
+/**
+ * Hashtable handle for storing initialised barriers
+ */
+static struct GNUNET_CONTAINER_MultiHashMap *barrier_map;
+
+/**
+ * Service context
+ */
+static struct GNUNET_SERVICE_Context *ctx;
+
+
+/**
+ * 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 client context
+ * @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_cb (void *cls, size_t size, void *buf)
+{
+  struct ClientCtx *ctx = cls;
+  struct GNUNET_SERVER_Client *client = ctx->client;
+  struct MessageQueue *mq;
+  struct GNUNET_MessageHeader *msg;
+  size_t wrote;
+
+  ctx->tx = NULL;
+  wrote = 0;
+  if ((0 == size) || (NULL == buf))
+  {
+    GNUNET_assert (NULL != ctx->client);
+    GNUNET_SERVER_client_drop (ctx->client);
+    ctx->client = NULL;    
+    return 0;
+  }
+  mq = ctx->mq_head;
+  msg = mq->msg;
+  wrote = ntohs (msg->size);
+  GNUNET_assert (size >= wrote);
+  (void) memcpy (buf, msg, wrote);
+  GNUNET_CONTAINER_DLL_remove (ctx->mq_head, ctx->mq_tail, mq);
+  GNUNET_free (mq->msg);
+  GNUNET_free (mq);
+  if (NULL != (mq = ctx->mq_head))
+    ctx->tx = GNUNET_SERVER_notify_transmit_ready (client, ntohs (msg->size),
+                                                  MESSAGE_SEND_TIMEOUT (30),
+                                                  &transmit_ready_cb, ctx);
+  return wrote;
+}
+
+
+/**
+ * Queue a message into a clients message queue
+ *
+ * @param ctx the context associated with the client
+ * @param msg the message to queue.  Will be consumed
+ * @param suspended is the client suspended at the time of calling 
queue_message
+ */
+static void
+queue_message (struct ClientCtx *ctx, struct GNUNET_MessageHeader *msg)
+{
+  struct MessageQueue *mq;
+  struct GNUNET_SERVER_Client *client = ctx->client;
+  
+  mq = GNUNET_malloc (sizeof (struct MessageQueue));
+  mq->msg = msg;
+  GNUNET_CONTAINER_DLL_insert_tail (ctx->mq_head, ctx->mq_tail, mq);
+  if (NULL == ctx->tx)
+   ctx->tx = GNUNET_SERVER_notify_transmit_ready (client, ntohs (msg->size),
+                                                  MESSAGE_SEND_TIMEOUT (30),
+                                                  &transmit_ready_cb, ctx);
+}
+
+
+#if 0
+/**
+ * Function to remove a barrier from the barrier map and cleanup resources
+ * occupied by a barrier
+ *
+ * @param barrier the barrier handle
+ */
+static void
+remove_barrier (struct Barrier *barrier)
+{
+  GNUNET_assert (GNUNET_YES == GNUNET_CONTAINER_multihashmap_remove 
(barrier_map,
+                                                                    
&barrier->hash,
+                                                                    barrier));
+  GNUNET_free (barrier->name);
+  GNUNET_free (barrier);
+}
+
+
+/**
+ * Function called upon timeout while waiting for a response from the
+ * subcontrollers to barrier init message
+ *
+ * @param 
+ * @return 
+ */
+static void
+fwd_tout_barrier_init (void *cls, const struct GNUNET_SCHEDULER_TaskContext 
*tc)
+{
+  struct ForwardedOperationContext *foctx = cls;
+  struct Barrier *barrier = foctx->cls;
+  
+  barrier->nslaves--;
+  barrier->timedout = GNUNET_YES;
+  if (0 == barrier->nslaves)
+  {
+    GST_send_operation_fail_msg (foctx->client, foctx->operation_id,
+                                 "Timeout while contacting a slave 
controller");
+    remove_barrier (barrier);
+  }
+}
+#endif
+
+/**
+ * Task for sending barrier crossed notifications to waiting client
+ *
+ * @param cls the barrier which is crossed
+ * @param tc scheduler task context
+ */
+static void
+notify_task_cb (void *cls, const struct GNUNET_SCHEDULER_TaskContext *tc)
+{
+  struct Barrier *barrier = cls;
+  struct ClientCtx *client_ctx;
+  struct GNUNET_TESTBED_BarrierStatus *msg;
+  struct GNUNET_MessageHeader *dup_msg;
+  uint16_t name_len;
+  uint16_t msize;
+
+  name_len = strlen (barrier->name) + 1;
+  msize = sizeof (struct GNUNET_TESTBED_BarrierStatus) + name_len;  
+  msg = GNUNET_malloc (msize);
+  msg->header.size = htons (msize);
+  msg->header.type = htons (GNUNET_MESSAGE_TYPE_TESTBED_BARRIER_STATUS);
+  msg->status = 0;
+  msg->name_len = htons (name_len);
+  (void) memcpy (msg->data, barrier->name, name_len);
+  msg->data[name_len] = '\0';
+  while (NULL != (client_ctx = barrier->head))
+  {
+    dup_msg = GNUNET_copy_message (&msg->header);
+    queue_message (client_ctx, dup_msg);
+    GNUNET_CONTAINER_DLL_remove (barrier->head, barrier->tail, client_ctx);
+    GNUNET_SERVER_client_set_user_context_ (client_ctx->client, NULL, 0);
+    GNUNET_free (client_ctx);
+  }
+}
+
+
+/**
+ * Message handler for GNUNET_MESSAGE_TYPE_TESTBED_BARRIER_WAIT messages.  This
+ * message should come from peers or a shared helper service using the
+ * testbed-barrier client API (@see gnunet_testbed_barrier_service.h)
+ *
+ * This handler is queued in the main service and will handle the messages sent
+ * either from the testbed driver or from a high level controller
+ *
+ * @param cls NULL
+ * @param client identification of the client
+ * @param message the actual message
+ */
+static void
+handle_barrier_wait (void *cls, struct GNUNET_SERVER_Client *client,
+                     const struct GNUNET_MessageHeader *message)
+{
+  const struct GNUNET_TESTBED_BarrierWait *msg;
+  struct Barrier *barrier;
+  char *name;
+  struct ClientCtx *client_ctx;
+  struct GNUNET_HashCode key;
+  size_t name_len;
+  uint16_t msize;
+  
+  msize = ntohs (message->size);
+  if (msize <= sizeof (struct GNUNET_TESTBED_BarrierWait))
+  {
+    GNUNET_break_op (0);
+    GNUNET_SERVER_receive_done (client, GNUNET_SYSERR);
+    return;
+  }
+  if (NULL == barrier_map)
+  {
+    GNUNET_break (0);
+    GNUNET_SERVER_receive_done (client, GNUNET_SYSERR);
+    return;
+  }
+  msg = (const struct GNUNET_TESTBED_BarrierWait *) message;
+  name_len = msize - sizeof (struct GNUNET_TESTBED_BarrierWait);
+  name = GNUNET_malloc (name_len + 1);
+  name[name_len] = '\0';
+  (void) memcpy (name, msg->name, name_len);
+  GNUNET_CRYPTO_hash (name, name_len - 1, &key);
+  if (NULL == (barrier = GNUNET_CONTAINER_multihashmap_get (barrier_map, 
&key)))
+  {
+    GNUNET_break (0);
+    GNUNET_SERVER_receive_done (client, GNUNET_SYSERR);
+    GNUNET_free (name);
+    return;
+  }
+  client_ctx = GNUNET_SERVER_client_get_user_context (client, struct 
ClientCtx);
+  if (NULL == client_ctx)
+  {
+    client_ctx = GNUNET_malloc (sizeof (struct ClientCtx));
+    client_ctx->client = client;
+    GNUNET_SERVER_client_keep (client);
+    client_ctx->barrier = barrier;
+    GNUNET_CONTAINER_DLL_insert_tail (barrier->head, barrier->tail, 
client_ctx);
+    barrier->nreached++;
+    if ((barrier->quorum * GST_num_local_peers) <= (barrier->nreached * 100))
+      notify_task_cb (barrier, NULL);
+  }
+  GNUNET_SERVER_receive_done (client, GNUNET_OK);
+}
+
+
+/**
+ * Functions with this signature are called whenever a client
+ * is disconnected on the network level.
+ *
+ * @param cls closure
+ * @param client identification of the client; NULL
+ *        for the last call when the server is destroyed
+ */
+static void
+disconnect_cb (void *cls, struct GNUNET_SERVER_Client *client)
+{
+  struct ClientCtx *client_ctx;
+  struct Barrier *barrier;
+  
+  client_ctx = GNUNET_SERVER_client_get_user_context (client, struct 
ClientCtx);
+  if (NULL == client_ctx)
+    return;
+  barrier = client_ctx->barrier;
+  GNUNET_CONTAINER_DLL_remove (barrier->head, barrier->tail, client_ctx);
+  if (NULL != client_ctx->tx)
+    GNUNET_SERVER_notify_transmit_ready_cancel (client_ctx->tx);
+  
+}
+
+
+/**
+ * Function to initialise barrriers component
+ */
+void
+GST_barriers_init (struct GNUNET_CONFIGURATION_Handle *cfg)
+{
+  static const struct GNUNET_SERVER_MessageHandler message_handlers[] = {
+    {&handle_barrier_wait, NULL, GNUNET_MESSAGE_TYPE_TESTBED_BARRIER_WAIT, 0},
+    {NULL, NULL, 0, 0}
+  };
+  struct GNUNET_SERVER_Handle *srv;
+
+  barrier_map = GNUNET_CONTAINER_multihashmap_create (3, GNUNET_YES);
+  ctx = GNUNET_SERVICE_start ("testbed-barrier", cfg,
+                              GNUNET_SERVICE_OPTION_MANUAL_SHUTDOWN);
+  srv = GNUNET_SERVICE_get_server (ctx);
+  GNUNET_SERVER_add_handlers (srv, message_handlers);
+  GNUNET_SERVER_disconnect_notify (srv, &disconnect_cb, NULL);  
+}
+
+
+/**
+ * Function to stop the barrier service
+ */
+void
+GST_barriers_stop ()
+{
+  GNUNET_assert (NULL != ctx);
+  GNUNET_SERVICE_stop (ctx);
+}
+
+
+/**
+ * Message handler for GNUNET_MESSAGE_TYPE_TESTBED_BARRIER_INIT messages.  This
+ * message should always come from a parent controller or the testbed API if we
+ * are the root controller.
+ *
+ * This handler is queued in the main service and will handle the messages sent
+ * either from the testbed driver or from a high level controller
+ *
+ * @param cls NULL
+ * @param client identification of the client
+ * @param message the actual message
+ */
+void
+GST_handle_barrier_init (void *cls, struct GNUNET_SERVER_Client *client,
+                         const struct GNUNET_MessageHeader *message)
+{
+  const struct GNUNET_TESTBED_BarrierInit *msg;
+  const char *name;
+  struct Barrier *barrier;
+  struct Slave *slave;
+  struct GNUNET_HashCode hash;
+  size_t name_len;
+  uint64_t op_id;
+  unsigned int cnt;
+  uint16_t msize;
+  
+  if (NULL == GST_context)
+  {
+    GNUNET_break_op (0);
+    GNUNET_SERVER_receive_done (client, GNUNET_SYSERR);
+    return;
+  }
+  if (client != GST_context->client)
+  {
+    GNUNET_break_op (0);
+    GNUNET_SERVER_receive_done (client, GNUNET_SYSERR);
+    return;
+  }
+  msize = ntohs (message->size);
+  if (msize <= sizeof (struct GNUNET_TESTBED_BarrierInit))
+  {
+    GNUNET_break_op (0);
+    GNUNET_SERVER_receive_done (client, GNUNET_SYSERR);
+    return;
+  }
+  msg = (const struct GNUNET_TESTBED_BarrierInit *) message;
+  op_id = GNUNET_ntohll (msg->op_id);
+  name = msg->name;
+  name_len = (size_t) msize - sizeof (struct GNUNET_TESTBED_BarrierInit);
+  GNUNET_CRYPTO_hash (name, name_len, &hash);
+  if (GNUNET_YES == GNUNET_CONTAINER_multihashmap_contains (barrier_map, 
&hash))
+  {
+    GST_send_operation_fail_msg (client, op_id, "Barrier already initialised");
+    GNUNET_SERVER_receive_done (client, GNUNET_OK);
+    return;
+  }
+  barrier = GNUNET_malloc (sizeof (struct Barrier));
+  (void) memcpy (&barrier->hash, &hash, sizeof (struct GNUNET_HashCode));
+  barrier->quorum = msg->quorum;
+  barrier->name = GNUNET_malloc (name_len + 1);
+  barrier->name[name_len] = '\0';
+  (void) memcpy (barrier->name, name, name_len);
+  GNUNET_assert (GNUNET_OK ==
+                 GNUNET_CONTAINER_multihashmap_put (barrier_map,
+                                                    &barrier->hash,
+                                                    barrier,
+                                                    
GNUNET_CONTAINER_MULTIHASHMAPOPTION_UNIQUE_FAST));
+  GNUNET_SERVER_receive_done (client, GNUNET_OK);
+  /* Propagate barrier init to subcontrollers */
+  for (cnt = 0; cnt < GST_slave_list_size; cnt++)
+  {
+    if (NULL == (slave = GST_slave_list[cnt]))
+      continue;
+    if (NULL == slave->controller)
+    {
+      GNUNET_break (0);/* May happen when we are connecting to the controller 
*/
+      continue;
+    }    
+    GNUNET_break (0);           /* FIXME */
+  }
+}

Modified: gnunet/src/testbed/gnunet-service-testbed_peers.c
===================================================================
--- gnunet/src/testbed/gnunet-service-testbed_peers.c   2013-08-30 13:55:21 UTC 
(rev 28920)
+++ gnunet/src/testbed/gnunet-service-testbed_peers.c   2013-08-30 14:55:13 UTC 
(rev 28921)
@@ -35,7 +35,12 @@
  */
 struct Peer **GST_peer_list;
 
+/**
+ * The current number of peers running locally under this controller
+ */
+unsigned int GST_num_local_peers;
 
+
 /**
  * Context information to manage peers' services
  */
@@ -162,6 +167,8 @@
     GST_array_grow_large_enough (GST_peer_list, GST_peer_list_size, peer->id);
   GNUNET_assert (NULL == GST_peer_list[peer->id]);
   GST_peer_list[peer->id] = peer;
+  if (GNUNET_NO == peer->is_remote)
+    GST_num_local_peers++;
 }
 
 
@@ -176,6 +183,8 @@
   unsigned int orig_size;
   uint32_t id;
 
+  if (GNUNET_NO == peer->is_remote)
+    GST_num_local_peers--;
   GST_peer_list[peer->id] = NULL;
   orig_size = GST_peer_list_size;
   while (GST_peer_list_size >= LIST_GROW_STEP)

Modified: gnunet/src/testbed/testbed.h
===================================================================
--- gnunet/src/testbed/testbed.h        2013-08-30 13:55:21 UTC (rev 28920)
+++ gnunet/src/testbed/testbed.h        2013-08-30 14:55:13 UTC (rev 28921)
@@ -768,6 +768,84 @@
 };
 
 
+/**
+ * Message to initialise a barrier
+ */
+struct GNUNET_TESTBED_BarrierInit
+{
+  /**
+   * Type is GNUNET_MESSAGE_TYPE_TESTBED_BARRIER_INIT
+   */
+  struct GNUNET_MessageHeader header;
+
+  /**
+   * Unused.  Only of alignment.
+   */
+  uint32_t unused;
+  
+  /**
+   * The operation id
+   */
+  uint64_t op_id;
+  
+  /**
+   * The quorum percentage needed for crossing the barrier
+   */
+  uint8_t quorum;
+
+  /**
+   * name of the barrier.  Non NULL-terminated.
+   */
+  char name[0];
+};
+
+
+/**
+ * Message for signalling status changes of a barrier
+ */
+struct GNUNET_TESTBED_BarrierStatus
+{
+  /**
+   * Type is GNUNET_MESSAGE_TYPE_TESTBED_BARRIER_STATUS
+   */
+  struct GNUNET_MessageHeader header;
+  
+  /**
+   * status.  0 to signal success (barrier is crossed).  1 for error.
+   */
+  uint16_t status;
+
+  /**
+   * strlen of the barrier name
+   */
+  uint16_t name_len;
+  
+  /**
+   * the barrier name (NULL terminated) concatenated with an error message 
(NULL
+   * terminated) if the status were to indicate an error
+   */
+  char data[0];
+};
+
+
+/**
+ * Message sent from peers to the testbed-barrier service to indicate that they
+ * have reached a barrier and are waiting for it to be crossed
+ */
+struct GNUNET_TESTBED_BarrierWait
+{
+  /**
+   * Type is GNUNET_MESSAGE_TYPE_TESTBED_BARRIER_WAIT
+   */
+  struct GNUNET_MessageHeader header;
+
+  /**
+   * The name of the barrier they have reached.  Non-NULL terminated.
+   */
+  char name[0];
+};
+
+
 GNUNET_NETWORK_STRUCT_END
 #endif
 /* end of testbed.h */

Modified: gnunet/src/testbed/testbed_api.c
===================================================================
--- gnunet/src/testbed/testbed_api.c    2013-08-30 13:55:21 UTC (rev 28920)
+++ gnunet/src/testbed/testbed_api.c    2013-08-30 14:55:13 UTC (rev 28921)
@@ -1159,6 +1159,13 @@
                                          GNUNET_TESTBED_ControllerLinkResponse
                                          *) msg);
     break;
+  case GNUNET_MESSAGE_TYPE_TESTBED_BARRIER_STATUS:
+    status =
+        GNUNET_TESTBED_handle_barrier_status_ (c,
+                                               (const struct
+                                                GNUNET_TESTBED_BarrierStatus *)
+                                               msg);
+    break;
   default:
     GNUNET_assert (0);
   }

Modified: gnunet/src/testbed/testbed_api.h
===================================================================
--- gnunet/src/testbed/testbed_api.h    2013-08-30 13:55:21 UTC (rev 28920)
+++ gnunet/src/testbed/testbed_api.h    2013-08-30 14:55:13 UTC (rev 28921)
@@ -496,7 +496,23 @@
                                  *slave_cfg, int is_subordinate);
 
 
+/**
+ * Handler for GNUNET_MESSAGE_TYPE_TESTBED_BARRIER_STATUS messages.  This
+ * function is defined in @file testbed_api_barriers.c
+ *
+ * @param c the controller handle to determine the connection this message
+ *   belongs to
+ * @param msg the barrier status message
+ * @return GNUNET_OK to keep the connection active; GNUNET_SYSERR to tear it
+ *   down signalling an error
+ */
+int
+GNUNET_TESTBED_handle_barrier_status_ (struct GNUNET_TESTBED_Controller *c,
+                                       const struct 
GNUNET_TESTBED_BarrierStatus
+                                       *msg);
 
 
+
+
 #endif
 /* end of testbed_api.h */

Added: gnunet/src/testbed/testbed_api_barriers.c
===================================================================
--- gnunet/src/testbed/testbed_api_barriers.c                           (rev 0)
+++ gnunet/src/testbed/testbed_api_barriers.c   2013-08-30 14:55:13 UTC (rev 
28921)
@@ -0,0 +1,221 @@
+/*
+  This file is part of GNUnet.
+  (C) 2008--2013 Christian Grothoff (and other contributing authors)
+
+  GNUnet is free software; you can redistribute it and/or modify
+  it under the terms of the GNU General Public License as published
+  by the Free Software Foundation; either version 3, or (at your
+  option) any later version.
+
+  GNUnet is distributed in the hope that it will be useful, but
+  WITHOUT ANY WARRANTY; without even the implied warranty of
+  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+  General Public License for more details.
+
+  You should have received a copy of the GNU General Public License
+  along with GNUnet; see the file COPYING.  If not, write to the
+  Free Software Foundation, Inc., 59 Temple Place - Suite 330,
+  Boston, MA 02111-1307, USA.
+*/
+
+/**
+ * @file testbed/testbed_api_barriers.c
+ * @brief API implementation for testbed barriers
+ * @author Sree Harsha Totakura <address@hidden> 
+ */
+
+#include "platform.h"
+#include "gnunet_testbed_service.h"
+#include "testbed_api.h"
+
+/**
+ * Handle for barrier
+ */
+struct GNUNET_TESTBED_Barrier
+{
+  /**
+   * hashcode identifying this barrier in the hashmap
+   */
+  struct GNUNET_HashCode key;
+
+  /**
+   * The controller handle given while initiliasing this barrier
+   */
+  struct GNUNET_TESTBED_Controller *c;
+  
+  /**
+   * The name of the barrier
+   */
+  char *name;
+
+  /**
+   * The continuation callback to call when we have a status update on this
+   */
+  GNUNET_TESTBED_barrier_status_cb cb;
+
+  /**
+   * the closure for the above callback
+   */
+  void *cls;
+ 
+};
+
+
+/**
+ * handle for hashtable of barrier handles
+ */
+static struct GNUNET_CONTAINER_MultiHashMap *barrier_map;
+
+
+/**
+ * Remove a barrier and it was the last one in the barrier hash map, destroy 
the
+ * hash map
+ *
+ * @param barrier the barrier to remove
+ */
+static void
+barrier_remove (struct GNUNET_TESTBED_Barrier *barrier)
+{
+  GNUNET_assert (NULL != barrier_map); /* No barriers present */
+  GNUNET_assert (GNUNET_OK ==
+                 GNUNET_CONTAINER_multihashmap_remove (barrier_map,
+                                                       &barrier->key,
+                                                       barrier));
+  GNUNET_free (barrier->name);
+  GNUNET_free (barrier);
+  if (0 == GNUNET_CONTAINER_multihashmap_size (barrier_map))
+  {
+    GNUNET_CONTAINER_multihashmap_destroy (barrier_map);
+    barrier_map = NULL;
+  }
+}
+
+
+/**
+ * Handler for GNUNET_MESSAGE_TYPE_TESTBED_BARRIER_STATUS messages
+ *
+ * @param c the controller handle to determine the connection this message
+ *   belongs to
+ * @param msg the barrier status message
+ * @return GNUNET_OK to keep the connection active; GNUNET_SYSERR to tear it
+ *   down signalling an error
+ */
+int
+GNUNET_TESTBED_handle_barrier_status_ (struct GNUNET_TESTBED_Controller *c,
+                                       const struct 
GNUNET_TESTBED_BarrierStatus
+                                       *msg)
+{
+  struct GNUNET_TESTBED_Barrier *barrier;
+  char *emsg;
+  const char *name;
+  struct GNUNET_HashCode key;  
+  size_t emsg_len;
+  int status;
+  uint16_t msize;
+  uint16_t name_len;
+  
+  emsg = NULL;
+  barrier = NULL;
+  msize = ntohs (msg->header.size);  
+  name = msg->data;
+  name_len = ntohs (msg->name_len);
+  if (  (sizeof (struct GNUNET_TESTBED_BarrierStatus) + name_len + 1 > msize)
+        || ('\0' != name[name_len])  )
+  {
+    GNUNET_break_op (0);
+    return GNUNET_SYSERR;
+  }
+  status = ntohs (msg->status);
+  if (0 != status)
+  {
+    status = -1;
+    emsg_len = msize - (sizeof (struct GNUNET_TESTBED_BarrierStatus) + name_len
+                        + 1);
+    if (0 == emsg_len)
+    {
+      GNUNET_break_op (0);
+      return GNUNET_SYSERR;
+    }
+    emsg_len++;
+    emsg = GNUNET_malloc (emsg_len);
+    emsg_len--;
+    emsg[emsg_len] = '\0';
+    (void) memcpy (emsg, msg->data + name_len + 1, emsg_len);
+  }
+  if (NULL == barrier_map)
+    goto cleanup;
+  GNUNET_CRYPTO_hash (name, name_len, &key);
+  barrier = GNUNET_CONTAINER_multihashmap_get (barrier_map, &key);
+  if (NULL == barrier)
+    goto cleanup;
+  GNUNET_assert (NULL != barrier->cb);
+  barrier->cb (barrier->cls, name, barrier, status, emsg);
+
+ cleanup:
+  GNUNET_free_non_null (emsg);
+  if (NULL != barrier)
+    barrier_remove (barrier);
+  return GNUNET_OK;
+}
+
+
+/**
+ * Initialise a barrier and call the given callback when the required 
percentage
+ * of peers (quorum) reach the barrier OR upon error.
+ *
+ * @param controller the handle to the controller
+ * @param name identification name of the barrier
+ * @param quorum the percentage of peers that is required to reach the barrier.
+ *   Peers signal reaching a barrier by calling
+ *   GNUNET_TESTBED_barrier_reached().
+ * @param cb the callback to call when the barrier is reached or upon error.
+ *   Cannot be NULL.
+ * @param cls closure for the above callback
+ * @return barrier handle; NULL upon error
+ */
+struct GNUNET_TESTBED_Barrier *
+GNUNET_TESTBED_barrier_init (struct GNUNET_TESTBED_Controller *controller,
+                             const char *name,
+                             unsigned int quorum,
+                             GNUNET_TESTBED_barrier_status_cb cb, void *cls)
+{
+  struct GNUNET_TESTBED_Barrier *barrier;
+  struct GNUNET_HashCode key;
+  size_t name_len;
+  
+  GNUNET_assert (quorum <= 100);
+  GNUNET_assert (NULL != cb);
+  name_len = strlen (name);
+  GNUNET_assert (0 < name_len);
+  GNUNET_CRYPTO_hash (name, name_len, &key);
+  if (NULL == barrier_map)
+    barrier_map = GNUNET_CONTAINER_multihashmap_create (3, GNUNET_YES);
+  if (GNUNET_YES ==
+      GNUNET_CONTAINER_multihashmap_contains (barrier_map, &key))
+  {
+    GNUNET_break (0);
+    return NULL;
+  }
+  barrier = GNUNET_malloc (sizeof (struct GNUNET_TESTBED_Barrier));
+  barrier->name = GNUNET_strdup (name);
+  barrier->cb = cb;
+  barrier->cls = cls;
+  (void) memcpy (&barrier->key, &key, sizeof (struct GNUNET_HashCode));
+  GNUNET_assert (GNUNET_OK ==
+                 GNUNET_CONTAINER_multihashmap_put (barrier_map, &barrier->key,
+                                                    barrier,
+                                                    
GNUNET_CONTAINER_MULTIHASHMAPOPTION_UNIQUE_FAST));
+  return barrier;
+}
+
+
+/**
+ * Cancel a barrier.
+ *
+ * @param barrier the barrier handle
+ */
+void
+GNUNET_TESTBED_barrier_cancel (struct GNUNET_TESTBED_Barrier *barrier)
+{
+  barrier_remove (barrier);
+}




reply via email to

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