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