add statistic to track estimated network diameter
[oweals/gnunet.git] / src / nse / gnunet-nse-profiler.c
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 nse/gnunet-nse-profiler.c
22  *
23  * @brief Profiling driver for the network size estimation service.
24  *        Generally, the profiler starts a given number of peers,
25  *        then churns some off, waits a certain amount of time, then
26  *        churns again, and repeats.
27  */
28 #include "platform.h"
29 #include "gnunet_testing_lib.h"
30 #include "gnunet_nse_service.h"
31
32 #define VERBOSE 3
33
34 struct NSEPeer
35 {
36   struct NSEPeer *prev;
37
38   struct NSEPeer *next;
39
40   struct GNUNET_TESTING_Daemon *daemon;
41
42   struct GNUNET_NSE_Handle *nse_handle;
43
44   struct GNUNET_STATISTICS_Handle *stats;
45   
46   GNUNET_SCHEDULER_TaskIdentifier stats_task;
47 };
48
49
50 struct StatsContext
51 {
52   unsigned long long total_nse_bytes;
53 };
54
55
56 static struct NSEPeer *peer_head;
57
58 static struct NSEPeer *peer_tail;
59
60 /**
61  * How long until we give up on connecting the peers?
62  */
63 #define TIMEOUT GNUNET_TIME_relative_multiply (GNUNET_TIME_UNIT_SECONDS, 1500)
64
65 static int ok;
66
67 /**
68  * Be verbose
69  */
70 static int verbose;
71
72 /**
73  * Total number of peers in the test.
74  */
75 static unsigned long long num_peers;
76
77 /**
78  * Global configuration file
79  */
80 static struct GNUNET_CONFIGURATION_Handle *testing_cfg;
81
82 /**
83  * Total number of currently running peers.
84  */
85 static unsigned long long peers_running;
86
87 /**
88  * Current round we are in.
89  */
90 static unsigned long long current_round;
91
92 /**
93  * Peers desired in the next round.
94  */
95 static unsigned long long peers_next_round;
96
97 /**
98  * Maximum number of connections to NSE services.
99  */
100 static unsigned long long connection_limit;
101
102 /**
103  * Total number of connections in the whole network.
104  */
105 static unsigned int total_connections;
106
107 /**
108  * The currently running peer group.
109  */
110 static struct GNUNET_TESTING_PeerGroup *pg;
111
112 /**
113  * File to report results to.
114  */
115 static struct GNUNET_DISK_FileHandle *output_file;
116
117 /**
118  * File to log connection info, statistics to.
119  */
120 static struct GNUNET_DISK_FileHandle *data_file;
121
122 /**
123  * How many data points to capture before triggering next round?
124  */
125 static struct GNUNET_TIME_Relative wait_time;
126
127 /**
128  * NSE interval.
129  */
130 static struct GNUNET_TIME_Relative interval;
131
132 /**
133  * Task called to disconnect peers.
134  */
135 static GNUNET_SCHEDULER_TaskIdentifier disconnect_task;
136
137 /**
138  * Task called to shutdown test.
139  */
140 static GNUNET_SCHEDULER_TaskIdentifier shutdown_handle;
141
142 /**
143  * Task used to churn the network.
144  */
145 static GNUNET_SCHEDULER_TaskIdentifier churn_task;
146
147 static char *topology_file;
148
149 /**
150  * Check whether peers successfully shut down.
151  */
152 static void
153 shutdown_callback (void *cls, const char *emsg)
154 {
155   if (emsg != NULL)
156   {
157 #if VERBOSE
158     GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "Shutdown of peers failed!\n");
159 #endif
160     if (ok == 0)
161       ok = 666;
162   }
163   else
164   {
165 #if VERBOSE
166     GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "All peers successfully shut down!\n");
167 #endif
168     ok = 0;
169   }
170 }
171
172
173 static void
174 shutdown_task (void *cls, const struct GNUNET_SCHEDULER_TaskContext *tc)
175 {
176   struct NSEPeer *pos;
177
178 #if VERBOSE
179   fprintf (stderr, "Ending test.\n");
180 #endif
181
182   if (disconnect_task != GNUNET_SCHEDULER_NO_TASK)
183   {
184     GNUNET_SCHEDULER_cancel (disconnect_task);
185     disconnect_task = GNUNET_SCHEDULER_NO_TASK;
186   }
187   while (NULL != (pos = peer_head))
188   {
189     if (pos->nse_handle != NULL)
190       GNUNET_NSE_disconnect (pos->nse_handle);
191     GNUNET_CONTAINER_DLL_remove (peer_head, peer_tail, pos);
192     GNUNET_free (pos);
193   }
194
195   if (data_file != NULL)
196     GNUNET_DISK_file_close (data_file);
197   GNUNET_TESTING_daemons_stop (pg, TIMEOUT, &shutdown_callback, NULL);
198 }
199
200
201 /**
202  * Callback to call when network size estimate is updated.
203  *
204  * @param cls closure
205  * @param timestamp server timestamp
206  * @param estimate the value of the current network size estimate
207  * @param std_dev standard deviation (rounded down to nearest integer)
208  *                of the size estimation values seen
209  *
210  */
211 static void
212 handle_estimate (void *cls, struct GNUNET_TIME_Absolute timestamp,
213                  double estimate, double std_dev)
214 {
215   struct NSEPeer *peer = cls;
216   char *output_buffer;
217   size_t size;
218
219   if (output_file != NULL)
220   {
221     size =
222         GNUNET_asprintf (&output_buffer, "%s %llu %llu %f %f %f\n",
223                          GNUNET_i2s (&peer->daemon->id), peers_running,
224                          timestamp.abs_value,
225                          GNUNET_NSE_log_estimate_to_n (estimate), estimate,
226                          std_dev);
227     if (size != GNUNET_DISK_file_write (output_file, output_buffer, size))
228       GNUNET_log (GNUNET_ERROR_TYPE_WARNING, "Unable to write to file!\n");
229     GNUNET_free (output_buffer);
230   }
231   else
232     fprintf (stderr,
233              "Received network size estimate from peer %s. Size: %f std.dev. %f\n",
234              GNUNET_i2s (&peer->daemon->id), estimate, std_dev);
235
236 }
237
238 /**
239  * Process core statistic values.
240  *
241  * @param cls closure
242  * @param subsystem name of subsystem that created the statistic
243  * @param name the name of the datum
244  * @param value the current value
245  * @param is_persistent GNUNET_YES if the value is persistent, GNUNET_NO if not
246  * @return GNUNET_OK to continue, GNUNET_SYSERR to abort iteration
247  */
248 static int
249 core_stats_iterator (void *cls, const char *subsystem, const char *name,
250                      uint64_t value, int is_persistent)
251 {
252   struct NSEPeer *peer = cls;
253   char *output_buffer;
254   size_t size;
255
256   if (output_file != NULL)
257   {
258     size =
259         GNUNET_asprintf (&output_buffer, "%s [%s] %s %llu\n",
260                           GNUNET_i2s (&peer->daemon->id),
261                          subsystem, name, value);
262     if (size != GNUNET_DISK_file_write (output_file, output_buffer, size))
263       GNUNET_log (GNUNET_ERROR_TYPE_WARNING, "Unable to write to file!\n");
264     GNUNET_free (output_buffer);
265   }
266   else
267     GNUNET_log (GNUNET_ERROR_TYPE_INFO,
268                 "%s -> %s [%s]: %llu\n",
269                 GNUNET_i2s (&peer->daemon->id), subsystem, name, value);
270
271   return GNUNET_OK;
272 }
273
274 /**
275  * Continuation called by "get_stats" function.
276  *
277  * @param cls closure
278  * @param success GNUNET_OK if statistics were
279  *        successfully obtained, GNUNET_SYSERR if not.
280  */
281 static void
282 core_stats_cont (void *cls, int success);
283
284 static void
285 core_get_stats (void *cls, const struct GNUNET_SCHEDULER_TaskContext *tc)
286 {
287   struct NSEPeer *peer = cls;
288   
289   peer->stats_task = GNUNET_SCHEDULER_NO_TASK;
290   if ((tc->reason & GNUNET_SCHEDULER_REASON_SHUTDOWN) != 0)
291   {
292     GNUNET_STATISTICS_destroy(peer->stats, GNUNET_NO);
293     peer->stats = NULL;
294   }
295   else
296   {
297     GNUNET_STATISTICS_get(peer->stats, "core", NULL,
298                           GNUNET_TIME_UNIT_FOREVER_REL,
299                           &core_stats_cont, &core_stats_iterator, peer);
300     GNUNET_STATISTICS_get(peer->stats, "transport", NULL,
301                           GNUNET_TIME_UNIT_FOREVER_REL,
302                           NULL, &core_stats_iterator, peer);
303     GNUNET_STATISTICS_get(peer->stats, "nse", NULL,
304                           GNUNET_TIME_UNIT_FOREVER_REL,
305                           NULL, &core_stats_iterator, peer);
306   }
307 }
308
309 /**
310  * Continuation called by "get_stats" function.
311  *
312  * @param cls closure
313  * @param success GNUNET_OK if statistics were
314  *        successfully obtained, GNUNET_SYSERR if not.
315  */
316 static void
317 core_stats_cont (void *cls, int success)
318 {
319   struct NSEPeer *peer = cls;
320   peer->stats_task = GNUNET_SCHEDULER_add_delayed (interval, &core_get_stats,
321                                                    peer);
322 }
323
324
325 /**
326  *
327  */
328 static void
329 connect_nse_service (void *cls, const struct GNUNET_SCHEDULER_TaskContext *tc)
330 {
331   struct NSEPeer *current_peer;
332   unsigned int i;
333
334 #if VERBOSE
335   GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "Connecting to nse service of peers\n");
336 #endif
337   for (i = 0; i < num_peers; i++)
338   {
339     if ((connection_limit > 0) && (i % (num_peers / connection_limit) != 0))
340       continue;
341 #if VERBOSE
342     GNUNET_log (GNUNET_ERROR_TYPE_WARNING,
343                 "nse-profiler: connecting to nse service of peer %d\n", i);
344 #endif
345     current_peer = GNUNET_malloc (sizeof (struct NSEPeer));
346     current_peer->daemon = GNUNET_TESTING_daemon_get (pg, i);
347     if (GNUNET_YES ==
348         GNUNET_TESTING_test_daemon_running (GNUNET_TESTING_daemon_get (pg, i)))
349     {
350       current_peer->nse_handle =
351           GNUNET_NSE_connect (current_peer->daemon->cfg, &handle_estimate,
352                               current_peer);
353       GNUNET_assert (current_peer->nse_handle != NULL);
354     }
355     current_peer->stats = GNUNET_STATISTICS_create("profiler", current_peer->daemon->cfg);
356     GNUNET_STATISTICS_get(current_peer->stats, "core", NULL,
357                           GNUNET_TIME_UNIT_FOREVER_REL,
358                           &core_stats_cont, &core_stats_iterator, current_peer);
359     GNUNET_STATISTICS_get(current_peer->stats, "transport", NULL,
360                           GNUNET_TIME_UNIT_FOREVER_REL,
361                           NULL, &core_stats_iterator, current_peer);
362     GNUNET_STATISTICS_get(current_peer->stats, "nse", NULL,
363                           GNUNET_TIME_UNIT_FOREVER_REL,
364                           NULL, &core_stats_iterator, current_peer);
365     GNUNET_CONTAINER_DLL_insert (peer_head, peer_tail, current_peer);
366   }
367 }
368
369
370 static void
371 churn_peers (void *cls, const struct GNUNET_SCHEDULER_TaskContext *tc);
372
373
374 /**
375  * Continuation called by the "get_all" and "get" functions.
376  *
377  * @param cls struct StatsContext
378  * @param success GNUNET_OK if statistics were
379  *        successfully obtained, GNUNET_SYSERR if not.
380  */
381 static void
382 stats_finished_callback (void *cls, int success)
383 {
384   struct StatsContext *stats_context = cls;
385   char *buf;
386   int buf_len;
387
388   if ((GNUNET_OK == success) && (data_file != NULL))
389   {
390     /* Stats lookup successful, write out data */
391     buf = NULL;
392     buf_len =
393         GNUNET_asprintf (&buf, "TOTAL_NSE_BYTES: %u\n",
394                          stats_context->total_nse_bytes);
395     if (buf_len > 0)
396     {
397       GNUNET_DISK_file_write (data_file, buf, buf_len);
398     }
399     GNUNET_free_non_null (buf);
400   }
401
402   GNUNET_assert (GNUNET_SCHEDULER_NO_TASK == shutdown_handle);
403   shutdown_handle = GNUNET_SCHEDULER_add_now (&shutdown_task, NULL);
404   GNUNET_free (stats_context);
405 }
406
407
408 /**
409  * Callback function to process statistic values.
410  *
411  * @param cls struct StatsContext
412  * @param peer the peer the statistics belong to
413  * @param subsystem name of subsystem that created the statistic
414  * @param name the name of the datum
415  * @param value the current value
416  * @param is_persistent GNUNET_YES if the value is persistent, GNUNET_NO if not
417  * @return GNUNET_OK to continue, GNUNET_SYSERR to abort iteration
418  */
419 static int
420 statistics_iterator (void *cls, const struct GNUNET_PeerIdentity *peer,
421                      const char *subsystem, const char *name, uint64_t value,
422                      int is_persistent)
423 {
424   struct StatsContext *stats_context = cls;
425
426   if ((0 == strstr (subsystem, "nse")) &&
427       (0 == strstr (name, "# flood messages received")))
428     stats_context->total_nse_bytes += value;
429   return GNUNET_OK;
430 }
431
432
433 static void
434 disconnect_nse_peers (void *cls, const struct GNUNET_SCHEDULER_TaskContext *tc)
435 {
436   struct NSEPeer *pos;
437   char *buf;
438   struct StatsContext *stats_context;
439
440   GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "disconnecting nse service of peers\n");
441   disconnect_task = GNUNET_SCHEDULER_NO_TASK;
442   pos = peer_head;
443   while (NULL != (pos = peer_head))
444   {
445     if (pos->nse_handle != NULL)
446     {
447       GNUNET_NSE_disconnect (pos->nse_handle);
448       pos->nse_handle = NULL;
449     }
450     GNUNET_CONTAINER_DLL_remove (peer_head, peer_tail, pos);
451     if (NULL != pos->stats)
452       GNUNET_STATISTICS_destroy(pos->stats, GNUNET_NO);
453     if (GNUNET_SCHEDULER_NO_TASK != pos->stats_task)
454       GNUNET_SCHEDULER_cancel (pos->stats_task);
455     GNUNET_free (pos);
456   }
457
458   GNUNET_asprintf (&buf, "round%llu", current_round);
459   if (GNUNET_OK ==
460       GNUNET_CONFIGURATION_get_value_number (testing_cfg, "nse-profiler", buf,
461                                              &peers_next_round))
462   {
463     current_round++;
464     GNUNET_assert (churn_task == GNUNET_SCHEDULER_NO_TASK);
465     churn_task = GNUNET_SCHEDULER_add_now (&churn_peers, NULL);
466   }
467   else                          /* No more rounds, let's shut it down! */
468   {
469     stats_context = GNUNET_malloc (sizeof (struct StatsContext));
470     GNUNET_SCHEDULER_cancel (shutdown_handle);
471     shutdown_handle = GNUNET_SCHEDULER_NO_TASK;
472     GNUNET_TESTING_get_statistics (pg, &stats_finished_callback,
473                                    &statistics_iterator, stats_context);
474   }
475   GNUNET_free (buf);
476 }
477
478
479 /**
480  * FIXME.
481  *
482  * @param cls unused
483  * @param emsg NULL on success
484  */
485 static void
486 topology_output_callback (void *cls, const char *emsg)
487 {
488   disconnect_task =
489       GNUNET_SCHEDULER_add_delayed (wait_time, &disconnect_nse_peers, NULL);
490   GNUNET_SCHEDULER_add_now (&connect_nse_service, NULL);
491 }
492
493
494 /**
495  * FIXME.
496  *
497  * @param cls closure
498  * @param emsg NULL on success
499  */
500 static void
501 churn_callback (void *cls, const char *emsg)
502 {
503   char *temp_output_file;
504
505   if (emsg == NULL)             /* Everything is okay! */
506   {
507     peers_running = peers_next_round;
508     GNUNET_log (GNUNET_ERROR_TYPE_WARNING,
509                 "Round %llu, churn finished successfully.\n", current_round);
510     GNUNET_assert (disconnect_task == GNUNET_SCHEDULER_NO_TASK);
511     GNUNET_asprintf (&temp_output_file, "%s_%llu.dot", topology_file,
512                      current_round);
513     GNUNET_TESTING_peergroup_topology_to_file (pg, temp_output_file,
514                                                &topology_output_callback, NULL);
515     GNUNET_log (GNUNET_ERROR_TYPE_WARNING, "Writing topology to file %s\n",
516                 temp_output_file);
517     GNUNET_free (temp_output_file);
518   }
519   else
520   {
521     GNUNET_log (GNUNET_ERROR_TYPE_WARNING, "Round %llu, churn FAILED!!\n",
522                 current_round);
523     GNUNET_SCHEDULER_cancel (shutdown_handle);
524     shutdown_handle = GNUNET_SCHEDULER_add_now (&shutdown_task, NULL);
525   }
526 }
527
528
529 static void
530 churn_peers (void *cls, const struct GNUNET_SCHEDULER_TaskContext *tc)
531 {
532   /* peers_running = GNUNET_TESTING_daemons_running(pg); */
533   churn_task = GNUNET_SCHEDULER_NO_TASK;
534   if (peers_next_round == peers_running)
535   {
536     /* Nothing to do... */
537     GNUNET_SCHEDULER_add_now (&connect_nse_service, NULL);
538     GNUNET_assert (disconnect_task == GNUNET_SCHEDULER_NO_TASK);
539     disconnect_task =
540         GNUNET_SCHEDULER_add_delayed (wait_time, &disconnect_nse_peers, NULL);
541     GNUNET_log (GNUNET_ERROR_TYPE_WARNING, "Round %lu, doing nothing!\n",
542                 current_round);
543   }
544   else
545   {
546     if (peers_next_round > num_peers)
547     {
548       GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
549                   "Asked to turn on more peers than we have!!\n");
550       GNUNET_SCHEDULER_cancel (shutdown_handle);
551       GNUNET_SCHEDULER_add_now (&shutdown_task, NULL);
552     }
553     GNUNET_log (GNUNET_ERROR_TYPE_WARNING,
554                 "Round %llu, turning off %llu peers, turning on %llu peers!\n",
555                 current_round,
556                 (peers_running >
557                  peers_next_round) ? peers_running - peers_next_round : 0,
558                 (peers_next_round >
559                  peers_running) ? peers_next_round - peers_running : 0);
560     GNUNET_TESTING_daemons_churn (pg, "nse",
561                                   (peers_running >
562                                    peers_next_round) ? peers_running -
563                                   peers_next_round : 0,
564                                   (peers_next_round >
565                                    peers_running) ? peers_next_round -
566                                   peers_running : 0, wait_time, &churn_callback,
567                                   NULL);
568   }
569 }
570
571
572 static void
573 nse_started_cb (void *cls, const char *emsg)
574 {
575   GNUNET_SCHEDULER_add_now (&connect_nse_service, NULL);
576   disconnect_task =
577       GNUNET_SCHEDULER_add_delayed (wait_time, &disconnect_nse_peers, NULL);
578 }
579
580
581 static void
582 my_cb (void *cls, const char *emsg)
583 {
584   char *buf;
585   int buf_len;
586
587   if (emsg != NULL)
588   {
589     GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
590                 "Peergroup callback called with error, aborting test!\n");
591     GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "Error from testing: `%s'\n");
592     ok = 1;
593     GNUNET_TESTING_daemons_stop (pg, TIMEOUT, &shutdown_callback, NULL);
594     return;
595   }
596 #if VERBOSE
597   GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
598               "Peer Group started successfully, connecting to NSE service for each peer!\n");
599 #endif
600   GNUNET_log (GNUNET_ERROR_TYPE_WARNING, "Have %u connections\n",
601               total_connections);
602   if (data_file != NULL)
603   {
604     buf = NULL;
605     buf_len = GNUNET_asprintf (&buf, "CONNECTIONS_0: %u\n", total_connections);
606     if (buf_len > 0)
607       GNUNET_DISK_file_write (data_file, buf, buf_len);
608     GNUNET_free (buf);
609   }
610   peers_running = GNUNET_TESTING_daemons_running (pg);
611   GNUNET_TESTING_daemons_start_service (pg, "nse", wait_time, &nse_started_cb,
612                                         NULL);
613
614 }
615
616
617 /**
618  * Function that will be called whenever two daemons are connected by
619  * the testing library.
620  *
621  * @param cls closure
622  * @param first peer id for first daemon
623  * @param second peer id for the second daemon
624  * @param distance distance between the connected peers
625  * @param first_cfg config for the first daemon
626  * @param second_cfg config for the second daemon
627  * @param first_daemon handle for the first daemon
628  * @param second_daemon handle for the second daemon
629  * @param emsg error message (NULL on success)
630  */
631 static void
632 connect_cb (void *cls, const struct GNUNET_PeerIdentity *first,
633             const struct GNUNET_PeerIdentity *second, uint32_t distance,
634             const struct GNUNET_CONFIGURATION_Handle *first_cfg,
635             const struct GNUNET_CONFIGURATION_Handle *second_cfg,
636             struct GNUNET_TESTING_Daemon *first_daemon,
637             struct GNUNET_TESTING_Daemon *second_daemon, const char *emsg)
638 {
639   if (emsg == NULL)
640     total_connections++;
641 }
642
643
644 static void
645 run (void *cls, char *const *args, const char *cfgfile,
646      const struct GNUNET_CONFIGURATION_Handle *cfg)
647 {
648   char *temp_str;
649   struct GNUNET_TESTING_Host *hosts;
650   char *data_filename;
651
652   ok = 1;
653   //testing_cfg = GNUNET_CONFIGURATION_create ();
654   testing_cfg = GNUNET_CONFIGURATION_dup (cfg);
655 #if VERBOSE
656   GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "Starting daemons.\n");
657   GNUNET_CONFIGURATION_set_value_string (testing_cfg, "testing",
658                                          "use_progressbars", "YES");
659 #endif
660   if (GNUNET_OK !=
661       GNUNET_CONFIGURATION_get_value_number (testing_cfg, "testing",
662                                              "num_peers", &num_peers))
663   {
664     GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
665                 "Option TESTING:NUM_PEERS is required!\n");
666     return;
667   }
668
669   if (GNUNET_OK !=
670       GNUNET_CONFIGURATION_get_value_time (testing_cfg, "nse-profiler",
671                                            "WAIT_TIME", &wait_time))
672   {
673     GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
674                 "Option nse-profiler:wait_time is required!\n");
675     return;
676   }
677
678   if (GNUNET_OK !=
679       GNUNET_CONFIGURATION_get_value_time (testing_cfg, "nse",
680                                            "INTERVAL", &interval))
681   {
682     GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
683                 "Option nse:interval is required!\n");
684     return;
685   }
686
687   if (GNUNET_OK !=
688       GNUNET_CONFIGURATION_get_value_number (testing_cfg, "nse-profiler",
689                                              "connection_limit",
690                                              &connection_limit))
691   {
692     connection_limit = 0;
693   }
694
695   if (GNUNET_OK !=
696       GNUNET_CONFIGURATION_get_value_string (testing_cfg, "nse-profiler",
697                                              "topology_output_file",
698                                              &topology_file))
699   {
700     GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
701                 "Option nse-profiler:topology_output_file is required!\n");
702     return;
703   }
704
705   if (GNUNET_OK ==
706       GNUNET_CONFIGURATION_get_value_string (testing_cfg, "nse-profiler",
707                                              "data_output_file",
708                                              &data_filename))
709   {
710     data_file =
711         GNUNET_DISK_file_open (data_filename,
712                                GNUNET_DISK_OPEN_READWRITE |
713                                GNUNET_DISK_OPEN_CREATE,
714                                GNUNET_DISK_PERM_USER_READ |
715                                GNUNET_DISK_PERM_USER_WRITE);
716     if (data_file == NULL)
717       GNUNET_log (GNUNET_ERROR_TYPE_WARNING, "Failed to open %s for output!\n",
718                   data_filename);
719     GNUNET_free (data_filename);
720   }
721
722   if (GNUNET_YES ==
723       GNUNET_CONFIGURATION_get_value_string (cfg, "nse-profiler", "output_file",
724                                              &temp_str))
725   {
726     output_file =
727         GNUNET_DISK_file_open (temp_str,
728                                GNUNET_DISK_OPEN_READWRITE |
729                                GNUNET_DISK_OPEN_CREATE,
730                                GNUNET_DISK_PERM_USER_READ |
731                                GNUNET_DISK_PERM_USER_WRITE);
732     if (output_file == NULL)
733       GNUNET_log (GNUNET_ERROR_TYPE_WARNING, "Failed to open %s for output!\n",
734                   temp_str);
735   }
736   GNUNET_free_non_null (temp_str);
737
738   hosts = GNUNET_TESTING_hosts_load (testing_cfg);
739
740   pg = GNUNET_TESTING_peergroup_start (testing_cfg, num_peers, TIMEOUT,
741                                        &connect_cb, &my_cb, NULL, hosts);
742   GNUNET_assert (pg != NULL);
743   shutdown_handle =
744       GNUNET_SCHEDULER_add_delayed (GNUNET_TIME_relative_get_forever (),
745                                     &shutdown_task, NULL);
746 }
747
748
749
750 /**
751  * nse-profiler command line options
752  */
753 static struct GNUNET_GETOPT_CommandLineOption options[] = {
754   {'V', "verbose", NULL,
755    gettext_noop ("be verbose (print progress information)"),
756    0, &GNUNET_GETOPT_set_one, &verbose},
757   GNUNET_GETOPT_OPTION_END
758 };
759
760
761 int
762 main (int argc, char *argv[])
763 {
764   GNUNET_log_setup ("nse-profiler",
765 #if VERBOSE
766                     "DEBUG",
767 #else
768                     "WARNING",
769 #endif
770                     NULL);
771   GNUNET_PROGRAM_run (argc, argv, "nse-profiler",
772                       gettext_noop
773                       ("Measure quality and performance of the NSE service."),
774                       options, &run, NULL);
775 #if REMOVE_DIR
776   GNUNET_DISK_directory_remove ("/tmp/nse-profiler");
777 #endif
778   return ok;
779 }
780
781 /* end of nse-profiler.c */