2 This file is part of GNUnet.
3 Copyright (C) 2008--2013 GNUnet e.V.
5 GNUnet is free software; you can redistribute it and/or modify
6 it under the terms of the GNU General Public License as published
7 by the Free Software Foundation; either version 3, or (at your
8 option) any later version.
10 GNUnet is distributed in the hope that it will be useful, but
11 WITHOUT ANY WARRANTY; without even the implied warranty of
12 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
13 General Public License for more details.
15 You should have received a copy of the GNU General Public License
16 along with GNUnet; see the file COPYING. If not, write to the
17 Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
18 Boston, MA 02110-1301, USA.
22 * @file testbed/testbed_api_barriers.c
23 * @brief API implementation for testbed barriers
24 * @author Sree Harsha Totakura <sreeharsha@totakura.in>
28 #include "gnunet_testbed_service.h"
29 #include "testbed_api.h"
30 #include "testbed_api_barriers.h"
35 #define LOG(type, ...) \
36 GNUNET_log_from (type, "testbed-api-barriers", __VA_ARGS__);
39 * Debug logging shorthand
41 #define LOG_DEBUG(...) \
42 LOG (GNUNET_ERROR_TYPE_DEBUG, __VA_ARGS__);
46 * Remove a barrier and it was the last one in the barrier hash map, destroy the
49 * @param barrier the barrier to remove
52 GNUNET_TESTBED_barrier_remove_ (struct GNUNET_TESTBED_Barrier *barrier)
54 struct GNUNET_TESTBED_Controller *c = barrier->c;
56 GNUNET_assert (NULL != c->barrier_map); /* No barriers present */
57 GNUNET_assert (GNUNET_OK ==
58 GNUNET_CONTAINER_multihashmap_remove (c->barrier_map,
61 GNUNET_free (barrier->name);
62 GNUNET_free (barrier);
63 if (0 == GNUNET_CONTAINER_multihashmap_size (c->barrier_map))
65 GNUNET_CONTAINER_multihashmap_destroy (c->barrier_map);
66 c->barrier_map = NULL;
72 * Initialise a barrier and call the given callback when the required percentage
73 * of peers (quorum) reach the barrier OR upon error.
75 * @param controller the handle to the controller
76 * @param name identification name of the barrier
77 * @param quorum the percentage of peers that is required to reach the barrier.
78 * Peers signal reaching a barrier by calling
79 * GNUNET_TESTBED_barrier_reached().
80 * @param cb the callback to call when the barrier is reached or upon error.
82 * @param cls closure for the above callback
83 * @param echo GNUNET_YES to echo the barrier crossed status message back to the
85 * @return barrier handle; NULL upon error
87 struct GNUNET_TESTBED_Barrier *
88 GNUNET_TESTBED_barrier_init_ (struct GNUNET_TESTBED_Controller *controller,
91 GNUNET_TESTBED_barrier_status_cb cb, void *cls,
94 struct GNUNET_TESTBED_BarrierInit *msg;
95 struct GNUNET_TESTBED_Barrier *barrier;
96 struct GNUNET_HashCode key;
100 GNUNET_assert (quorum <= 100);
101 GNUNET_assert (NULL != cb);
102 name_len = strlen (name);
103 GNUNET_assert (0 < name_len);
104 GNUNET_CRYPTO_hash (name, name_len, &key);
105 if (NULL == controller->barrier_map)
106 controller->barrier_map = GNUNET_CONTAINER_multihashmap_create (3, GNUNET_YES);
108 GNUNET_CONTAINER_multihashmap_contains (controller->barrier_map,
114 LOG_DEBUG ("Initialising barrier `%s'\n", name);
115 barrier = GNUNET_new (struct GNUNET_TESTBED_Barrier);
116 barrier->c = controller;
117 barrier->name = GNUNET_strdup (name);
120 barrier->echo = echo;
121 (void) memcpy (&barrier->key, &key, sizeof (struct GNUNET_HashCode));
122 GNUNET_assert (GNUNET_OK ==
123 GNUNET_CONTAINER_multihashmap_put (controller->barrier_map,
126 GNUNET_CONTAINER_MULTIHASHMAPOPTION_UNIQUE_FAST));
127 msize = name_len + sizeof (struct GNUNET_TESTBED_BarrierInit);
128 msg = GNUNET_malloc (msize);
129 msg->header.size = htons (msize);
130 msg->header.type = htons (GNUNET_MESSAGE_TYPE_TESTBED_BARRIER_INIT);
131 msg->quorum = (uint8_t) quorum;
132 (void) memcpy (msg->name, barrier->name, name_len);
133 GNUNET_TESTBED_queue_message_ (barrier->c, &msg->header);
139 * Initialise a barrier and call the given callback when the required percentage
140 * of peers (quorum) reach the barrier OR upon error.
142 * @param controller the handle to the controller
143 * @param name identification name of the barrier
144 * @param quorum the percentage of peers that is required to reach the barrier.
145 * Peers signal reaching a barrier by calling
146 * GNUNET_TESTBED_barrier_reached().
147 * @param cb the callback to call when the barrier is reached or upon error.
149 * @param cls closure for the above callback
150 * @return barrier handle; NULL upon error
152 struct GNUNET_TESTBED_Barrier *
153 GNUNET_TESTBED_barrier_init (struct GNUNET_TESTBED_Controller *controller,
156 GNUNET_TESTBED_barrier_status_cb cb, void *cls)
158 return GNUNET_TESTBED_barrier_init_ (controller,
159 name, quorum, cb, cls, GNUNET_YES);
166 * @param barrier the barrier handle
169 GNUNET_TESTBED_barrier_cancel (struct GNUNET_TESTBED_Barrier *barrier)
171 struct GNUNET_TESTBED_BarrierCancel *msg;
174 msize = sizeof (struct GNUNET_TESTBED_BarrierCancel) + strlen (barrier->name);
175 msg = GNUNET_malloc (msize);
176 msg->header.size = htons (msize);
177 msg->header.type = htons (GNUNET_MESSAGE_TYPE_TESTBED_BARRIER_CANCEL);
178 (void) memcpy (msg->name, barrier->name, strlen (barrier->name));
179 GNUNET_TESTBED_queue_message_ (barrier->c, &msg->header);
180 GNUNET_TESTBED_barrier_remove_ (barrier);
185 * Barrier wait handle
187 struct GNUNET_TESTBED_BarrierWaitHandle
190 * The name of the barrier
195 * Then configuration used for the client connection
197 struct GNUNET_CONFIGURATION_Handle *cfg;
200 * The client connection
202 struct GNUNET_CLIENT_Connection *conn;
207 struct GNUNET_CLIENT_TransmitHandle *tx;
210 * The message to transmit with tx
212 struct GNUNET_MessageHeader *msg;
215 * The barrier wait callback
217 GNUNET_TESTBED_barrier_wait_cb cb;
220 * The closure for the above callback
227 * Function to destroy barrier wait handle
229 * @param h the handle to destroy
232 destroy_handle (struct GNUNET_TESTBED_BarrierWaitHandle *h)
234 GNUNET_free (h->name);
236 GNUNET_CLIENT_notify_transmit_ready_cancel (h->tx);
238 GNUNET_CLIENT_disconnect (h->conn);
240 GNUNET_free (h->msg);
241 GNUNET_CONFIGURATION_destroy (h->cfg);
247 * Type of a function to call when we receive a message
251 * @param message received message; NULL on timeout or fatal error
254 receive_handler (void *cls,
255 const struct GNUNET_MessageHeader *message)
257 struct GNUNET_TESTBED_BarrierWaitHandle *h = cls;
258 const struct GNUNET_TESTBED_BarrierStatusMsg *msg;
266 if (GNUNET_MESSAGE_TYPE_TESTBED_BARRIER_STATUS != ntohs (message->type))
271 msize = ntohs (message->size);
272 if (msize <= sizeof (struct GNUNET_TESTBED_BarrierStatusMsg))
277 msg = (const struct GNUNET_TESTBED_BarrierStatusMsg *) message;
278 switch (ntohs (msg->status))
280 case GNUNET_TESTBED_BARRIERSTATUS_ERROR:
282 case GNUNET_TESTBED_BARRIERSTATUS_INITIALISED:
283 GNUNET_break (0); /* FIXME */
285 case GNUNET_TESTBED_BARRIERSTATUS_CROSSED:
286 h->cb (h->cls, h->name, GNUNET_OK);
293 h->cb (h->cls, h->name, GNUNET_SYSERR);
301 * Function called to notify a client about the connection
302 * begin ready to queue more data. "buf" will be
303 * NULL and "size" zero if the connection was closed for
304 * writing in the meantime.
307 * @param size number of bytes available in buf
308 * @param buf where the callee should write the message
309 * @return number of bytes written to buf
312 transmit_notify (void *cls, size_t size, void *buf)
314 struct GNUNET_TESTBED_BarrierWaitHandle *h = cls;
318 if ((0 == size) || (NULL == buf))
323 msize = htons (h->msg->size);
324 GNUNET_assert (msize <= size);
325 (void) memcpy (buf, h->msg, msize);
326 GNUNET_free (h->msg);
328 GNUNET_CLIENT_receive (h->conn, &receive_handler, h, GNUNET_TIME_UNIT_FOREVER_REL);
334 * Wait for a barrier to be crossed. This function should be called by the
335 * peers which have been started by the testbed. If the peer is not started by
336 * testbed this function may return error
338 * @param name the name of the barrier
339 * @param cb the barrier wait callback
340 * @param cls the closure for the above callback
341 * @return barrier wait handle which can be used to cancel the waiting at
342 * anytime before the callback is called. NULL upon error.
344 struct GNUNET_TESTBED_BarrierWaitHandle *
345 GNUNET_TESTBED_barrier_wait (const char *name,
346 GNUNET_TESTBED_barrier_wait_cb cb,
349 struct GNUNET_TESTBED_BarrierWait *msg;
350 struct GNUNET_CONFIGURATION_Handle *cfg;
351 struct GNUNET_TESTBED_BarrierWaitHandle *h;
356 GNUNET_assert (NULL != cb);
357 GNUNET_assert (NULL != name);
358 cfg_filename = getenv (ENV_TESTBED_CONFIG);
359 if (NULL == cfg_filename)
361 LOG (GNUNET_ERROR_TYPE_ERROR, "Are you running under testbed?\n");
364 cfg = GNUNET_CONFIGURATION_create ();
365 if (GNUNET_OK != GNUNET_CONFIGURATION_load (cfg, cfg_filename))
367 LOG (GNUNET_ERROR_TYPE_ERROR, "Unable to load configuration from file `%s'\n",
369 GNUNET_CONFIGURATION_destroy (cfg);
372 h = GNUNET_new (struct GNUNET_TESTBED_BarrierWaitHandle);
373 h->name = GNUNET_strdup (name);
375 h->conn = GNUNET_CLIENT_connect ("testbed-barrier", h->cfg);
380 LOG (GNUNET_ERROR_TYPE_ERROR,
381 "Unable to connect to local testbed-barrier service\n");
385 name_len = strlen (name);
386 msize = sizeof (struct GNUNET_TESTBED_BarrierWait) + name_len;
387 msg = GNUNET_malloc (msize);
388 msg->header.type = htons (GNUNET_MESSAGE_TYPE_TESTBED_BARRIER_WAIT);
389 msg->header.size = htons (msize);
390 (void) memcpy (msg->name, name, name_len);
391 h->msg = &msg->header;
393 GNUNET_CLIENT_notify_transmit_ready (h->conn, msize,
394 GNUNET_TIME_UNIT_FOREVER_REL,
403 * Cancel a barrier wait handle
405 * @param h the barrier wait handle
408 GNUNET_TESTBED_barrier_wait_cancel (struct GNUNET_TESTBED_BarrierWaitHandle *h)
413 /* end of testbed_api_barriers.c */