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