- minor
[oweals/gnunet.git] / src / ats-test / test_transport_ats_multiple_peers.c
1 /*
2      This file is part of GNUnet.
3      (C) 2009 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 testing/test_transport_ats_multiple_peers.c
22  * @brief testcase for ats functionality by starting multiple peers
23  */
24
25 #include "platform.h"
26 #include "gnunet_util_lib.h"
27
28 #include "gnunet_testing_lib.h"
29 #include "gnunet_transport_service.h"
30 #include "gauger.h"
31 #include "gnunet-service-transport_ats.h"
32
33 #define VERBOSE GNUNET_EXTRA_LOGGING
34
35 #define NUM_PEERS 11
36 #define MEASUREMENTS 5
37
38 #define DELAY GNUNET_TIME_relative_multiply (GNUNET_TIME_UNIT_SECONDS, 300)
39 #define TIMEOUT GNUNET_TIME_relative_multiply (GNUNET_TIME_UNIT_SECONDS, 300)
40 #define SEND_TIMEOUT GNUNET_TIME_relative_multiply (GNUNET_TIME_UNIT_SECONDS, 1)
41
42 static int ok;
43
44 static int peers_left;
45
46 static int failed_peers;
47
48 static int measurement_started = GNUNET_NO;
49 static char *config_file;
50
51 static struct GNUNET_TESTING_PeerGroup *pg;
52
53 static GNUNET_SCHEDULER_TaskIdentifier shutdown_task;
54 static GNUNET_SCHEDULER_TaskIdentifier stats_task;
55 static GNUNET_SCHEDULER_TaskIdentifier send_task;
56 struct GNUNET_TESTING_Daemon *master_deamon;
57 struct GNUNET_TESTING_Daemon *ping_deamon;
58
59 struct GNUNET_STATISTICS_Handle *stats;
60
61 struct TEST_result
62 {
63   uint64_t timestamp;
64   uint64_t duration;
65   uint64_t mechs;
66   uint64_t peers;
67   uint64_t solution;
68   uint64_t state;
69 };
70
71 GNUNET_NETWORK_STRUCT_BEGIN
72
73 struct TestMessage
74 {
75   struct GNUNET_MessageHeader header;
76   uint32_t num;
77 };
78 GNUNET_NETWORK_STRUCT_END
79
80
81 static int count;
82 static int c_new;
83 static int c_unmodified;
84 static int c_modified;
85 static int connected;
86 static int peers;
87
88 static int force_q_updates;
89 static int force_rebuild;
90 static int send_msg;
91 static int machine_parsable;
92
93 static struct TEST_result results_new[MEASUREMENTS + 1];
94 static struct TEST_result results_modified[MEASUREMENTS + 1];
95 static struct TEST_result results_unmodified[MEASUREMENTS + 1];
96 static struct TEST_result current;
97
98 static struct GNUNET_STATISTICS_GetHandle *s_solution;
99 static struct GNUNET_STATISTICS_GetHandle *s_time;
100 static struct GNUNET_STATISTICS_GetHandle *s_peers;
101 static struct GNUNET_STATISTICS_GetHandle *s_mechs;
102 static struct GNUNET_STATISTICS_GetHandle *s_duration;
103 static struct GNUNET_STATISTICS_GetHandle *s_invalid;
104 static struct GNUNET_STATISTICS_GetHandle *s_state;
105
106 struct GNUNET_TRANSPORT_TransmitHandle *t;
107 struct GNUNET_TRANSPORT_Handle *th;
108
109 /**
110  * Check whether peers successfully shut down.
111  */
112 static void
113 shutdown_callback (void *cls, const char *emsg)
114 {
115   if (emsg != NULL)
116   {
117 #if VERBOSE
118     GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "Shutdown of peers failed!\n");
119 #endif
120     if (ok == 0)
121       ok = 666;
122   }
123   else
124   {
125 #if VERBOSE
126     GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "All peers successfully shut down!\n");
127     if (stats != NULL)
128       GNUNET_STATISTICS_destroy (stats, GNUNET_NO);
129     stats = NULL;
130 #endif
131   }
132 }
133
134 static void
135 shutdown_peers ()
136 {
137   if (shutdown_task != GNUNET_SCHEDULER_NO_TASK)
138   {
139     GNUNET_SCHEDULER_cancel (shutdown_task);
140     shutdown_task = GNUNET_SCHEDULER_NO_TASK;
141   }
142   if (stats_task != GNUNET_SCHEDULER_NO_TASK)
143   {
144     GNUNET_SCHEDULER_cancel (stats_task);
145     stats_task = GNUNET_SCHEDULER_NO_TASK;
146   }
147   if (send_task != GNUNET_SCHEDULER_NO_TASK)
148   {
149     GNUNET_SCHEDULER_cancel (send_task);
150     send_task = GNUNET_SCHEDULER_NO_TASK;
151   }
152
153   if (t != NULL)
154   {
155     GNUNET_TRANSPORT_notify_transmit_ready_cancel (t);
156     t = NULL;
157   }
158   GNUNET_TRANSPORT_disconnect (th);
159   if (s_time != NULL)
160   {
161     GNUNET_STATISTICS_get_cancel (s_time);
162     s_time = NULL;
163   }
164   if (s_peers != NULL)
165   {
166     GNUNET_STATISTICS_get_cancel (s_peers);
167     s_peers = NULL;
168   }
169   if (s_mechs != NULL)
170   {
171     GNUNET_STATISTICS_get_cancel (s_mechs);
172     s_mechs = NULL;
173   }
174   if (s_solution != NULL)
175   {
176     GNUNET_STATISTICS_get_cancel (s_solution);
177     s_solution = NULL;
178   }
179   if (s_duration != NULL)
180   {
181     GNUNET_STATISTICS_get_cancel (s_duration);
182     s_duration = NULL;
183   }
184   if (s_invalid != NULL)
185   {
186     GNUNET_STATISTICS_get_cancel (s_invalid);
187     s_invalid = NULL;
188   }
189   if (s_state != NULL)
190   {
191     GNUNET_STATISTICS_get_cancel (s_state);
192     s_state = NULL;
193   }
194   GNUNET_TESTING_daemons_stop (pg, TIMEOUT, &shutdown_callback, NULL);
195 }
196
197 static void
198 evaluate_measurements ()
199 {
200   int c;
201
202   //int mechs = 0;
203   double average[3];
204   double stddev[3];
205
206   //char * output;
207   c = 1;
208
209   //GNUNET_asprintf(&output, "p,%i,m,%i,",peers, MEASUREMENTS, results_modified[0].mechs,
210
211   average[0] = 0.0;
212   for (c = 0; c < c_new; c++)
213   {
214     average[0] += (double) results_new[c].duration;
215   }
216   average[0] /= c_new;
217
218   stddev[0] = 0.0;
219   for (c = 0; c < c_new; c++)
220   {
221     stddev[0] +=
222         (results_new[c].duration - average[0]) * (results_new[c].duration -
223                                                   average[0]);
224   }
225   stddev[0] /= c_new;
226   stddev[0] = sqrt (stddev[0]);
227   if (!machine_parsable)
228     FPRINTF (stderr, "new, %i measurements, average: %f stddev: %f\n", c_new,
229              average[0], stddev[0]);
230
231   average[1] = 0.0;
232   for (c = 0; c < c_modified; c++)
233   {
234     average[1] += (double) results_modified[c].duration;
235   }
236   average[1] /= c_modified;
237
238   stddev[1] = 0.0;
239   for (c = 0; c < c_modified; c++)
240   {
241     stddev[1] +=
242         (results_modified[c].duration -
243          average[1]) * (results_modified[c].duration - average[1]);
244   }
245   stddev[1] /= c_modified;
246   stddev[1] = sqrt (stddev[1]);
247   if (!machine_parsable)
248     FPRINTF (stderr, "modified, %i measurements, average: %f stddev: %f\n",
249              c_modified, average[1], stddev[1]);
250
251   average[2] = 0.0;
252   for (c = 0; c < c_unmodified; c++)
253   {
254     average[2] += (double) results_unmodified[c].duration;
255   }
256   average[2] /= c_unmodified;
257   stddev[2] = 0.0;
258   for (c = 0; c < c_unmodified; c++)
259   {
260     stddev[2] +=
261         (results_unmodified[c].duration -
262          average[2]) * (results_unmodified[c].duration - average[2]);
263   }
264   stddev[2] /= c_unmodified;
265   stddev[2] = sqrt (stddev[2]);
266
267   if (!machine_parsable)
268     FPRINTF (stderr, "unmodified, %i measurements, average: %f stddev: %f\n",
269              c_unmodified, average[2], stddev[2]);
270
271   if (machine_parsable)
272     FPRINTF (stderr,
273              "peers,%i,mechs,%llu," "new,%i,%f,%f," "mod,%i,%f,%f,"
274              "unmod,%i,%f,%f\n", peers - 1,
275              (unsigned long long) results_unmodified[0].mechs, c_new,
276              average[0], stddev[0], c_modified, average[1], stddev[1],
277              c_unmodified, average[2], stddev[2]);
278   shutdown_peers ();
279 }
280
281
282 static int
283 stats_cb (void *cls, const char *subsystem, const char *name, uint64_t value,
284           int is_persistent)
285 {
286   static int printed = GNUNET_NO;
287
288 #if VERBOSE_ATS
289   GNUNET_log (GNUNET_ERROR_TYPE_ERROR, "%s = %llu\n", name, value);
290 #endif
291   if (0 == strcmp (name, "ATS invalid solutions"))
292   {
293     if (stats_task != GNUNET_SCHEDULER_NO_TASK)
294     {
295       GNUNET_SCHEDULER_cancel (stats_task);
296       stats_task = GNUNET_SCHEDULER_NO_TASK;
297     }
298     GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
299                 "MLP produced invalid %llu result(s)!\n", value);
300     shutdown_peers ();
301     return GNUNET_SYSERR;
302   }
303
304   if (0 == strcmp (name, "ATS solution"))
305   {
306     s_solution = NULL;
307   }
308
309   if (0 == strcmp (name, "ATS peers"))
310   {
311     s_peers = NULL;
312   }
313
314   if (0 == strcmp (name, "ATS mechanisms"))
315   {
316     s_mechs = NULL;
317   }
318
319   if (0 == strcmp (name, "ATS duration"))
320   {
321     s_duration = NULL;
322   }
323   if (0 == strcmp (name, "ATS timestamp"))
324   {
325     s_time = NULL;
326   }
327   if (0 == strcmp (name, "ATS state"))
328   {
329     s_state = NULL;
330   }
331
332   if ((measurement_started == GNUNET_NO) && (0 == strcmp (name, "ATS peers")) &&
333       (value == peers - 1))
334   {
335     measurement_started = GNUNET_YES;
336     count = 1;
337     GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "All %llu peers connected\n", value);
338 #if !VERBOSE
339     if (!machine_parsable)
340       FPRINTF (stderr, "%i", count);
341 #endif
342   }
343
344   if (measurement_started == GNUNET_YES)
345   {
346     // GNUNET_log (GNUNET_ERROR_TYPE_ERROR, "%s == %llu\n", name ,value);
347     if (0 == strcmp (name, "ATS timestamp"))
348     {
349       if (current.timestamp == 0)
350       {
351         printed = GNUNET_NO;
352         current.timestamp = value;
353       }
354       if (current.timestamp == value)
355       {
356         printed = GNUNET_YES;
357       }
358       if (current.timestamp != value)
359       {
360         if (current.state == ATS_NEW)
361         {
362           if (c_new < MEASUREMENTS)
363           {
364             results_new[c_new] = current;
365             c_new++;
366           }
367           else
368           {
369             force_rebuild = GNUNET_NO;
370             force_q_updates = GNUNET_NO;
371             send_msg = GNUNET_NO;
372           }
373         }
374         if (current.state == ATS_UNMODIFIED)
375         {
376           if (c_unmodified < MEASUREMENTS)
377           {
378             results_unmodified[c_unmodified] = current;
379             c_unmodified++;
380           }
381
382         }
383         if (current.state == ATS_QUALITY_UPDATED)
384         {
385           if (c_modified < MEASUREMENTS)
386           {
387             results_modified[c_modified] = current;
388             c_modified++;
389           }
390           else
391           {
392             force_q_updates = GNUNET_NO;
393             force_rebuild = GNUNET_YES;
394           }
395         }
396         count++;
397 #if VERBOSE
398         FPRINTF (stderr, "(new: %i / modified: %i / unmodified: %i) of %i \n",
399                  c_new, c_modified, c_unmodified, MEASUREMENTS);
400 #endif
401         if ((c_modified >= MEASUREMENTS) && (c_new >= MEASUREMENTS) &&
402             (c_unmodified >= MEASUREMENTS))
403         {
404 #if !VERBOSE
405           if (!machine_parsable)
406             FPRINTF (stdout, "\n");
407 #endif
408           if (stats_task != GNUNET_SCHEDULER_NO_TASK)
409           {
410             GNUNET_SCHEDULER_cancel (stats_task);
411             stats_task = GNUNET_SCHEDULER_NO_TASK;
412           }
413           evaluate_measurements ();
414           return GNUNET_SYSERR;
415         }
416
417         printed = GNUNET_NO;
418         current.timestamp = value;
419 #if !VERBOSE
420         if (!machine_parsable)
421           FPRINTF (stderr, "..%i", count);
422 #endif
423         return GNUNET_OK;
424       }
425     }
426
427     if (0 == strcmp (name, "ATS solution"))
428     {
429       current.solution = value;
430       if (printed == GNUNET_NO)
431         GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "[%i] %s: %llu \n", count, name,
432                     value);
433     }
434
435     if (0 == strcmp (name, "ATS peers"))
436     {
437       current.peers = value;
438       if (printed == GNUNET_NO)
439         GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "[%i] %s: %llu \n", count, name,
440                     value);
441     }
442
443     if (0 == strcmp (name, "ATS mechanisms"))
444     {
445       current.mechs = value;
446       if (printed == GNUNET_NO)
447         GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "[%i] %s: %llu \n", count, name,
448                     value);
449     }
450
451     if (0 == strcmp (name, "ATS duration"))
452     {
453       current.duration = value;
454       if (printed == GNUNET_NO)
455         GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "[%i] %s: %llu \n", count, name,
456                     value);
457     }
458     if (0 == strcmp (name, "ATS state"))
459     {
460       current.state = value;
461       const char *cont;
462
463       switch (value)
464       {
465       case ATS_NEW:
466         cont = "NEW";
467         break;
468       case ATS_COST_UPDATED:
469         cont = "C_UPDATED";
470         break;
471       case ATS_QUALITY_UPDATED:
472         cont = "Q_UPDATED";
473         break;
474       case ATS_QUALITY_COST_UPDATED:
475         cont = "QC_UPDATED";
476         break;
477       case ATS_UNMODIFIED:
478         cont = "UNMODIFIED";
479         break;
480       default:
481         GNUNET_break (0);
482         cont = "<undefined>";
483         break;
484       }
485       if (printed == GNUNET_NO)
486         GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "[%i] ATS state: %s\n", count,
487                     cont);
488     }
489   }
490   return GNUNET_OK;
491 }
492
493
494 static void
495 stats_get_task (void *cls, const struct GNUNET_SCHEDULER_TaskContext *tc)
496 {
497   stats_task = GNUNET_SCHEDULER_NO_TASK;
498   if ((tc->reason & GNUNET_SCHEDULER_REASON_SHUTDOWN) != 0)
499     return;
500
501   s_time =
502       GNUNET_STATISTICS_get (stats, "transport", "ATS timestamp", TIMEOUT, NULL,
503                              &stats_cb, NULL);
504   s_solution =
505       GNUNET_STATISTICS_get (stats, "transport", "ATS solution", TIMEOUT, NULL,
506                              &stats_cb, NULL);
507   s_duration =
508       GNUNET_STATISTICS_get (stats, "transport", "ATS duration", TIMEOUT, NULL,
509                              &stats_cb, NULL);
510   s_peers =
511       GNUNET_STATISTICS_get (stats, "transport", "ATS peers", TIMEOUT, NULL,
512                              &stats_cb, NULL);
513   s_mechs =
514       GNUNET_STATISTICS_get (stats, "transport", "ATS mechanisms", TIMEOUT,
515                              NULL, &stats_cb, NULL);
516   s_invalid =
517       GNUNET_STATISTICS_get (stats, "transport", "ATS invalid solutions",
518                              TIMEOUT, NULL, &stats_cb, NULL);
519   s_state =
520       GNUNET_STATISTICS_get (stats, "transport", "ATS state", TIMEOUT, NULL,
521                              &stats_cb, NULL);
522
523   stats_task =
524       GNUNET_SCHEDULER_add_delayed (GNUNET_TIME_relative_multiply
525                                     (GNUNET_TIME_UNIT_MILLISECONDS, 100),
526                                     &stats_get_task, NULL);
527 }
528
529
530 static void
531 delay (void *cls, const struct GNUNET_SCHEDULER_TaskContext *tc)
532 {
533   shutdown_task = GNUNET_SCHEDULER_NO_TASK;
534   if ((tc->reason & GNUNET_SCHEDULER_REASON_SHUTDOWN) != 0)
535     return;
536 #if VERBOSE
537   GNUNET_log (GNUNET_ERROR_TYPE_ERROR, "Delay over\n");
538 #endif
539   shutdown_peers ();
540 }
541
542 static void
543 connect_peers ()
544 {
545   shutdown_task = GNUNET_SCHEDULER_add_delayed (DELAY, &delay, NULL);
546 }
547
548
549 /* To make compiler happy */
550 void
551 dummy (void)
552 {
553   struct ATS_quality_metric *q = qm;
554
555   q = NULL;
556   q++;
557   struct ATS_ressource *r = ressources;
558
559   r = NULL;
560   r++;
561 }
562
563 static size_t
564 send_dummy_data_task (void *cls, size_t size, void *buf)
565 {
566   int s = sizeof (struct TestMessage);
567   struct TestMessage hdr;
568
569   hdr.header.size = htons (s);
570   hdr.header.type = htons (GNUNET_MESSAGE_TYPE_TRANSPORT_ATS);
571   if (force_rebuild)
572     hdr.num = htonl (1);
573   else if (force_q_updates)
574     hdr.num = htonl (2);
575   else
576     hdr.num = htonl (0);
577   memcpy (buf, &hdr, s);
578   // GNUNET_log (GNUNET_ERROR_TYPE_ERROR, "Sent bytes: %i of %i\n", s, s);
579   t = NULL;
580   return s;
581 }
582
583
584 static void
585 send_task_f (void *cls, const struct GNUNET_SCHEDULER_TaskContext *tc)
586 {
587   send_task = GNUNET_SCHEDULER_NO_TASK;
588   if ((tc->reason & GNUNET_SCHEDULER_REASON_SHUTDOWN) != 0)
589     return;
590
591   if (t != NULL)
592   {
593     GNUNET_TRANSPORT_notify_transmit_ready_cancel (t);
594     t = NULL;
595   }
596
597   if (send_msg == GNUNET_YES)
598     t = GNUNET_TRANSPORT_notify_transmit_ready (th, &master_deamon->id,
599                                                 sizeof (struct TestMessage), 0,
600                                                 SEND_TIMEOUT,
601                                                 &send_dummy_data_task, NULL);
602   send_task =
603       GNUNET_SCHEDULER_add_delayed (GNUNET_TIME_relative_multiply
604                                     (GNUNET_TIME_UNIT_MILLISECONDS, 1000),
605                                     &send_task_f, NULL);
606
607 }
608
609 static void
610 notify_connect (void *cls, const struct GNUNET_PeerIdentity *peer,
611                 const struct GNUNET_ATS_Information *ats, uint32_t ats_count)
612 {
613   send_task = GNUNET_SCHEDULER_add_now (&send_task_f, NULL);
614 }
615
616 static void
617 notify_disconnect (void *cls, const struct GNUNET_PeerIdentity *peer)
618 {
619   if (GNUNET_SCHEDULER_NO_TASK != send_task)
620   {
621     GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
622                 "Disconnect event before transmission request could be scheduled!\n");
623     GNUNET_SCHEDULER_cancel (send_task);
624     send_task = GNUNET_SCHEDULER_NO_TASK;
625   }
626   if (NULL != t)
627   {
628     GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
629                 "Disconnect event before transmission request could be completed!\n");
630     GNUNET_TRANSPORT_notify_transmit_ready_cancel (t);
631     t = NULL;
632   }
633 }
634
635 static void
636 daemon_connect_cb (void *cls, const struct GNUNET_PeerIdentity *first,
637                    const struct GNUNET_PeerIdentity *second, uint32_t distance,
638                    const struct GNUNET_CONFIGURATION_Handle *first_cfg,
639                    const struct GNUNET_CONFIGURATION_Handle *second_cfg,
640                    struct GNUNET_TESTING_Daemon *first_daemon,
641                    struct GNUNET_TESTING_Daemon *second_daemon,
642                    const char *emsg)
643 {
644   char *firstc = GNUNET_strdup (GNUNET_i2s (first));
645   char *secondc = GNUNET_strdup (GNUNET_i2s (second));
646
647   connected++;
648   GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "Connected peers `%s'<->`%s' (%i/%i)\n",
649               firstc, secondc, connected, peers - 1);
650   GNUNET_free (firstc);
651   GNUNET_free (secondc);
652
653   if (((first_daemon == ping_deamon) || (second_daemon == ping_deamon)) &&
654       (master_deamon != NULL) && (ping_deamon != NULL))
655   {
656     th = GNUNET_TRANSPORT_connect (ping_deamon->cfg, &ping_deamon->id, NULL,
657                                    NULL, &notify_connect, &notify_disconnect);
658     force_q_updates = GNUNET_YES;
659     send_msg = GNUNET_YES;
660   }
661 }
662
663
664
665 static void
666 daemon_start_cb (void *cls, const struct GNUNET_PeerIdentity *id,
667                  const struct GNUNET_CONFIGURATION_Handle *cfg,
668                  struct GNUNET_TESTING_Daemon *d, const char *emsg)
669 {
670   if (id == NULL)
671   {
672     GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
673                 "Start callback called with error (too long starting peers), aborting test!\n");
674     GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "Error from testing: `%s'\n");
675     failed_peers++;
676     if (failed_peers == peers_left)
677     {
678       GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
679                   "Too many peers failed, ending test!\n");
680       ok = 1;
681       shutdown_peers ();
682     }
683     return;
684   }
685   peers_left--;
686
687   if (master_deamon == NULL)
688   {
689     GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "Master peer `%s' '%s'\n",
690                 GNUNET_i2s (id), d->cfgfile);
691     master_deamon = d;
692     stats = GNUNET_STATISTICS_create ("transport", master_deamon->cfg);
693     GNUNET_assert (stats != NULL);
694     stats_task = GNUNET_SCHEDULER_add_now (&stats_get_task, NULL);
695   }
696   else
697   {
698     GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "Connecting peer `%s'\n",
699                 GNUNET_i2s (id), GNUNET_i2s (&master_deamon->id));
700     GNUNET_TESTING_daemons_connect (d, master_deamon, TIMEOUT, 0, GNUNET_YES,
701                                     &daemon_connect_cb, NULL);
702   }
703
704   if (peers_left == 0)
705   {
706     if (ping_deamon == NULL)
707     {
708       ping_deamon = d;
709       GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "Ping peer `%s' '%s'\n",
710                   GNUNET_i2s (id), d->cfgfile);
711     }
712
713     GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "All peers started successfully!\n");
714     connect_peers ();
715     ok = 0;
716   }
717   else if (failed_peers == peers_left)
718   {
719     GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
720                 "Too many peers failed, ending test!\n");
721     shutdown_peers ();
722     ok = 1;
723   }
724 }
725
726
727 static void
728 run (void *cls, char *const *args, const char *cfgfile,
729      const struct GNUNET_CONFIGURATION_Handle *cfg)
730 {
731   ok = 1;
732   measurement_started = GNUNET_NO;
733 #if VERBOSE
734   GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "Starting %i peers.\n", peers);
735 #endif
736   peers_left = peers;
737   pg = GNUNET_TESTING_daemons_start (cfg, peers_left,   /* Total number of peers */
738                                      peers_left,        /* Number of outstanding connections */
739                                      peers_left,        /* Number of parallel ssh connections, or peers being started at once */
740                                      TIMEOUT, NULL, NULL, &daemon_start_cb,
741                                      NULL, NULL, NULL, NULL);
742   GNUNET_assert (pg != NULL);
743 }
744
745
746 static int
747 check ()
748 {
749   char *const argv[] = { "test-testing",
750     "-c",
751     config_file,
752 #if VERBOSE
753     "-L", "DEBUG",
754 #endif
755     NULL
756   };
757   struct GNUNET_GETOPT_CommandLineOption options[] = {
758     GNUNET_GETOPT_OPTION_END
759   };
760   GNUNET_PROGRAM_run ((sizeof (argv) / sizeof (char *)) - 1, argv,
761                       "test_transport_ats_multiple_peers", "nohelp", options,
762                       &run, &ok);
763   return ok;
764 }
765
766 int
767 main (int argc, char *argv[])
768 {
769   int ret = 0;
770
771   GNUNET_log_setup ("test-transport-ats-multiple-peers",
772 #if VERBOSE
773                     "DEBUG",
774 #else
775                     "INFO",
776 #endif
777                     NULL);
778
779   GNUNET_DISK_directory_remove ("/tmp/test-gnunet-testing");
780   machine_parsable = GNUNET_NO;
781   peers = NUM_PEERS;
782   config_file = "test_transport_ats_4addr.conf";
783
784   int c = 0;
785
786   if (argc >= 2)
787   {
788     for (c = 0; c < argc; c++)
789     {
790       /* set peers */
791       if ((strcmp (argv[c], "-p") == 0) && c < (argc - 1))
792       {
793         peers = atoi (argv[c + 1]);
794         peers++;
795       }
796       /* set machine parsable */
797       if (strcmp (argv[c], "-m") == 0)
798       {
799         machine_parsable = GNUNET_YES;
800       }
801       /* set config file */
802       if ((strcmp (argv[c], "-c") == 0) && c < (argc - 1))
803       {
804         config_file = argv[c + 1];
805       }
806     }
807   }
808
809   ret = check ();
810   /**
811    * Still need to remove the base testing directory here,
812    * because group starts will create subdirectories under this
813    * main dir.  However, we no longer need to sleep, as the
814    * shutdown sequence won't return until everything is cleaned
815    * up.
816    */
817   GNUNET_DISK_directory_remove ("/tmp/test-gnunet-testing");
818   return ret;
819 }
820
821 /* end of test_transport_ats_multiple_peers.c*/