521 lines
16 KiB
C
521 lines
16 KiB
C
|
/*
|
||
|
* This file is part of GNUnet
|
||
|
* Copyright (C) 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/>.
|
||
|
|
||
|
SPDX-License-Identifier: AGPL3.0-or-later
|
||
|
*/
|
||
|
|
||
|
/**
|
||
|
* @file multicast/test_multicast_2peers.c
|
||
|
* @brief Tests for the Multicast API with two peers doing the ping
|
||
|
* pong test.
|
||
|
* @author xrs
|
||
|
*/
|
||
|
|
||
|
#include <inttypes.h>
|
||
|
|
||
|
#include "platform.h"
|
||
|
#include "gnunet_crypto_lib.h"
|
||
|
#include "gnunet_common.h"
|
||
|
#include "gnunet_util_lib.h"
|
||
|
#include "gnunet_testbed_service.h"
|
||
|
#include "gnunet_multicast_service.h"
|
||
|
|
||
|
#define NUM_PEERS 2
|
||
|
|
||
|
static struct GNUNET_TESTBED_Operation *op0;
|
||
|
static struct GNUNET_TESTBED_Operation *op1;
|
||
|
static struct GNUNET_TESTBED_Operation *pi_op0;
|
||
|
static struct GNUNET_TESTBED_Operation *pi_op1;
|
||
|
|
||
|
static struct GNUNET_TESTBED_Peer **peers;
|
||
|
const struct GNUNET_PeerIdentity *peer_id[2];
|
||
|
|
||
|
static struct GNUNET_SCHEDULER_Task *timeout_tid;
|
||
|
|
||
|
static struct GNUNET_MULTICAST_Origin *origin;
|
||
|
static struct GNUNET_MULTICAST_Member *member;
|
||
|
|
||
|
struct GNUNET_CRYPTO_EddsaPrivateKey *group_key;
|
||
|
struct GNUNET_CRYPTO_EddsaPublicKey group_pub_key;
|
||
|
|
||
|
struct GNUNET_CRYPTO_EcdsaPrivateKey *member_key;
|
||
|
struct GNUNET_CRYPTO_EcdsaPublicKey member_pub_key;
|
||
|
|
||
|
/**
|
||
|
* Global result for testcase.
|
||
|
*/
|
||
|
static int result;
|
||
|
|
||
|
|
||
|
/**
|
||
|
* Function run on CTRL-C or shutdown (i.e. success/timeout/etc.).
|
||
|
* Cleans up.
|
||
|
*/
|
||
|
static void
|
||
|
shutdown_task (void *cls)
|
||
|
{
|
||
|
if (NULL != op0)
|
||
|
{
|
||
|
GNUNET_TESTBED_operation_done (op0);
|
||
|
op0 = NULL;
|
||
|
}
|
||
|
if (NULL != op1)
|
||
|
{
|
||
|
GNUNET_TESTBED_operation_done (op1);
|
||
|
op1 = NULL;
|
||
|
}
|
||
|
if (NULL != pi_op0)
|
||
|
{
|
||
|
GNUNET_TESTBED_operation_done (pi_op0);
|
||
|
pi_op0 = NULL;
|
||
|
}
|
||
|
if (NULL != pi_op1)
|
||
|
{
|
||
|
GNUNET_TESTBED_operation_done (pi_op1);
|
||
|
pi_op1 = NULL;
|
||
|
}
|
||
|
if (NULL != timeout_tid)
|
||
|
{
|
||
|
GNUNET_SCHEDULER_cancel (timeout_tid);
|
||
|
timeout_tid = NULL;
|
||
|
}
|
||
|
}
|
||
|
|
||
|
|
||
|
static void
|
||
|
timeout_task (void *cls)
|
||
|
{
|
||
|
GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
|
||
|
"Timeout!\n");
|
||
|
result = GNUNET_SYSERR;
|
||
|
GNUNET_SCHEDULER_shutdown ();
|
||
|
}
|
||
|
|
||
|
|
||
|
static void
|
||
|
member_join_request (void *cls,
|
||
|
const struct GNUNET_CRYPTO_EcdsaPublicKey *member_pub_key,
|
||
|
const struct GNUNET_MessageHeader *join_msg,
|
||
|
struct GNUNET_MULTICAST_JoinHandle *jh)
|
||
|
{
|
||
|
GNUNET_log (GNUNET_ERROR_TYPE_INFO,
|
||
|
"Member sent a join request.\n");
|
||
|
|
||
|
}
|
||
|
|
||
|
|
||
|
static int
|
||
|
notify (void *cls,
|
||
|
size_t *data_size,
|
||
|
void *data)
|
||
|
{
|
||
|
|
||
|
char text[] = "ping";
|
||
|
*data_size = strlen(text)+1;
|
||
|
GNUNET_memcpy(data, text, *data_size);
|
||
|
|
||
|
GNUNET_log (GNUNET_ERROR_TYPE_INFO,
|
||
|
"Member sents message to origin: %s\n", text);
|
||
|
|
||
|
return GNUNET_YES;
|
||
|
}
|
||
|
|
||
|
|
||
|
static void
|
||
|
member_join_decision (void *cls,
|
||
|
int is_admitted,
|
||
|
const struct GNUNET_PeerIdentity *peer,
|
||
|
uint16_t relay_count,
|
||
|
const struct GNUNET_PeerIdentity *relays,
|
||
|
const struct GNUNET_MessageHeader *join_msg)
|
||
|
{
|
||
|
GNUNET_log (GNUNET_ERROR_TYPE_INFO,
|
||
|
"Member received a decision from origin: %s\n",
|
||
|
(GNUNET_YES == is_admitted)
|
||
|
? "accepted"
|
||
|
: "rejected");
|
||
|
|
||
|
if (GNUNET_YES == is_admitted)
|
||
|
{
|
||
|
struct GNUNET_MULTICAST_MemberTransmitHandle *req;
|
||
|
|
||
|
// FIXME: move to MQ-style API!
|
||
|
req = GNUNET_MULTICAST_member_to_origin (member,
|
||
|
0,
|
||
|
¬ify,
|
||
|
NULL);
|
||
|
}
|
||
|
}
|
||
|
|
||
|
|
||
|
static void
|
||
|
member_message (void *cls,
|
||
|
const struct GNUNET_MULTICAST_MessageHeader *msg)
|
||
|
{
|
||
|
if (0 != strncmp ("pong", (char *)&msg[1], 4))
|
||
|
{
|
||
|
GNUNET_log (GNUNET_ERROR_TYPE_ERROR, "member did not receive pong\n");
|
||
|
result = GNUNET_SYSERR;
|
||
|
GNUNET_SCHEDULER_shutdown ();
|
||
|
}
|
||
|
|
||
|
GNUNET_log (GNUNET_ERROR_TYPE_INFO,
|
||
|
"member receives: %s\n", (char *)&msg[1]);
|
||
|
|
||
|
// Testcase ends here.
|
||
|
result = GNUNET_YES;
|
||
|
GNUNET_SCHEDULER_shutdown ();
|
||
|
}
|
||
|
|
||
|
|
||
|
static void
|
||
|
origin_join_request (void *cls,
|
||
|
const struct GNUNET_CRYPTO_EcdsaPublicKey *member_pub_key,
|
||
|
const struct GNUNET_MessageHeader *join_msg,
|
||
|
struct GNUNET_MULTICAST_JoinHandle *jh)
|
||
|
{
|
||
|
struct GNUNET_MessageHeader *join_resp;
|
||
|
|
||
|
uint8_t data_size = ntohs (join_msg->size);
|
||
|
|
||
|
GNUNET_log (GNUNET_ERROR_TYPE_INFO,
|
||
|
"origin got a join request...\n");
|
||
|
GNUNET_log (GNUNET_ERROR_TYPE_INFO,
|
||
|
"origin receives: '%s'\n", (char *)&join_msg[1]);
|
||
|
|
||
|
const char data[] = "Come in!";
|
||
|
data_size = strlen (data) + 1;
|
||
|
join_resp = GNUNET_malloc (sizeof (join_resp) + data_size);
|
||
|
join_resp->size = htons (sizeof (join_resp) + data_size);
|
||
|
join_resp->type = htons (123);
|
||
|
GNUNET_memcpy (&join_resp[1], data, data_size);
|
||
|
|
||
|
GNUNET_log (GNUNET_ERROR_TYPE_INFO,
|
||
|
"origin sends: '%s'\n", data);
|
||
|
|
||
|
GNUNET_MULTICAST_join_decision (jh,
|
||
|
GNUNET_YES,
|
||
|
0,
|
||
|
NULL,
|
||
|
join_resp);
|
||
|
GNUNET_free (join_resp);
|
||
|
result = GNUNET_OK;
|
||
|
}
|
||
|
|
||
|
|
||
|
int
|
||
|
origin_notify (void *cls,
|
||
|
size_t *data_size,
|
||
|
void *data)
|
||
|
{
|
||
|
char text[] = "pong";
|
||
|
|
||
|
*data_size = strlen(text)+1;
|
||
|
GNUNET_memcpy (data,
|
||
|
text,
|
||
|
*data_size);
|
||
|
|
||
|
GNUNET_log (GNUNET_ERROR_TYPE_INFO, "origin sends (to all): %s\n", text);
|
||
|
|
||
|
return GNUNET_YES;
|
||
|
}
|
||
|
|
||
|
|
||
|
static void
|
||
|
origin_request (void *cls,
|
||
|
const struct GNUNET_MULTICAST_RequestHeader *req)
|
||
|
{
|
||
|
GNUNET_log (GNUNET_ERROR_TYPE_INFO, "origin receives: %s\n", (char *)&req[1]);
|
||
|
|
||
|
if (0 != strncmp ("ping", (char *)&req[1], 4))
|
||
|
GNUNET_log (GNUNET_ERROR_TYPE_ERROR, "origin didn't reveice a correct request");
|
||
|
|
||
|
GNUNET_MULTICAST_origin_to_all (origin,
|
||
|
0,
|
||
|
0,
|
||
|
origin_notify,
|
||
|
NULL);
|
||
|
}
|
||
|
|
||
|
|
||
|
static void
|
||
|
origin_message (void *cls,
|
||
|
const struct GNUNET_MULTICAST_MessageHeader *msg)
|
||
|
{
|
||
|
GNUNET_log (GNUNET_ERROR_TYPE_INFO, "origin message msg\n");
|
||
|
}
|
||
|
|
||
|
|
||
|
static void
|
||
|
service_connect1 (void *cls,
|
||
|
struct GNUNET_TESTBED_Operation *op,
|
||
|
void *ca_result,
|
||
|
const char *emsg)
|
||
|
{
|
||
|
member = ca_result;
|
||
|
|
||
|
if (NULL == member)
|
||
|
{
|
||
|
result = GNUNET_SYSERR;
|
||
|
GNUNET_SCHEDULER_shutdown ();
|
||
|
}
|
||
|
else
|
||
|
{
|
||
|
GNUNET_log (GNUNET_ERROR_TYPE_INFO, "Connected to multicast service of member\n");
|
||
|
}
|
||
|
}
|
||
|
|
||
|
|
||
|
static void
|
||
|
multicast_da1 (void *cls,
|
||
|
void * op_result)
|
||
|
{
|
||
|
GNUNET_log (GNUNET_ERROR_TYPE_INFO,
|
||
|
"Member parting from multicast group\n");
|
||
|
|
||
|
GNUNET_MULTICAST_member_part (member, NULL, NULL);
|
||
|
}
|
||
|
|
||
|
|
||
|
static void *
|
||
|
multicast_ca1 (void *cls,
|
||
|
const struct GNUNET_CONFIGURATION_Handle *cfg)
|
||
|
{
|
||
|
struct GNUNET_MessageHeader *join_msg;
|
||
|
void *ret;
|
||
|
|
||
|
// Get members keys
|
||
|
member_key = GNUNET_CRYPTO_ecdsa_key_create ();
|
||
|
GNUNET_CRYPTO_ecdsa_key_get_public (member_key, &member_pub_key);
|
||
|
|
||
|
char data[] = "Hi, can I enter?";
|
||
|
uint8_t data_size = strlen (data) + 1;
|
||
|
join_msg = GNUNET_malloc (sizeof (join_msg) + data_size);
|
||
|
join_msg->size = htons (sizeof (join_msg) + data_size);
|
||
|
join_msg->type = htons (123);
|
||
|
GNUNET_memcpy (&join_msg[1], data, data_size);
|
||
|
|
||
|
GNUNET_log (GNUNET_ERROR_TYPE_INFO,
|
||
|
"Members tries to join multicast group\n");
|
||
|
|
||
|
ret = GNUNET_MULTICAST_member_join (cfg,
|
||
|
&group_pub_key,
|
||
|
member_key,
|
||
|
peer_id[0],
|
||
|
0,
|
||
|
NULL,
|
||
|
join_msg, /* join message */
|
||
|
member_join_request,
|
||
|
member_join_decision,
|
||
|
NULL, /* no test for member_replay_frag */
|
||
|
NULL, /* no test for member_replay_msg */
|
||
|
member_message,
|
||
|
NULL);
|
||
|
GNUNET_free (join_msg);
|
||
|
return ret;
|
||
|
}
|
||
|
|
||
|
|
||
|
static void
|
||
|
peer_information_cb (void *cls,
|
||
|
struct GNUNET_TESTBED_Operation *op,
|
||
|
const struct GNUNET_TESTBED_PeerInformation *pinfo,
|
||
|
const char *emsg)
|
||
|
{
|
||
|
int i = (int) (long) cls;
|
||
|
|
||
|
if (NULL == pinfo)
|
||
|
{
|
||
|
result = GNUNET_SYSERR;
|
||
|
GNUNET_SCHEDULER_shutdown ();
|
||
|
}
|
||
|
|
||
|
peer_id[i] = pinfo->result.id;
|
||
|
|
||
|
GNUNET_log (GNUNET_ERROR_TYPE_INFO,
|
||
|
"Got peer information of %s (%s)\n", (0==i)?"origin":"member" ,GNUNET_i2s(pinfo->result.id));
|
||
|
|
||
|
GNUNET_log (GNUNET_ERROR_TYPE_INFO,
|
||
|
"Create member peer\n");
|
||
|
|
||
|
if (0 == i)
|
||
|
{
|
||
|
/* connect to multicast service of member */
|
||
|
op1 = GNUNET_TESTBED_service_connect (NULL, /* Closure for operation */
|
||
|
peers[1], /* The peer whose service to connect to */
|
||
|
"multicast", /* The name of the service */
|
||
|
service_connect1, /* callback to call after a handle to service
|
||
|
is opened */
|
||
|
NULL, /* closure for the above callback */
|
||
|
multicast_ca1, /* callback to call with peer's configuration;
|
||
|
this should open the needed service connection */
|
||
|
multicast_da1, /* callback to be called when closing the
|
||
|
opened service connection */
|
||
|
NULL); /* closure for the above two callbacks */
|
||
|
}
|
||
|
}
|
||
|
|
||
|
|
||
|
/**
|
||
|
* Test logic of peer "0" being origin starts here.
|
||
|
*
|
||
|
* @param cls closure, for the example: NULL
|
||
|
* @param op should be equal to "dht_op"
|
||
|
* @param ca_result result of the connect operation, the
|
||
|
* connection to the DHT service
|
||
|
* @param emsg error message, if testbed somehow failed to
|
||
|
* connect to the DHT.
|
||
|
*/
|
||
|
static void
|
||
|
service_connect0 (void *cls,
|
||
|
struct GNUNET_TESTBED_Operation *op,
|
||
|
void *ca_result,
|
||
|
const char *emsg)
|
||
|
{
|
||
|
origin = ca_result;
|
||
|
|
||
|
GNUNET_log (GNUNET_ERROR_TYPE_INFO,
|
||
|
"Connected to multicast service of origin\n");
|
||
|
|
||
|
// Get GNUnet identity of origin
|
||
|
pi_op0 = GNUNET_TESTBED_peer_get_information (peers[0],
|
||
|
GNUNET_TESTBED_PIT_IDENTITY,
|
||
|
peer_information_cb,
|
||
|
(void *) 0);
|
||
|
// Get GNUnet identity of member
|
||
|
pi_op1 = GNUNET_TESTBED_peer_get_information (peers[1],
|
||
|
GNUNET_TESTBED_PIT_IDENTITY,
|
||
|
peer_information_cb,
|
||
|
(void *) 1);
|
||
|
|
||
|
/* Connection to service successful. Here we'd usually do something with
|
||
|
* the service. */
|
||
|
result = GNUNET_OK;
|
||
|
//GNUNET_SCHEDULER_shutdown (); /* Also kills the testbed */
|
||
|
}
|
||
|
|
||
|
|
||
|
|
||
|
/**
|
||
|
* Function run when service multicast has started and is providing us
|
||
|
* with a configuration file.
|
||
|
*/
|
||
|
static void *
|
||
|
multicast_ca0 (void *cls,
|
||
|
const struct GNUNET_CONFIGURATION_Handle *cfg)
|
||
|
{
|
||
|
group_key = GNUNET_CRYPTO_eddsa_key_create ();
|
||
|
GNUNET_CRYPTO_eddsa_key_get_public (group_key, &group_pub_key);
|
||
|
|
||
|
return GNUNET_MULTICAST_origin_start (cfg,
|
||
|
group_key,
|
||
|
0,
|
||
|
origin_join_request,
|
||
|
NULL, /* no test for origin_replay_frag */
|
||
|
NULL, /* no test for origin_replay_msg */
|
||
|
origin_request,
|
||
|
origin_message,
|
||
|
NULL);
|
||
|
}
|
||
|
|
||
|
static void
|
||
|
multicast_da0 (void *cls,
|
||
|
void *op_result)
|
||
|
{
|
||
|
GNUNET_log (GNUNET_ERROR_TYPE_INFO,
|
||
|
"Origin closes multicast group\n");
|
||
|
|
||
|
GNUNET_MULTICAST_origin_stop (origin, NULL, NULL);
|
||
|
}
|
||
|
|
||
|
|
||
|
/**
|
||
|
* Main function inovked from TESTBED once all of the
|
||
|
* peers are up and running. This one then connects
|
||
|
* just to the multicast service of peer 0 and 1.
|
||
|
* Peer 0 is going to be origin.
|
||
|
* Peer 1 is going to be one member.
|
||
|
* Origin will start a multicast group and the member will try to join it.
|
||
|
* After that we execute some multicast test.
|
||
|
*
|
||
|
* @param cls closure
|
||
|
* @param h the run handle
|
||
|
* @param peers started peers for the test
|
||
|
* @param num_peers size of the 'peers' array
|
||
|
* @param links_succeeded number of links between peers that were created
|
||
|
* @param links_failed number of links testbed was unable to establish
|
||
|
*/
|
||
|
static void
|
||
|
testbed_master (void *cls,
|
||
|
struct GNUNET_TESTBED_RunHandle *h,
|
||
|
unsigned int num_peers,
|
||
|
struct GNUNET_TESTBED_Peer **p,
|
||
|
unsigned int links_succeeded,
|
||
|
unsigned int links_failed)
|
||
|
{
|
||
|
/* Testbed is ready with peers running and connected in a pre-defined overlay
|
||
|
topology (FIXME) */
|
||
|
GNUNET_log (GNUNET_ERROR_TYPE_INFO,
|
||
|
"Connected to testbed_master()\n");
|
||
|
|
||
|
peers = p;
|
||
|
|
||
|
GNUNET_log (GNUNET_ERROR_TYPE_INFO,
|
||
|
"Create origin peer\n");
|
||
|
op0 = GNUNET_TESTBED_service_connect (NULL, /* Closure for operation */
|
||
|
peers[0], /* The peer whose service to connect to */
|
||
|
"multicast", /* The name of the service */
|
||
|
service_connect0, /* callback to call after a handle to service
|
||
|
is opened */
|
||
|
NULL, /* closure for the above callback */
|
||
|
multicast_ca0, /* callback to call with peer's configuration;
|
||
|
this should open the needed service connection */
|
||
|
multicast_da0, /* callback to be called when closing the
|
||
|
opened service connection */
|
||
|
NULL); /* closure for the above two callbacks */
|
||
|
|
||
|
GNUNET_SCHEDULER_add_shutdown (&shutdown_task, NULL); /* Schedule a new task on shutdown */
|
||
|
|
||
|
/* Schedule the shutdown task with a delay of a few Seconds */
|
||
|
timeout_tid = GNUNET_SCHEDULER_add_delayed (GNUNET_TIME_relative_multiply(GNUNET_TIME_UNIT_SECONDS, 50),
|
||
|
&timeout_task, NULL);
|
||
|
}
|
||
|
|
||
|
|
||
|
int
|
||
|
main (int argc, char *argv[])
|
||
|
{
|
||
|
int ret;
|
||
|
|
||
|
result = GNUNET_SYSERR;
|
||
|
ret = GNUNET_TESTBED_test_run
|
||
|
("test-multicast-2peers", /* test case name */
|
||
|
"test_multicast.conf", /* template configuration */
|
||
|
NUM_PEERS, /* number of peers to start */
|
||
|
0LL, /* Event mask - set to 0 for no event notifications */
|
||
|
NULL, /* Controller event callback */
|
||
|
NULL, /* Closure for controller event callback */
|
||
|
testbed_master, /* continuation callback to be called when testbed setup is complete */
|
||
|
NULL); /* Closure for the test_master callback */
|
||
|
if ( (GNUNET_OK != ret) || (GNUNET_OK != result) )
|
||
|
return 1;
|
||
|
return 0;
|
||
|
}
|
||
|
|
||
|
|
||
|
/* end of test_multicast_2peers.c */
|