disabling tests not yet passing
[oweals/gnunet.git] / src / ats-tests / perf_ats.c
1 /*
2      This file is part of GNUnet.
3      (C) 2010-2013 Christian Grothoff (and other contributing authors)
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., 59 Temple Place - Suite 330,
18      Boston, MA 02111-1307, USA.
19 */
20 /**
21  * @file ats/perf_ats.c
22  * @brief ats benchmark: start peers and modify preferences, monitor change over time
23  * @author Christian Grothoff
24  * @author Matthias Wachs
25  */
26 #include "platform.h"
27 #include "gnunet_util_lib.h"
28 #include "gnunet_testbed_service.h"
29 #include "gnunet_ats_service.h"
30 #include "gnunet_core_service.h"
31
32 #define TEST_TIMEOUT GNUNET_TIME_relative_multiply (GNUNET_TIME_UNIT_SECONDS, 10)
33 #define BENCHMARK_DURATION GNUNET_TIME_relative_multiply (GNUNET_TIME_UNIT_SECONDS, 5)
34 #define TESTNAME_PREFIX "perf_ats_"
35 #define DEFAULT_SLAVES_NUM 3
36 #define DEFAULT_MASTERS_NUM 1
37
38 #define TEST_MESSAGE_TYPE_PING 12345
39 #define TEST_MESSAGE_TYPE_PONG 12346
40 #define TEST_MESSAGE_SIZE 1000
41 #define TEST_MESSAGE_FREQUENCY GNUNET_TIME_relative_multiply (GNUNET_TIME_UNIT_SECONDS, 1)
42
43
44 /**
45  * Information we track for a peer in the testbed.
46  */
47 struct BenchmarkPeer
48 {
49   /**
50    * Handle with testbed.
51    */
52   struct GNUNET_TESTBED_Peer *peer;
53
54   /**
55    * Unique identifier
56    */
57   int no;
58
59   /**
60    *  master: GNUNET_YES/NO
61    */
62   int master;
63
64   /**
65    *  Peer ID
66    */
67   struct GNUNET_PeerIdentity id;
68
69   /**
70    *  Core handle
71    */
72   struct GNUNET_CORE_Handle *ch;
73
74   /**
75    * Testbed operation to connect to ATS performance service
76    */
77   struct GNUNET_TESTBED_Operation *ats_perf_op;
78
79   /**
80    * Testbed operation to get peer information
81    */
82   struct GNUNET_TESTBED_Operation *info_op;
83
84   /**
85    * Testbed operation to connect to core
86    */
87   struct GNUNET_TESTBED_Operation *core_op;
88
89   /**
90    * ATS performance handle
91    */
92   struct GNUNET_ATS_PerformanceHandle *p_handle;
93
94   /**
95    * Testbed connecect operation
96    */
97   struct ConnectOperation *connect_ops;
98
99         /**
100          * ATS Measurement Partner
101          */
102   struct BenchmarkPeer *destination;
103
104   GNUNET_SCHEDULER_TaskIdentifier ats_task;
105
106   /* Message exchange */
107
108   /**
109    * Core transmit handle
110    */
111   struct GNUNET_CORE_TransmitHandle *cth;
112
113   /**
114    * DLL for pending messages: head
115    */
116         struct PendingMessages *p_head;
117
118   /**
119    * DLL for pending messages: tail
120    */
121         struct PendingMessages *p_tail;
122
123         /**
124          *  Bit-mask for next partner selection
125          */
126         uint32_t send_mask;
127
128         /**
129          * Current message for partner?
130          */
131         int partner_msg;
132
133         /**
134          * Number of core connections
135          */
136   int core_connections;
137
138         /**
139          * Number of slave connections
140          */
141   int slave_connections;
142
143   /**
144    * Statistics
145    */
146   unsigned int messages_sent;
147   unsigned int messages_sent_partner;
148   unsigned int messages_received;
149 };
150
151
152 static int c_master_peers;
153
154 /**
155  * Array of master peers
156  * Preferences to be set for
157  */
158 static struct BenchmarkPeer *bp_master;
159
160 static int c_slave_peers;
161
162 /**
163  * Array of slave peers
164  * Peer used for measurements
165  */
166 static struct BenchmarkPeer *bp_slaves;
167
168
169 struct BenchmarkState
170 {
171         /* Are we connected to ATS service of all peers: GNUNET_YES/NO */
172         int connected_ATS_service;
173
174         /* Are we connected to CORE service of all peers: GNUNET_YES/NO */
175         int connected_CORE_service;
176
177         /* Are we connected to all peers: GNUNET_YES/NO */
178         int connected_PEERS;
179
180         /* Are we connected to all slave peers on CORE level: GNUNET_YES/NO */
181         int connected_CORE;
182
183         /* Are we connected to CORE service of all peers: GNUNET_YES/NO */
184         int benchmarking;
185
186         int *core_connections;
187
188         uint32_t partner_map;
189 };
190
191 static struct BenchmarkState state;
192
193 /**
194  * Shutdown task
195  */
196 static GNUNET_SCHEDULER_TaskIdentifier shutdown_task;
197
198 static int result;
199 static char *solver;
200 static char *pref_str;
201 static int pref_val;
202
203 /**
204  * Pending Responses
205  */
206 struct PendingMessages
207 {
208         struct PendingMessages *prev;
209         struct PendingMessages *next;
210         struct GNUNET_PeerIdentity target;
211 };
212
213
214 /**
215  * Information we track for a peer in the testbed.
216  */
217 struct ConnectOperation
218 {
219         struct BenchmarkPeer *master;
220
221         struct BenchmarkPeer *slave;
222   /**
223    * Testbed operation to connect peers
224    */
225   struct GNUNET_TESTBED_Operation *connect_op;
226
227 };
228
229
230 static void
231 core_connect_completion_cb (void *cls,
232                             struct GNUNET_TESTBED_Operation *op,
233                             void *ca_result,
234                             const char *emsg );
235
236
237 static void evaluate ()
238 {
239         int c_p;
240         struct BenchmarkPeer *bp;
241         int total_out;
242         int partner_out;
243
244   for (c_p = 0; c_p < c_master_peers; c_p++)
245   {
246         bp = &bp_master[c_p];
247         total_out = (bp->messages_sent * TEST_MESSAGE_SIZE) / 10240;
248         partner_out = (bp->messages_sent_partner * TEST_MESSAGE_SIZE) / 10240;
249     fprintf (stderr, _("Peer %u: Out total: %u KiB/s, out partner %u KiB/s\n"),
250                 bp->no,
251                 total_out, partner_out
252                 /*partner_out / (total_out / 100)*/);
253   }
254 }
255
256 /**
257  * Shutdown nicely
258  *
259  * @param cls NULL
260  * @param tc the task context
261  */
262 static void
263 do_shutdown (void *cls, const struct GNUNET_SCHEDULER_TaskContext *tc)
264 {
265   int c_p;
266   int c_op;
267   struct PendingMessages *cur;
268   struct PendingMessages *next;
269
270   shutdown_task = GNUNET_SCHEDULER_NO_TASK;
271
272   state.benchmarking = GNUNET_NO;
273
274   evaluate ();
275   GNUNET_log (GNUNET_ERROR_TYPE_INFO, _("Benchmarking done\n"));
276
277   for (c_p = 0; c_p < c_master_peers; c_p++)
278   {
279         next = bp_master[c_p].p_head;
280         for (cur = next; cur != NULL; cur = next )
281         {
282                 next = cur->next;
283                 GNUNET_CONTAINER_DLL_remove (bp_master[c_p].p_head, bp_master[c_p].p_tail, cur);
284                 GNUNET_free (cur);
285         }
286
287         if (GNUNET_SCHEDULER_NO_TASK != bp_master[c_p].ats_task)
288         {
289                 GNUNET_SCHEDULER_cancel (bp_master[c_p].ats_task);
290                 bp_master[c_p].ats_task = GNUNET_SCHEDULER_NO_TASK;
291         }
292
293         if (NULL != bp_master[c_p].cth)
294         {
295                 GNUNET_CORE_notify_transmit_ready_cancel(bp_master[c_p].cth);
296                 bp_master[c_p].cth = NULL;
297         }
298
299         if (NULL != bp_master[c_p].ats_perf_op)
300         {
301                 GNUNET_TESTBED_operation_done (bp_master[c_p].ats_perf_op);
302                 bp_master[c_p].ats_perf_op = NULL;
303         }
304
305         if (NULL != bp_master[c_p].core_op)
306         {
307                 GNUNET_TESTBED_operation_done (bp_master[c_p].core_op);
308                 bp_master[c_p].core_op = NULL;
309         }
310
311         if (NULL != bp_master[c_p].info_op)
312         {
313                 GNUNET_break (0);
314                 GNUNET_TESTBED_operation_done (bp_master[c_p].info_op);
315                 bp_master[c_p].info_op = NULL;
316         }
317
318         for (c_op = 0; c_op < c_slave_peers; c_op++)
319         {
320                 if (NULL != bp_master[c_p].connect_ops[c_op].connect_op)
321                 {
322                 GNUNET_log (GNUNET_ERROR_TYPE_INFO, _("Failed to connect peer 0 and %u\n"), c_p);
323                 GNUNET_TESTBED_operation_done (bp_master[c_p].connect_ops[c_op].connect_op);
324                 bp_master[c_p].connect_ops[c_op].connect_op = NULL;
325         result = 1;
326                 }
327         }
328         GNUNET_free (bp_master[c_p].connect_ops);
329   }
330
331   for (c_p = 0; c_p < c_slave_peers; c_p++)
332   {
333         next = bp_slaves[c_p].p_head;
334         for (cur = next; cur != NULL; cur = next )
335         {
336                 next = cur->next;
337                 GNUNET_CONTAINER_DLL_remove (bp_slaves[c_p].p_head, bp_slaves[c_p].p_tail, cur);
338                 GNUNET_free (cur);
339         }
340
341         if (NULL != bp_slaves[c_p].cth)
342         {
343                 GNUNET_CORE_notify_transmit_ready_cancel(bp_slaves[c_p].cth);
344                 bp_slaves[c_p].cth = NULL;
345         }
346
347         if (NULL != bp_slaves[c_p].ats_perf_op)
348         {
349                 GNUNET_TESTBED_operation_done (bp_slaves[c_p].ats_perf_op);
350                 bp_slaves[c_p].ats_perf_op = NULL;
351         }
352
353         if (NULL != bp_slaves[c_p].core_op)
354         {
355                 GNUNET_TESTBED_operation_done (bp_slaves[c_p].core_op);
356                 bp_slaves[c_p].core_op = NULL;
357         }
358
359         if (NULL != bp_slaves[c_p].info_op)
360         {
361                 GNUNET_break (0);
362                 GNUNET_TESTBED_operation_done (bp_slaves[c_p].info_op);
363                 bp_slaves[c_p].info_op = NULL;
364         }
365
366   }
367
368         GNUNET_SCHEDULER_shutdown();
369 }
370
371 static struct BenchmarkPeer *
372 find_peer (const struct GNUNET_PeerIdentity * peer)
373 {
374         int c_p;
375
376   for (c_p = 0; c_p < c_master_peers; c_p++)
377   {
378     if (0 == memcmp (&bp_master[c_p].id, peer, sizeof (struct GNUNET_PeerIdentity)))
379         return &bp_master[c_p];
380   }
381
382   for (c_p = 0; c_p < c_slave_peers; c_p++)
383   {
384     if (0 == memcmp (&bp_slaves[c_p].id, peer, sizeof (struct GNUNET_PeerIdentity)))
385         return &bp_slaves[c_p];
386   }
387
388         return NULL;
389 }
390
391
392 static void
393 store_information (struct GNUNET_PeerIdentity *id,
394                  const struct GNUNET_HELLO_Address *address,
395                  int address_active,
396                  struct GNUNET_BANDWIDTH_Value32NBO bandwidth_out,
397                  struct GNUNET_BANDWIDTH_Value32NBO bandwidth_in,
398                  const struct GNUNET_ATS_Information *ats,
399                  uint32_t ats_count)
400 {
401         struct BenchmarkPeer *bp;
402
403         bp = find_peer (id);
404
405         if (NULL == bp)
406         {
407                 GNUNET_break (0);
408                 return;
409         }
410 }
411
412 static void
413 ats_performance_info_cb (void *cls,
414                          const struct GNUNET_HELLO_Address *address,
415                          int address_active,
416                          struct GNUNET_BANDWIDTH_Value32NBO bandwidth_out,
417                          struct GNUNET_BANDWIDTH_Value32NBO bandwidth_in,
418                          const struct GNUNET_ATS_Information *ats,
419                          uint32_t ats_count)
420 {
421         struct BenchmarkPeer *bp = cls;
422         int c_a;
423         char *peer_id;
424
425         peer_id = GNUNET_strdup (GNUNET_i2s (&bp->id));
426         for (c_a = 0; c_a < ats_count; c_a++)
427         {
428                 /*GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, _("%c %03u: %s %s %u\n"),
429                                         (GNUNET_YES == p->master) ? 'M' : 'S',
430                                         p->no,
431                             GNUNET_i2s (&address->peer),
432                             GNUNET_ATS_print_property_type(ntohl(ats[c_a].type)),
433                             ntohl(ats[c_a].value));*/
434         }
435
436         if ((GNUNET_YES == bp->master) &&
437         (0 == memcmp (&address->peer,  &bp->destination->id,
438                         sizeof (struct GNUNET_PeerIdentity))))
439         {
440                 GNUNET_log (GNUNET_ERROR_TYPE_INFO, "Bandwidth for master %u: %lu %lu\n",
441                                 bp->no,
442                                 (long unsigned int) ntohl(bandwidth_in.value__),
443                                 (long unsigned int) ntohl(bandwidth_in.value__));
444         }
445
446         store_information (&bp->id, address, address_active,
447                         bandwidth_in, bandwidth_out,
448                         ats, ats_count);
449
450         GNUNET_free (peer_id);
451 }
452
453 static size_t
454 core_send_ready (void *cls, size_t size, void *buf)
455 {
456         static char msgbuf[TEST_MESSAGE_SIZE];
457         struct BenchmarkPeer *bp = cls;
458         struct GNUNET_MessageHeader *msg;
459
460         bp->cth = NULL;
461
462         bp->messages_sent ++;
463         if (GNUNET_YES == bp->partner_msg)
464         {
465                 bp->messages_sent_partner ++;
466                 bp->partner_msg = GNUNET_NO;
467         }
468
469         msg = (struct GNUNET_MessageHeader *) &msgbuf;
470         memset (&msgbuf, 'a', TEST_MESSAGE_SIZE);
471         msg->type = htons (TEST_MESSAGE_TYPE_PING);
472         msg->size = htons (TEST_MESSAGE_SIZE);
473         memcpy (buf, msg, TEST_MESSAGE_SIZE);
474         return TEST_MESSAGE_SIZE;
475 }
476
477 static struct BenchmarkPeer *
478 get_next (struct BenchmarkPeer *p)
479 {
480         uint32_t b_index;
481         uint32_t index;
482         int counter;
483
484         if (0 == p->send_mask)
485                 p->send_mask = (1 << c_slave_peers) - 1; /* Next round */
486
487         GNUNET_assert (p->send_mask <= (1 << c_slave_peers) - 1);
488         counter = 0;
489         do
490         {
491                 index = GNUNET_CRYPTO_random_u32 (GNUNET_CRYPTO_QUALITY_WEAK, c_slave_peers);
492                 b_index = 1 << index;
493                 counter++;
494         }
495         while   ((b_index != (p->send_mask & b_index)) && (counter < c_slave_peers));
496         if ((b_index != (p->send_mask & b_index)) && (counter == c_slave_peers))
497         {
498                 /* To many random attempts use fcfs */
499                 for (index = 0; index < c_slave_peers - 1; index ++)
500                 {
501                         b_index = 1 << index;
502                         if (b_index == (p->send_mask & b_index))
503                                 break;
504                 }
505         }
506         p->send_mask ^= b_index; /* Remove bit */
507         return &bp_slaves[index];
508
509 }
510
511
512 static void
513 ats_pref_task (void *cls, const struct GNUNET_SCHEDULER_TaskContext *tc)
514 {
515         static double last = 1;
516         struct BenchmarkPeer *bp = cls;
517
518         bp->ats_task = GNUNET_SCHEDULER_NO_TASK;
519
520         GNUNET_log (GNUNET_ERROR_TYPE_INFO, "Set preference for master %u: %f\n",
521                         bp->no, last);
522         GNUNET_ATS_performance_change_preference (bp->p_handle, &bp->destination->id,
523                         pref_val, (double) last,
524                         GNUNET_ATS_PREFERENCE_END);
525         last++;
526         bp->ats_task = GNUNET_SCHEDULER_add_delayed (GNUNET_TIME_UNIT_SECONDS,
527                         &ats_pref_task, bp);
528 }
529
530
531 static void 
532 do_benchmark ()
533 {
534         int c_m;
535         struct BenchmarkPeer *s;
536         struct BenchmarkPeer *bp;
537
538         if ((state.connected_ATS_service == GNUNET_NO) ||
539                         (state.connected_CORE_service == GNUNET_NO) ||
540                         (state.connected_PEERS == GNUNET_NO) ||
541                         (state.connected_CORE == GNUNET_NO))
542                 return;
543
544         state.benchmarking = GNUNET_YES;
545         GNUNET_log (GNUNET_ERROR_TYPE_INFO,
546                         _("Benchmarking start\n"));
547
548         if (GNUNET_SCHEDULER_NO_TASK != shutdown_task)
549                 GNUNET_SCHEDULER_cancel (shutdown_task);
550         shutdown_task = GNUNET_SCHEDULER_add_delayed (BENCHMARK_DURATION, &do_shutdown, NULL);
551
552         /* Start sending test messages */
553         for (c_m = 0; c_m < c_master_peers; c_m ++)
554         {
555                 bp = &bp_master[c_m];
556                 s = get_next (bp);
557                 if (0 == memcmp(&s->id, &bp->destination->id, sizeof (struct GNUNET_PeerIdentity)))
558                         bp->partner_msg = GNUNET_YES;
559                 bp->cth = GNUNET_CORE_notify_transmit_ready (bp->ch,
560                                         GNUNET_NO, 0, GNUNET_TIME_UNIT_MINUTES,
561                                         &s->id,
562                                         TEST_MESSAGE_SIZE, &core_send_ready, bp);
563                 bp->ats_task = GNUNET_SCHEDULER_add_delayed (GNUNET_TIME_UNIT_SECONDS,
564                                 &ats_pref_task, bp);
565         }
566
567
568 }
569
570
571 static void 
572 connect_completion_callback (void *cls,
573                              struct GNUNET_TESTBED_Operation *op,
574                              const char *emsg)
575 {
576         struct ConnectOperation *cop = cls;
577         static int ops = 0 ;
578         int c;
579         if (NULL == emsg)
580         {
581                 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
582                                 _("Connected master peer %u with peer %u\n"), cop->master->no, cop->slave->no);
583         }
584         else
585         {
586                 GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
587                                 _("Failed to connect master peer%u with peer %u\n"), cop->master->no, cop->slave->no);
588                 GNUNET_break (0);
589                 if (GNUNET_SCHEDULER_NO_TASK != shutdown_task)
590                         GNUNET_SCHEDULER_cancel(shutdown_task);
591                 shutdown_task = GNUNET_SCHEDULER_add_now (do_shutdown, NULL);
592         }
593         GNUNET_TESTBED_operation_done(op);
594         ops++;
595         for (c = 0; c < c_slave_peers; c++)
596         {
597                 if (cop == &cop->master->connect_ops[c])
598                         cop->master->connect_ops[c].connect_op = NULL;
599         }
600         if (ops == c_master_peers * c_slave_peers)
601         {
602                 state.connected_PEERS = GNUNET_YES;
603                 GNUNET_SCHEDULER_add_now (&do_benchmark, NULL);
604         }
605 }
606
607
608 static void
609 do_connect_peers (void *cls, const struct GNUNET_SCHEDULER_TaskContext *tc)
610 {
611         int c_m;
612         int c_s;
613         struct BenchmarkPeer *bp;
614
615         if ((state.connected_ATS_service == GNUNET_NO) ||
616                         (state.connected_CORE_service == GNUNET_NO))
617         {
618                 return;
619         }
620
621         GNUNET_log (GNUNET_ERROR_TYPE_INFO, _("Connecting peers on CORE level\n"));
622
623         for (c_m = 0; c_m < c_master_peers; c_m ++)
624         {
625                 bp = &bp_master[c_m];
626                 bp->connect_ops = GNUNET_malloc (c_slave_peers * sizeof (struct ConnectOperation));
627
628                 for (c_s = 0; c_s < c_slave_peers; c_s ++)
629                 {
630                         GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, _("Connecting master peer %u with slave peer %u\n"),
631                                         bp->no, bp_slaves[c_s].no);
632
633                         bp->connect_ops[c_s].master = bp;
634                         bp->connect_ops[c_s].slave = &bp_slaves[c_s];
635                         bp->connect_ops[c_s].connect_op = GNUNET_TESTBED_overlay_connect( NULL,
636                                         &connect_completion_callback,
637                                         &bp->connect_ops[c_s],
638                                         bp_slaves[c_s].peer,
639                                         bp->peer);
640
641                         if (NULL == bp->connect_ops[c_s].connect_op)
642                         {
643                                 GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
644                                                 _("Could not connect master peer %u and slave peer %u\n"),
645                                                 bp->no, bp_slaves[c_s].no);
646                                 GNUNET_break (0);
647                                 if (GNUNET_SCHEDULER_NO_TASK != shutdown_task)
648                                         GNUNET_SCHEDULER_cancel(shutdown_task);
649                                 shutdown_task = GNUNET_SCHEDULER_add_now (do_shutdown, NULL);
650                                 return;
651                         }
652                 }
653         }
654 }
655
656
657 /**
658  * Controller event callback
659  *
660  * @param cls NULL
661  * @param event the controller event
662  */
663 static void
664 controller_event_cb (void *cls,
665                      const struct GNUNET_TESTBED_EventInformation *event)
666 {
667         //struct BenchmarkPeer *p = cls;
668   switch (event->type)
669   {
670   case GNUNET_TESTBED_ET_CONNECT:
671     break;
672   case GNUNET_TESTBED_ET_OPERATION_FINISHED:
673     break;
674   default:
675     GNUNET_break (0);
676     result = 2;
677     GNUNET_SCHEDULER_cancel (shutdown_task);
678     shutdown_task = GNUNET_SCHEDULER_add_now (&do_shutdown, NULL);
679   }
680 }
681
682 /**
683  * Method called whenever a given peer connects.
684  *
685  * @param cls closure
686  * @param peer peer identity this notification is about
687  */
688 static void
689 core_connect_cb (void *cls, const struct GNUNET_PeerIdentity * peer)
690 {
691   struct BenchmarkPeer *p = cls;
692   struct BenchmarkPeer *t;
693   char *id;
694   int c;
695   int cs;
696
697   t = find_peer (peer);
698   if (NULL == t)
699   {
700         GNUNET_break (0);
701         return;
702   }
703
704   id = GNUNET_strdup (GNUNET_i2s (&p->id));
705   GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
706               "%s %s connected to %s %s\n",
707               (p->master == GNUNET_YES) ? "Master": "Slave",
708               id,
709               (t->master == GNUNET_YES) ? "Master": "Slave",
710               GNUNET_i2s (peer));
711
712   p->core_connections ++;
713   if ((GNUNET_YES == p->master) && (GNUNET_NO == t->master) && (GNUNET_NO == state.connected_CORE))
714   {
715         p->slave_connections ++;
716
717                 if (p->slave_connections == c_slave_peers)
718                 {
719                         GNUNET_log (GNUNET_ERROR_TYPE_INFO,
720                                         "Master %u connected all slaves\n", p->no);
721                 }
722                 cs = GNUNET_YES;
723                 for (c = 0; c < c_master_peers; c ++)
724                 {
725                         if (bp_master[c].slave_connections != c_slave_peers)
726                                 cs = GNUNET_NO;
727                 }
728                 if (GNUNET_YES == cs)
729                 {
730                         GNUNET_log (GNUNET_ERROR_TYPE_INFO,
731                         "All master peers connected all slave peers\n", id, GNUNET_i2s (peer));
732                         state.connected_CORE = GNUNET_YES;
733                         GNUNET_SCHEDULER_add_now (&do_benchmark, NULL);
734                 }
735         }
736         GNUNET_free (id);
737 }
738
739
740 /**
741  * Method called whenever a peer disconnects.
742  *
743  * @param cls closure
744  * @param peer peer identity this notification is about
745  */
746 static void
747 core_disconnect_cb (void *cls, const struct GNUNET_PeerIdentity * peer)
748 {
749   struct BenchmarkPeer *p = cls;
750   struct BenchmarkPeer *t;
751   char *id;
752
753   t = find_peer (peer);
754   if (NULL == t)
755   {
756         GNUNET_break (0);
757         return;
758   }
759
760   id = GNUNET_strdup (GNUNET_i2s (&p->id));
761   GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
762               "%s disconnected from %s \n", id, GNUNET_i2s (peer));
763   GNUNET_assert (p->core_connections > 0);
764   p->core_connections --;
765
766   if ((GNUNET_YES == state.benchmarking) &&
767                 ((GNUNET_YES == p->master) || (GNUNET_YES == t->master)))
768   {
769     GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
770               "%s disconnected from %s while benchmarking \n", id, GNUNET_i2s (peer));
771   }
772
773   GNUNET_free (id);
774 }
775
776 static size_t
777 core_send_echo_queued_ready (void *cls, size_t size, void *buf);
778
779 static size_t
780 core_send_echo_ready (void *cls, size_t size, void *buf)
781 {
782         static char msgbuf[TEST_MESSAGE_SIZE];
783         struct BenchmarkPeer *bp = cls;
784         struct GNUNET_MessageHeader *msg;
785
786         bp->cth = NULL;
787
788         msg = (struct GNUNET_MessageHeader *) &msgbuf;
789         memset (&msgbuf, 'a', TEST_MESSAGE_SIZE);
790         msg->type = htons (TEST_MESSAGE_TYPE_PONG);
791         msg->size = htons (TEST_MESSAGE_SIZE);
792         memcpy (buf, msg, TEST_MESSAGE_SIZE);
793
794         /* send echo */
795         if (NULL != bp->p_head)
796                 bp->cth = GNUNET_CORE_notify_transmit_ready (bp->ch,
797                                 GNUNET_NO, 0, GNUNET_TIME_UNIT_MINUTES,
798                                 &bp->p_head->target,
799                                 TEST_MESSAGE_SIZE, &core_send_echo_queued_ready, bp);
800
801         return TEST_MESSAGE_SIZE;
802 }
803
804 static size_t
805 core_send_echo_queued_ready (void *cls, size_t size, void *buf)
806 {
807         struct BenchmarkPeer *bp = cls;
808         struct PendingMessages *pm;
809         GNUNET_assert (NULL != bp->p_head);
810
811         pm = bp->p_head;
812         GNUNET_CONTAINER_DLL_remove (bp->p_head, bp->p_tail, pm);
813         GNUNET_free (pm);
814
815
816         return core_send_echo_ready (cls, size, buf);
817
818 }
819
820
821 static int
822 core_handle_ping (void *cls, const struct GNUNET_PeerIdentity *other,
823                 const struct GNUNET_MessageHeader *message)
824 {
825         struct BenchmarkPeer *me = cls;
826         struct BenchmarkPeer *remote;
827         struct PendingMessages *pm;
828
829         remote = find_peer (other);
830
831         if (NULL == remote)
832         {
833                 GNUNET_break (0);
834                 return GNUNET_SYSERR;
835         }
836
837         if (NULL != me->cth)
838         {
839                 pm = GNUNET_malloc (sizeof (struct PendingMessages));
840                 pm->target = (*other);
841                 GNUNET_CONTAINER_DLL_insert_tail (me->p_head, me->p_tail, pm);
842                 return GNUNET_OK;
843         }
844
845         if (GNUNET_NO == remote->master)
846         {
847                 GNUNET_break (0);
848                 return GNUNET_OK;
849         }
850
851         me->messages_received ++;
852         /* send echo */
853         me->cth = GNUNET_CORE_notify_transmit_ready (me->ch,
854                                 GNUNET_NO, 0, GNUNET_TIME_UNIT_MINUTES,
855                                 &remote->id,
856                                 TEST_MESSAGE_SIZE, &core_send_echo_ready, me);
857         return GNUNET_OK;
858 }
859
860 static int
861 core_handle_pong (void *cls, const struct GNUNET_PeerIdentity *other,
862                 const struct GNUNET_MessageHeader *message)
863 {
864         struct BenchmarkPeer *me = cls;
865         struct BenchmarkPeer *remote;
866         struct BenchmarkPeer *next;
867
868         remote = find_peer (other);
869
870         if (NULL == remote)
871         {
872                 GNUNET_break (0);
873                 return GNUNET_SYSERR;
874         }
875
876         if (NULL != me->cth)
877         {
878                 GNUNET_break (0);
879                 return GNUNET_OK;
880         }
881
882         if (GNUNET_YES == remote->master)
883         {
884                 GNUNET_break (0);
885                 return GNUNET_OK;
886         }
887         me->messages_received ++;
888         next = get_next (me);
889         if (0 == memcmp(&remote->id, &me->destination->id, sizeof (struct GNUNET_PeerIdentity)))
890                         me->partner_msg = GNUNET_YES;
891         me->cth = GNUNET_CORE_notify_transmit_ready (me->ch,
892                                 GNUNET_NO, 0, GNUNET_TIME_UNIT_MINUTES,
893                                 &next->id,
894                                 TEST_MESSAGE_SIZE, &core_send_ready, me);
895
896         return GNUNET_OK;
897 }
898
899
900 /**
901  * Called to open a connection to the peer's ATS performance
902  *
903  * @param cls peer context
904  * @param cfg configuration of the peer to connect to; will be available until
905  *          GNUNET_TESTBED_operation_done() is called on the operation returned
906  *          from GNUNET_TESTBED_service_connect()
907  * @return service handle to return in 'op_result', NULL on error
908  */
909 static void *
910 core_connect_adapter (void *cls,
911                       const struct GNUNET_CONFIGURATION_Handle *cfg)
912 {
913   struct BenchmarkPeer *peer = cls;
914
915   static const struct GNUNET_CORE_MessageHandler handlers[] = {
916       {&core_handle_ping, TEST_MESSAGE_TYPE_PING, 0},
917       {&core_handle_pong, TEST_MESSAGE_TYPE_PONG, 0},
918       {NULL, 0, 0}
919   };
920
921   peer->ch = GNUNET_CORE_connect(cfg, peer, NULL,
922                                  core_connect_cb, core_disconnect_cb,
923                                  NULL, GNUNET_NO, NULL, GNUNET_NO, handlers);
924   if (NULL == peer->ch)
925     GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
926                 "Failed to create core connection \n");
927   return peer->ch;
928 }
929
930
931 /**
932  * Callback to be called when a service connect operation is completed
933  *
934  * @param cls the callback closure from functions generating an operation
935  * @param op the operation that has been finished
936  * @param ca_result the service handle returned from GNUNET_TESTBED_ConnectAdapter()
937  * @param emsg error message in case the operation has failed; will be NULL if
938  *          operation has executed successfully.
939  */
940 static void
941 core_connect_completion_cb (void *cls,
942                             struct GNUNET_TESTBED_Operation *op,
943                             void *ca_result,
944                             const char *emsg )
945 {
946         static int core_done = 0;
947         if ((NULL != emsg) || (NULL == ca_result))
948         {
949                 GNUNET_log (GNUNET_ERROR_TYPE_INFO,
950                                 _("Initialization failed, shutdown\n"));
951                 GNUNET_break (0);
952                 if (GNUNET_SCHEDULER_NO_TASK != shutdown_task)
953                         GNUNET_SCHEDULER_cancel(shutdown_task);
954                 shutdown_task = GNUNET_SCHEDULER_add_now (do_shutdown, NULL);
955                 return;
956         }
957         core_done ++;
958
959         if (core_done == c_slave_peers + c_master_peers)
960         {
961                 GNUNET_log (GNUNET_ERROR_TYPE_INFO,
962                                 "Connected to all CORE services\n");
963                 state.connected_CORE_service = GNUNET_YES;
964                 GNUNET_SCHEDULER_add_now (&do_connect_peers, NULL);
965         }
966 }
967
968
969 /**
970  * Called to disconnect from peer's statistics service
971  *
972  * @param cls peer context
973  * @param op_result service handle returned from the connect adapter
974  */
975 static void
976 core_disconnect_adapter (void *cls, void *op_result)
977 {
978   struct BenchmarkPeer *peer = cls;
979
980   GNUNET_CORE_disconnect (peer->ch);
981   peer->ch = NULL;
982 }
983
984 static void
985 do_connect_core (void *cls, const struct GNUNET_SCHEDULER_TaskContext *tc)
986 {
987         int c_p;
988         GNUNET_log (GNUNET_ERROR_TYPE_INFO,
989                         "Connecting to all CORE services\n");
990   for (c_p = 0; c_p < c_master_peers; c_p++)
991   {
992     bp_master[c_p].core_op = GNUNET_TESTBED_service_connect (NULL,
993                                                         bp_master[c_p].peer, "core",
994                                                       core_connect_completion_cb, NULL,
995                                                       &core_connect_adapter,
996                                                       &core_disconnect_adapter,
997                                                       &bp_master[c_p]);
998
999   }
1000
1001   for (c_p = 0; c_p < c_slave_peers; c_p++)
1002   {
1003     bp_slaves[c_p].core_op = GNUNET_TESTBED_service_connect (NULL,
1004                                                 bp_slaves[c_p].peer, "core",
1005                                               core_connect_completion_cb, NULL,
1006                                               &core_connect_adapter,
1007                                               &core_disconnect_adapter,
1008                                               &bp_slaves[c_p]);
1009   }
1010 }
1011
1012
1013
1014 /**
1015  * Called to open a connection to the peer's ATS performance
1016  *
1017  * @param cls peer context
1018  * @param cfg configuration of the peer to connect to; will be available until
1019  *          GNUNET_TESTBED_operation_done() is called on the operation returned
1020  *          from GNUNET_TESTBED_service_connect()
1021  * @return service handle to return in 'op_result', NULL on error
1022  */
1023 static void *
1024 ats_perf_connect_adapter (void *cls,
1025                       const struct GNUNET_CONFIGURATION_Handle *cfg)
1026 {
1027   struct BenchmarkPeer *peer = cls;
1028
1029   peer->p_handle = GNUNET_ATS_performance_init (cfg, &ats_performance_info_cb, peer);
1030   if (NULL == peer->p_handle)
1031     GNUNET_log (GNUNET_ERROR_TYPE_ERROR, "Failed to create ATS performance handle \n");
1032   return peer->p_handle;
1033 }
1034
1035
1036 /**
1037  * Called to disconnect from peer's statistics service
1038  *
1039  * @param cls peer context
1040  * @param op_result service handle returned from the connect adapter
1041  */
1042 static void
1043 ats_perf_disconnect_adapter (void *cls, void *op_result)
1044 {
1045   struct BenchmarkPeer *peer = cls;
1046
1047   GNUNET_ATS_performance_done(peer->p_handle);
1048   peer->p_handle = NULL;
1049 }
1050
1051
1052 /**
1053  * Callback to be called when a service connect operation is completed
1054  *
1055  * @param cls the callback closure from functions generating an operation
1056  * @param op the operation that has been finished
1057  * @param ca_result the service handle returned from GNUNET_TESTBED_ConnectAdapter()
1058  * @param emsg error message in case the operation has failed; will be NULL if
1059  *          operation has executed successfully.
1060  */
1061 static void
1062 ats_connect_completion_cb (void *cls,
1063                            struct GNUNET_TESTBED_Operation *op,
1064                            void *ca_result,
1065                            const char *emsg )
1066 {
1067         static int op_done = 0;
1068         if ((NULL != emsg) || (NULL == ca_result))
1069         {
1070                 GNUNET_log (GNUNET_ERROR_TYPE_INFO,
1071                                 _("Initialization failed, shutdown\n"));
1072                 GNUNET_break (0);
1073                 if (GNUNET_SCHEDULER_NO_TASK != shutdown_task)
1074                         GNUNET_SCHEDULER_cancel(shutdown_task);
1075                 shutdown_task = GNUNET_SCHEDULER_add_now (do_shutdown, NULL);
1076                 return;
1077         }
1078
1079         op_done ++;
1080         if (op_done == (c_slave_peers + c_master_peers))
1081         {
1082                 GNUNET_log (GNUNET_ERROR_TYPE_INFO,
1083                                 "Connected to all ATS services\n");
1084                 state.connected_ATS_service = GNUNET_YES;
1085                 GNUNET_SCHEDULER_add_now (&do_connect_core, NULL);
1086         }
1087 }
1088
1089 static void
1090 do_connect_ats (void *cls, const struct GNUNET_SCHEDULER_TaskContext *tc)
1091 {
1092         int c_p;
1093         GNUNET_log (GNUNET_ERROR_TYPE_INFO,
1094                         "Connecting to all ATS services %u\n", c_slave_peers);
1095   for (c_p = 0; c_p < c_master_peers; c_p++)
1096   {
1097     bp_master[c_p].ats_perf_op = GNUNET_TESTBED_service_connect (NULL,
1098                                                 bp_master[c_p].peer, "ats",
1099                                                           ats_connect_completion_cb, NULL,
1100                                                           &ats_perf_connect_adapter,
1101                                                           &ats_perf_disconnect_adapter,
1102                                                           &bp_master[c_p]);
1103
1104   }
1105
1106   for (c_p = 0; c_p < c_slave_peers; c_p++)
1107   {
1108     bp_slaves[c_p].ats_perf_op = GNUNET_TESTBED_service_connect (NULL,
1109                                                 bp_slaves[c_p].peer, "ats",
1110                                                           ats_connect_completion_cb, NULL,
1111                                                           &ats_perf_connect_adapter,
1112                                                           &ats_perf_disconnect_adapter,
1113                                                           &bp_slaves[c_p]);
1114   }
1115
1116 }
1117
1118
1119 /**
1120  * Callback to be called when the requested peer information is available
1121  *
1122  * @param cb_cls the closure from GNUNET_TETSBED_peer_get_information()
1123  * @param op the operation this callback corresponds to
1124  * @param pinfo the result; will be NULL if the operation has failed
1125  * @param emsg error message if the operation has failed; will be NULL if the
1126  *          operation is successfull
1127  */
1128 static void
1129 peerinformation_cb (void *cb_cls,
1130                     struct GNUNET_TESTBED_Operation *op,
1131                     const struct GNUNET_TESTBED_PeerInformation*pinfo,
1132                     const char *emsg)
1133 {
1134   struct BenchmarkPeer *p = cb_cls;
1135         static int done = 0;
1136
1137   if (pinfo->pit == GNUNET_TESTBED_PIT_IDENTITY)
1138   {
1139     p->id = *pinfo->result.id;
1140     GNUNET_log (GNUNET_ERROR_TYPE_INFO,
1141                 "[%c %03u] Peers %s\n",
1142                 (p->master == GNUNET_YES) ? 'M' : 'S', p->no, GNUNET_i2s (&p->id));
1143   }
1144   else
1145   {
1146     GNUNET_assert (0);
1147   }
1148   GNUNET_TESTBED_operation_done (op);
1149   p->info_op = NULL;
1150   done++;
1151
1152   if (done == c_master_peers + c_slave_peers)
1153   {
1154                 GNUNET_log (GNUNET_ERROR_TYPE_INFO,
1155                                 "Retrieved all peer ID, connect to ATS\n");
1156                 state.connected_CORE_service = GNUNET_YES;
1157                 GNUNET_SCHEDULER_add_now (&do_connect_ats, NULL);
1158   }
1159 }
1160
1161
1162 /**
1163  * Signature of a main function for a testcase.
1164  *
1165  * @param cls closure
1166  * @param num_peers number of peers in 'peers'
1167  * @param peers_ handle to peers run in the testbed
1168  * @param links_succeeded the number of overlay link connection attempts that
1169  *          succeeded
1170  * @param links_failed the number of overlay link connection attempts that
1171  *          failed
1172  */
1173 static void
1174 test_main (void *cls,
1175            struct GNUNET_TESTBED_RunHandle *h,
1176            unsigned int num_peers,
1177            struct GNUNET_TESTBED_Peer **peers_,
1178            unsigned int links_succeeded,
1179            unsigned int links_failed)
1180 {
1181   int c_p;
1182
1183   GNUNET_log (GNUNET_ERROR_TYPE_INFO,
1184               _("Benchmarking solver `%s' on preference `%s' with %u master and %u slave peers\n"),
1185               solver, pref_str, c_master_peers, c_slave_peers);
1186
1187   shutdown_task = GNUNET_SCHEDULER_add_delayed (GNUNET_TIME_relative_multiply(TEST_TIMEOUT, c_master_peers + c_slave_peers), &do_shutdown, NULL);
1188
1189   GNUNET_assert (NULL == cls);
1190   GNUNET_assert (c_slave_peers + c_master_peers == num_peers);
1191   GNUNET_assert (NULL != peers_);
1192
1193   GNUNET_log (GNUNET_ERROR_TYPE_INFO,
1194               _("Initializing... \n"));
1195
1196   for (c_p = 0; c_p < c_master_peers; c_p++)
1197   {
1198     GNUNET_assert (NULL != peers_[c_p]);
1199     bp_master[c_p].no = c_p;
1200     bp_master[c_p].send_mask = (1 << c_slave_peers) - 1;
1201     bp_master[c_p].master = GNUNET_YES;
1202     bp_master[c_p].peer = peers_[c_p];
1203     bp_master[c_p].info_op = GNUNET_TESTBED_peer_get_information (bp_master[c_p].peer,
1204                                                            GNUNET_TESTBED_PIT_IDENTITY,
1205                                                            &peerinformation_cb, &bp_master[c_p]);
1206
1207     /* Select ATS measurement partner */
1208     bp_master[c_p].destination = &bp_slaves[c_p];
1209   }
1210
1211   for (c_p = 0; c_p < c_slave_peers; c_p++)
1212   {
1213     GNUNET_assert (NULL != peers_[c_p + c_master_peers]);
1214     bp_slaves[c_p].no = c_p + c_master_peers;
1215     bp_slaves[c_p].master = GNUNET_NO;
1216     bp_slaves[c_p].peer = peers_[c_p + c_master_peers];
1217     bp_slaves[c_p].info_op = GNUNET_TESTBED_peer_get_information (bp_slaves[c_p].peer,
1218                                                            GNUNET_TESTBED_PIT_IDENTITY, 
1219                                                            &peerinformation_cb, &bp_slaves[c_p]);
1220   }
1221
1222 }
1223
1224
1225 int
1226 main (int argc, char *argv[])
1227 {
1228   char *tmp;
1229   char *tmp_sep;
1230   char *test_name;
1231   char *conf_name;
1232   char *dotexe;
1233   char *prefs[GNUNET_ATS_PreferenceCount] = GNUNET_ATS_PreferenceTypeString;
1234   int c;
1235
1236   result = 0;
1237
1238   /* figure out testname */
1239   tmp = strstr (argv[0], TESTNAME_PREFIX);
1240   if (NULL == tmp)
1241   {
1242         fprintf (stderr, "Unable to parse test name `%s'\n", argv[0]);
1243         return GNUNET_SYSERR;
1244   }
1245   tmp += strlen(TESTNAME_PREFIX);
1246   solver = GNUNET_strdup (tmp);
1247   if (NULL != (dotexe = strstr (solver, ".exe")) &&
1248       dotexe[4] == '\0')
1249     dotexe[0] = '\0';
1250   tmp_sep = strchr (solver, '_');
1251   if (NULL == tmp_sep)
1252   {
1253         fprintf (stderr, "Unable to parse test name `%s'\n", argv[0]);
1254         GNUNET_free (solver);
1255         return GNUNET_SYSERR;
1256   }
1257   tmp_sep[0] = '\0';
1258   pref_str = GNUNET_strdup(tmp_sep + 1);
1259
1260   GNUNET_asprintf(&conf_name, "%s%s_%s.conf", TESTNAME_PREFIX, solver, pref_str);
1261   GNUNET_asprintf(&test_name, "%s%s_%s", TESTNAME_PREFIX, solver, pref_str);
1262
1263   for (c = 0; c <= strlen (pref_str); c++)
1264   {
1265         pref_str[c] = toupper(pref_str[c]);
1266   }
1267   pref_val = -1;
1268         for (c = 1; c < GNUNET_ATS_PreferenceCount; c++)
1269         {
1270                 if (0 == strcmp (pref_str, prefs[c]))
1271                 {
1272                         pref_val = c;
1273                         break;
1274                 }
1275         }
1276         if (-1 == pref_val)
1277         {
1278                 fprintf (stderr, "Unknown preference: `%s'\n", pref_str);
1279           GNUNET_free (solver);
1280           GNUNET_free (pref_str);
1281           return -1;
1282         }
1283
1284   for (c = 0; c < (argc -1); c++)
1285   {
1286         if (0 == strcmp(argv[c], "-s"))
1287                 break;
1288   }
1289   if (c < argc-1)
1290   {
1291     if ((0L != (c_slave_peers = strtol (argv[c + 1], NULL, 10))) && (c_slave_peers >= 1))
1292       fprintf (stderr, "Starting %u slave peers\n", c_slave_peers);
1293     else
1294         c_slave_peers = DEFAULT_SLAVES_NUM;
1295   }
1296   else
1297         c_slave_peers = DEFAULT_SLAVES_NUM;
1298
1299   for (c = 0; c < (argc -1); c++)
1300   {
1301         if (0 == strcmp(argv[c], "-m"))
1302                 break;
1303   }
1304   if (c < argc-1)
1305   {
1306     if ((0L != (c_master_peers = strtol (argv[c + 1], NULL, 10))) && (c_master_peers >= 2))
1307       fprintf (stderr, "Starting %u master peers\n", c_master_peers);
1308     else
1309         c_master_peers = DEFAULT_MASTERS_NUM;
1310   }
1311   else
1312         c_master_peers = DEFAULT_MASTERS_NUM;
1313
1314   bp_slaves = GNUNET_malloc (c_slave_peers * sizeof (struct BenchmarkPeer));
1315   bp_master = GNUNET_malloc (c_master_peers * sizeof (struct BenchmarkPeer));
1316
1317   state.connected_ATS_service = GNUNET_NO;
1318   state.connected_CORE_service = GNUNET_NO;
1319   state.connected_PEERS = GNUNET_NO;
1320
1321   /* Start topology */
1322   uint64_t event_mask;
1323   event_mask = 0;
1324   event_mask |= (1LL << GNUNET_TESTBED_ET_CONNECT);
1325   event_mask |= (1LL << GNUNET_TESTBED_ET_OPERATION_FINISHED);
1326   (void) GNUNET_TESTBED_test_run ("perf_ats",
1327                                   conf_name, c_slave_peers + c_master_peers,
1328                                   event_mask, &controller_event_cb, NULL,
1329                                   &test_main, NULL);
1330
1331   GNUNET_free (solver);
1332   GNUNET_free (pref_str);
1333   GNUNET_free (conf_name);
1334   GNUNET_free (test_name);
1335   GNUNET_free (bp_slaves);
1336
1337   return result;
1338 }
1339
1340 /* end of file perf_ats.c */