adding extended proxy support for http(s) client
[oweals/gnunet.git] / src / psyc / test_psyc.c
1 /*
2  * This file is part of GNUnet
3  * (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 Test for the PSYC service.
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_service.h"
37
38 #define TIMEOUT GNUNET_TIME_relative_multiply (GNUNET_TIME_UNIT_SECONDS, 30)
39
40 #define DEBUG_SERVICE 1
41
42
43 /**
44  * Return value from 'main'.
45  */
46 static int res;
47
48 static const struct GNUNET_CONFIGURATION_Handle *cfg;
49
50 /**
51  * Handle for task for timeout termination.
52  */
53 static GNUNET_SCHEDULER_TaskIdentifier end_badly_task;
54
55 static struct GNUNET_PSYC_Master *mst;
56 static struct GNUNET_PSYC_Slave *slv;
57 static struct GNUNET_PSYC_Channel *ch;
58
59 static struct GNUNET_CRYPTO_EddsaPrivateKey *channel_key;
60 static struct GNUNET_CRYPTO_EddsaPrivateKey *slave_key;
61
62 static struct GNUNET_CRYPTO_EddsaPublicKey channel_pub_key;
63 static struct GNUNET_CRYPTO_EddsaPublicKey slave_pub_key;
64
65 struct GNUNET_PSYC_MasterTransmitHandle *mth;
66
67 struct TransmitClosure
68 {
69   struct GNUNET_PSYC_MasterTransmitHandle *mst_tmit;
70   struct GNUNET_PSYC_SlaveTransmitHandle *slv_tmit;
71   struct GNUNET_ENV_Environment *env;
72   char *data[16];
73   const char *mod_value;
74   size_t mod_value_size;
75   uint8_t data_delay[16];
76   uint8_t data_count;
77   uint8_t paused;
78   uint8_t n;
79 };
80
81 struct TransmitClosure *tmit;
82
83
84 enum
85 {
86   TEST_NONE,
87   TEST_SLAVE_TRANSMIT,
88   TEST_MASTER_TRANSMIT,
89 } test;
90
91
92 static void
93 master_transmit ();
94
95
96 /**
97  * Clean up all resources used.
98  */
99 static void
100 cleanup ()
101 {
102   if (NULL != slv)
103   {
104     GNUNET_PSYC_slave_part (slv);
105     slv = NULL;
106   }
107   if (NULL != mst)
108   {
109     GNUNET_PSYC_master_stop (mst);
110     mst = NULL;
111   }
112   if (NULL != tmit)
113   {
114     GNUNET_ENV_environment_destroy (tmit->env);
115     GNUNET_free (tmit);
116     tmit = NULL;
117   }
118   GNUNET_SCHEDULER_shutdown ();
119 }
120
121
122 /**
123  * Terminate the testcase (failure).
124  *
125  * @param cls NULL
126  * @param tc scheduler context
127  */
128 static void
129 end_badly (void *cls, const struct GNUNET_SCHEDULER_TaskContext *tc)
130 {
131   res = 1;
132   cleanup ();
133 }
134
135
136 /**
137  * Terminate the testcase (success).
138  *
139  * @param cls NULL
140  * @param tc scheduler context
141  */
142 static void
143 end_normally (void *cls, const struct GNUNET_SCHEDULER_TaskContext *tc)
144 {
145   res = 0;
146   cleanup ();
147 }
148
149
150 /**
151  * Finish the testcase (successfully).
152  */
153 static void
154 end ()
155 {
156   GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "Ending tests.\n");
157
158   if (end_badly_task != GNUNET_SCHEDULER_NO_TASK)
159   {
160     GNUNET_SCHEDULER_cancel (end_badly_task);
161     end_badly_task = GNUNET_SCHEDULER_NO_TASK;
162   }
163   GNUNET_SCHEDULER_add_delayed (GNUNET_TIME_UNIT_MILLISECONDS,
164                                 &end_normally, NULL);
165 }
166
167
168 static void
169 master_message (void *cls, uint64_t message_id, uint32_t flags,
170                 const struct GNUNET_MessageHeader *msg)
171 {
172   if (NULL == msg)
173   {
174     GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
175                 "Error while receiving message %llu\n", message_id);
176     return;
177   }
178
179   uint16_t type = ntohs (msg->type);
180   uint16_t size = ntohs (msg->size);
181
182   GNUNET_log (GNUNET_ERROR_TYPE_WARNING,
183               "Master got message part of type %u and size %u "
184               "belonging to message ID %llu with flags %u\n",
185               type, size, message_id, flags);
186
187   switch (test)
188   {
189   case TEST_SLAVE_TRANSMIT:
190     if (GNUNET_PSYC_MESSAGE_REQUEST != flags)
191     {
192       GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
193                   "Unexpected request flags: %lu\n", flags);
194       GNUNET_assert (0);
195       return;
196     }
197     // FIXME: check rest of message
198
199     if (GNUNET_MESSAGE_TYPE_PSYC_MESSAGE_END == type)
200       master_transmit ();
201     break;
202
203   case TEST_MASTER_TRANSMIT:
204     break;
205
206   default:
207     GNUNET_assert (0);
208   }
209 }
210
211
212 static void
213 slave_message (void *cls, uint64_t message_id, uint32_t flags,
214                const struct GNUNET_MessageHeader *msg)
215 {
216   if (NULL == msg)
217   {
218     GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
219                 "Error while receiving message %llu\n", message_id);
220     return;
221   }
222
223   uint16_t type = ntohs (msg->type);
224   uint16_t size = ntohs (msg->size);
225
226   GNUNET_log (GNUNET_ERROR_TYPE_WARNING,
227               "Slave got message part of type %u and size %u "
228               "belonging to message ID %llu with flags %u\n",
229               type, size, message_id, flags);
230
231   switch (test)
232   {
233   case TEST_MASTER_TRANSMIT:
234     if (GNUNET_MESSAGE_TYPE_PSYC_MESSAGE_END == type)
235       end ();
236     break;
237
238   default:
239     GNUNET_assert (0);
240   }
241 }
242
243
244 static void
245 join_request (void *cls, const struct GNUNET_CRYPTO_EddsaPublicKey *slave_key,
246               const char *method_name,
247               size_t variable_count, const struct GNUNET_ENV_Modifier *variables,
248               const void *data, size_t data_size,
249               struct GNUNET_PSYC_JoinHandle *jh)
250 {
251   GNUNET_log (GNUNET_ERROR_TYPE_WARNING,
252               "Got join request: %s (%zu vars)", method_name, variable_count);
253   GNUNET_PSYC_join_decision (jh, GNUNET_YES, 0, NULL, "_notice_join", NULL,
254                              "you're in", 9);
255 }
256
257
258 static void
259 transmit_resume (void *cls, const struct GNUNET_SCHEDULER_TaskContext *tc)
260 {
261   GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "Transmission resumed.\n");
262   struct TransmitClosure *tmit = cls;
263   if (NULL != tmit->mst_tmit)
264     GNUNET_PSYC_master_transmit_resume (tmit->mst_tmit);
265   else
266     GNUNET_PSYC_slave_transmit_resume (tmit->slv_tmit);
267 }
268
269
270 static int
271 tmit_notify_mod (void *cls, uint16_t *data_size, void *data, uint8_t *oper,
272                  uint32_t *full_value_size)
273 {
274   struct TransmitClosure *tmit = cls;
275   GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
276               "Transmit notify modifier: %lu bytes available, "
277               "%u modifiers left to process.\n",
278               *data_size, GNUNET_ENV_environment_get_count (tmit->env));
279
280   enum GNUNET_ENV_Operator op = 0;
281   const char *name = NULL;
282   const char *value = NULL;
283   uint16_t name_size = 0;
284   size_t value_size = 0;
285
286   if (NULL != oper)
287   { /* New modifier */
288     if (GNUNET_NO == GNUNET_ENV_environment_shift (tmit->env, &op, &name,
289                                                    (void *) &value, &value_size))
290     { /* No more modifiers, continue with data */
291       *data_size = 0;
292       return GNUNET_YES;
293     }
294
295     GNUNET_assert (value_size < UINT32_MAX);
296     *full_value_size = value_size;
297     *oper = op;
298     name_size = strlen (name);
299
300     if (name_size + 1 + value_size <= *data_size)
301     {
302       *data_size = name_size + 1 + value_size;
303     }
304     else
305     {
306       tmit->mod_value_size = value_size;
307       value_size = *data_size - name_size - 1;
308       tmit->mod_value_size -= value_size;
309       tmit->mod_value = value + value_size;
310     }
311
312     memcpy (data, name, name_size);
313     ((char *)data)[name_size] = '\0';
314     memcpy ((char *)data + name_size + 1, value, value_size);
315   }
316   else if (NULL != tmit->mod_value && 0 < tmit->mod_value_size)
317   { /* Modifier continuation */
318     value = tmit->mod_value;
319     if (tmit->mod_value_size <= *data_size)
320     {
321       value_size = tmit->mod_value_size;
322       tmit->mod_value = NULL;
323     }
324     else
325     {
326       value_size = *data_size;
327       tmit->mod_value += value_size;
328     }
329     tmit->mod_value_size -= value_size;
330
331     if (*data_size < value_size)
332     {
333       GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
334                   "value larger than buffer: %u < %zu\n",
335                   *data_size, value_size);
336       *data_size = 0;
337       return GNUNET_NO;
338     }
339
340     *data_size = value_size;
341     memcpy (data, value, value_size);
342   }
343
344   return 0 == tmit->mod_value_size ? GNUNET_YES : GNUNET_NO;
345 }
346
347
348 static int
349 tmit_notify_data (void *cls, uint16_t *data_size, void *data)
350 {
351   struct TransmitClosure *tmit = cls;
352   if (0 == tmit->data_count)
353   {
354     *data_size = 0;
355     return GNUNET_YES;
356   }
357
358   uint16_t size = strlen (tmit->data[tmit->n]);
359   GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
360               "Transmit notify data: %u bytes available, "
361               "processing fragment %u/%u (size %u).\n",
362               *data_size, tmit->n + 1, tmit->data_count, size);
363   if (*data_size < size)
364   {
365     *data_size = 0;
366     GNUNET_assert (0);
367     return GNUNET_SYSERR;
368   }
369
370   if (GNUNET_YES != tmit->paused && 0 < tmit->data_delay[tmit->n])
371   {
372     GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "Transmission paused.\n");
373     tmit->paused = GNUNET_YES;
374     GNUNET_SCHEDULER_add_delayed (
375       GNUNET_TIME_relative_multiply (GNUNET_TIME_UNIT_SECONDS,
376                                      tmit->data_delay[tmit->n]),
377       &transmit_resume, tmit);
378     *data_size = 0;
379     return GNUNET_NO;
380   }
381   tmit->paused = GNUNET_NO;
382
383   *data_size = size;
384   memcpy (data, tmit->data[tmit->n], size);
385
386   return ++tmit->n < tmit->data_count ? GNUNET_NO : GNUNET_YES;
387 }
388
389
390 static void
391 slave_joined (void *cls, uint64_t max_message_id)
392 {
393   GNUNET_log (GNUNET_ERROR_TYPE_WARNING, "Slave joined: %lu\n", max_message_id);
394   GNUNET_log (GNUNET_ERROR_TYPE_WARNING, "Slave sending request to master.\n");
395
396   test = TEST_SLAVE_TRANSMIT;
397
398   tmit = GNUNET_new (struct TransmitClosure);
399   tmit->env = GNUNET_ENV_environment_create ();
400   GNUNET_ENV_environment_add (tmit->env, GNUNET_ENV_OP_ASSIGN,
401                               "_abc", "abc def", 7);
402   GNUNET_ENV_environment_add (tmit->env, GNUNET_ENV_OP_ASSIGN,
403                               "_abc_def", "abc def ghi", 11);
404   tmit->n = 0;
405   tmit->data[0] = "slave test";
406   tmit->data_count = 1;
407   tmit->slv_tmit
408     = GNUNET_PSYC_slave_transmit (slv, "_request_test", tmit_notify_mod,
409                                   tmit_notify_data, tmit,
410                                   GNUNET_PSYC_SLAVE_TRANSMIT_NONE);
411 }
412
413 static void
414 slave_join ()
415 {
416   GNUNET_log (GNUNET_ERROR_TYPE_WARNING, "Joining slave.\n");
417
418   struct GNUNET_PeerIdentity origin;
419   struct GNUNET_PeerIdentity relays[16];
420   struct GNUNET_ENV_Environment *env = GNUNET_ENV_environment_create ();
421   GNUNET_ENV_environment_add (env, GNUNET_ENV_OP_ASSIGN,
422                               "_foo", "bar baz", 7);
423   GNUNET_ENV_environment_add (env, GNUNET_ENV_OP_ASSIGN,
424                               "_foo_bar", "foo bar baz", 11);
425   slv = GNUNET_PSYC_slave_join (cfg, &channel_pub_key, slave_key, &origin,
426                                 16, relays, &slave_message, &join_request,
427                                 &slave_joined, NULL, "_request_join", env,
428                                 "some data", 9);
429   GNUNET_ENV_environment_destroy (env);
430 }
431
432
433 static void
434 master_transmit ()
435 {
436   GNUNET_log (GNUNET_ERROR_TYPE_WARNING, "Master sending message to all.\n");
437   test = TEST_MASTER_TRANSMIT;
438   uint32_t i, j;
439
440   char *name_max = "_test_max";
441   uint8_t name_max_size = sizeof ("_test_max");
442   char *val_max = GNUNET_malloc (GNUNET_PSYC_MODIFIER_MAX_PAYLOAD);
443   for (i = 0; i < GNUNET_PSYC_MODIFIER_MAX_PAYLOAD; i++)
444     val_max[i] = (0 == i % 10000) ? '0' + i / 10000 : '.';
445
446   char *name_cont = "_test_cont";
447   uint8_t name_cont_size = sizeof ("_test_cont");
448   char *val_cont = GNUNET_malloc (GNUNET_PSYC_MODIFIER_MAX_PAYLOAD
449                                   + GNUNET_PSYC_MOD_CONT_MAX_PAYLOAD);
450   for (i = 0; i < GNUNET_PSYC_MODIFIER_MAX_PAYLOAD - name_cont_size; i++)
451     val_cont[i] = (0 == i % 10000) ? '0' + i / 10000 : ':';
452   for (j = 0; j < GNUNET_PSYC_MOD_CONT_MAX_PAYLOAD; j++, i++)
453     val_cont[i] = (0 == j % 10000) ? '0' + j / 10000 : '!';
454
455   tmit = GNUNET_new (struct TransmitClosure);
456   tmit->env = GNUNET_ENV_environment_create ();
457   GNUNET_ENV_environment_add (tmit->env, GNUNET_ENV_OP_ASSIGN,
458                               "_foo", "bar baz", 7);
459   GNUNET_ENV_environment_add (tmit->env, GNUNET_ENV_OP_ASSIGN,
460                               name_max, val_max,
461                               GNUNET_PSYC_MODIFIER_MAX_PAYLOAD
462                               - name_max_size);
463   GNUNET_ENV_environment_add (tmit->env, GNUNET_ENV_OP_ASSIGN,
464                               "_foo_bar", "foo bar baz", 11);
465   GNUNET_ENV_environment_add (tmit->env, GNUNET_ENV_OP_ASSIGN,
466                               name_cont, val_cont,
467                               GNUNET_PSYC_MODIFIER_MAX_PAYLOAD - name_cont_size
468                               + GNUNET_PSYC_MOD_CONT_MAX_PAYLOAD);
469   tmit->data[0] = "foo";
470   tmit->data[1] =  GNUNET_malloc (GNUNET_PSYC_DATA_MAX_PAYLOAD + 1);
471   for (i = 0; i < GNUNET_PSYC_DATA_MAX_PAYLOAD; i++)
472     tmit->data[1][i] = (0 == i % 10000) ? '0' + i / 10000 : '_';
473   tmit->data[2] = "foo bar";
474   tmit->data[3] = "foo bar baz";
475   tmit->data_delay[1] = 3;
476   tmit->data_count = 4;
477   tmit->mst_tmit
478     = GNUNET_PSYC_master_transmit (mst, "_notice_test", tmit_notify_mod,
479                                    tmit_notify_data, tmit,
480                                    GNUNET_PSYC_MASTER_TRANSMIT_INC_GROUP_GEN);
481 }
482
483
484 static void
485 master_started (void *cls, uint64_t max_message_id)
486 {
487   GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
488               "Master started: %" PRIu64 "\n", max_message_id);
489   slave_join ();
490 }
491
492
493 /**
494  * Main function of the test, run from scheduler.
495  *
496  * @param cls NULL
497  * @param cfg configuration we use (also to connect to PSYC service)
498  * @param peer handle to access more of the peer (not used)
499  */
500 static void
501 #if DEBUG_SERVICE
502 run (void *cls, char *const *args, const char *cfgfile,
503      const struct GNUNET_CONFIGURATION_Handle *c)
504 #else
505 run (void *cls,
506      const struct GNUNET_CONFIGURATION_Handle *c,
507      struct GNUNET_TESTING_Peer *peer)
508 #endif
509 {
510   cfg = c;
511   end_badly_task = GNUNET_SCHEDULER_add_delayed (TIMEOUT, &end_badly, NULL);
512
513   channel_key = GNUNET_CRYPTO_eddsa_key_create ();
514   slave_key = GNUNET_CRYPTO_eddsa_key_create ();
515
516   GNUNET_CRYPTO_eddsa_key_get_public (channel_key, &channel_pub_key);
517   GNUNET_CRYPTO_eddsa_key_get_public (slave_key, &slave_pub_key);
518
519   GNUNET_log (GNUNET_ERROR_TYPE_WARNING, "Starting master.\n");
520   mst = GNUNET_PSYC_master_start (cfg, channel_key, GNUNET_PSYC_CHANNEL_PRIVATE,
521                                   &master_message, &join_request, &master_started, NULL);
522 }
523
524
525 int
526 main (int argc, char *argv[])
527 {
528   res = 1;
529 #if DEBUG_SERVICE
530   const struct GNUNET_GETOPT_CommandLineOption opts[] = {
531     GNUNET_GETOPT_OPTION_END
532   };
533   if (GNUNET_OK != GNUNET_PROGRAM_run (argc, argv, "test-psyc",
534                                        "test-psyc [options]",
535                                        opts, &run, NULL))
536     return 1;
537 #else
538   if (0 != GNUNET_TESTING_peer_run ("test-psyc", "test_psyc.conf", &run, NULL))
539     return 1;
540 #endif
541   return res;
542 }
543
544 /* end of test_psyc.c */