(no commit message)
[oweals/gnunet.git] / src / ats / test_ats_api_scheduling.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.c
22  * @brief test automatic transport selection scheduling 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 "ats.h"
36
37 #define VERBOSE GNUNET_YES
38
39 #define VERBOSE_ARM GNUNET_EXTRA_LOGGING
40
41 #define TIMEOUT GNUNET_TIME_relative_multiply (GNUNET_TIME_UNIT_SECONDS, 10)
42
43 static GNUNET_SCHEDULER_TaskIdentifier die_task;
44
45 static struct GNUNET_ATS_SchedulingHandle *ats;
46
47 struct GNUNET_OS_Process * arm_proc;
48
49 struct Address addr;
50 struct PeerContext p;
51 struct GNUNET_TRANSPORT_ATS_Information atsi[2];
52
53 static int ret;
54
55 struct Address
56 {
57   char * plugin;
58   size_t plugin_len;
59
60   void * addr;
61   size_t addr_len;
62
63   struct GNUNET_TRANSPORT_ATS_Information * ats;
64   int ats_count;
65
66   void  *session;
67 };
68
69 struct PeerContext
70 {
71   struct GNUNET_PeerIdentity id;
72
73   struct Address * addr;
74 };
75
76
77 static void
78 stop_arm ()
79 {
80   if (0 != GNUNET_OS_process_kill (arm_proc, SIGTERM))
81     GNUNET_log_strerror (GNUNET_ERROR_TYPE_WARNING, "kill");
82   GNUNET_OS_process_wait (arm_proc);
83   GNUNET_OS_process_close (arm_proc);
84   arm_proc = NULL;
85 }
86
87
88 static void
89 end_badly (void *cls, const struct GNUNET_SCHEDULER_TaskContext *tc)
90 {
91   die_task = GNUNET_SCHEDULER_NO_TASK;
92   if (ats != NULL)
93     GNUNET_ATS_scheduling_done (ats);
94
95   ret = GNUNET_SYSERR;
96
97   stop_arm ();
98 }
99
100
101 static void
102 end ()
103 {
104   GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "Shutting down\n");
105   if (die_task != GNUNET_SCHEDULER_NO_TASK)
106   {
107     GNUNET_SCHEDULER_cancel(die_task);
108     die_task = GNUNET_SCHEDULER_NO_TASK;
109   }
110
111   GNUNET_ATS_scheduling_done (ats);
112
113   ret = 0;
114
115   stop_arm ();
116 }
117
118
119 static void
120 address_suggest_cb (void *cls,
121                     const struct
122                     GNUNET_PeerIdentity *
123                     peer,
124                     const char *plugin_name,
125                     const void *plugin_addr,
126                     size_t plugin_addr_len,
127                     struct Session * session,
128                     struct
129                     GNUNET_BANDWIDTH_Value32NBO
130                     bandwidth_out,
131                     struct
132                     GNUNET_BANDWIDTH_Value32NBO
133                     bandwidth_in,
134                     const struct
135                     GNUNET_TRANSPORT_ATS_Information
136                     * ats,
137                     uint32_t ats_count)
138
139 {
140   GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "ATS suggests address `%s'\n", GNUNET_i2s (peer));
141
142   GNUNET_assert (0 == memcmp (peer, &p.id, sizeof (struct GNUNET_PeerIdentity)));
143   GNUNET_assert (0 == strcmp (plugin_name, addr.plugin));
144   GNUNET_assert (plugin_addr_len == addr.addr_len);
145   GNUNET_assert (0 == memcmp (plugin_addr, addr.plugin, plugin_addr_len));
146   GNUNET_assert (addr.session == session);
147
148
149   /* TODO ats merge
150   GNUNET_assert (ats_count == 2);
151   GNUNET_assert (atsi[0].type == htons (1));
152   GNUNET_assert (atsi[0].type == htons (2));
153   GNUNET_assert (atsi[1].type == htons (2));
154   GNUNET_assert (atsi[1].type == htons (2));
155   */
156
157   ret = 0;
158
159   GNUNET_SCHEDULER_add_now(&end, NULL);
160 }
161
162 void
163 start_arm (const char *cfgname)
164 {
165   arm_proc = GNUNET_OS_start_process (NULL, NULL, "gnunet-service-arm",
166                            "gnunet-service-arm",
167 #if VERBOSE_ARM
168                            "-L", "DEBUG",
169 #endif
170                            "-c", cfgname, NULL);
171 }
172
173 static void
174 check (void *cls, char *const *args, const char *cfgfile,
175        const struct GNUNET_CONFIGURATION_Handle *cfg)
176 {
177   ret = GNUNET_SYSERR;
178
179   die_task = GNUNET_SCHEDULER_add_delayed(TIMEOUT, &end_badly, NULL);
180   start_arm (cfgfile);
181
182   ats = GNUNET_ATS_scheduling_init (cfg, &address_suggest_cb, NULL);
183
184   if (ats == NULL)
185   {
186     ret = GNUNET_SYSERR;
187     end ();
188     return;
189   }
190
191   /* set up peer */
192   GNUNET_CRYPTO_hash_create_random(GNUNET_CRYPTO_QUALITY_WEAK, &p.id.hashPubKey);
193
194
195   GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "Created peer `%s'\n", GNUNET_i2s (&p.id));
196   p.addr = &addr;
197   addr.plugin = "test";
198   addr.session = NULL;
199   addr.addr = NULL;
200   addr.addr_len = 0;
201
202   GNUNET_ATS_address_update(ats, &p.id, addr.plugin, addr.addr, addr.addr_len, addr.session, NULL, 0);
203
204   atsi[0].type = htons (1);
205   atsi[0].type = htons (1);
206
207   GNUNET_ATS_address_update(ats, &p.id, addr.plugin, addr.addr, addr.addr_len, addr.session, atsi, 1);
208
209   atsi[0].type = htons (1);
210   atsi[0].type = htons (2);
211
212   atsi[1].type = htons (2);
213   atsi[1].type = htons (2);
214
215   GNUNET_ATS_address_update(ats, &p.id, addr.plugin, addr.addr, addr.addr_len, addr.session, atsi, 2);
216
217   GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "Requesting peer `%s'\n", GNUNET_i2s (&p.id));
218   GNUNET_ATS_suggest_address(ats, &p.id);
219 }
220
221 int
222 main (int argc, char *argv[])
223 {
224   static char *const argv2[] = { "test_ats_api_scheduling",
225     "-c",
226     "test_ats_api.conf",
227 #if VERBOSE
228     "-L", "DEBUG",
229 #else
230     "-L", "WARNING",
231 #endif
232     NULL
233   };
234
235   static struct GNUNET_GETOPT_CommandLineOption options[] = {
236     GNUNET_GETOPT_OPTION_END
237   };
238
239   GNUNET_PROGRAM_run ((sizeof (argv2) / sizeof (char *)) - 1, argv2,
240                       "test_ats_api_scheduling", "nohelp", options, &check,
241                       NULL);
242
243
244   return ret;
245 }
246
247 /* end of file test_ats_api_scheduling.c */