-rps service: prevent division by zero
[oweals/gnunet.git] / src / psyc / test_psyc.c
1 /*
2  * This file is part of GNUnet
3  * Copyright (C) 2013 GNUnet e.V.
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., 51 Franklin Street, Fifth Floor,
18  * Boston, MA 02110-1301, USA.
19  */
20
21 /**
22  * @file psyc/test_psyc.c
23  * @brief Tests for the PSYC API.
24  * @author Gabor X Toth
25  * @author Christian Grothoff
26  */
27
28 #include <inttypes.h>
29
30 #include "platform.h"
31 #include "gnunet_crypto_lib.h"
32 #include "gnunet_common.h"
33 #include "gnunet_util_lib.h"
34 #include "gnunet_testing_lib.h"
35 #include "gnunet_psyc_util_lib.h"
36 #include "gnunet_psyc_service.h"
37 #include "gnunet_core_service.h"
38
39 #define TIMEOUT GNUNET_TIME_relative_multiply (GNUNET_TIME_UNIT_SECONDS, 30)
40
41 /**
42  * Return value from 'main'.
43  */
44 static int res;
45
46 static const struct GNUNET_CONFIGURATION_Handle *cfg;
47
48 static struct GNUNET_CORE_Handle *core;
49 static struct GNUNET_PeerIdentity this_peer;
50
51 /**
52  * Handle for task for timeout termination.
53  */
54 static struct GNUNET_SCHEDULER_Task * end_badly_task;
55
56 static struct GNUNET_PSYC_Master *mst;
57 static struct GNUNET_PSYC_Slave *slv;
58
59 static struct GNUNET_PSYC_Channel *mst_chn, *slv_chn;
60
61 static struct GNUNET_CRYPTO_EddsaPrivateKey *channel_key;
62 static struct GNUNET_CRYPTO_EcdsaPrivateKey *slave_key;
63
64 static struct GNUNET_CRYPTO_EddsaPublicKey channel_pub_key;
65 static struct GNUNET_CRYPTO_EcdsaPublicKey slave_pub_key;
66
67 struct TransmitClosure
68 {
69   struct GNUNET_PSYC_MasterTransmitHandle *mst_tmit;
70   struct GNUNET_PSYC_SlaveTransmitHandle *slv_tmit;
71   struct GNUNET_PSYC_Environment *env;
72   struct GNUNET_PSYC_Modifier *mod;
73   char *data[16];
74   const char *mod_value;
75   size_t mod_value_size;
76   uint8_t data_delay[16];
77   uint8_t data_count;
78   uint8_t paused;
79   uint8_t n;
80 };
81
82 static struct TransmitClosure *tmit;
83
84 static uint8_t join_req_count, end_count;
85
86 enum
87 {
88   TEST_NONE                         = 0,
89   TEST_MASTER_START                 = 1,
90   TEST_SLAVE_JOIN_REJECT            = 2,
91   TEST_SLAVE_JOIN_ACCEPT            = 3,
92   TEST_SLAVE_ADD                    = 4,
93   TEST_SLAVE_REMOVE                 = 5,
94   TEST_SLAVE_TRANSMIT               = 6,
95   TEST_MASTER_TRANSMIT              = 7,
96   TEST_MASTER_HISTORY_REPLAY_LATEST = 8,
97   TEST_SLAVE_HISTORY_REPLAY_LATEST  = 9,
98   TEST_MASTER_HISTORY_REPLAY       = 10,
99   TEST_SLAVE_HISTORY_REPLAY        = 11,
100   TEST_MASTER_STATE_GET            = 12,
101   TEST_SLAVE_STATE_GET             = 13,
102   TEST_MASTER_STATE_GET_PREFIX     = 14,
103   TEST_SLAVE_STATE_GET_PREFIX      = 15,
104 } test;
105
106
107 static void
108 master_transmit ();
109
110 static void
111 master_history_replay_latest ();
112
113
114 static void
115 master_stopped (void *cls)
116 {
117   if (NULL != tmit)
118   {
119     GNUNET_PSYC_env_destroy (tmit->env);
120     GNUNET_free (tmit);
121     tmit = NULL;
122   }
123   GNUNET_SCHEDULER_shutdown ();
124 }
125
126
127 static void
128 slave_parted (void *cls)
129 {
130   if (NULL != mst)
131   {
132     GNUNET_PSYC_master_stop (mst, GNUNET_NO, &master_stopped, NULL);
133     mst = NULL;
134   }
135   else
136     master_stopped (NULL);
137 }
138
139
140 /**
141  * Clean up all resources used.
142  */
143 static void
144 cleanup ()
145 {
146   if (NULL != core)
147   {
148     GNUNET_CORE_disconnecT (core);
149     core = NULL;
150   }
151   if (NULL != slv)
152   {
153     GNUNET_PSYC_slave_part (slv, GNUNET_NO, &slave_parted, NULL);
154     slv = NULL;
155   }
156   else
157     slave_parted (NULL);
158 }
159
160
161 /**
162  * Terminate the test case (failure).
163  *
164  * @param cls NULL
165  */
166 static void
167 end_badly (void *cls)
168 {
169   res = 1;
170   cleanup ();
171   GNUNET_log (GNUNET_ERROR_TYPE_ERROR, "Test FAILED.\n");
172 }
173
174
175 /**
176  * Terminate the test case (success).
177  *
178  * @param cls NULL
179  */
180 static void
181 end_normally (void *cls)
182 {
183   res = 0;
184   cleanup ();
185   GNUNET_log (GNUNET_ERROR_TYPE_WARNING, "Test PASSED.\n");
186 }
187
188
189 /**
190  * Finish the test case (successfully).
191  */
192 static void
193 end ()
194 {
195   GNUNET_log (GNUNET_ERROR_TYPE_INFO, "Ending tests.\n");
196
197   if (end_badly_task != NULL)
198   {
199     GNUNET_SCHEDULER_cancel (end_badly_task);
200     end_badly_task = NULL;
201   }
202   GNUNET_SCHEDULER_add_delayed (GNUNET_TIME_UNIT_MILLISECONDS,
203                                 &end_normally, NULL);
204 }
205
206
207 static void
208 master_message_cb (void *cls, const struct GNUNET_PSYC_MessageHeader *msg)
209 {
210   GNUNET_assert (NULL != msg);
211   GNUNET_log (GNUNET_ERROR_TYPE_INFO,
212               "Test #%d: Master got PSYC message fragment of size %u "
213               "belonging to message ID %" PRIu64 " with flags %x\n",
214               test, ntohs (msg->header.size),
215               GNUNET_ntohll (msg->message_id), ntohl (msg->flags));
216   // FIXME
217 }
218
219
220 static void
221 master_message_part_cb (void *cls, const struct GNUNET_PSYC_MessageHeader *msg,
222                         const struct GNUNET_MessageHeader *pmsg)
223 {
224   GNUNET_assert (NULL != msg && NULL != pmsg);
225
226   uint64_t message_id = GNUNET_ntohll (msg->message_id);
227   uint32_t flags = ntohl (msg->flags);
228
229   uint16_t type = ntohs (pmsg->type);
230   uint16_t size = ntohs (pmsg->size);
231
232   GNUNET_log (GNUNET_ERROR_TYPE_INFO,
233               "Test #%d: Master got message part of type %u and size %u "
234               "belonging to message ID %" PRIu64 " with flags %x\n",
235               test, type, size, message_id, flags);
236
237   switch (test)
238   {
239   case TEST_SLAVE_TRANSMIT:
240     if (GNUNET_PSYC_MESSAGE_REQUEST != flags)
241     {
242       GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
243                   "Test #%d: Unexpected request flags: %x" PRIu32 "\n",
244                   test, flags);
245       GNUNET_assert (0);
246       return;
247     }
248     // FIXME: check rest of message
249
250     if (GNUNET_MESSAGE_TYPE_PSYC_MESSAGE_END == type)
251       master_transmit ();
252     break;
253
254   case TEST_MASTER_TRANSMIT:
255     if (GNUNET_MESSAGE_TYPE_PSYC_MESSAGE_END == type && 2 == ++end_count)
256       master_history_replay_latest ();
257     break;
258
259   case TEST_MASTER_HISTORY_REPLAY:
260   case TEST_MASTER_HISTORY_REPLAY_LATEST:
261     if (GNUNET_PSYC_MESSAGE_HISTORIC != flags)
262     {
263       GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
264                   "Test #%d: Unexpected flags for historic message: %x" PRIu32 "\n",
265                   test, flags);
266       GNUNET_assert (0);
267       return;
268     }
269     break;
270
271   default:
272     GNUNET_assert (0);
273   }
274 }
275
276
277 static void
278 slave_message_cb (void *cls, const struct GNUNET_PSYC_MessageHeader *msg)
279 {
280   GNUNET_assert (NULL != msg);
281   GNUNET_log (GNUNET_ERROR_TYPE_INFO,
282               "Test #%d: Slave got PSYC message fragment of size %u "
283               "belonging to message ID %" PRIu64 " with flags %x\n",
284               test, ntohs (msg->header.size),
285               GNUNET_ntohll (msg->message_id), ntohl (msg->flags));
286   // FIXME
287 }
288
289
290 static void
291 slave_message_part_cb (void *cls,
292                        const struct GNUNET_PSYC_MessageHeader *msg,
293                        const struct GNUNET_MessageHeader *pmsg)
294 {
295   GNUNET_assert (NULL != msg && NULL != pmsg);
296
297   uint64_t message_id = GNUNET_ntohll (msg->message_id);
298   uint32_t flags = ntohl (msg->flags);
299
300   uint16_t type = ntohs (pmsg->type);
301   uint16_t size = ntohs (pmsg->size);
302
303   GNUNET_log (GNUNET_ERROR_TYPE_INFO,
304               "Test #%d: Slave got message part of type %u and size %u "
305               "belonging to message ID %" PRIu64 " with flags %x\n",
306               test, type, size, message_id, flags);
307
308   switch (test)
309   {
310   case TEST_MASTER_TRANSMIT:
311     if (GNUNET_MESSAGE_TYPE_PSYC_MESSAGE_END == type && 2 == ++end_count)
312       master_history_replay_latest ();
313     break;
314
315   case TEST_SLAVE_HISTORY_REPLAY:
316   case TEST_SLAVE_HISTORY_REPLAY_LATEST:
317     if (GNUNET_PSYC_MESSAGE_HISTORIC != flags)
318     {
319       GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
320                   "Test #%d: Unexpected flags for historic message: %x" PRIu32 "\n",
321                   test, flags);
322       GNUNET_assert (0);
323       return;
324     }
325     break;
326
327   default:
328     GNUNET_assert (0);
329   }
330 }
331
332
333 static void
334 state_get_var (void *cls, const struct GNUNET_MessageHeader *mod,
335                const char *name, const void *value,
336                uint32_t value_size, uint32_t full_value_size)
337 {
338   GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
339               "Got state var: %s\n%.*s\n",
340               name,
341               (int) value_size,
342               (const char *) value);
343 }
344
345
346 /*** Slave state_get_prefix() ***/
347
348 static void
349 slave_state_get_prefix_result (void *cls, int64_t result,
350                                const void *err_msg, uint16_t err_msg_size)
351 {
352   GNUNET_log (GNUNET_ERROR_TYPE_INFO,
353               "Test #%d: slave_state_get_prefix:\t%" PRId64 " (%.*s)\n",
354               test, result,
355               (int) err_msg_size,
356               (const char *) err_msg);
357   // FIXME: GNUNET_assert (2 == result);
358   end ();
359 }
360
361
362 static void
363 slave_state_get_prefix ()
364 {
365   test = TEST_SLAVE_STATE_GET_PREFIX;
366   GNUNET_PSYC_channel_state_get_prefix (slv_chn, "_foo", state_get_var,
367                                         slave_state_get_prefix_result, NULL);
368 }
369
370
371 /*** Master state_get_prefix() ***/
372
373
374 static void
375 master_state_get_prefix_result (void *cls, int64_t result,
376                                 const void *err_msg, uint16_t err_msg_size)
377 {
378   GNUNET_log (GNUNET_ERROR_TYPE_INFO,
379               "Test #%d: master_state_get_prefix:\t%" PRId64 " (%s)\n",
380               test, result, (char *) err_msg);
381   // FIXME: GNUNET_assert (2 == result);
382   slave_state_get_prefix ();
383 }
384
385
386 static void
387 master_state_get_prefix ()
388 {
389   test = TEST_MASTER_STATE_GET_PREFIX;
390   GNUNET_PSYC_channel_state_get_prefix (mst_chn, "_foo", state_get_var,
391                                         master_state_get_prefix_result, NULL);
392 }
393
394
395 /*** Slave state_get() ***/
396
397
398 static void
399 slave_state_get_result (void *cls, int64_t result,
400                         const void *err_msg, uint16_t err_msg_size)
401 {
402   GNUNET_log (GNUNET_ERROR_TYPE_INFO,
403               "Test #%d: slave_state_get:\t%" PRId64 " (%.*s)\n",
404               test, result, err_msg_size, (char *) err_msg);
405   // FIXME: GNUNET_assert (2 == result);
406   master_state_get_prefix ();
407 }
408
409
410 static void
411 slave_state_get ()
412 {
413   test = TEST_SLAVE_STATE_GET;
414   GNUNET_PSYC_channel_state_get (slv_chn, "_foo_bar_baz", state_get_var,
415                                  slave_state_get_result, NULL);
416 }
417
418
419 /*** Master state_get() ***/
420
421
422 static void
423 master_state_get_result (void *cls, int64_t result,
424                          const void *err_msg, uint16_t err_msg_size)
425 {
426   GNUNET_log (GNUNET_ERROR_TYPE_INFO,
427               "Test #%d: master_state_get:\t%" PRId64 " (%.*s)\n",
428               test, result, err_msg_size, (char *) err_msg);
429   // FIXME: GNUNET_assert (1 == result);
430   slave_state_get ();
431 }
432
433
434 static void
435 master_state_get ()
436 {
437   test = TEST_MASTER_STATE_GET;
438   GNUNET_PSYC_channel_state_get (mst_chn, "_foo_bar_baz", state_get_var,
439                                  master_state_get_result, NULL);
440 }
441
442
443 /*** Slave history_replay() ***/
444
445 static void
446 slave_history_replay_result (void *cls, int64_t result,
447                              const void *err_msg, uint16_t err_msg_size)
448 {
449   GNUNET_log (GNUNET_ERROR_TYPE_INFO,
450               "Test #%d: slave_history_replay:\t%" PRId64 " (%.*s)\n",
451               test, result,
452               (int) err_msg_size,
453               (const char *) err_msg);
454   GNUNET_assert (9 == result);
455
456   master_state_get ();
457 }
458
459
460 static void
461 slave_history_replay ()
462 {
463   test = TEST_SLAVE_HISTORY_REPLAY;
464   GNUNET_PSYC_channel_history_replay (slv_chn, 1, 1, "",
465                                       GNUNET_PSYC_HISTORY_REPLAY_LOCAL,
466                                       slave_message_cb,
467                                       slave_message_part_cb,
468                                       slave_history_replay_result, NULL);
469 }
470
471
472 /*** Master history_replay() ***/
473
474
475 static void
476 master_history_replay_result (void *cls, int64_t result,
477                               const void *err_msg, uint16_t err_msg_size)
478 {
479   GNUNET_log (GNUNET_ERROR_TYPE_INFO,
480               "Test #%d: master_history_replay:\t%" PRId64 " (%.*s)\n",
481               test, result,
482               (int) err_msg_size,
483               (const char *) err_msg);
484   GNUNET_assert (9 == result);
485
486   slave_history_replay ();
487 }
488
489
490 static void
491 master_history_replay ()
492 {
493   test = TEST_MASTER_HISTORY_REPLAY;
494   GNUNET_PSYC_channel_history_replay (mst_chn, 1, 1, "",
495                                       GNUNET_PSYC_HISTORY_REPLAY_LOCAL,
496                                       master_message_cb,
497                                       master_message_part_cb,
498                                       master_history_replay_result, NULL);
499 }
500
501
502 /*** Slave history_replay_latest() ***/
503
504
505 static void
506 slave_history_replay_latest_result (void *cls, int64_t result,
507                                     const void *err_msg, uint16_t err_msg_size)
508 {
509   GNUNET_log (GNUNET_ERROR_TYPE_INFO,
510               "Test #%d: slave_history_replay_latest:\t%" PRId64 " (%.*s)\n",
511               test, result,
512               (int) err_msg_size,
513               (const char *) err_msg);
514   GNUNET_assert (9 == result);
515
516   master_history_replay ();
517 }
518
519
520 static void
521 slave_history_replay_latest ()
522 {
523   test = TEST_SLAVE_HISTORY_REPLAY_LATEST;
524   GNUNET_PSYC_channel_history_replay_latest (slv_chn, 1, "",
525                                              GNUNET_PSYC_HISTORY_REPLAY_LOCAL,
526                                              &slave_message_cb,
527                                              &slave_message_part_cb,
528                                              &slave_history_replay_latest_result,
529                                              NULL);
530 }
531
532
533 /*** Master history_replay_latest() ***/
534
535
536 static void
537 master_history_replay_latest_result (void *cls, int64_t result,
538                                      const void *err_msg, uint16_t err_msg_size)
539 {
540   GNUNET_log (GNUNET_ERROR_TYPE_INFO,
541               "Test #%d: master_history_replay_latest:\t%" PRId64 " (%.*s)\n",
542               test, result, err_msg_size, (char *) err_msg);
543   GNUNET_assert (9 == result);
544
545   slave_history_replay_latest ();
546 }
547
548
549 static void
550 master_history_replay_latest ()
551 {
552   test = TEST_MASTER_HISTORY_REPLAY_LATEST;
553   GNUNET_PSYC_channel_history_replay_latest (mst_chn, 1, "",
554                                              GNUNET_PSYC_HISTORY_REPLAY_LOCAL,
555                                              &master_message_cb,
556                                              &master_message_part_cb,
557                                              &master_history_replay_latest_result,
558                                              NULL);
559 }
560
561
562 static void
563 transmit_resume (void *cls)
564 {
565   GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
566               "Test #%d: Transmission resumed.\n", test);
567   struct TransmitClosure *tmit = cls;
568   if (NULL != tmit->mst_tmit)
569     GNUNET_PSYC_master_transmit_resume (tmit->mst_tmit);
570   else
571     GNUNET_PSYC_slave_transmit_resume (tmit->slv_tmit);
572 }
573
574
575 static int
576 tmit_notify_data (void *cls, uint16_t *data_size, void *data)
577 {
578   struct TransmitClosure *tmit = cls;
579   if (0 == tmit->data_count)
580   {
581     *data_size = 0;
582     return GNUNET_YES;
583   }
584
585   uint16_t size = strlen (tmit->data[tmit->n]);
586   GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
587               "Test #%d: Transmit notify data: %u bytes available, "
588               "processing fragment %u/%u (size %u).\n",
589               test, *data_size, tmit->n + 1, tmit->data_count, size);
590   if (*data_size < size)
591   {
592     *data_size = 0;
593     GNUNET_assert (0);
594     return GNUNET_SYSERR;
595   }
596
597   if (GNUNET_YES != tmit->paused && 0 < tmit->data_delay[tmit->n])
598   {
599     GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
600                 "Test #%d: Transmission paused.\n", test);
601     tmit->paused = GNUNET_YES;
602     GNUNET_SCHEDULER_add_delayed (
603       GNUNET_TIME_relative_multiply (GNUNET_TIME_UNIT_SECONDS,
604                                      tmit->data_delay[tmit->n]),
605       &transmit_resume, tmit);
606     *data_size = 0;
607     return GNUNET_NO;
608   }
609   tmit->paused = GNUNET_NO;
610
611   *data_size = size;
612   GNUNET_memcpy (data, tmit->data[tmit->n], size);
613
614   return ++tmit->n < tmit->data_count ? GNUNET_NO : GNUNET_YES;
615 }
616
617
618 static int
619 tmit_notify_mod (void *cls, uint16_t *data_size, void *data, uint8_t *oper,
620                  uint32_t *full_value_size)
621 {
622   struct TransmitClosure *tmit = cls;
623   GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
624               "Test #%d: Transmit notify modifier: %u bytes available, "
625               "%u modifiers left to process.\n",
626               test, *data_size, (unsigned int) GNUNET_PSYC_env_get_count (tmit->env));
627
628   uint16_t name_size = 0;
629   size_t value_size = 0;
630   const char *value = NULL;
631
632   if (NULL != oper && NULL != tmit->mod)
633   { /* New modifier */
634     tmit->mod = tmit->mod->next;
635     if (NULL == tmit->mod)
636     { /* No more modifiers, continue with data */
637       *data_size = 0;
638       return GNUNET_YES;
639     }
640
641     GNUNET_assert (tmit->mod->value_size < UINT32_MAX);
642     *full_value_size = tmit->mod->value_size;
643     *oper = tmit->mod->oper;
644     name_size = strlen (tmit->mod->name);
645
646     if (name_size + 1 + tmit->mod->value_size <= *data_size)
647     {
648       *data_size = name_size + 1 + tmit->mod->value_size;
649     }
650     else
651     {
652       tmit->mod_value_size = tmit->mod->value_size;
653       value_size = *data_size - name_size - 1;
654       tmit->mod_value_size -= value_size;
655       tmit->mod_value = tmit->mod->value + value_size;
656     }
657
658     GNUNET_memcpy (data, tmit->mod->name, name_size);
659     ((char *)data)[name_size] = '\0';
660     GNUNET_memcpy ((char *)data + name_size + 1, tmit->mod->value, value_size);
661   }
662   else if (NULL != tmit->mod_value && 0 < tmit->mod_value_size)
663   { /* Modifier continuation */
664     value = tmit->mod_value;
665     if (tmit->mod_value_size <= *data_size)
666     {
667       value_size = tmit->mod_value_size;
668       tmit->mod_value = NULL;
669     }
670     else
671     {
672       value_size = *data_size;
673       tmit->mod_value += value_size;
674     }
675     tmit->mod_value_size -= value_size;
676
677     if (*data_size < value_size)
678     {
679       GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
680                   "value larger than buffer: %u < %zu\n",
681                   *data_size, value_size);
682       *data_size = 0;
683       return GNUNET_NO;
684     }
685
686     *data_size = value_size;
687     GNUNET_memcpy (data, value, value_size);
688   }
689
690   return GNUNET_NO;
691 }
692
693
694 static void
695 slave_join ();
696
697
698 static void
699 slave_transmit ()
700 {
701   test = TEST_SLAVE_TRANSMIT;
702   GNUNET_log (GNUNET_ERROR_TYPE_INFO,
703               "Test #%d: Slave sending request to master.\n", test);
704
705   tmit = GNUNET_new (struct TransmitClosure);
706   tmit->env = GNUNET_PSYC_env_create ();
707   GNUNET_PSYC_env_add (tmit->env, GNUNET_PSYC_OP_ASSIGN,
708                               "_abc", "abc def", 7);
709   GNUNET_PSYC_env_add (tmit->env, GNUNET_PSYC_OP_ASSIGN,
710                               "_abc_def", "abc def ghi", 11);
711   tmit->mod = GNUNET_PSYC_env_head (tmit->env);
712   tmit->n = 0;
713   tmit->data[0] = "slave test";
714   tmit->data_count = 1;
715   tmit->slv_tmit
716     = GNUNET_PSYC_slave_transmit (slv, "_request_test", &tmit_notify_mod,
717                                   &tmit_notify_data, tmit,
718                                   GNUNET_PSYC_SLAVE_TRANSMIT_NONE);
719 }
720
721
722 static void
723 slave_remove_cb (void *cls, int64_t result,
724                  const void *err_msg, uint16_t err_msg_size)
725 {
726   GNUNET_log (GNUNET_ERROR_TYPE_INFO,
727               "Test #%d: slave_remove:\t%" PRId64 " (%.*s)\n",
728               test, result, err_msg_size, (char *) err_msg);
729
730   slave_transmit ();
731 }
732
733
734 static void
735 slave_remove ()
736 {
737   test = TEST_SLAVE_REMOVE;
738   struct GNUNET_PSYC_Channel *chn = GNUNET_PSYC_master_get_channel (mst);
739   GNUNET_PSYC_channel_slave_remove (chn, &slave_pub_key, 2,
740                                     &slave_remove_cb, chn);
741 }
742
743
744 static void
745 slave_add_cb (void *cls, int64_t result,
746               const void *err_msg, uint16_t err_msg_size)
747 {
748   GNUNET_log (GNUNET_ERROR_TYPE_INFO,
749               "Test #%d: slave_add:\t%" PRId64 " (%.*s)\n",
750               test, result, err_msg_size, (char *) err_msg);
751   slave_remove ();
752 }
753
754
755 static void
756 slave_add ()
757 {
758   test = TEST_SLAVE_ADD;
759   struct GNUNET_PSYC_Channel *chn = GNUNET_PSYC_master_get_channel (mst);
760   GNUNET_PSYC_channel_slave_add (chn, &slave_pub_key, 2, 2, &slave_add_cb, chn);
761 }
762
763
764 static void
765 first_slave_parted (void *cls)
766 {
767   GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "First slave parted.\n");
768   slave_join (TEST_SLAVE_JOIN_ACCEPT);
769 }
770
771
772 static void
773 schedule_slave_part (void *cls)
774 {
775   GNUNET_PSYC_slave_part (slv, GNUNET_NO, &first_slave_parted, NULL);
776 }
777
778
779 static void
780 join_decision_cb (void *cls,
781                   const struct GNUNET_PSYC_JoinDecisionMessage *dcsn,
782                   int is_admitted,
783                   const struct GNUNET_PSYC_Message *join_msg)
784 {
785   GNUNET_log (GNUNET_ERROR_TYPE_INFO,
786               "Test #%d: Slave got join decision: %d\n", test, is_admitted);
787
788   switch (test)
789   {
790   case TEST_SLAVE_JOIN_REJECT:
791     GNUNET_assert (0 == is_admitted);
792     GNUNET_assert (1 == join_req_count);
793     GNUNET_SCHEDULER_add_now (&schedule_slave_part, NULL);
794     break;
795
796   case TEST_SLAVE_JOIN_ACCEPT:
797     GNUNET_assert (1 == is_admitted);
798     GNUNET_assert (2 == join_req_count);
799     slave_add ();
800     break;
801
802   default:
803     GNUNET_break (0);
804   }
805 }
806
807
808 static void
809 join_request_cb (void *cls,
810                  const struct GNUNET_PSYC_JoinRequestMessage *req,
811                  const struct GNUNET_CRYPTO_EcdsaPublicKey *slave_key,
812                  const struct GNUNET_PSYC_Message *join_msg,
813                  struct GNUNET_PSYC_JoinHandle *jh)
814 {
815   struct GNUNET_HashCode slave_key_hash;
816   GNUNET_CRYPTO_hash (slave_key, sizeof (*slave_key), &slave_key_hash);
817   GNUNET_log (GNUNET_ERROR_TYPE_INFO,
818               "Test #%d: Got join request #%u from %s.\n",
819               test, join_req_count, GNUNET_h2s (&slave_key_hash));
820
821   /* Reject first request */
822   int is_admitted = (0 < join_req_count++) ? GNUNET_YES : GNUNET_NO;
823   GNUNET_PSYC_join_decision (jh, is_admitted, 0, NULL, NULL);
824 }
825
826
827 static void
828 slave_connect_cb (void *cls, int result, uint64_t max_message_id)
829 {
830   GNUNET_log (GNUNET_ERROR_TYPE_INFO,
831               "Test #%d: Slave connected: %d, max_message_id: %" PRIu64 "\n",
832               test, result, max_message_id);
833   GNUNET_assert (TEST_SLAVE_JOIN_REJECT == test || TEST_SLAVE_JOIN_ACCEPT == test);
834   GNUNET_assert (GNUNET_OK == result || GNUNET_NO == result);
835 }
836
837
838 static void
839 slave_join (int t)
840 {
841   test = t;
842   GNUNET_log (GNUNET_ERROR_TYPE_INFO,
843               "Test #%d: Joining slave.\n", t);
844
845   struct GNUNET_PeerIdentity origin = this_peer;
846   struct GNUNET_PSYC_Environment *env = GNUNET_PSYC_env_create ();
847   GNUNET_PSYC_env_add (env, GNUNET_PSYC_OP_ASSIGN,
848                               "_foo", "bar baz", 7);
849   GNUNET_PSYC_env_add (env, GNUNET_PSYC_OP_ASSIGN,
850                               "_foo_bar", "foo bar baz", 11);
851   struct GNUNET_PSYC_Message *
852     join_msg = GNUNET_PSYC_message_create ("_request_join", env, "some data", 9);
853
854   slv = GNUNET_PSYC_slave_join (cfg, &channel_pub_key, slave_key,
855                                 GNUNET_PSYC_SLAVE_JOIN_NONE,
856                                 &origin, 0, NULL,
857                                 &slave_message_cb, &slave_message_part_cb,
858                                 &slave_connect_cb, &join_decision_cb, NULL,
859                                 join_msg);
860   GNUNET_free (join_msg);
861   slv_chn = GNUNET_PSYC_slave_get_channel (slv);
862   GNUNET_PSYC_env_destroy (env);
863 }
864
865
866 static void
867 master_transmit ()
868 {
869   test = TEST_MASTER_TRANSMIT;
870   GNUNET_log (GNUNET_ERROR_TYPE_INFO,
871               "Test #%d: Master sending message to all.\n", test);
872   end_count = 0;
873
874   uint32_t i, j;
875
876   char *name_max = "_test_max";
877   uint8_t name_max_size = sizeof ("_test_max");
878   char *val_max = GNUNET_malloc (GNUNET_PSYC_MODIFIER_MAX_PAYLOAD);
879   for (i = 0; i < GNUNET_PSYC_MODIFIER_MAX_PAYLOAD; i++)
880     val_max[i] = (0 == i % 10000) ? '0' + i / 10000 : '.';
881
882   char *name_cont = "_test_cont";
883   uint8_t name_cont_size = sizeof ("_test_cont");
884   char *val_cont = GNUNET_malloc (GNUNET_PSYC_MODIFIER_MAX_PAYLOAD
885                                   + GNUNET_PSYC_MOD_CONT_MAX_PAYLOAD);
886   for (i = 0; i < GNUNET_PSYC_MODIFIER_MAX_PAYLOAD - name_cont_size; i++)
887     val_cont[i] = (0 == i % 10000) ? '0' + i / 10000 : ':';
888   for (j = 0; j < GNUNET_PSYC_MOD_CONT_MAX_PAYLOAD; j++, i++)
889     val_cont[i] = (0 == j % 10000) ? '0' + j / 10000 : '!';
890
891   tmit = GNUNET_new (struct TransmitClosure);
892   tmit->env = GNUNET_PSYC_env_create ();
893   GNUNET_PSYC_env_add (tmit->env, GNUNET_PSYC_OP_ASSIGN,
894                               "_foo", "bar baz", 7);
895   GNUNET_PSYC_env_add (tmit->env, GNUNET_PSYC_OP_ASSIGN,
896                               name_max, val_max,
897                               GNUNET_PSYC_MODIFIER_MAX_PAYLOAD
898                               - name_max_size);
899   GNUNET_PSYC_env_add (tmit->env, GNUNET_PSYC_OP_ASSIGN,
900                               "_foo_bar", "foo bar baz", 11);
901   GNUNET_PSYC_env_add (tmit->env, GNUNET_PSYC_OP_ASSIGN,
902                               name_cont, val_cont,
903                               GNUNET_PSYC_MODIFIER_MAX_PAYLOAD - name_cont_size
904                               + GNUNET_PSYC_MOD_CONT_MAX_PAYLOAD);
905   tmit->mod = GNUNET_PSYC_env_head (tmit->env);
906   tmit->data[0] = "foo";
907   tmit->data[1] =  GNUNET_malloc (GNUNET_PSYC_DATA_MAX_PAYLOAD + 1);
908   for (i = 0; i < GNUNET_PSYC_DATA_MAX_PAYLOAD; i++)
909     tmit->data[1][i] = (0 == i % 10000) ? '0' + i / 10000 : '_';
910   tmit->data[2] = "foo bar";
911   tmit->data[3] = "foo bar baz";
912   tmit->data_delay[1] = 3;
913   tmit->data_count = 4;
914   tmit->mst_tmit
915     = GNUNET_PSYC_master_transmit (mst, "_notice_test", &tmit_notify_mod,
916                                    &tmit_notify_data, tmit,
917                                    GNUNET_PSYC_MASTER_TRANSMIT_INC_GROUP_GEN);
918 }
919
920
921 static void
922 master_start_cb (void *cls, int result, uint64_t max_message_id)
923 {
924   GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
925               "Test #%d: Master started: %d, max_message_id: %" PRIu64 "\n",
926               test, result, max_message_id);
927   GNUNET_assert (TEST_MASTER_START == test);
928   GNUNET_assert (GNUNET_OK == result || GNUNET_NO == result);
929   slave_join (TEST_SLAVE_JOIN_REJECT);
930 }
931
932
933 static void
934 master_start ()
935 {
936   test = TEST_MASTER_START;
937   GNUNET_log (GNUNET_ERROR_TYPE_INFO,
938               "Test #%d: Starting master.\n", test);
939   mst = GNUNET_PSYC_master_start (cfg, channel_key, GNUNET_PSYC_CHANNEL_PRIVATE,
940                                   &master_start_cb, &join_request_cb,
941                                   &master_message_cb, &master_message_part_cb,
942                                   NULL);
943   mst_chn = GNUNET_PSYC_master_get_channel (mst);
944 }
945
946
947 static void
948 schedule_master_start (void *cls)
949 {
950   master_start ();
951 }
952
953
954 static void
955 core_connected (void *cls, const struct GNUNET_PeerIdentity *my_identity)
956 {
957   this_peer = *my_identity;
958
959 #if DEBUG_TEST_PSYC
960   master_start ();
961 #else
962   /* Allow some time for the services to initialize. */
963   GNUNET_SCHEDULER_add_delayed (GNUNET_TIME_UNIT_SECONDS,
964                                 &schedule_master_start, NULL);
965 #endif
966
967 }
968
969 /**
970  * Main function of the test, run from scheduler.
971  *
972  * @param cls NULL
973  * @param cfg configuration we use (also to connect to PSYC service)
974  * @param peer handle to access more of the peer (not used)
975  */
976 static void
977 #if DEBUG_TEST_PSYC
978 run (void *cls, char *const *args, const char *cfgfile,
979      const struct GNUNET_CONFIGURATION_Handle *c)
980 #else
981 run (void *cls,
982      const struct GNUNET_CONFIGURATION_Handle *c,
983      struct GNUNET_TESTING_Peer *peer)
984 #endif
985 {
986   cfg = c;
987   end_badly_task = GNUNET_SCHEDULER_add_delayed (TIMEOUT, &end_badly, NULL);
988
989   channel_key = GNUNET_CRYPTO_eddsa_key_create ();
990   slave_key = GNUNET_CRYPTO_ecdsa_key_create ();
991
992   GNUNET_CRYPTO_eddsa_key_get_public (channel_key, &channel_pub_key);
993   GNUNET_CRYPTO_ecdsa_key_get_public (slave_key, &slave_pub_key);
994
995   core = GNUNET_CORE_connecT (cfg, NULL, &core_connected, NULL, NULL, NULL);
996 }
997
998
999 int
1000 main (int argc, char *argv[])
1001 {
1002   res = 1;
1003 #if DEBUG_TEST_PSYC
1004   const struct GNUNET_GETOPT_CommandLineOption opts[] = {
1005     GNUNET_GETOPT_OPTION_END
1006   };
1007   if (GNUNET_OK != GNUNET_PROGRAM_run (argc, argv, "test-psyc",
1008                                        "test-psyc [options]",
1009                                        opts, &run, NULL))
1010     return 1;
1011 #else
1012   if (0 != GNUNET_TESTING_peer_run ("test-psyc", "test_psyc.conf", &run, NULL))
1013     return 1;
1014 #endif
1015   return res;
1016 }
1017
1018 /* end of test_psyc.c */