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