ba31d9329e0f0a96a11fbec5dca94b8710fe9e4d
[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., 59 Temple Place - Suite 330,
18  * Boston, MA 02111-1307, 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, uint64_t message_id,
217                         uint64_t data_offset, uint32_t flags,
218                         const struct GNUNET_MessageHeader *msg)
219 {
220   if (NULL == msg)
221   {
222     GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
223                 "Error while receiving message %" PRIu64 "\n", message_id);
224     return;
225   }
226
227   uint16_t type = ntohs (msg->type);
228   uint16_t size = ntohs (msg->size);
229
230   GNUNET_log (GNUNET_ERROR_TYPE_WARNING,
231               "Test #%d: Master got message part of type %u and size %u "
232               "belonging to message ID %" PRIu64 " with flags %x\n",
233               test, type, size, message_id, flags);
234
235   switch (test)
236   {
237   case TEST_SLAVE_TRANSMIT:
238     if (GNUNET_PSYC_MESSAGE_REQUEST != flags)
239     {
240       GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
241                   "Unexpected request flags: %x" PRIu32 "\n", flags);
242       GNUNET_assert (0);
243       return;
244     }
245     // FIXME: check rest of message
246
247     if (GNUNET_MESSAGE_TYPE_PSYC_MESSAGE_END == type)
248       master_transmit ();
249     break;
250
251   case TEST_MASTER_TRANSMIT:
252     if (GNUNET_MESSAGE_TYPE_PSYC_MESSAGE_END == type && 2 == ++end_count)
253       master_history_replay_latest ();
254     break;
255
256   case TEST_MASTER_HISTORY_REPLAY:
257   case TEST_MASTER_HISTORY_REPLAY_LATEST:
258     if (GNUNET_PSYC_MESSAGE_HISTORIC != flags)
259     {
260       GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
261                   "Test #%d: Unexpected flags for historic message: %x" PRIu32 "\n",
262                   test, flags);
263       GNUNET_assert (0);
264       return;
265     }
266     break;
267
268   default:
269     GNUNET_assert (0);
270   }
271 }
272
273
274 void
275 slave_message_cb (void *cls, uint64_t message_id, uint32_t flags,
276                   const struct GNUNET_PSYC_MessageHeader *msg)
277 {
278   GNUNET_log (GNUNET_ERROR_TYPE_WARNING,
279               "Test #%d: Slave got PSYC message fragment of size %u "
280               "belonging to message ID %" PRIu64 " with flags %x\n",
281               test, ntohs (msg->header.size), message_id, flags);
282   // FIXME
283 }
284
285
286 void
287 slave_message_part_cb (void *cls, uint64_t message_id,
288                        uint64_t data_offset, uint32_t flags,
289                        const struct GNUNET_MessageHeader *msg)
290 {
291   if (NULL == msg)
292   {
293     GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
294                 "Error while receiving message " PRIu64 "\n", message_id);
295     return;
296   }
297
298   uint16_t type = ntohs (msg->type);
299   uint16_t size = ntohs (msg->size);
300
301   GNUNET_log (GNUNET_ERROR_TYPE_WARNING,
302               "Test #%d: Slave got message part of type %u and size %u "
303               "belonging to message ID %" PRIu64 " with flags %x\n",
304               test, type, size, message_id, flags);
305
306   switch (test)
307   {
308   case TEST_MASTER_TRANSMIT:
309     if (GNUNET_MESSAGE_TYPE_PSYC_MESSAGE_END == type && 2 == ++end_count)
310       master_history_replay_latest ();
311     break;
312
313   case TEST_SLAVE_HISTORY_REPLAY:
314   case TEST_SLAVE_HISTORY_REPLAY_LATEST:
315     if (GNUNET_PSYC_MESSAGE_HISTORIC != flags)
316     {
317       GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
318                   "Test #%d: Unexpected flags for historic message: %x" PRIu32 "\n",
319                   flags);
320       GNUNET_assert (0);
321       return;
322     }
323     break;
324
325   default:
326     GNUNET_assert (0);
327   }
328 }
329
330
331 void
332 state_get_var (void *cls, const char *name, const void *value, size_t value_size)
333 {
334   GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
335               "Got state var: %s\n%.*s\n", name, value_size, value);
336 }
337
338
339 /*** Slave state_get_prefix() ***/
340
341 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_WARNING,
346               "slave_state_get_prefix:\t%" PRId64 " (%.s)\n",
347               result, err_msg_size, err_msg);
348   // FIXME: GNUNET_assert (2 == result);
349   end ();
350 }
351
352
353 void
354 slave_state_get_prefix ()
355 {
356   test = TEST_SLAVE_STATE_GET_PREFIX;
357   GNUNET_PSYC_channel_state_get_prefix (slv_chn, "_foo", &state_get_var,
358                                         &slave_state_get_prefix_result, NULL);
359 }
360
361
362 /*** Master state_get_prefix() ***/
363
364
365 void
366 master_state_get_prefix_result (void *cls, int64_t result,
367                                 const void *err_msg, uint16_t err_msg_size)
368 {
369   GNUNET_log (GNUNET_ERROR_TYPE_WARNING,
370               "master_state_get_prefix:\t%" PRId64 " (%s)\n", result, err_msg);
371   // FIXME: GNUNET_assert (2 == result);
372   slave_state_get_prefix ();
373 }
374
375
376 void
377 master_state_get_prefix ()
378 {
379   test = TEST_MASTER_STATE_GET_PREFIX;
380   GNUNET_PSYC_channel_state_get_prefix (mst_chn, "_foo", &state_get_var,
381                                         &master_state_get_prefix_result, NULL);
382 }
383
384
385 /*** Slave state_get() ***/
386
387
388 void
389 slave_state_get_result (void *cls, int64_t result,
390                         const void *err_msg, uint16_t err_msg_size)
391 {
392   GNUNET_log (GNUNET_ERROR_TYPE_WARNING,
393               "slave_state_get:\t%" PRId64 " (%.*s)\n",
394               result, err_msg_size, err_msg);
395   // FIXME: GNUNET_assert (2 == result);
396   master_state_get_prefix ();
397 }
398
399
400 void
401 slave_state_get ()
402 {
403   test = TEST_SLAVE_STATE_GET;
404   GNUNET_PSYC_channel_state_get (slv_chn, "_foo_bar_baz", &state_get_var,
405                                  &slave_state_get_result, NULL);
406 }
407
408
409 /*** Master state_get() ***/
410
411
412 void
413 master_state_get_result (void *cls, int64_t result,
414                          const void *err_msg, uint16_t err_msg_size)
415 {
416   GNUNET_log (GNUNET_ERROR_TYPE_WARNING,
417               "master_state_get:\t%" PRId64 " (%.*s)\n",
418               result, err_msg_size, err_msg);
419   // FIXME: GNUNET_assert (1 == result);
420   slave_state_get ();
421 }
422
423
424 void
425 master_state_get ()
426 {
427   test = TEST_MASTER_STATE_GET;
428   GNUNET_PSYC_channel_state_get (mst_chn, "_foo_bar_baz", &state_get_var,
429                                  &master_state_get_result, NULL);
430 }
431
432
433 /*** Slave history_replay() ***/
434
435 void
436 slave_history_replay_result (void *cls, int64_t result,
437                              const void *err_msg, uint16_t err_msg_size)
438 {
439   GNUNET_log (GNUNET_ERROR_TYPE_WARNING,
440               "slave_history_replay:\t%" PRId64 " (%.*s)\n",
441               result, err_msg_size, err_msg);
442   GNUNET_assert (9 == result);
443
444   master_state_get ();
445 }
446
447
448 void
449 slave_history_replay ()
450 {
451   test = TEST_SLAVE_HISTORY_REPLAY;
452   GNUNET_PSYC_channel_history_replay (slv_chn, 1, 1, "",
453                                       GNUNET_PSYC_HISTORY_REPLAY_LOCAL,
454                                       &slave_message_cb,
455                                       &slave_message_part_cb,
456                                       &slave_history_replay_result, NULL);
457 }
458
459
460 /*** Master history_replay() ***/
461
462
463 void
464 master_history_replay_result (void *cls, int64_t result,
465                               const void *err_msg, uint16_t err_msg_size)
466 {
467   GNUNET_log (GNUNET_ERROR_TYPE_WARNING,
468               "master_history_replay:\t%" PRId64 " (%.*s)\n",
469               result, err_msg_size, err_msg);
470   GNUNET_assert (9 == result);
471
472   slave_history_replay ();
473 }
474
475
476 void
477 master_history_replay ()
478 {
479   test = TEST_MASTER_HISTORY_REPLAY;
480   GNUNET_PSYC_channel_history_replay (mst_chn, 1, 1, "",
481                                       GNUNET_PSYC_HISTORY_REPLAY_LOCAL,
482                                       &master_message_cb,
483                                       &master_message_part_cb,
484                                       &master_history_replay_result, NULL);
485 }
486
487
488 /*** Slave history_replay_latest() ***/
489
490
491 void
492 slave_history_replay_latest_result (void *cls, int64_t result,
493                                     const void *err_msg, uint16_t err_msg_size)
494 {
495   GNUNET_log (GNUNET_ERROR_TYPE_WARNING,
496               "slave_history_replay_latest:\t%" PRId64 " (%.*s)\n",
497               result, err_msg_size, err_msg);
498   GNUNET_assert (9 == result);
499
500   master_history_replay ();
501 }
502
503
504 void
505 slave_history_replay_latest ()
506 {
507   test = TEST_SLAVE_HISTORY_REPLAY_LATEST;
508   GNUNET_PSYC_channel_history_replay_latest (slv_chn, 1, "",
509                                              GNUNET_PSYC_HISTORY_REPLAY_LOCAL,
510                                              &slave_message_cb,
511                                              &slave_message_part_cb,
512                                              &slave_history_replay_latest_result,
513                                              NULL);
514 }
515
516
517 /*** Master history_replay_latest() ***/
518
519
520 void
521 master_history_replay_latest_result (void *cls, int64_t result,
522                                      const void *err_msg, uint16_t err_msg_size)
523 {
524   GNUNET_log (GNUNET_ERROR_TYPE_WARNING,
525               "master_history_replay_latest:\t%" PRId64 " (%.*s)\n",
526               result, err_msg_size, err_msg);
527   GNUNET_assert (9 == result);
528
529   slave_history_replay_latest ();
530 }
531
532
533 void
534 master_history_replay_latest ()
535 {
536   test = TEST_MASTER_HISTORY_REPLAY_LATEST;
537   GNUNET_PSYC_channel_history_replay_latest (mst_chn, 1, "",
538                                              GNUNET_PSYC_HISTORY_REPLAY_LOCAL,
539                                              &master_message_cb,
540                                              &master_message_part_cb,
541                                              &master_history_replay_latest_result,
542                                              NULL);
543 }
544
545
546 void
547 transmit_resume (void *cls, const struct GNUNET_SCHEDULER_TaskContext *tc)
548 {
549   GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "Transmission resumed.\n");
550   struct TransmitClosure *tmit = cls;
551   if (NULL != tmit->mst_tmit)
552     GNUNET_PSYC_master_transmit_resume (tmit->mst_tmit);
553   else
554     GNUNET_PSYC_slave_transmit_resume (tmit->slv_tmit);
555 }
556
557
558 int
559 tmit_notify_data (void *cls, uint16_t *data_size, void *data)
560 {
561   struct TransmitClosure *tmit = cls;
562   if (0 == tmit->data_count)
563   {
564     *data_size = 0;
565     return GNUNET_YES;
566   }
567
568   uint16_t size = strlen (tmit->data[tmit->n]);
569   GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
570               "Transmit notify data: %u bytes available, "
571               "processing fragment %u/%u (size %u).\n",
572               *data_size, tmit->n + 1, tmit->data_count, size);
573   if (*data_size < size)
574   {
575     *data_size = 0;
576     GNUNET_assert (0);
577     return GNUNET_SYSERR;
578   }
579
580   if (GNUNET_YES != tmit->paused && 0 < tmit->data_delay[tmit->n])
581   {
582     GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "Transmission paused.\n");
583     tmit->paused = GNUNET_YES;
584     GNUNET_SCHEDULER_add_delayed (
585       GNUNET_TIME_relative_multiply (GNUNET_TIME_UNIT_SECONDS,
586                                      tmit->data_delay[tmit->n]),
587       &transmit_resume, tmit);
588     *data_size = 0;
589     return GNUNET_NO;
590   }
591   tmit->paused = GNUNET_NO;
592
593   *data_size = size;
594   memcpy (data, tmit->data[tmit->n], size);
595
596   return ++tmit->n < tmit->data_count ? GNUNET_NO : GNUNET_YES;
597 }
598
599
600 int
601 tmit_notify_mod (void *cls, uint16_t *data_size, void *data, uint8_t *oper,
602                  uint32_t *full_value_size)
603 {
604   struct TransmitClosure *tmit = cls;
605   GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
606               "Transmit notify modifier: %lu bytes available, "
607               "%u modifiers left to process.\n",
608               *data_size, GNUNET_ENV_environment_get_count (tmit->env));
609
610   uint16_t name_size = 0;
611   size_t value_size = 0;
612   const char *value = NULL;
613
614   if (NULL != oper && NULL != tmit->mod)
615   { /* New modifier */
616     tmit->mod = tmit->mod->next;
617     if (NULL == tmit->mod)
618     { /* No more modifiers, continue with data */
619       *data_size = 0;
620       return GNUNET_YES;
621     }
622
623     GNUNET_assert (tmit->mod->value_size < UINT32_MAX);
624     *full_value_size = tmit->mod->value_size;
625     *oper = tmit->mod->oper;
626     name_size = strlen (tmit->mod->name);
627
628     if (name_size + 1 + tmit->mod->value_size <= *data_size)
629     {
630       *data_size = name_size + 1 + tmit->mod->value_size;
631     }
632     else
633     {
634       tmit->mod_value_size = tmit->mod->value_size;
635       value_size = *data_size - name_size - 1;
636       tmit->mod_value_size -= value_size;
637       tmit->mod_value = tmit->mod->value + value_size;
638     }
639
640     memcpy (data, tmit->mod->name, name_size);
641     ((char *)data)[name_size] = '\0';
642     memcpy ((char *)data + name_size + 1, tmit->mod->value, value_size);
643   }
644   else if (NULL != tmit->mod_value && 0 < tmit->mod_value_size)
645   { /* Modifier continuation */
646     value = tmit->mod_value;
647     if (tmit->mod_value_size <= *data_size)
648     {
649       value_size = tmit->mod_value_size;
650       tmit->mod_value = NULL;
651     }
652     else
653     {
654       value_size = *data_size;
655       tmit->mod_value += value_size;
656     }
657     tmit->mod_value_size -= value_size;
658
659     if (*data_size < value_size)
660     {
661       GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
662                   "value larger than buffer: %u < %zu\n",
663                   *data_size, value_size);
664       *data_size = 0;
665       return GNUNET_NO;
666     }
667
668     *data_size = value_size;
669     memcpy (data, value, value_size);
670   }
671
672   return GNUNET_NO;
673 }
674
675
676 static void
677 slave_join ();
678
679
680 void
681 slave_transmit ()
682 {
683
684   GNUNET_log (GNUNET_ERROR_TYPE_WARNING, "Slave sending request to master.\n");
685   test = TEST_SLAVE_TRANSMIT;
686
687   tmit = GNUNET_new (struct TransmitClosure);
688   tmit->env = GNUNET_ENV_environment_create ();
689   GNUNET_ENV_environment_add (tmit->env, GNUNET_ENV_OP_ASSIGN,
690                               "_abc", "abc def", 7);
691   GNUNET_ENV_environment_add (tmit->env, GNUNET_ENV_OP_ASSIGN,
692                               "_abc_def", "abc def ghi", 11);
693   tmit->mod = GNUNET_ENV_environment_head (tmit->env);
694   tmit->n = 0;
695   tmit->data[0] = "slave test";
696   tmit->data_count = 1;
697   tmit->slv_tmit
698     = GNUNET_PSYC_slave_transmit (slv, "_request_test", &tmit_notify_mod,
699                                   &tmit_notify_data, tmit,
700                                   GNUNET_PSYC_SLAVE_TRANSMIT_NONE);
701 }
702
703
704 void
705 slave_remove_cb (void *cls, int64_t result,
706                  const void *err_msg, uint16_t err_msg_size)
707 {
708   GNUNET_log (GNUNET_ERROR_TYPE_WARNING,
709               "slave_remove:\t%" PRId64 " (%.*s)\n",
710               result, err_msg_size, err_msg);
711
712   slave_transmit ();
713 }
714
715
716 void
717 slave_add_cb (void *cls, int64_t result,
718               const void *err_msg, uint16_t err_msg_size)
719 {
720   GNUNET_log (GNUNET_ERROR_TYPE_WARNING,
721               "slave_add:\t%" PRId64 " (%.*s)\n",
722               result, err_msg_size, err_msg);
723
724   struct GNUNET_PSYC_Channel *chn = cls;
725   GNUNET_PSYC_channel_slave_remove (chn, &slave_pub_key, 2,
726                                     &slave_remove_cb, chn);
727
728 }
729
730
731 static void
732 join_decision_cb (void *cls,
733                   const struct GNUNET_PSYC_JoinDecisionMessage *dcsn,
734                   int is_admitted,
735                   const struct GNUNET_PSYC_Message *join_msg)
736 {
737   GNUNET_log (GNUNET_ERROR_TYPE_WARNING,
738               "Slave got join decision: %d\n", is_admitted);
739
740   if (GNUNET_YES != is_admitted)
741   { /* First join request is refused, retry. */
742     GNUNET_assert (1 == join_req_count);
743     slave_join ();
744     return;
745   }
746
747   struct GNUNET_PSYC_Channel *chn = GNUNET_PSYC_master_get_channel (mst);
748   GNUNET_PSYC_channel_slave_add (chn, &slave_pub_key, 2, 2, &slave_add_cb, chn);
749 }
750
751
752 static void
753 join_request_cb (void *cls,
754                  const struct GNUNET_PSYC_JoinRequestMessage *req,
755                  const struct GNUNET_CRYPTO_EcdsaPublicKey *slave_key,
756                  const struct GNUNET_PSYC_Message *join_msg,
757                  struct GNUNET_PSYC_JoinHandle *jh)
758 {
759   struct GNUNET_HashCode slave_key_hash;
760   GNUNET_CRYPTO_hash (slave_key, sizeof (*slave_key), &slave_key_hash);
761   GNUNET_log (GNUNET_ERROR_TYPE_WARNING,
762               "Got join request #%u from %s.\n",
763               join_req_count, GNUNET_h2s (&slave_key_hash));
764
765   /* Reject first request */
766   int is_admitted = (0 < join_req_count++) ? GNUNET_YES : GNUNET_NO;
767   GNUNET_PSYC_join_decision (jh, is_admitted, 0, NULL, NULL);
768 }
769
770
771 static void
772 slave_connect_cb (void *cls, int result, uint64_t max_message_id)
773 {
774   GNUNET_log (GNUNET_ERROR_TYPE_WARNING,
775               "Slave connected: %d, max_message_id: %" PRIu64 "\n",
776               result, max_message_id);
777   GNUNET_assert (TEST_SLAVE_JOIN == test);
778   GNUNET_assert (GNUNET_OK == result || GNUNET_NO == result);
779 }
780
781
782 static void
783 slave_join ()
784 {
785   GNUNET_log (GNUNET_ERROR_TYPE_WARNING, "Joining slave.\n");
786   test = TEST_SLAVE_JOIN;
787
788   struct GNUNET_PeerIdentity origin = this_peer;
789   struct GNUNET_ENV_Environment *env = GNUNET_ENV_environment_create ();
790   GNUNET_ENV_environment_add (env, GNUNET_ENV_OP_ASSIGN,
791                               "_foo", "bar baz", 7);
792   GNUNET_ENV_environment_add (env, GNUNET_ENV_OP_ASSIGN,
793                               "_foo_bar", "foo bar baz", 11);
794   struct GNUNET_PSYC_Message *
795     join_msg = GNUNET_PSYC_message_create ("_request_join", env, "some data", 9);
796
797   slv = GNUNET_PSYC_slave_join (cfg, &channel_pub_key, slave_key, &origin, 0, NULL,
798                                 &slave_message_cb, &slave_message_part_cb,
799                                 &slave_connect_cb, &join_decision_cb, NULL,
800                                 join_msg);
801   GNUNET_free (join_msg);
802   slv_chn = GNUNET_PSYC_slave_get_channel (slv);
803   GNUNET_ENV_environment_destroy (env);
804 }
805
806
807 void
808 master_transmit ()
809 {
810   GNUNET_log (GNUNET_ERROR_TYPE_WARNING, "Master sending message to all.\n");
811   test = TEST_MASTER_TRANSMIT;
812   end_count = 0;
813
814   uint32_t i, j;
815
816   char *name_max = "_test_max";
817   uint8_t name_max_size = sizeof ("_test_max");
818   char *val_max = GNUNET_malloc (GNUNET_PSYC_MODIFIER_MAX_PAYLOAD);
819   for (i = 0; i < GNUNET_PSYC_MODIFIER_MAX_PAYLOAD; i++)
820     val_max[i] = (0 == i % 10000) ? '0' + i / 10000 : '.';
821
822   char *name_cont = "_test_cont";
823   uint8_t name_cont_size = sizeof ("_test_cont");
824   char *val_cont = GNUNET_malloc (GNUNET_PSYC_MODIFIER_MAX_PAYLOAD
825                                   + GNUNET_PSYC_MOD_CONT_MAX_PAYLOAD);
826   for (i = 0; i < GNUNET_PSYC_MODIFIER_MAX_PAYLOAD - name_cont_size; i++)
827     val_cont[i] = (0 == i % 10000) ? '0' + i / 10000 : ':';
828   for (j = 0; j < GNUNET_PSYC_MOD_CONT_MAX_PAYLOAD; j++, i++)
829     val_cont[i] = (0 == j % 10000) ? '0' + j / 10000 : '!';
830
831   tmit = GNUNET_new (struct TransmitClosure);
832   tmit->env = GNUNET_ENV_environment_create ();
833   GNUNET_ENV_environment_add (tmit->env, GNUNET_ENV_OP_ASSIGN,
834                               "_foo", "bar baz", 7);
835   GNUNET_ENV_environment_add (tmit->env, GNUNET_ENV_OP_ASSIGN,
836                               name_max, val_max,
837                               GNUNET_PSYC_MODIFIER_MAX_PAYLOAD
838                               - name_max_size);
839   GNUNET_ENV_environment_add (tmit->env, GNUNET_ENV_OP_ASSIGN,
840                               "_foo_bar", "foo bar baz", 11);
841   GNUNET_ENV_environment_add (tmit->env, GNUNET_ENV_OP_ASSIGN,
842                               name_cont, val_cont,
843                               GNUNET_PSYC_MODIFIER_MAX_PAYLOAD - name_cont_size
844                               + GNUNET_PSYC_MOD_CONT_MAX_PAYLOAD);
845   tmit->mod = GNUNET_ENV_environment_head (tmit->env);
846   tmit->data[0] = "foo";
847   tmit->data[1] =  GNUNET_malloc (GNUNET_PSYC_DATA_MAX_PAYLOAD + 1);
848   for (i = 0; i < GNUNET_PSYC_DATA_MAX_PAYLOAD; i++)
849     tmit->data[1][i] = (0 == i % 10000) ? '0' + i / 10000 : '_';
850   tmit->data[2] = "foo bar";
851   tmit->data[3] = "foo bar baz";
852   tmit->data_delay[1] = 3;
853   tmit->data_count = 4;
854   tmit->mst_tmit
855     = GNUNET_PSYC_master_transmit (mst, "_notice_test", &tmit_notify_mod,
856                                    &tmit_notify_data, tmit,
857                                    GNUNET_PSYC_MASTER_TRANSMIT_INC_GROUP_GEN);
858 }
859
860
861 void
862 master_start_cb (void *cls, int result, uint64_t max_message_id)
863 {
864   GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
865               "Master started: %d, max_message_id: %" PRIu64 "\n",
866               result, max_message_id);
867   GNUNET_assert (TEST_MASTER_START == test);
868   GNUNET_assert (GNUNET_OK == result || GNUNET_NO == result);
869   slave_join ();
870 }
871
872
873 void
874 master_start ()
875 {
876   GNUNET_log (GNUNET_ERROR_TYPE_WARNING, "Starting master.\n");
877   test = TEST_MASTER_START;
878   mst = GNUNET_PSYC_master_start (cfg, channel_key, GNUNET_PSYC_CHANNEL_PRIVATE,
879                                   &master_start_cb, &join_request_cb,
880                                   &master_message_cb, &master_message_part_cb,
881                                   NULL);
882   mst_chn = GNUNET_PSYC_master_get_channel (mst);
883 }
884
885 void
886 schedule_master_start (void *cls, const struct GNUNET_SCHEDULER_TaskContext *tc)
887 {
888   master_start ();
889 }
890
891
892 void
893 core_connected (void *cls, const struct GNUNET_PeerIdentity *my_identity)
894 {
895   this_peer = *my_identity;
896
897 #if DEBUG_TEST_PSYC
898   master_start ();
899 #else
900   /* Allow some time for the services to initialize. */
901   GNUNET_SCHEDULER_add_delayed (GNUNET_TIME_UNIT_SECONDS,
902                                 &schedule_master_start, NULL);
903 #endif
904
905 }
906
907 /**
908  * Main function of the test, run from scheduler.
909  *
910  * @param cls NULL
911  * @param cfg configuration we use (also to connect to PSYC service)
912  * @param peer handle to access more of the peer (not used)
913  */
914 void
915 #if DEBUG_TEST_PSYC
916 run (void *cls, char *const *args, const char *cfgfile,
917      const struct GNUNET_CONFIGURATION_Handle *c)
918 #else
919 run (void *cls,
920      const struct GNUNET_CONFIGURATION_Handle *c,
921      struct GNUNET_TESTING_Peer *peer)
922 #endif
923 {
924   cfg = c;
925   end_badly_task = GNUNET_SCHEDULER_add_delayed (TIMEOUT, &end_badly, NULL);
926
927   channel_key = GNUNET_CRYPTO_eddsa_key_create ();
928   slave_key = GNUNET_CRYPTO_ecdsa_key_create ();
929
930   GNUNET_CRYPTO_eddsa_key_get_public (channel_key, &channel_pub_key);
931   GNUNET_CRYPTO_ecdsa_key_get_public (slave_key, &slave_pub_key);
932
933   core = GNUNET_CORE_connect (cfg, NULL, &core_connected, NULL, NULL,
934                               NULL, GNUNET_NO, NULL, GNUNET_NO, NULL);
935 }
936
937
938 int
939 main (int argc, char *argv[])
940 {
941   res = 1;
942 #if DEBUG_TEST_PSYC
943   const struct GNUNET_GETOPT_CommandLineOption opts[] = {
944     GNUNET_GETOPT_OPTION_END
945   };
946   if (GNUNET_OK != GNUNET_PROGRAM_run (argc, argv, "test-psyc",
947                                        "test-psyc [options]",
948                                        opts, &run, NULL))
949     return 1;
950 #else
951   if (0 != GNUNET_TESTING_peer_run ("test-psyc", "test_psyc.conf", &run, NULL))
952     return 1;
953 #endif
954   return res;
955 }
956
957 /* end of test_psyc.c */