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