/*
This file is part of GNUnet
Copyright (C) 2008--2013 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 <http://www.gnu.org/licenses/>.
*/
/**
* @file testbed/testbed_api_peers.c
* @brief management of the knowledge about peers in this library
* (we know the peer ID, its host, pending operations, etc.)
* @author Christian Grothoff
* @author Sree Harsha Totakura
*/
#include "platform.h"
#include "testbed_api_peers.h"
#include "testbed_api.h"
#include "testbed.h"
#include "testbed_api_hosts.h"
#include "testbed_api_operations.h"
/**
* Peer list DLL head
*/
static struct GNUNET_TESTBED_Peer *peer_list_head;
/**
* Peer list DLL tail
*/
static struct GNUNET_TESTBED_Peer *peer_list_tail;
/**
* Adds a peer to the peer list
*
* @param peer the peer to add to the peer list
*/
void
GNUNET_TESTBED_peer_register_ (struct GNUNET_TESTBED_Peer *peer)
{
GNUNET_CONTAINER_DLL_insert_tail (peer_list_head, peer_list_tail, peer);
}
/**
* Removes a peer from the peer list
*
* @param peer the peer to remove
*/
void
GNUNET_TESTBED_peer_deregister_ (struct GNUNET_TESTBED_Peer *peer)
{
GNUNET_CONTAINER_DLL_remove (peer_list_head, peer_list_tail, peer);
}
/**
* Frees all peers
*/
void
GNUNET_TESTBED_cleanup_peers_ (void)
{
struct GNUNET_TESTBED_Peer *peer;
while (NULL != (peer = peer_list_head))
{
GNUNET_TESTBED_peer_deregister_ (peer);
GNUNET_free (peer);
}
}
/**
* Function to call to start a peer_create type operation once all
* queues the operation is part of declare that the
* operation can be activated.
*
* @param cls the closure from GNUNET_TESTBED_operation_create_()
*/
static void
opstart_peer_create (void *cls)
{
struct OperationContext *opc = cls;
struct PeerCreateData *data = opc->data;
struct GNUNET_TESTBED_PeerCreateMessage *msg;
struct GNUNET_MQ_Envelope *env;
char *config;
char *xconfig;
size_t c_size;
size_t xc_size;
GNUNET_assert (OP_PEER_CREATE == opc->type);
GNUNET_assert (NULL != data);
GNUNET_assert (NULL != data->peer);
opc->state = OPC_STATE_STARTED;
config = GNUNET_CONFIGURATION_serialize (data->cfg,
&c_size);
xc_size = GNUNET_TESTBED_compress_config_ (config,
c_size,
&xconfig);
GNUNET_free (config);
env = GNUNET_MQ_msg_extra (msg,
xc_size,
GNUNET_MESSAGE_TYPE_TESTBED_CREATE_PEER);
msg->operation_id = GNUNET_htonll (opc->id);
msg->host_id = htonl (GNUNET_TESTBED_host_get_id_ (data->peer->host));
msg->peer_id = htonl (data->peer->unique_id);
msg->config_size = htons ((uint16_t) c_size);
GNUNET_memcpy (&msg[1],
xconfig,
xc_size);
GNUNET_MQ_send (opc->c->mq,
env);
GNUNET_free (xconfig);
GNUNET_TESTBED_insert_opc_ (opc->c, opc);
}
/**
* Callback which will be called when peer_create type operation is released
*
* @param cls the closure from GNUNET_TESTBED_operation_create_()
*/
static void
oprelease_peer_create (void *cls)
{
struct OperationContext *opc = cls;
switch (opc->state)
{
case OPC_STATE_STARTED:
GNUNET_TESTBED_remove_opc_ (opc->c, opc);
/* No break we continue flow */
case OPC_STATE_INIT:
GNUNET_free (((struct PeerCreateData *) opc->data)->peer);
GNUNET_free (opc->data);
break;
case OPC_STATE_FINISHED:
break;
}
GNUNET_free (opc);
}
/**
* Function called when a peer destroy operation is ready
*
* @param cls the closure from GNUNET_TESTBED_operation_create_()
*/
static void
opstart_peer_destroy (void *cls)
{
struct OperationContext *opc = cls;
struct GNUNET_TESTBED_Peer *peer = opc->data;
struct GNUNET_TESTBED_PeerDestroyMessage *msg;
struct GNUNET_MQ_Envelope *env;
GNUNET_assert (OP_PEER_DESTROY == opc->type);
GNUNET_assert (NULL != peer);
opc->state = OPC_STATE_STARTED;
env = GNUNET_MQ_msg (msg,
GNUNET_MESSAGE_TYPE_TESTBED_DESTROY_PEER);
msg->peer_id = htonl (peer->unique_id);
msg->operation_id = GNUNET_htonll (opc->id);
GNUNET_TESTBED_insert_opc_ (opc->c, opc);
GNUNET_MQ_send (peer->controller->mq,
env);
}
/**
* Callback which will be called when peer_create type operation is released
*
* @param cls the closure from GNUNET_TESTBED_operation_create_()
*/
static void
oprelease_peer_destroy (void *cls)
{
struct OperationContext *opc = cls;
switch (opc->state)
{
case OPC_STATE_STARTED:
GNUNET_TESTBED_remove_opc_ (opc->c, opc);
/* no break; continue */
case OPC_STATE_INIT:
break;
case