psycstore
[oweals/gnunet.git] / src / ats-tests / ats-testing.c
1 /*
2  This file is part of GNUnet.
3  Copyright (C) 2010-2013, 2016 GNUnet e.V.
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., 51 Franklin Street, Fifth Floor,
18  Boston, MA 02110-1301, USA.
19  */
20 /**
21  * @file ats-tests/ats-testing.c
22  * @brief ats testing library: setup topology
23  * solvers
24  * @author Christian Grothoff
25  * @author Matthias Wachs
26  */
27 #include "ats-testing.h"
28
29
30 /**
31  * Connect peers with testbed
32  */
33 struct TestbedConnectOperation
34 {
35   /**
36    * The benchmarking master initiating this connection
37    */
38   struct BenchmarkPeer *master;
39
40   /**
41    * The benchmarking slave to connect to
42    */
43   struct BenchmarkPeer *slave;
44
45   /**
46    * Testbed operation to connect peers
47    */
48   struct GNUNET_TESTBED_Operation *connect_op;
49 };
50
51 struct GNUNET_CONFIGURATION_Handle *cfg;
52
53 struct GNUNET_ATS_TEST_Topology *top;
54
55
56 /**
57  * Shutdown nicely
58  *
59  * @param cls NULL
60  */
61 static void
62 do_shutdown (void *cls)
63 {
64   int c_m;
65   int c_s;
66   int c_op;
67   struct BenchmarkPeer *p;
68
69   top->state.benchmarking = GNUNET_NO;
70
71   GNUNET_log (GNUNET_ERROR_TYPE_INFO,
72               "Benchmarking done\n");
73
74   GNUNET_ATS_TEST_generate_traffic_stop_all ();
75
76   for (c_m = 0; c_m < top->num_masters; c_m++)
77   {
78     p = &top->mps[c_m];
79     if (NULL != top->mps[c_m].peer_id_op)
80     {
81       GNUNET_TESTBED_operation_done (p->peer_id_op);
82       p->peer_id_op = NULL;
83     }
84
85     if (NULL != p->ats_task)
86       GNUNET_SCHEDULER_cancel (p->ats_task);
87     p->ats_task = NULL;
88
89     for (c_op = 0; c_op < p->num_partners; c_op++)
90     {
91       if (NULL != p->partners[c_op].cth)
92       {
93         GNUNET_CORE_notify_transmit_ready_cancel (p->partners[c_op].cth);
94         p->partners[c_op].cth = NULL;
95       }
96       if ( (NULL != p->core_connect_ops) &&
97            (NULL != p->core_connect_ops[c_op].connect_op) )
98       {
99         GNUNET_log (GNUNET_ERROR_TYPE_INFO,
100                     "Failed to connect peer 0 and %u\n",
101                     c_op);
102         GNUNET_TESTBED_operation_done (p->core_connect_ops[c_op].connect_op);
103         p->core_connect_ops[c_op].connect_op = NULL;
104       }
105     }
106
107     if (NULL != p->ats_perf_op)
108     {
109       GNUNET_TESTBED_operation_done (p->ats_perf_op);
110       p->ats_perf_op = NULL;
111     }
112
113     if (NULL != p->comm_op)
114     {
115       GNUNET_TESTBED_operation_done (p->comm_op);
116       p->comm_op = NULL;
117     }
118     GNUNET_free_non_null (p->core_connect_ops);
119     GNUNET_free(p->partners);
120     p->partners = NULL;
121   }
122
123   for (c_s = 0; c_s < top->num_slaves; c_s++)
124   {
125     p = &top->sps[c_s];
126     if (NULL != p->peer_id_op)
127     {
128       GNUNET_TESTBED_operation_done (p->peer_id_op);
129       p->peer_id_op = NULL;
130     }
131
132     for (c_op = 0; c_op < p->num_partners; c_op++)
133     {
134       if (NULL != p->partners[c_op].cth)
135       {
136         GNUNET_CORE_notify_transmit_ready_cancel (p->partners[c_op].cth);
137         p->partners[c_op].cth = NULL;
138       }
139     }
140     if (NULL != p->ats_perf_op)
141     {
142       GNUNET_TESTBED_operation_done (p->ats_perf_op);
143       p->ats_perf_op = NULL;
144     }
145     if (NULL != p->comm_op)
146     {
147       GNUNET_TESTBED_operation_done (p->comm_op);
148       p->comm_op = NULL;
149     }
150     GNUNET_free(p->partners);
151     p->partners = NULL;
152   }
153   GNUNET_SCHEDULER_shutdown ();
154   GNUNET_free (top);
155   top = NULL;
156 }
157
158
159 static struct BenchmarkPartner *
160 find_partner (struct BenchmarkPeer *me,
161               const struct GNUNET_PeerIdentity *peer)
162 {
163   int c_m;
164
165   for (c_m = 0; c_m < me->num_partners; c_m++)
166   {
167     /* Find a partner with other as destination */
168     if (0 == memcmp (peer,
169                      &me->partners[c_m].dest->id,
170                      sizeof (struct GNUNET_PeerIdentity)))
171     {
172       return &me->partners[c_m];
173     }
174   }
175
176   return NULL;
177 }
178
179
180 static struct BenchmarkPeer *
181 find_peer (const struct GNUNET_PeerIdentity * peer)
182 {
183   int c_p;
184
185   for (c_p = 0; c_p < top->num_masters; c_p++)
186   {
187     if (0 == memcmp (&top->mps[c_p].id,
188                      peer,
189                      sizeof(struct GNUNET_PeerIdentity)))
190       return &top->mps[c_p];
191   }
192
193   for (c_p = 0; c_p < top->num_slaves; c_p++)
194   {
195     if (0 == memcmp (&top->sps[c_p].id,
196                      peer,
197                      sizeof(struct GNUNET_PeerIdentity)))
198       return &top->sps[c_p];
199   }
200   return NULL ;
201 }
202
203
204 /**
205  * Method called whenever a given peer connects.
206  *
207  * @param cls closure
208  * @param peer peer identity this notification is about
209  * @param mq queue to use to send messages to @a peer
210  * @return the `struct BenchmarkPartner` of @a peer
211  */
212 static void *
213 comm_connect_cb (void *cls,
214                  const struct GNUNET_PeerIdentity *peer,
215                  struct GNUNET_MQ_Handle *mq)
216 {
217   struct BenchmarkPeer *me = cls;
218   struct BenchmarkPeer *remote;
219   struct BenchmarkPartner *p;
220   char *id;
221   int c;
222   int completed;
223
224   remote = find_peer (peer);
225   if (NULL == remote)
226   {
227     GNUNET_log (GNUNET_ERROR_TYPE_WARNING,
228                 "Unknown peer connected: `%s'\n",
229                 GNUNET_i2s (peer));
230     GNUNET_break (0);
231     return NULL;
232   }
233
234   id = GNUNET_strdup (GNUNET_i2s (&me->id));
235   GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
236               "%s [%u] `%s' connected to %s [%u] %s\n",
237               (me->master == GNUNET_YES) ? "Master": "Slave",
238               me->no,
239               id,
240               (remote->master == GNUNET_YES) ? "Master": "Slave",
241               remote->no,
242               GNUNET_i2s (peer));
243
244   me->core_connections++;
245   if ((GNUNET_YES == me->master) &&
246       (GNUNET_NO == remote->master) &&
247       (GNUNET_NO == top->state.connected_CORE))
248   {
249     me->core_slave_connections++;
250
251     if (me->core_slave_connections == top->num_slaves)
252     {
253       GNUNET_log (GNUNET_ERROR_TYPE_INFO,
254                   "Master [%u] connected all slaves\n",
255                   me->no);
256     }
257     completed = GNUNET_YES;
258     for (c = 0; c < top->num_masters; c++)
259     {
260       if (top->mps[c].core_slave_connections != top->num_slaves)
261         completed = GNUNET_NO;
262     }
263     if (GNUNET_YES == completed)
264     {
265       GNUNET_log (GNUNET_ERROR_TYPE_INFO,
266                   "All master peers connected all slave peers\n");
267       top->state.connected_CORE = GNUNET_YES;
268       /* Notify about setup done */
269       if (NULL != top->done_cb)
270         top->done_cb (top->done_cb_cls,
271                       top->mps,
272                       top->sps);
273     }
274   }
275   GNUNET_free (id);
276   p = find_partner (me,
277                     peer);
278   if (NULL != p)
279     p->mq = mq;
280   return p;
281 }
282
283
284 /**
285  * @param cls this peer
286  * @param peer id of disconnecting peer
287  * @param internal_cls the `struct BenchmarkPartner` of @a peer
288  */
289 static void
290 comm_disconnect_cb (void *cls,
291                     const struct GNUNET_PeerIdentity *peer,
292                     void *internal_cls)
293 {
294   struct BenchmarkPeer *me = cls;
295   struct BenchmarkPartner *p = internal_cls;
296   char *id;
297
298   if (NULL == p)
299     return;
300
301   id = GNUNET_strdup (GNUNET_i2s (&me->id));
302   GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
303               "%s disconnected from %s\n",
304               id,
305               GNUNET_i2s (peer));
306   GNUNET_assert (me->core_connections > 0);
307   me->core_connections--;
308
309   if ( (GNUNET_YES == top->state.benchmarking) &&
310        ( (GNUNET_YES == me->master) ||
311          (GNUNET_YES == p->dest->master) ) )
312   {
313     GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
314                 "%s disconnected from %s while benchmarking\n",
315                 id,
316                 GNUNET_i2s (peer));
317     if (NULL != p->cth)
318     {
319       GNUNET_CORE_notify_transmit_ready_cancel (p->cth);
320       p->cth = NULL;
321     }
322   }
323   GNUNET_free(id);
324 }
325
326
327 static void
328 handle_pong (void *cls,
329              const struct TestMessage *message)
330 {
331   struct BenchmarkPartner *p = cls;
332
333   GNUNET_ATS_TEST_traffic_handle_pong (p);
334 }
335
336
337 static void
338 handle_ping (void *cls,
339              const struct TestMessage *message)
340 {
341   struct BenchmarkPartner *p = cls;
342
343   GNUNET_ATS_TEST_traffic_handle_ping (p);
344 }
345
346
347 static void *
348 transport_connect_adapter (void *cls,
349                            const struct GNUNET_CONFIGURATION_Handle *cfg)
350 {
351   struct BenchmarkPeer *me = cls;
352   struct GNUNET_MQ_MessageHandler handlers[] = {
353     GNUNET_MQ_hd_fixed_size (ping,
354                              TEST_MESSAGE_TYPE_PING,
355                              struct TestMessage,
356                              me),
357     GNUNET_MQ_hd_fixed_size (pong,
358                              TEST_MESSAGE_TYPE_PONG,
359                              struct TestMessage,
360                              me),
361     GNUNET_MQ_handler_end ()
362   };
363
364   me->th = GNUNET_TRANSPORT_core_connect (cfg,
365                                           &me->id,
366                                           handlers,
367                                           me,
368                                           &comm_connect_cb,
369                                           &comm_disconnect_cb,
370                                           NULL);
371   if (NULL == me->th)
372     GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
373                 "Failed to create transport connection \n");
374   return me->th;
375 }
376
377
378 static void
379 transport_disconnect_adapter (void *cls,
380                               void *op_result)
381 {
382   struct BenchmarkPeer *me = cls;
383
384   GNUNET_TRANSPORT_core_disconnect (me->th);
385   me->th = NULL;
386 }
387
388
389 static void *
390 core_connect_adapter (void *cls,
391                       const struct GNUNET_CONFIGURATION_Handle *cfg)
392 {
393   struct BenchmarkPeer *me = cls;
394   struct GNUNET_MQ_MessageHandler handlers[] = {
395     GNUNET_MQ_hd_fixed_size (ping,
396                              TEST_MESSAGE_TYPE_PING,
397                              struct TestMessage,
398                              me),
399     GNUNET_MQ_hd_fixed_size (pong,
400                              TEST_MESSAGE_TYPE_PONG,
401                              struct TestMessage,
402                              me),
403     GNUNET_MQ_handler_end ()
404   };
405
406   me->ch = GNUNET_CORE_connecT (cfg,
407                                 me,
408                                 NULL,
409                                 &comm_connect_cb,
410                                 &comm_disconnect_cb,
411                                 handlers);
412   if (NULL == me->ch)
413     GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
414                 "Failed to create core connection \n");
415   return me->ch;
416 }
417
418
419 static void
420 core_disconnect_adapter (void *cls,
421                          void *op_result)
422 {
423   struct BenchmarkPeer *me = cls;
424
425   GNUNET_CORE_disconnecT (me->ch);
426   me->ch = NULL;
427 }
428
429
430 static void
431 connect_completion_callback (void *cls,
432                              struct GNUNET_TESTBED_Operation *op,
433                              const char *emsg)
434 {
435   struct TestbedConnectOperation *cop = cls;
436   static int ops = 0;
437   int c;
438   if (NULL == emsg)
439   {
440     GNUNET_log(GNUNET_ERROR_TYPE_INFO,
441                _("Connected master [%u] with slave [%u]\n"),
442                cop->master->no,
443                cop->slave->no);
444   }
445   else
446   {
447     GNUNET_log(GNUNET_ERROR_TYPE_ERROR,
448         _("Failed to connect master peer [%u] with slave [%u]\n"),
449         cop->master->no, cop->slave->no);
450     GNUNET_break(0);
451     GNUNET_SCHEDULER_shutdown ();
452   }
453   GNUNET_TESTBED_operation_done (op);
454   ops++;
455   for (c = 0; c < top->num_slaves; c++)
456   {
457     if (cop == &cop->master->core_connect_ops[c])
458       cop->master->core_connect_ops[c].connect_op = NULL;
459   }
460   if (ops == top->num_masters * top->num_slaves)
461   {
462     top->state.connected_PEERS = GNUNET_YES;
463   }
464 }
465
466
467 static void
468 do_connect_peers (void *cls)
469 {
470   int c_m;
471   int c_s;
472   struct BenchmarkPeer *p;
473
474   if ((top->state.connected_ATS_service == GNUNET_NO) ||
475       (top->state.connected_COMM_service == GNUNET_NO))
476     return;
477
478   GNUNET_log (GNUNET_ERROR_TYPE_INFO,
479               "Connecting peers on CORE level\n");
480   for (c_m = 0; c_m < top->num_masters; c_m++)
481   {
482     p = &top->mps[c_m];
483     p->core_connect_ops = GNUNET_malloc (top->num_slaves *
484         sizeof (struct TestbedConnectOperation));
485
486     for (c_s = 0; c_s < top->num_slaves; c_s++)
487     {
488       GNUNET_log (GNUNET_ERROR_TYPE_INFO,
489                  "Connecting master [%u] with slave [%u]\n",
490                   p->no,
491                   top->sps[c_s].no);
492       p->core_connect_ops[c_s].master = p;
493       p->core_connect_ops[c_s].slave = &top->sps[c_s];
494       p->core_connect_ops[c_s].connect_op
495         = GNUNET_TESTBED_overlay_connect (NULL,
496                                           &connect_completion_callback,
497                                           &p->core_connect_ops[c_s],
498                                           top->sps[c_s].peer,
499                                           p->peer);
500       if (NULL == p->core_connect_ops[c_s].connect_op)
501        {
502         GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
503                     "Could not connect master [%u] and slave [%u]\n",
504                     p->no,
505                     top->sps[c_s].no);
506         GNUNET_break(0);
507         GNUNET_SCHEDULER_shutdown ();
508         return;
509       }
510     }
511   }
512 }
513
514
515 static void
516 comm_connect_completion_cb (void *cls,
517                             struct GNUNET_TESTBED_Operation *op,
518                             void *ca_result,
519                             const char *emsg)
520 {
521   static int comm_done = 0;
522
523   if ((NULL != emsg) || (NULL == ca_result))
524   {
525     GNUNET_log(GNUNET_ERROR_TYPE_INFO,
526                "Initialization failed, shutdown\n");
527     GNUNET_break(0);
528     GNUNET_SCHEDULER_shutdown ();
529     return;
530   }
531   comm_done++;
532
533   if (comm_done == top->num_slaves + top->num_masters)
534   {
535     GNUNET_log (GNUNET_ERROR_TYPE_INFO,
536                 "Connected to all %s services\n",
537                 (GNUNET_YES == top->test_core) ? "CORE" : "TRANSPORT");
538     top->state.connected_COMM_service = GNUNET_YES;
539     GNUNET_SCHEDULER_add_now (&do_connect_peers,
540                               NULL);
541   }
542 }
543
544
545 static void
546 do_comm_connect (void *cls)
547 {
548   int c_s;
549   int c_m;
550   GNUNET_log (GNUNET_ERROR_TYPE_INFO,
551               "Connecting to all %s services\n",
552               (GNUNET_YES == top->test_core) ? "CORE" : "TRANSPORT");
553   for (c_m = 0; c_m < top->num_masters; c_m++)
554   {
555     if (GNUNET_YES == top->test_core)
556       top->mps[c_m].comm_op
557         = GNUNET_TESTBED_service_connect (NULL,
558                                           top->mps[c_m].peer,
559                                           "core",
560                                           &comm_connect_completion_cb,
561                                           NULL,
562                                           &core_connect_adapter,
563                                           &core_disconnect_adapter,
564                                           &top->mps[c_m]);
565     else
566     {
567       top->mps[c_m].comm_op
568         = GNUNET_TESTBED_service_connect (NULL,
569                                           top->mps[c_m].peer,
570                                           "transport",
571                                           &comm_connect_completion_cb,
572                                           NULL,
573                                           &transport_connect_adapter,
574                                           &transport_disconnect_adapter,
575                                           &top->mps[c_m]);
576     }
577   }
578
579   for (c_s = 0; c_s < top->num_slaves; c_s++)
580   {
581     if (GNUNET_YES == top->test_core)
582       top->sps[c_s].comm_op
583         = GNUNET_TESTBED_service_connect (NULL,
584                                           top->sps[c_s].peer,
585                                           "core",
586                                           &comm_connect_completion_cb,
587                                           NULL,
588                                           &core_connect_adapter,
589                                           &core_disconnect_adapter,
590                                           &top->sps[c_s]);
591     else
592     {
593       top->sps[c_s].comm_op
594         = GNUNET_TESTBED_service_connect (NULL,
595                                           top->sps[c_s].peer,
596                                           "transport",
597                                           &comm_connect_completion_cb,
598                                           NULL,
599                                           &transport_connect_adapter,
600                                           &transport_disconnect_adapter,
601                                           &top->sps[c_s]);
602     }
603   }
604 }
605
606
607 static void
608 ats_performance_info_cb (void *cls,
609                          const struct GNUNET_HELLO_Address *address,
610                          int address_active,
611                          struct GNUNET_BANDWIDTH_Value32NBO bandwidth_out,
612                          struct GNUNET_BANDWIDTH_Value32NBO bandwidth_in,
613                          const struct GNUNET_ATS_Properties *ats_prop)
614 {
615   struct BenchmarkPeer *me = cls;
616   struct BenchmarkPartner *p;
617   int log;
618   char *peer_id;
619
620   if (NULL == address)
621   {
622     GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
623                 "Peer %u: ATS Service disconnected!\n",
624                 me->no);
625     return;
626   }
627
628   p = find_partner (me,
629                     &address->peer);
630   if (NULL == p)
631   {
632     /* This is not one of my partners
633      * Will happen since the peers will connect to each other due to gossiping
634      */
635     return;
636   }
637   peer_id = GNUNET_strdup (GNUNET_i2s (&me->id));
638
639   log = GNUNET_NO;
640   if ((p->bandwidth_in != ntohl (bandwidth_in.value__)) ||
641       (p->bandwidth_out != ntohl (bandwidth_out.value__)))
642       log = GNUNET_YES;
643   p->bandwidth_in = ntohl (bandwidth_in.value__);
644   p->bandwidth_out = ntohl (bandwidth_out.value__);
645
646   GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
647               "%s [%u] received ATS information: %s\n",
648               (GNUNET_YES == p->me->master) ? "Master" : "Slave",
649               p->me->no,
650               GNUNET_i2s (&p->dest->id));
651
652   p->props.utilization_out = ats_prop->utilization_out;
653   p->props.utilization_in = ats_prop->utilization_in;
654   p->props.scope = ats_prop->scope;
655   p->props.delay = ats_prop->delay;
656   p->props.distance = ats_prop->distance;
657
658   if (GNUNET_YES == log)
659     top->ats_perf_cb (cls, address,
660                       address_active,
661                       bandwidth_out,
662                       bandwidth_in,
663                       ats_prop);
664   GNUNET_free(peer_id);
665 }
666
667
668 static void *
669 ats_perf_connect_adapter (void *cls,
670                           const struct GNUNET_CONFIGURATION_Handle *cfg)
671 {
672   struct BenchmarkPeer *me = cls;
673
674   me->ats_perf_handle
675     = GNUNET_ATS_performance_init (cfg,
676                                    &ats_performance_info_cb,
677                                    me);
678   if (NULL == me->ats_perf_handle)
679     GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
680                 "Failed to create ATS performance handle \n");
681   return me->ats_perf_handle;
682 }
683
684
685 static void
686 ats_perf_disconnect_adapter (void *cls,
687                              void *op_result)
688 {
689   struct BenchmarkPeer *me = cls;
690
691   GNUNET_ATS_performance_done (me->ats_perf_handle);
692   me->ats_perf_handle = NULL;
693 }
694
695
696 static void
697 ats_connect_completion_cb (void *cls,
698                            struct GNUNET_TESTBED_Operation *op,
699                            void *ca_result,
700                            const char *emsg)
701 {
702   static int op_done = 0;
703
704   if ((NULL != emsg) || (NULL == ca_result))
705   {
706     GNUNET_log(GNUNET_ERROR_TYPE_INFO,
707                "Initialization failed, shutdown\n");
708     GNUNET_break(0);
709     GNUNET_SCHEDULER_shutdown ();
710     return;
711   }
712   op_done++;
713   if (op_done == (top->num_masters + top->num_slaves))
714   {
715     GNUNET_log (GNUNET_ERROR_TYPE_INFO,
716                 "Connected to all ATS services\n");
717     top->state.connected_ATS_service = GNUNET_YES;
718     GNUNET_SCHEDULER_add_now (&do_comm_connect,
719                               NULL);
720   }
721 }
722
723
724 static void
725 do_connect_ats (void *cls)
726 {
727   int c_m;
728   int c_s;
729
730   GNUNET_log (GNUNET_ERROR_TYPE_INFO,
731               "Connecting to all ATS services\n");
732   for (c_m = 0; c_m < top->num_masters; c_m++)
733   {
734     top->mps[c_m].ats_perf_op
735       = GNUNET_TESTBED_service_connect (NULL,
736                                         top->mps[c_m].peer,
737                                         "ats",
738                                         &ats_connect_completion_cb,
739                                         NULL,
740                                         &ats_perf_connect_adapter,
741                                         &ats_perf_disconnect_adapter,
742                                         &top->mps[c_m]);
743   }
744
745   for (c_s = 0; c_s < top->num_slaves; c_s++)
746   {
747     top->sps[c_s].ats_perf_op
748       = GNUNET_TESTBED_service_connect (NULL,
749                                         top->sps[c_s].peer,
750                                         "ats",
751                                         &ats_connect_completion_cb,
752                                         NULL,
753                                         &ats_perf_connect_adapter,
754                                         &ats_perf_disconnect_adapter,
755                                         &top->sps[c_s]);
756   }
757 }
758
759
760
761 static void
762 peerinformation_cb (void *cb_cls,
763                     struct GNUNET_TESTBED_Operation *op,
764                     const struct GNUNET_TESTBED_PeerInformation *pinfo,
765                     const char *emsg)
766 {
767   struct BenchmarkPeer *p = cb_cls;
768   static int done = 0;
769
770   GNUNET_assert(pinfo->pit == GNUNET_TESTBED_PIT_IDENTITY);
771
772   p->id = *pinfo->result.id;
773   GNUNET_log (GNUNET_ERROR_TYPE_INFO,
774               "%s [%u] has peer id `%s'\n",
775               (p->master == GNUNET_YES) ? "Master" : "Slave",
776               p->no,
777               GNUNET_i2s (&p->id));
778
779   GNUNET_TESTBED_operation_done (op);
780   p->peer_id_op = NULL;
781   done++;
782
783   if (done == top->num_slaves + top->num_masters)
784   {
785     GNUNET_log (GNUNET_ERROR_TYPE_INFO,
786                 "Retrieved all peer ID, connect to ATS\n");
787     GNUNET_SCHEDULER_add_now (&do_connect_ats,
788                               NULL);
789   }
790 }
791
792
793 /**
794  * Signature of a main function for a testcase.
795  *
796  * @param cls closure
797  * @param h testbed handle
798  * @param num_peers number of peers in 'peers'
799  * @param peers_ handle to peers run in the testbed
800  * @param links_succeeded the number of overlay link connection attempts that
801  *          succeeded
802  * @param links_failed the number of overlay link connection attempts that
803  *          failed
804  */
805 static void
806 main_run (void *cls,
807           struct GNUNET_TESTBED_RunHandle *h,
808           unsigned int num_peers,
809           struct GNUNET_TESTBED_Peer **peers_,
810           unsigned int links_succeeded,
811           unsigned int links_failed)
812 {
813   int c_m;
814   int c_s;
815
816   GNUNET_assert (NULL == cls);
817   GNUNET_assert (top->num_masters + top->num_slaves == num_peers);
818   GNUNET_assert (NULL != peers_);
819
820   GNUNET_SCHEDULER_add_shutdown (&do_shutdown,
821                                  top);
822
823   GNUNET_log (GNUNET_ERROR_TYPE_INFO,
824               "Setting up %u masters and %u slaves\n",
825               top->num_masters,
826               top->num_slaves);
827
828   /* Setup master peers */
829   for (c_m = 0; c_m < top->num_masters; c_m++)
830   {
831     GNUNET_assert(NULL != peers_[c_m]);
832     top->mps[c_m].peer = peers_[c_m];
833     top->mps[c_m].no = c_m;
834     top->mps[c_m].master = GNUNET_YES;
835     top->mps[c_m].pref_partner = &top->sps[c_m];
836     top->mps[c_m].pref_value = TEST_ATS_PREFERENCE_DEFAULT;
837     top->mps[c_m].partners =
838         GNUNET_malloc (top->num_slaves * sizeof (struct BenchmarkPartner));
839     top->mps[c_m].num_partners = top->num_slaves;
840     /* Initialize partners */
841     for (c_s = 0; c_s < top->num_slaves; c_s++)
842     {
843       top->mps[c_m].partners[c_s].me = &top->mps[c_m];
844       top->mps[c_m].partners[c_s].dest = &top->sps[c_s];
845     }
846     /* Get configuration */
847     top->mps[c_m].peer_id_op
848       = GNUNET_TESTBED_peer_get_information (top->mps[c_m].peer,
849                                              GNUNET_TESTBED_PIT_IDENTITY,
850                                              &peerinformation_cb,
851                                              &top->mps[c_m]);
852   }
853
854   /* Setup slave peers */
855   for (c_s = 0; c_s < top->num_slaves; c_s++)
856   {
857     GNUNET_assert(NULL != peers_[c_s + top->num_masters]);
858     top->sps[c_s].peer = peers_[c_s + top->num_masters];
859     top->sps[c_s].no = c_s + top->num_masters;
860     top->sps[c_s].master = GNUNET_NO;
861     top->sps[c_s].partners =
862       GNUNET_new_array (top->num_masters,
863                         struct BenchmarkPartner);
864     top->sps[c_s].num_partners = top->num_masters;
865     /* Initialize partners */
866     for (c_m = 0; c_m < top->num_masters; c_m++)
867     {
868       top->sps[c_s].partners[c_m].me = &top->sps[c_s];
869       top->sps[c_s].partners[c_m].dest = &top->mps[c_m];
870
871       /* Initialize properties */
872       top->sps[c_s].partners[c_m].props.delay = GNUNET_TIME_UNIT_ZERO;
873       top->sps[c_s].partners[c_m].props.distance = 0;
874       top->sps[c_s].partners[c_m].props.scope = GNUNET_ATS_NET_UNSPECIFIED;
875       top->sps[c_s].partners[c_m].props.utilization_in = 0;
876       top->sps[c_s].partners[c_m].props.utilization_out = 0;
877     }
878     /* Get configuration */
879     top->sps[c_s].peer_id_op
880       = GNUNET_TESTBED_peer_get_information (top->sps[c_s].peer,
881                                              GNUNET_TESTBED_PIT_IDENTITY,
882                                              &peerinformation_cb,
883                                              &top->sps[c_s]);
884   }
885 }
886
887
888 /**
889  * Controller event callback
890  *
891  * @param cls NULL
892  * @param event the controller event
893  */
894 static void
895 controller_event_cb (void *cls,
896                      const struct GNUNET_TESTBED_EventInformation *event)
897 {
898   switch (event->type)
899   {
900   case GNUNET_TESTBED_ET_CONNECT:
901     break;
902   case GNUNET_TESTBED_ET_OPERATION_FINISHED:
903     break;
904   default:
905     GNUNET_break(0);
906     GNUNET_SCHEDULER_shutdown ();
907   }
908 }
909
910
911 struct BenchmarkPeer *
912 GNUNET_ATS_TEST_get_peer (int src)
913 {
914   if (src > top->num_masters)
915     return NULL;
916   return &top->mps[src];
917 }
918
919
920 struct BenchmarkPartner *
921 GNUNET_ATS_TEST_get_partner (int src,
922                              int dest)
923 {
924   if (src > top->num_masters)
925     return NULL;
926   if (dest > top->num_slaves)
927     return NULL;
928   return &top->mps[src].partners[dest];
929 }
930
931
932 /**
933  * Create a topology for ats testing
934  *
935  * @param name test name
936  * @param cfg_file configuration file to use for the peers
937  * @param num_slaves number of slaves
938  * @param num_masters number of masters
939  * @param test_core connect to CORE service (GNUNET_YES) or transport (GNUNET_NO)
940  * @param done_cb function to call when topology is setup
941  * @param done_cb_cls cls for callback
942  * @param log_request_cb callback to call when logging is required
943  */
944 void
945 GNUNET_ATS_TEST_create_topology (char *name, char *cfg_file,
946                                  unsigned int num_slaves,
947                                  unsigned int num_masters,
948                                  int test_core,
949                                  GNUNET_ATS_TEST_TopologySetupDoneCallback done_cb,
950                                  void *done_cb_cls,
951                                  GNUNET_ATS_AddressInformationCallback log_request_cb)
952 {
953   top = GNUNET_new (struct GNUNET_ATS_TEST_Topology);
954   top->num_masters = num_masters;
955   top->num_slaves = num_slaves;
956   top->done_cb = done_cb;
957   top->done_cb_cls = done_cb_cls;
958   top->test_core = test_core;
959   top->ats_perf_cb = log_request_cb;
960   top->mps = GNUNET_new_array (num_masters,
961                                struct BenchmarkPeer);
962   top->sps = GNUNET_new_array (num_slaves,
963                                struct BenchmarkPeer);
964
965   /* Start topology */
966   uint64_t event_mask;
967   event_mask = 0;
968   event_mask |= (1LL << GNUNET_TESTBED_ET_CONNECT);
969   event_mask |= (1LL << GNUNET_TESTBED_ET_OPERATION_FINISHED);
970   (void) GNUNET_TESTBED_test_run (name,
971                                   cfg_file,
972                                   num_slaves + num_masters,
973                                   event_mask,
974                                   &controller_event_cb, NULL,
975                                   &main_run, NULL);
976 }
977
978
979 /**
980  * Shutdown topology
981  */
982 void
983 GNUNET_ATS_TEST_shutdown_topology (void)
984 {
985   if (NULL == top)
986     return;
987   GNUNET_SCHEDULER_shutdown();
988 }
989
990
991 /* end of file ats-testing.c */