changed testbed API to include convenience callbacks
[oweals/gnunet.git] / src / ats / test_ats_api_update_address.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/ats_api.c
22  * @brief automatic transport selection API
23  * @author Christian Grothoff
24  * @author Matthias Wachs
25  *
26  * TODO:
27  * - write test case
28  * - extend API to get performance data
29  * - implement simplistic strategy based on say 'lowest latency' or strict ordering
30  * - extend API to get peer preferences, implement proportional bandwidth assignment
31  * - re-implement API against a real ATS service (!)
32  */
33 #include "platform.h"
34 #include "gnunet_ats_service.h"
35 #include "gnunet_transport_service.h"
36
37 #define START_ARM GNUNET_YES
38
39 #define TIMEOUT GNUNET_TIME_relative_multiply (GNUNET_TIME_UNIT_SECONDS, 5)
40
41 #define VALID GNUNET_TIME_UNIT_FOREVER_ABS
42
43 static struct GNUNET_ATS_SchedulingHandle *ats;
44
45 static struct GNUNET_ATS_SuggestionContext *asc;
46
47 static struct GNUNET_PeerIdentity peer;
48
49 static GNUNET_SCHEDULER_TaskIdentifier end_task;
50
51 static struct AllocationRecord *ar;
52
53 static int result;
54
55 struct ExpectedValues
56 {
57   int expected_ats_count;
58
59   int expected_ats_type;
60
61   int expected_ats_value;
62
63   int expected_in_index;
64 };
65
66 struct AllocationRecord
67 {
68
69   /**
70    * Performance information associated with this address (array).
71    */
72   struct GNUNET_ATS_Information *ats;
73
74   /**
75    * Name of the plugin
76    */
77   char *plugin_name;
78
79   /**
80    * Address this record represents, allocated at the end of this struct.
81    */
82   const void *plugin_addr;
83
84   /**
85    * Session associated with this record.
86    */
87   struct Session *session;
88
89   /**
90    * Number of bytes in plugin_addr.
91    */
92   size_t plugin_addr_len;
93
94   /**
95    * Number of entries in 'ats'.
96    */
97   uint32_t ats_count;
98 };
99
100 static void
101 end (void *cls, const struct GNUNET_SCHEDULER_TaskContext *tc)
102 {
103   GNUNET_log (GNUNET_ERROR_TYPE_INFO, "Shutdown\n");
104   if (asc != NULL)
105   {
106     GNUNET_ATS_suggest_address_cancel (asc);
107     asc = NULL;
108   }
109   GNUNET_ATS_shutdown (ats);
110
111   GNUNET_array_grow (ar->ats, ar->ats_count, 0);
112   GNUNET_free (ar);
113 }
114
115 void
116 suggest_cb (void *cls, const struct GNUNET_PeerIdentity *peer,
117             const char *plugin_name, const void *plugin_addr,
118             size_t plugin_addr_len, struct Session *session,
119             struct GNUNET_BANDWIDTH_Value32NBO bandwidth,
120             const struct GNUNET_ATS_Information *ats, uint32_t ats_count)
121 {
122   struct ExpectedValues *ex = cls;
123
124   GNUNET_log (GNUNET_ERROR_TYPE_INFO,
125               "ATS suggested address for peer `%s': `%s' `%s'\n",
126               GNUNET_i2s (peer), plugin_name, plugin_addr);
127   GNUNET_log (GNUNET_ERROR_TYPE_INFO, "ATS count %u\n", ats_count);
128
129   int c = 0;
130
131   while (c < ats_count)
132   {
133     GNUNET_log (GNUNET_ERROR_TYPE_INFO, "ats[%u]: type %u value %u\n", c,
134                 ntohl (ats[c].type), ntohl (ats[c].value));
135
136     c++;
137   }
138
139   if (ex->expected_ats_count != GNUNET_SYSERR)
140     GNUNET_assert (ex->expected_ats_count == ats_count);
141
142   if ((ex->expected_ats_value != GNUNET_SYSERR) &&
143       (ex->expected_in_index != GNUNET_SYSERR))
144     GNUNET_assert (ex->expected_ats_value ==
145                    ntohl (ats[ex->expected_in_index].value));
146
147   if ((ex->expected_ats_type != GNUNET_SYSERR) &&
148       (ex->expected_in_index != GNUNET_SYSERR))
149     GNUNET_assert (ex->expected_ats_type ==
150                    ntohl (ats[ex->expected_in_index].type));
151
152
153 }
154
155 static void
156 check (void *cls, char *const *args, const char *cfgfile,
157        const struct GNUNET_CONFIGURATION_Handle *cfg)
158 {
159   struct ExpectedValues ex;
160
161   GNUNET_CRYPTO_hash_create_random (GNUNET_CRYPTO_QUALITY_WEAK,
162                                     &peer.hashPubKey);
163   GNUNET_log (GNUNET_ERROR_TYPE_INFO, "Created peer identity `%s'\n",
164               GNUNET_i2s (&peer));
165
166   ats = GNUNET_ATS_init (cfg, NULL, NULL);
167   GNUNET_assert (ats != NULL);
168
169   end_task = GNUNET_SCHEDULER_add_delayed (TIMEOUT, &end, NULL);
170
171   ar = GNUNET_malloc (sizeof (struct AllocationRecord));
172
173   ar->plugin_name = "test";
174   ar->session = NULL;
175   ar->plugin_addr = "address1";
176   ar->plugin_addr_len = strlen (ar->plugin_addr) + 1;
177   ar->ats = GNUNET_malloc (sizeof (struct GNUNET_ATS_Information));
178
179   GNUNET_log (GNUNET_ERROR_TYPE_INFO, "Initial ATS information\n");
180   ar->ats_count = 1;
181   ar->ats[0].type = htonl (0);
182   ar->ats[0].value = htonl (0);
183
184   ex.expected_ats_count = 1;
185   ex.expected_ats_type = 0;
186   ex.expected_ats_value = 0;
187   ex.expected_in_index = 0;
188
189   GNUNET_ATS_address_update (ats, &peer, VALID, ar->plugin_name, ar->session,
190                              ar->plugin_addr, ar->plugin_addr_len, ar->ats,
191                              ar->ats_count);
192   asc = GNUNET_ATS_suggest_address (ats, &peer, &suggest_cb, &ex);
193
194   GNUNET_log (GNUNET_ERROR_TYPE_INFO, "Extending empty ATS information\n");
195
196   GNUNET_array_grow (ar->ats, ar->ats_count, ar->ats_count + 1);
197   ar->ats[0].type = htonl (1);
198   ar->ats[0].value = htonl (1);
199   ar->ats[1].type = htonl (0);
200   ar->ats[1].value = htonl (0);
201
202   ex.expected_ats_count = 2;
203   ex.expected_ats_type = 1;
204   ex.expected_ats_value = 1;
205   ex.expected_in_index = 0;
206
207   GNUNET_ATS_address_update (ats, &peer, VALID, ar->plugin_name, ar->session,
208                              ar->plugin_addr, ar->plugin_addr_len, ar->ats,
209                              ar->ats_count);
210   asc = GNUNET_ATS_suggest_address (ats, &peer, &suggest_cb, &ex);
211
212   GNUNET_log (GNUNET_ERROR_TYPE_INFO, "Updating existing ATS information\n");
213
214   ar->ats[0].type = htonl (1);
215   ar->ats[0].value = htonl (2);
216   ar->ats[1].type = htonl (0);
217   ar->ats[1].value = htonl (0);
218
219   ex.expected_ats_count = 2;
220   ex.expected_ats_type = 1;
221   ex.expected_ats_value = 2;
222   ex.expected_in_index = 0;
223
224   GNUNET_ATS_address_update (ats, &peer, VALID, ar->plugin_name, ar->session,
225                              ar->plugin_addr, ar->plugin_addr_len, ar->ats,
226                              ar->ats_count);
227   asc = GNUNET_ATS_suggest_address (ats, &peer, &suggest_cb, &ex);
228
229   /* Extending existing ATS information */
230   GNUNET_log (GNUNET_ERROR_TYPE_INFO, "Extending existing ATS information\n");
231
232
233   ar->ats[0].type = htonl (2);
234   ar->ats[0].value = htonl (2);
235   ar->ats[1].type = htonl (0);
236   ar->ats[1].value = htonl (0);
237
238   ex.expected_ats_count = 3;
239   ex.expected_ats_type = 2;
240   ex.expected_ats_value = 2;
241   ex.expected_in_index = 1;
242
243   GNUNET_ATS_address_update (ats, &peer, VALID, ar->plugin_name, ar->session,
244                              ar->plugin_addr, ar->plugin_addr_len, ar->ats,
245                              ar->ats_count);
246   asc = GNUNET_ATS_suggest_address (ats, &peer, &suggest_cb, &ex);
247
248   GNUNET_log (GNUNET_ERROR_TYPE_INFO, "Updating existing ATS information\n");
249
250   ar->ats[0].type = htonl (2);
251   ar->ats[0].value = htonl (3);
252   ar->ats[1].type = htonl (0);
253   ar->ats[1].value = htonl (0);
254
255   ex.expected_ats_count = 3;
256   ex.expected_ats_type = 2;
257   ex.expected_ats_value = 3;
258   ex.expected_in_index = 1;
259
260   GNUNET_ATS_address_update (ats, &peer, VALID, ar->plugin_name, ar->session,
261                              ar->plugin_addr, ar->plugin_addr_len, ar->ats,
262                              ar->ats_count);
263   asc = GNUNET_ATS_suggest_address (ats, &peer, &suggest_cb, &ex);
264
265   if (end_task != GNUNET_SCHEDULER_NO_TASK)
266     GNUNET_SCHEDULER_cancel (end_task);
267   end_task = GNUNET_SCHEDULER_add_now (&end, NULL);
268 }
269
270 int
271 main (int argc, char *argv1[])
272 {
273   static char *const argv[] = { "test_ats_api_update_address",
274     "-c",
275     "test_ats_api.conf",
276     "-L", "WARNING",
277     NULL
278   };
279
280   static struct GNUNET_GETOPT_CommandLineOption options[] = {
281     GNUNET_GETOPT_OPTION_END
282   };
283
284   GNUNET_PROGRAM_run ((sizeof (argv) / sizeof (char *)) - 1, argv,
285                       "test_ats_api_update_address", "nohelp", options, &check,
286                       NULL);
287
288   return result;
289 }