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