aboutsummaryrefslogtreecommitdiff
path: root/src/mesh
diff options
context:
space:
mode:
authorBart Polot <bart@net.in.tum.de>2011-10-17 11:05:05 +0000
committerBart Polot <bart@net.in.tum.de>2011-10-17 11:05:05 +0000
commit469571975ea9114c835789caf3f4951984374000 (patch)
tree997073234a9e1ff8bd9113f9f2d218409dc101d0 /src/mesh
parent522e801284ab0a8b39f6e8cc96c0609a0f28e6a8 (diff)
downloadgnunet-469571975ea9114c835789caf3f4951984374000.tar.gz
gnunet-469571975ea9114c835789caf3f4951984374000.zip
Refactored multicast code to allow sending any message as multicast, added multicast testcase copied from unicast
Diffstat (limited to 'src/mesh')
-rw-r--r--src/mesh/Makefile.am15
-rw-r--r--src/mesh/gnunet-service-mesh.c154
-rw-r--r--src/mesh/test_mesh_small_mulicast.c776
3 files changed, 885 insertions, 60 deletions
diff --git a/src/mesh/Makefile.am b/src/mesh/Makefile.am
index 391d86f80..2c4dc0b4c 100644
--- a/src/mesh/Makefile.am
+++ b/src/mesh/Makefile.am
@@ -56,7 +56,8 @@ check_PROGRAMS = \
56 test_mesh_local_2 \ 56 test_mesh_local_2 \
57 test_mesh_small \ 57 test_mesh_small \
58 test_mesh_small_unicast \ 58 test_mesh_small_unicast \
59 test_mesh_small_unicast_far 59 test_mesh_small_unicast_far \
60 test_mesh_small_multicast
60 61
61test_mesh_api_SOURCES = \ 62test_mesh_api_SOURCES = \
62 test_mesh_api.c 63 test_mesh_api.c
@@ -119,8 +120,18 @@ test_mesh_small_unicast_far_LDADD = \
119test_mesh_small_unicast_far_DEPENDENCIES = \ 120test_mesh_small_unicast_far_DEPENDENCIES = \
120 libgnunetmeshnew.la 121 libgnunetmeshnew.la
121 122
123test_mesh_small_multicast_SOURCES = \
124 test_mesh_small_multicast.c
125test_mesh_small_multicast_LDADD = \
126 $(top_builddir)/src/mesh/libgnunetmeshnew.la \
127 $(top_builddir)/src/util/libgnunetutil.la \
128 $(top_builddir)/src/testing/libgnunettesting.la
129test_mesh_small_multicast_DEPENDENCIES = \
130 libgnunetmeshnew.la
131
132
122if ENABLE_TEST_RUN 133if ENABLE_TEST_RUN
123TESTS = test_mesh_api test_mesh_path_api test_mesh_local_1 test_mesh_local_2 test_mesh_small 134TESTS = test_mesh_api test_mesh_path_api test_mesh_local_1 test_mesh_local_2 test_mesh_small test_mesh_small_unicast
124endif 135endif
125 136
126EXTRA_DIST = \ 137EXTRA_DIST = \
diff --git a/src/mesh/gnunet-service-mesh.c b/src/mesh/gnunet-service-mesh.c
index 434e448af..da0af99b1 100644
--- a/src/mesh/gnunet-service-mesh.c
+++ b/src/mesh/gnunet-service-mesh.c
@@ -813,6 +813,21 @@ static size_t
813send_core_create_path (void *cls, size_t size, void *buf); 813send_core_create_path (void *cls, size_t size, void *buf);
814 814
815/** 815/**
816 * Function called to notify a client about the socket
817 * being ready to queue more data. "buf" will be
818 * NULL and "size" zero if the socket was closed for
819 * writing in the meantime.
820 *
821 * @param cls closure (data itself)
822 * @param size number of bytes available in buf
823 * @param buf where the callee should write the message
824 *
825 * @return number of bytes written to buf
826 */
827static size_t
828send_core_data_multicast (void *cls, size_t size, void *buf);
829
830/**
816 * Cancel a core transmission that was already requested and free all resources 831 * Cancel a core transmission that was already requested and free all resources
817 * associated to the request. 832 * associated to the request.
818 * 833 *
@@ -1601,6 +1616,82 @@ tunnel_notify_connection_broken (struct MeshTunnel *t,
1601 1616
1602 1617
1603/** 1618/**
1619 * Send a message in a tunnel in multicast, sending a copy to each child node
1620 * down the local one in the tunnel tree.
1621 *
1622 * @param t Tunnel in which to send the data.
1623 * @param msg Message to be sent
1624 *
1625 * @return Number of copies sent.
1626 */
1627static int
1628tunnel_send_multicast (struct MeshTunnel *t,
1629 const struct GNUNET_MessageHeader *msg)
1630{
1631 struct GNUNET_PeerIdentity *neighbor;
1632 struct MeshDataDescriptor *info;
1633 struct MeshTunnelTreeNode *n;
1634 unsigned int *copies;
1635 unsigned int i;
1636 size_t size;
1637 void *data;
1638
1639 size = ntohs (msg->size);
1640 GNUNET_assert (NULL != t->tree->me);
1641 n = t->tree->me->children_head;
1642 if (NULL == n)
1643 return 0;
1644 copies = GNUNET_malloc (sizeof (unsigned int));
1645 for (*copies = 0; NULL != n; n = n->next)
1646 (*copies)++;
1647 n = t->tree->me->children_head;
1648 data = GNUNET_malloc (size);
1649 memcpy (data, &msg, size);
1650 while (NULL != n)
1651 {
1652 info = GNUNET_malloc (sizeof (struct MeshDataDescriptor));
1653 info->origin = &t->id;
1654 info->data = data;
1655 info->size = size;
1656 info->copies = copies;
1657 if (NULL != t->client->handle)
1658 {
1659 info->client = t->client->handle;
1660
1661 info->timeout_task = GNUNET_SCHEDULER_add_delayed (UNACKNOWLEDGED_WAIT,
1662 &client_allow_send,
1663 t->client->handle);
1664 }
1665 info->destination = n->peer;
1666 neighbor = path_get_first_hop(t->tree, n->peer);
1667 info->peer = peer_info_get(neighbor);
1668 GNUNET_assert (NULL != info->peer);
1669 for (i = 0; NULL != info->peer->core_transmit[i]; i++)
1670 {
1671 if (i == (CORE_QUEUE_SIZE - 1))
1672 {
1673 GNUNET_free (info);
1674 GNUNET_break (0);
1675 return GNUNET_OK;
1676 }
1677 }
1678 info->handler_n = i;
1679 info->peer->infos[i] = info;
1680 info->peer->types[i] = GNUNET_MESSAGE_TYPE_MESH_MULTICAST;
1681 info->peer->core_transmit[i] =
1682 GNUNET_CORE_notify_transmit_ready (core_handle,
1683 0,
1684 0,
1685 GNUNET_TIME_UNIT_FOREVER_REL,
1686 neighbor,
1687 size,
1688 &send_core_data_multicast, info);
1689 }
1690 return *copies;
1691}
1692
1693
1694/**
1604 * Destroy the tunnel and free any allocated resources linked to it 1695 * Destroy the tunnel and free any allocated resources linked to it
1605 * 1696 *
1606 * @param t the tunnel to destroy 1697 * @param t the tunnel to destroy
@@ -1846,12 +1937,12 @@ static size_t
1846send_core_data_multicast (void *cls, size_t size, void *buf) 1937send_core_data_multicast (void *cls, size_t size, void *buf)
1847{ 1938{
1848 struct MeshDataDescriptor *info = cls; 1939 struct MeshDataDescriptor *info = cls;
1849 struct GNUNET_MESH_Multicast *msg = buf; 1940 struct GNUNET_MessageHeader *msg = buf;
1850 size_t total_size; 1941 size_t total_size;
1851 1942
1852 GNUNET_assert (NULL != info); 1943 GNUNET_assert (NULL != info);
1853 GNUNET_assert (NULL != info->peer); 1944 GNUNET_assert (NULL != info->peer);
1854 total_size = info->size + sizeof (struct GNUNET_MESH_Multicast); 1945 total_size = info->size;
1855 GNUNET_assert (total_size < GNUNET_SERVER_MAX_MESSAGE_SIZE); 1946 GNUNET_assert (total_size < GNUNET_SERVER_MAX_MESSAGE_SIZE);
1856 1947
1857 if (total_size > size) 1948 if (total_size > size)
@@ -1860,8 +1951,6 @@ send_core_data_multicast (void *cls, size_t size, void *buf)
1860 struct GNUNET_PeerIdentity id; 1951 struct GNUNET_PeerIdentity id;
1861 1952
1862 GNUNET_PEER_resolve(info->peer->id, &id); 1953 GNUNET_PEER_resolve(info->peer->id, &id);
1863 info->peer->infos[info->handler_n] = info;
1864 info->peer->types[info->handler_n] = GNUNET_MESSAGE_TYPE_MESH_MULTICAST;
1865 info->peer->core_transmit[info->handler_n] = 1954 info->peer->core_transmit[info->handler_n] =
1866 GNUNET_CORE_notify_transmit_ready (core_handle, 1955 GNUNET_CORE_notify_transmit_ready (core_handle,
1867 0, 1956 0,
@@ -1875,11 +1964,7 @@ send_core_data_multicast (void *cls, size_t size, void *buf)
1875 } 1964 }
1876 info->peer->core_transmit[info->handler_n] = NULL; 1965 info->peer->core_transmit[info->handler_n] = NULL;
1877 info->peer->infos[info->handler_n] = NULL; 1966 info->peer->infos[info->handler_n] = NULL;
1878 msg->header.type = htons (GNUNET_MESSAGE_TYPE_MESH_MULTICAST); 1967 memcpy (&msg, info->data, total_size);
1879 msg->header.size = htons (total_size);
1880 GNUNET_PEER_resolve (info->origin->oid, &msg->oid);
1881 msg->tid = htonl (info->origin->tid);
1882 memcpy (&msg[1], info->data, info->size);
1883 if (0 == --(*info->copies)) 1968 if (0 == --(*info->copies))
1884 { 1969 {
1885 if (NULL != info->client) 1970 if (NULL != info->client)
@@ -2273,14 +2358,8 @@ handle_mesh_data_multicast (void *cls, const struct GNUNET_PeerIdentity *peer,
2273 const struct GNUNET_ATS_Information *atsi) 2358 const struct GNUNET_ATS_Information *atsi)
2274{ 2359{
2275 struct GNUNET_MESH_Multicast *msg; 2360 struct GNUNET_MESH_Multicast *msg;
2276 struct GNUNET_PeerIdentity *id;
2277 struct MeshDataDescriptor *info;
2278 struct MeshTunnelTreeNode *n;
2279 struct MeshTunnel *t; 2361 struct MeshTunnel *t;
2280 unsigned int *copies;
2281 unsigned int i;
2282 size_t size; 2362 size_t size;
2283 void *data;
2284 2363
2285 size = ntohs (message->size) - sizeof (struct GNUNET_MESH_Multicast); 2364 size = ntohs (message->size) - sizeof (struct GNUNET_MESH_Multicast);
2286 if (size < sizeof (struct GNUNET_MessageHeader)) 2365 if (size < sizeof (struct GNUNET_MessageHeader))
@@ -2303,48 +2382,7 @@ handle_mesh_data_multicast (void *cls, const struct GNUNET_PeerIdentity *peer,
2303 { 2382 {
2304 send_subscribed_clients (message, (struct GNUNET_MessageHeader *) &msg[1]); 2383 send_subscribed_clients (message, (struct GNUNET_MessageHeader *) &msg[1]);
2305 } 2384 }
2306 n = t->tree->me->children_head; 2385 tunnel_send_multicast(t, message);
2307 if (NULL == n)
2308 return GNUNET_OK;
2309 copies = GNUNET_malloc (sizeof (unsigned int));
2310 for (*copies = 0; NULL != n; n = n->next)
2311 (*copies)++;
2312 n = t->tree->me->children_head;
2313 data = GNUNET_malloc (size);
2314 memcpy (data, &msg[1], size);
2315 while (NULL != n)
2316 {
2317 info = GNUNET_malloc (sizeof (struct MeshDataDescriptor));
2318 info->origin = &t->id;
2319 info->data = data;
2320 info->size = size;
2321 info->copies = copies;
2322 info->client = t->client->handle;
2323 info->timeout_task = GNUNET_SCHEDULER_add_delayed(UNACKNOWLEDGED_WAIT,
2324 &client_allow_send,
2325 t->client->handle);
2326 info->destination = n->peer;
2327 id = path_get_first_hop(t->tree, n->peer);
2328 info->peer = peer_info_get(id);
2329 GNUNET_assert (NULL != info->peer);
2330 for (i = 0; NULL != info->peer->core_transmit[i]; i++)
2331 {
2332 if (i == (CORE_QUEUE_SIZE - 1))
2333 {
2334 GNUNET_free (info);
2335 GNUNET_break (0);
2336 return GNUNET_OK;
2337 }
2338 }
2339 info->handler_n = i;
2340 info->peer->infos[i] = info;
2341 info->peer->types[i] = GNUNET_MESSAGE_TYPE_MESH_MULTICAST;
2342 info->peer->core_transmit[i] =
2343 GNUNET_CORE_notify_transmit_ready (core_handle, 0, 0,
2344 GNUNET_TIME_UNIT_FOREVER_REL, id,
2345 ntohs (msg->header.size),
2346 &send_core_data_multicast, info);
2347 }
2348 2386
2349 return GNUNET_OK; 2387 return GNUNET_OK;
2350} 2388}
@@ -3083,7 +3121,7 @@ handle_local_tunnel_destroy (void *cls, struct GNUNET_SERVER_Client *client,
3083 t = GNUNET_CONTAINER_multihashmap_get (c->tunnels, &hash); 3121 t = GNUNET_CONTAINER_multihashmap_get (c->tunnels, &hash);
3084 GNUNET_CONTAINER_multihashmap_remove (c->tunnels, &hash, t); 3122 GNUNET_CONTAINER_multihashmap_remove (c->tunnels, &hash, t);
3085 3123
3086// notify_tunnel_destroy(t); FIXME 3124// notify_tunnel_destroy(t);
3087 tunnel_destroy(t); 3125 tunnel_destroy(t);
3088 GNUNET_SERVER_receive_done (client, GNUNET_OK); 3126 GNUNET_SERVER_receive_done (client, GNUNET_OK);
3089 return; 3127 return;
diff --git a/src/mesh/test_mesh_small_mulicast.c b/src/mesh/test_mesh_small_mulicast.c
new file mode 100644
index 000000000..bb76e0878
--- /dev/null
+++ b/src/mesh/test_mesh_small_mulicast.c
@@ -0,0 +1,776 @@
1/*
2 This file is part of GNUnet.
3 (C) 2011 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 * @file mesh/test_mesh_small_multicast.c
22 *
23 * @brief Test for the mesh service: retransmission of multicast traffic.
24 */
25#include "platform.h"
26#include "gnunet_testing_lib.h"
27#include "gnunet_mesh_service_new.h"
28
29#define VERBOSE GNUNET_YES
30#define REMOVE_DIR GNUNET_YES
31
32struct MeshPeer
33{
34 struct MeshPeer *prev;
35
36 struct MeshPeer *next;
37
38 struct GNUNET_TESTING_Daemon *daemon;
39
40 struct GNUNET_MESH_Handle *mesh_handle;
41};
42
43
44struct StatsContext
45{
46 unsigned long long total_mesh_bytes;
47};
48
49
50/**
51 * How long until we give up on connecting the peers?
52 */
53#define TIMEOUT GNUNET_TIME_relative_multiply (GNUNET_TIME_UNIT_SECONDS, 1500)
54
55/**
56 * Time to wait for stuff that should be rather fast
57 */
58#define SHORT_TIME GNUNET_TIME_relative_multiply (GNUNET_TIME_UNIT_SECONDS, 5)
59
60#define OK_GOAL 4
61
62static int ok;
63
64/**
65 * Be verbose
66 */
67static int verbose;
68
69/**
70 * Total number of peers in the test.
71 */
72static unsigned long long num_peers;
73
74/**
75 * Global configuration file
76 */
77static struct GNUNET_CONFIGURATION_Handle *testing_cfg;
78
79/**
80 * Total number of currently running peers.
81 */
82static unsigned long long peers_running;
83
84/**
85 * Total number of connections in the whole network.
86 */
87static unsigned int total_connections;
88
89/**
90 * The currently running peer group.
91 */
92static struct GNUNET_TESTING_PeerGroup *pg;
93
94/**
95 * File to report results to.
96 */
97static struct GNUNET_DISK_FileHandle *output_file;
98
99/**
100 * File to log connection info, statistics to.
101 */
102static struct GNUNET_DISK_FileHandle *data_file;
103
104/**
105 * How many data points to capture before triggering next round?
106 */
107static struct GNUNET_TIME_Relative wait_time;
108
109/**
110 * Task called to disconnect peers.
111 */
112static GNUNET_SCHEDULER_TaskIdentifier disconnect_task;
113
114/**
115 * Task To perform tests
116 */
117static GNUNET_SCHEDULER_TaskIdentifier test_task;
118
119/**
120 * Task called to shutdown test.
121 */
122static GNUNET_SCHEDULER_TaskIdentifier shutdown_handle;
123
124static char *topology_file;
125
126static char *data_filename;
127
128static struct GNUNET_TESTING_Daemon *d1;
129
130static GNUNET_PEER_Id pid1;
131
132static struct GNUNET_TESTING_Daemon *d2;
133
134static struct GNUNET_MESH_Handle *h1;
135
136static struct GNUNET_MESH_Handle *h2;
137
138static struct GNUNET_MESH_Tunnel *t;
139
140static struct GNUNET_MESH_Tunnel *incoming_t;
141
142static uint16_t *mesh_peers;
143
144/**
145 * Check whether peers successfully shut down.
146 */
147static void
148shutdown_callback (void *cls, const char *emsg)
149{
150 if (emsg != NULL)
151 {
152#if VERBOSE
153 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "test: Shutdown of peers failed!\n");
154#endif
155 ok--;
156 }
157 else
158 {
159#if VERBOSE
160 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "test: All peers successfully shut down!\n");
161#endif
162 }
163}
164
165
166static void
167shutdown_task (void *cls, const struct GNUNET_SCHEDULER_TaskContext *tc)
168{
169#if VERBOSE
170 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "test: Ending test.\n");
171#endif
172
173 if (disconnect_task != GNUNET_SCHEDULER_NO_TASK)
174 {
175 GNUNET_SCHEDULER_cancel (disconnect_task);
176 disconnect_task = GNUNET_SCHEDULER_NO_TASK;
177 }
178
179 if (data_file != NULL)
180 GNUNET_DISK_file_close (data_file);
181 GNUNET_TESTING_daemons_stop (pg, TIMEOUT, &shutdown_callback, NULL);
182 GNUNET_CONFIGURATION_destroy (testing_cfg);
183}
184
185
186static void
187disconnect_mesh_peers (void *cls, const struct GNUNET_SCHEDULER_TaskContext *tc)
188{
189 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
190 "test: disconnecting mesh service of peers\n");
191 disconnect_task = GNUNET_SCHEDULER_NO_TASK;
192 GNUNET_MESH_disconnect(h1);
193 GNUNET_MESH_disconnect(h2);
194 GNUNET_SCHEDULER_cancel (shutdown_handle);
195 shutdown_handle = GNUNET_SCHEDULER_add_now(&shutdown_task, NULL);
196}
197
198
199/**
200 * Transmit ready callback
201 */
202size_t
203tmt_rdy (void *cls, size_t size, void *buf)
204{
205 struct GNUNET_MessageHeader *msg = buf;
206
207 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "test: tmt_rdy called\n");
208 if (size < sizeof(struct GNUNET_MessageHeader) || NULL == buf)
209 return 0;
210 msg->size = htons (sizeof(struct GNUNET_MessageHeader));
211 msg->type = htons ((long) cls);
212 return sizeof(struct GNUNET_MessageHeader);
213}
214
215
216/**
217 * Function is called whenever a message is received.
218 *
219 * @param cls closure (set from GNUNET_MESH_connect)
220 * @param tunnel connection to the other end
221 * @param tunnel_ctx place to store local state associated with the tunnel
222 * @param sender who sent the message
223 * @param message the actual message
224 * @param atsi performance data for the connection
225 * @return GNUNET_OK to keep the connection open,
226 * GNUNET_SYSERR to close it (signal serious error)
227 */
228int
229data_callback (void *cls,
230 struct GNUNET_MESH_Tunnel * tunnel,
231 void **tunnel_ctx,
232 const struct GNUNET_PeerIdentity *sender,
233 const struct GNUNET_MessageHeader *message,
234 const struct GNUNET_TRANSPORT_ATS_Information *atsi)
235{
236 long client = (long) cls;
237
238 switch (client)
239 {
240 case 1L:
241 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
242 "test: Origin client got a response!\n");
243 ok++;
244 GNUNET_SCHEDULER_cancel (disconnect_task);
245 disconnect_task = GNUNET_SCHEDULER_add_now(&disconnect_mesh_peers,
246 NULL);
247 break;
248 case 2L:
249 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
250 "test: Destination client got a message \n");
251 ok++;
252 GNUNET_MESH_notify_transmit_ready(incoming_t,
253 GNUNET_NO,
254 0,
255 GNUNET_TIME_UNIT_FOREVER_REL,
256 sender,
257 sizeof(struct GNUNET_MessageHeader),
258 &tmt_rdy,
259 (void *) 1L);
260 GNUNET_SCHEDULER_cancel (disconnect_task);
261 disconnect_task = GNUNET_SCHEDULER_add_delayed(SHORT_TIME,
262 &disconnect_mesh_peers,
263 NULL);
264 break;
265 default:
266 break;
267 }
268 return GNUNET_OK;
269}
270
271
272/**
273 * Handlers, for diverse services
274 */
275static struct GNUNET_MESH_MessageHandler handlers[] = {
276 {&data_callback, 1, sizeof(struct GNUNET_MessageHeader)},
277 {NULL, 0, 0}
278};
279
280
281/**
282 * Method called whenever another peer has added us to a tunnel
283 * the other peer initiated.
284 *
285 * @param cls closure
286 * @param tunnel new handle to the tunnel
287 * @param initiator peer that started the tunnel
288 * @param atsi performance information for the tunnel
289 * @return initial tunnel context for the tunnel
290 * (can be NULL -- that's not an error)
291 */
292static void *
293incoming_tunnel (void *cls,
294 struct GNUNET_MESH_Tunnel * tunnel,
295 const struct GNUNET_PeerIdentity * initiator,
296 const struct GNUNET_TRANSPORT_ATS_Information * atsi)
297{
298 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
299 "test: Incoming tunnel from %s\n",
300 GNUNET_i2s(initiator));
301 ok++;
302 incoming_t = tunnel;
303 GNUNET_SCHEDULER_cancel (disconnect_task);
304 disconnect_task = GNUNET_SCHEDULER_add_delayed(SHORT_TIME,
305 &disconnect_mesh_peers,
306 NULL);
307 return NULL;
308}
309
310/**
311 * Function called whenever an inbound tunnel is destroyed. Should clean up
312 * any associated state.
313 *
314 * @param cls closure (set from GNUNET_MESH_connect)
315 * @param tunnel connection to the other end (henceforth invalid)
316 * @param tunnel_ctx place where local state associated
317 * with the tunnel is stored
318 */
319static void
320tunnel_cleaner (void *cls, const struct GNUNET_MESH_Tunnel *tunnel,
321 void *tunnel_ctx)
322{
323#if VERBOSE
324 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "test: tunnel disconnected\n");
325#endif
326
327 return;
328}
329
330
331/**
332 * Method called whenever a tunnel falls apart.
333 *
334 * @param cls closure
335 * @param peer peer identity the tunnel stopped working with
336 */
337static void
338dh (void *cls, const struct GNUNET_PeerIdentity *peer)
339{
340 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
341 "test: peer %s disconnected\n",
342 GNUNET_i2s(peer));
343 return;
344}
345
346
347/**
348 * Method called whenever a tunnel is established.
349 *
350 * @param cls closure
351 * @param peer peer identity the tunnel was created to, NULL on timeout
352 * @param atsi performance data for the connection
353 */
354static void
355ch (void *cls, const struct GNUNET_PeerIdentity *peer,
356 const struct GNUNET_TRANSPORT_ATS_Information *atsi)
357{
358 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
359 "test: peer %s connected\n",
360 GNUNET_i2s(peer));
361 if (0 == memcmp(&d2->id, peer, sizeof(d2->id)) && (long) cls == 1L)
362 ok++;
363 if (GNUNET_SCHEDULER_NO_TASK != disconnect_task)
364 {
365 GNUNET_SCHEDULER_cancel (disconnect_task);
366 disconnect_task = GNUNET_SCHEDULER_add_delayed(SHORT_TIME,
367 &disconnect_mesh_peers,
368 NULL);
369 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "test: Sending data multicast...\n");
370 GNUNET_MESH_notify_transmit_ready(t,
371 GNUNET_NO,
372 0,
373 GNUNET_TIME_UNIT_FOREVER_REL,
374 &d2->id,
375 sizeof(struct GNUNET_MessageHeader),
376 &tmt_rdy,
377 (void *) 1L);
378 }
379 return;
380}
381
382
383static void
384do_test (void *cls, const struct GNUNET_SCHEDULER_TaskContext *tc)
385{
386 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "test: test_task\n");
387 GNUNET_MESH_peer_request_connect_add(t, &d2->id);
388 GNUNET_SCHEDULER_cancel (disconnect_task);
389 disconnect_task = GNUNET_SCHEDULER_add_delayed(
390 GNUNET_TIME_relative_multiply(GNUNET_TIME_UNIT_SECONDS, 30),
391 &disconnect_mesh_peers, NULL);
392}
393
394
395/**
396 * Prototype of a callback function indicating that two peers
397 * are currently connected.
398 *
399 * @param cls closure
400 * @param first peer id for first daemon
401 * @param second peer id for the second daemon
402 * @param distance distance between the connected peers
403 * @param emsg error message (NULL on success)
404 */
405void
406topo_cb (void *cls,
407 const struct GNUNET_PeerIdentity* first,
408 const struct GNUNET_PeerIdentity* second,
409 const char *emsg)
410{
411 GNUNET_PEER_Id p1;
412 GNUNET_PEER_Id p2;
413 struct GNUNET_PeerIdentity id;
414
415 GNUNET_PEER_resolve(1, &id);
416 p1 = GNUNET_PEER_search(first);
417 if (p1 == pid1)
418 {
419 p2 = GNUNET_PEER_search(second);
420 GNUNET_assert(p2 < num_peers);
421 GNUNET_assert(p2 > 0);
422 mesh_peers[p2]++;
423 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
424 "test: %s IS a neighbor\n",
425 GNUNET_i2s(second));
426 return;
427 }
428 p1 = GNUNET_PEER_search(second);
429 if (p1 == pid1)
430 {
431 p2 = GNUNET_PEER_search(first);
432 GNUNET_assert(p2 < num_peers);
433 GNUNET_assert(p2 > 0);
434 mesh_peers[p2]++;
435 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
436 "test: %s IS a neighbor\n",
437 GNUNET_i2s(first));
438 return;
439 }
440}
441
442/**
443 * connect_mesh_service: connect to the mesh service of one of the peers
444 *
445 */
446static void
447connect_mesh_service (void *cls, const struct GNUNET_SCHEDULER_TaskContext *tc)
448{
449 GNUNET_MESH_ApplicationType app;
450 unsigned int i;
451 struct GNUNET_PeerIdentity id;
452
453 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "test: connect_mesh_service\n");
454
455 for (i = 1; i <= num_peers; i++)
456 {
457 GNUNET_PEER_resolve(i, &id);
458 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
459 "test: peer %s has %u conns to d1\n",
460 GNUNET_i2s (&id),
461 mesh_peers[i]);
462 if (mesh_peers[i] == 0)
463 break;
464 }
465 GNUNET_assert (i < num_peers);
466 d2 = GNUNET_TESTING_daemon_get_by_id (pg, &id);
467 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
468 "test: Peer searched: %s\n",
469 GNUNET_i2s (&d2->id));
470 app = (GNUNET_MESH_ApplicationType) 0;
471
472#if VERBOSE
473 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
474 "test: connecting to mesh service of peer %s (%u)\n",
475 GNUNET_i2s (&d1->id),
476 mesh_peers[0]);
477 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
478 "test: connecting to mesh service of peer %s (%u)\n",
479 GNUNET_i2s (&d2->id),
480 i);
481#endif
482 h1 = GNUNET_MESH_connect (d1->cfg,
483 10,
484 (void *) 1L,
485 NULL,
486 &tunnel_cleaner,
487 handlers,
488 &app);
489 h2 = GNUNET_MESH_connect (d2->cfg,
490 10,
491 (void *) 2L,
492 &incoming_tunnel,
493 &tunnel_cleaner,
494 handlers,
495 &app);
496#if VERBOSE
497 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
498 "test: connected to mesh service of peer %s\n",
499 GNUNET_i2s (&d1->id));
500 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
501 "test: connected to mesh service of peer %s\n",
502 GNUNET_i2s (&d2->id));
503#endif
504 t = GNUNET_MESH_tunnel_create (h1, NULL, &ch, &dh, (void *) 1L);
505 test_task =
506 GNUNET_SCHEDULER_add_delayed(
507 GNUNET_TIME_relative_multiply(GNUNET_TIME_UNIT_SECONDS, 6),
508 &do_test, NULL);
509}
510
511
512
513/**
514 * peergroup_ready: start test when all peers are connected
515 * @param cls closure
516 * @param emsg error message
517 */
518static void
519peergroup_ready (void *cls, const char *emsg)
520{
521 char *buf;
522 int buf_len;
523 unsigned int i;
524
525 if (emsg != NULL)
526 {
527 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
528 "test: Peergroup callback called with error, aborting test!\n");
529 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
530 "test: Error from testing: `%s'\n", emsg);
531 ok--;
532 GNUNET_TESTING_daemons_stop (pg, TIMEOUT, &shutdown_callback, NULL);
533 return;
534 }
535#if VERBOSE
536 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
537 "************************************************************\n");
538 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
539 "test: Peer Group started successfully!\n");
540 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
541 "test: Have %u connections\n",
542 total_connections);
543#endif
544
545 if (data_file != NULL)
546 {
547 buf = NULL;
548 buf_len = GNUNET_asprintf (&buf, "CONNECTIONS_0: %u\n", total_connections);
549 if (buf_len > 0)
550 GNUNET_DISK_file_write (data_file, buf, buf_len);
551 GNUNET_free (buf);
552 }
553 peers_running = GNUNET_TESTING_daemons_running (pg);
554 for (i = 0; i < num_peers; i++)
555 {
556 d1 = GNUNET_TESTING_daemon_get (pg, i);
557 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
558 "test: %u: %s\n",
559 GNUNET_PEER_intern(&d1->id),
560 GNUNET_i2s (&d1->id));
561 }
562 d1 = GNUNET_TESTING_daemon_get (pg, 0);
563 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
564 "test: Peer looking: %s\n",
565 GNUNET_i2s (&d1->id));
566 pid1 = GNUNET_PEER_intern(&d1->id);
567 mesh_peers[pid1] = 100;
568 GNUNET_TESTING_get_topology(pg, &topo_cb, NULL);
569
570 GNUNET_SCHEDULER_add_delayed (GNUNET_TIME_relative_multiply(
571 GNUNET_TIME_UNIT_SECONDS,
572 4),
573 &connect_mesh_service,
574 NULL);
575 disconnect_task =
576 GNUNET_SCHEDULER_add_delayed (wait_time, &disconnect_mesh_peers, NULL);
577
578}
579
580
581/**
582 * Function that will be called whenever two daemons are connected by
583 * the testing library.
584 *
585 * @param cls closure
586 * @param first peer id for first daemon
587 * @param second peer id for the second daemon
588 * @param distance distance between the connected peers
589 * @param first_cfg config for the first daemon
590 * @param second_cfg config for the second daemon
591 * @param first_daemon handle for the first daemon
592 * @param second_daemon handle for the second daemon
593 * @param emsg error message (NULL on success)
594 */
595static void
596connect_cb (void *cls, const struct GNUNET_PeerIdentity *first,
597 const struct GNUNET_PeerIdentity *second, uint32_t distance,
598 const struct GNUNET_CONFIGURATION_Handle *first_cfg,
599 const struct GNUNET_CONFIGURATION_Handle *second_cfg,
600 struct GNUNET_TESTING_Daemon *first_daemon,
601 struct GNUNET_TESTING_Daemon *second_daemon, const char *emsg)
602{
603 if (emsg == NULL)
604 {
605 total_connections++;
606 }
607 else
608 {
609 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
610 "test: Problem with new connection (%s)\n",
611 emsg);
612 }
613
614}
615
616
617/**
618 * run: load configuration options and schedule test to run (start peergroup)
619 * @param cls closure
620 * @param args argv
621 * @param cfgfile configuration file name (can be NULL)
622 * @param cfg configuration handle
623 */
624static void
625run (void *cls, char *const *args, const char *cfgfile,
626 const struct GNUNET_CONFIGURATION_Handle *cfg)
627{
628 char *temp_str;
629 unsigned long long temp_wait;
630 struct GNUNET_TESTING_Host *hosts;
631
632 ok = 0;
633 testing_cfg = GNUNET_CONFIGURATION_dup (cfg);
634
635 GNUNET_log_setup ("test_mesh_small_multicast",
636#if VERBOSE
637 "DEBUG",
638#else
639 "WARNING",
640#endif
641 NULL);
642
643#if VERBOSE
644 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "test: Starting daemons.\n");
645 GNUNET_CONFIGURATION_set_value_string (testing_cfg, "testing",
646 "use_progressbars", "YES");
647#endif
648
649 if (GNUNET_OK !=
650 GNUNET_CONFIGURATION_get_value_number (testing_cfg, "testing",
651 "num_peers", &num_peers))
652 {
653 GNUNET_assert (GNUNET_OK ==
654 GNUNET_CONFIGURATION_load (testing_cfg,
655 "test_mesh_small.conf"));
656 if (GNUNET_OK !=
657 GNUNET_CONFIGURATION_get_value_number (testing_cfg, "testing",
658 "num_peers", &num_peers))
659 {
660 GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
661 "Option TESTING:NUM_PEERS is required!\n");
662 return;
663 }
664 }
665
666 mesh_peers = GNUNET_malloc (sizeof(GNUNET_PEER_Id) * (num_peers + 1));
667
668 if (GNUNET_OK !=
669 GNUNET_CONFIGURATION_get_value_number (testing_cfg, "test_mesh_small",
670 "wait_time", &temp_wait))
671 {
672 GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
673 "Option test_mesh_small:wait_time is required!\n");
674 return;
675 }
676
677 if (GNUNET_OK !=
678 GNUNET_CONFIGURATION_get_value_string (testing_cfg, "testing",
679 "topology_output_file",
680 &topology_file))
681 {
682 GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
683 "Option test_mesh_small:topology_output_file is required!\n");
684 return;
685 }
686
687 if (GNUNET_OK !=
688 GNUNET_CONFIGURATION_get_value_string (testing_cfg, "test_mesh_small",
689 "data_output_file",
690 &data_filename))
691 {
692 GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
693 "Option test_mesh_small:data_output_file is required!\n");
694 return;
695 }
696
697 data_file =
698 GNUNET_DISK_file_open (data_filename,
699 GNUNET_DISK_OPEN_READWRITE |
700 GNUNET_DISK_OPEN_CREATE,
701 GNUNET_DISK_PERM_USER_READ |
702 GNUNET_DISK_PERM_USER_WRITE);
703 if (data_file == NULL)
704 {
705 GNUNET_log (GNUNET_ERROR_TYPE_WARNING, "Failed to open %s for output!\n",
706 data_filename);
707 GNUNET_free (data_filename);
708 }
709
710 wait_time =
711 GNUNET_TIME_relative_multiply (GNUNET_TIME_UNIT_SECONDS, temp_wait);
712
713 if (GNUNET_YES ==
714 GNUNET_CONFIGURATION_get_value_string (cfg, "test_mesh_small",
715 "output_file", &temp_str))
716 {
717 output_file =
718 GNUNET_DISK_file_open (temp_str,
719 GNUNET_DISK_OPEN_READWRITE |
720 GNUNET_DISK_OPEN_CREATE,
721 GNUNET_DISK_PERM_USER_READ |
722 GNUNET_DISK_PERM_USER_WRITE);
723 if (output_file == NULL)
724 GNUNET_log (GNUNET_ERROR_TYPE_WARNING, "Failed to open %s for output!\n",
725 temp_str);
726 }
727 GNUNET_free_non_null (temp_str);
728
729 hosts = GNUNET_TESTING_hosts_load (testing_cfg);
730
731 pg = GNUNET_TESTING_peergroup_start (testing_cfg, num_peers, TIMEOUT,
732 &connect_cb, &peergroup_ready, NULL,
733 hosts);
734 GNUNET_assert (pg != NULL);
735 shutdown_handle =
736 GNUNET_SCHEDULER_add_delayed (GNUNET_TIME_relative_get_forever (),
737 &shutdown_task, NULL);
738}
739
740
741
742/**
743 * test_mesh_small command line options
744 */
745static struct GNUNET_GETOPT_CommandLineOption options[] = {
746 {'V', "verbose", NULL,
747 gettext_noop ("be verbose (print progress information)"),
748 0, &GNUNET_GETOPT_set_one, &verbose},
749 GNUNET_GETOPT_OPTION_END
750};
751
752
753/**
754 * Main: start test
755 */
756int
757main (int argc, char *argv[])
758{
759 GNUNET_PROGRAM_run (argc, argv, "test_mesh_small_multicast",
760 gettext_noop ("Test mesh multicast in a small network."),
761 options, &run, NULL);
762#if REMOVE_DIR
763 GNUNET_DISK_directory_remove ("/tmp/test_mesh_small_multicast");
764#endif
765 if (OK_GOAL != ok)
766 {
767 GNUNET_log (GNUNET_ERROR_TYPE_WARNING,
768 "test: FAILED! (%d/%d)\n",
769 ok, OK_GOAL);
770 return 1;
771 }
772 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "test: success\n");
773 return 0;
774}
775
776/* end of test_mesh_small_multicast.c */