split up code to multiple files
[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 };
89
90
91 struct ExperimentationPeer ph[NUM_PEERS];
92
93 /**
94  * Shutdown nicely
95  *
96  * @param cls NULL
97  * @param tc the task context
98  */
99 static void
100 do_shutdown (void *cls, const struct GNUNET_SCHEDULER_TaskContext *tc)
101 {
102   unsigned int peer;
103         shutdown_task = GNUNET_SCHEDULER_NO_TASK;
104
105   for (peer = 0; peer < NUM_PEERS; peer++)
106   {
107         if (NULL != ph[peer].stat_op)
108                 GNUNET_TESTBED_operation_done (ph[peer].stat_op);
109         ph[peer].stat_op = NULL;
110   }
111
112   if (NULL != op)
113   {
114     GNUNET_TESTBED_operation_done (op);
115     op = NULL;
116   }
117   GNUNET_SCHEDULER_shutdown ();
118 }
119
120 /**
121  * Controller event callback
122  *
123  * @param cls NULL
124  * @param event the controller event
125  */
126 static void
127 controller_event_cb (void *cls,
128                      const struct GNUNET_TESTBED_EventInformation *event)
129 {
130   switch (event->type)
131   {
132   case GNUNET_TESTBED_ET_CONNECT:
133     overlay_connects++;
134     if ((NUM_PEERS * (NUM_PEERS - 1)) == overlay_connects)
135     {
136       result = GNUNET_OK;
137       GNUNET_log (GNUNET_ERROR_TYPE_INFO, "All %u peers connected \n", NUM_PEERS);
138       if (GNUNET_SCHEDULER_NO_TASK != shutdown_task)
139       {
140                 GNUNET_SCHEDULER_cancel (shutdown_task);
141       }
142       shutdown_task = GNUNET_SCHEDULER_add_delayed (TEST_TIMEOUT, do_shutdown, NULL);
143     }
144     break;
145   case GNUNET_TESTBED_ET_OPERATION_FINISHED:
146     break;
147   default:
148     GNUNET_break (0);
149     result = GNUNET_SYSERR;
150     GNUNET_SCHEDULER_cancel (shutdown_task);
151     shutdown_task = GNUNET_SCHEDULER_add_now (&do_shutdown, NULL);
152   }
153 }
154
155 static void
156 check_end ()
157 {
158         static int last_value = 0;
159   unsigned int peer;
160   unsigned int total_active = 0;
161   unsigned int total_inactive = 0;
162   unsigned int total_requested = 0;
163
164         for (peer = 0; peer < NUM_PEERS; peer++)
165         {
166                         total_active += ph[peer].active_nodes;
167                         total_requested += ph[peer].requested_nodes;
168                         total_inactive += ph[peer].inactive_nodes;
169         }
170         if (last_value < total_active)
171                 fprintf (stderr, ".");
172
173         if ((total_active == (NUM_PEERS * (NUM_PEERS -1))) &&
174                  (total_requested == 0) && (total_inactive == 0))
175         {
176                         fprintf (stderr, "\n");
177                         GNUNET_log (GNUNET_ERROR_TYPE_INFO, "All %u peers active in a clique\n", NUM_PEERS);
178                         GNUNET_SCHEDULER_add_now (&do_shutdown, NULL);
179         }
180 }
181
182
183
184 /**
185  * Callback function to process statistic values.
186  *
187  * @param cls struct StatsContext
188  * @param subsystem name of subsystem that created the statistic
189  * @param name the name of the datum
190  * @param value the current value
191  * @param is_persistent GNUNET_YES if the value is persistent, GNUNET_NO if not
192  * @return GNUNET_OK to continue, GNUNET_SYSERR to abort iteration
193  */
194 static int
195 stat_iterator (void *cls, const char *subsystem, const char *name,
196                      uint64_t value, int is_persistent)
197 {
198   struct ExperimentationPeer *peer = cls;
199
200         if (0 == strcmp (name, "# nodes active"))
201         {
202                         peer->active_nodes = value;
203         }
204         if (0 == strcmp (name, "# nodes inactive"))
205         {
206                         peer->inactive_nodes = value;
207         }
208         if (0 == strcmp (name, "# nodes requested"))
209         {
210                         peer->requested_nodes = value;
211         }
212         check_end ();
213
214         return GNUNET_OK;
215 }
216
217 /**
218  * Called after successfully opening a connection to a peer's statistics
219  * service; we register statistics monitoring here.
220  *
221  * @param cls the callback closure from functions generating an operation
222  * @param op the operation that has been finished
223  * @param ca_result the service handle returned from GNUNET_TESTBED_ConnectAdapter()
224  * @param emsg error message in case the operation has failed; will be NULL if
225  *          operation has executed successfully.
226  */
227 static void
228 stat_comp_cb (void *cls, struct GNUNET_TESTBED_Operation *op,
229               void *ca_result, const char *emsg )
230 {
231   struct GNUNET_STATISTICS_Handle *sh = ca_result;
232   struct ExperimentationPeer *peer = cls;
233
234   if (NULL != emsg)
235   {
236     GNUNET_break (0);
237     return;
238   }
239
240   GNUNET_break (GNUNET_OK == GNUNET_STATISTICS_watch
241                 (sh, "experimentation", "# nodes active",
242                  stat_iterator, peer));
243   GNUNET_break (GNUNET_OK == GNUNET_STATISTICS_watch
244                 (sh, "experimentation", "# nodes inactive",
245                  stat_iterator, peer));
246   GNUNET_break (GNUNET_OK == GNUNET_STATISTICS_watch
247                 (sh, "experimentation", "# nodes requested",
248                  stat_iterator, peer));
249 }
250
251 /**
252  * Called to open a connection to the peer's statistics
253  *
254  * @param cls peer context
255  * @param cfg configuration of the peer to connect to; will be available until
256  *          GNUNET_TESTBED_operation_done() is called on the operation returned
257  *          from GNUNET_TESTBED_service_connect()
258  * @return service handle to return in 'op_result', NULL on error
259  */
260 static void *
261 stat_connect_adapter (void *cls,
262                       const struct GNUNET_CONFIGURATION_Handle *cfg)
263 {
264   struct ExperimentationPeer *peer = cls;
265   peer->sh = GNUNET_STATISTICS_create ("experimentation", cfg);
266   if (NULL == peer->sh)
267     GNUNET_log (GNUNET_ERROR_TYPE_ERROR, "Failed to create statistics \n");
268   return peer->sh;
269 }
270
271
272 /**
273  * Called to disconnect from peer's statistics service
274  *
275  * @param cls peer context
276  * @param op_result service handle returned from the connect adapter
277  */
278 static void
279 stat_disconnect_adapter (void *cls, void *op_result)
280 {
281   struct ExperimentationPeer *peer = cls;
282
283   GNUNET_break (GNUNET_OK == GNUNET_STATISTICS_watch_cancel
284                 (peer->sh, "experimentation", "# nodes active",
285                  stat_iterator, peer));
286   GNUNET_break (GNUNET_OK == GNUNET_STATISTICS_watch_cancel
287                 (peer->sh, "experimentation", "# nodes inactive",
288                  stat_iterator, peer));
289   GNUNET_break (GNUNET_OK == GNUNET_STATISTICS_watch_cancel
290                 (peer->sh, "experimentation", "# nodes requested",
291                  stat_iterator, peer));
292   GNUNET_STATISTICS_destroy (op_result, GNUNET_NO);
293   peer->sh = NULL;
294 }
295
296
297
298 /**
299  * Signature of a main function for a testcase.
300  *
301  * @param cls closure
302  * @param num_peers number of peers in 'peers'
303  * @param peers_ handle to peers run in the testbed
304  * @param links_succeeded the number of overlay link connection attempts that
305  *          succeeded
306  * @param links_failed the number of overlay link connection attempts that
307  *          failed
308  */
309 static void
310 test_master (void *cls, unsigned int num_peers,
311              struct GNUNET_TESTBED_Peer **peers_,
312              unsigned int links_succeeded,
313              unsigned int links_failed)
314 {
315   unsigned int peer;
316
317   GNUNET_assert (NULL == cls);
318   GNUNET_assert (NUM_PEERS == num_peers);
319   GNUNET_assert (NULL != peers_);
320   for (peer = 0; peer < num_peers; peer++)
321   {
322     GNUNET_assert (NULL != peers_[peer]);
323     /* Connect to peer's statistic service */
324     ph[peer].stat_op = GNUNET_TESTBED_service_connect (NULL,
325                                                                                                                                 peers_[peer], "statistics",
326                                                                                                                                 &stat_comp_cb, &ph[peer],
327                                     &stat_connect_adapter,
328                                     &stat_disconnect_adapter,
329                                     &ph[peer]);
330
331   }
332   peers = peers_;
333   overlay_connects = 0;
334   op = GNUNET_TESTBED_overlay_configure_topology (NULL, NUM_PEERS, peers, NULL,
335                                                   NULL,
336                                                   NULL,
337                                                   GNUNET_TESTBED_TOPOLOGY_CLIQUE,
338                                                   /* GNUNET_TESTBED_TOPOLOGY_ERDOS_RENYI, */
339                                                   /* NUM_PEERS, */
340                                                   GNUNET_TESTBED_TOPOLOGY_OPTION_END);
341   GNUNET_assert (NULL != op);
342   shutdown_task = GNUNET_SCHEDULER_add_delayed (TEST_TIMEOUT, do_shutdown, NULL);
343 }
344
345
346 /**
347  * Main function
348  */
349 int
350 main (int argc, char **argv)
351 {
352   uint64_t event_mask;
353
354   result = GNUNET_SYSERR;
355   event_mask = 0;
356   event_mask |= (1LL << GNUNET_TESTBED_ET_CONNECT);
357   event_mask |= (1LL << GNUNET_TESTBED_ET_OPERATION_FINISHED);
358   (void) GNUNET_TESTBED_test_run ("test_experimentation_clique",
359                                   "test_experimentation_clique.conf", NUM_PEERS,
360                                   event_mask, &controller_event_cb, NULL,
361                                   &test_master, NULL);
362   if (GNUNET_OK != result)
363     return 1;
364   return 0;
365 }
366
367 /* end of test_testbed_api_topology.c */