256b9efa0fedfa33fbdf5755b3eaa1d6206c6b47
[oweals/gnunet.git] / src / testbed / gnunet-testbed-profiler.c
1 /*
2      This file is part of GNUnet.
3      (C) 2011, 2012 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-testbed-profiler.c
23  * @brief Profiling driver for the testbed.
24  * @author Sree Harsha Totakura <sreeharsha@totakura.in> 
25  */
26
27 #include "platform.h"
28 #include "gnunet_common.h"
29 #include "gnunet_testbed_service.h"
30 #include "testbed_api_hosts.h"
31
32
33 /**
34  * An array of hosts loaded from the hostkeys file
35  */
36 static struct GNUNET_TESTBED_Host **hosts;
37
38 /**
39  * The array of peers; we fill this as the peers are given to us by the testbed
40  */
41 static struct GNUNET_TESTBED_Peer **peers;
42
43 /**
44  * Operation handle
45  */
46 static struct GNUNET_TESTBED_Operation *op;
47
48 /**
49  * Abort task identifier
50  */
51 static GNUNET_SCHEDULER_TaskIdentifier abort_task;
52
53 /**
54  * Current peer id
55  */
56 unsigned int peer_id;
57
58 /**
59  * Number of peers to be started by the profiler
60  */
61 static unsigned int num_peers;
62
63 /**
64  * Number of hosts in the hosts array
65  */
66 static unsigned int num_hosts;
67
68 /**
69  * Global testing status
70  */
71 static int result;
72
73
74 /**
75  * Shutdown nicely
76  *
77  * @param cls NULL
78  * @param tc the task context
79  */
80 static void
81 do_shutdown (void *cls, const struct GNUNET_SCHEDULER_TaskContext *tc)
82 {
83   unsigned int nhost;
84
85   if (GNUNET_SCHEDULER_NO_TASK != abort_task)
86     GNUNET_SCHEDULER_cancel (abort_task);
87   GNUNET_free_non_null (peers);
88   for (nhost = 0; nhost < num_hosts; nhost++)
89     if (NULL != hosts[nhost])
90       GNUNET_TESTBED_host_destroy (hosts[nhost]);
91   GNUNET_free_non_null (hosts);
92   GNUNET_SCHEDULER_shutdown (); /* Stop scheduler to shutdown testbed run */
93 }
94
95
96 /**
97  * abort task to run on test timed out
98  *
99  * @param cls NULL
100  * @param tc the task context
101  */
102 static void
103 do_abort (void *cls, const struct GNUNET_SCHEDULER_TaskContext *tc)
104 {
105   GNUNET_log (GNUNET_ERROR_TYPE_WARNING, "Profiling timedout -- Aborting\n");
106   abort_task = GNUNET_SCHEDULER_NO_TASK;
107   GNUNET_SCHEDULER_add_now (&do_shutdown, NULL);
108 }
109
110
111 /**
112  * Task to be executed when peers are ready
113  *
114  * @param cls NULL
115  * @param tc the task context
116  */
117 static void
118 master_task (void *cls, const struct GNUNET_SCHEDULER_TaskContext *tc)
119 {
120   result = GNUNET_OK;
121   GNUNET_assert (NULL != peers[0]);
122   op = GNUNET_TESTBED_peer_stop (peers[0], NULL, NULL);
123   GNUNET_assert (NULL != op);
124 }
125
126
127 /**
128  * Controller event callback
129  *
130  * @param cls NULL
131  * @param event the controller event
132  */
133 static void
134 controller_event_cb (void *cls,
135                      const struct GNUNET_TESTBED_EventInformation *event)
136 {
137
138   switch (event->type)
139   {
140   case GNUNET_TESTBED_ET_PEER_START:
141     GNUNET_assert (NULL == peers[peer_id]);
142     GNUNET_assert (NULL != event->details.peer_start.peer);
143     peers[peer_id++] = event->details.peer_start.peer;
144     break;
145   case GNUNET_TESTBED_ET_PEER_STOP:
146     GNUNET_assert (NULL != op);
147     GNUNET_TESTBED_operation_done (op);
148     GNUNET_assert (peers[0] == event->details.peer_stop.peer);
149     GNUNET_SCHEDULER_add_now (&do_shutdown, NULL);
150     break;
151   default:
152     GNUNET_assert (0);
153   }
154 }
155
156
157 /**
158  * Main function that will be run by the scheduler.
159  *
160  * @param cls closure
161  * @param args remaining command-line arguments
162  * @param cfgfile name of the configuration file used (for saving, can be NULL!)
163  * @param cfg configuration
164  */
165 static void
166 run (void *cls, char *const *args, const char *cfgfile,
167      const struct GNUNET_CONFIGURATION_Handle *config)
168 {
169   uint64_t event_mask;
170   unsigned int nhost;
171
172   if (NULL == args[0])
173   {
174     FPRINTF (stderr, _("No hosts-file specified on command line\n"));
175     return;
176   }
177   if (0 == num_peers)
178   {
179     result = GNUNET_OK;
180     return;
181   }
182   num_hosts = GNUNET_TESTBED_hosts_load_from_file (args[0], &hosts);
183   if (0 == num_hosts)
184   {
185     FPRINTF (stderr, _("No hosts loaded\n"));
186     return;
187   }
188   for (nhost = 0; nhost < num_hosts; nhost++)
189   {
190     if (GNUNET_YES != GNUNET_TESTBED_is_host_habitable (hosts[nhost]))
191     {
192       FPRINTF (stderr, _("Host %s cannot start testbed\n"),
193                          GNUNET_TESTBED_host_get_hostname_ (hosts[nhost]));
194       break;
195     }
196   }
197   if (num_hosts != nhost)
198   {
199     GNUNET_SCHEDULER_add_now (&do_shutdown, NULL);
200     return;
201   }
202   peers = GNUNET_malloc (num_peers * sizeof (struct GNUNET_TESTBED_Peer *));
203   event_mask = 0;
204   event_mask |= (1LL << GNUNET_TESTBED_ET_PEER_START);
205   event_mask |= (1LL << GNUNET_TESTBED_ET_PEER_STOP);
206   event_mask |= (1LL << GNUNET_TESTBED_ET_CONNECT);
207   event_mask |= (1LL << GNUNET_TESTBED_ET_DISCONNECT);
208   GNUNET_TESTBED_run (NULL, config, num_peers, event_mask, &controller_event_cb,
209                       NULL, &master_task, NULL);
210   abort_task =
211       GNUNET_SCHEDULER_add_delayed (GNUNET_TIME_relative_multiply
212                                     (GNUNET_TIME_UNIT_SECONDS, 5), &do_abort,
213                                     NULL);
214 }
215
216
217 /**
218  * Main function.
219  *
220  * @return 0 on success
221  */
222 int
223 main (int argc, char *const *argv)
224 {
225   static const struct GNUNET_GETOPT_CommandLineOption options[] = {
226     { 'n', "num-peers", "COUNT",
227       gettext_noop ("create COUNT number of peers"),
228       GNUNET_YES, &GNUNET_GETOPT_set_uint, &num_peers },
229     { 'n', "num-peers", "COUNT",
230       gettext_noop ("create COUNT number of peers"),
231       GNUNET_YES, &GNUNET_GETOPT_set_uint, &num_peers },
232     GNUNET_GETOPT_OPTION_END
233   };
234   int ret;
235
236   if (GNUNET_OK != GNUNET_STRINGS_get_utf8_args (argc, argv, &argc, &argv))
237     return 2;
238   
239   result = GNUNET_SYSERR;
240   ret =
241       GNUNET_PROGRAM_run (argc, argv, "gnunet-testbed-profiler [OPTIONS] hosts-file",
242                           _("Profiler for testbed"),
243                           options, &run, NULL);
244   if (GNUNET_OK != ret)
245     return ret;
246   if (GNUNET_OK != result)
247     return 1;
248   return 0;
249 }