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