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