/*
This file is part of GNUnet.
Copyright (C) 2012 GNUnet e.V.
GNUnet is free software: you can redistribute it and/or modify it
under the terms of the GNU Affero General Public License as published
by the Free Software Foundation, either version 3 of the License,
or (at your option) any later version.
GNUnet is distributed in the hope that it will be useful, but
WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
Affero General Public License for more details.
You should have received a copy of the GNU Affero General Public License
along with this program. If not, see .
SPDX-License-Identifier: AGPL3.0-or-later
*/
/**
* @file dht/dht_test_lib.c
* @author Christian Grothoff
* @brief library for writing DHT tests
*/
#include "platform.h"
#include "dht_test_lib.h"
/**
* Test context for a DHT Test.
*/
struct GNUNET_DHT_TEST_Context
{
/**
* Array of running peers.
*/
struct GNUNET_TESTBED_Peer **peers;
/**
* Array of handles to the DHT for each peer.
*/
struct GNUNET_DHT_Handle **dhts;
/**
* Operation associated with the connection to the DHT.
*/
struct GNUNET_TESTBED_Operation **ops;
/**
* Main function of the test to run once all DHTs are available.
*/
GNUNET_DHT_TEST_AppMain app_main;
/**
* Closure for 'app_main'.
*/
void *app_main_cls;
/**
* Number of peers running, size of the arrays above.
*/
unsigned int num_peers;
};
/**
* Adapter function called to establish a connection to
* the DHT service.
*
* @param cls closure
* @param cfg configuration of the peer to connect to; will be available until
* GNUNET_TESTBED_operation_done() is called on the operation returned
* from GNUNET_TESTBED_service_connect()
* @return service handle to return in 'op_result', NULL on error
*/
static void *
dht_connect_adapter (void *cls,
const struct GNUNET_CONFIGURATION_Handle *cfg)
{
return GNUNET_DHT_connect (cfg, 16);
}
/**
* Adapter function called to destroy a connection to
* the DHT service.
*
* @param cls closure
* @param op_result service handle returned from the connect adapter
*/
static void
dht_disconnect_adapter (void *cls,
void *op_result)
{
struct GNUNET_DHT_Handle *dht = op_result;
GNUNET_DHT_disconnect (dht);
}
/**
* Callback to be called when a service connect operation is completed
*
* @param cls the callback closure from functions generating an operation
* @param op the operation that has been finished
* @param ca_result the service handle returned from GNUNET_TESTBED_ConnectAdapter()
* @param emsg error message in case the operation has failed; will be NULL if
* operation has executed successfully.
*/
static void
dht_connect_cb (void *cls,
struct GNUNET_TESTBED_Operation *op,
void *ca_result,
const char *emsg)
{
struct GNUNET_DHT_TEST_Context *ctx = cls;
if (NULL != emsg)
{
fprintf (stderr,
"Failed to connect to DHT service: %s\n",
emsg);
GNUNET_SCHEDULER_shutdown ();
return;
}
for (unsigned int i=0;inum_peers;i++)
if (op == ctx->ops[i])
ctx->dhts[i] = ca_result;
for (unsigned int i=0;inum_peers;i++)
if (NULL == ctx->dhts[i])
return; /* still some DHT connections missing */
/* all DHT connections ready! */
ctx->app_main (ctx->app_main_cls,
ctx,
ctx->num_peers,
ctx->peers,
ctx->dhts);
}
/**
* Clean up the testbed.
*
* @param ctx handle for the testbed
*/
void
GNUNET_DHT_TEST_cleanup (struct GNUNET_DHT_TEST_Context *ctx)
{
for (unsigned int i=0;inum_peers;i++)
GNUNET_TESTBED_operation_done (ctx->ops[i]);
GNUNET_free (ctx->ops);
GNUNET_free (ctx->dhts);
GNUNET_free (ctx);
GNUNET_SCHEDULER_shutdown ();
}
static void
dht_test_run (void *cls,
struct GNUNET_TESTBED_RunHandle *h,
unsigned int num_peers,
struct GNUNET_TESTBED_Peer **peers,
unsigned int links_succeeded,
unsigned int links_failed)
{
struct GNUNET_DHT_TEST_Context *ctx = cls;
GNUNET_assert (num_peers == ctx->num_peers);
ctx->peers = peers;
for (unsigned int i=0;iops[i] = GNUNET_TESTBED_service_connect (ctx,
peers[i],
"dht",
&dht_connect_cb,
ctx,
&dht_connect_adapter,
&dht_disconnect_adapter,
ctx);
}
/**
* Run a test using the given name, configuration file and number of
* peers.
*
* @param testname name of the test (for logging)
* @param cfgname name of the configuration file
* @param num_peers number of peers to start
* @param tmain main function to run once the testbed is ready
* @param tmain_cls closure for 'tmain'
*/
void
GNUNET_DHT_TEST_run (const char *testname,
const char *cfgname,
unsigned int num_peers,
GNUNET_DHT_TEST_AppMain tmain,
void *tmain_cls)
{
struct GNUNET_DHT_TEST_Context *ctx;
ctx = GNUNET_new (struct GNUNET_DHT_TEST_Context);
ctx->num_peers = num_peers;
ctx->ops = GNUNET_new_array (num_peers,
struct GNUNET_TESTBED_Operation *);
ctx->dhts = GNUNET_new_array (num_peers,
struct GNUNET_DHT_Handle *);
ctx->app_main = tmain;
ctx->app_main_cls = tmain_cls;
(void) GNUNET_TESTBED_test_run (testname,
cfgname,
num_peers,
0LL, NULL, NULL,
&dht_test_run, ctx);
}
/* end of dht_test_lib.c */