additional test
[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                                     GNUNET_TIME_UNIT_SECONDS,
325                                     &p2.id,
326                                     NULL, NULL);
327 }
328
329
330 static void
331 init_notify (void *cls,
332              struct GNUNET_CORE_Handle *server,
333              const struct GNUNET_PeerIdentity *my_identity,
334              const struct GNUNET_CRYPTO_RsaPublicKeyBinaryEncoded *publicKey)
335 {
336   struct PeerContext *p = cls;
337
338   GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
339               "Core connection to `%4s' established\n",
340               GNUNET_i2s (my_identity));
341   GNUNET_assert (server != NULL);
342   p->id = *my_identity;
343   p->ch = server;
344   if (cls == &p1)
345     {
346       GNUNET_assert (ok == 2);
347       OKPP;
348       /* connect p2 */
349       GNUNET_CORE_connect (p2.cfg, 1,
350                            &p2,
351                            &init_notify,                         
352                            &connect_notify,
353                            &disconnect_notify,
354                            NULL,
355                            &inbound_notify,
356                            GNUNET_YES,
357                            &outbound_notify, GNUNET_YES, handlers);
358     }
359   else
360     {
361       GNUNET_assert (ok == 3);
362       OKPP;
363       GNUNET_assert (cls == &p2);
364       GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
365                   "Asking core (1) to connect to peer `%4s'\n",
366                   GNUNET_i2s (&p2.id));
367       err_task = 
368         GNUNET_SCHEDULER_add_delayed (GNUNET_TIME_relative_multiply(GNUNET_TIME_UNIT_SECONDS, 60), 
369                                       &terminate_task_error, NULL);
370       ask_task =
371         GNUNET_SCHEDULER_add_delayed (GNUNET_TIME_UNIT_SECONDS,
372                                       &ask_connect_task, NULL);
373       GNUNET_CORE_peer_request_connect (p1.ch,
374                                         GNUNET_TIME_UNIT_SECONDS,
375                                         &p2.id,
376                                         NULL, NULL);
377     }
378 }
379
380
381 static void
382 process_hello (void *cls,
383                const struct GNUNET_MessageHeader *message)
384 {
385   struct PeerContext *p = cls;
386
387   GNUNET_TRANSPORT_get_hello_cancel (p->th, &process_hello, p);
388   GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
389               "Received (my) `%s' from transport service\n",
390               "HELLO");
391   GNUNET_assert (message != NULL);
392   p->hello = GNUNET_malloc (ntohs (message->size));
393   memcpy (p->hello, message, ntohs (message->size));
394   if ((p == &p1) && (p2.th != NULL))
395     GNUNET_TRANSPORT_offer_hello (p2.th, message, NULL, NULL);
396   if ((p == &p2) && (p1.th != NULL))
397     GNUNET_TRANSPORT_offer_hello (p1.th, message, NULL, NULL);
398
399   if ((p == &p1) && (p2.hello != NULL))
400     GNUNET_TRANSPORT_offer_hello (p1.th, p2.hello, NULL, NULL);
401   if ((p == &p2) && (p1.hello != NULL))
402     GNUNET_TRANSPORT_offer_hello (p2.th, p1.hello, NULL, NULL);
403 }
404
405
406
407 static void
408 setup_peer (struct PeerContext *p, const char *cfgname)
409 {
410   p->cfg = GNUNET_CONFIGURATION_create ();
411 #if START_ARM
412   p->arm_proc = GNUNET_OS_start_process (NULL, NULL, "gnunet-service-arm",
413                                         "gnunet-service-arm",
414 #if VERBOSE
415                                         "-L", "DEBUG",
416 #endif
417                                         "-c", cfgname, NULL);
418 #endif
419   GNUNET_assert (GNUNET_OK == GNUNET_CONFIGURATION_load (p->cfg, cfgname));
420   p->th = GNUNET_TRANSPORT_connect (p->cfg, NULL, p, NULL, NULL, NULL);
421   GNUNET_assert (p->th != NULL);
422   GNUNET_TRANSPORT_get_hello (p->th, &process_hello, p);
423 }
424
425
426 static void
427 run (void *cls,
428      char *const *args,
429      const char *cfgfile,
430      const struct GNUNET_CONFIGURATION_Handle *cfg)
431 {
432   GNUNET_assert (ok == 1);
433   OKPP;
434   setup_peer (&p1, "test_core_quota_asymmetric_recv_limited_peer1.conf");
435   setup_peer (&p2, "test_core_quota_asymmetric_recv_limited_peer2.conf");
436   GNUNET_CORE_connect (p1.cfg, 1,
437                        &p1,
438                        &init_notify,
439                        &connect_notify,
440                        &disconnect_notify,
441                        NULL,
442                        &inbound_notify,
443                        GNUNET_YES, &outbound_notify, GNUNET_YES, handlers);
444 }
445
446 static void
447 stop_arm (struct PeerContext *p)
448 {
449 #if START_ARM
450   if (0 != GNUNET_OS_process_kill (p->arm_proc, SIGTERM))
451     GNUNET_log_strerror (GNUNET_ERROR_TYPE_WARNING, "kill");
452   if (GNUNET_OS_process_wait(p->arm_proc) != GNUNET_OK)
453     GNUNET_log_strerror (GNUNET_ERROR_TYPE_WARNING, "waitpid");
454   GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
455               "ARM process %u stopped\n", GNUNET_OS_process_get_pid (p->arm_proc));
456   GNUNET_OS_process_close (p->arm_proc);
457   p->arm_proc = NULL;
458 #endif
459   GNUNET_CONFIGURATION_destroy (p->cfg);
460 }
461
462 static int
463 check ()
464 {
465   char *const argv[] = { "test-core-api-preferences",
466     "-c",
467     "test_core_api_data.conf",
468 #if VERBOSE
469     "-L", "DEBUG",
470 #endif
471     NULL
472   };
473   struct GNUNET_GETOPT_CommandLineOption options[] = {
474     GNUNET_GETOPT_OPTION_END
475   };
476   ok = 1;
477   GNUNET_PROGRAM_run ((sizeof (argv) / sizeof (char *)) - 1,
478                       argv, "test-core-api-preferences", "nohelp", options, &run, &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 */