changing time measurement from milliseconds to microseconds
[oweals/gnunet.git] / src / ats / test_ats_api_scheduling_block_and_reset.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_scheduling_reset_backoff.c
22  * @brief test case for blocking suggests and blocking reset API
23  *        measure duration of initial suggest, measure blocking duration,
24  *        reset block, measure suggest, compare time
25  * @author Christian Grothoff
26  * @author Matthias Wachs
27  */
28 #include "platform.h"
29 #include "gnunet_ats_service.h"
30 #include "gnunet_testing_lib.h"
31 #include "ats.h"
32 #include "test_ats_api_common.h"
33
34 #define WAIT GNUNET_TIME_relative_multiply (GNUNET_TIME_UNIT_MILLISECONDS, 10)
35
36 static GNUNET_SCHEDULER_TaskIdentifier die_task;
37
38 static GNUNET_SCHEDULER_TaskIdentifier wait_task;
39
40 /**
41  * Scheduling handle
42  */
43 static struct GNUNET_ATS_SchedulingHandle *sched_ats;
44
45 /**
46  * Return value
47  */
48 static int ret;
49
50 /**
51  * Test address
52  */
53 static struct Test_Address test_addr;
54
55 /**
56  * Test peer
57  */
58 static struct PeerContext p;
59
60 /**
61  * HELLO address
62  */
63 struct GNUNET_HELLO_Address test_hello_address;
64
65 /**
66  * Session
67  */
68 static void *test_session;
69
70 /**
71  * Test ats info
72  */
73 struct GNUNET_ATS_Information test_ats_info[2];
74
75 /**
76  * Test ats count
77  */
78 uint32_t test_ats_count;
79
80
81 struct GNUNET_TIME_Absolute initial_start;
82
83 struct GNUNET_TIME_Relative initial_duration;
84
85 /**
86  * Blocking start
87  */
88 struct GNUNET_TIME_Absolute block_start;
89
90 struct GNUNET_TIME_Relative block_duration;
91
92 struct GNUNET_TIME_Absolute reset_block_start;
93
94 struct GNUNET_TIME_Relative reset_block_duration;
95
96 static void
97 end_badly (void *cls, const struct GNUNET_SCHEDULER_TaskContext *tc)
98 {
99   die_task = GNUNET_SCHEDULER_NO_TASK;
100   if (wait_task != GNUNET_SCHEDULER_NO_TASK)
101   {
102     GNUNET_SCHEDULER_cancel (wait_task);
103     wait_task = GNUNET_SCHEDULER_NO_TASK;
104   }
105   if (sched_ats != NULL)
106     GNUNET_ATS_scheduling_done (sched_ats);
107   free_test_address (&test_addr);
108   ret = GNUNET_SYSERR;
109 }
110
111
112 static void
113 end ()
114 {
115   GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "Shutting down\n");
116   if (die_task != GNUNET_SCHEDULER_NO_TASK)
117   {
118     GNUNET_SCHEDULER_cancel (die_task);
119     die_task = GNUNET_SCHEDULER_NO_TASK;
120   }
121   if (wait_task != GNUNET_SCHEDULER_NO_TASK)
122   {
123     GNUNET_SCHEDULER_cancel (wait_task);
124     wait_task = GNUNET_SCHEDULER_NO_TASK;
125   }
126   GNUNET_ATS_scheduling_done (sched_ats);
127   sched_ats = NULL;
128   free_test_address (&test_addr);
129 }
130
131 static void
132 request_task (void *cls, const struct GNUNET_SCHEDULER_TaskContext *tc)
133 {
134   wait_task = GNUNET_SCHEDULER_NO_TASK;
135   GNUNET_ATS_suggest_address (sched_ats, &p.id);
136   wait_task = GNUNET_SCHEDULER_add_delayed (WAIT, &request_task, NULL);
137 }
138
139 static void
140 address_suggest_cb (void *cls, const struct GNUNET_HELLO_Address *address,
141                     struct Session *session,
142                     struct GNUNET_BANDWIDTH_Value32NBO bandwidth_out,
143                     struct GNUNET_BANDWIDTH_Value32NBO bandwidth_in,
144                     const struct GNUNET_ATS_Information *atsi,
145                     uint32_t ats_count)
146 {
147   static int stage = 0;
148
149   GNUNET_log (GNUNET_ERROR_TYPE_INFO, "Stage %u\n", stage);
150   if (3 == stage)
151   {
152       /* Suggestion after resetting block interval */
153       reset_block_duration = GNUNET_TIME_absolute_get_difference (reset_block_start, 
154                                                                   GNUNET_TIME_absolute_get());
155       GNUNET_log (GNUNET_ERROR_TYPE_INFO,
156                   "Address suggestion after resetting blocking took about %s!\n",
157                   GNUNET_STRINGS_relative_time_to_string (reset_block_duration,
158                                                           GNUNET_YES));
159       if ((block_duration.rel_value_us <= (initial_duration.rel_value_us * 3)) ||
160           (initial_duration.rel_value_us <= (block_duration.rel_value_us * 3)))
161       {
162         GNUNET_log (GNUNET_ERROR_TYPE_INFO,
163                     "Address suggestion after resetting blocking took about the same as initial suggestion (%s)\n",
164                     GNUNET_STRINGS_relative_time_to_string (initial_duration,
165                                                             GNUNET_YES));
166         ret = 0;
167       }
168       else
169       {
170         GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
171                     "Address suggestion after resetting blocking has too big difference to initial suggestion (%s)\n",
172                     GNUNET_STRINGS_relative_time_to_string (initial_duration,
173                                                             GNUNET_YES));
174         ret = 1;
175         GNUNET_ATS_suggest_address_cancel (sched_ats, &p.id);
176         GNUNET_SCHEDULER_add_now (&end, NULL);
177         return;
178       }
179
180       if (((initial_duration.rel_value_us * 3) <= block_duration.rel_value_us) &&
181           ((reset_block_duration.rel_value_us * 3) <= block_duration.rel_value_us))
182       {
183         GNUNET_log (GNUNET_ERROR_TYPE_INFO, 
184                     "Address suggestion after resetting blocking and initial suggestion (%llu us) much faster than with blocking (%llu us)\n",
185                     (unsigned long long) initial_duration.rel_value_us,
186                     (unsigned long long) block_duration.rel_value_us);
187         ret = 0;
188       }
189       else
190       {
191         GNUNET_log (GNUNET_ERROR_TYPE_ERROR, 
192                     "Address suggestion after resetting blocking and initial suggestion (%llu us) not faster than with blocking (%llu us)\n",
193                     (unsigned long long) initial_duration.rel_value_us,
194                     (unsigned long long) block_duration.rel_value_us);
195         ret = 1;
196       }
197
198
199       GNUNET_ATS_suggest_address_cancel (sched_ats, &p.id);
200       GNUNET_SCHEDULER_add_now (&end, NULL);
201
202   }
203   if (2 == stage)
204   {
205       /* Suggestion after block*/
206       block_duration = GNUNET_TIME_absolute_get_difference(block_start, GNUNET_TIME_absolute_get());
207       GNUNET_log (GNUNET_ERROR_TYPE_INFO,
208                   "Address suggestion was blocked for about %s!\n",
209                   GNUNET_STRINGS_relative_time_to_string (block_duration,
210                                                           GNUNET_YES));
211
212       if (GNUNET_OK == compare_addresses (address, session, &test_hello_address, test_session))
213       {
214           GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, 
215                       "Stage %u: Callback with correct address `%s'\n", stage,
216                       GNUNET_i2s (&address->peer));
217           ret = 0;
218       }
219       else
220       {
221           GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
222                       "Stage %u: Callback with invalid address `%s'\n", stage,
223                       GNUNET_i2s (&address->peer));
224           GNUNET_ATS_suggest_address_cancel (sched_ats, &p.id);
225           GNUNET_SCHEDULER_add_now (&end, NULL);
226           ret = 1;
227       }
228
229       if (GNUNET_OK != compare_ats(atsi, ats_count, test_ats_info, test_ats_count))
230       {
231         GNUNET_log (GNUNET_ERROR_TYPE_ERROR, 
232                     "Stage %u: Callback with incorrect ats info \n");
233         GNUNET_ATS_suggest_address_cancel (sched_ats, &p.id);
234         GNUNET_SCHEDULER_add_now (&end, NULL);
235         ret = 1;
236       }
237       stage ++;
238
239       /* Reset block interval */
240       GNUNET_ATS_reset_backoff (sched_ats, &address->peer);
241       reset_block_start = GNUNET_TIME_absolute_get();
242       GNUNET_ATS_suggest_address (sched_ats, &p.id);
243   }
244   if (1 == stage)
245   {
246     /* Initial suggestion */
247     if (GNUNET_OK == compare_addresses (address, session, &test_hello_address, test_session))
248     {
249         GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, 
250                     "Stage %u: Callback with correct address `%s'\n", 
251                     stage,
252                     GNUNET_i2s (&address->peer));
253         ret = 0;
254     }
255     else
256     {
257         GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, 
258                     "Stage %u: Callback with invalid address `%s'\n", 
259                     stage,
260                     GNUNET_i2s (&address->peer));
261         GNUNET_ATS_suggest_address_cancel (sched_ats, &p.id);
262         GNUNET_SCHEDULER_add_now (&end, NULL);
263         ret = 1;
264     }
265
266     if (GNUNET_OK != compare_ats(atsi, ats_count, test_ats_info, test_ats_count))
267     {
268       GNUNET_log (GNUNET_ERROR_TYPE_ERROR, 
269                   "Stage %u: Callback with incorrect ats info\n",
270                   stage);
271       GNUNET_ATS_suggest_address_cancel (sched_ats, &p.id);
272       GNUNET_SCHEDULER_add_now (&end, NULL);
273       ret = 1;
274     }
275     stage++;
276     initial_duration = GNUNET_TIME_absolute_get_difference(initial_start, GNUNET_TIME_absolute_get());
277     GNUNET_log (GNUNET_ERROR_TYPE_INFO, 
278                 "Stage %u: Initial suggestion took about %s\n", 
279                 stage,
280                 GNUNET_STRINGS_relative_time_to_string (block_duration,
281                                                         GNUNET_YES));
282
283     block_start = GNUNET_TIME_absolute_get();
284     wait_task = GNUNET_SCHEDULER_add_delayed (WAIT, &request_task, NULL);
285   }
286   if (0 == stage)
287   {
288     /* Startup suggestion */
289     if (GNUNET_OK == compare_addresses (address, session, &test_hello_address, test_session))
290     {
291         GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, 
292                     "Stage %u: Callback with correct address `%s'\n", 
293                     stage,
294                     GNUNET_i2s (&address->peer));
295         ret = 0;
296     }
297     else
298     {
299         GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
300                     "Stage %u: Callback with invalid address `%s'\n", 
301                     stage,
302                     GNUNET_i2s (&address->peer));
303         GNUNET_ATS_suggest_address_cancel (sched_ats, &p.id);
304         GNUNET_SCHEDULER_add_now (&end, NULL);
305         ret = 1;
306     }
307
308     if (GNUNET_OK != compare_ats (atsi, ats_count, test_ats_info, test_ats_count))
309     {
310       GNUNET_log (GNUNET_ERROR_TYPE_ERROR, 
311                   "Stage %u: Callback with incorrect ats info\n",
312                   stage);
313       GNUNET_ATS_suggest_address_cancel (sched_ats, &p.id);
314       GNUNET_SCHEDULER_add_now (&end, NULL);
315       ret = 1;
316     }
317     stage ++;
318
319     GNUNET_ATS_suggest_address_cancel (sched_ats, &p.id);
320
321     initial_start = GNUNET_TIME_absolute_get();
322     GNUNET_ATS_suggest_address (sched_ats, &p.id);
323   }
324 }
325
326
327 static void
328 run (void *cls, 
329      const struct GNUNET_CONFIGURATION_Handle *cfg,
330      struct GNUNET_TESTING_Peer *peer)
331 {
332
333   die_task = GNUNET_SCHEDULER_add_delayed (TIMEOUT, &end_badly, NULL);
334
335   /* Connect to ATS scheduling */
336   sched_ats = GNUNET_ATS_scheduling_init (cfg, &address_suggest_cb, NULL);
337   if (sched_ats == NULL)
338   {
339     GNUNET_log (GNUNET_ERROR_TYPE_ERROR, 
340                 "Could not connect to ATS scheduling!\n");
341     ret = 1;
342     end ();
343     return;
344   }
345
346   /* Set up peer */
347   if (GNUNET_SYSERR == GNUNET_CRYPTO_hash_from_string(PEERID0, &p.id.hashPubKey))
348   {
349       GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
350                   "Could not setup peer!\n");
351       ret = GNUNET_SYSERR;
352       end ();
353       return;
354   }
355   GNUNET_assert (0 == strcmp (PEERID0, GNUNET_i2s_full (&p.id)));
356
357   GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
358               "Created peer `%s'\n",
359               GNUNET_i2s_full(&p.id));
360
361   /* Prepare ATS Information */
362   test_ats_info[0].type = htonl (GNUNET_ATS_NETWORK_TYPE);
363   test_ats_info[0].value = htonl(GNUNET_ATS_NET_WAN);
364   test_ats_info[1].type = htonl (GNUNET_ATS_QUALITY_NET_DISTANCE);
365   test_ats_info[1].value = htonl(1);
366   test_ats_count = 2;
367
368   /* Adding address without session */
369   test_session = &test_addr;
370   create_test_address (&test_addr, "test", test_session, "test", strlen ("test") + 1);
371   test_hello_address.peer = p.id;
372   test_hello_address.transport_name = test_addr.plugin;
373   test_hello_address.address = test_addr.addr;
374   test_hello_address.address_length = test_addr.addr_len;
375   GNUNET_ATS_address_add (sched_ats, &test_hello_address, test_session, test_ats_info, test_ats_count);
376
377   initial_start = GNUNET_TIME_absolute_get();
378   GNUNET_ATS_suggest_address (sched_ats, &p.id);
379 }
380
381
382 int
383 main (int argc, char *argv[])
384 {
385   if (0 != GNUNET_TESTING_peer_run ("test_ats_api_scheduling_add_address",
386                                     "test_ats_api.conf",
387                                     &run, NULL))
388     return 1;
389   return ret;
390 }
391 /* end of file test_ats_api_scheduling_reset_backoff.c */