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