GNUnet  0.19.4
testing_messenger_setup.c
Go to the documentation of this file.
1 /*
2  This file is part of GNUnet.
3  Copyright (C) 2020--2021 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  */
26 #include "platform.h"
28 
29 #include <stdio.h>
30 #include "gnunet_util_lib.h"
32 #include "gnunet_testbed_service.h"
33 #include "gnunet_testing_lib.h"
36 
37 #define TEST_ROOM "test"
38 #define TEST_NAME "tester"
39 
40 struct test_properties;
41 
42 struct test_peer {
44  unsigned int num;
45 
48 
52 
55 
56  unsigned int peer_messages;
57 
58  const char *message;
59 };
60 
62  const struct test_configuration *cfg;
63 
64  unsigned int num_hosts;
65 
68 
70 
71  struct test_peer *peers;
72  unsigned int num_peer;
73 
74  int status;
75 };
76 
77 static void
78 shutdown_cb (void *cls)
79 {
80  struct test_properties *properties = cls;
81 
82 
83  for (unsigned int i = 0; i < properties->num_peer; i++)
84  {
85  struct test_peer *peer = &properties->peers[i];
86 
87  GNUNET_assert(peer != NULL);
88 
89  if (peer->op_task)
90  GNUNET_SCHEDULER_cancel(peer->op_task);
91 
92  peer->op_task = NULL;
93 
94  if (peer->op)
96 
97  peer->op = NULL;
98 
99  if (peer->wait)
101 
102  peer->wait = NULL;
103 
104  if (peer->room)
106 
107  peer->room = NULL;
108 
109  if (peer->handle)
111 
112  peer->handle = NULL;
113  }
114 
115  if (properties->die_task)
116  GNUNET_SCHEDULER_cancel(properties->die_task);
117 
118  properties->die_task = NULL;
119  properties->end_task = NULL;
120 
121  if (properties->barrier)
122  GNUNET_cancel_barrier(properties->barrier);
123 
124  properties->barrier = NULL;
125 }
126 
127 
128 
129 static void
130 end_cb (void *cls)
131 {
132  struct test_properties *properties = cls;
133 
134  GNUNET_assert(properties != NULL);
135 
136  properties->die_task = NULL;
137 
138  int status = 0;
139 
140  for (unsigned int i = 0; i < properties->num_peer; i++)
141  {
142  struct test_peer *peer = &properties->peers[i];
143 
144  GNUNET_assert(peer != NULL);
145 
146  const int members = GNUNET_MESSENGER_iterate_members(peer->room, NULL, NULL);
147 
148  GNUNET_assert (members >= 0);
149 
150  if (peer->props->num_peer != (unsigned int) members)
151  {
152  fprintf (stderr, "Testcase failed (members: %d/%u).\n", members, peer->props->num_peer);
153  status = 1;
154  break;
155  }
156  }
157 
159 
160  properties->status = status;
161 }
162 
163 static void
164 end_badly_cb (void *cls)
165 {
166  struct test_properties *properties = cls;
167 
168  GNUNET_assert(properties != NULL);
169 
170  fprintf (stderr, "Testcase failed (timeout).\n");
171 
172  end_cb (properties);
173 
174  properties->status = 1;
175 }
176 
177 static void
178 end_operation_cb (void *cls)
179 {
180  struct test_peer *peer = cls;
181 
182  GNUNET_assert(peer != NULL);
183 
184  peer->op_task = NULL;
185 
186  fprintf (stderr, "Testcase failed (operation: '%s').\n", peer->message);
187 
189 }
190 
191 static void
192 end_error_cb (void *cls)
193 {
194  struct test_peer *peer = cls;
195 
196  GNUNET_assert(peer != NULL);
197 
198  peer->op_task = NULL;
199 
200  fprintf (stderr, "Testcase failed (error: '%s').\n", peer->message);
201  GNUNET_free (peer);
202 
204 }
205 
206 static void
207 barrier2_wait_cb (void *cls,
208  struct GNUNET_BarrierWaitHandle *waiting,
209  int status)
210 {
211  struct test_peer *peer = cls;
212 
213  GNUNET_assert(peer != NULL);
214 
215  if (peer->wait == waiting)
216  peer->wait = NULL;
217 }
218 
219 static void
220 barrier_wait_cb (void *cls,
221  struct GNUNET_BarrierWaitHandle *waiting,
222  int status)
223 {
224  struct test_peer *peer = cls;
225 
226  GNUNET_assert(peer != NULL);
227 
228  if (peer->wait == waiting)
229  peer->wait = NULL;
230 
231  if (0 != (peer->props->cfg->stages[peer->num - 1] & 0x02))
232  {
233  unsigned int door = peer->props->cfg->doors[peer->num - 1];
234 
235  if (door == 0)
236  door = GNUNET_CRYPTO_random_u32(GNUNET_CRYPTO_QUALITY_WEAK, peer->props->cfg->count);
237  else
238  door = door - 1;
239 
240  struct GNUNET_HashCode hash;
241  GNUNET_CRYPTO_hash (TEST_ROOM, sizeof(TEST_ROOM), &hash);
242 
243  struct GNUNET_MESSENGER_Room *room;
244  room = GNUNET_MESSENGER_enter_room(peer->handle, &(peer->props->peers[door].peer_id), &hash);
245 
246  if (peer->room)
247  GNUNET_assert(room == peer->room);
248  else
249  GNUNET_assert(room != NULL);
250 
251  peer->room = room;
252  }
253 }
254 
265 static void
266 on_message (void *cls,
267  struct GNUNET_MESSENGER_Room *room,
268  const struct GNUNET_MESSENGER_Contact *sender,
269  const struct GNUNET_MESSENGER_Message *message,
270  const struct GNUNET_HashCode *hash,
272 {
273  struct test_peer *peer = cls;
274 
275  GNUNET_assert(peer != NULL);
276 
277  fprintf (stderr, "Peer: %s; [%s] Message: %s (%s)\n",
278  GNUNET_i2s(&(peer->peer_id)),
279  GNUNET_sh2s(&(message->header.sender_id)),
281  GNUNET_h2s(hash));
282 
283  if (GNUNET_MESSENGER_KIND_PEER == message->header.kind)
284  peer->peer_messages++;
285 
286  if (peer->props->num_hosts == peer->peer_messages)
287  peer->wait = GNUNET_wait_barrier (peer->props->barrier, &barrier2_wait_cb, peer);
288  else if (peer->props->num_hosts < peer->peer_messages)
289  {
290  if (peer->wait)
292 
293  peer->wait = NULL;
294 
295  if (peer->op_task)
296  GNUNET_SCHEDULER_cancel(peer->op_task);
297 
298  peer->message = "peer";
300  }
301 }
302 
303 static void
304 second_stage (void *cls)
305 {
306  struct test_peer *peer = cls;
307 
308  GNUNET_assert(peer != NULL);
309 
310  peer->op_task = NULL;
311 
312  struct GNUNET_HashCode hash;
313  GNUNET_CRYPTO_hash (TEST_ROOM, sizeof(TEST_ROOM), &hash);
314 
315  if (0 != (peer->props->cfg->stages[peer->num - 1] & 0x10))
316  {
317  struct GNUNET_MESSENGER_Room *room;
318  room = GNUNET_MESSENGER_open_room (peer->handle, &hash);
319 
320  if (peer->room)
321  GNUNET_assert(room == peer->room);
322  else
323  GNUNET_assert(room != NULL);
324 
325  peer->room = room;
326  }
327 
328  if (0 != (peer->props->cfg->stages[peer->num - 1] & 0x20))
329  {
330  unsigned int door = peer->props->cfg->doors[peer->num - 1];
331 
332  if (door == 0)
333  door = GNUNET_CRYPTO_random_u32(GNUNET_CRYPTO_QUALITY_WEAK, peer->props->cfg->count);
334  else
335  door = door - 1;
336 
337  struct GNUNET_MESSENGER_Room *room;
338  room = GNUNET_MESSENGER_enter_room(peer->handle, &(peer->props->peers[door].peer_id), &hash);
339 
340  if (peer->room)
341  GNUNET_assert(room == peer->room);
342  else
343  GNUNET_assert(room != NULL);
344 
345  peer->room = room;
346  }
347 }
348 
349 static void
350 on_peer (void *cb_cls,
352  const struct GNUNET_TESTBED_PeerInformation *pinfo,
353  const char *emsg)
354 {
355  struct test_peer *peer = cb_cls;
356 
357  GNUNET_assert(peer != NULL);
358 
359  if (emsg)
360  {
361  peer->message = GNUNET_strdup(emsg);
363  return;
364  }
365 
366  if (!pinfo)
367  {
368  peer->message = "info";
370  return;
371  }
372 
374  {
375  peer->message = "config";
377  return;
378  }
379 
380  peer->handle = GNUNET_MESSENGER_connect (pinfo->result.cfg, TEST_NAME, NULL, NULL, &on_message, peer);
381 
383  pinfo->result.cfg, &(peer->peer_id)
384  ));
385 
386  if (0 != (peer->props->cfg->stages[peer->num - 1] & 0x01))
387  {
388  struct GNUNET_HashCode hash;
389  GNUNET_CRYPTO_hash (TEST_ROOM, sizeof(TEST_ROOM), &hash);
390 
391  peer->room = GNUNET_MESSENGER_open_room (peer->handle, &hash);
392 
393  GNUNET_assert(peer->room != NULL);
394  }
395  else
396  peer->room = NULL;
397 
398  peer->wait = GNUNET_wait_barrier (peer->props->barrier, &barrier_wait_cb, peer);
399 }
400 
407 static void
408 run (void *cls,
409  const struct GNUNET_TESTBED_EventInformation *event)
410 {
411  struct test_properties *properties = cls;
412 
413  GNUNET_assert(properties != NULL);
414 
415  if (GNUNET_TESTBED_ET_PEER_START != event->type)
416  {
417  fprintf (stderr, "Testcase failed (operation: 'start').\n");
418 
420  return;
421  }
422 
423  struct test_peer *peer = &(properties->peers[properties->num_peer++]);
424 
425  peer->props = properties;
426  peer->num = properties->num_peer;
427 
428  peer->peer = event->details.peer_start.peer;
430 }
431 
432 static void
433 barrier2_cb (void *cls,
434  struct GNUNET_BarrierHandle *barrier,
435  int status)
436 {
437  struct test_properties *properties = cls;
438 
439  GNUNET_assert(properties != NULL);
440 
441  if (properties->barrier == barrier)
442  properties->barrier = NULL;
443 
444  if (GNUNET_SYSERR == status)
445  {
446  fprintf (stderr, "Testcase failed (operation: 'barrier2').\n");
447 
449  return;
450  }
451  else if (GNUNET_OK == status)
452  {
453  if (properties->die_task)
454  GNUNET_SCHEDULER_cancel(properties->die_task);
455 
456  properties->die_task = GNUNET_SCHEDULER_add_delayed (
458  &end_cb, properties
459  );
460  }
461 }
462 
463 static void
464 barrier_cb (void *cls,
466  int status)
467 {
468  struct test_properties *properties = cls;
469 
470  GNUNET_assert(properties != NULL);
471 
472  if (properties->barrier == barrier)
473  properties->barrier = NULL;
474  else if (!properties->barrier)
475  return;
476 
477  if (properties->num_peer != properties->cfg->count)
478  {
479  fprintf (stderr, "Testcase failed (operation: 'process').\n");
480 
482  return;
483  }
484 
485  if (GNUNET_SYSERR == status)
486  {
487  fprintf (stderr, "Testcase failed (operation: 'barrier').\n");
488 
490  return;
491  }
492  else if (GNUNET_OK == status)
493  {
494  properties->barrier = GNUNET_init_barrier (properties->num_peer, &barrier2_cb, properties);
495 
496  for (unsigned int i = 0; i < properties->num_peer; i++)
497  properties->peers[i].op_task = GNUNET_SCHEDULER_add_now (&second_stage, &(properties->peers[i]));
498  }
499 }
500 
501 static void
502 init (void *cls,
503  struct GNUNET_TESTBED_RunHandle *h,
504  unsigned int num_peers,
505  struct GNUNET_TESTBED_Peer **peers,
506  unsigned int links_succeeded,
507  unsigned int links_failed)
508 {
509  struct test_properties *properties = cls;
510 
511  GNUNET_assert(properties != NULL);
512 
513  properties->end_task = GNUNET_SCHEDULER_add_shutdown(&shutdown_cb, properties);
514  properties->die_task = GNUNET_SCHEDULER_add_delayed (
516  &end_badly_cb, properties
517  );
518 }
519 
520 int
521 GNUNET_run_messenger_setup (const char* test_name,
522  const struct test_configuration *cfg)
523 {
524  struct test_properties properties;
525  memset(&properties, 0, sizeof(properties));
526 
527  properties.cfg = cfg;
528  properties.peers = GNUNET_new_array(cfg->count, struct test_peer);
529 
530  for (unsigned int i = 0; i < cfg->count; i++)
531  if (0 != (cfg->stages[i] & 0x11))
532  properties.num_hosts++;
533 
534  properties.status = 1;
535  properties.barrier = GNUNET_init_barrier (cfg->count, &barrier_cb, &properties);
536 
537  if (GNUNET_OK != GNUNET_TESTBED_test_run (test_name, "test_messenger_api.conf",
538  cfg->count,
540  &run, &properties,
541  &init, &properties))
542  return 1;
543 
544  GNUNET_free(properties.peers);
545 
546  return properties.status;
547 }
static const struct GNUNET_CONFIGURATION_Handle * cfg
Configuration we are using.
Definition: gnunet-abd.c:36
static struct GNUNET_ARM_Operation * op
Current operation.
Definition: gnunet-arm.c:144
static struct GNUNET_ARM_Handle * h
Connection with ARM.
Definition: gnunet-arm.c:99
static struct CadetPeer * peers
Operation to get peer ids.
static unsigned int num_peers
uint16_t status
See PRISM_STATUS_*-constants.
API for submitting data to the testbed logger service.
API for writing tests and creating large-scale emulation testbeds for GNUnet.
Convenience API for writing testcases for GNUnet.
uint32_t GNUNET_CRYPTO_random_u32(enum GNUNET_CRYPTO_Quality mode, uint32_t i)
Produce a random value.
enum GNUNET_GenericReturnValue GNUNET_CRYPTO_get_peer_identity(const struct GNUNET_CONFIGURATION_Handle *cfg, struct GNUNET_PeerIdentity *dst)
Retrieve the identity of the host's peer.
@ GNUNET_CRYPTO_QUALITY_WEAK
No good quality of the operation is needed (i.e., random numbers can be pseudo-random).
void GNUNET_CRYPTO_hash(const void *block, size_t size, struct GNUNET_HashCode *ret)
Compute hash of a given block.
Definition: crypto_hash.c:41
@ GNUNET_OK
@ GNUNET_SYSERR
const char * GNUNET_i2s(const struct GNUNET_PeerIdentity *pid)
Convert a peer identity to a string (for printing debug messages).
#define GNUNET_assert(cond)
Use this for fatal errors that cannot be handled.
const char * GNUNET_sh2s(const struct GNUNET_ShortHashCode *shc)
Convert a short hash value to a string (for printing debug messages).
const char * GNUNET_h2s(const struct GNUNET_HashCode *hc)
Convert a hash value to a string (for printing debug messages).
#define GNUNET_strdup(a)
Wrapper around GNUNET_xstrdup_.
#define GNUNET_new_array(n, type)
Allocate a size n array with structs or unions of the given type.
#define GNUNET_free(ptr)
Wrapper around free.
struct GNUNET_MESSENGER_Room * GNUNET_MESSENGER_enter_room(struct GNUNET_MESSENGER_Handle *handle, const struct GNUNET_PeerIdentity *door, const struct GNUNET_HashCode *key)
Enter a room to send and receive messages through a door opened using GNUNET_MESSENGER_open_room.
int GNUNET_MESSENGER_iterate_members(struct GNUNET_MESSENGER_Room *room, GNUNET_MESSENGER_MemberCallback callback, void *cls)
Iterates through all members of a given room and calls a selected callback for each of them with a pr...
struct GNUNET_MESSENGER_Room * GNUNET_MESSENGER_open_room(struct GNUNET_MESSENGER_Handle *handle, const struct GNUNET_HashCode *key)
Open a room to send and receive messages.
GNUNET_MESSENGER_MessageFlags
Enum for the different supported flags used by message handling Compatible flags can be OR'ed togethe...
struct GNUNET_MESSENGER_Handle * GNUNET_MESSENGER_connect(const struct GNUNET_CONFIGURATION_Handle *cfg, const char *name, GNUNET_MESSENGER_IdentityCallback identity_callback, void *identity_cls, GNUNET_MESSENGER_MessageCallback msg_callback, void *msg_cls)
Set up a handle for the messenger related functions and connects to all necessary services.
const char * GNUNET_MESSENGER_name_of_kind(enum GNUNET_MESSENGER_MessageKind kind)
Get the name of a message kind.
Definition: messenger_api.c:36
void GNUNET_MESSENGER_disconnect(struct GNUNET_MESSENGER_Handle *handle)
Disconnect all of the messengers used services and clears up its used memory.
void GNUNET_MESSENGER_close_room(struct GNUNET_MESSENGER_Room *room)
Close a room which was entered, opened or both in various order and variety.
@ GNUNET_MESSENGER_KIND_PEER
The peer kind.
void GNUNET_SCHEDULER_shutdown(void)
Request the shutdown of a scheduler.
Definition: scheduler.c:562
struct GNUNET_SCHEDULER_Task * GNUNET_SCHEDULER_add_now(GNUNET_SCHEDULER_TaskCallback task, void *task_cls)
Schedule a new task to be run as soon as possible.
Definition: scheduler.c:1299
struct GNUNET_SCHEDULER_Task * GNUNET_SCHEDULER_add_shutdown(GNUNET_SCHEDULER_TaskCallback task, void *task_cls)
Schedule a new task to be run on shutdown, that is when a CTRL-C signal is received,...
Definition: scheduler.c:1334
void * GNUNET_SCHEDULER_cancel(struct GNUNET_SCHEDULER_Task *task)
Cancel the task with the specified identifier.
Definition: scheduler.c:975
struct GNUNET_SCHEDULER_Task * GNUNET_SCHEDULER_add_delayed(struct GNUNET_TIME_Relative delay, GNUNET_SCHEDULER_TaskCallback task, void *task_cls)
Schedule a new task to be run with a specified delay.
Definition: scheduler.c:1272
void GNUNET_TESTBED_operation_done(struct GNUNET_TESTBED_Operation *operation)
This function is used to signal that the event information (struct GNUNET_TESTBED_EventInformation) f...
Definition: testbed_api.c:2021
struct GNUNET_TESTBED_Operation * GNUNET_TESTBED_peer_get_information(struct GNUNET_TESTBED_Peer *peer, enum GNUNET_TESTBED_PeerInformationType pit, GNUNET_TESTBED_PeerInfoCallback cb, void *cb_cls)
Request information about a peer.
int GNUNET_TESTBED_test_run(const char *testname, const char *cfg_filename, unsigned int num_peers, uint64_t event_mask, GNUNET_TESTBED_ControllerCallback cc, void *cc_cls, GNUNET_TESTBED_TestMaster test_master, void *test_master_cls)
Convenience method for running a "simple" test on the local system with a single call from 'main'.
@ GNUNET_TESTBED_PIT_CONFIGURATION
What configuration is the peer using? Returns a 'const struct GNUNET_CONFIGURATION_Handle *'.
@ GNUNET_TESTBED_ET_PEER_START
A peer has been started.
#define GNUNET_TIME_UNIT_SECONDS
One second.
struct GNUNET_TIME_Relative GNUNET_TIME_relative_multiply(struct GNUNET_TIME_Relative rel, unsigned long long factor)
Multiply relative time by a given factor.
Definition: time.c:484
A 512-bit hashcode.
The identity of the host (wraps the signing key of the peer).
Entry in list of pending tasks.
Definition: scheduler.c:136
Argument to GNUNET_TESTBED_ControllerCallback with details about the event.
enum GNUNET_TESTBED_EventType type
Type of the event.
Opaque handle to an abstract operation to be executed by the testing framework.
Data returned from GNUNET_TESTBED_peer_get_information.
struct GNUNET_CONFIGURATION_Handle * cfg
The configuration of the peer.
union GNUNET_TESTBED_PeerInformation::@49 result
The result of the get information operation; Choose according to the pit.
enum GNUNET_TESTBED_PeerInformationType pit
Peer information type; captures which of the types in the 'op_result' is actually in use.
A peer controlled by the testing framework.
struct GNUNET_SCHEDULER_Task * op_task
struct GNUNET_TESTBED_Operation * op
unsigned int num
unsigned int peer_messages
struct test_properties * props
struct GNUNET_BarrierWaitHandle * wait
struct GNUNET_TESTBED_Peer * peer
struct GNUNET_PeerIdentity peer_id
struct GNUNET_MESSENGER_Handle * handle
const char * message
struct GNUNET_MESSENGER_Room * room
const struct test_configuration * cfg
struct test_peer * peers
struct GNUNET_SCHEDULER_Task * end_task
struct GNUNET_SCHEDULER_Task * die_task
struct GNUNET_BarrierHandle * barrier
struct GNUNET_TESTBED_Peer * peer
The peer associated with this model.
void GNUNET_cancel_barrier(struct GNUNET_BarrierHandle *barrier)
Cancel a pseudo-barrier.
void GNUNET_cancel_wait_barrier(struct GNUNET_BarrierWaitHandle *waiting)
Cancel a pseudo-barrier wait handle.
struct GNUNET_BarrierHandle * GNUNET_init_barrier(unsigned int requirement, GNUNET_BarrierStatusCallback cb, void *cb_cls)
Initialise a pseudo-barrier and call the given callback when the required amount of peers (requiremen...
struct GNUNET_BarrierWaitHandle * GNUNET_wait_barrier(struct GNUNET_BarrierHandle *barrier, GNUNET_BarrierWaitStatusCallback cb, void *cb_cls)
Wait for a pseudo-barrier to be crossed.
Pseudo-barriers for simple event handling.
static void barrier_cb(void *cls, struct GNUNET_BarrierHandle *barrier, int status)
static void on_message(void *cls, struct GNUNET_MESSENGER_Room *room, const struct GNUNET_MESSENGER_Contact *sender, const struct GNUNET_MESSENGER_Message *message, const struct GNUNET_HashCode *hash, enum GNUNET_MESSENGER_MessageFlags flags)
Function called whenever a message is received or sent.
static void barrier_wait_cb(void *cls, struct GNUNET_BarrierWaitHandle *waiting, int status)
static void on_peer(void *cb_cls, struct GNUNET_TESTBED_Operation *op, const struct GNUNET_TESTBED_PeerInformation *pinfo, const char *emsg)
static void barrier2_wait_cb(void *cls, struct GNUNET_BarrierWaitHandle *waiting, int status)
static void end_error_cb(void *cls)
#define TEST_NAME
static void shutdown_cb(void *cls)
static void barrier2_cb(void *cls, struct GNUNET_BarrierHandle *barrier, int status)
#define TEST_ROOM
static void end_cb(void *cls)
static void run(void *cls, const struct GNUNET_TESTBED_EventInformation *event)
Main function for a peer of the testcase.
static void second_stage(void *cls)
static void init(void *cls, struct GNUNET_TESTBED_RunHandle *h, unsigned int num_peers, struct GNUNET_TESTBED_Peer **peers, unsigned int links_succeeded, unsigned int links_failed)
static void end_badly_cb(void *cls)
static void end_operation_cb(void *cls)
int GNUNET_run_messenger_setup(const char *test_name, const struct test_configuration *cfg)
A simple test-case setup for the messenger service.