- re-added testcase for crypto-paillier
[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, 10)
39
40 #define DEBUG_SERVICE 0
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 *handle;
70   struct GNUNET_ENV_Environment *env;
71   char *data[16];
72   const char *mod_value;
73   size_t mod_value_size;
74   uint8_t data_count;
75   uint8_t paused;
76   uint8_t n;
77 };
78
79 struct TransmitClosure *tmit;
80
81 /**
82  * Clean up all resources used.
83  */
84 static void
85 cleanup ()
86 {
87   if (NULL != mst)
88   {
89     GNUNET_PSYC_master_stop (mst);
90     mst = NULL;
91   }
92   if (NULL != tmit)
93   {
94     GNUNET_ENV_environment_destroy (tmit->env);
95     GNUNET_free (tmit);
96     tmit = NULL;
97   }
98   GNUNET_SCHEDULER_shutdown ();
99 }
100
101
102 /**
103  * Terminate the testcase (failure).
104  *
105  * @param cls NULL
106  * @param tc scheduler context
107  */
108 static void
109 end_badly (void *cls, const struct GNUNET_SCHEDULER_TaskContext *tc)
110 {
111   res = 1;
112   cleanup ();
113 }
114
115
116 /**
117  * Terminate the testcase (success).
118  *
119  * @param cls NULL
120  * @param tc scheduler context
121  */
122 static void
123 end_normally (void *cls, const struct GNUNET_SCHEDULER_TaskContext *tc)
124 {
125   res = 0;
126   cleanup ();
127 }
128
129
130 /**
131  * Finish the testcase (successfully).
132  */
133 static void
134 end ()
135 {
136   if (end_badly_task != GNUNET_SCHEDULER_NO_TASK)
137   {
138     GNUNET_SCHEDULER_cancel (end_badly_task);
139     end_badly_task = GNUNET_SCHEDULER_NO_TASK;
140   }
141   GNUNET_SCHEDULER_add_delayed (GNUNET_TIME_UNIT_MILLISECONDS,
142                                 &end_normally, NULL);
143 }
144
145
146 static void
147 message (void *cls, uint64_t message_id, uint32_t flags,
148          const struct GNUNET_MessageHeader *msg)
149 {
150   if (NULL == msg)
151   {
152     GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
153                 "Error while receiving message %llu\n", message_id);
154     return;
155   }
156
157   uint16_t type = ntohs (msg->type);
158   uint16_t size = ntohs (msg->size);
159
160   GNUNET_log (GNUNET_ERROR_TYPE_WARNING,
161               "Got message part of type %u and size %u "
162               "belonging to message ID %llu with flags %u\n",
163               type, size, message_id, flags);
164
165   if (GNUNET_MESSAGE_TYPE_PSYC_MESSAGE_END == type)
166     end ();
167 }
168
169
170 static void
171 join_request (void *cls, const struct GNUNET_CRYPTO_EddsaPublicKey *slave_key,
172               const char *method_name,
173               size_t variable_count, const struct GNUNET_ENV_Modifier *variables,
174               const void *data, size_t data_size,
175               struct GNUNET_PSYC_JoinHandle *jh)
176 {
177   GNUNET_log (GNUNET_ERROR_TYPE_WARNING,
178               "Got join request.");
179 }
180
181
182 static void
183 transmit_resume (void *cls, const struct GNUNET_SCHEDULER_TaskContext *tc)
184 {
185   GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "Transmission resumed.\n");
186   struct TransmitClosure *tmit = cls;
187   tmit->paused = GNUNET_NO;
188   GNUNET_PSYC_master_transmit_resume (tmit->handle);
189 }
190
191
192 static int
193 tmit_notify_mod (void *cls, uint16_t *data_size, void *data, uint8_t *oper)
194 {
195   struct TransmitClosure *tmit = cls;
196   GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
197               "Transmit notify modifier: %lu bytes available, "
198               "%u modifiers left to process.\n",
199               *data_size, GNUNET_ENV_environment_get_count (tmit->env));
200
201   enum GNUNET_ENV_Operator op = 0;
202   const char *name = NULL;
203   const char *value = NULL;
204   uint16_t name_size = 0;
205   size_t value_size = 0;
206
207   if (NULL != tmit->mod_value && 0 < tmit->mod_value_size)
208   { /* Modifier continuation */
209     value = tmit->mod_value;
210     if (tmit->mod_value_size <= *data_size)
211     {
212       value_size = tmit->mod_value_size;
213       tmit->mod_value = NULL;
214     }
215     else
216     {
217       value_size = *data_size;
218       tmit->mod_value += value_size;
219     }
220     tmit->mod_value_size -= value_size;
221
222     if (*data_size < value_size)
223     {
224       GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
225                   "value larger than buffer: %u < %zu\n",
226                   *data_size, value_size);
227       *data_size = 0;
228       return GNUNET_NO;
229     }
230
231     *data_size = value_size;
232     memcpy (data, value, value_size);
233   }
234   else if (NULL != oper)
235   {
236     if (GNUNET_NO == GNUNET_ENV_environment_shift (tmit->env, &op, &name,
237                                                    (void *) &value, &value_size))
238     { /* No more modifiers, continue with data */
239       *data_size = 0;
240       return GNUNET_YES;
241     }
242
243     *oper = op;
244     name_size = strlen (name);
245
246     if (name_size + 1 + value_size <= *data_size)
247     {
248       *data_size = name_size + 1 + value_size;
249     }
250     else
251     {
252       tmit->mod_value_size = value_size;
253       value_size = *data_size - name_size - 1;
254       tmit->mod_value_size -= value_size;
255       tmit->mod_value = value + value_size;
256     }
257
258     memcpy (data, name, name_size);
259     ((char *)data)[name_size] = '\0';
260     memcpy ((char *)data + name_size + 1, value, value_size);
261   }
262
263   return 0 == tmit->mod_value_size ? GNUNET_YES : GNUNET_NO;
264 }
265
266
267 static int
268 tmit_notify_data (void *cls, uint16_t *data_size, void *data)
269 {
270   struct TransmitClosure *tmit = cls;
271   uint16_t size = strlen (tmit->data[tmit->n]);
272   GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
273               "Transmit notify data: %lu bytes available, "
274               "processing fragment %u/%u (size %u).\n",
275               *data_size, tmit->n + 1, tmit->data_count, size);
276   if (*data_size < size)
277   {
278     *data_size = 0;
279     GNUNET_assert (0);
280     return GNUNET_SYSERR;
281   }
282
283   if (GNUNET_YES == tmit->paused && tmit->n == tmit->data_count - 1)
284   {
285     /* Send last fragment later. */
286     GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "Transmission paused.\n");
287     tmit->paused = GNUNET_YES;
288     GNUNET_SCHEDULER_add_delayed (GNUNET_TIME_relative_multiply
289                                   (GNUNET_TIME_UNIT_SECONDS, 3),
290                                   &transmit_resume, tmit);
291     *data_size = 0;
292     return GNUNET_NO;
293   }
294
295   *data_size = size;
296   memcpy (data, tmit->data[tmit->n], size);
297
298   return ++tmit->n < tmit->data_count ? GNUNET_NO : GNUNET_YES;
299 }
300
301
302 static void
303 master_started (void *cls, uint64_t max_message_id)
304 {
305   GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
306               "Master started: %" PRIu64 "\n", max_message_id);
307
308   tmit = GNUNET_new (struct TransmitClosure);
309   tmit->env = GNUNET_ENV_environment_create ();
310   GNUNET_ENV_environment_add (tmit->env, GNUNET_ENV_OP_ASSIGN,
311                               "_foo", "bar baz", 7);
312   GNUNET_ENV_environment_add (tmit->env, GNUNET_ENV_OP_ASSIGN,
313                               "_foo_bar", "foo bar baz", 11);
314   tmit->data[0] = "foo";
315   tmit->data[1] = "foo bar";
316   tmit->data[2] = "foo bar baz";
317   tmit->data_count = 3;
318   tmit->handle
319     = GNUNET_PSYC_master_transmit (mst, "_test", tmit_notify_mod,
320                                    tmit_notify_data, tmit,
321                                    GNUNET_PSYC_MASTER_TRANSMIT_INC_GROUP_GEN);
322 }
323
324
325 static void
326 slave_joined (void *cls, uint64_t max_message_id)
327 {
328   GNUNET_log (GNUNET_ERROR_TYPE_WARNING, "Slave joined: %lu\n", max_message_id);
329 }
330
331
332 /**
333  * Main function of the test, run from scheduler.
334  *
335  * @param cls NULL
336  * @param cfg configuration we use (also to connect to PSYC service)
337  * @param peer handle to access more of the peer (not used)
338  */
339 static void
340 #if DEBUG_SERVICE
341 run (void *cls, char *const *args, const char *cfgfile,
342      const struct GNUNET_CONFIGURATION_Handle *c)
343 #else
344 run (void *cls,
345      const struct GNUNET_CONFIGURATION_Handle *c,
346      struct GNUNET_TESTING_Peer *peer)
347 #endif
348 {
349   cfg = c;
350   end_badly_task = GNUNET_SCHEDULER_add_delayed (TIMEOUT, &end_badly, NULL);
351
352   channel_key = GNUNET_CRYPTO_eddsa_key_create ();
353   slave_key = GNUNET_CRYPTO_eddsa_key_create ();
354
355   GNUNET_CRYPTO_eddsa_key_get_public (channel_key, &channel_pub_key);
356   GNUNET_CRYPTO_eddsa_key_get_public (slave_key, &slave_pub_key);
357
358   mst = GNUNET_PSYC_master_start (cfg, channel_key, GNUNET_PSYC_CHANNEL_PRIVATE,
359                                   &message, &join_request, &master_started, NULL);
360   return; /* FIXME: test slave */
361
362   struct GNUNET_PeerIdentity origin;
363   struct GNUNET_PeerIdentity relays[16];
364   struct GNUNET_ENV_Environment *env = GNUNET_ENV_environment_create ();
365   GNUNET_ENV_environment_add (env, GNUNET_ENV_OP_ASSIGN,
366                               "_foo", "bar baz", 7);
367   GNUNET_ENV_environment_add (env, GNUNET_ENV_OP_ASSIGN,
368                               "_foo_bar", "foo bar baz", 11);
369   slv = GNUNET_PSYC_slave_join (cfg, &channel_pub_key, slave_key, &origin,
370                                 16, relays, &message, &join_request, &slave_joined,
371                                 NULL, "_request_join", env, "some data", 9);
372   GNUNET_ENV_environment_destroy (env);
373 }
374
375
376 int
377 main (int argc, char *argv[])
378 {
379   res = 1;
380 #if DEBUG_SERVICE
381   const struct GNUNET_GETOPT_CommandLineOption opts[] = {
382     GNUNET_GETOPT_OPTION_END
383   };
384   if (GNUNET_OK != GNUNET_PROGRAM_run (argc, argv, "test-psyc",
385                                        "test-psyc [options]",
386                                        opts, &run, NULL))
387     return 1;
388 #else
389   if (0 != GNUNET_TESTING_peer_run ("test-psyc", "test_psyc.conf", &run, NULL))
390     return 1;
391 #endif
392   return res;
393 }
394
395 /* end of test_psyc.c */