- Fixed coverity #10084
[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, "%s",  "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   while (NULL != (pos = peer_head))
558   {
559     if (pos->nse_handle != NULL)
560     {
561       GNUNET_NSE_disconnect (pos->nse_handle);
562       pos->nse_handle = NULL;
563     }
564     GNUNET_CONTAINER_DLL_remove (peer_head, peer_tail, pos);
565     if (NULL != pos->stats)
566       GNUNET_STATISTICS_destroy(pos->stats, GNUNET_NO);
567     if (GNUNET_SCHEDULER_NO_TASK != pos->stats_task)
568       GNUNET_SCHEDULER_cancel (pos->stats_task);
569     GNUNET_free (pos);
570   }
571
572   GNUNET_asprintf (&buf, "round%llu", current_round);
573   if (GNUNET_OK ==
574       GNUNET_CONFIGURATION_get_value_number (testing_cfg, "nse-profiler", buf,
575                                              &peers_next_round))
576   {
577     current_round++;
578     if (current_round == 1)
579     {
580       stats_context = GNUNET_malloc (sizeof (struct StatsContext));
581       stats_context->shutdown = GNUNET_NO;
582       GNUNET_TESTING_get_statistics (pg, &stats_finished_callback,
583                                     &statistics_iterator, stats_context);
584     }
585     else
586     {
587       GNUNET_assert (churn_task == GNUNET_SCHEDULER_NO_TASK);
588       churn_task = GNUNET_SCHEDULER_add_now (&churn_peers, NULL);
589     }
590   }
591   else                          /* No more rounds, let's shut it down! */
592   {
593     stats_context = GNUNET_malloc (sizeof (struct StatsContext));
594     stats_context->shutdown = GNUNET_YES;
595     GNUNET_SCHEDULER_cancel (shutdown_handle);
596     shutdown_handle = GNUNET_SCHEDULER_NO_TASK;
597     GNUNET_TESTING_get_statistics (pg, &stats_finished_callback,
598                                    &statistics_iterator, stats_context);
599   }
600   GNUNET_free (buf);
601 }
602
603
604 /**
605  * FIXME.
606  *
607  * @param cls unused
608  * @param emsg NULL on success
609  */
610 static void
611 topology_output_callback (void *cls, const char *emsg)
612 {
613   disconnect_task =
614       GNUNET_SCHEDULER_add_delayed (wait_time, &disconnect_nse_peers, NULL);
615   GNUNET_SCHEDULER_add_now (&connect_nse_service, NULL);
616 }
617
618
619 /**
620  * FIXME.
621  *
622  * @param cls closure
623  * @param emsg NULL on success
624  */
625 static void
626 churn_callback (void *cls, const char *emsg)
627 {
628   char *temp_output_file;
629
630   if (emsg == NULL)             /* Everything is okay! */
631   {
632     peers_running = peers_next_round;
633     GNUNET_log (GNUNET_ERROR_TYPE_WARNING,
634                 "Round %llu, churn finished successfully.\n", current_round);
635     GNUNET_assert (disconnect_task == GNUNET_SCHEDULER_NO_TASK);
636     GNUNET_asprintf (&temp_output_file, "%s_%llu.dot", topology_file,
637                      current_round);
638     GNUNET_TESTING_peergroup_topology_to_file (pg, temp_output_file,
639                                                &topology_output_callback, NULL);
640     GNUNET_log (GNUNET_ERROR_TYPE_WARNING, "Writing topology to file %s\n",
641                 temp_output_file);
642     GNUNET_free (temp_output_file);
643   }
644   else
645   {
646     GNUNET_log (GNUNET_ERROR_TYPE_WARNING, "Round %llu, churn FAILED!!\n",
647                 current_round);
648     GNUNET_SCHEDULER_cancel (shutdown_handle);
649     shutdown_handle = GNUNET_SCHEDULER_add_now (&shutdown_task, NULL);
650   }
651 }
652
653
654 static void
655 churn_peers (void *cls, const struct GNUNET_SCHEDULER_TaskContext *tc)
656 {
657   /* peers_running = GNUNET_TESTING_daemons_running(pg); */
658   churn_task = GNUNET_SCHEDULER_NO_TASK;
659   if (peers_next_round == peers_running)
660   {
661     /* Nothing to do... */
662     GNUNET_SCHEDULER_add_now (&connect_nse_service, NULL);
663     GNUNET_assert (disconnect_task == GNUNET_SCHEDULER_NO_TASK);
664     disconnect_task =
665         GNUNET_SCHEDULER_add_delayed (wait_time, &disconnect_nse_peers, NULL);
666     GNUNET_log (GNUNET_ERROR_TYPE_WARNING, "Round %lu, doing nothing!\n",
667                 current_round);
668   }
669   else
670   {
671     if (peers_next_round > num_peers)
672     {
673       GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
674                   "Asked to turn on more peers than we have!!\n");
675       GNUNET_SCHEDULER_cancel (shutdown_handle);
676       GNUNET_SCHEDULER_add_now (&shutdown_task, NULL);
677     }
678     GNUNET_log (GNUNET_ERROR_TYPE_WARNING,
679                 "Round %llu, turning off %llu peers, turning on %llu peers!\n",
680                 current_round,
681                 (peers_running >
682                  peers_next_round) ? peers_running - peers_next_round : 0,
683                 (peers_next_round >
684                  peers_running) ? peers_next_round - peers_running : 0);
685     GNUNET_TESTING_daemons_churn (pg, "nse",
686                                   (peers_running >
687                                    peers_next_round) ? peers_running -
688                                   peers_next_round : 0,
689                                   (peers_next_round >
690                                    peers_running) ? peers_next_round -
691                                   peers_running : 0, wait_time, &churn_callback,
692                                   NULL);
693   }
694 }
695
696
697 static void
698 nse_started_cb (void *cls, const char *emsg)
699 {
700   GNUNET_SCHEDULER_add_now (&connect_nse_service, NULL);
701   disconnect_task =
702       GNUNET_SCHEDULER_add_delayed (wait_time, &disconnect_nse_peers, NULL);
703 }
704
705
706 static void
707 my_cb (void *cls, const char *emsg)
708 {
709   char *buf;
710   int buf_len;
711
712   if (emsg != NULL)
713   {
714     GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
715                 "Peergroup callback called with error, aborting test!\n");
716     GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "Error from testing: `%s'\n");
717     ok = 1;
718     GNUNET_TESTING_daemons_stop (pg, TIMEOUT, &shutdown_callback, NULL);
719     return;
720   }
721 #if VERBOSE
722   GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
723               "Peer Group started successfully, connecting to NSE service for each peer!\n");
724 #endif
725   GNUNET_log (GNUNET_ERROR_TYPE_WARNING, "Have %u connections\n",
726               total_connections);
727   if (data_file != NULL)
728   {
729     buf = NULL;
730     buf_len = GNUNET_asprintf (&buf, "CONNECTIONS_0: %u\n", total_connections);
731     if (buf_len > 0)
732       GNUNET_DISK_file_write (data_file, buf, buf_len);
733     GNUNET_free (buf);
734   }
735   peers_running = GNUNET_TESTING_daemons_running (pg);
736   GNUNET_TESTING_daemons_start_service (pg, "nse", wait_time, &nse_started_cb,
737                                         NULL);
738
739 }
740
741
742 /**
743  * Function that will be called whenever two daemons are connected by
744  * the testing library.
745  *
746  * @param cls closure
747  * @param first peer id for first daemon
748  * @param second peer id for the second daemon
749  * @param distance distance between the connected peers
750  * @param first_cfg config for the first daemon
751  * @param second_cfg config for the second daemon
752  * @param first_daemon handle for the first daemon
753  * @param second_daemon handle for the second daemon
754  * @param emsg error message (NULL on success)
755  */
756 static void
757 connect_cb (void *cls, const struct GNUNET_PeerIdentity *first,
758             const struct GNUNET_PeerIdentity *second, uint32_t distance,
759             const struct GNUNET_CONFIGURATION_Handle *first_cfg,
760             const struct GNUNET_CONFIGURATION_Handle *second_cfg,
761             struct GNUNET_TESTING_Daemon *first_daemon,
762             struct GNUNET_TESTING_Daemon *second_daemon, const char *emsg)
763 {
764   if (emsg == NULL)
765     total_connections++;
766 }
767
768
769 static void
770 run (void *cls, char *const *args, const char *cfgfile,
771      const struct GNUNET_CONFIGURATION_Handle *cfg)
772 {
773   char *temp_str;
774   struct GNUNET_TESTING_Host *hosts;
775   char *data_filename;
776
777   ok = 1;
778   //testing_cfg = GNUNET_CONFIGURATION_create ();
779   testing_cfg = GNUNET_CONFIGURATION_dup (cfg);
780 #if VERBOSE
781   GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "Starting daemons.\n");
782   GNUNET_CONFIGURATION_set_value_string (testing_cfg, "testing",
783                                          "use_progressbars", "YES");
784 #endif
785   if (GNUNET_OK !=
786       GNUNET_CONFIGURATION_get_value_number (testing_cfg, "testing",
787                                              "num_peers", &num_peers))
788   {
789     GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
790                 "Option TESTING:NUM_PEERS is required!\n");
791     return;
792   }
793
794   if (GNUNET_OK !=
795       GNUNET_CONFIGURATION_get_value_time (testing_cfg, "nse-profiler",
796                                            "WAIT_TIME", &wait_time))
797   {
798     GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
799                 "Option nse-profiler:wait_time is required!\n");
800     return;
801   }
802
803   if (GNUNET_OK !=
804       GNUNET_CONFIGURATION_get_value_time (testing_cfg, "nse",
805                                            "INTERVAL", &interval))
806   {
807     GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
808                 "Option nse:interval is required!\n");
809     return;
810   }
811
812   if (GNUNET_OK !=
813       GNUNET_CONFIGURATION_get_value_number (testing_cfg, "nse-profiler",
814                                              "connection_limit",
815                                              &connection_limit))
816   {
817     connection_limit = 0;
818   }
819
820   if (GNUNET_OK !=
821       GNUNET_CONFIGURATION_get_value_string (testing_cfg, "nse-profiler",
822                                              "topology_output_file",
823                                              &topology_file))
824   {
825     GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
826                 "Option nse-profiler:topology_output_file is required!\n");
827     return;
828   }
829
830   if (GNUNET_OK ==
831       GNUNET_CONFIGURATION_get_value_string (testing_cfg, "nse-profiler",
832                                              "data_output_file",
833                                              &data_filename))
834   {
835     data_file =
836         GNUNET_DISK_file_open (data_filename,
837                                GNUNET_DISK_OPEN_READWRITE |
838                                GNUNET_DISK_OPEN_TRUNCATE |
839                                GNUNET_DISK_OPEN_CREATE,
840                                GNUNET_DISK_PERM_USER_READ |
841                                GNUNET_DISK_PERM_USER_WRITE);
842     if (data_file == NULL)
843       GNUNET_log (GNUNET_ERROR_TYPE_WARNING, "Failed to open %s for output!\n",
844                   data_filename);
845     GNUNET_free (data_filename);
846   }
847
848   if (GNUNET_YES ==
849       GNUNET_CONFIGURATION_get_value_string (cfg, "nse-profiler", "output_file",
850                                              &temp_str))
851   {
852     output_file =
853         GNUNET_DISK_file_open (temp_str,
854                                GNUNET_DISK_OPEN_READWRITE |
855                                GNUNET_DISK_OPEN_CREATE,
856                                GNUNET_DISK_PERM_USER_READ |
857                                GNUNET_DISK_PERM_USER_WRITE);
858     if (output_file == NULL)
859       GNUNET_log (GNUNET_ERROR_TYPE_WARNING, "Failed to open %s for output!\n",
860                   temp_str);
861   }
862   GNUNET_free_non_null (temp_str);
863
864   hosts = GNUNET_TESTING_hosts_load (testing_cfg);
865
866   pg = GNUNET_TESTING_peergroup_start (testing_cfg, num_peers, TIMEOUT,
867                                        &connect_cb, &my_cb, NULL, hosts);
868   GNUNET_assert (pg != NULL);
869   shutdown_handle =
870       GNUNET_SCHEDULER_add_delayed (GNUNET_TIME_relative_get_forever (),
871                                     &shutdown_task, NULL);
872 }
873
874
875
876 /**
877  * nse-profiler command line options
878  */
879 static struct GNUNET_GETOPT_CommandLineOption options[] = {
880   {'V', "verbose", NULL,
881    gettext_noop ("be verbose (print progress information)"),
882    0, &GNUNET_GETOPT_set_one, &verbose},
883   GNUNET_GETOPT_OPTION_END
884 };
885
886
887 int
888 main (int argc, char *argv[])
889 {
890   GNUNET_log_setup ("nse-profiler",
891 #if VERBOSE
892                     "DEBUG",
893 #else
894                     "WARNING",
895 #endif
896                     NULL);
897   GNUNET_PROGRAM_run (argc, argv, "nse-profiler",
898                       gettext_noop
899                       ("Measure quality and performance of the NSE service."),
900                       options, &run, NULL);
901 #if REMOVE_DIR
902   GNUNET_DISK_directory_remove ("/tmp/nse-profiler");
903 #endif
904   return ok;
905 }
906
907 /* end of nse-profiler.c */