RECLAIM/OIDC: code cleanup
[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   if (NULL == emsg)
417   {
418     GNUNET_log(GNUNET_ERROR_TYPE_INFO,
419                _("Connected master [%u] with slave [%u]\n"),
420                cop->master->no,
421                cop->slave->no);
422   }
423   else
424   {
425     GNUNET_log(GNUNET_ERROR_TYPE_ERROR,
426         _("Failed to connect master peer [%u] with slave [%u]\n"),
427         cop->master->no, cop->slave->no);
428     GNUNET_break(0);
429     GNUNET_SCHEDULER_shutdown ();
430   }
431   GNUNET_TESTBED_operation_done (op);
432   ops++;
433   for (c = 0; c < top->num_slaves; c++)
434   {
435     if (cop == &cop->master->core_connect_ops[c])
436       cop->master->core_connect_ops[c].connect_op = NULL;
437   }
438   if (ops == top->num_masters * top->num_slaves)
439   {
440     top->state.connected_PEERS = GNUNET_YES;
441   }
442 }
443
444
445 static void
446 do_connect_peers (void *cls)
447 {
448   int c_m;
449   int c_s;
450   struct BenchmarkPeer *p;
451
452   if ((top->state.connected_ATS_service == GNUNET_NO) ||
453       (top->state.connected_COMM_service == GNUNET_NO))
454     return;
455
456   GNUNET_log (GNUNET_ERROR_TYPE_INFO,
457               "Connecting peers on CORE level\n");
458   for (c_m = 0; c_m < top->num_masters; c_m++)
459   {
460     p = &top->mps[c_m];
461     p->core_connect_ops = GNUNET_malloc (top->num_slaves *
462         sizeof (struct TestbedConnectOperation));
463
464     for (c_s = 0; c_s < top->num_slaves; c_s++)
465     {
466       GNUNET_log (GNUNET_ERROR_TYPE_INFO,
467                  "Connecting master [%u] with slave [%u]\n",
468                   p->no,
469                   top->sps[c_s].no);
470       p->core_connect_ops[c_s].master = p;
471       p->core_connect_ops[c_s].slave = &top->sps[c_s];
472       p->core_connect_ops[c_s].connect_op
473         = GNUNET_TESTBED_overlay_connect (NULL,
474                                           &connect_completion_callback,
475                                           &p->core_connect_ops[c_s],
476                                           top->sps[c_s].peer,
477                                           p->peer);
478       if (NULL == p->core_connect_ops[c_s].connect_op)
479        {
480         GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
481                     "Could not connect master [%u] and slave [%u]\n",
482                     p->no,
483                     top->sps[c_s].no);
484         GNUNET_break(0);
485         GNUNET_SCHEDULER_shutdown ();
486         return;
487       }
488     }
489   }
490 }
491
492
493 static void
494 comm_connect_completion_cb (void *cls,
495                             struct GNUNET_TESTBED_Operation *op,
496                             void *ca_result,
497                             const char *emsg)
498 {
499   static int comm_done = 0;
500
501   if ((NULL != emsg) || (NULL == ca_result))
502   {
503     GNUNET_log(GNUNET_ERROR_TYPE_INFO,
504                "Initialization failed, shutdown\n");
505     GNUNET_break(0);
506     GNUNET_SCHEDULER_shutdown ();
507     return;
508   }
509   comm_done++;
510
511   if (comm_done == top->num_slaves + top->num_masters)
512   {
513     GNUNET_log (GNUNET_ERROR_TYPE_INFO,
514                 "Connected to all %s services\n",
515                 (GNUNET_YES == top->test_core) ? "CORE" : "TRANSPORT");
516     top->state.connected_COMM_service = GNUNET_YES;
517     GNUNET_SCHEDULER_add_now (&do_connect_peers,
518                               NULL);
519   }
520 }
521
522
523 static void
524 do_comm_connect (void *cls)
525 {
526   int c_s;
527   int c_m;
528   GNUNET_log (GNUNET_ERROR_TYPE_INFO,
529               "Connecting to all %s services\n",
530               (GNUNET_YES == top->test_core) ? "CORE" : "TRANSPORT");
531   for (c_m = 0; c_m < top->num_masters; c_m++)
532   {
533     if (GNUNET_YES == top->test_core)
534       top->mps[c_m].comm_op
535         = GNUNET_TESTBED_service_connect (NULL,
536                                           top->mps[c_m].peer,
537                                           "core",
538                                           &comm_connect_completion_cb,
539                                           NULL,
540                                           &core_connect_adapter,
541                                           &core_disconnect_adapter,
542                                           &top->mps[c_m]);
543     else
544     {
545       top->mps[c_m].comm_op
546         = GNUNET_TESTBED_service_connect (NULL,
547                                           top->mps[c_m].peer,
548                                           "transport",
549                                           &comm_connect_completion_cb,
550                                           NULL,
551                                           &transport_connect_adapter,
552                                           &transport_disconnect_adapter,
553                                           &top->mps[c_m]);
554     }
555   }
556
557   for (c_s = 0; c_s < top->num_slaves; c_s++)
558   {
559     if (GNUNET_YES == top->test_core)
560       top->sps[c_s].comm_op
561         = GNUNET_TESTBED_service_connect (NULL,
562                                           top->sps[c_s].peer,
563                                           "core",
564                                           &comm_connect_completion_cb,
565                                           NULL,
566                                           &core_connect_adapter,
567                                           &core_disconnect_adapter,
568                                           &top->sps[c_s]);
569     else
570     {
571       top->sps[c_s].comm_op
572         = GNUNET_TESTBED_service_connect (NULL,
573                                           top->sps[c_s].peer,
574                                           "transport",
575                                           &comm_connect_completion_cb,
576                                           NULL,
577                                           &transport_connect_adapter,
578                                           &transport_disconnect_adapter,
579                                           &top->sps[c_s]);
580     }
581   }
582 }
583
584
585 static void
586 ats_performance_info_cb (void *cls,
587                          const struct GNUNET_HELLO_Address *address,
588                          int address_active,
589                          struct GNUNET_BANDWIDTH_Value32NBO bandwidth_out,
590                          struct GNUNET_BANDWIDTH_Value32NBO bandwidth_in,
591                          const struct GNUNET_ATS_Properties *ats_prop)
592 {
593   struct BenchmarkPeer *me = cls;
594   struct BenchmarkPartner *p;
595   int log;
596   char *peer_id;
597
598   if (NULL == address)
599   {
600     GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
601                 "Peer %u: ATS Service disconnected!\n",
602                 me->no);
603     return;
604   }
605
606   p = find_partner (me,
607                     &address->peer);
608   if (NULL == p)
609   {
610     /* This is not one of my partners
611      * Will happen since the peers will connect to each other due to gossiping
612      */
613     return;
614   }
615   peer_id = GNUNET_strdup (GNUNET_i2s (&me->id));
616
617   log = GNUNET_NO;
618   if ((p->bandwidth_in != ntohl (bandwidth_in.value__)) ||
619       (p->bandwidth_out != ntohl (bandwidth_out.value__)))
620       log = GNUNET_YES;
621   p->bandwidth_in = ntohl (bandwidth_in.value__);
622   p->bandwidth_out = ntohl (bandwidth_out.value__);
623
624   GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
625               "%s [%u] received ATS information: %s\n",
626               (GNUNET_YES == p->me->master) ? "Master" : "Slave",
627               p->me->no,
628               GNUNET_i2s (&p->dest->id));
629
630   p->props.utilization_out = ats_prop->utilization_out;
631   p->props.utilization_in = ats_prop->utilization_in;
632   p->props.scope = ats_prop->scope;
633   p->props.delay = ats_prop->delay;
634   p->props.distance = ats_prop->distance;
635
636   if (GNUNET_YES == log)
637     top->ats_perf_cb (cls, address,
638                       address_active,
639                       bandwidth_out,
640                       bandwidth_in,
641                       ats_prop);
642   GNUNET_free(peer_id);
643 }
644
645
646 static void *
647 ats_perf_connect_adapter (void *cls,
648                           const struct GNUNET_CONFIGURATION_Handle *cfg)
649 {
650   struct BenchmarkPeer *me = cls;
651
652   me->ats_perf_handle
653     = GNUNET_ATS_performance_init (cfg,
654                                    &ats_performance_info_cb,
655                                    me);
656   if (NULL == me->ats_perf_handle)
657     GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
658                 "Failed to create ATS performance handle \n");
659   return me->ats_perf_handle;
660 }
661
662
663 static void
664 ats_perf_disconnect_adapter (void *cls,
665                              void *op_result)
666 {
667   struct BenchmarkPeer *me = cls;
668
669   GNUNET_ATS_performance_done (me->ats_perf_handle);
670   me->ats_perf_handle = NULL;
671 }
672
673
674 static void
675 ats_connect_completion_cb (void *cls,
676                            struct GNUNET_TESTBED_Operation *op,
677                            void *ca_result,
678                            const char *emsg)
679 {
680   static int op_done = 0;
681
682   if ((NULL != emsg) || (NULL == ca_result))
683   {
684     GNUNET_log(GNUNET_ERROR_TYPE_INFO,
685                "Initialization failed, shutdown\n");
686     GNUNET_break(0);
687     GNUNET_SCHEDULER_shutdown ();
688     return;
689   }
690   op_done++;
691   if (op_done == (top->num_masters + top->num_slaves))
692   {
693     GNUNET_log (GNUNET_ERROR_TYPE_INFO,
694                 "Connected to all ATS services\n");
695     top->state.connected_ATS_service = GNUNET_YES;
696     GNUNET_SCHEDULER_add_now (&do_comm_connect,
697                               NULL);
698   }
699 }
700
701
702 static void
703 do_connect_ats (void *cls)
704 {
705   int c_m;
706   int c_s;
707
708   GNUNET_log (GNUNET_ERROR_TYPE_INFO,
709               "Connecting to all ATS services\n");
710   for (c_m = 0; c_m < top->num_masters; c_m++)
711   {
712     top->mps[c_m].ats_perf_op
713       = GNUNET_TESTBED_service_connect (NULL,
714                                         top->mps[c_m].peer,
715                                         "ats",
716                                         &ats_connect_completion_cb,
717                                         NULL,
718                                         &ats_perf_connect_adapter,
719                                         &ats_perf_disconnect_adapter,
720                                         &top->mps[c_m]);
721   }
722
723   for (c_s = 0; c_s < top->num_slaves; c_s++)
724   {
725     top->sps[c_s].ats_perf_op
726       = GNUNET_TESTBED_service_connect (NULL,
727                                         top->sps[c_s].peer,
728                                         "ats",
729                                         &ats_connect_completion_cb,
730                                         NULL,
731                                         &ats_perf_connect_adapter,
732                                         &ats_perf_disconnect_adapter,
733                                         &top->sps[c_s]);
734   }
735 }
736
737
738
739 static void
740 peerinformation_cb (void *cb_cls,
741                     struct GNUNET_TESTBED_Operation *op,
742                     const struct GNUNET_TESTBED_PeerInformation *pinfo,
743                     const char *emsg)
744 {
745   struct BenchmarkPeer *p = cb_cls;
746   static int done = 0;
747
748   GNUNET_assert(pinfo->pit == GNUNET_TESTBED_PIT_IDENTITY);
749
750   p->id = *pinfo->result.id;
751   GNUNET_log (GNUNET_ERROR_TYPE_INFO,
752               "%s [%u] has peer id `%s'\n",
753               (p->master == GNUNET_YES) ? "Master" : "Slave",
754               p->no,
755               GNUNET_i2s (&p->id));
756
757   GNUNET_TESTBED_operation_done (op);
758   p->peer_id_op = NULL;
759   done++;
760
761   if (done == top->num_slaves + top->num_masters)
762   {
763     GNUNET_log (GNUNET_ERROR_TYPE_INFO,
764                 "Retrieved all peer ID, connect to ATS\n");
765     GNUNET_SCHEDULER_add_now (&do_connect_ats,
766                               NULL);
767   }
768 }
769
770
771 /**
772  * Signature of a main function for a testcase.
773  *
774  * @param cls closure
775  * @param h testbed handle
776  * @param num_peers number of peers in 'peers'
777  * @param peers_ handle to peers run in the testbed
778  * @param links_succeeded the number of overlay link connection attempts that
779  *          succeeded
780  * @param links_failed the number of overlay link connection attempts that
781  *          failed
782  */
783 static void
784 main_run (void *cls,
785           struct GNUNET_TESTBED_RunHandle *h,
786           unsigned int num_peers,
787           struct GNUNET_TESTBED_Peer **peers_,
788           unsigned int links_succeeded,
789           unsigned int links_failed)
790 {
791   int c_m;
792   int c_s;
793
794   GNUNET_assert (NULL == cls);
795   GNUNET_assert (top->num_masters + top->num_slaves == num_peers);
796   GNUNET_assert (NULL != peers_);
797
798   GNUNET_SCHEDULER_add_shutdown (&do_shutdown,
799                                  top);
800
801   GNUNET_log (GNUNET_ERROR_TYPE_INFO,
802               "Setting up %u masters and %u slaves\n",
803               top->num_masters,
804               top->num_slaves);
805
806   /* Setup master peers */
807   for (c_m = 0; c_m < top->num_masters; c_m++)
808   {
809     GNUNET_assert(NULL != peers_[c_m]);
810     top->mps[c_m].peer = peers_[c_m];
811     top->mps[c_m].no = c_m;
812     top->mps[c_m].master = GNUNET_YES;
813     top->mps[c_m].pref_partner = &top->sps[c_m];
814     top->mps[c_m].pref_value = TEST_ATS_PREFERENCE_DEFAULT;
815     top->mps[c_m].partners =
816         GNUNET_malloc (top->num_slaves * sizeof (struct BenchmarkPartner));
817     top->mps[c_m].num_partners = top->num_slaves;
818     /* Initialize partners */
819     for (c_s = 0; c_s < top->num_slaves; c_s++)
820     {
821       top->mps[c_m].partners[c_s].me = &top->mps[c_m];
822       top->mps[c_m].partners[c_s].dest = &top->sps[c_s];
823     }
824     /* Get configuration */
825     top->mps[c_m].peer_id_op
826       = GNUNET_TESTBED_peer_get_information (top->mps[c_m].peer,
827                                              GNUNET_TESTBED_PIT_IDENTITY,
828                                              &peerinformation_cb,
829                                              &top->mps[c_m]);
830   }
831
832   /* Setup slave peers */
833   for (c_s = 0; c_s < top->num_slaves; c_s++)
834   {
835     GNUNET_assert(NULL != peers_[c_s + top->num_masters]);
836     top->sps[c_s].peer = peers_[c_s + top->num_masters];
837     top->sps[c_s].no = c_s + top->num_masters;
838     top->sps[c_s].master = GNUNET_NO;
839     top->sps[c_s].partners =
840       GNUNET_new_array (top->num_masters,
841                         struct BenchmarkPartner);
842     top->sps[c_s].num_partners = top->num_masters;
843     /* Initialize partners */
844     for (c_m = 0; c_m < top->num_masters; c_m++)
845     {
846       top->sps[c_s].partners[c_m].me = &top->sps[c_s];
847       top->sps[c_s].partners[c_m].dest = &top->mps[c_m];
848
849       /* Initialize properties */
850       top->sps[c_s].partners[c_m].props.delay = GNUNET_TIME_UNIT_ZERO;
851       top->sps[c_s].partners[c_m].props.distance = 0;
852       top->sps[c_s].partners[c_m].props.scope = GNUNET_NT_UNSPECIFIED;
853       top->sps[c_s].partners[c_m].props.utilization_in = 0;
854       top->sps[c_s].partners[c_m].props.utilization_out = 0;
855     }
856     /* Get configuration */
857     top->sps[c_s].peer_id_op
858       = GNUNET_TESTBED_peer_get_information (top->sps[c_s].peer,
859                                              GNUNET_TESTBED_PIT_IDENTITY,
860                                              &peerinformation_cb,
861                                              &top->sps[c_s]);
862   }
863 }
864
865
866 /**
867  * Controller event callback
868  *
869  * @param cls NULL
870  * @param event the controller event
871  */
872 static void
873 controller_event_cb (void *cls,
874                      const struct GNUNET_TESTBED_EventInformation *event)
875 {
876   switch (event->type)
877   {
878   case GNUNET_TESTBED_ET_CONNECT:
879     break;
880   case GNUNET_TESTBED_ET_OPERATION_FINISHED:
881     break;
882   default:
883     GNUNET_break(0);
884     GNUNET_SCHEDULER_shutdown ();
885   }
886 }
887
888
889 struct BenchmarkPeer *
890 GNUNET_ATS_TEST_get_peer (int src)
891 {
892   if (src > top->num_masters)
893     return NULL;
894   return &top->mps[src];
895 }
896
897
898 struct BenchmarkPartner *
899 GNUNET_ATS_TEST_get_partner (int src,
900                              int dest)
901 {
902   if (src > top->num_masters)
903     return NULL;
904   if (dest > top->num_slaves)
905     return NULL;
906   return &top->mps[src].partners[dest];
907 }
908
909
910 /**
911  * Create a topology for ats testing
912  *
913  * @param name test name
914  * @param cfg_file configuration file to use for the peers
915  * @param num_slaves number of slaves
916  * @param num_masters number of masters
917  * @param test_core connect to CORE service (GNUNET_YES) or transport (GNUNET_NO)
918  * @param done_cb function to call when topology is setup
919  * @param done_cb_cls cls for callback
920  * @param log_request_cb callback to call when logging is required
921  */
922 void
923 GNUNET_ATS_TEST_create_topology (char *name, char *cfg_file,
924                                  unsigned int num_slaves,
925                                  unsigned int num_masters,
926                                  int test_core,
927                                  GNUNET_ATS_TEST_TopologySetupDoneCallback done_cb,
928                                  void *done_cb_cls,
929                                  GNUNET_ATS_AddressInformationCallback log_request_cb)
930 {
931   top = GNUNET_new (struct GNUNET_ATS_TEST_Topology);
932   top->num_masters = num_masters;
933   top->num_slaves = num_slaves;
934   top->done_cb = done_cb;
935   top->done_cb_cls = done_cb_cls;
936   top->test_core = test_core;
937   top->ats_perf_cb = log_request_cb;
938   top->mps = GNUNET_new_array (num_masters,
939                                struct BenchmarkPeer);
940   top->sps = GNUNET_new_array (num_slaves,
941                                struct BenchmarkPeer);
942
943   /* Start topology */
944   uint64_t event_mask;
945   event_mask = 0;
946   event_mask |= (1LL << GNUNET_TESTBED_ET_CONNECT);
947   event_mask |= (1LL << GNUNET_TESTBED_ET_OPERATION_FINISHED);
948   (void) GNUNET_TESTBED_test_run (name,
949                                   cfg_file,
950                                   num_slaves + num_masters,
951                                   event_mask,
952                                   &controller_event_cb, NULL,
953                                   &main_run, NULL);
954 }
955
956
957 /**
958  * Shutdown topology
959  */
960 void
961 GNUNET_ATS_TEST_shutdown_topology (void)
962 {
963   if (NULL == top)
964     return;
965   GNUNET_SCHEDULER_shutdown();
966 }
967
968
969 /* end of file ats-testing.c */