GNUnet  0.10.x
transport-testing-main.c
Go to the documentation of this file.
1 /*
2  This file is part of GNUnet.
3  Copyright (C) 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  */
25 #include "transport-testing.h"
26 
27 
36 
41 
46 
51 
56 
61 };
62 
63 
69 static void
70 do_shutdown(void *cls)
71 {
74 
76  "Testcase shutting down\n");
77  if (NULL != ccc->shutdown_task)
79  if (NULL != ccc->timeout_task)
80  {
82  ccc->timeout_task = NULL;
83  }
84  if (NULL != ccc->connect_task)
85  {
87  ccc->connect_task = NULL;
88  }
89  while (NULL != (crl = ccc->crl_head))
90  {
92  ccc->crl_tail,
93  crl);
95  GNUNET_free(crl);
96  }
97  for (unsigned int i = 0; i < ccc->num_peers; i++)
98  {
99  if (NULL != ccc->p[i])
100  {
102  ccc->p[i] = NULL;
103  }
104  }
105 }
106 
107 
113 static void
114 do_timeout(void *cls)
115 {
117 
118  ccc->timeout_task = NULL;
120  "Testcase timed out\n");
121  ccc->global_ret = GNUNET_SYSERR;
123 }
124 
125 
136 
140  unsigned int off;
141 };
142 
143 
152 
157 };
158 
159 
166 static void
167 connect_cb(void *cls)
168 {
171 
173  ccc->crl_tail,
174  crl);
175  {
176  char *p1_c = GNUNET_strdup(GNUNET_i2s(&crl->p1->id));
177 
179  "Peers connected: %u (%s) <-> %u (%s)\n",
180  crl->p1->no,
181  p1_c,
182  crl->p2->no,
183  GNUNET_i2s(&crl->p2->id));
184  GNUNET_free(p1_c);
185  GNUNET_free(crl);
186  }
187  if (NULL == ccc->crl_head)
188  {
190  "All connections UP, launching custom test logic.\n");
193  }
194 }
195 
196 
206  const struct GNUNET_PeerIdentity *peer)
207 {
208  for (unsigned int i = 0; i < ccc->num_peers; i++)
209  if ((NULL != ccc->p[i]) &&
210  (0 == memcmp(peer,
211  &ccc->p[i]->id,
212  sizeof(*peer))))
213  return ccc->p[i];
214  return NULL;
215 }
216 
217 
226 static void *
227 my_nc(void *cls,
228  const struct GNUNET_PeerIdentity *peer,
229  struct GNUNET_MQ_Handle *mq)
230 {
233  struct ConnectPairInfo *cpi;
234 
235  if (NULL != ccc->nc)
236  ccc->nc(ccc->cls,
237  ccc->p[ipi->off],
238  peer);
239  cpi = GNUNET_new(struct ConnectPairInfo);
240  cpi->ipi = ipi;
241  cpi->sender = peer; /* valid until disconnect */
242  return cpi;
243 }
244 
245 
253 static void
254 my_nd(void *cls,
255  const struct GNUNET_PeerIdentity *peer,
256  void *custom_cls)
257 {
260  struct ConnectPairInfo *cpi = custom_cls;
261 
262  if (NULL != ccc->nd)
263  ccc->nd(ccc->cls,
264  ccc->p[ipi->off],
265  peer);
266  GNUNET_free(cpi);
267 }
268 
269 
277 static int
278 check_test(void *cls,
279  const struct GNUNET_TRANSPORT_TESTING_TestMessage *message)
280 {
281  return GNUNET_OK;
282 }
283 
284 
291 static void
292 handle_test(void *cls,
293  const struct GNUNET_TRANSPORT_TESTING_TestMessage *message)
294 {
295  struct ConnectPairInfo *cpi = cls;
298 
299  if (NULL != ccc->rec)
300  ccc->rec(ccc->cls,
301  ccc->p[ipi->off],
302  cpi->sender,
303  message);
304 }
305 
306 
314 static int
316  const struct GNUNET_TRANSPORT_TESTING_TestMessage *message)
317 {
318  return GNUNET_OK;
319 }
320 
321 
328 static void
330  const struct GNUNET_TRANSPORT_TESTING_TestMessage *message)
331 {
332  struct ConnectPairInfo *cpi = cls;
335 
336  if (NULL != ccc->rec)
337  ccc->rec(ccc->cls,
338  ccc->p[ipi->off],
339  cpi->sender,
340  message);
341 }
342 
343 
349 static void
351 {
353 
354  ccc->connect_task = NULL;
355  for (unsigned int i = 0; i < ccc->num_peers; i++)
356  for (unsigned int j = (ccc->bi_directional ? 0 : i + 1); j < ccc->num_peers; j++)
357  {
359 
360  if (i == j)
361  continue;
364  ccc->crl_tail,
365  crl);
366  crl->ccc = ccc;
367  crl->p1 = ccc->p[i];
368  crl->p2 = ccc->p[j];
369  {
370  char *sender_c = GNUNET_strdup(GNUNET_i2s(&ccc->p[0]->id));
371 
373  "Test tries to connect peer %u (`%s') -> peer %u (`%s')\n",
374  ccc->p[0]->no,
375  sender_c,
376  ccc->p[1]->no,
377  GNUNET_i2s(&ccc->p[1]->id));
378  GNUNET_free(sender_c);
379  }
381  ccc->p[j],
382  &connect_cb,
383  crl);
384  }
385 }
386 
387 
395 static void
396 start_cb(void *cls)
397 {
400  struct GNUNET_TRANSPORT_TESTING_PeerContext *p = ccc->p[ipi->off];
401 
402  ccc->started++;
404  "Peer %u (`%s') started\n",
405  p->no,
406  GNUNET_i2s(&p->id));
407  if (ccc->started != ccc->num_peers)
408  return;
409  if (NULL != ccc->pre_connect_task)
410  {
411  /* Run the custom per-connect job, then give it a second to
412  go into effect before we continue connecting peers. */
415  &do_connect,
416  ccc);
417  }
418  else
419  {
420  do_connect(ccc);
421  }
422 }
423 
424 
435 static void
437  char *const *args,
438  const char *cfgfile,
439  const struct GNUNET_CONFIGURATION_Handle *cfg)
440 {
442  int ok;
443 
444  ccc->cfg = cfg;
446  &do_timeout,
447  ccc);
449  ccc);
450  ok = GNUNET_OK;
451  for (unsigned int i = 0; i < ccc->num_peers; i++)
452  {
453  struct GNUNET_MQ_MessageHandler handlers[] = {
457  NULL),
458  GNUNET_MQ_hd_var_size(test2,
461  NULL),
463  };
465  ccc->cfg_files[i],
466  i + 1,
467  handlers,
468  &my_nc,
469  &my_nd,
470  &ccc->ip[i],
471  &start_cb,
472  &ccc->ip[i]);
473  if (NULL == ccc->p[i])
474  ok = GNUNET_SYSERR;
475  }
476  if (GNUNET_OK != ok)
477  {
479  "Fail! Could not start peers!\n");
481  }
482 }
483 
484 
500 int
502  struct GNUNET_TRANSPORT_TESTING_Handle *tth_,
503  const char *test_plugin_,
504  const char *test_name_,
505  unsigned int num_peers,
506  char *cfg_files[])
507 {
508  static struct GNUNET_GETOPT_CommandLineOption options[] = {
510  };
514  char * argv[] = {
515  (char *)test_name_,
516  "-c",
517  (char *)ccc->config_file,
518  NULL
519  };
520 
521  ccc->num_peers = num_peers;
522  ccc->cfg_files = cfg_files;
523  ccc->test_plugin = test_plugin_;
524  ccc->test_name = test_name_;
525  ccc->tth = tth_;
526  ccc->global_ret = GNUNET_OK;
527  ccc->p = p;
528  ccc->ip = ip;
529  for (unsigned int i = 0; i < num_peers; i++)
530  {
531  ip[i].off = i;
532  ip[i].ccc = ccc;
533  }
534  if (GNUNET_OK !=
535  GNUNET_PROGRAM_run((sizeof(argv) / sizeof(char *)) - 1,
536  argv,
537  test_name_,
538  "nohelp",
539  options,
541  ccc))
542  return GNUNET_SYSERR;
543  return ccc->global_ret;
544 }
545 
546 
557 int
559  const char *filename,
560  unsigned int num_peers,
562  void *check_cls)
563 {
565  char *test_name;
566  char *test_source;
567  char *test_plugin;
568  char *cfg_names[num_peers];
569  int ret;
570 
571  ret = GNUNET_OK;
572  test_name = GNUNET_TRANSPORT_TESTING_get_test_name(argv0);
573  GNUNET_log_setup(test_name,
574  "WARNING",
575  NULL);
576  test_source = GNUNET_TRANSPORT_TESTING_get_test_source_name(filename);
578  test_source);
579  for (unsigned int i = 0; i < num_peers; i++)
580  cfg_names[i] = GNUNET_TRANSPORT_TESTING_get_config_name(argv0,
581  i + 1);
583  if (NULL == tth)
584  {
585  ret = GNUNET_SYSERR;
586  }
587  else
588  {
589  ret = check(check_cls,
590  tth,
591  test_plugin,
592  test_name,
593  num_peers,
594  cfg_names);
596  }
597  for (unsigned int i = 0; i < num_peers; i++)
598  GNUNET_free(cfg_names[i]);
599  GNUNET_free(test_source);
600  GNUNET_free_non_null(test_plugin);
601  GNUNET_free(test_name);
602  return ret;
603 }
604 
605 /* end of transport-testing-main.c */
#define GNUNET_CONTAINER_DLL_remove(head, tail, element)
Remove an element from a DLL.
struct GNUNET_TRANSPORT_TESTING_ConnectRequestList * prev
Stored in a DLL.
static void my_nd(void *cls, const struct GNUNET_PeerIdentity *peer, void *custom_cls)
Wrapper around peers disconnecting.
static int check_test(void *cls, const struct GNUNET_TRANSPORT_TESTING_TestMessage *message)
Wrapper around receiving data.
struct GNUNET_SCHEDULER_Task * connect_task
Task run to connect peers.
Handle for a request to connect two peers.
GNUNET_SCHEDULER_TaskCallback connect_continuation
How should we continue after the connect?
int(* GNUNET_TRANSPORT_TESTING_CheckCallback)(void *cls, struct GNUNET_TRANSPORT_TESTING_Handle *tth_, const char *test_plugin_, const char *test_name_, unsigned int num_peers, char *cfg_files[])
Main function of a testcase.
int global_ret
Result from the main function, set to GNUNET_OK on success.
struct GNUNET_TRANSPORT_TESTING_PeerContext ** p
Array with num_peers entries.
#define GNUNET_CONTAINER_DLL_insert(head, tail, element)
Insert an element at the head of a DLL.
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, or when GNUNET_SCHEDULER_shutdown() is being invoked.
Definition: scheduler.c:1284
struct GNUNET_PeerIdentity id
Peer identity.
const char * test_name
Name of the testcase.
Closure that must be passed to GNUNET_TRANSPORT_TESTING_connect_check.
#define GNUNET_TIME_UNIT_SECONDS
One second.
unsigned int num_peers
Number of peers involved in the test.
struct GNUNET_TRANSPORT_TESTING_Handle * GNUNET_TRANSPORT_TESTING_init()
Initialize the transport testing.
static void do_shutdown(void *cls)
Shutdown function for the test.
struct GNUNET_TRANSPORT_TESTING_Handle * tth
Main testing handle.
Context for a single peer.
static void connect_cb(void *cls)
Function called when we connected two peers.
static int ok
Return value from &#39;main&#39; (0 == success)
const struct GNUNET_PeerIdentity * sender
Peer this is about.
char ** cfg_files
Configuration files we have, array with num_peers entries.
unsigned int off
Offset of the peer this is about.
#define GNUNET_OK
Named constants for return values.
Definition: gnunet_common.h:75
#define GNUNET_free_non_null(ptr)
Free the memory pointed to by ptr if ptr is not NULL.
#define GNUNET_new(type)
Allocate a struct or union of the given type.
Definition of a command line option.
char * GNUNET_TRANSPORT_TESTING_get_test_name(const char *file)
Extracts the test filename from an absolute file name and removes the extension.
struct GNUNET_TRANSPORT_TESTING_ConnectCheckContext * ccc
Overall context of the callback.
unsigned int no
An unique number to identify the peer.
void GNUNET_SCHEDULER_shutdown(void)
Request the shutdown of a scheduler.
Definition: scheduler.c:517
static int ret
Final status code.
Definition: gnunet-arm.c:89
#define GNUNET_strdup(a)
Wrapper around GNUNET_xstrdup_.
static void do_connect(void *cls)
Connect the peers as a clique.
int GNUNET_TRANSPORT_TESTING_connect_check(void *cls, struct GNUNET_TRANSPORT_TESTING_Handle *tth_, const char *test_plugin_, const char *test_name_, unsigned int num_peers, char *cfg_files[])
Common implementation of the GNUNET_TRANSPORT_TESTING_CheckCallback.
void GNUNET_TRANSPORT_TESTING_done(struct GNUNET_TRANSPORT_TESTING_Handle *tth)
Clean up the transport testing.
struct GNUNET_GETOPT_CommandLineOption GNUNET_GETOPT_OPTION_END
Definition: 002.c:13
int GNUNET_TRANSPORT_TESTING_main_(const char *argv0, const char *filename, unsigned int num_peers, GNUNET_TRANSPORT_TESTING_CheckCallback check, void *check_cls)
Setup testcase.
const struct GNUNET_CONFIGURATION_Handle * cfg
Configuration object for the testcase.
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:1237
struct GNUNET_TRANSPORT_TESTING_PeerContext * p1
Peer being connected.
static struct GNUNET_OS_Process * p
Helper process we started.
Definition: gnunet-qr.c:59
void * cls
Closure for mv and cb.
#define GNUNET_MQ_hd_var_size(name, code, str, ctx)
void * cls
Closure for rec, nc and nd.
struct GNUNET_TRANSPORT_TESTING_ConnectRequestList * crl_tail
DLL of active connect requests.
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:1264
const char * config_file
Which configuration file should we pass to the GNUNET_PROGRAM_run() of the testcase?
static void handle_test(void *cls, const struct GNUNET_TRANSPORT_TESTING_TestMessage *message)
Wrapper around receiving data.
static void do_timeout(void *cls)
Testcase hit timeout, shut it down with error.
void * connect_continuation_cls
Closure for connect_continuation.
static char * filename
const char * test_plugin
Name of the plugin.
void * pre_connect_task_cls
Closure for shutdown_task.
Message handler for a specific message type.
struct GNUNET_TRANSPORT_TESTING_InternalPeerContext * ip
Array with num_peers entries.
static struct GNUNET_CONFIGURATION_Handle * cfg
Our configuration.
Definition: gnunet-arm.c:104
#define GNUNET_TRANSPORT_TESTING_SIMPLE_MTYPE2
Alternative message type for tests.
char * GNUNET_TRANSPORT_TESTING_get_test_plugin_name(const char *file, const char *test)
Extracts the plugin name from an absolute file name and the test name.
struct GNUNET_TESTBED_Peer * peer
The peer associated with this model.
#define GNUNET_SYSERR
Definition: gnunet_common.h:76
int bi_directional
Should we try to create connections in both directions?
void GNUNET_TRANSPORT_TESTING_connect_peers_cancel(struct GNUNET_TRANSPORT_TESTING_ConnectRequest *cc)
Cancel the request to connect two peers Tou MUST cancel the request if you stop the peers before the ...
struct GNUNET_TRANSPORT_TESTING_ConnectRequestList * next
Stored in a DLL.
struct GNUNET_TRANSPORT_TESTING_PeerContext * GNUNET_TRANSPORT_TESTING_find_peer(struct GNUNET_TRANSPORT_TESTING_ConnectCheckContext *ccc, const struct GNUNET_PeerIdentity *peer)
Find peer by peer ID.
static unsigned int num_peers
struct GNUNET_TRANSPORT_TESTING_ConnectRequest * GNUNET_TRANSPORT_TESTING_connect_peers(struct GNUNET_TRANSPORT_TESTING_PeerContext *p1, struct GNUNET_TRANSPORT_TESTING_PeerContext *p2, GNUNET_SCHEDULER_TaskCallback cb, void *cls)
Initiate a connection from p1 to p2 by offering p1 p2&#39;s HELLO message.
struct GNUNET_TIME_Relative timeout
When should the testcase time out?
Handle to a message queue.
Definition: mq.c:84
The identity of the host (wraps the signing key of the peer).
struct GNUNET_TRANSPORT_TESTING_PeerContext * p2
Peer being connected.
struct GNUNET_TRANSPORT_TESTING_ConnectRequest * cr
Connect request this is about.
configuration data
Definition: configuration.c:83
char * GNUNET_TRANSPORT_TESTING_get_test_source_name(const char *file)
Extracts the filename from an absolute file name and removes the extension.
static int check_test2(void *cls, const struct GNUNET_TRANSPORT_TESTING_TestMessage *message)
Wrapper around receiving data.
static void * my_nc(void *cls, const struct GNUNET_PeerIdentity *peer, struct GNUNET_MQ_Handle *mq)
Wrapper around peers connecting.
struct GNUNET_TRANSPORT_TESTING_InternalPeerContext * ipi
Information about the receiving peer.
struct GNUNET_MQ_Handle * mq
Definition: 003.c:5
#define GNUNET_log(kind,...)
int GNUNET_PROGRAM_run(int argc, char *const *argv, const char *binaryName, const char *binaryHelp, const struct GNUNET_GETOPT_CommandLineOption *options, GNUNET_PROGRAM_Main task, void *task_cls)
Run a standard GNUnet command startup sequence (initialize loggers and configuration, parse options).
Definition: program.c:367
GNUNET_SCHEDULER_TaskCallback shutdown_task
Custom task to run on shutdown.
GNUNET_SCHEDULER_TaskCallback pre_connect_task
Custom task to run after peers were started but before we try to connect them.
static void start_cb(void *cls)
Function called once we have successfully launched a peer.
GNUNET_TRANSPORT_TESTING_NotifyDisconnect nd
Notify disconnect argument to give for peers we start.
struct GNUNET_SCHEDULER_Task * timeout_task
Task run on timeout.
Information tracked per connected peer.
void GNUNET_TRANSPORT_TESTING_stop_peer(struct GNUNET_TRANSPORT_TESTING_PeerContext *p)
Shutdown the given peer.
int GNUNET_log_setup(const char *comp, const char *loglevel, const char *logfile)
Setup logging.
struct GNUNET_TRANSPORT_TESTING_ConnectCheckContext * ccc
Overall context we are in.
static void connect_check_run(void *cls, char *const *args, const char *cfgfile, const struct GNUNET_CONFIGURATION_Handle *cfg)
Function run from GNUNET_TRANSPORT_TESTING_connect_check once the scheduler is up.
void * shutdown_task_cls
Closure for shutdown_task.
struct GNUNET_TRANSPORT_TESTING_PeerContext * GNUNET_TRANSPORT_TESTING_start_peer(struct GNUNET_TRANSPORT_TESTING_Handle *tth, const char *cfgname, int peer_id, const struct GNUNET_MQ_MessageHandler *handlers, GNUNET_TRANSPORT_NotifyConnect nc, GNUNET_TRANSPORT_NotifyDisconnect nd, void *cb_cls, GNUNET_SCHEDULER_TaskCallback start_cb, void *start_cb_cls)
Start a peer with the given configuration.
struct GNUNET_TRANSPORT_TESTING_ConnectRequestList * crl_head
DLL of active connect requests.
GNUNET_TRANSPORT_TESTING_ReceiveCallback rec
Receiver argument to give for peers we start.
#define GNUNET_TRANSPORT_TESTING_SIMPLE_MTYPE
Message type used by GNUNET_TRANSPORT_TESTING_simple_send().
testing lib for transport service
const char * GNUNET_i2s(const struct GNUNET_PeerIdentity *pid)
Convert a peer identity to a string (for printing debug messages).
#define GNUNET_MQ_handler_end()
End-marker for the handlers array.
unsigned int started
Number of peers that have been started.
static void handle_test2(void *cls, const struct GNUNET_TRANSPORT_TESTING_TestMessage *message)
Wrapper around receiving data.
GNUNET_TRANSPORT_TESTING_NotifyConnect nc
Notify connect argument to give for peers we start.
#define GNUNET_free(ptr)
Wrapper around free.
char * GNUNET_TRANSPORT_TESTING_get_config_name(const char *file, int count)
This function takes the filename (e.g.
void * GNUNET_SCHEDULER_cancel(struct GNUNET_SCHEDULER_Task *task)
Cancel the task with the specified identifier.
Definition: scheduler.c:956