guix-env: some update.
[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
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->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 == memcmp (peer,
155                      &me->partners[c_m].dest->id,
156                      sizeof (struct GNUNET_PeerIdentity)))
157     {
158       return &me->partners[c_m];
159     }
160   }
161
162   return NULL;
163 }
164
165
166 static struct BenchmarkPeer *
167 find_peer (const struct GNUNET_PeerIdentity * peer)
168 {
169   int c_p;
170
171   for (c_p = 0; c_p < top->num_masters; c_p++)
172   {
173     if (0 == memcmp (&top->mps[c_p].id,
174                      peer,
175                      sizeof(struct GNUNET_PeerIdentity)))
176       return &top->mps[c_p];
177   }
178
179   for (c_p = 0; c_p < top->num_slaves; c_p++)
180   {
181     if (0 == memcmp (&top->sps[c_p].id,
182                      peer,
183                      sizeof(struct GNUNET_PeerIdentity)))
184       return &top->sps[c_p];
185   }
186   return NULL ;
187 }
188
189
190 /**
191  * Method called whenever a given peer connects.
192  *
193  * @param cls closure
194  * @param peer peer identity this notification is about
195  * @param mq queue to use to send messages to @a peer
196  * @return the `struct BenchmarkPartner` of @a peer
197  */
198 static void *
199 comm_connect_cb (void *cls,
200                  const struct GNUNET_PeerIdentity *peer,
201                  struct GNUNET_MQ_Handle *mq)
202 {
203   struct BenchmarkPeer *me = cls;
204   struct BenchmarkPeer *remote;
205   struct BenchmarkPartner *p;
206   char *id;
207   int c;
208   int completed;
209
210   remote = find_peer (peer);
211   if (NULL == remote)
212   {
213     GNUNET_log (GNUNET_ERROR_TYPE_WARNING,
214                 "Unknown peer connected: `%s'\n",
215                 GNUNET_i2s (peer));
216     GNUNET_break (0);
217     return NULL;
218   }
219
220   id = GNUNET_strdup (GNUNET_i2s (&me->id));
221   GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
222               "%s [%u] `%s' connected to %s [%u] %s\n",
223               (me->master == GNUNET_YES) ? "Master": "Slave",
224               me->no,
225               id,
226               (remote->master == GNUNET_YES) ? "Master": "Slave",
227               remote->no,
228               GNUNET_i2s (peer));
229
230   me->core_connections++;
231   if ((GNUNET_YES == me->master) &&
232       (GNUNET_NO == remote->master) &&
233       (GNUNET_NO == top->state.connected_CORE))
234   {
235     me->core_slave_connections++;
236
237     if (me->core_slave_connections == top->num_slaves)
238     {
239       GNUNET_log (GNUNET_ERROR_TYPE_INFO,
240                   "Master [%u] connected all slaves\n",
241                   me->no);
242     }
243     completed = GNUNET_YES;
244     for (c = 0; c < top->num_masters; c++)
245     {
246       if (top->mps[c].core_slave_connections != top->num_slaves)
247         completed = GNUNET_NO;
248     }
249     if (GNUNET_YES == completed)
250     {
251       GNUNET_log (GNUNET_ERROR_TYPE_INFO,
252                   "All master peers connected all slave peers\n");
253       top->state.connected_CORE = GNUNET_YES;
254       /* Notify about setup done */
255       if (NULL != top->done_cb)
256         top->done_cb (top->done_cb_cls,
257                       top->mps,
258                       top->sps);
259     }
260   }
261   GNUNET_free (id);
262   p = find_partner (me,
263                     peer);
264   if (NULL != p)
265     p->mq = mq;
266   return p;
267 }
268
269
270 /**
271  * @param cls this peer
272  * @param peer id of disconnecting peer
273  * @param internal_cls the `struct BenchmarkPartner` of @a peer
274  */
275 static void
276 comm_disconnect_cb (void *cls,
277                     const struct GNUNET_PeerIdentity *peer,
278                     void *internal_cls)
279 {
280   struct BenchmarkPeer *me = cls;
281   struct BenchmarkPartner *p = internal_cls;
282   char *id;
283
284   if (NULL == p)
285     return;
286
287   id = GNUNET_strdup (GNUNET_i2s (&me->id));
288   GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
289               "%s disconnected from %s\n",
290               id,
291               GNUNET_i2s (peer));
292   GNUNET_assert (me->core_connections > 0);
293   me->core_connections--;
294
295   if ( (GNUNET_YES == top->state.benchmarking) &&
296        ( (GNUNET_YES == me->master) ||
297          (GNUNET_YES == p->dest->master) ) )
298   {
299     GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
300                 "%s disconnected from %s while benchmarking\n",
301                 id,
302                 GNUNET_i2s (peer));
303   }
304   GNUNET_free(id);
305 }
306
307
308 static void
309 handle_pong (void *cls,
310              const struct TestMessage *message)
311 {
312   struct BenchmarkPartner *p = cls;
313
314   GNUNET_ATS_TEST_traffic_handle_pong (p);
315 }
316
317
318 static void
319 handle_ping (void *cls,
320              const struct TestMessage *message)
321 {
322   struct BenchmarkPartner *p = cls;
323
324   GNUNET_ATS_TEST_traffic_handle_ping (p);
325 }
326
327
328 static void *
329 transport_connect_adapter (void *cls,
330                            const struct GNUNET_CONFIGURATION_Handle *cfg)
331 {
332   struct BenchmarkPeer *me = cls;
333   struct GNUNET_MQ_MessageHandler handlers[] = {
334     GNUNET_MQ_hd_fixed_size (ping,
335                              TEST_MESSAGE_TYPE_PING,
336                              struct TestMessage,
337                              me),
338     GNUNET_MQ_hd_fixed_size (pong,
339                              TEST_MESSAGE_TYPE_PONG,
340                              struct TestMessage,
341                              me),
342     GNUNET_MQ_handler_end ()
343   };
344
345   me->th = GNUNET_TRANSPORT_core_connect (cfg,
346                                           &me->id,
347                                           handlers,
348                                           me,
349                                           &comm_connect_cb,
350                                           &comm_disconnect_cb,
351                                           NULL);
352   if (NULL == me->th)
353     GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
354                 "Failed to create transport connection \n");
355   return me->th;
356 }
357
358
359 static void
360 transport_disconnect_adapter (void *cls,
361                               void *op_result)
362 {
363   struct BenchmarkPeer *me = cls;
364
365   GNUNET_TRANSPORT_core_disconnect (me->th);
366   me->th = NULL;
367 }
368
369
370 static void *
371 core_connect_adapter (void *cls,
372                       const struct GNUNET_CONFIGURATION_Handle *cfg)
373 {
374   struct BenchmarkPeer *me = cls;
375   struct GNUNET_MQ_MessageHandler handlers[] = {
376     GNUNET_MQ_hd_fixed_size (ping,
377                              TEST_MESSAGE_TYPE_PING,
378                              struct TestMessage,
379                              me),
380     GNUNET_MQ_hd_fixed_size (pong,
381                              TEST_MESSAGE_TYPE_PONG,
382                              struct TestMessage,
383                              me),
384     GNUNET_MQ_handler_end ()
385   };
386
387   me->ch = GNUNET_CORE_connect (cfg,
388                                 me,
389                                 NULL,
390                                 &comm_connect_cb,
391                                 &comm_disconnect_cb,
392                                 handlers);
393   if (NULL == me->ch)
394     GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
395                 "Failed to create core connection \n");
396   return me->ch;
397 }
398
399
400 static void
401 core_disconnect_adapter (void *cls,
402                          void *op_result)
403 {
404   struct BenchmarkPeer *me = cls;
405
406   GNUNET_CORE_disconnect (me->ch);
407   me->ch = NULL;
408 }
409
410
411 static void
412 connect_completion_callback (void *cls,
413                              struct GNUNET_TESTBED_Operation *op,
414                              const char *emsg)
415 {
416   struct TestbedConnectOperation *cop = cls;
417   static int ops = 0;
418   int c;
419   if (NULL == emsg)
420   {
421     GNUNET_log(GNUNET_ERROR_TYPE_INFO,
422                _("Connected master [%u] with slave [%u]\n"),
423                cop->master->no,
424                cop->slave->no);
425   }
426   else
427   {
428     GNUNET_log(GNUNET_ERROR_TYPE_ERROR,
429         _("Failed to connect master peer [%u] with slave [%u]\n"),
430         cop->master->no, cop->slave->no);
431     GNUNET_break(0);
432     GNUNET_SCHEDULER_shutdown ();
433   }
434   GNUNET_TESTBED_operation_done (op);
435   ops++;
436   for (c = 0; c < top->num_slaves; c++)
437   {
438     if (cop == &cop->master->core_connect_ops[c])
439       cop->master->core_connect_ops[c].connect_op = NULL;
440   }
441   if (ops == top->num_masters * top->num_slaves)
442   {
443     top->state.connected_PEERS = GNUNET_YES;
444   }
445 }
446
447
448 static void
449 do_connect_peers (void *cls)
450 {
451   int c_m;
452   int c_s;
453   struct BenchmarkPeer *p;
454
455   if ((top->state.connected_ATS_service == GNUNET_NO) ||
456       (top->state.connected_COMM_service == GNUNET_NO))
457     return;
458
459   GNUNET_log (GNUNET_ERROR_TYPE_INFO,
460               "Connecting peers on CORE level\n");
461   for (c_m = 0; c_m < top->num_masters; c_m++)
462   {
463     p = &top->mps[c_m];
464     p->core_connect_ops = GNUNET_malloc (top->num_slaves *
465         sizeof (struct TestbedConnectOperation));
466
467     for (c_s = 0; c_s < top->num_slaves; c_s++)
468     {
469       GNUNET_log (GNUNET_ERROR_TYPE_INFO,
470                  "Connecting master [%u] with slave [%u]\n",
471                   p->no,
472                   top->sps[c_s].no);
473       p->core_connect_ops[c_s].master = p;
474       p->core_connect_ops[c_s].slave = &top->sps[c_s];
475       p->core_connect_ops[c_s].connect_op
476         = GNUNET_TESTBED_overlay_connect (NULL,
477                                           &connect_completion_callback,
478                                           &p->core_connect_ops[c_s],
479                                           top->sps[c_s].peer,
480                                           p->peer);
481       if (NULL == p->core_connect_ops[c_s].connect_op)
482        {
483         GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
484                     "Could not connect master [%u] and slave [%u]\n",
485                     p->no,
486                     top->sps[c_s].no);
487         GNUNET_break(0);
488         GNUNET_SCHEDULER_shutdown ();
489         return;
490       }
491     }
492   }
493 }
494
495
496 static void
497 comm_connect_completion_cb (void *cls,
498                             struct GNUNET_TESTBED_Operation *op,
499                             void *ca_result,
500                             const char *emsg)
501 {
502   static int comm_done = 0;
503
504   if ((NULL != emsg) || (NULL == ca_result))
505   {
506     GNUNET_log(GNUNET_ERROR_TYPE_INFO,
507                "Initialization failed, shutdown\n");
508     GNUNET_break(0);
509     GNUNET_SCHEDULER_shutdown ();
510     return;
511   }
512   comm_done++;
513
514   if (comm_done == top->num_slaves + top->num_masters)
515   {
516     GNUNET_log (GNUNET_ERROR_TYPE_INFO,
517                 "Connected to all %s services\n",
518                 (GNUNET_YES == top->test_core) ? "CORE" : "TRANSPORT");
519     top->state.connected_COMM_service = GNUNET_YES;
520     GNUNET_SCHEDULER_add_now (&do_connect_peers,
521                               NULL);
522   }
523 }
524
525
526 static void
527 do_comm_connect (void *cls)
528 {
529   int c_s;
530   int c_m;
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_ATS_NET_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   case GNUNET_TESTBED_ET_OPERATION_FINISHED:
884     break;
885   default:
886     GNUNET_break(0);
887     GNUNET_SCHEDULER_shutdown ();
888   }
889 }
890
891
892 struct BenchmarkPeer *
893 GNUNET_ATS_TEST_get_peer (int src)
894 {
895   if (src > top->num_masters)
896     return NULL;
897   return &top->mps[src];
898 }
899
900
901 struct BenchmarkPartner *
902 GNUNET_ATS_TEST_get_partner (int src,
903                              int dest)
904 {
905   if (src > top->num_masters)
906     return NULL;
907   if (dest > top->num_slaves)
908     return NULL;
909   return &top->mps[src].partners[dest];
910 }
911
912
913 /**
914  * Create a topology for ats testing
915  *
916  * @param name test name
917  * @param cfg_file configuration file to use for the peers
918  * @param num_slaves number of slaves
919  * @param num_masters number of masters
920  * @param test_core connect to CORE service (GNUNET_YES) or transport (GNUNET_NO)
921  * @param done_cb function to call when topology is setup
922  * @param done_cb_cls cls for callback
923  * @param log_request_cb callback to call when logging is required
924  */
925 void
926 GNUNET_ATS_TEST_create_topology (char *name, char *cfg_file,
927                                  unsigned int num_slaves,
928                                  unsigned int num_masters,
929                                  int test_core,
930                                  GNUNET_ATS_TEST_TopologySetupDoneCallback done_cb,
931                                  void *done_cb_cls,
932                                  GNUNET_ATS_AddressInformationCallback log_request_cb)
933 {
934   top = GNUNET_new (struct GNUNET_ATS_TEST_Topology);
935   top->num_masters = num_masters;
936   top->num_slaves = num_slaves;
937   top->done_cb = done_cb;
938   top->done_cb_cls = done_cb_cls;
939   top->test_core = test_core;
940   top->ats_perf_cb = log_request_cb;
941   top->mps = GNUNET_new_array (num_masters,
942                                struct BenchmarkPeer);
943   top->sps = GNUNET_new_array (num_slaves,
944                                struct BenchmarkPeer);
945
946   /* Start topology */
947   uint64_t event_mask;
948   event_mask = 0;
949   event_mask |= (1LL << GNUNET_TESTBED_ET_CONNECT);
950   event_mask |= (1LL << GNUNET_TESTBED_ET_OPERATION_FINISHED);
951   (void) GNUNET_TESTBED_test_run (name,
952                                   cfg_file,
953                                   num_slaves + num_masters,
954                                   event_mask,
955                                   &controller_event_cb, NULL,
956                                   &main_run, NULL);
957 }
958
959
960 /**
961  * Shutdown topology
962  */
963 void
964 GNUNET_ATS_TEST_shutdown_topology (void)
965 {
966   if (NULL == top)
967     return;
968   GNUNET_SCHEDULER_shutdown();
969 }
970
971
972 /* end of file ats-testing.c */