issuer
[oweals/gnunet.git] / src / experimentation / test_experimentation_clique.c
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 src/testbed/test_testbed_api_topology.c
23  * @brief test case to connect experimentation daemons in a clique
24  * @author Sree Harsha Totakura <sreeharsha@totakura.in>
25  * @author Matthias Wachs
26  */
27
28 #include "platform.h"
29 #include "gnunet_common.h"
30 #include "gnunet_testbed_service.h"
31
32
33 /**
34  * Number of peers we want to start
35  */
36 #define NUM_PEERS 10
37
38 #define TEST_TIMEOUT GNUNET_TIME_relative_multiply (GNUNET_TIME_UNIT_SECONDS, (5 * NUM_PEERS) + 20)
39
40 /**
41  * Array of peers
42  */
43 static struct GNUNET_TESTBED_Peer **peers;
44
45 /**
46  * Operation handle
47  */
48 static struct GNUNET_TESTBED_Operation *op;
49
50 /**
51  * Shutdown task
52  */
53 static GNUNET_SCHEDULER_TaskIdentifier shutdown_task;
54
55 /**
56  * Testing result
57  */
58 static int result;
59
60 /**
61  * Counter for counting overlay connections
62  */
63 static unsigned int overlay_connects;
64
65 /**
66  * Information we track for a peer in the testbed.
67  */
68 struct ExperimentationPeer
69 {
70   /**
71    * Handle with testbed.
72    */
73   struct GNUNET_TESTBED_Peer *daemon;
74
75   /**
76    * Testbed operation to connect to statistics service
77    */
78   struct GNUNET_TESTBED_Operation *stat_op;
79
80   /**
81    * Handle to the statistics service
82    */
83   struct GNUNET_STATISTICS_Handle *sh;
84
85   unsigned int active_nodes;
86   unsigned int requested_nodes;
87   unsigned int inactive_nodes;
88   unsigned int issuer;
89 };
90
91
92 struct ExperimentationPeer ph[NUM_PEERS];
93
94 /**
95  * Shutdown nicely
96  *
97  * @param cls NULL
98  * @param tc the task context
99  */
100 static void
101 do_shutdown (void *cls, const struct GNUNET_SCHEDULER_TaskContext *tc)
102 {
103   unsigned int peer;
104         shutdown_task = GNUNET_SCHEDULER_NO_TASK;
105
106   for (peer = 0; peer < NUM_PEERS; peer++)
107   {
108         if (NULL != ph[peer].stat_op)
109                 GNUNET_TESTBED_operation_done (ph[peer].stat_op);
110         ph[peer].stat_op = NULL;
111   }
112
113   if (NULL != op)
114   {
115     GNUNET_TESTBED_operation_done (op);
116     op = NULL;
117   }
118   GNUNET_SCHEDULER_shutdown ();
119 }
120
121 /**
122  * Controller event callback
123  *
124  * @param cls NULL
125  * @param event the controller event
126  */
127 static void
128 controller_event_cb (void *cls,
129                      const struct GNUNET_TESTBED_EventInformation *event)
130 {
131   switch (event->type)
132   {
133   case GNUNET_TESTBED_ET_CONNECT:
134     overlay_connects++;
135     if ((NUM_PEERS * (NUM_PEERS - 1)) == overlay_connects)
136     {
137       result = GNUNET_OK;
138       GNUNET_log (GNUNET_ERROR_TYPE_INFO, "All %u peers connected \n", NUM_PEERS);
139       if (GNUNET_SCHEDULER_NO_TASK != shutdown_task)
140       {
141                 GNUNET_SCHEDULER_cancel (shutdown_task);
142       }
143       shutdown_task = GNUNET_SCHEDULER_add_delayed (TEST_TIMEOUT, do_shutdown, NULL);
144     }
145     break;
146   case GNUNET_TESTBED_ET_OPERATION_FINISHED:
147     break;
148   default:
149     GNUNET_break (0);
150     result = GNUNET_SYSERR;
151     GNUNET_SCHEDULER_cancel (shutdown_task);
152     shutdown_task = GNUNET_SCHEDULER_add_now (&do_shutdown, NULL);
153   }
154 }
155
156 static void
157 check_end ()
158 {
159         static int last_value = 0;
160   unsigned int peer;
161   unsigned int total_active = 0;
162   unsigned int total_inactive = 0;
163   unsigned int total_requested = 0;
164   unsigned int issuer = 0;
165
166         for (peer = 0; peer < NUM_PEERS; peer++)
167         {
168                         total_active += ph[peer].active_nodes;
169                         total_requested += ph[peer].requested_nodes;
170                         total_inactive += ph[peer].inactive_nodes;
171                         if (1 == ph[peer].issuer)
172                                 issuer ++;
173
174         }
175         if (last_value < total_active)
176                 fprintf (stderr, ".");
177
178         if ((total_active == (NUM_PEERS * (NUM_PEERS -1))) &&
179                  (total_requested == 0) && (total_inactive == 0) &&
180                  (issuer == NUM_PEERS))
181         {
182                         fprintf (stderr, "\n");
183                         GNUNET_log (GNUNET_ERROR_TYPE_INFO, "All %u peers active in a clique\n", NUM_PEERS);
184                         GNUNET_SCHEDULER_add_now (&do_shutdown, NULL);
185         }
186 }
187
188
189
190 /**
191  * Callback function to process statistic values.
192  *
193  * @param cls struct StatsContext
194  * @param subsystem name of subsystem that created the statistic
195  * @param name the name of the datum
196  * @param value the current value
197  * @param is_persistent GNUNET_YES if the value is persistent, GNUNET_NO if not
198  * @return GNUNET_OK to continue, GNUNET_SYSERR to abort iteration
199  */
200 static int
201 stat_iterator (void *cls, const char *subsystem, const char *name,
202                      uint64_t value, int is_persistent)
203 {
204   struct ExperimentationPeer *peer = cls;
205
206         if (0 == strcmp (name, "# nodes active"))
207         {
208                         peer->active_nodes = value;
209         }
210         if (0 == strcmp (name, "# nodes inactive"))
211         {
212                         peer->inactive_nodes = value;
213         }
214         if (0 == strcmp (name, "# nodes requested"))
215         {
216                         peer->requested_nodes = value;
217         }
218         if (0 == strcmp (name, "# issuer"))
219         {
220                         peer->issuer = value;
221         }
222
223         check_end ();
224
225         return GNUNET_OK;
226 }
227
228 /**
229  * Called after successfully opening a connection to a peer's statistics
230  * service; we register statistics monitoring here.
231  *
232  * @param cls the callback closure from functions generating an operation
233  * @param op the operation that has been finished
234  * @param ca_result the service handle returned from GNUNET_TESTBED_ConnectAdapter()
235  * @param emsg error message in case the operation has failed; will be NULL if
236  *          operation has executed successfully.
237  */
238 static void
239 stat_comp_cb (void *cls, struct GNUNET_TESTBED_Operation *op,
240               void *ca_result, const char *emsg )
241 {
242   struct GNUNET_STATISTICS_Handle *sh = ca_result;
243   struct ExperimentationPeer *peer = cls;
244
245   if (NULL != emsg)
246   {
247     GNUNET_break (0);
248     return;
249   }
250
251   GNUNET_break (GNUNET_OK == GNUNET_STATISTICS_watch
252                 (sh, "experimentation", "# nodes active",
253                  stat_iterator, peer));
254   GNUNET_break (GNUNET_OK == GNUNET_STATISTICS_watch
255                 (sh, "experimentation", "# nodes inactive",
256                  stat_iterator, peer));
257   GNUNET_break (GNUNET_OK == GNUNET_STATISTICS_watch
258                 (sh, "experimentation", "# nodes requested",
259                  stat_iterator, peer));
260   GNUNET_break (GNUNET_OK == GNUNET_STATISTICS_watch
261                 (sh, "experimentation", "# issuer",
262                  stat_iterator, peer));
263 }
264
265 /**
266  * Called to open a connection to the peer's statistics
267  *
268  * @param cls peer context
269  * @param cfg configuration of the peer to connect to; will be available until
270  *          GNUNET_TESTBED_operation_done() is called on the operation returned
271  *          from GNUNET_TESTBED_service_connect()
272  * @return service handle to return in 'op_result', NULL on error
273  */
274 static void *
275 stat_connect_adapter (void *cls,
276                       const struct GNUNET_CONFIGURATION_Handle *cfg)
277 {
278   struct ExperimentationPeer *peer = cls;
279   peer->sh = GNUNET_STATISTICS_create ("experimentation", cfg);
280   if (NULL == peer->sh)
281     GNUNET_log (GNUNET_ERROR_TYPE_ERROR, "Failed to create statistics \n");
282   return peer->sh;
283 }
284
285
286 /**
287  * Called to disconnect from peer's statistics service
288  *
289  * @param cls peer context
290  * @param op_result service handle returned from the connect adapter
291  */
292 static void
293 stat_disconnect_adapter (void *cls, void *op_result)
294 {
295   struct ExperimentationPeer *peer = cls;
296
297   GNUNET_break (GNUNET_OK == GNUNET_STATISTICS_watch_cancel
298                 (peer->sh, "experimentation", "# nodes active",
299                  stat_iterator, peer));
300   GNUNET_break (GNUNET_OK == GNUNET_STATISTICS_watch_cancel
301                 (peer->sh, "experimentation", "# nodes inactive",
302                  stat_iterator, peer));
303   GNUNET_break (GNUNET_OK == GNUNET_STATISTICS_watch_cancel
304                 (peer->sh, "experimentation", "# nodes requested",
305                  stat_iterator, peer));
306   GNUNET_STATISTICS_destroy (op_result, GNUNET_NO);
307   peer->sh = NULL;
308 }
309
310
311
312 /**
313  * Signature of a main function for a testcase.
314  *
315  * @param cls closure
316  * @param num_peers number of peers in 'peers'
317  * @param peers_ handle to peers run in the testbed
318  * @param links_succeeded the number of overlay link connection attempts that
319  *          succeeded
320  * @param links_failed the number of overlay link connection attempts that
321  *          failed
322  */
323 static void
324 test_master (void *cls, unsigned int num_peers,
325              struct GNUNET_TESTBED_Peer **peers_,
326              unsigned int links_succeeded,
327              unsigned int links_failed)
328 {
329   unsigned int peer;
330
331   GNUNET_assert (NULL == cls);
332   GNUNET_assert (NUM_PEERS == num_peers);
333   GNUNET_assert (NULL != peers_);
334   for (peer = 0; peer < num_peers; peer++)
335   {
336     GNUNET_assert (NULL != peers_[peer]);
337     /* Connect to peer's statistic service */
338     ph[peer].stat_op = GNUNET_TESTBED_service_connect (NULL,
339                                                                                                                                 peers_[peer], "statistics",
340                                                                                                                                 &stat_comp_cb, &ph[peer],
341                                     &stat_connect_adapter,
342                                     &stat_disconnect_adapter,
343                                     &ph[peer]);
344
345   }
346   peers = peers_;
347   overlay_connects = 0;
348   op = GNUNET_TESTBED_overlay_configure_topology (NULL, NUM_PEERS, peers, NULL,
349                                                   NULL,
350                                                   NULL,
351                                                   GNUNET_TESTBED_TOPOLOGY_CLIQUE,
352                                                   /* GNUNET_TESTBED_TOPOLOGY_ERDOS_RENYI, */
353                                                   /* NUM_PEERS, */
354                                                   GNUNET_TESTBED_TOPOLOGY_OPTION_END);
355   GNUNET_assert (NULL != op);
356   shutdown_task = GNUNET_SCHEDULER_add_delayed (TEST_TIMEOUT, do_shutdown, NULL);
357 }
358
359
360 /**
361  * Main function
362  */
363 int
364 main (int argc, char **argv)
365 {
366   uint64_t event_mask;
367
368   result = GNUNET_SYSERR;
369   event_mask = 0;
370   event_mask |= (1LL << GNUNET_TESTBED_ET_CONNECT);
371   event_mask |= (1LL << GNUNET_TESTBED_ET_OPERATION_FINISHED);
372   (void) GNUNET_TESTBED_test_run ("test_experimentation_clique",
373                                   "test_experimentation_clique.conf", NUM_PEERS,
374                                   event_mask, &controller_event_cb, NULL,
375                                   &test_master, NULL);
376   if (GNUNET_OK != result)
377     return 1;
378   return 0;
379 }
380
381 /* end of test_testbed_api_topology.c */