Merge branch 'master' of ssh://gnunet.org/gnunet
[oweals/gnunet.git] / src / topology / test_gnunet_daemon_topology.c
1 /*
2      This file is part of GNUnet.
3      Copyright (C) 2009, 2012 GNUnet e.V.
4
5      GNUnet is free software: you can redistribute it and/or modify it
6      under the terms of the GNU Affero General Public License as published
7      by the Free Software Foundation, either version 3 of the License,
8      or (at your 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      Affero General Public License for more details.
14     
15      You should have received a copy of the GNU Affero General Public License
16      along with this program.  If not, see <http://www.gnu.org/licenses/>.
17 */
18 /**
19  * @file topology/test_gnunet_daemon_topology.c
20  * @brief testcase for topology maintenance code
21  * @author Christian Grothoff
22  * @author xrs
23  */
24 #include "platform.h"
25 #include "gnunet_testbed_service.h"
26 #include "gnunet_statistics_service.h"
27
28
29 #define NUM_PEERS 8
30
31 /* 
32  * The threshold defines the number of connection that are needed
33  * for one peer to pass the test. Be aware that setting NUM_PEERS
34  * too high can cause bandwidth problems for the testing peers.
35  * Normal should be 5KB/s per peer. See gnunet-config -s ats.
36  */
37 #define THRESHOLD NUM_PEERS/2
38
39 /**
40  * How long until we give up on connecting the peers?
41  */
42 #define TIMEOUT GNUNET_TIME_relative_multiply (GNUNET_TIME_UNIT_SECONDS, 60)
43
44 /*
45  * Store manual connections.
46  */
47 static unsigned int connect_left;
48
49 /*
50  * Result of the testcase.
51  */
52 static int result;
53
54 /*
55  * Peers that reached the threshold of connections.
56  */
57 static int checked_peers;
58
59 /*
60  * Testbed operations.
61  */
62 struct GNUNET_TESTBED_Operation *op[NUM_PEERS];
63
64 /*
65  * Timeout for testcase.
66  */
67 static struct GNUNET_SCHEDULER_Task *timeout_tid;
68
69 /*
70  * Peer context for every testbed peer.
71  */
72 struct peerctx 
73 {
74   int index;
75   struct GNUNET_STATISTICS_Handle *statistics;
76   int connections;
77   int reported; /* GNUNET_NO | GNUNET_YES */
78 };
79
80
81 static void
82 shutdown_task (void *cls)
83 {
84   unsigned int i;
85
86   GNUNET_log (GNUNET_ERROR_TYPE_INFO,
87               "Shutting down testcase\n");
88
89   for (i=0;i<NUM_PEERS;i++) {
90     if (NULL != op[i])
91       GNUNET_TESTBED_operation_done (op[i]);
92   }
93
94   if (NULL != timeout_tid)
95     GNUNET_SCHEDULER_cancel (timeout_tid);
96 }
97
98 static void
99 timeout_task (void *cls)
100 {
101   timeout_tid = NULL;
102   GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
103               "Testcase timeout\n");
104
105   result = GNUNET_SYSERR;
106   GNUNET_SCHEDULER_shutdown();
107 }
108
109 /*
110  * The function is called every time the topology of connected
111  * peers to a peer changes. 
112  */
113 int
114 statistics_iterator (void *cls,
115                      const char *subsystem,
116                      const char *name,
117                      uint64_t value,
118                      int is_persistent)
119 {
120   struct peerctx *p_ctx = (struct peerctx*) cls;
121
122   GNUNET_log (GNUNET_ERROR_TYPE_INFO,
123               "Peer %d: %s = %d\n",
124               p_ctx->index,
125               name,
126               value);
127
128   if (p_ctx->connections < value)
129     p_ctx->connections = value;
130
131   if (THRESHOLD <= value && GNUNET_NO == p_ctx->reported) {
132     p_ctx->reported = GNUNET_YES;
133     checked_peers++;
134     GNUNET_log(GNUNET_ERROR_TYPE_INFO,
135                "Peer %d successfully connected to at least %d peers once.\n",
136                p_ctx->index,
137                THRESHOLD);
138
139     if (checked_peers == NUM_PEERS) {
140       GNUNET_log(GNUNET_ERROR_TYPE_INFO,
141                "Test OK: All peers have connected to %d peers once.\n",
142                THRESHOLD);
143       result = GNUNET_YES;
144       GNUNET_SCHEDULER_shutdown();
145     }
146   }
147
148   return GNUNET_YES;
149 }
150
151 static void *
152 ca_statistics (void *cls,
153                const struct GNUNET_CONFIGURATION_Handle *cfg)
154 {
155   return GNUNET_STATISTICS_create ("topology", cfg); 
156 }
157
158
159 void
160 da_statistics (void *cls,
161                void *op_result)
162 {
163   struct peerctx *p_ctx = (struct peerctx *) cls;
164   
165   GNUNET_break (GNUNET_OK == GNUNET_STATISTICS_watch_cancel
166                 (p_ctx->statistics, "topology", "# peers connected",
167                  statistics_iterator, p_ctx));
168
169   GNUNET_STATISTICS_destroy (p_ctx->statistics, GNUNET_NO);
170   p_ctx->statistics = NULL;
171
172   GNUNET_free (p_ctx);
173 }
174
175     
176 static void 
177 service_connect_complete (void *cls,
178                           struct GNUNET_TESTBED_Operation *op,
179                           void *ca_result,
180                           const char *emsg)
181 {
182   int ret;
183   struct peerctx *p_ctx = (struct peerctx*) cls;
184
185   if (NULL == ca_result) 
186     GNUNET_SCHEDULER_shutdown();
187
188   p_ctx->statistics = ca_result;
189
190   ret = GNUNET_STATISTICS_watch (ca_result,
191                                  "topology",
192                                  "# peers connected",
193                                  statistics_iterator,
194                                  p_ctx);
195
196   if (GNUNET_NO == ret)
197     GNUNET_log (GNUNET_ERROR_TYPE_INFO,
198                 "call to GNUNET_STATISTICS_watch() failed\n");
199 }
200
201 static void
202 notify_connect_complete (void *cls,
203                          struct GNUNET_TESTBED_Operation *op,
204                          const char *emsg)
205 {
206   GNUNET_TESTBED_operation_done (op);
207   if (NULL != emsg)
208   {
209     FPRINTF (stderr, "Failed to connect two peers: %s\n", emsg);
210     result = GNUNET_SYSERR;
211     GNUNET_SCHEDULER_shutdown ();
212     return;
213   }
214   connect_left--;
215 }
216
217 static void
218 do_connect (void *cls,
219             struct GNUNET_TESTBED_RunHandle *h,
220             unsigned int num_peers,
221             struct GNUNET_TESTBED_Peer **peers,
222             unsigned int links_succeeded,
223             unsigned int links_failed)
224 {
225   unsigned int i;
226   struct peerctx *p_ctx;
227
228   GNUNET_log (GNUNET_ERROR_TYPE_INFO,
229               "Threshold is set to %d.\n",
230               THRESHOLD);
231
232   GNUNET_assert (NUM_PEERS == num_peers);
233
234   for (i=0;i<NUM_PEERS;i++)
235     {
236       p_ctx = GNUNET_new (struct peerctx);
237       p_ctx->index = i;
238       p_ctx->connections = 0;
239       p_ctx->reported = GNUNET_NO;
240
241       if (i<NUM_PEERS-1) {
242         connect_left++;
243         GNUNET_TESTBED_overlay_connect (NULL,
244                                         &notify_connect_complete, NULL,
245                                         peers[i], peers[i+1]);
246       }
247
248       op[i] = 
249         GNUNET_TESTBED_service_connect (cls, 
250                                         peers[i],
251                                         "statistics",
252                                         service_connect_complete, 
253                                         p_ctx, /* cls of completion cb */
254                                         ca_statistics, /* connect adapter */
255                                         da_statistics, /* disconnect adapter */
256                                         p_ctx);
257                                       
258     }
259
260   GNUNET_SCHEDULER_add_shutdown (&shutdown_task, NULL);
261   timeout_tid = 
262     GNUNET_SCHEDULER_add_delayed (TIMEOUT,
263                                   &timeout_task,
264                                   NULL);
265 }
266
267
268 int
269 main (int argc, char *argv[])
270 {
271   result = GNUNET_SYSERR;
272   checked_peers = 0;
273
274   (void) GNUNET_TESTBED_test_run ("test-gnunet-daemon-topology",
275                                   "test_gnunet_daemon_topology_data.conf",
276                                   NUM_PEERS,
277                                   0, NULL, NULL,
278                                   &do_connect, NULL);
279   GNUNET_DISK_directory_remove ("/tmp/test-gnunet-topology");
280
281   return (GNUNET_OK != result) ? 1 : 0;
282 }
283
284 /* end of test_gnunet_daemon_topology.c */