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