stage 3
[oweals/gnunet.git] / src / ats / test_ats_api_performance.c
1 /*
2      This file is part of GNUnet.
3      (C) 2010,2011 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/test_ats_api_performance.c
22  * @brief test adding addresses in automatic transport selection performance API
23  * @author Christian Grothoff
24  * @author Matthias Wachs
25  */
26 #include "platform.h"
27 #include "gnunet_ats_service.h"
28 #include "gnunet_testing_lib-new.h"
29 #include "ats.h"
30
31 #define TIMEOUT GNUNET_TIME_relative_multiply (GNUNET_TIME_UNIT_SECONDS, 10)
32
33 static GNUNET_SCHEDULER_TaskIdentifier die_task;
34
35 struct GNUNET_CONFIGURATION_Handle *cfg;
36
37 static struct GNUNET_ATS_SchedulingHandle *atsh;
38 static struct GNUNET_ATS_PerformanceHandle *ph;
39 struct GNUNET_ATS_AddressListHandle* phal;
40
41 static int ret;
42
43 struct Address
44 {
45   char *plugin;
46   size_t plugin_len;
47
48   void *addr;
49   size_t addr_len;
50
51   struct GNUNET_ATS_Information *ats;
52   int ats_count;
53
54   void *session;
55 };
56
57 struct PeerContext
58 {
59   struct GNUNET_PeerIdentity id;
60
61   struct Address *addr;
62 };
63
64
65
66 static struct PeerContext p[2];
67
68 static struct Address p0_addresses[2];
69 static struct Address p1_addresses[2];
70
71 struct GNUNET_HELLO_Address p0_ha[2];
72 struct GNUNET_HELLO_Address p1_ha[2];
73 struct GNUNET_HELLO_Address *s_ha[2];
74
75 static unsigned int stage = 0;
76
77 static void
78 end_badly (void *cls, const struct GNUNET_SCHEDULER_TaskContext *tc)
79 {
80   die_task = GNUNET_SCHEDULER_NO_TASK;
81
82   GNUNET_log (GNUNET_ERROR_TYPE_ERROR, "Timeout in stage %u\n", stage);
83
84   if (NULL != atsh)
85   GNUNET_ATS_scheduling_done (atsh);
86   if (phal != NULL)
87     GNUNET_ATS_performance_list_addresses_cancel (phal);
88   phal = NULL;
89   if (ph != NULL)
90     GNUNET_ATS_performance_done (ph);
91   ph = NULL;
92
93   GNUNET_free_non_null (p0_addresses[0].addr);
94   GNUNET_free_non_null (p0_addresses[1].addr);
95   GNUNET_free_non_null (p1_addresses[0].addr);
96   GNUNET_free_non_null (p1_addresses[1].addr);
97
98   ret = GNUNET_SYSERR;
99 }
100
101
102 static void
103 end ()
104 {
105   GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "Shutting down\n");
106   if (die_task != GNUNET_SCHEDULER_NO_TASK)
107   {
108     GNUNET_SCHEDULER_cancel (die_task);
109     die_task = GNUNET_SCHEDULER_NO_TASK;
110   }
111   if (NULL != atsh)
112   GNUNET_ATS_scheduling_done (atsh);
113   if (phal != NULL)
114     GNUNET_ATS_performance_list_addresses_cancel (phal);
115   phal = NULL;
116   if (ph != NULL)
117     GNUNET_ATS_performance_done (ph);
118   ph = NULL;
119
120   GNUNET_free_non_null (p0_addresses[0].addr);
121   GNUNET_free_non_null (p0_addresses[1].addr);
122   GNUNET_free_non_null (p1_addresses[0].addr);
123   GNUNET_free_non_null (p1_addresses[1].addr);
124
125   ret = 0;
126 }
127
128 static void
129 test_performance_api (void *cls, const struct GNUNET_SCHEDULER_TaskContext *tc);
130
131 void all_active_addresses_peer_cb (void *cls,
132                       const struct
133                       GNUNET_HELLO_Address *
134                       address,
135                       struct
136                       GNUNET_BANDWIDTH_Value32NBO
137                       bandwidth_out,
138                       struct
139                       GNUNET_BANDWIDTH_Value32NBO
140                       bandwidth_in,
141                       const struct
142                       GNUNET_ATS_Information *
143                       ats, uint32_t ats_count)
144 {
145
146 }
147
148 void all_active_addresses_cb (void *cls,
149                       const struct
150                       GNUNET_HELLO_Address *
151                       address,
152                       struct
153                       GNUNET_BANDWIDTH_Value32NBO
154                       bandwidth_out,
155                       struct
156                       GNUNET_BANDWIDTH_Value32NBO
157                       bandwidth_in,
158                       const struct
159                       GNUNET_ATS_Information *
160                       ats, uint32_t ats_count)
161 {
162   static int cb = 0;
163   int fail = GNUNET_NO;
164
165   if (address != NULL)
166   {
167     if (0 == memcmp (&address->peer, &p[0].id,
168                      sizeof (struct GNUNET_PeerIdentity)))
169     {
170         if (0 == strcmp(address->address, s_ha[0]->address))
171         {
172           GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "Callback for peer 0 suggested address %s\n", s_ha[0]->address);
173           cb ++;
174         }
175         else
176         {
177           GNUNET_log (GNUNET_ERROR_TYPE_ERROR, "Expected callback for peer 0 address `%s', got address `%s'!\n", s_ha[0]->address, address->address);
178           GNUNET_ATS_performance_list_addresses_cancel (phal);
179           fail = GNUNET_YES;
180         }
181     }
182
183     if (0 == memcmp (&address->peer, &p[1].id,
184                      sizeof (struct GNUNET_PeerIdentity)))
185     {
186         if (0 == strcmp(address->address, s_ha[1]->address))
187         {
188           GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "Callback for peer 1 suggested address %s\n", s_ha[1]->address);
189           cb ++;
190         }
191         else
192         {
193           GNUNET_log (GNUNET_ERROR_TYPE_ERROR, "Expected callback for peer 1 address `%s', got address `%s'!\n", s_ha[1]->address, address->address);
194           GNUNET_ATS_performance_list_addresses_cancel (phal);
195           fail = GNUNET_YES;
196         }
197     }
198   }
199   if ((address == NULL) || (GNUNET_YES == fail))
200   {
201       phal = NULL;
202       if ((2 == cb) && (GNUNET_NO == fail))
203       {
204         /* Received all addresses + terminator cb, next stage */
205         GNUNET_log (GNUNET_ERROR_TYPE_INFO, "Stage %i:  SUCCESS\n", stage);
206         GNUNET_SCHEDULER_add_now (&test_performance_api, NULL);
207         return;
208       }
209       else
210       {
211         GNUNET_log (GNUNET_ERROR_TYPE_ERROR, "Stage %i:  FAIL\n", stage);
212         GNUNET_SCHEDULER_add_now (&end, NULL);
213         ret = 5;
214         return;
215       }
216   }
217 }
218
219
220
221 void all_addresses_peer_cb (void *cls,
222                       const struct
223                       GNUNET_HELLO_Address *
224                       address,
225                       struct
226                       GNUNET_BANDWIDTH_Value32NBO
227                       bandwidth_out,
228                       struct
229                       GNUNET_BANDWIDTH_Value32NBO
230                       bandwidth_in,
231                       const struct
232                       GNUNET_ATS_Information *
233                       ats, uint32_t ats_count)
234 {
235   static int cb = 0;
236   int fail = GNUNET_NO;
237
238   if (address != NULL)
239   {
240       GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "Callback for peer `%s'  address `%s'\n",
241            GNUNET_i2s (&address->peer), address->address);
242
243     if (0 != memcmp (&address->peer, &p[1].id,
244                      sizeof (struct GNUNET_PeerIdentity)))
245     {
246         GNUNET_log (GNUNET_ERROR_TYPE_ERROR, "Stage %i:  Received address for wrong peer\n", stage);
247         GNUNET_ATS_performance_list_addresses_cancel (phal);
248         fail = GNUNET_YES;
249         ret = 4;
250     }
251     cb ++;
252   }
253
254   if ((NULL == address) || (fail))
255   {
256       phal = NULL;
257       if ((2 == cb) && (GNUNET_NO == fail))
258       {
259         /* Received all addresses + terminator cb, next stage */
260         GNUNET_log (GNUNET_ERROR_TYPE_INFO, "Stage %i:  SUCCESS\n", stage);
261         GNUNET_SCHEDULER_add_now (&test_performance_api, NULL);
262         return;
263       }
264       else
265       {
266         GNUNET_log (GNUNET_ERROR_TYPE_ERROR, "Stage %i:  FAIL\n", stage);
267         GNUNET_SCHEDULER_add_now (&end, NULL);
268         ret = 5;
269         return;
270       }
271   }
272 }
273
274 void all_addresses_cb (void *cls,
275                               const struct
276                               GNUNET_HELLO_Address *
277                               address,
278                               struct
279                               GNUNET_BANDWIDTH_Value32NBO
280                               bandwidth_out,
281                               struct
282                               GNUNET_BANDWIDTH_Value32NBO
283                               bandwidth_in,
284                               const struct
285                               GNUNET_ATS_Information *
286                               ats, uint32_t ats_count)
287 {
288   static int cb = 0;
289
290   if (address != NULL)
291   {
292       GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "Callback for peer `%s'  address `%s'\n",
293            GNUNET_i2s (&address->peer), address->address);
294
295     if (0 == memcmp (&address->peer, &p[0].id,
296                      sizeof (struct GNUNET_PeerIdentity)))
297     {
298       GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "Callback for peer 0 `%s'\n", GNUNET_i2s (&address->peer));
299       if (0 == strcmp(address->address, p0_addresses[0].addr))
300       {
301         GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "Callback for peer 0 address 0\n");
302         cb |= 1;
303       }
304       if (0 == strcmp(address->address, p0_addresses[1].addr))
305       {
306         GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "Callback for peer 0 address 1\n");
307         cb |= 2;
308       }
309     }
310     if (0 == memcmp (&address->peer, &p[1].id,
311                      sizeof (struct GNUNET_PeerIdentity)));
312     {
313         GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "Callback for peer 1 `%s'\n", GNUNET_i2s (&address->peer));
314         if (0 == strcmp(address->address, p1_addresses[0].addr))
315         {
316           GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "Callback for peer 1 address 0\n");
317           cb |= 4;
318         }
319         if (0 == strcmp(address->address, p1_addresses[1].addr))
320         {
321           GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "Callback for peer 1 address 1\n");
322           cb |= 8;
323         }
324     }
325   }
326   else
327   {
328       phal = NULL;
329       if (((1 << 4) - 1) == cb)
330       {
331         /* Received all addresses + terminator cb, next stage */
332         GNUNET_log (GNUNET_ERROR_TYPE_INFO, "Stage %i:  SUCCESS\n", stage);
333         GNUNET_SCHEDULER_add_now (&test_performance_api, NULL);
334         return;
335       }
336       else
337       {
338         GNUNET_log (GNUNET_ERROR_TYPE_ERROR, "Stage %i:  FAIL\n", stage);
339         GNUNET_SCHEDULER_add_now (&end, NULL);
340         ret = 3;
341         return;
342       }
343   }
344 }
345
346 static void
347 test_performance_api (void *cls, const struct GNUNET_SCHEDULER_TaskContext *tc)
348 {
349   if (NULL == ph)
350     ph = GNUNET_ATS_performance_init (cfg, NULL, NULL);
351   if (NULL == ph)
352   {
353       GNUNET_log (GNUNET_ERROR_TYPE_ERROR, "Failed to initialize performance handle\n");
354       ret = 2;
355   }
356   stage++;
357   switch (stage) {
358     case 1: /* Get all peers, all addresses */
359       GNUNET_log (GNUNET_ERROR_TYPE_INFO, "Run stage 1: \n");
360       phal = GNUNET_ATS_performance_list_addresses (ph,
361                                              NULL,
362                                              GNUNET_YES,
363                                              &all_addresses_cb, NULL);
364       GNUNET_assert (NULL != phal);
365       break;
366     case 2: /* Get specific peer, all addresses */
367       GNUNET_log (GNUNET_ERROR_TYPE_INFO, "Run stage 2: \n");
368       phal = GNUNET_ATS_performance_list_addresses (ph,
369                                              &p[1].id,
370                                              GNUNET_YES,
371                                              &all_addresses_peer_cb, NULL);
372       GNUNET_assert (NULL != phal);
373       break;
374     case 3: /* Get all peers, active addresses */
375       GNUNET_log (GNUNET_ERROR_TYPE_INFO, "Run stage 3: \n");
376       phal = GNUNET_ATS_performance_list_addresses (ph,
377                                              NULL,
378                                              GNUNET_NO,
379                                              &all_active_addresses_cb, NULL);
380       GNUNET_assert (NULL != phal);
381       break;
382     default:
383       /* done */
384       GNUNET_log (GNUNET_ERROR_TYPE_INFO, "All tests successful, shutdown... \n");
385       GNUNET_SCHEDULER_add_now (&end, NULL);
386       return;
387   }
388 }
389
390
391 static void
392 address_suggest_cb (void *cls, const struct GNUNET_HELLO_Address *address,
393                     struct Session *session,
394                     struct GNUNET_BANDWIDTH_Value32NBO bandwidth_out,
395                     struct GNUNET_BANDWIDTH_Value32NBO bandwidth_in,
396                     const struct GNUNET_ATS_Information *ats,
397                     uint32_t ats_count)
398 {
399   static int suggest_p0 = GNUNET_NO;
400   static int suggest_p1 = GNUNET_NO;
401   static int running = GNUNET_NO;
402
403   if (0 == memcmp (&address->peer, &p[0].id,
404                    sizeof (struct GNUNET_PeerIdentity)))
405   {
406     suggest_p0 = GNUNET_YES;;
407
408     if (s_ha[0] != NULL)
409       GNUNET_free (s_ha[0]);
410     s_ha[0] = GNUNET_HELLO_address_copy (address);
411
412     GNUNET_ATS_suggest_address_cancel (atsh, &p[0].id);
413   }
414   if (0 == memcmp (&address->peer, &p[1].id,
415                    sizeof (struct GNUNET_PeerIdentity)))
416   {
417     suggest_p1 = GNUNET_YES;
418
419     if (s_ha[1] != NULL)
420       GNUNET_free (s_ha[1]);
421     s_ha[1] = GNUNET_HELLO_address_copy (address);
422
423     GNUNET_ATS_suggest_address_cancel (atsh, &p[1].id);
424   }
425
426
427   if ((GNUNET_NO == running) && (GNUNET_YES == suggest_p0) && (GNUNET_YES == suggest_p1))
428   {
429       running = GNUNET_YES;
430       GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "Have address suggestion for both peers\n");
431       GNUNET_SCHEDULER_add_now (&test_performance_api, NULL);
432   }
433
434 }
435
436
437 static void
438 run (void *cls, 
439      const struct GNUNET_CONFIGURATION_Handle *mycfg,
440      struct GNUNET_TESTING_Peer *peer)
441 {
442   ret = 1;
443   cfg = (struct GNUNET_CONFIGURATION_Handle *) mycfg;
444   die_task = GNUNET_SCHEDULER_add_delayed (TIMEOUT, &end_badly, NULL);
445
446
447   /* set up peer 0 */
448   GNUNET_CRYPTO_hash_create_random (GNUNET_CRYPTO_QUALITY_WEAK,
449                                     &p[0].id.hashPubKey);
450
451   p0_addresses[0].plugin = "test";
452   p0_addresses[0].session = NULL;
453   p0_addresses[0].addr = GNUNET_strdup ("test_p0_a0");
454   p0_addresses[0].addr_len = strlen (p0_addresses[0].addr) + 1;
455
456   p0_ha[0].address = p0_addresses[0].addr;
457   p0_ha[0].address_length = p0_addresses[0].addr_len;
458   p0_ha[0].peer = p[0].id;
459   p0_ha[0].transport_name = p0_addresses[0].plugin;
460
461   p0_addresses[1].plugin = "test";
462   p0_addresses[1].session = NULL;
463   p0_addresses[1].addr = GNUNET_strdup ("test_p0_a1");
464   p0_addresses[1].addr_len = strlen(p0_addresses[1].addr) + 1;
465
466   p0_ha[1].address = p0_addresses[1].addr;
467   p0_ha[1].address_length = p0_addresses[1].addr_len;
468   p0_ha[1].peer = p[0].id;
469   p0_ha[1].transport_name = p0_addresses[1].plugin;
470
471   GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "Created peer 0: `%s'\n",
472               GNUNET_i2s (&p[0].id));
473
474   GNUNET_CRYPTO_hash_create_random (GNUNET_CRYPTO_QUALITY_WEAK,
475                                     &p[1].id.hashPubKey);
476
477   p1_addresses[0].plugin = "test";
478   p1_addresses[0].session = NULL;
479   p1_addresses[0].addr = GNUNET_strdup ("test_p1_a0");
480   p1_addresses[0].addr_len = strlen(p1_addresses[0].addr) + 1;
481
482   p1_ha[0].address = p1_addresses[0].addr;
483   p1_ha[0].address_length = p1_addresses[0].addr_len;
484   p1_ha[0].peer = p[1].id;
485   p1_ha[0].transport_name = p1_addresses[0].plugin;
486
487   p1_addresses[1].plugin = "test";
488   p1_addresses[1].session = NULL;
489   p1_addresses[1].addr = GNUNET_strdup ("test_p1_a1");
490   p1_addresses[1].addr_len = strlen(p1_addresses[1].addr) + 1;
491
492   p1_ha[1].address = p1_addresses[1].addr;
493   p1_ha[1].address_length = p1_addresses[1].addr_len;
494   p1_ha[1].peer = p[1].id;
495   p1_ha[1].transport_name = p1_addresses[1].plugin;
496
497
498   GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "Created peer 1: `%s'\n",
499               GNUNET_i2s (&p[1].id));
500
501
502   /* Add addresses */
503   atsh = GNUNET_ATS_scheduling_init (cfg, &address_suggest_cb, NULL);
504   if (atsh == NULL)
505   {
506     ret = GNUNET_SYSERR;
507     end ();
508     return;
509   }
510
511   GNUNET_ATS_address_add (atsh, &p0_ha[0], NULL, NULL, 0);
512   GNUNET_ATS_address_add (atsh, &p0_ha[1], NULL, NULL, 0);
513
514   GNUNET_ATS_address_add (atsh, &p1_ha[0], NULL, NULL, 0);
515   GNUNET_ATS_address_add (atsh, &p1_ha[1], NULL, NULL, 0);
516
517
518   GNUNET_ATS_suggest_address (atsh, &p[0].id);
519   GNUNET_ATS_suggest_address (atsh, &p[1].id);
520 }
521
522
523 int
524 main (int argc, char *argv[])
525 {
526   if (0 != GNUNET_TESTING_peer_run ("test_ats_api_performance",
527                                     "test_ats_api.conf",
528                                     &run, NULL))
529     return 1;
530   return ret;
531 }
532
533 /* end of file test_ats_api_performance.c */