*/
typedef void (*GNUNET_TESTBED_barrier_wait_cb) (void *cls,
const char *name,
- int estatus);
+ int status);
/**
/**
- * Cancel a barrier wait handle
+ * Cancel a barrier wait handle. Should not be called in or after the callback
+ * given to GNUNET_TESTBED_barrier_wait() has been called.
*
* @param h the barrier wait handle
*/
gnunet-service-testbed_cpustatus.c \
gnunet-service-testbed_meminfo.c \
gnunet-service-testbed_meminfo.h \
- gnunet-service-testbed_barriers.c
+ gnunet-service-testbed_barriers.c \
+ gnunet-service-testbed_barriers.h
gnunet_service_testbed_LDADD = $(XLIB) \
$(top_builddir)/src/util/libgnunetutil.la \
$(top_builddir)/src/core/libgnunetcore.la \
libgnunettestbed.la
test_testbed_api_barriers_SOURCES = \
- test_testbed_api_barriers.c
+ test_testbed_api_barriers.c \
+ test_testbed_api_barriers.h
test_testbed_api_barriers_LDADD = \
$(top_builddir)/src/util/libgnunetutil.la \
libgnunettestbed.la
$(do_subst) < $(srcdir)/buildvars.py.in > $@
gnunet_service_test_barriers_SOURCES = \
- gnunet-service-test-barriers.c
+ gnunet-service-test-barriers.c \
+ test_testbed_api_barriers.h
gnunet_service_test_barriers_LDADD = \
$(top_builddir)/src/util/libgnunetutil.la \
libgnunettestbed.la
* @author Sree Harsha Totakura <sreeharsha@totakura.in>
*/
+#include "platform.h"
+#include "gnunet_util_lib.h"
+#include "gnunet_testbed_service.h"
+#include "test_testbed_api_barriers.h"
-int main ()
+/**
+ * logging short hand
+ */
+#define LOG(type,...) \
+ GNUNET_log (type, __VA_ARGS__);
+
+/**
+ * Our barrier wait handle
+ */
+struct GNUNET_TESTBED_BarrierWaitHandle *wh;
+
+
+/**
+ * Dummy task callback to keep us running forever
+ *
+ * @param cls NULL
+ * @param tc scheduler task context
+ */
+static void
+do_shutdown (void *cls, const struct GNUNET_SCHEDULER_TaskContext *tc)
+{
+ if (NULL != wh)
+ GNUNET_TESTBED_barrier_wait_cancel (wh);
+ wh = NULL;
+}
+
+
+/**
+ * Functions of this type are to be given as acallback argumetn to
+ * GNUNET_TESTBED_barrier_wait(). The callback will be called when the barrier
+ * corresponding given in GNUNET_TESTBED_barrier_wait() is crossed or cancelled.
+ *
+ * @param cls NULL
+ * @param name the barrier name
+ * @param status GNUNET_SYSERR in case of error while waiting for the barrier;
+ * GNUNET_OK if the barrier is crossed
+ */
+static void
+barrier_wait_cb (void *cls, const char *name, int status)
+{
+ GNUNET_break (NULL == cls);
+ wh = NULL;
+ GNUNET_break (GNUNET_OK == status);
+}
+
+
+/**
+ * Task to wait for the barrier
+ *
+ * @param cls NULL
+ * @param tc scheduler task context
+ * @return
+ */
+static void
+do_wait (void *cls, const struct GNUNET_SCHEDULER_TaskContext *tc)
+{
+ if (0 != (GNUNET_SCHEDULER_REASON_SHUTDOWN & tc->reason))
+ return;
+ wh = GNUNET_TESTBED_barrier_wait (TEST_BARRIER_NAME, &barrier_wait_cb, NULL);
+ GNUNET_break (NULL != wh);
+}
+
+
+/**
+ * Main run function.
+ *
+ * @param cls NULL
+ * @param args arguments passed to GNUNET_PROGRAM_run
+ * @param cfgfile the path to configuration file
+ * @param cfg the configuration file handle
+ */
+static void
+run (void *cls, char *const *args, const char *cfgfile,
+ const struct GNUNET_CONFIGURATION_Handle *config)
+{
+ unsigned int rsec;
+
+ rsec = GNUNET_CRYPTO_random_u32 (GNUNET_CRYPTO_QUALITY_NONCE, 10);
+ GNUNET_SCHEDULER_add_delayed (GNUNET_TIME_relative_multiply
+ (GNUNET_TIME_UNIT_SECONDS, rsec),
+ &do_wait, NULL);
+ GNUNET_SCHEDULER_add_delayed (GNUNET_TIME_UNIT_FOREVER_REL,
+ &do_shutdown, NULL);
+}
+
+
+
+/**
+ * Main
+ */
+int main (int argc, char **argv)
{
- return 0;
+ struct GNUNET_GETOPT_CommandLineOption options[] = {
+ GNUNET_GETOPT_OPTION_END
+ };
+ int ret;
+
+ ret =
+ GNUNET_PROGRAM_run (argc, argv,
+ "test-barriers", "nohelp", options, &run, NULL);
+ return ret;
}
GNUNET_free (mq_entry);
}
GNUNET_free_non_null (hostname);
- GNUNET_CONFIGURATION_destroy (GST_config);
/* Free hello cache */
GST_cache_clear ();
GNUNET_TESTBED_operation_queue_destroy_ (GST_opq_openfds);
GST_opq_openfds = NULL;
GST_stats_destroy ();
+ GST_barriers_destroy ();
+ GNUNET_CONFIGURATION_destroy (GST_config);
}
&shutdown_task, NULL);
LOG_DEBUG ("Testbed startup complete\n");
GST_stats_init (GST_config);
+ GST_barriers_init (GST_config);
}
((barrier->quorum * GST_num_local_peers) <= (barrier->nreached * 100))
+#ifdef LOG
+#undef LOG
+#endif
+
+/**
+ * Logging shorthand
+ */
+#define LOG(kind,...) \
+ GNUNET_log_from (kind, "testbed-barriers", __VA_ARGS__)
+
+
/**
* Barrier
*/
uint16_t msize;
GNUNET_assert ((NULL == emsg) || (BARRIER_STATUS_ERROR == status));
- name_len = strlen (name) + 1;
+ name_len = strlen (name);
msize = sizeof (struct GNUNET_TESTBED_BarrierStatusMsg)
- + name_len
- + (NULL == emsg) ? 0 : strlen (emsg) + 1;
+ + (name_len + 1)
+ + ((NULL == emsg) ? 0 : (strlen (emsg) + 1));
msg = GNUNET_malloc (msize);
+ msg->header.size = htons (msize);
+ msg->header.type = htons (GNUNET_MESSAGE_TYPE_TESTBED_BARRIER_STATUS);
msg->status = htons (status);
msg->name_len = htons ((uint16_t) name_len);
(void) memcpy (msg->data, name, name_len);
if (NULL != emsg)
- (void) memcpy (msg->data + name_len, emsg, strlen (emsg) + 1);
+ (void) memcpy (msg->data + name_len + 1, emsg, strlen (emsg));
GST_queue_message (client, &msg->header);
}
msg = GNUNET_malloc (msize);
msg->header.size = htons (msize);
msg->header.type = htons (GNUNET_MESSAGE_TYPE_TESTBED_BARRIER_STATUS);
- msg->status = 0;
+ msg->status = htons (BARRIER_STATUS_CROSSED);
msg->name_len = htons (name_len);
(void) memcpy (msg->data, barrier->name, name_len);
msg->data[name_len] = '\0';
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);
}
}
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);
+ LOG_DEBUG ("Received BARRIER_WAIT for barrier `%s'\n", name);
+ GNUNET_CRYPTO_hash (name, name_len, &key);
if (NULL == (barrier = GNUNET_CONTAINER_multihashmap_get (barrier_map, &key)))
{
GNUNET_break (0);
GNUNET_SERVER_client_keep (client);
client_ctx->barrier = barrier;
GNUNET_CONTAINER_DLL_insert_tail (barrier->head, barrier->tail, client_ctx);
- barrier->nreached++;
- if (LOCAL_QUORUM_REACHED (barrier))
- notify_task_cb (barrier, NULL);
+ }
+ barrier->nreached++;
+ if ((barrier->num_wbarriers_reached == barrier->num_wbarriers)
+ && (LOCAL_QUORUM_REACHED (barrier)))
+ {
+ barrier->status = BARRIER_STATUS_CROSSED;
+ send_barrier_status_msg (barrier, NULL);
+ notify_task_cb (barrier, NULL);
}
GNUNET_SERVER_receive_done (client, GNUNET_OK);
}
{
struct ClientCtx *client_ctx;
+ if (NULL == client)
+ return;
client_ctx = GNUNET_SERVER_client_get_user_context (client, struct ClientCtx);
if (NULL == client_ctx)
return; /* We only set user context for locally
/**
* Function to initialise barrriers component
+ *
+ * @param cfg the configuration to use for initialisation
*/
void
GST_barriers_init (struct GNUNET_CONFIGURATION_Handle *cfg)
* Function to stop the barrier service
*/
void
-GST_barriers_stop ()
+GST_barriers_destroy ()
{
GNUNET_assert (NULL != barrier_map);
GNUNET_CONTAINER_multihashmap_destroy (barrier_map);
name = GNUNET_malloc (name_len + 1);
(void) memcpy (name, msg->name, name_len);
GNUNET_CRYPTO_hash (name, name_len, &hash);
+ LOG_DEBUG ("Received BARRIER_INIT for barrier `%s'\n", name);
if (GNUNET_YES == GNUNET_CONTAINER_multihashmap_contains (barrier_map, &hash))
{
-
+
send_client_status_msg (client, name, BARRIER_STATUS_ERROR,
"A barrier with the same name already exists");
GNUNET_free (name);
if (NULL == barrier->whead) /* No further propagation */
{
barrier->status = BARRIER_STATUS_INITIALISED;
+ LOG_DEBUG ("Sending BARRIER_STATUS_INITIALISED for barrier `%s'\n",
+ barrier->name);
send_barrier_status_msg (barrier, NULL);
}else
barrier->tout_task = GNUNET_SCHEDULER_add_delayed (MESSAGE_SEND_TIMEOUT (30),
#ifndef GNUNET_SERVER_TESTBED_BARRIERS_H_
#define GNUNET_SERVER_TESTBED_BARRIERS_H_
+/**
+ * Function to initialise barrriers component
+ *
+ * @param cfg the configuration to use for initialisation
+ */
+void
+GST_barriers_init (struct GNUNET_CONFIGURATION_Handle *cfg);
+
+
+/**
+ * Function to stop the barrier service
+ */
+void
+GST_barriers_destroy ();
+
+
/**
* 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
#include "platform.h"
#include "gnunet_util_lib.h"
#include "gnunet_testbed_service.h"
+#include "test_testbed_api_barriers.h"
+
+
+/**
+ * logging short hand
+ */
+#define LOG(type,...) \
+ GNUNET_log (type, __VA_ARGS__);
/**
* Number of peers we start in this test case
*/
#define NUM_PEERS 3
+
+/**
+ * Our barrier
+ */
+struct GNUNET_TESTBED_Barrier *barrier;
+
+/**
+ * Identifier for the shutdown task
+ */
+static GNUNET_SCHEDULER_TaskIdentifier shutdown_task;
+
/**
* Result of this test case
*/
static int result;
+/**
+ * Shutdown this test case when it takes too long
+ *
+ * @param cls NULL
+ * @param tc scheduler task context
+ */
+static void
+do_shutdown (void *cls, const struct GNUNET_SCHEDULER_TaskContext *tc)
+{
+ shutdown_task = GNUNET_SCHEDULER_NO_TASK;
+ if (NULL != barrier)
+ {
+ GNUNET_TESTBED_barrier_cancel (barrier);
+ barrier = NULL;
+ }
+
+ GNUNET_SCHEDULER_shutdown ();
+}
+
+
+/**
+ * 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
+ */
+static void
+barrier_cb (void *cls,
+ const char *name,
+ struct GNUNET_TESTBED_Barrier *_barrier,
+ enum GNUNET_TESTBED_BarrierStatus status,
+ const char *emsg)
+{
+ static enum GNUNET_TESTBED_BarrierStatus old_status;
+
+ GNUNET_assert (NULL == cls);
+ GNUNET_assert (_barrier == barrier);
+ switch (status)
+ {
+ case BARRIER_STATUS_INITIALISED:
+ LOG (GNUNET_ERROR_TYPE_INFO, "Barrier initialised\n");
+ old_status = status;
+ return;
+ case BARRIER_STATUS_ERROR:
+ LOG (GNUNET_ERROR_TYPE_ERROR, "Barrier initialisation failed: %s",
+ (NULL == emsg) ? "unknown reason" : emsg);
+ barrier = NULL;
+ GNUNET_SCHEDULER_shutdown ();
+ return;
+ case BARRIER_STATUS_CROSSED:
+ LOG (GNUNET_ERROR_TYPE_INFO, "Barrier crossed\n");
+ if (old_status == BARRIER_STATUS_INITIALISED)
+ result = GNUNET_OK;
+ barrier = NULL;
+ GNUNET_SCHEDULER_shutdown ();
+ return;
+ default:
+ GNUNET_assert (0);
+ }
+}
+
+
/**
* Signature of a main function for a testcase.
*
unsigned int links_succeeded,
unsigned int links_failed)
{
+ struct GNUNET_TESTBED_Controller *c;
GNUNET_assert (NULL == cls);
if (NULL == peers_)
return;
}
GNUNET_assert (NUM_PEERS == num_peers);
-
- result = GNUNET_OK;
- GNUNET_SCHEDULER_shutdown ();
- /* shutdown_task = */
- /* GNUNET_SCHEDULER_add_delayed (GNUNET_TIME_relative_multiply */
- /* (GNUNET_TIME_UNIT_SECONDS, 300), */
- /* do_shutdown, NULL); */
+ c = GNUNET_TESTBED_run_get_controller_handle (h);
+ barrier = GNUNET_TESTBED_barrier_init (c, TEST_BARRIER_NAME, 100,
+ &barrier_cb, NULL);
+ shutdown_task =
+ GNUNET_SCHEDULER_add_delayed (GNUNET_TIME_relative_multiply
+ (GNUNET_TIME_UNIT_SECONDS,
+ 10 * (NUM_PEERS + 1)),
+ &do_shutdown, NULL);
}
result = GNUNET_SYSERR;
event_mask = 0;
- (void) GNUNET_TESTBED_test_run ("test_testbed_api_test",
+ (void) GNUNET_TESTBED_test_run ("test_testbed_api_barriers",
"test_testbed_api_barriers.conf", NUM_PEERS,
event_mask, NULL, NULL,
&test_master, NULL);
import subprocess
-import shutil
import os
import sys
from buildvars import libexecdir
test_testbed_api_barriers = './test_testbed_api_barriers'
# copy gnunet-service-test-barriers service to gnunet's libexec dir
-shutil.copy (service, libexecdir)
+ret = subprocess.call (['libtool', '--mode=install', 'install',
+ service, libexecdir],
+ shell=False, executable='libtool')
+if ret is not 0:
+ print "could not install test daemon"
+ sys.exit (ret);
# start the testcase binary
ret = subprocess.call (test_testbed_api_barriers, shell=False)
DIR = /tmp
UNIX_MATCH_UID = YES
UNIX_MATCH_GID = YES
+
+
+[testbed-barrier]
+AUTOSTART = NO
+@UNIXONLY@ PORT = 2103
+HOSTNAME = localhost
+UNIXPATH = /tmp/gnunet-service-testbed-barrier.sock
+UNIX_MATCH_UID = YES
+UNIX_MATCH_GID = YES
/**
* status. Use enumerated values of enum BarrierStatus
*/
- uint16_t status;
+ uint16_t status GNUNET_PACKED;
/**
* strlen of the barrier name
*/
- uint16_t name_len;
+ uint16_t name_len GNUNET_PACKED;
/**
* the barrier name (NULL terminated) concatenated with an error message (NULL
#include "gnunet_testbed_service.h"
#include "testbed_api.h"
+/**
+ * Logging shorthand
+ */
+#define LOG(type, ...) \
+ GNUNET_log_from (type, "testbed-api-barriers", __VA_ARGS__);
+
+/**
+ * Debug logging shorthand
+ */
+#define LOG_DEBUG(...) \
+ LOG (GNUNET_ERROR_TYPE_DEBUG, __VA_ARGS__);
+
/**
* Handle for barrier
*/
msize = ntohs (msg->header.size);
name = msg->data;
name_len = ntohs (msg->name_len);
- if ( (sizeof (struct GNUNET_TESTBED_BarrierStatusMsg) + name_len + 1 > msize)
- || ('\0' != name[name_len]) )
+ LOG_DEBUG ("Received BARRIER_STATUS msg\n");
+ if (sizeof (struct GNUNET_TESTBED_BarrierStatusMsg) + name_len + 1 > msize)
+ {
+ GNUNET_break_op (0);
+ return GNUNET_SYSERR;
+ }
+ if ('\0' != name[name_len])
{
GNUNET_break_op (0);
return GNUNET_SYSERR;
(void) memcpy (emsg, msg->data + name_len + 1, emsg_len);
}
if (NULL == barrier_map)
+ {
+ GNUNET_break_op (0);
goto cleanup;
+ }
GNUNET_CRYPTO_hash (name, name_len, &key);
barrier = GNUNET_CONTAINER_multihashmap_get (barrier_map, &key);
if (NULL == barrier)
+ {
+ GNUNET_break_op (0);
goto cleanup;
+ }
GNUNET_assert (NULL != barrier->cb);
barrier->cb (barrier->cls, name, barrier, status, emsg);
if (BARRIER_STATUS_INITIALISED == status)
GNUNET_break (0);
return NULL;
}
+ LOG_DEBUG ("Initialising barrier `%s'\n", name);
barrier = GNUNET_malloc (sizeof (struct GNUNET_TESTBED_Barrier));
barrier->c = controller;
barrier->name = GNUNET_strdup (name);
case BARRIER_STATUS_CROSSED:
h->cb (h->cls, h->name, GNUNET_OK);
goto destroy;
+ default:
+ GNUNET_break_op (0);
}
fail:
GNUNET_assert (NULL != name);
cfg_filename = getenv (ENV_TESTBED_CONFIG);
if (NULL == cfg_filename)
+ {
+ LOG (GNUNET_ERROR_TYPE_ERROR, "Are you running under testbed?\n");
return NULL;
+ }
cfg = GNUNET_CONFIGURATION_create ();
- if (GNUNET_OK != GNUNET_CONFIGURATION_load (cfg, cfg_filename));
+ if (GNUNET_OK != GNUNET_CONFIGURATION_load (cfg, cfg_filename))
{
+ LOG (GNUNET_ERROR_TYPE_ERROR, "Unable to load configuration from file `%s'\n",
+ cfg_filename);
GNUNET_CONFIGURATION_destroy (cfg);
return NULL;
}
h->cls = cls;
if (NULL == h->conn)
{
+ LOG (GNUNET_ERROR_TYPE_ERROR, "Unable to connect to local testbed-barrier service\n");
destroy_handle (h);
return NULL;
}
if (status != GNUNET_OK)
{
+ rc->cproc = NULL;
GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
_("Controller crash detected. Shutting down.\n"));
GNUNET_SCHEDULER_shutdown ();
}
+/**
+ * Obtain handle to the master controller from a testbed run. The handle
+ * returned should not be disconnected.
+ *
+ * @param h the testbed run handle
+ * @return handle to the master controller
+ */
+struct GNUNET_TESTBED_Controller *
+GNUNET_TESTBED_run_get_controller_handle (struct GNUNET_TESTBED_RunHandle *h)
+{
+ return h->c;
+}
+
+
/* end of testbed_api_testbed.c */