diff options
author | Sree Harsha Totakura <totakura@in.tum.de> | 2013-08-30 14:55:13 +0000 |
---|---|---|
committer | Sree Harsha Totakura <totakura@in.tum.de> | 2013-08-30 14:55:13 +0000 |
commit | 5e1efe185cf484018f53dd33d64e546ac042fdee (patch) | |
tree | e1369e8e1a239426d4ba2d81bb31571bbd4f82eb /src | |
parent | 7d8d536bbaa0f72587552af517f643e3c05e7a6f (diff) | |
download | gnunet-5e1efe185cf484018f53dd33d64e546ac042fdee.tar.gz gnunet-5e1efe185cf484018f53dd33d64e546ac042fdee.zip |
- towards testbed barriers
Diffstat (limited to 'src')
-rw-r--r-- | src/include/gnunet_protocols.h | 19 | ||||
-rw-r--r-- | src/include/gnunet_testbed_service.h | 57 | ||||
-rw-r--r-- | src/testbed/Makefile.am | 6 | ||||
-rw-r--r-- | src/testbed/gnunet-service-testbed.c | 14 | ||||
-rw-r--r-- | src/testbed/gnunet-service-testbed.h | 7 | ||||
-rw-r--r-- | src/testbed/gnunet-service-testbed_barriers.c | 512 | ||||
-rw-r--r-- | src/testbed/gnunet-service-testbed_peers.c | 9 | ||||
-rw-r--r-- | src/testbed/testbed.h | 78 | ||||
-rw-r--r-- | src/testbed/testbed_api.c | 7 | ||||
-rw-r--r-- | src/testbed/testbed_api.h | 16 | ||||
-rw-r--r-- | src/testbed/testbed_api_barriers.c | 221 |
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 | */ | ||
1477 | struct 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 | */ | ||
1493 | typedef 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 | */ | ||
1515 | struct GNUNET_TESTBED_Barrier * | ||
1516 | GNUNET_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 | */ | ||
1527 | void | ||
1528 | GNUNET_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 | ||
43 | gnunet_service_testbed_LDADD = $(XLIB) \ | 44 | gnunet_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 | ||
102 | libgnunettestbed_la_LIBADD = $(XLIB) \ | 104 | libgnunettestbed_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 | */ |
37 | struct GNUNET_CONFIGURATION_Handle *our_config; | 37 | struct 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 | */ |
415 | extern struct GNUNET_CONFIGURATION_Handle *our_config; | 415 | extern 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; | |||
455 | extern unsigned int GST_peer_list_size; | 455 | extern unsigned int GST_peer_list_size; |
456 | 456 | ||
457 | /** | 457 | /** |
458 | * The current number of peers running locally under this controller | ||
459 | */ | ||
460 | extern unsigned int GST_num_local_peers; | ||
461 | |||
462 | /** | ||
458 | * The size of the host list | 463 | * The size of the host list |
459 | */ | 464 | */ |
460 | extern unsigned int GST_host_list_size; | 465 | extern 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 | */ | ||
39 | struct Barrier; | ||
40 | |||
41 | |||
42 | /** | ||
43 | * Message queue for transmitting messages | ||
44 | */ | ||
45 | struct 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 | */ | ||
66 | struct 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 | */ | ||
108 | struct 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 | */ | ||
155 | static struct GNUNET_CONTAINER_MultiHashMap *barrier_map; | ||
156 | |||
157 | /** | ||
158 | * Service context | ||
159 | */ | ||
160 | static 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 | */ | ||
174 | static size_t | ||
175 | transmit_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 | */ | ||
215 | static void | ||
216 | queue_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 | */ | ||
238 | static void | ||
239 | remove_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 | */ | ||
256 | static void | ||
257 | fwd_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 | */ | ||
279 | static void | ||
280 | notify_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 | */ | ||
321 | static void | ||
322 | handle_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 | */ | ||
383 | static void | ||
384 | disconnect_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 | */ | ||
403 | void | ||
404 | GST_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 | */ | ||
424 | void | ||
425 | GST_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 | */ | ||
444 | void | ||
445 | GST_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 | */ |
36 | struct Peer **GST_peer_list; | 36 | struct Peer **GST_peer_list; |
37 | 37 | ||
38 | /** | ||
39 | * The current number of peers running locally under this controller | ||
40 | */ | ||
41 | unsigned 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 | */ | ||
774 | struct 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 | */ | ||
806 | struct 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 | */ | ||
835 | struct 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 | |||
771 | GNUNET_NETWORK_STRUCT_END | 849 | GNUNET_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 | */ | ||
509 | int | ||
510 | GNUNET_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 | */ | ||
34 | struct 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 | */ | ||
67 | static 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 | */ | ||
76 | static void | ||
77 | barrier_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 | */ | ||
103 | int | ||
104 | GNUNET_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 | */ | ||
176 | struct GNUNET_TESTBED_Barrier * | ||
177 | GNUNET_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 | */ | ||
217 | void | ||
218 | GNUNET_TESTBED_barrier_cancel (struct GNUNET_TESTBED_Barrier *barrier) | ||
219 | { | ||
220 | barrier_remove (barrier); | ||
221 | } | ||