aboutsummaryrefslogtreecommitdiff
path: root/src
diff options
context:
space:
mode:
authorSree Harsha Totakura <totakura@in.tum.de>2013-08-30 14:55:13 +0000
committerSree Harsha Totakura <totakura@in.tum.de>2013-08-30 14:55:13 +0000
commit5e1efe185cf484018f53dd33d64e546ac042fdee (patch)
treee1369e8e1a239426d4ba2d81bb31571bbd4f82eb /src
parent7d8d536bbaa0f72587552af517f643e3c05e7a6f (diff)
downloadgnunet-5e1efe185cf484018f53dd33d64e546ac042fdee.tar.gz
gnunet-5e1efe185cf484018f53dd33d64e546ac042fdee.zip
- towards testbed barriers
Diffstat (limited to 'src')
-rw-r--r--src/include/gnunet_protocols.h19
-rw-r--r--src/include/gnunet_testbed_service.h57
-rw-r--r--src/testbed/Makefile.am6
-rw-r--r--src/testbed/gnunet-service-testbed.c14
-rw-r--r--src/testbed/gnunet-service-testbed.h7
-rw-r--r--src/testbed/gnunet-service-testbed_barriers.c512
-rw-r--r--src/testbed/gnunet-service-testbed_peers.c9
-rw-r--r--src/testbed/testbed.h78
-rw-r--r--src/testbed/testbed_api.c7
-rw-r--r--src/testbed/testbed_api.h16
-rw-r--r--src/testbed/testbed_api_barriers.c221
11 files changed, 935 insertions, 11 deletions
diff --git a/src/include/gnunet_protocols.h b/src/include/gnunet_protocols.h
index 04745c5f9..a52727f4d 100644
--- a/src/include/gnunet_protocols.h
+++ b/src/include/gnunet_protocols.h
@@ -1566,10 +1566,27 @@ extern "C"
1566#define GNUNET_MESSAGE_TYPE_TESTBED_MANAGE_PEER_SERVICE 483 1566#define GNUNET_MESSAGE_TYPE_TESTBED_MANAGE_PEER_SERVICE 483
1567 1567
1568/** 1568/**
1569 * Message to initialise a barrier. Messages of these type are flooded to all
1570 * sub-controllers
1571 */
1572#define GNUNET_MESSAGE_TYPE_TESTBED_BARRIER_INIT 484
1573
1574/**
1575 * Message for signalling status of a barrier
1576 */
1577#define GNUNET_MESSAGE_TYPE_TESTBED_BARRIER_STATUS 485
1578
1579/**
1580 * Message sent by a peer when it has reached a barrier and is waiting for it to
1581 * be crossed
1582 */
1583#define GNUNET_MESSAGE_TYPE_TESTBED_BARRIER_WAIT 486
1584
1585/**
1569 * Not really a message, but for careful checks on the testbed messages; Should 1586 * Not really a message, but for careful checks on the testbed messages; Should
1570 * always be the maximum and never be used to send messages with this type 1587 * always be the maximum and never be used to send messages with this type
1571 */ 1588 */
1572#define GNUNET_MESSAGE_TYPE_TESTBED_MAX 484 1589#define GNUNET_MESSAGE_TYPE_TESTBED_MAX 487
1573 1590
1574/** 1591/**
1575 * The initialization message towards gnunet-testbed-helper 1592 * The initialization message towards gnunet-testbed-helper
diff --git a/src/include/gnunet_testbed_service.h b/src/include/gnunet_testbed_service.h
index 6249707d9..173aa76b3 100644
--- a/src/include/gnunet_testbed_service.h
+++ b/src/include/gnunet_testbed_service.h
@@ -1471,6 +1471,63 @@ GNUNET_TESTBED_test_run (const char *testname,
1471 void *test_master_cls); 1471 void *test_master_cls);
1472 1472
1473 1473
1474/**
1475 * Opaque handle for barrier
1476 */
1477struct GNUNET_TESTBED_Barrier;
1478
1479
1480/**
1481 * Functions of this type are to be given as callback argument to
1482 * GNUNET_TESTBED_barrier_init(). The callback will be called when status
1483 * information is available for the barrier.
1484 *
1485 * @param cls the closure given to GNUNET_TESTBED_barrier_init()
1486 * @param name the name of the barrier
1487 * @param barrier the barrier handle
1488 * @param status status of the barrier; GNUNET_OK if the barrier is crossed;
1489 * GNUNET_SYSERR upon error
1490 * @param emsg if the status were to be GNUNET_SYSERR, this parameter has the
1491 * error messsage
1492 */
1493typedef void (*GNUNET_TESTBED_barrier_status_cb) (void *cls,
1494 const char *name,
1495 struct GNUNET_TESTBED_Barrier
1496 *barrier,
1497 int status,
1498 const char *emsg);
1499
1500
1501/**
1502 * Initialise a barrier and call the given callback when the required percentage
1503 * of peers (quorum) reach the barrier.
1504 *
1505 * @param controller the handle to the controller
1506 * @param name identification name of the barrier
1507 * @param quorum the percentage of peers that is required to reach the barrier.
1508 * Peers signal reaching a barrier by calling
1509 * GNUNET_TESTBED_barrier_reached().
1510 * @param cb the callback to call when the barrier is reached or upon error.
1511 * Cannot be NULL.
1512 * @param cls closure for the above callback
1513 * @return barrier handle
1514 */
1515struct GNUNET_TESTBED_Barrier *
1516GNUNET_TESTBED_barrier_init (struct GNUNET_TESTBED_Controller *controller,
1517 const char *name,
1518 unsigned int quorum,
1519 GNUNET_TESTBED_barrier_status_cb cb, void *cls);
1520
1521
1522/**
1523 * Cancel a barrier.
1524 *
1525 * @param barrier the barrier handle
1526 */
1527void
1528GNUNET_TESTBED_barrier_cancel (struct GNUNET_TESTBED_Barrier *barrier);
1529
1530
1474#if 0 /* keep Emacsens' auto-indent happy */ 1531#if 0 /* keep Emacsens' auto-indent happy */
1475{ 1532{
1476#endif 1533#endif
diff --git a/src/testbed/Makefile.am b/src/testbed/Makefile.am
index 3aa88453b..f07639b8a 100644
--- a/src/testbed/Makefile.am
+++ b/src/testbed/Makefile.am
@@ -39,7 +39,8 @@ gnunet_service_testbed_SOURCES = \
39 gnunet-service-testbed_oc.c \ 39 gnunet-service-testbed_oc.c \
40 gnunet-service-testbed_cpustatus.c \ 40 gnunet-service-testbed_cpustatus.c \
41 gnunet-service-testbed_meminfo.c \ 41 gnunet-service-testbed_meminfo.c \
42 gnunet-service-testbed_meminfo.h 42 gnunet-service-testbed_meminfo.h \
43 gnunet-service-testbed_barriers.c
43gnunet_service_testbed_LDADD = $(XLIB) \ 44gnunet_service_testbed_LDADD = $(XLIB) \
44 $(top_builddir)/src/util/libgnunetutil.la \ 45 $(top_builddir)/src/util/libgnunetutil.la \
45 $(top_builddir)/src/core/libgnunetcore.la \ 46 $(top_builddir)/src/core/libgnunetcore.la \
@@ -98,7 +99,8 @@ libgnunettestbed_la_SOURCES = \
98 testbed_api_testbed.c \ 99 testbed_api_testbed.c \
99 testbed_api_test.c \ 100 testbed_api_test.c \
100 testbed_api_topology.c testbed_api_topology.h \ 101 testbed_api_topology.c testbed_api_topology.h \
101 testbed_api_sd.c testbed_api_sd.h 102 testbed_api_sd.c testbed_api_sd.h \
103 testbed_api_barriers.c
102libgnunettestbed_la_LIBADD = $(XLIB) \ 104libgnunettestbed_la_LIBADD = $(XLIB) \
103 $(top_builddir)/src/core/libgnunetcore.la \ 105 $(top_builddir)/src/core/libgnunetcore.la \
104 $(top_builddir)/src/statistics/libgnunetstatistics.la \ 106 $(top_builddir)/src/statistics/libgnunetstatistics.la \
diff --git a/src/testbed/gnunet-service-testbed.c b/src/testbed/gnunet-service-testbed.c
index de038eeae..3b01bc504 100644
--- a/src/testbed/gnunet-service-testbed.c
+++ b/src/testbed/gnunet-service-testbed.c
@@ -34,7 +34,7 @@
34/** 34/**
35 * Our configuration 35 * Our configuration
36 */ 36 */
37struct GNUNET_CONFIGURATION_Handle *our_config; 37struct GNUNET_CONFIGURATION_Handle *GST_config;
38 38
39/** 39/**
40 * The master context; generated with the first INIT message 40 * The master context; generated with the first INIT message
@@ -516,11 +516,11 @@ handle_init (void *cls, struct GNUNET_SERVER_Client *client,
516 } 516 }
517 ss_str = NULL; 517 ss_str = NULL;
518 ss = NULL; 518 ss = NULL;
519 if (GNUNET_OK == GNUNET_CONFIGURATION_get_value_string (our_config, "TESTBED", 519 if (GNUNET_OK == GNUNET_CONFIGURATION_get_value_string (GST_config, "TESTBED",
520 "SHARED_SERVICES", 520 "SHARED_SERVICES",
521 &ss_str)) 521 &ss_str))
522 { 522 {
523 ss = parse_shared_services (ss_str, our_config); 523 ss = parse_shared_services (ss_str, GST_config);
524 GNUNET_free (ss_str); 524 GNUNET_free (ss_str);
525 ss_str = NULL; 525 ss_str = NULL;
526 } 526 }
@@ -546,7 +546,7 @@ handle_init (void *cls, struct GNUNET_SERVER_Client *client,
546 host = 546 host =
547 GNUNET_TESTBED_host_create_with_id (GST_context->host_id, 547 GNUNET_TESTBED_host_create_with_id (GST_context->host_id,
548 GST_context->master_ip, NULL, 548 GST_context->master_ip, NULL,
549 our_config, 0); 549 GST_config, 0);
550 host_list_add (host); 550 host_list_add (host);
551 LOG_DEBUG ("Created master context with host ID: %u\n", GST_context->host_id); 551 LOG_DEBUG ("Created master context with host ID: %u\n", GST_context->host_id);
552 GNUNET_SERVER_receive_done (client, GNUNET_OK); 552 GNUNET_SERVER_receive_done (client, GNUNET_OK);
@@ -824,7 +824,7 @@ shutdown_task (void *cls, const struct GNUNET_SCHEDULER_TaskContext *tc)
824 GNUNET_free (mq_entry); 824 GNUNET_free (mq_entry);
825 } 825 }
826 GNUNET_free_non_null (hostname); 826 GNUNET_free_non_null (hostname);
827 GNUNET_CONFIGURATION_destroy (our_config); 827 GNUNET_CONFIGURATION_destroy (GST_config);
828 /* Free hello cache */ 828 /* Free hello cache */
829 GST_cache_clear (); 829 GST_cache_clear ();
830 GNUNET_TESTBED_operation_queue_destroy_ (GST_opq_openfds); 830 GNUNET_TESTBED_operation_queue_destroy_ (GST_opq_openfds);
@@ -929,7 +929,7 @@ testbed_run (void *cls, struct GNUNET_SERVER_Handle *server,
929 GNUNET_assert (GNUNET_OK == 929 GNUNET_assert (GNUNET_OK ==
930 GNUNET_CONFIGURATION_get_value_string (cfg, "testbed", 930 GNUNET_CONFIGURATION_get_value_string (cfg, "testbed",
931 "HOSTNAME", &hostname)); 931 "HOSTNAME", &hostname));
932 our_config = GNUNET_CONFIGURATION_dup (cfg); 932 GST_config = GNUNET_CONFIGURATION_dup (cfg);
933 GNUNET_SERVER_add_handlers (server, message_handlers); 933 GNUNET_SERVER_add_handlers (server, message_handlers);
934 GNUNET_SERVER_disconnect_notify (server, &client_disconnect_cb, NULL); 934 GNUNET_SERVER_disconnect_notify (server, &client_disconnect_cb, NULL);
935 shutdown_task_id = 935 shutdown_task_id =
@@ -937,7 +937,7 @@ testbed_run (void *cls, struct GNUNET_SERVER_Handle *server,
937 GNUNET_SCHEDULER_PRIORITY_IDLE, 937 GNUNET_SCHEDULER_PRIORITY_IDLE,
938 &shutdown_task, NULL); 938 &shutdown_task, NULL);
939 LOG_DEBUG ("Testbed startup complete\n"); 939 LOG_DEBUG ("Testbed startup complete\n");
940 GST_stats_init (our_config); 940 GST_stats_init (GST_config);
941} 941}
942 942
943 943
diff --git a/src/testbed/gnunet-service-testbed.h b/src/testbed/gnunet-service-testbed.h
index 38d1ae80e..55861faba 100644
--- a/src/testbed/gnunet-service-testbed.h
+++ b/src/testbed/gnunet-service-testbed.h
@@ -412,7 +412,7 @@ struct HandlerContext_ShutdownPeers
412/** 412/**
413 * Our configuration 413 * Our configuration
414 */ 414 */
415extern struct GNUNET_CONFIGURATION_Handle *our_config; 415extern struct GNUNET_CONFIGURATION_Handle *GST_config;
416 416
417/** 417/**
418 * The master context; generated with the first INIT message 418 * The master context; generated with the first INIT message
@@ -455,6 +455,11 @@ const extern struct GNUNET_TIME_Relative GST_timeout;
455extern unsigned int GST_peer_list_size; 455extern unsigned int GST_peer_list_size;
456 456
457/** 457/**
458 * The current number of peers running locally under this controller
459 */
460extern unsigned int GST_num_local_peers;
461
462/**
458 * The size of the host list 463 * The size of the host list
459 */ 464 */
460extern unsigned int GST_host_list_size; 465extern unsigned int GST_host_list_size;
diff --git a/src/testbed/gnunet-service-testbed_barriers.c b/src/testbed/gnunet-service-testbed_barriers.c
new file mode 100644
index 000000000..079096d86
--- /dev/null
+++ b/src/testbed/gnunet-service-testbed_barriers.c
@@ -0,0 +1,512 @@
1/*
2 This file is part of GNUnet.
3 (C) 2008--2013 Christian Grothoff (and other contributing authors)
4
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.
9
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.
14
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., 59 Temple Place - Suite 330,
18 Boston, MA 02111-1307, USA.
19*/
20
21/**
22 * @file testbed/gnunet-service-testbed_barriers.c
23 * @brief barrier handling at the testbed controller
24 * @author Sree Harsha Totakura <sreeharsha@totakura.in>
25 */
26
27#include "gnunet-service-testbed.h"
28
29/**
30 * timeout for outgoing message transmissions in seconds
31 */
32#define MESSAGE_SEND_TIMEOUT(s) \
33 GNUNET_TIME_relative_multiply (GNUNET_TIME_UNIT_SECONDS, s)
34
35
36/**
37 * Barrier
38 */
39struct Barrier;
40
41
42/**
43 * Message queue for transmitting messages
44 */
45struct MessageQueue
46{
47 /**
48 * next pointer for DLL
49 */
50 struct MessageQueue *next;
51
52 /**
53 * prev pointer for DLL
54 */
55 struct MessageQueue *prev;
56
57 /**
58 * The message to be sent
59 */
60 struct GNUNET_MessageHeader *msg;
61};
62
63/**
64 * Context to be associated with each client
65 */
66struct ClientCtx
67{
68 /**
69 * The barrier this client is waiting for
70 */
71 struct Barrier *barrier;
72
73 /**
74 * DLL next ptr
75 */
76 struct ClientCtx *next;
77
78 /**
79 * DLL prev ptr
80 */
81 struct ClientCtx *prev;
82
83 /**
84 * The client handle
85 */
86 struct GNUNET_SERVER_Client *client;
87
88 /**
89 * the transmission handle
90 */
91 struct GNUNET_SERVER_TransmitHandle *tx;
92
93 /**
94 * message queue head
95 */
96 struct MessageQueue *mq_head;
97
98 /**
99 * message queue tail
100 */
101 struct MessageQueue *mq_tail;
102};
103
104
105/**
106 * Barrier
107 */
108struct Barrier
109{
110 /**
111 * The hashcode of the barrier name
112 */
113 struct GNUNET_HashCode hash;
114
115 /**
116 * The name of the barrier
117 */
118 char *name;
119
120 /**
121 * DLL head for the list of clients waiting for this barrier
122 */
123 struct ClientCtx *head;
124
125 /**
126 * DLL tail for the list of clients waiting for this barrier
127 */
128 struct ClientCtx *tail;
129
130 /**
131 * Number of peers which have reached this barrier
132 */
133 unsigned int nreached;
134
135 /**
136 * Number of slaves we have initialised this barrier
137 */
138 unsigned int nslaves;
139
140 /**
141 * Quorum percentage to be reached
142 */
143 uint8_t quorum;
144
145 /**
146 * Was there a timeout while propagating initialisation
147 */
148 uint8_t timedout;
149};
150
151
152/**
153 * Hashtable handle for storing initialised barriers
154 */
155static struct GNUNET_CONTAINER_MultiHashMap *barrier_map;
156
157/**
158 * Service context
159 */
160static struct GNUNET_SERVICE_Context *ctx;
161
162
163/**
164 * Function called to notify a client about the connection
165 * begin ready to queue more data. "buf" will be
166 * NULL and "size" zero if the connection was closed for
167 * writing in the meantime.
168 *
169 * @param cls client context
170 * @param size number of bytes available in buf
171 * @param buf where the callee should write the message
172 * @return number of bytes written to buf
173 */
174static size_t
175transmit_ready_cb (void *cls, size_t size, void *buf)
176{
177 struct ClientCtx *ctx = cls;
178 struct GNUNET_SERVER_Client *client = ctx->client;
179 struct MessageQueue *mq;
180 struct GNUNET_MessageHeader *msg;
181 size_t wrote;
182
183 ctx->tx = NULL;
184 wrote = 0;
185 if ((0 == size) || (NULL == buf))
186 {
187 GNUNET_assert (NULL != ctx->client);
188 GNUNET_SERVER_client_drop (ctx->client);
189 ctx->client = NULL;
190 return 0;
191 }
192 mq = ctx->mq_head;
193 msg = mq->msg;
194 wrote = ntohs (msg->size);
195 GNUNET_assert (size >= wrote);
196 (void) memcpy (buf, msg, wrote);
197 GNUNET_CONTAINER_DLL_remove (ctx->mq_head, ctx->mq_tail, mq);
198 GNUNET_free (mq->msg);
199 GNUNET_free (mq);
200 if (NULL != (mq = ctx->mq_head))
201 ctx->tx = GNUNET_SERVER_notify_transmit_ready (client, ntohs (msg->size),
202 MESSAGE_SEND_TIMEOUT (30),
203 &transmit_ready_cb, ctx);
204 return wrote;
205}
206
207
208/**
209 * Queue a message into a clients message queue
210 *
211 * @param ctx the context associated with the client
212 * @param msg the message to queue. Will be consumed
213 * @param suspended is the client suspended at the time of calling queue_message
214 */
215static void
216queue_message (struct ClientCtx *ctx, struct GNUNET_MessageHeader *msg)
217{
218 struct MessageQueue *mq;
219 struct GNUNET_SERVER_Client *client = ctx->client;
220
221 mq = GNUNET_malloc (sizeof (struct MessageQueue));
222 mq->msg = msg;
223 GNUNET_CONTAINER_DLL_insert_tail (ctx->mq_head, ctx->mq_tail, mq);
224 if (NULL == ctx->tx)
225 ctx->tx = GNUNET_SERVER_notify_transmit_ready (client, ntohs (msg->size),
226 MESSAGE_SEND_TIMEOUT (30),
227 &transmit_ready_cb, ctx);
228}
229
230
231#if 0
232/**
233 * Function to remove a barrier from the barrier map and cleanup resources
234 * occupied by a barrier
235 *
236 * @param barrier the barrier handle
237 */
238static void
239remove_barrier (struct Barrier *barrier)
240{
241 GNUNET_assert (GNUNET_YES == GNUNET_CONTAINER_multihashmap_remove (barrier_map,
242 &barrier->hash,
243 barrier));
244 GNUNET_free (barrier->name);
245 GNUNET_free (barrier);
246}
247
248
249/**
250 * Function called upon timeout while waiting for a response from the
251 * subcontrollers to barrier init message
252 *
253 * @param
254 * @return
255 */
256static void
257fwd_tout_barrier_init (void *cls, const struct GNUNET_SCHEDULER_TaskContext *tc)
258{
259 struct ForwardedOperationContext *foctx = cls;
260 struct Barrier *barrier = foctx->cls;
261
262 barrier->nslaves--;
263 barrier->timedout = GNUNET_YES;
264 if (0 == barrier->nslaves)
265 {
266 GST_send_operation_fail_msg (foctx->client, foctx->operation_id,
267 "Timeout while contacting a slave controller");
268 remove_barrier (barrier);
269 }
270}
271#endif
272
273/**
274 * Task for sending barrier crossed notifications to waiting client
275 *
276 * @param cls the barrier which is crossed
277 * @param tc scheduler task context
278 */
279static void
280notify_task_cb (void *cls, const struct GNUNET_SCHEDULER_TaskContext *tc)
281{
282 struct Barrier *barrier = cls;
283 struct ClientCtx *client_ctx;
284 struct GNUNET_TESTBED_BarrierStatus *msg;
285 struct GNUNET_MessageHeader *dup_msg;
286 uint16_t name_len;
287 uint16_t msize;
288
289 name_len = strlen (barrier->name) + 1;
290 msize = sizeof (struct GNUNET_TESTBED_BarrierStatus) + name_len;
291 msg = GNUNET_malloc (msize);
292 msg->header.size = htons (msize);
293 msg->header.type = htons (GNUNET_MESSAGE_TYPE_TESTBED_BARRIER_STATUS);
294 msg->status = 0;
295 msg->name_len = htons (name_len);
296 (void) memcpy (msg->data, barrier->name, name_len);
297 msg->data[name_len] = '\0';
298 while (NULL != (client_ctx = barrier->head))
299 {
300 dup_msg = GNUNET_copy_message (&msg->header);
301 queue_message (client_ctx, dup_msg);
302 GNUNET_CONTAINER_DLL_remove (barrier->head, barrier->tail, client_ctx);
303 GNUNET_SERVER_client_set_user_context_ (client_ctx->client, NULL, 0);
304 GNUNET_free (client_ctx);
305 }
306}
307
308
309/**
310 * Message handler for GNUNET_MESSAGE_TYPE_TESTBED_BARRIER_WAIT messages. This
311 * message should come from peers or a shared helper service using the
312 * testbed-barrier client API (@see gnunet_testbed_barrier_service.h)
313 *
314 * This handler is queued in the main service and will handle the messages sent
315 * either from the testbed driver or from a high level controller
316 *
317 * @param cls NULL
318 * @param client identification of the client
319 * @param message the actual message
320 */
321static void
322handle_barrier_wait (void *cls, struct GNUNET_SERVER_Client *client,
323 const struct GNUNET_MessageHeader *message)
324{
325 const struct GNUNET_TESTBED_BarrierWait *msg;
326 struct Barrier *barrier;
327 char *name;
328 struct ClientCtx *client_ctx;
329 struct GNUNET_HashCode key;
330 size_t name_len;
331 uint16_t msize;
332
333 msize = ntohs (message->size);
334 if (msize <= sizeof (struct GNUNET_TESTBED_BarrierWait))
335 {
336 GNUNET_break_op (0);
337 GNUNET_SERVER_receive_done (client, GNUNET_SYSERR);
338 return;
339 }
340 if (NULL == barrier_map)
341 {
342 GNUNET_break (0);
343 GNUNET_SERVER_receive_done (client, GNUNET_SYSERR);
344 return;
345 }
346 msg = (const struct GNUNET_TESTBED_BarrierWait *) message;
347 name_len = msize - sizeof (struct GNUNET_TESTBED_BarrierWait);
348 name = GNUNET_malloc (name_len + 1);
349 name[name_len] = '\0';
350 (void) memcpy (name, msg->name, name_len);
351 GNUNET_CRYPTO_hash (name, name_len - 1, &key);
352 if (NULL == (barrier = GNUNET_CONTAINER_multihashmap_get (barrier_map, &key)))
353 {
354 GNUNET_break (0);
355 GNUNET_SERVER_receive_done (client, GNUNET_SYSERR);
356 GNUNET_free (name);
357 return;
358 }
359 client_ctx = GNUNET_SERVER_client_get_user_context (client, struct ClientCtx);
360 if (NULL == client_ctx)
361 {
362 client_ctx = GNUNET_malloc (sizeof (struct ClientCtx));
363 client_ctx->client = client;
364 GNUNET_SERVER_client_keep (client);
365 client_ctx->barrier = barrier;
366 GNUNET_CONTAINER_DLL_insert_tail (barrier->head, barrier->tail, client_ctx);
367 barrier->nreached++;
368 if ((barrier->quorum * GST_num_local_peers) <= (barrier->nreached * 100))
369 notify_task_cb (barrier, NULL);
370 }
371 GNUNET_SERVER_receive_done (client, GNUNET_OK);
372}
373
374
375/**
376 * Functions with this signature are called whenever a client
377 * is disconnected on the network level.
378 *
379 * @param cls closure
380 * @param client identification of the client; NULL
381 * for the last call when the server is destroyed
382 */
383static void
384disconnect_cb (void *cls, struct GNUNET_SERVER_Client *client)
385{
386 struct ClientCtx *client_ctx;
387 struct Barrier *barrier;
388
389 client_ctx = GNUNET_SERVER_client_get_user_context (client, struct ClientCtx);
390 if (NULL == client_ctx)
391 return;
392 barrier = client_ctx->barrier;
393 GNUNET_CONTAINER_DLL_remove (barrier->head, barrier->tail, client_ctx);
394 if (NULL != client_ctx->tx)
395 GNUNET_SERVER_notify_transmit_ready_cancel (client_ctx->tx);
396
397}
398
399
400/**
401 * Function to initialise barrriers component
402 */
403void
404GST_barriers_init (struct GNUNET_CONFIGURATION_Handle *cfg)
405{
406 static const struct GNUNET_SERVER_MessageHandler message_handlers[] = {
407 {&handle_barrier_wait, NULL, GNUNET_MESSAGE_TYPE_TESTBED_BARRIER_WAIT, 0},
408 {NULL, NULL, 0, 0}
409 };
410 struct GNUNET_SERVER_Handle *srv;
411
412 barrier_map = GNUNET_CONTAINER_multihashmap_create (3, GNUNET_YES);
413 ctx = GNUNET_SERVICE_start ("testbed-barrier", cfg,
414 GNUNET_SERVICE_OPTION_MANUAL_SHUTDOWN);
415 srv = GNUNET_SERVICE_get_server (ctx);
416 GNUNET_SERVER_add_handlers (srv, message_handlers);
417 GNUNET_SERVER_disconnect_notify (srv, &disconnect_cb, NULL);
418}
419
420
421/**
422 * Function to stop the barrier service
423 */
424void
425GST_barriers_stop ()
426{
427 GNUNET_assert (NULL != ctx);
428 GNUNET_SERVICE_stop (ctx);
429}
430
431
432/**
433 * Message handler for GNUNET_MESSAGE_TYPE_TESTBED_BARRIER_INIT messages. This
434 * message should always come from a parent controller or the testbed API if we
435 * are the root controller.
436 *
437 * This handler is queued in the main service and will handle the messages sent
438 * either from the testbed driver or from a high level controller
439 *
440 * @param cls NULL
441 * @param client identification of the client
442 * @param message the actual message
443 */
444void
445GST_handle_barrier_init (void *cls, struct GNUNET_SERVER_Client *client,
446 const struct GNUNET_MessageHeader *message)
447{
448 const struct GNUNET_TESTBED_BarrierInit *msg;
449 const char *name;
450 struct Barrier *barrier;
451 struct Slave *slave;
452 struct GNUNET_HashCode hash;
453 size_t name_len;
454 uint64_t op_id;
455 unsigned int cnt;
456 uint16_t msize;
457
458 if (NULL == GST_context)
459 {
460 GNUNET_break_op (0);
461 GNUNET_SERVER_receive_done (client, GNUNET_SYSERR);
462 return;
463 }
464 if (client != GST_context->client)
465 {
466 GNUNET_break_op (0);
467 GNUNET_SERVER_receive_done (client, GNUNET_SYSERR);
468 return;
469 }
470 msize = ntohs (message->size);
471 if (msize <= sizeof (struct GNUNET_TESTBED_BarrierInit))
472 {
473 GNUNET_break_op (0);
474 GNUNET_SERVER_receive_done (client, GNUNET_SYSERR);
475 return;
476 }
477 msg = (const struct GNUNET_TESTBED_BarrierInit *) message;
478 op_id = GNUNET_ntohll (msg->op_id);
479 name = msg->name;
480 name_len = (size_t) msize - sizeof (struct GNUNET_TESTBED_BarrierInit);
481 GNUNET_CRYPTO_hash (name, name_len, &hash);
482 if (GNUNET_YES == GNUNET_CONTAINER_multihashmap_contains (barrier_map, &hash))
483 {
484 GST_send_operation_fail_msg (client, op_id, "Barrier already initialised");
485 GNUNET_SERVER_receive_done (client, GNUNET_OK);
486 return;
487 }
488 barrier = GNUNET_malloc (sizeof (struct Barrier));
489 (void) memcpy (&barrier->hash, &hash, sizeof (struct GNUNET_HashCode));
490 barrier->quorum = msg->quorum;
491 barrier->name = GNUNET_malloc (name_len + 1);
492 barrier->name[name_len] = '\0';
493 (void) memcpy (barrier->name, name, name_len);
494 GNUNET_assert (GNUNET_OK ==
495 GNUNET_CONTAINER_multihashmap_put (barrier_map,
496 &barrier->hash,
497 barrier,
498 GNUNET_CONTAINER_MULTIHASHMAPOPTION_UNIQUE_FAST));
499 GNUNET_SERVER_receive_done (client, GNUNET_OK);
500 /* Propagate barrier init to subcontrollers */
501 for (cnt = 0; cnt < GST_slave_list_size; cnt++)
502 {
503 if (NULL == (slave = GST_slave_list[cnt]))
504 continue;
505 if (NULL == slave->controller)
506 {
507 GNUNET_break (0);/* May happen when we are connecting to the controller */
508 continue;
509 }
510 GNUNET_break (0); /* FIXME */
511 }
512}
diff --git a/src/testbed/gnunet-service-testbed_peers.c b/src/testbed/gnunet-service-testbed_peers.c
index ece0e83e9..1792373a3 100644
--- a/src/testbed/gnunet-service-testbed_peers.c
+++ b/src/testbed/gnunet-service-testbed_peers.c
@@ -35,6 +35,11 @@
35 */ 35 */
36struct Peer **GST_peer_list; 36struct Peer **GST_peer_list;
37 37
38/**
39 * The current number of peers running locally under this controller
40 */
41unsigned int GST_num_local_peers;
42
38 43
39/** 44/**
40 * Context information to manage peers' services 45 * Context information to manage peers' services
@@ -162,6 +167,8 @@ peer_list_add (struct Peer *peer)
162 GST_array_grow_large_enough (GST_peer_list, GST_peer_list_size, peer->id); 167 GST_array_grow_large_enough (GST_peer_list, GST_peer_list_size, peer->id);
163 GNUNET_assert (NULL == GST_peer_list[peer->id]); 168 GNUNET_assert (NULL == GST_peer_list[peer->id]);
164 GST_peer_list[peer->id] = peer; 169 GST_peer_list[peer->id] = peer;
170 if (GNUNET_NO == peer->is_remote)
171 GST_num_local_peers++;
165} 172}
166 173
167 174
@@ -176,6 +183,8 @@ peer_list_remove (struct Peer *peer)
176 unsigned int orig_size; 183 unsigned int orig_size;
177 uint32_t id; 184 uint32_t id;
178 185
186 if (GNUNET_NO == peer->is_remote)
187 GST_num_local_peers--;
179 GST_peer_list[peer->id] = NULL; 188 GST_peer_list[peer->id] = NULL;
180 orig_size = GST_peer_list_size; 189 orig_size = GST_peer_list_size;
181 while (GST_peer_list_size >= LIST_GROW_STEP) 190 while (GST_peer_list_size >= LIST_GROW_STEP)
diff --git a/src/testbed/testbed.h b/src/testbed/testbed.h
index 66f8ddb17..3b159591d 100644
--- a/src/testbed/testbed.h
+++ b/src/testbed/testbed.h
@@ -768,6 +768,84 @@ struct GNUNET_TESTBED_ManagePeerServiceMessage
768}; 768};
769 769
770 770
771/**
772 * Message to initialise a barrier
773 */
774struct GNUNET_TESTBED_BarrierInit
775{
776 /**
777 * Type is GNUNET_MESSAGE_TYPE_TESTBED_BARRIER_INIT
778 */
779 struct GNUNET_MessageHeader header;
780
781 /**
782 * Unused. Only of alignment.
783 */
784 uint32_t unused;
785
786 /**
787 * The operation id
788 */
789 uint64_t op_id;
790
791 /**
792 * The quorum percentage needed for crossing the barrier
793 */
794 uint8_t quorum;
795
796 /**
797 * name of the barrier. Non NULL-terminated.
798 */
799 char name[0];
800};
801
802
803/**
804 * Message for signalling status changes of a barrier
805 */
806struct GNUNET_TESTBED_BarrierStatus
807{
808 /**
809 * Type is GNUNET_MESSAGE_TYPE_TESTBED_BARRIER_STATUS
810 */
811 struct GNUNET_MessageHeader header;
812
813 /**
814 * status. 0 to signal success (barrier is crossed). 1 for error.
815 */
816 uint16_t status;
817
818 /**
819 * strlen of the barrier name
820 */
821 uint16_t name_len;
822
823 /**
824 * the barrier name (NULL terminated) concatenated with an error message (NULL
825 * terminated) if the status were to indicate an error
826 */
827 char data[0];
828};
829
830
831/**
832 * Message sent from peers to the testbed-barrier service to indicate that they
833 * have reached a barrier and are waiting for it to be crossed
834 */
835struct GNUNET_TESTBED_BarrierWait
836{
837 /**
838 * Type is GNUNET_MESSAGE_TYPE_TESTBED_BARRIER_WAIT
839 */
840 struct GNUNET_MessageHeader header;
841
842 /**
843 * The name of the barrier they have reached. Non-NULL terminated.
844 */
845 char name[0];
846};
847
848
771GNUNET_NETWORK_STRUCT_END 849GNUNET_NETWORK_STRUCT_END
772#endif 850#endif
773/* end of testbed.h */ 851/* end of testbed.h */
diff --git a/src/testbed/testbed_api.c b/src/testbed/testbed_api.c
index 48b7fe189..0a109aa7f 100644
--- a/src/testbed/testbed_api.c
+++ b/src/testbed/testbed_api.c
@@ -1159,6 +1159,13 @@ message_handler (void *cls, const struct GNUNET_MessageHeader *msg)
1159 GNUNET_TESTBED_ControllerLinkResponse 1159 GNUNET_TESTBED_ControllerLinkResponse
1160 *) msg); 1160 *) msg);
1161 break; 1161 break;
1162 case GNUNET_MESSAGE_TYPE_TESTBED_BARRIER_STATUS:
1163 status =
1164 GNUNET_TESTBED_handle_barrier_status_ (c,
1165 (const struct
1166 GNUNET_TESTBED_BarrierStatus *)
1167 msg);
1168 break;
1162 default: 1169 default:
1163 GNUNET_assert (0); 1170 GNUNET_assert (0);
1164 } 1171 }
diff --git a/src/testbed/testbed_api.h b/src/testbed/testbed_api.h
index dbeea9243..f658c08dd 100644
--- a/src/testbed/testbed_api.h
+++ b/src/testbed/testbed_api.h
@@ -496,6 +496,22 @@ GNUNET_TESTBED_controller_link_ (void *op_cls,
496 *slave_cfg, int is_subordinate); 496 *slave_cfg, int is_subordinate);
497 497
498 498
499/**
500 * Handler for GNUNET_MESSAGE_TYPE_TESTBED_BARRIER_STATUS messages. This
501 * function is defined in @file testbed_api_barriers.c
502 *
503 * @param c the controller handle to determine the connection this message
504 * belongs to
505 * @param msg the barrier status message
506 * @return GNUNET_OK to keep the connection active; GNUNET_SYSERR to tear it
507 * down signalling an error
508 */
509int
510GNUNET_TESTBED_handle_barrier_status_ (struct GNUNET_TESTBED_Controller *c,
511 const struct GNUNET_TESTBED_BarrierStatus
512 *msg);
513
514
499 515
500 516
501#endif 517#endif
diff --git a/src/testbed/testbed_api_barriers.c b/src/testbed/testbed_api_barriers.c
new file mode 100644
index 000000000..231e00600
--- /dev/null
+++ b/src/testbed/testbed_api_barriers.c
@@ -0,0 +1,221 @@
1/*
2 This file is part of GNUnet.
3 (C) 2008--2013 Christian Grothoff (and other contributing authors)
4
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.
9
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.
14
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., 59 Temple Place - Suite 330,
18 Boston, MA 02111-1307, USA.
19*/
20
21/**
22 * @file testbed/testbed_api_barriers.c
23 * @brief API implementation for testbed barriers
24 * @author Sree Harsha Totakura <sreeharsha@totakura.in>
25 */
26
27#include "platform.h"
28#include "gnunet_testbed_service.h"
29#include "testbed_api.h"
30
31/**
32 * Handle for barrier
33 */
34struct GNUNET_TESTBED_Barrier
35{
36 /**
37 * hashcode identifying this barrier in the hashmap
38 */
39 struct GNUNET_HashCode key;
40
41 /**
42 * The controller handle given while initiliasing this barrier
43 */
44 struct GNUNET_TESTBED_Controller *c;
45
46 /**
47 * The name of the barrier
48 */
49 char *name;
50
51 /**
52 * The continuation callback to call when we have a status update on this
53 */
54 GNUNET_TESTBED_barrier_status_cb cb;
55
56 /**
57 * the closure for the above callback
58 */
59 void *cls;
60
61};
62
63
64/**
65 * handle for hashtable of barrier handles
66 */
67static struct GNUNET_CONTAINER_MultiHashMap *barrier_map;
68
69
70/**
71 * Remove a barrier and it was the last one in the barrier hash map, destroy the
72 * hash map
73 *
74 * @param barrier the barrier to remove
75 */
76static void
77barrier_remove (struct GNUNET_TESTBED_Barrier *barrier)
78{
79 GNUNET_assert (NULL != barrier_map); /* No barriers present */
80 GNUNET_assert (GNUNET_OK ==
81 GNUNET_CONTAINER_multihashmap_remove (barrier_map,
82 &barrier->key,
83 barrier));
84 GNUNET_free (barrier->name);
85 GNUNET_free (barrier);
86 if (0 == GNUNET_CONTAINER_multihashmap_size (barrier_map))
87 {
88 GNUNET_CONTAINER_multihashmap_destroy (barrier_map);
89 barrier_map = NULL;
90 }
91}
92
93
94/**
95 * Handler for GNUNET_MESSAGE_TYPE_TESTBED_BARRIER_STATUS messages
96 *
97 * @param c the controller handle to determine the connection this message
98 * belongs to
99 * @param msg the barrier status message
100 * @return GNUNET_OK to keep the connection active; GNUNET_SYSERR to tear it
101 * down signalling an error
102 */
103int
104GNUNET_TESTBED_handle_barrier_status_ (struct GNUNET_TESTBED_Controller *c,
105 const struct GNUNET_TESTBED_BarrierStatus
106 *msg)
107{
108 struct GNUNET_TESTBED_Barrier *barrier;
109 char *emsg;
110 const char *name;
111 struct GNUNET_HashCode key;
112 size_t emsg_len;
113 int status;
114 uint16_t msize;
115 uint16_t name_len;
116
117 emsg = NULL;
118 barrier = NULL;
119 msize = ntohs (msg->header.size);
120 name = msg->data;
121 name_len = ntohs (msg->name_len);
122 if ( (sizeof (struct GNUNET_TESTBED_BarrierStatus) + name_len + 1 > msize)
123 || ('\0' != name[name_len]) )
124 {
125 GNUNET_break_op (0);
126 return GNUNET_SYSERR;
127 }
128 status = ntohs (msg->status);
129 if (0 != status)
130 {
131 status = -1;
132 emsg_len = msize - (sizeof (struct GNUNET_TESTBED_BarrierStatus) + name_len
133 + 1);
134 if (0 == emsg_len)
135 {
136 GNUNET_break_op (0);
137 return GNUNET_SYSERR;
138 }
139 emsg_len++;
140 emsg = GNUNET_malloc (emsg_len);
141 emsg_len--;
142 emsg[emsg_len] = '\0';
143 (void) memcpy (emsg, msg->data + name_len + 1, emsg_len);
144 }
145 if (NULL == barrier_map)
146 goto cleanup;
147 GNUNET_CRYPTO_hash (name, name_len, &key);
148 barrier = GNUNET_CONTAINER_multihashmap_get (barrier_map, &key);
149 if (NULL == barrier)
150 goto cleanup;
151 GNUNET_assert (NULL != barrier->cb);
152 barrier->cb (barrier->cls, name, barrier, status, emsg);
153
154 cleanup:
155 GNUNET_free_non_null (emsg);
156 if (NULL != barrier)
157 barrier_remove (barrier);
158 return GNUNET_OK;
159}
160
161
162/**
163 * Initialise a barrier and call the given callback when the required percentage
164 * of peers (quorum) reach the barrier OR upon error.
165 *
166 * @param controller the handle to the controller
167 * @param name identification name of the barrier
168 * @param quorum the percentage of peers that is required to reach the barrier.
169 * Peers signal reaching a barrier by calling
170 * GNUNET_TESTBED_barrier_reached().
171 * @param cb the callback to call when the barrier is reached or upon error.
172 * Cannot be NULL.
173 * @param cls closure for the above callback
174 * @return barrier handle; NULL upon error
175 */
176struct GNUNET_TESTBED_Barrier *
177GNUNET_TESTBED_barrier_init (struct GNUNET_TESTBED_Controller *controller,
178 const char *name,
179 unsigned int quorum,
180 GNUNET_TESTBED_barrier_status_cb cb, void *cls)
181{
182 struct GNUNET_TESTBED_Barrier *barrier;
183 struct GNUNET_HashCode key;
184 size_t name_len;
185
186 GNUNET_assert (quorum <= 100);
187 GNUNET_assert (NULL != cb);
188 name_len = strlen (name);
189 GNUNET_assert (0 < name_len);
190 GNUNET_CRYPTO_hash (name, name_len, &key);
191 if (NULL == barrier_map)
192 barrier_map = GNUNET_CONTAINER_multihashmap_create (3, GNUNET_YES);
193 if (GNUNET_YES ==
194 GNUNET_CONTAINER_multihashmap_contains (barrier_map, &key))
195 {
196 GNUNET_break (0);
197 return NULL;
198 }
199 barrier = GNUNET_malloc (sizeof (struct GNUNET_TESTBED_Barrier));
200 barrier->name = GNUNET_strdup (name);
201 barrier->cb = cb;
202 barrier->cls = cls;
203 (void) memcpy (&barrier->key, &key, sizeof (struct GNUNET_HashCode));
204 GNUNET_assert (GNUNET_OK ==
205 GNUNET_CONTAINER_multihashmap_put (barrier_map, &barrier->key,
206 barrier,
207 GNUNET_CONTAINER_MULTIHASHMAPOPTION_UNIQUE_FAST));
208 return barrier;
209}
210
211
212/**
213 * Cancel a barrier.
214 *
215 * @param barrier the barrier handle
216 */
217void
218GNUNET_TESTBED_barrier_cancel (struct GNUNET_TESTBED_Barrier *barrier)
219{
220 barrier_remove (barrier);
221}