/*
This file is part of GNUnet.
Copyright (C) 2008--2013, 2016 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 testbed/gnunet-service-testbed.c
* @brief implementation of the TESTBED service
* @author Sree Harsha Totakura
*/
#include "gnunet-service-testbed.h"
#include "gnunet-service-testbed_barriers.h"
#include "gnunet-service-testbed_connectionpool.h"
/***********/
/* Globals */
/***********/
/**
* Our configuration
*/
struct GNUNET_CONFIGURATION_Handle *GST_config;
/**
* The master context; generated with the first INIT message
*/
struct Context *GST_context;
/**
* Array of hosts
*/
struct GNUNET_TESTBED_Host **GST_host_list;
/**
* DLL head for forwarded operation contexts
*/
struct ForwardedOperationContext *fopcq_head;
/**
* DLL tail for forwarded operation contexts
*/
struct ForwardedOperationContext *fopcq_tail;
/**
* Operation queue for open file descriptors
*/
struct OperationQueue *GST_opq_openfds;
/**
* Timeout for operations which may take some time
*/
struct GNUNET_TIME_Relative GST_timeout;
/**
* The size of the host list
*/
unsigned int GST_host_list_size;
/**
* The size of the peer list
*/
unsigned int GST_peer_list_size;
/***********************************/
/* Local definitions and variables */
/***********************************/
/**
* Our hostname; we give this to all the peers we start
*/
static char *hostname;
/**
* Function to add a host to the current list of known hosts
*
* @param host the host to add
* @return #GNUNET_OK on success; #GNUNET_SYSERR on failure due to host-id
* already in use
*/
static int
host_list_add(struct GNUNET_TESTBED_Host *host)
{
uint32_t host_id;
host_id = GNUNET_TESTBED_host_get_id_(host);
if (GST_host_list_size <= host_id)
GST_array_grow_large_enough(GST_host_list, GST_host_list_size, host_id);
if (NULL != GST_host_list[host_id])
{
LOG_DEBUG("A host with id: %u already exists\n", host_id);
return GNUNET_SYSERR;
}
GST_host_list[host_id] = host;
return GNUNET_OK;
}
/**
* Send operation failure message to client
*
* @param client the client to which the failure message has to be sent to
* @param operation_id the id of the failed operation
* @param emsg the error message; can be NULL
*/
void
GST_send_operation_fail_msg(struct GNUNET_SERVICE_Client *client,
uint64_t operation_id,
const char *emsg)
{
struct GNUNET_MQ_Envelope *env;
struct GNUNET_TESTBED_OperationFailureEventMessage *msg;
uint16_t emsg_len;
emsg_len = (NULL == emsg) ? 0 : strlen(emsg) + 1;
env = GNUNET_MQ_msg_extra(msg,
emsg_len,
GNUNET_MESSAGE_TYPE_TESTBED_OPERATION_FAIL_EVENT);
msg->event_type = htonl(GNUNET_TESTBED_ET_OPERATION_FINISHED);
msg->operation_id = GNUNET_htonll(operation_id);
GNUNET_memcpy(&msg[1],
emsg,
emsg_len);
GNUNET_MQ_send(GNUNET_SERVICE_client_get_mq(client),
env);
}
/**
* Function to send generic operation success message to given client
*
* @param client the client to send the message to
* @param operation_id the id of the operation which was successful
*/
void
GST_send_operation_success_msg(struct GNUNET_SERVICE_Client *client,
uint64_t operation_id)
{
struct GNUNET_MQ_Envelope *env;
struct GNUNET_TESTBED_GenericOperationSuccessEventMessage *msg;
env = GNUNET_MQ_msg(msg,
GNUNET_MESSAGE_TYPE_TESTBED_GENERIC_OPERATION_SUCCESS);
msg->operation_id = GNUNET_htonll(operation_id);
msg->event_type = htonl(GNUNET_TESTBED_ET_OPERATION_FINISHED);
GNUNET_MQ_send(GNUNET_SERVICE_client_get_mq(client),
env);
}
/**
* Callback which will be called after a host registration succeeded or failed
*
* @param cls the handle to the slave at which the registration is completed
* @param emsg the error message; NULL if host registration is successful
*/
static void
hr_completion(void *cls,
const char *emsg);
/**
* Attempts to register the next host in the host registration queue
*
* @param slave the slave controller whose host registration queue is checked
* for host registrations
*/
static void
register_next_host(struct Slave *slave)
{
struct HostRegistration *hr;
hr = slave->hr_dll_head;
GNUNET_assert(NULL != hr);
GNUNET_assert(NULL == slave->rhandle);
LOG(GNUNET_ERROR_TYPE_DEBUG, "Registering host %u at %u\n",
GNUNET_TESTBED_host_get_id_(hr->host),
GNUNET_TESTBED_host_get_id_(GST_host_list[slave->host_id]));
slave->rhandle
= GNUNET_TESTBED_register_host(slave->controller,
hr->host,
hr_completion,
slave);
}
/**
* Callback which will be called to after a host registration succeeded or failed
*
* @param cls the handle to the slave at which the registration is completed
* @param emsg the error message; NULL if host registration is successful
*/
static void
hr_completion(void *cls,
const char *emsg)
{
struct Slave *slave = cls;
struct HostRegistration *hr;
slave->rhandle = NULL;
hr = slave->hr_dll_head;
GNUNET_assert(NULL != hr);
LOG(GNUNET_ERROR_TYPE_DEBUG,
"Registering host %u at %u successful\n",
GNUNET_TESTBED_host_get_id_(hr->host),
GNUNET_TESTBED_host_get_id_(GST_host_list[slave->host_id]));
GNUNET_CONTAINER_DLL_remove(slave->hr_dll_head,
slave->hr_dll_tail,
hr);
if (NULL != hr->cb)
hr->cb(hr->cb_cls,
emsg);
GNUNET_free(hr);
if (NULL != slave->hr_dll_head)
register_next_host(slave);
}
/**
* Adds a host registration's request to a slave's registration queue
*
* @param slave the slave controller at which the given host has to be
* registered
* @param cb the host registration completion callback
* @param cb_cls the closure for the host registration completion callback
* @param host the host which has to be registered
*/
void
GST_queue_host_registration(struct Slave *slave,
GNUNET_TESTBED_HostRegistrationCompletion cb,
void *cb_cls,
struct GNUNET_TESTBED_Host *host)
{
struct HostRegistration *hr;
int call_register;
LOG(GNUNET_ERROR_TYPE_DEBUG,
"Queueing host registration for host %u at %u\n",
GNUNET_TESTBED_host_get_id_(host),
GNUNET_TESTBED_host_get_id_(GST_host_list[slave->host_id]));
hr = GNUNET_new(struct HostRegistration);
hr->cb = cb;
hr->cb_cls = cb_cls;
hr->host = host;
call_register = (NULL == slave->hr_dll_head) ? GNUNET_YES : GNUNET_NO;
GNUNET_CONTAINER_DLL_insert_tail(slave->hr_dll_head,
slave->hr_dll_tail,
hr);
if (GNUNET_YES == call_register)
register_next_host(slave);
}
/**
* Callback to relay the reply msg of a forwarded operation back to the client
*
* @param cls ForwardedOperationContext
* @param msg the message to relay
*/
void
GST_forwarded_operation_reply_relay(void *cls,
const struct GNUNET_MessageHeader *msg)
{
struct ForwardedOperationContext *fopc = cls;
struct GNUNET_MQ_Envelope *env;
LOG_DEBUG("Relaying message with type: %u, size: %u\n",
ntohs(msg->type),
ntohs(msg->size));
env = GNUNET_MQ_msg_copy(msg);
GNUNET_MQ_send(GNUNET_SERVICE_client_get_mq(fopc->client),
env);
GNUNET_SCHEDULER_cancel(fopc->timeout_task);
GNUNET_CONTAINER_DLL_remove(fopcq_head,
fopcq_tail,
fopc);
GNUNET_free(fopc);
}
/**
* Task to free resources when forwarded operation has been timed out
*
* @param cls the ForwardedOperationContext
*/
void
GST_forwarded_operation_timeout(void *cls)
{
struct ForwardedOperationContext *fopc = cls;
fopc->timeout_task = NULL;
GNUNET_TESTBED_forward_operation_msg_cancel_(fopc->opc);
LOG(GNUNET_ERROR_TYPE_DEBUG,
"A forwarded operation has timed out\n");
GST_send_operation_fail_msg(fopc->client,
fopc->operation_id,
"A forwarded operation has timed out");
GNUNET_CONTAINER_DLL_remove(fopcq_head,
fopcq_tail,
fopc);
GNUNET_free(fopc);
}
/**
* Parse service sharing specification line.
* Format is "[] [] ..."
*
* @param ss_str the spec string to be parsed
* @param cfg the configuration to use for shared services
* @return an array suitable to pass to GNUNET_TESTING_system_create(). NULL
* upon empty service sharing specification.
*/
static struct GNUNET_TESTING_SharedService *
parse_shared_services(char *ss_str,
struct GNUNET_CONFIGURATION_Handle *cfg)
{
struct GNUNET_TESTING_SharedService ss;
struct GNUNET_TESTING_SharedService *slist;
char service[256];
char *arg;
unsigned int n;
#define GROW_SS \
do { \
GNUNET_array_grow(slist, n, n + 1); \
GNUNET_memcpy(&slist[n - 1], &ss, \
sizeof(struct GNUNET_TESTING_SharedService)); \
} while (0)
slist = NULL;
n = 0;
ss.cfg = cfg;
for (; NULL != (arg = strtok(ss_str, " ")); ss_str = NULL)
{
ss.service = NULL;
ss.share = 0;
if (2 != sscanf(arg, "%255[^:]:%u",
service,
&ss.share))
{
LOG(GNUNET_ERROR_TYPE_WARNING,
"Ignoring shared service spec: %s",
arg);
continue;
}
LOG_DEBUG("Will be sharing %s service among %u peers\n",
service,
ss.share);
ss.service = GNUNET_strdup(service);
GROW_SS;
}
if (NULL != slist)
{
/* Add trailing NULL block */
(void)memset(&ss,
0,
sizeof(struct GNUNET_TESTING_SharedService));
GROW_SS;
}
return slist;
#undef GROW_SS
}
/**
* Check #GNUNET_MESSAGE_TYPE_TESTBED_INIT messages
*
* @param cls identification of the client
* @param message the actual message
* @return #GNUNET_OK if @a message is well-formed
*/
static int
check_init(void *cls,
const struct GNUNET_TESTBED_InitMessage *msg)
{
const char *controller_hostname;
uint16_t msize;
msize = ntohs(msg->header.size) - sizeof(struct GNUNET_TESTBED_InitMessage);
controller_hostname = (const char *)&msg[1];
if ('\0' != controller_hostname[msize - 1])
{
GNUNET_break(0);
return GNUNET_SYSERR;
}
return GNUNET_OK;
}
/**
* Message handler for #GNUNET_MESSAGE_TYPE_TESTBED_INIT messages
*
* @param cls identification of the client
* @param message the actual message
*/
static void
handle_init(void *cls,
const struct GNUNET_TESTBED_InitMessage *msg)
{
struct GNUNET_SERVICE_Client *client = cls;
struct GNUNET_TESTBED_Host *host;
const char *controller_hostname;
char *ss_str;
struct GNUNET_TESTING_SharedService *ss;
unsigned int cnt;
if (NULL != GST_context)
{
LOG_DEBUG("We are being connected to laterally\n");
GNUNET_SERVICE_client_continue(client);
return;
}
controller_hostname = (const char *)&msg[1];
ss_str = NULL;
ss = NULL;
if (GNUNET_OK ==
GNUNET_CONFIGURATION_get_value_string(GST_config,
"TESTBED",
"SHARED_SERVICES",
&ss_str))
{
ss = parse_shared_services(ss_str,
GST_config);
GNUNET_free(ss_str);
ss_str = NULL;
}
GST_context = GNUNET_new(struct Context);
GST_context->client = client;
GST_context->host_id = ntohl(msg->host_id);
GST_context->master_ip = GNUNET_strdup(controller_hostname);
LOG_DEBUG("Our IP: %s\n",
GST_context->master_ip);
GST_context->system
= GNUNET_TESTING_system_create("testbed",
GST_context->master_ip,
hostname,
ss);
if (NULL != ss)
{
for (cnt = 0; NULL != ss[cnt].service; cnt++)
{
ss_str = (char *)ss[cnt].service;
GNUNET_free(ss_str);
}
GNUNET_free(ss);
ss = NULL;
}
host =
GNUNET_TESTBED_host_create_with_id(GST_context->host_id,
GST_context->master_ip,
NULL,
GST_config,
0);
host_list_add(host);
LOG_DEBUG("Created master context with host ID: %u\n",
GST_context->host_id);
GNUNET_SERVICE_client_continue(client);
}
/**
* Check #GNUNET_MESSAGE_TYPE_TESTBED_ADDHOST messages
*
* @param cls identification of the client
* @param msg the actual message
* @return #GNUNET_OK if @a message is well-formed
*/
static int
check_add_host(void *cls,
const struct GNUNET_TESTBED_AddHostMessage *msg)
{
uint16_t username_length;
uint16_t hostname_length;
uint16_t msize;
msize = ntohs(msg->header.size) - sizeof(struct GNUNET_TESTBED_AddHostMessage);
username_length = ntohs(msg->username_length);
hostname_length = ntohs(msg->hostname_length);
/* msg must contain hostname */
if ((msize <= username_length) ||
(0 == hostname_length))
{
GNUNET_break(0);
return GNUNET_SYSERR;
}
/* msg must contain configuration */
if (msize <= username_length + hostname_length)
{
GNUNET_break(0);
return GNUNET_SYSERR;
}
return GNUNET_OK;
}
/**
* Message handler for #GNUNET_MESSAGE_TYPE_TESTBED_ADDHOST messages
*
* @param cls identification of the client
* @param msg the actual message
*/
static void
handle_add_host(void *cls,
const struct GNUNET_TESTBED_AddHostMessage *msg)
{
struct GNUNET_SERVICE_Client *client = cls;
struct GNUNET_TESTBED_Host *host;
struct GNUNET_TESTBED_HostConfirmedMessage *reply;
struct GNUNET_CONFIGURATION_Handle *host_cfg;
char *username;
char *hostname;
char *emsg;
const void *ptr;
uint32_t host_id;
uint16_t username_length;
uint16_t hostname_length;
struct GNUNET_MQ_Envelope *env;
username_length = ntohs(msg->username_length);
hostname_length = ntohs(msg->hostname_length);
username = NULL;
hostname = NULL;
ptr = &msg[1];
if (0 != username_length)
{
username = GNUNET_malloc(username_length + 1);
GNUNET_strlcpy(username, ptr, username_length + 1);
ptr += username_length;
}
hostname = GNUNET_malloc(hostname_length + 1);
GNUNET_strlcpy(hostname, ptr, hostname_length + 1);
if (NULL == (host_cfg = GNUNET_TESTBED_extract_config_(&msg->header)))
{
GNUNET_free_non_null(username);
GNUNET_free_non_null(hostname);
GNUNET_break_op(0);
GNUNET_SERVICE_client_drop(client);
return;
}
host_id = ntohl(msg->host_id);
LOG_DEBUG("Received ADDHOST %u message\n", host_id);
LOG_DEBUG("-------host id: %u\n", host_id);
LOG_DEBUG("-------hostname: %s\n", hostname);
if (NULL != username)
LOG_DEBUG("-------username: %s\n", username);
else
LOG_DEBUG("-------username: \n");
LOG_DEBUG("-------ssh port: %u\n", ntohs(msg->ssh_port));
host = GNUNET_TESTBED_host_create_with_id(host_id,
hostname,
username,
host_cfg,
ntohs(msg->ssh_port));
GNUNET_free_non_null(username);
GNUNET_free(hostname);
GNUNET_CONFIGURATION_destroy(host_cfg);
if (NULL == host)
{
GNUNET_break_op(0);
GNUNET_SERVICE_client_drop(client);
return;
}
if (GNUNET_OK != host_list_add(host))
{
/* We are unable to add a host */
emsg = "A host exists with given host-id";
LOG_DEBUG("%s: %u",
emsg,
host_id);
GNUNET_TESTBED_host_destroy(host);
env = GNUNET_MQ_msg_extra(reply,
strlen(emsg) + 1,
GNUNET_MESSAGE_TYPE_TESTBED_ADD_HOST_SUCCESS);
GNUNET_memcpy(&reply[1],
emsg,
strlen(emsg) + 1);
}
else
{
LOG_DEBUG("Added host %u at %u\n",
host_id,
GST_context->host_id);
env = GNUNET_MQ_msg(reply,
GNUNET_MESSAGE_TYPE_TESTBED_ADD_HOST_SUCCESS);
}
reply->host_id = htonl(host_id);
GNUNET_MQ_send(GNUNET_SERVICE_client_get_mq(client),
env);
GNUNET_SERVICE_client_continue(client);
}
/**
* Handler for #GNUNET_MESSAGE_TYPE_TESTBED_GETSLAVECONFIG messages
*
* @param cls identification of the client
* @param msg the actual message
*/
static void
handle_slave_get_config(void *cls,
const struct GNUNET_TESTBED_SlaveGetConfigurationMessage *msg)
{
struct GNUNET_SERVICE_Client *client = cls;
struct Slave *slave;
struct GNUNET_TESTBED_SlaveConfiguration *reply;
const struct GNUNET_CONFIGURATION_Handle *cfg;
struct GNUNET_MQ_Envelope *env;
char *config;
char *xconfig;
size_t config_size;
size_t xconfig_size;
uint64_t op_id;
uint32_t slave_id;
slave_id = ntohl(msg->slave_id);
op_id = GNUNET_ntohll(msg->operation_id);
if ((GST_slave_list_size <= slave_id) ||
(NULL == GST_slave_list[slave_id]))
{
/* FIXME: Add forwardings for this type of message here.. */
GST_send_operation_fail_msg(client,
op_id,
"Slave not found");
GNUNET_SERVICE_client_continue(client);
return;
}
slave = GST_slave_list[slave_id];
GNUNET_assert(NULL != (cfg = GNUNET_TESTBED_host_get_cfg_(GST_host_list[slave->host_id])));
config = GNUNET_CONFIGURATION_serialize(cfg,
&config_size);
/* FIXME: maybe we want to transmit the delta to the default here? */
xconfig_size = GNUNET_TESTBED_compress_config_(config,
config_size,
&xconfig);
GNUNET_free(config);
GNUNET_assert(xconfig_size + sizeof(struct GNUNET_TESTBED_SlaveConfiguration) <= UINT16_MAX);
GNUNET_assert(xconfig_size <= UINT16_MAX);
env = GNUNET_MQ_msg_extra(reply,
xconfig_size,
GNUNET_MESSAGE_TYPE_TESTBED_SLAVE_CONFIGURATION);
reply->slave_id = msg->slave_id;
reply->operation_id = msg->operation_id;
reply->config_size = htons((uint16_t)config_size);
GNUNET_memcpy(&reply[1],
xconfig,
xconfig_size);
GNUNET_free(xconfig);
GNUNET_MQ_send(GNUNET_SERVICE_client_get_mq(client),
env);
GNUNET_SERVICE_client_continue(client);
}
/**
* Clears the forwarded operations queue
*/
void
GST_clear_fopcq()
{
struct ForwardedOperationContext *fopc;
while (NULL != (fopc = fopcq_head))
{
GNUNET_CONTAINER_DLL_remove(fopcq_head,
fopcq_tail,
fopc);
GNUNET_TESTBED_forward_operation_msg_cancel_(fopc->opc);
if (NULL != fopc->timeout_task)
GNUNET_SCHEDULER_cancel(fopc->timeout_task);
switch (fopc->type)
{
case OP_PEER_CREATE:
GNUNET_free(fopc->cls);
break;
case OP_SHUTDOWN_PEERS:
{
struct HandlerContext_ShutdownPeers *hc = fopc->cls;
GNUNET_assert(0 < hc->nslaves);
hc->nslaves--;
if (0 == hc->nslaves)
GNUNET_free(hc);
}
break;
case OP_PEER_START:
case OP_PEER_STOP:
case OP_PEER_DESTROY:
case OP_PEER_INFO:
case OP_OVERLAY_CONNECT:
case OP_LINK_CONTROLLERS:
case OP_GET_SLAVE_CONFIG:
case OP_MANAGE_SERVICE:
case OP_PEER_RECONFIGURE:
break;
case OP_FORWARDED:
GNUNET_assert(0);
}
;
GNUNET_free(fopc);
}
}
/**
* Task to clean up and shutdown nicely
*
* @param cls NULL
*/
static void
shutdown_task(void *cls)
{
uint32_t id;
LOG_DEBUG("Shutting down testbed service\n");
/* cleanup any remaining forwarded operations */
GST_clear_fopcq();
GST_free_lcf();
GST_free_mctxq();
GST_free_occq();
GST_free_roccq();
GST_free_nccq();
GST_neighbour_list_clean();
GST_free_prcq();
/* Clear peer list */
GST_destroy_peers();
/* Clear route list */
GST_route_list_clear();
/* Clear GST_slave_list */
GST_slave_list_clear();
/* Clear host list */
for (id = 0; id < GST_host_list_size; id++)
if (NULL != GST_host_list[id])
GNUNET_TESTBED_host_destroy(GST_host_list[id]);
GNUNET_free_non_null(GST_host_list);
if (NULL != GST_context)
{
GNUNET_free_non_null(GST_context->master_ip);
if (NULL != GST_context->system)
GNUNET_TESTING_system_destroy(GST_context->system,
GNUNET_YES);
GNUNET_free(GST_context);
GST_context = NULL;
}
GNUNET_free_non_null(hostname);
/* Free hello cache */
GST_cache_clear();
GST_connection_pool_destroy();
GNUNET_TESTBED_operation_queue_destroy_(GST_opq_openfds);
GST_opq_openfds = NULL;
GST_stats_destroy();
GST_barriers_destroy();
GNUNET_CONFIGURATION_destroy(GST_config);
}
/**
* Callback for client connect
*
* @param cls NULL
* @param client the client which has disconnected
* @param mq queue for sending messages to @a client
* @return @a client
*/
static void *
client_connect_cb(void *cls,
struct GNUNET_SERVICE_Client *client,
struct GNUNET_MQ_Handle *mq)
{
return client;
}
/**
* Callback for client disconnect
*
* @param cls NULL
* @param client the client which has disconnected
* @param app_ctx should match @a client
*/
static void
client_disconnect_cb(void *cls,
struct GNUNET_SERVICE_Client *client,
void *app_ctx)
{
struct ForwardedOperationContext *fopc;
struct ForwardedOperationContext *fopcn;
GNUNET_assert(client == app_ctx);
GST_notify_client_disconnect_oc(client);
GST_link_notify_disconnect(client);
GST_notify_client_disconnect_peers(client);
for (fopc = fopcq_head; NULL != fopc; fopc = fopcn)
{
fopcn = fopc->next;
if (fopc->client == client)
{
/* handle as if it were a timeout */
GNUNET_SCHEDULER_cancel(fopc->timeout_task);
GST_forwarded_operation_timeout(fopc);
}
}
if (NULL == GST_context)
return;
if (client == GST_context->client)
{
LOG(GNUNET_ERROR_TYPE_DEBUG,
"Master client disconnected\n");
GST_context->client = NULL;
/* should not be needed as we're terminated by failure to read
* from stdin, but if stdin fails for some reason, this shouldn't
* hurt for now --- might need to revise this later if we ever
* decide that master connections might be temporarily down
* for some reason */
//GNUNET_SCHEDULER_shutdown ();
}
}
/**
* Testbed setup
*
* @param cls closure
* @param cfg configuration to use
* @param service the initialized server
*/
static void
testbed_run(void *cls,
const struct GNUNET_CONFIGURATION_Handle *cfg,
struct GNUNET_SERVICE_Handle *service)
{
char *logfile;
unsigned long long num;
LOG_DEBUG("Starting testbed\n");
if (GNUNET_OK ==
GNUNET_CONFIGURATION_get_value_filename(cfg, "TESTBED", "LOG_FILE",
&logfile))
{
GNUNET_break(GNUNET_OK ==
GNUNET_log_setup("testbed",
"DEBUG",
logfile));
GNUNET_free(logfile);
}
GNUNET_assert(GNUNET_OK ==
GNUNET_CONFIGURATION_get_value_number(cfg,
"testbed",
"CACHE_SIZE",
&num));
GST_cache_init((unsigned int)num);
GST_connection_pool_init((unsigned int)num);
GNUNET_assert(GNUNET_OK ==
GNUNET_CONFIGURATION_get_value_number(cfg,
"testbed",
"MAX_OPEN_FDS",
&num));
GST_opq_openfds = GNUNET_TESTBED_operation_queue_create_(OPERATION_QUEUE_TYPE_FIXED,
(unsigned int)num);
GNUNET_assert(GNUNET_OK ==
GNUNET_CONFIGURATION_get_value_time(cfg,
"testbed",
"OPERATION_TIMEOUT",
&GST_timeout));
GNUNET_assert(GNUNET_OK ==
GNUNET_CONFIGURATION_get_value_string(cfg,
"testbed",
"HOSTNAME",
&hostname));
GST_config = GNUNET_CONFIGURATION_dup(cfg);
GNUNET_SCHEDULER_add_shutdown(&shutdown_task,
NULL);
LOG_DEBUG("Testbed startup complete\n");
GST_stats_init(GST_config);
GST_barriers_init(GST_config);
}
/**
* Define "main" method using service macro.
*/
GNUNET_SERVICE_MAIN
("testbed",
GNUNET_SERVICE_OPTION_NONE,
&testbed_run,
&client_connect_cb,
&client_disconnect_cb,
NULL,
GNUNET_MQ_hd_var_size(init,
GNUNET_MESSAGE_TYPE_TESTBED_INIT,
struct GNUNET_TESTBED_InitMessage,
NULL),
GNUNET_MQ_hd_var_size(add_host,
GNUNET_MESSAGE_TYPE_TESTBED_ADD_HOST,
struct GNUNET_TESTBED_AddHostMessage,
NULL),
GNUNET_MQ_hd_fixed_size(slave_get_config,
GNUNET_MESSAGE_TYPE_TESTBED_GET_SLAVE_CONFIGURATION,
struct GNUNET_TESTBED_SlaveGetConfigurationMessage,
NULL),
GNUNET_MQ_hd_fixed_size(link_controllers,
GNUNET_MESSAGE_TYPE_TESTBED_LINK_CONTROLLERS,
struct GNUNET_TESTBED_ControllerLinkRequest,
NULL),
GNUNET_MQ_hd_var_size(remote_overlay_connect,
GNUNET_MESSAGE_TYPE_TESTBED_REMOTE_OVERLAY_CONNECT,
struct GNUNET_TESTBED_RemoteOverlayConnectMessage,
NULL),
GNUNET_MQ_hd_fixed_size(overlay_connect,
GNUNET_MESSAGE_TYPE_TESTBED_OVERLAY_CONNECT,
struct GNUNET_TESTBED_OverlayConnectMessage,
NULL),
GNUNET_MQ_hd_var_size(peer_create,
GNUNET_MESSAGE_TYPE_TESTBED_CREATE_PEER,
struct GNUNET_TESTBED_PeerCreateMessage,
NULL),
GNUNET_MQ_hd_fixed_size(peer_destroy,
GNUNET_MESSAGE_TYPE_TESTBED_DESTROY_PEER,
struct GNUNET_TESTBED_PeerDestroyMessage,
NULL),
GNUNET_MQ_hd_fixed_size(peer_start,
GNUNET_MESSAGE_TYPE_TESTBED_START_PEER,
struct GNUNET_TESTBED_PeerStartMessage,
NULL),
GNUNET_MQ_hd_fixed_size(peer_stop,
GNUNET_MESSAGE_TYPE_TESTBED_STOP_PEER,
struct GNUNET_TESTBED_PeerStopMessage,
NULL),
GNUNET_MQ_hd_fixed_size(peer_get_config,
GNUNET_MESSAGE_TYPE_TESTBED_GET_PEER_INFORMATION,
struct GNUNET_TESTBED_PeerGetConfigurationMessage,
NULL),
GNUNET_MQ_hd_var_size(manage_peer_service,
GNUNET_MESSAGE_TYPE_TESTBED_MANAGE_PEER_SERVICE,
struct GNUNET_TESTBED_ManagePeerServiceMessage,
NULL),
GNUNET_MQ_hd_fixed_size(shutdown_peers,
GNUNET_MESSAGE_TYPE_TESTBED_SHUTDOWN_PEERS,
struct GNUNET_TESTBED_ShutdownPeersMessage,
NULL),
GNUNET_MQ_hd_var_size(peer_reconfigure,
GNUNET_MESSAGE_TYPE_TESTBED_RECONFIGURE_PEER,
struct GNUNET_TESTBED_PeerReconfigureMessage,
NULL),
GNUNET_MQ_hd_var_size(barrier_init,
GNUNET_MESSAGE_TYPE_TESTBED_BARRIER_INIT,
struct GNUNET_TESTBED_BarrierInit,
NULL),
GNUNET_MQ_hd_var_size(barrier_cancel,
GNUNET_MESSAGE_TYPE_TESTBED_BARRIER_CANCEL,
struct GNUNET_TESTBED_BarrierCancel,
NULL),
GNUNET_MQ_hd_var_size(barrier_status,
GNUNET_MESSAGE_TYPE_TESTBED_BARRIER_STATUS,
struct GNUNET_TESTBED_BarrierStatusMsg,
NULL),
GNUNET_MQ_handler_end());
/* end of gnunet-service-testbed.c */