adding a GNUNET_memcmp_priv for constant-time comparing of data; fixes #6152 (modulo...
[oweals/gnunet.git] / src / set / test_set_union_result_symmetric.c
1 /*
2      This file is part of GNUnet.
3      Copyright (C) 2012, 2016 GNUnet e.V.
4
5      GNUnet is free software: you can redistribute it and/or modify it
6      under the terms of the GNU Affero General Public License as published
7      by the Free Software Foundation, either version 3 of the License,
8      or (at your 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      Affero General Public License for more details.
14
15      You should have received a copy of the GNU Affero General Public License
16      along with this program.  If not, see <http://www.gnu.org/licenses/>.
17
18      SPDX-License-Identifier: AGPL3.0-or-later
19  */
20
21 /**
22  * @file set/test_set_union_result_smmetric
23  * @brief testcase for symmetric result mode of the union set operation
24  * @author Florian Dold
25  * @author Christian Grothoff
26  */
27 #include "platform.h"
28 #include "gnunet_util_lib.h"
29 #include "gnunet_testing_lib.h"
30 #include "gnunet_set_service.h"
31
32
33 /**
34  * Value to return from #main().
35  */
36 static int ret;
37
38 static struct GNUNET_PeerIdentity local_id;
39
40 static struct GNUNET_HashCode app_id;
41
42 static struct GNUNET_SET_Handle *set1;
43
44 static struct GNUNET_SET_Handle *set2;
45
46 static struct GNUNET_SET_ListenHandle *listen_handle;
47
48 static const struct GNUNET_CONFIGURATION_Handle *config;
49
50 static struct GNUNET_SET_OperationHandle *oh1;
51
52 static struct GNUNET_SET_OperationHandle *oh2;
53
54 static int iter_count;
55
56 /**
57  * Are we testing correctness for the empty set union?
58  */
59 static int empty;
60
61 /**
62  * Number of elements found in set 1
63  */
64 static unsigned int count_set1;
65
66 /**
67  * Number of elements found in set 2
68  */
69 static unsigned int count_set2;
70
71 /**
72  * Task that is run when the test times out.
73  */
74 static struct GNUNET_SCHEDULER_Task *timeout_task;
75
76
77 static void
78 result_cb_set1 (void *cls,
79                 const struct GNUNET_SET_Element *element,
80                 uint64_t current_size,
81                 enum GNUNET_SET_Status status)
82 {
83   switch (status)
84   {
85   case GNUNET_SET_STATUS_ADD_LOCAL:
86     count_set1++;
87     GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
88                 "set 1: got element\n");
89     break;
90
91   case GNUNET_SET_STATUS_FAILURE:
92     GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
93                 "set 1: failure\n");
94     oh1 = NULL;
95     ret = 1;
96     if (NULL != timeout_task)
97     {
98       GNUNET_SCHEDULER_cancel (timeout_task);
99       timeout_task = NULL;
100     }
101     GNUNET_SCHEDULER_shutdown ();
102     break;
103
104   case GNUNET_SET_STATUS_DONE:
105     oh1 = NULL;
106     GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
107                 "set 1: done\n");
108     GNUNET_SET_destroy (set1);
109     set1 = NULL;
110     if (NULL == set2)
111     {
112       if (NULL != timeout_task)
113       {
114         GNUNET_SCHEDULER_cancel (timeout_task);
115         timeout_task = NULL;
116       }
117       GNUNET_SCHEDULER_shutdown ();
118     }
119     break;
120
121   case GNUNET_SET_STATUS_ADD_REMOTE:
122     break;
123
124   default:
125     GNUNET_assert (0);
126   }
127 }
128
129
130 static void
131 result_cb_set2 (void *cls,
132                 const struct GNUNET_SET_Element *element,
133                 uint64_t current_size,
134                 enum GNUNET_SET_Status status)
135 {
136   switch (status)
137   {
138   case GNUNET_SET_STATUS_ADD_LOCAL:
139     count_set2++;
140     GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
141                 "set 2: got element\n");
142     break;
143
144   case GNUNET_SET_STATUS_FAILURE:
145     GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
146                 "set 2: failure\n");
147     oh2 = NULL;
148     ret = 1;
149     if (NULL != timeout_task)
150     {
151       GNUNET_SCHEDULER_cancel (timeout_task);
152       timeout_task = NULL;
153     }
154     GNUNET_SCHEDULER_shutdown ();
155     break;
156
157   case GNUNET_SET_STATUS_DONE:
158     GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
159                 "set 2: done\n");
160     oh2 = NULL;
161     GNUNET_SET_destroy (set2);
162     set2 = NULL;
163     if (NULL == set1)
164     {
165       if (NULL != timeout_task)
166       {
167         GNUNET_SCHEDULER_cancel (timeout_task);
168         timeout_task = NULL;
169       }
170       GNUNET_SCHEDULER_shutdown ();
171     }
172     break;
173
174   case GNUNET_SET_STATUS_ADD_REMOTE:
175     break;
176
177   default:
178     GNUNET_assert (0);
179   }
180 }
181
182
183 static void
184 listen_cb (void *cls,
185            const struct GNUNET_PeerIdentity *other_peer,
186            const struct GNUNET_MessageHeader *context_msg,
187            struct GNUNET_SET_Request *request)
188 {
189   GNUNET_assert (NULL != context_msg);
190   GNUNET_assert (ntohs (context_msg->type) == GNUNET_MESSAGE_TYPE_DUMMY);
191   GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
192               "listen cb called\n");
193   oh2 = GNUNET_SET_accept (request,
194                            GNUNET_SET_RESULT_SYMMETRIC,
195                            (struct GNUNET_SET_Option[]) { 0 },
196                            &result_cb_set2,
197                            NULL);
198   GNUNET_SET_commit (oh2,
199                      set2);
200 }
201
202
203 /**
204  * Start the set operation.
205  *
206  * @param cls closure, unused
207  */
208 static void
209 start (void *cls)
210 {
211   struct GNUNET_MessageHeader context_msg;
212
213   context_msg.size = htons (sizeof context_msg);
214   context_msg.type = htons (GNUNET_MESSAGE_TYPE_DUMMY);
215
216   listen_handle = GNUNET_SET_listen (config,
217                                      GNUNET_SET_OPERATION_UNION,
218                                      &app_id,
219                                      &listen_cb, NULL);
220   oh1 = GNUNET_SET_prepare (&local_id,
221                             &app_id,
222                             &context_msg,
223                             GNUNET_SET_RESULT_SYMMETRIC,
224                             (struct GNUNET_SET_Option[]) { 0 },
225                             &result_cb_set1, NULL);
226   GNUNET_SET_commit (oh1, set1);
227 }
228
229
230 /**
231  * Initialize the second set, continue
232  *
233  * @param cls closure, unused
234  */
235 static void
236 init_set2 (void *cls)
237 {
238   struct GNUNET_SET_Element element;
239
240   GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
241               "initializing set 2\n");
242   if (empty)
243   {
244     start (NULL);
245     return;
246   }
247   element.element_type = 0;
248   element.data = "hello";
249   element.size = strlen (element.data);
250   GNUNET_SET_add_element (set2,
251                           &element,
252                           NULL,
253                           NULL);
254   element.data = "quux";
255   element.size = strlen (element.data);
256   GNUNET_SET_add_element (set2,
257                           &element,
258                           NULL,
259                           NULL);
260   element.data = "baz";
261   element.size = strlen (element.data);
262   GNUNET_SET_add_element (set2,
263                           &element,
264                           &start, NULL);
265 }
266
267
268 /**
269  * Initialize the first set, continue.
270  */
271 static void
272 init_set1 (void)
273 {
274   struct GNUNET_SET_Element element;
275
276   if (empty)
277   {
278     init_set2 (NULL);
279     return;
280   }
281   element.element_type = 0;
282   element.data = "hello";
283   element.size = strlen (element.data);
284   GNUNET_SET_add_element (set1,
285                           &element,
286                           NULL,
287                           NULL);
288   element.data = "bar";
289   element.size = strlen (element.data);
290   GNUNET_SET_add_element (set1,
291                           &element,
292                           &init_set2,
293                           NULL);
294   GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
295               "initialized set 1\n");
296 }
297
298
299 static int
300 iter_cb (void *cls,
301          const struct GNUNET_SET_Element *element)
302 {
303   if (NULL == element)
304   {
305     GNUNET_assert (iter_count == 3);
306     GNUNET_SET_destroy (cls);
307     return GNUNET_YES;
308   }
309   GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
310               "iter: got element\n");
311   iter_count++;
312   return GNUNET_YES;
313 }
314
315
316 static void
317 test_iter ()
318 {
319   struct GNUNET_SET_Element element;
320   struct GNUNET_SET_Handle *iter_set;
321
322   iter_count = 0;
323   iter_set = GNUNET_SET_create (config, GNUNET_SET_OPERATION_UNION);
324   element.element_type = 0;
325   element.data = "hello";
326   element.size = strlen (element.data);
327   GNUNET_SET_add_element (iter_set, &element, NULL, NULL);
328   element.data = "bar";
329   element.size = strlen (element.data);
330   GNUNET_SET_add_element (iter_set, &element, NULL, NULL);
331   element.data = "quux";
332   element.size = strlen (element.data);
333   GNUNET_SET_add_element (iter_set, &element, NULL, NULL);
334
335   GNUNET_SET_iterate (iter_set,
336                       &iter_cb,
337                       iter_set);
338 }
339
340
341 /**
342  * Signature of the main function of a task.
343  *
344  * @param cls closure
345  */
346 static void
347 timeout_fail (void *cls)
348 {
349   timeout_task = NULL;
350   GNUNET_SCHEDULER_shutdown ();
351   GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
352               "test timed out\n");
353   ret = 1;
354 }
355
356
357 /**
358  * Function run on shutdown.
359  *
360  * @param cls closure
361  */
362 static void
363 do_shutdown (void *cls)
364 {
365   if (NULL != timeout_task)
366   {
367     GNUNET_SCHEDULER_cancel (timeout_task);
368     timeout_task = NULL;
369   }
370   if (NULL != oh1)
371   {
372     GNUNET_SET_operation_cancel (oh1);
373     oh1 = NULL;
374   }
375   if (NULL != oh2)
376   {
377     GNUNET_SET_operation_cancel (oh2);
378     oh2 = NULL;
379   }
380   if (NULL != set1)
381   {
382     GNUNET_SET_destroy (set1);
383     set1 = NULL;
384   }
385   if (NULL != set2)
386   {
387     GNUNET_SET_destroy (set2);
388     set2 = NULL;
389   }
390   if (NULL != listen_handle)
391   {
392     GNUNET_SET_listen_cancel (listen_handle);
393     listen_handle = NULL;
394   }
395 }
396
397
398 /**
399  * Signature of the 'main' function for a (single-peer) testcase that
400  * is run using 'GNUNET_TESTING_peer_run'.
401  *
402  * @param cls closure
403  * @param cfg configuration of the peer that was started
404  * @param peer identity of the peer that was created
405  */
406 static void
407 run (void *cls,
408      const struct GNUNET_CONFIGURATION_Handle *cfg,
409      struct GNUNET_TESTING_Peer *peer)
410 {
411   timeout_task = GNUNET_SCHEDULER_add_delayed (GNUNET_TIME_relative_multiply (
412                                                  GNUNET_TIME_UNIT_SECONDS, 5),
413                                                &timeout_fail,
414                                                NULL);
415   GNUNET_SCHEDULER_add_shutdown (&do_shutdown,
416                                  NULL);
417   config = cfg;
418   GNUNET_TESTING_peer_get_identity (peer,
419                                     &local_id);
420
421   if (0)
422     test_iter ();
423
424   set1 = GNUNET_SET_create (cfg, GNUNET_SET_OPERATION_UNION);
425   set2 = GNUNET_SET_create (cfg, GNUNET_SET_OPERATION_UNION);
426   GNUNET_CRYPTO_hash_create_random (GNUNET_CRYPTO_QUALITY_WEAK, &app_id);
427
428   /* test the real set reconciliation */
429   init_set1 ();
430 }
431
432
433 int
434 main (int argc, char **argv)
435 {
436   empty = 1;
437   if (0 != GNUNET_TESTING_peer_run ("test_set_api",
438                                     "test_set.conf",
439                                     &run, NULL))
440   {
441     return 1;
442   }
443   GNUNET_assert (0 == count_set1);
444   GNUNET_assert (0 == count_set2);
445   empty = 0;
446   if (0 != GNUNET_TESTING_peer_run ("test_set_api",
447                                     "test_set.conf",
448                                     &run, NULL))
449   {
450     return 1;
451   }
452   GNUNET_break (2 == count_set1);
453   GNUNET_break (1 == count_set2);
454   return ret;
455 }