use new transport API, minor core API change
[oweals/gnunet.git] / src / core / test_core_api_preferences.c
1 /*
2      This file is part of GNUnet.
3      (C) 2009, 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 core/test_core_api_preferences.c
22  * @brief testcase for core_api.c's GNUNET_CORE_change_preference
23  */
24 #include "platform.h"
25 #include "gnunet_common.h"
26 #include "gnunet_arm_service.h"
27 #include "gnunet_core_service.h"
28 #include "gnunet_getopt_lib.h"
29 #include "gnunet_os_lib.h"
30 #include "gnunet_program_lib.h"
31 #include "gnunet_scheduler_lib.h"
32 #include "gnunet_transport_service.h"
33
34 #define VERBOSE GNUNET_NO
35
36 #define START_ARM GNUNET_YES
37
38 #define MTYPE 12345
39
40 struct PeerContext
41 {
42   struct GNUNET_CONFIGURATION_Handle *cfg;
43   struct GNUNET_CORE_Handle *ch;
44   struct GNUNET_PeerIdentity id;   
45   struct GNUNET_TRANSPORT_Handle *th;
46   struct GNUNET_MessageHeader *hello;
47   int connect_status;
48 #if START_ARM
49   struct GNUNET_OS_Process *arm_proc;
50 #endif
51 };
52
53 static struct PeerContext p1;
54
55 static struct PeerContext p2;
56
57 static GNUNET_SCHEDULER_TaskIdentifier err_task;
58
59 static int ok;
60
61 #if VERBOSE
62 #define OKPP do { ok++; fprintf (stderr, "Now at stage %u at %s:%u\n", ok, __FILE__, __LINE__); } while (0)
63 #else
64 #define OKPP do { ok++; } while (0)
65 #endif
66
67 static struct GNUNET_CORE_InformationRequestContext *irc;
68
69 static GNUNET_SCHEDULER_TaskIdentifier irc_task;
70
71 static GNUNET_SCHEDULER_TaskIdentifier ask_task;
72
73 static unsigned int total_reserve = 5;
74
75
76
77 static void
78 terminate_task (void *cls, const struct GNUNET_SCHEDULER_TaskContext *tc)
79 {
80 #if VERBOSE
81   fprintf(stderr, "Regular shutdown\n");
82 #endif
83   GNUNET_assert (ok == 6);
84   GNUNET_assert (NULL == irc);
85   GNUNET_CORE_disconnect (p1.ch);
86   GNUNET_CORE_disconnect (p2.ch);
87   GNUNET_TRANSPORT_disconnect (p1.th);
88   GNUNET_TRANSPORT_disconnect (p2.th);
89   ok = 0;
90 }
91
92
93 static void
94 terminate_task_error (void *cls, const struct GNUNET_SCHEDULER_TaskContext *tc)
95 {
96   err_task = GNUNET_SCHEDULER_NO_TASK;
97 #if VERBOSE
98   fprintf(stderr, "ENDING ANGRILY %u\n", ok);
99 #endif
100   GNUNET_break (0);
101   if (NULL != irc)
102     GNUNET_CORE_peer_change_preference_cancel (irc);
103   if (GNUNET_SCHEDULER_NO_TASK != irc_task)
104     GNUNET_SCHEDULER_cancel (irc_task);
105   if (GNUNET_SCHEDULER_NO_TASK != ask_task)
106     GNUNET_SCHEDULER_cancel (ask_task);
107   GNUNET_CORE_disconnect (p1.ch);
108   GNUNET_CORE_disconnect (p2.ch);
109   GNUNET_TRANSPORT_disconnect (p1.th);
110   GNUNET_TRANSPORT_disconnect (p2.th);
111   ok = 42;
112 }
113
114
115 static size_t
116 transmit_ready (void *cls, size_t size, void *buf)
117 {
118   struct PeerContext *p = cls;
119   struct GNUNET_MessageHeader *m;
120
121   GNUNET_assert (ok == 4);
122   OKPP;
123   GNUNET_assert (p == &p1);
124   GNUNET_assert (buf != NULL);
125   m = (struct GNUNET_MessageHeader *) buf;
126   m->type = htons (MTYPE);
127   m->size = htons (sizeof (struct GNUNET_MessageHeader));
128   err_task = 
129     GNUNET_SCHEDULER_add_delayed (GNUNET_TIME_relative_multiply(GNUNET_TIME_UNIT_SECONDS, 120), 
130                                   &terminate_task_error, NULL);
131
132   return sizeof (struct GNUNET_MessageHeader);
133 }
134
135 static void
136 preference_cb (void *cls,
137                const struct
138                GNUNET_PeerIdentity *peer,
139                struct GNUNET_BANDWIDTH_Value32NBO bandwidth_out,
140                int32_t amount,
141                struct GNUNET_TIME_Relative res_delay,
142                uint64_t preference);
143
144 static void
145 do_reserve (void *cls,
146             const struct GNUNET_SCHEDULER_TaskContext *tc)
147 {
148   struct PeerContext *pc = cls;
149
150   irc_task = GNUNET_SCHEDULER_NO_TASK;
151   if (0 != (tc->reason & GNUNET_SCHEDULER_REASON_SHUTDOWN))
152     {
153       GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
154                   "Aborted during attempt to request reservation\n");
155       return;
156     }
157   GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
158               "Requesting reservatin of 32k from core in 1s!\n");
159   irc = GNUNET_CORE_peer_change_preference (p1.ch,
160                                             &p2.id,
161                                             GNUNET_TIME_UNIT_SECONDS,
162                                             GNUNET_BANDWIDTH_VALUE_MAX,
163                                             1000000 /* bandwidth for 1s */,
164                                             0,
165                                             &preference_cb,
166                                             pc);
167 }
168
169 static void
170 preference_cb (void *cls,
171                const struct
172                GNUNET_PeerIdentity *peer,
173                struct GNUNET_BANDWIDTH_Value32NBO bandwidth_out,
174                int32_t amount,
175                struct GNUNET_TIME_Relative res_delay,
176                uint64_t preference)
177 {
178   struct PeerContext *pc = cls;
179
180   irc = NULL;
181   if (0 == amount)
182     {
183       GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
184                   "Delaying reservation request by %llu ms!\n",
185                   (unsigned long long) res_delay.rel_value);
186       irc_task = GNUNET_SCHEDULER_add_delayed (res_delay,
187                                                &do_reserve, pc);
188       return;
189     }
190   total_reserve--;
191   GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
192               "Reservation done!\n");
193   if (total_reserve > 0)
194     {
195       irc_task = GNUNET_SCHEDULER_add_now (&do_reserve, pc);
196       return;
197     }
198   GNUNET_SCHEDULER_cancel (err_task);
199   err_task = GNUNET_SCHEDULER_NO_TASK;
200   GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
201               "Asking core (1) for transmission to peer `%4s'\n",
202               GNUNET_i2s (&p2.id));
203   if (NULL == GNUNET_CORE_notify_transmit_ready (p1.ch,
204                                                  GNUNET_YES,
205                                                  0,
206                                                  GNUNET_TIME_relative_multiply (GNUNET_TIME_UNIT_SECONDS, 45),
207                                                  &p2.id,
208                                                  sizeof (struct GNUNET_MessageHeader),
209                                                  &transmit_ready, &p1))
210     {
211       GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
212                   "RECEIVED NULL when asking core (1) for transmission to peer `%4s'\n",
213                   GNUNET_i2s (&p2.id));
214     }    
215 }
216
217
218 static void
219 connect_notify (void *cls,
220                 const struct GNUNET_PeerIdentity *peer,
221                 const struct GNUNET_TRANSPORT_ATS_Information *atsi)
222 {
223   struct PeerContext *pc = cls;
224
225   if (0 == memcmp (&pc->id,
226                    peer,
227                    sizeof (struct GNUNET_PeerIdentity)))
228     return;
229   GNUNET_assert (pc->connect_status == 0);
230   pc->connect_status = 1;
231   if (pc == &p1)
232     {
233       GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
234                   "Encrypted connection established to peer `%4s'\n",
235                   GNUNET_i2s (peer));
236       GNUNET_SCHEDULER_cancel (ask_task);
237       ask_task = GNUNET_SCHEDULER_NO_TASK;
238       GNUNET_SCHEDULER_cancel (err_task);
239       err_task = 
240         GNUNET_SCHEDULER_add_delayed (GNUNET_TIME_relative_multiply(GNUNET_TIME_UNIT_SECONDS, 120), 
241                                       &terminate_task_error, NULL);
242       irc_task = GNUNET_SCHEDULER_add_now (&do_reserve, pc);
243     }
244 }
245
246
247 static void
248 disconnect_notify (void *cls,
249                    const struct GNUNET_PeerIdentity *peer)
250 {
251   struct PeerContext *pc = cls;
252
253   if (0 == memcmp (&pc->id,
254                    peer,
255                    sizeof (struct GNUNET_PeerIdentity)))
256     return;
257   pc->connect_status = 0;
258   GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
259               "Encrypted connection to `%4s' cut\n", GNUNET_i2s (peer));
260 }
261
262
263 static int
264 inbound_notify (void *cls,
265                 const struct GNUNET_PeerIdentity *other,
266                 const struct GNUNET_MessageHeader *message,
267                 const struct GNUNET_TRANSPORT_ATS_Information *atsi)
268 {
269   GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
270               "Core provides inbound data from `%4s'.\n", GNUNET_i2s (other));
271   return GNUNET_OK;
272 }
273
274
275 static int
276 outbound_notify (void *cls,
277                  const struct GNUNET_PeerIdentity *other,
278                  const struct GNUNET_MessageHeader *message,
279                  const struct GNUNET_TRANSPORT_ATS_Information *atsi)
280 {
281   GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
282               "Core notifies about outbound data for `%4s'.\n",
283               GNUNET_i2s (other));
284   return GNUNET_OK;
285 }
286
287
288
289 static int
290 process_mtype (void *cls,
291                const struct GNUNET_PeerIdentity *peer,
292                const struct GNUNET_MessageHeader *message,
293                const struct GNUNET_TRANSPORT_ATS_Information *atsi)
294 {
295   GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
296               "Receiving message from `%4s'.\n", GNUNET_i2s (peer));
297   GNUNET_assert (ok == 5);
298   OKPP;
299   GNUNET_SCHEDULER_cancel (err_task);
300   err_task = GNUNET_SCHEDULER_NO_TASK;
301   GNUNET_SCHEDULER_add_now (&terminate_task, NULL);
302   return GNUNET_OK;
303 }
304
305
306 static struct GNUNET_CORE_MessageHandler handlers[] = {
307   {&process_mtype, MTYPE, sizeof (struct GNUNET_MessageHeader)},
308   {NULL, 0, 0}
309 };
310
311
312
313 static void 
314 ask_connect_task (void *cls,
315                   const struct GNUNET_SCHEDULER_TaskContext *tc)
316 {
317   ask_task =
318     GNUNET_SCHEDULER_add_delayed (GNUNET_TIME_UNIT_SECONDS,
319                                   &ask_connect_task, NULL);
320   GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
321               "Asking core (1) AGAIN to connect to peer `%4s'\n",
322               GNUNET_i2s (&p2.id));
323   GNUNET_CORE_peer_request_connect (p1.ch,
324                                     &p2.id,
325                                     NULL, NULL);
326 }
327
328
329 static void
330 init_notify (void *cls,
331              struct GNUNET_CORE_Handle *server,
332              const struct GNUNET_PeerIdentity *my_identity,
333              const struct GNUNET_CRYPTO_RsaPublicKeyBinaryEncoded *publicKey)
334 {
335   struct PeerContext *p = cls;
336
337   GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
338               "Core connection to `%4s' established\n",
339               GNUNET_i2s (my_identity));
340   GNUNET_assert (server != NULL);
341   p->id = *my_identity;
342   p->ch = server;
343   if (cls == &p1)
344     {
345       GNUNET_assert (ok == 2);
346       OKPP;
347       /* connect p2 */
348       GNUNET_CORE_connect (p2.cfg, 1,
349                            &p2,
350                            &init_notify,                         
351                            &connect_notify,
352                            &disconnect_notify,
353                            NULL,
354                            &inbound_notify,
355                            GNUNET_YES,
356                            &outbound_notify, GNUNET_YES, handlers);
357     }
358   else
359     {
360       GNUNET_assert (ok == 3);
361       OKPP;
362       GNUNET_assert (cls == &p2);
363       GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
364                   "Asking core (1) to connect to peer `%4s'\n",
365                   GNUNET_i2s (&p2.id));
366       err_task = 
367         GNUNET_SCHEDULER_add_delayed (GNUNET_TIME_relative_multiply(GNUNET_TIME_UNIT_SECONDS, 60), 
368                                       &terminate_task_error, NULL);
369       ask_task =
370         GNUNET_SCHEDULER_add_delayed (GNUNET_TIME_UNIT_SECONDS,
371                                       &ask_connect_task, NULL);
372       GNUNET_CORE_peer_request_connect (p1.ch,
373                                         &p2.id,
374                                         NULL, NULL);
375     }
376 }
377
378
379 static void
380 process_hello (void *cls,
381                const struct GNUNET_MessageHeader *message)
382 {
383   struct PeerContext *p = cls;
384
385   GNUNET_TRANSPORT_get_hello_cancel (p->th, &process_hello, p);
386   GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
387               "Received (my) `%s' from transport service\n",
388               "HELLO");
389   GNUNET_assert (message != NULL);
390   p->hello = GNUNET_malloc (ntohs (message->size));
391   memcpy (p->hello, message, ntohs (message->size));
392   if ((p == &p1) && (p2.th != NULL))
393     GNUNET_TRANSPORT_offer_hello (p2.th, message, NULL, NULL);
394   if ((p == &p2) && (p1.th != NULL))
395     GNUNET_TRANSPORT_offer_hello (p1.th, message, NULL, NULL);
396
397   if ((p == &p1) && (p2.hello != NULL))
398     GNUNET_TRANSPORT_offer_hello (p1.th, p2.hello, NULL, NULL);
399   if ((p == &p2) && (p1.hello != NULL))
400     GNUNET_TRANSPORT_offer_hello (p2.th, p1.hello, NULL, NULL);
401 }
402
403
404
405 static void
406 setup_peer (struct PeerContext *p, const char *cfgname)
407 {
408   p->cfg = GNUNET_CONFIGURATION_create ();
409 #if START_ARM
410   p->arm_proc = GNUNET_OS_start_process (NULL, NULL, "gnunet-service-arm",
411                                         "gnunet-service-arm",
412 #if VERBOSE
413                                         "-L", "DEBUG",
414 #endif
415                                         "-c", cfgname, NULL);
416 #endif
417   GNUNET_assert (GNUNET_OK == GNUNET_CONFIGURATION_load (p->cfg, cfgname));
418   p->th = GNUNET_TRANSPORT_connect (p->cfg, NULL, p, NULL, NULL, NULL);
419   GNUNET_assert (p->th != NULL);
420   GNUNET_TRANSPORT_get_hello (p->th, &process_hello, p);
421 }
422
423
424 static void
425 run (void *cls,
426      char *const *args,
427      const char *cfgfile,
428      const struct GNUNET_CONFIGURATION_Handle *cfg)
429 {
430   GNUNET_assert (ok == 1);
431   OKPP;
432   setup_peer (&p1, "test_core_quota_asymmetric_recv_limited_peer1.conf");
433   setup_peer (&p2, "test_core_quota_asymmetric_recv_limited_peer2.conf");
434   GNUNET_CORE_connect (p1.cfg, 1,
435                        &p1,
436                        &init_notify,
437                        &connect_notify,
438                        &disconnect_notify,
439                        NULL,
440                        &inbound_notify,
441                        GNUNET_YES, &outbound_notify, GNUNET_YES, handlers);
442 }
443
444 static void
445 stop_arm (struct PeerContext *p)
446 {
447 #if START_ARM
448   if (0 != GNUNET_OS_process_kill (p->arm_proc, SIGTERM))
449     GNUNET_log_strerror (GNUNET_ERROR_TYPE_WARNING, "kill");
450   if (GNUNET_OS_process_wait(p->arm_proc) != GNUNET_OK)
451     GNUNET_log_strerror (GNUNET_ERROR_TYPE_WARNING, "waitpid");
452   GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
453               "ARM process %u stopped\n", GNUNET_OS_process_get_pid (p->arm_proc));
454   GNUNET_OS_process_close (p->arm_proc);
455   p->arm_proc = NULL;
456 #endif
457   GNUNET_CONFIGURATION_destroy (p->cfg);
458 }
459
460 static int
461 check ()
462 {
463   char *const argv[] = { "test-core-api-preferences",
464     "-c",
465     "test_core_api_data.conf",
466 #if VERBOSE
467     "-L", "DEBUG",
468 #endif
469     NULL
470   };
471   struct GNUNET_GETOPT_CommandLineOption options[] = {
472     GNUNET_GETOPT_OPTION_END
473   };
474   ok = 1;
475   GNUNET_PROGRAM_run ((sizeof (argv) / sizeof (char *)) - 1,
476                       argv, "test-core-api-preferences", "nohelp", options, &run, &ok);
477   stop_arm (&p1);
478   stop_arm (&p2);
479   return ok;
480 }
481
482 int
483 main (int argc, char *argv[])
484 {
485   int ret;
486
487   GNUNET_log_setup ("test-core-api",
488 #if VERBOSE
489                     "DEBUG",
490 #else
491                     "WARNING",
492 #endif
493                     NULL);
494   ret = check ();
495   GNUNET_DISK_directory_remove ("/tmp/test-gnunet-core-peer-1"); 
496   GNUNET_DISK_directory_remove ("/tmp/test-gnunet-core-peer-2");
497
498   return ret;
499 }
500
501 /* end of test_core_api_preferences.c */