/* * 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 . 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 #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 */