From 72068a707bede6121cfa535ddcdfe74052259c0c Mon Sep 17 00:00:00 2001 From: Christian Grothoff Date: Sun, 22 Nov 2020 21:17:27 +0100 Subject: fix type --- src/util/perf_crypto_rsa.c | 14 +++++++++----- 1 file changed, 9 insertions(+), 5 deletions(-) (limited to 'src') diff --git a/src/util/perf_crypto_rsa.c b/src/util/perf_crypto_rsa.c index d652e8d4e..aba61786f 100644 --- a/src/util/perf_crypto_rsa.c +++ b/src/util/perf_crypto_rsa.c @@ -44,7 +44,7 @@ eval (unsigned int len) struct GNUNET_CRYPTO_RsaBlindingKeySecret bsec[10]; unsigned int i; char sbuf[128]; - char *bbuf; + void *bbuf; size_t bbuf_len; struct GNUNET_HashCode hc; @@ -88,14 +88,16 @@ eval (unsigned int len) 64 * 1024 / (1 + GNUNET_TIME_absolute_get_duration (start).rel_value_us / 1000LL), "keys/ms"); - */start = GNUNET_TIME_absolute_get (); + */ + start = GNUNET_TIME_absolute_get (); GNUNET_CRYPTO_hash ("test", 4, &hc); for (i = 0; i < 10; i++) { GNUNET_CRYPTO_rsa_blind (&hc, &bsec[i], public_key, - &bbuf, &bbuf_len); + &bbuf, + &bbuf_len); GNUNET_free (bbuf); } printf ("10x %u-blinding took %s\n", @@ -115,12 +117,14 @@ eval (unsigned int len) GNUNET_CRYPTO_rsa_blind (&hc, &bsec[0], public_key, - &bbuf, &bbuf_len); + &bbuf, + &bbuf_len); start = GNUNET_TIME_absolute_get (); for (i = 0; i < 10; i++) { sig = GNUNET_CRYPTO_rsa_sign_blinded (private_key, - bbuf, bbuf_len); + bbuf, + bbuf_len); GNUNET_CRYPTO_rsa_signature_free (sig); } printf ("10x %u-signing took %s\n", -- cgit v1.2.3 From 430ed7f8b4b33295e84990ec97cbb71431cef923 Mon Sep 17 00:00:00 2001 From: Martin Schanzenbach Date: Mon, 30 Nov 2020 13:19:49 +0900 Subject: -fix communicator cleanup --- po/POTFILES.in | 4 +--- src/transport/gnunet-communicator-udp.c | 19 +++++++++++++++++-- 2 files changed, 18 insertions(+), 5 deletions(-) (limited to 'src') diff --git a/po/POTFILES.in b/po/POTFILES.in index 00bdd7cbc..b0371ba21 100644 --- a/po/POTFILES.in +++ b/po/POTFILES.in @@ -205,8 +205,8 @@ src/json/json_generator.c src/json/json_helper.c src/json/json_mhd.c src/messenger/gnunet-messenger.c -src/messenger/gnunet-service-messenger.c src/messenger/gnunet-service-messenger_basement.c +src/messenger/gnunet-service-messenger.c src/messenger/gnunet-service-messenger_contact.c src/messenger/gnunet-service-messenger_handle.c src/messenger/gnunet-service-messenger_list_handles.c @@ -545,7 +545,5 @@ src/vpn/vpn_api.c src/zonemaster/gnunet-service-zonemaster.c src/zonemaster/gnunet-service-zonemaster-monitor.c src/fs/fs_api.h -src/include/gnunet_identity_service.h -src/include/gnunet_messenger_service.h src/testbed/testbed_api.h src/testbed/testbed_api_operations.h diff --git a/src/transport/gnunet-communicator-udp.c b/src/transport/gnunet-communicator-udp.c index 849adf4ab..073b1ea02 100644 --- a/src/transport/gnunet-communicator-udp.c +++ b/src/transport/gnunet-communicator-udp.c @@ -1668,8 +1668,7 @@ static void kce_generate_cb (void *cls) { struct SharedSecret *ss = cls; - - + kce_task = NULL; if (ss->sender->acks_available < KCN_TARGET) { @@ -1699,6 +1698,7 @@ static void kce_generate_rekey_cb (void *cls) { struct SharedSecret *ss = cls; + kce_task_rekey = NULL; if (NULL == kce_task) { @@ -3132,6 +3132,21 @@ do_shutdown (void *cls) GNUNET_SCHEDULER_cancel (broadcast_task); broadcast_task = NULL; } + if (NULL != kce_task_rekey) + { + GNUNET_SCHEDULER_cancel (kce_task_rekey); + kce_task_rekey = NULL; + } + if (NULL != kce_task) + { + GNUNET_SCHEDULER_cancel (kce_task); + kce_task = NULL; + } + if (NULL != timeout_task) + { + GNUNET_SCHEDULER_cancel (timeout_task); + timeout_task = NULL; + } if (NULL != read_task) { GNUNET_SCHEDULER_cancel (read_task); -- cgit v1.2.3 From 948a62546c5c772d89efd5268393464c95eb7f1e Mon Sep 17 00:00:00 2001 From: Martin Schanzenbach Date: Mon, 30 Nov 2020 13:30:07 +0900 Subject: -rename communicator testing logic --- src/transport/Makefile.am | 2 +- src/transport/test_communicator_basic.c | 2 +- src/transport/transport-testing-communicator.c | 1164 ++++++++++++++++++++++++ src/transport/transport-testing-communicator.h | 355 ++++++++ src/transport/transport-testing2.c | 1164 ------------------------ src/transport/transport-testing2.h | 355 -------- 6 files changed, 1521 insertions(+), 1521 deletions(-) create mode 100644 src/transport/transport-testing-communicator.c create mode 100644 src/transport/transport-testing-communicator.h delete mode 100644 src/transport/transport-testing2.c delete mode 100644 src/transport/transport-testing2.h (limited to 'src') diff --git a/src/transport/Makefile.am b/src/transport/Makefile.am index e0369059d..477973af9 100644 --- a/src/transport/Makefile.am +++ b/src/transport/Makefile.am @@ -168,7 +168,7 @@ libgnunettransporttesting_la_LDFLAGS = \ $(GN_LIB_LDFLAGS) libgnunettransporttesting2_la_SOURCES = \ - transport-testing2.c transport-testing2.h + transport-testing-communicator.c transport-testing-communicator.h libgnunettransporttesting2_la_LIBADD = \ libgnunettransport.la \ $(top_builddir)/src/hello/libgnunethello.la \ diff --git a/src/transport/test_communicator_basic.c b/src/transport/test_communicator_basic.c index df3c73b20..7ea04afdb 100644 --- a/src/transport/test_communicator_basic.c +++ b/src/transport/test_communicator_basic.c @@ -26,7 +26,7 @@ */ #include "platform.h" #include "gnunet_util_lib.h" -#include "transport-testing2.h" +#include "transport-testing-communicator.h" #include "gnunet_ats_transport_service.h" #include "gnunet_signatures.h" #include "gnunet_testing_lib.h" diff --git a/src/transport/transport-testing-communicator.c b/src/transport/transport-testing-communicator.c new file mode 100644 index 000000000..6d74b12e8 --- /dev/null +++ b/src/transport/transport-testing-communicator.c @@ -0,0 +1,1164 @@ +/* + This file is part of GNUnet. + Copyright (C) 2019 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 transport/transport-testing-communicator.c + * @brief functions related to testing-tng + * @author Christian Grothoff + * @author Julius Bünger + */ +#include "platform.h" +#include "gnunet_util_lib.h" +#include "gnunet_protocols.h" +#include "gnunet_constants.h" +#include "transport-testing-communicator.h" +#include "gnunet_ats_transport_service.h" +#include "gnunet_hello_lib.h" +#include "gnunet_signatures.h" +#include "transport.h" +#include + +#define LOG(kind, ...) GNUNET_log_from (kind, "transport-testing2", __VA_ARGS__) + +struct MyClient +{ + struct MyClient *prev; + struct MyClient *next; + /** + * @brief Handle to the client + */ + struct GNUNET_SERVICE_Client *client; + + /** + * @brief Handle to the client + */ + struct GNUNET_MQ_Handle *c_mq; + + /** + * The TCH + */ + struct GNUNET_TRANSPORT_TESTING_TransportCommunicatorHandle *tc; + +}; + +/** + * @brief Queue of a communicator and some context + */ +struct GNUNET_TRANSPORT_TESTING_TransportCommunicatorQueue +{ + /** + * @brief Handle to the TransportCommunicator + */ + struct GNUNET_TRANSPORT_TESTING_TransportCommunicatorHandle *tc_h; + + /** + * @brief Envelope to a message that requests the opening of the queue. + * + * If the client already requests queue(s), but the communicator is not yet + * connected, we cannot send the request to open the queue. Save it until the + * communicator becomes available and send it then. + */ + struct GNUNET_MQ_Envelope *open_queue_env; + + /** + * @brief Peer ID of the peer on the other side of the queue + */ + struct GNUNET_PeerIdentity peer_id; + + /** + * @brief Queue ID + */ + uint32_t qid; + + /** + * @brief Current message id + */ + uint64_t mid; + + /** + * An `enum GNUNET_NetworkType` in NBO. + */ + uint32_t nt; + + /** + * Maximum transmission unit. UINT32_MAX for unlimited. + */ + uint32_t mtu; + + /** + * Queue length. UINT64_MAX for unlimited. + */ + uint64_t q_len; + + /** + * Queue prio + */ + uint32_t priority; + + /** + * An `enum GNUNET_TRANSPORT_ConnectionStatus` in NBO. + */ + uint32_t cs; + + /** + * @brief Next element inside a DLL + */ + struct GNUNET_TRANSPORT_TESTING_TransportCommunicatorQueue *next; + + /** + * @brief Previous element inside a DLL + */ + struct GNUNET_TRANSPORT_TESTING_TransportCommunicatorQueue *prev; +}; + + +/** + * @brief Handle/Context to a single transmission + */ +struct GNUNET_TRANSPORT_TESTING_TransportCommunicatorTransmission +{ +}; + + +/** + * @brief Check whether incoming msg indicating available communicator is + * correct + * + * @param cls Closure + * @param msg Message struct + * + * @return GNUNET_YES in case message is correct + */ +static int +check_communicator_available ( + void *cls, + const struct GNUNET_TRANSPORT_CommunicatorAvailableMessage *msg) +{ + uint16_t size; + + size = ntohs (msg->header.size) - sizeof(*msg); + if (0 == size) + return GNUNET_OK; /* receive-only communicator */ + GNUNET_MQ_check_zero_termination (msg); + return GNUNET_OK; +} + + +/** + * @brief Handle new communicator + * + * Store characteristics of communicator, call respective client callback. + * + * @param cls Closure - communicator handle + * @param msg Message struct + */ +static void +handle_communicator_available ( + void *cls, + const struct GNUNET_TRANSPORT_CommunicatorAvailableMessage *msg) +{ + struct MyClient *client = cls; + struct GNUNET_TRANSPORT_TESTING_TransportCommunicatorHandle *tc_h = + client->tc; + uint16_t size; + tc_h->c_mq = client->c_mq; + + size = ntohs (msg->header.size) - sizeof(*msg); + if (0 == size) + { + GNUNET_SERVICE_client_continue (client->client); + return; /* receive-only communicator */ + } + tc_h->c_characteristics = ntohl (msg->cc); + tc_h->c_addr_prefix = GNUNET_strdup ((const char *) &msg[1]); + if (NULL != tc_h->communicator_available_cb) + { + LOG (GNUNET_ERROR_TYPE_DEBUG, "calling communicator_available_cb()\n"); + tc_h->communicator_available_cb (tc_h->cb_cls, + tc_h, + tc_h->c_characteristics, + tc_h->c_addr_prefix); + } + GNUNET_SERVICE_client_continue (client->client); + LOG (GNUNET_ERROR_TYPE_DEBUG, "finished communicator_available_cb()\n"); + +} + + +/** + * Incoming message. Test message is well-formed. + * + * @param cls the client + * @param msg the send message that was sent + * @return #GNUNET_OK if message is well-formed + */ +static int +check_communicator_backchannel (void *cls, + const struct + GNUNET_TRANSPORT_CommunicatorBackchannel *msg) +{ + // struct TransportClient *tc = cls; + + // if (CT_COMMUNICATOR != tc->type) + // { + // GNUNET_break (0); + // return GNUNET_SYSERR; + // } + // GNUNET_MQ_check_boxed_message (msg); + return GNUNET_OK; +} + + +/** + * @brief Receive an incoming message. + * + * Pass the message to the client. + * + * @param cls Closure - communicator handle + * @param msg Message + */ +static void +handle_communicator_backchannel (void *cls, + const struct + GNUNET_TRANSPORT_CommunicatorBackchannel * + bc_msg) +{ + struct MyClient *client = cls; + struct GNUNET_TRANSPORT_TESTING_TransportCommunicatorHandle *tc_h = + client->tc; + struct GNUNET_TRANSPORT_TESTING_TransportCommunicatorHandle *other_tc_h; + struct GNUNET_MessageHeader *msg; + msg = (struct GNUNET_MessageHeader *) &bc_msg[1]; + uint16_t isize = ntohs (msg->size); + const char *target_communicator = ((const char *) msg) + isize; + struct GNUNET_TRANSPORT_CommunicatorBackchannelIncoming *cbi; + struct GNUNET_MQ_Envelope *env; + + LOG (GNUNET_ERROR_TYPE_DEBUG, + "Received backchannel message\n"); + if (tc_h->bc_enabled != GNUNET_YES) + { + GNUNET_SERVICE_client_continue (client->client); + return; + } + /* Find client providing this communicator */ + /* Finally, deliver backchannel message to communicator */ + LOG (GNUNET_ERROR_TYPE_DEBUG, + "Delivering backchannel message of type %u to %s\n", + ntohs (msg->type), + target_communicator); + other_tc_h = tc_h->bc_cb (tc_h, msg, (struct + GNUNET_PeerIdentity*) &bc_msg->pid); + env = GNUNET_MQ_msg_extra ( + cbi, + isize, + GNUNET_MESSAGE_TYPE_TRANSPORT_COMMUNICATOR_BACKCHANNEL_INCOMING); + cbi->pid = tc_h->peer_id; + memcpy (&cbi[1], msg, isize); + + + GNUNET_MQ_send (other_tc_h->c_mq, env); + GNUNET_SERVICE_client_continue (client->client); +} + + +/** + * Address of our peer added. Test message is well-formed. + * + * @param cls the client + * @param aam the send message that was sent + * @return #GNUNET_OK if message is well-formed + */ +static int +check_add_address (void *cls, + const struct GNUNET_TRANSPORT_AddAddressMessage *msg) +{ + // if (CT_COMMUNICATOR != tc->type) + // { + // GNUNET_break (0); + // return GNUNET_SYSERR; + // } + GNUNET_MQ_check_zero_termination (msg); + return GNUNET_OK; +} + + +/** + * @brief The communicator informs about an address. + * + * Store address and call client callback. + * + * @param cls Closure - communicator handle + * @param msg Message + */ +static void +handle_add_address (void *cls, + const struct GNUNET_TRANSPORT_AddAddressMessage *msg) +{ + struct MyClient *client = cls; + struct GNUNET_TRANSPORT_TESTING_TransportCommunicatorHandle *tc_h = + client->tc; + uint16_t size; + size = ntohs (msg->header.size) - sizeof(*msg); + if (0 == size) + return; /* receive-only communicator */ + LOG (GNUNET_ERROR_TYPE_DEBUG, "received add address cb %u\n", size); + tc_h->c_address = GNUNET_strdup ((const char *) &msg[1]); + if (NULL != tc_h->add_address_cb) + { + LOG (GNUNET_ERROR_TYPE_DEBUG, "calling add_address_cb()\n"); + tc_h->add_address_cb (tc_h->cb_cls, + tc_h, + tc_h->c_address, + GNUNET_TIME_relative_ntoh (msg->expiration), + msg->aid, + ntohl (msg->nt)); + } + GNUNET_SERVICE_client_continue (client->client); +} + + +/** + * Incoming message. Test message is well-formed. + * + * @param cls the client + * @param msg the send message that was sent + * @return #GNUNET_OK if message is well-formed + */ +static int +check_incoming_msg (void *cls, + const struct GNUNET_TRANSPORT_IncomingMessage *msg) +{ + // struct TransportClient *tc = cls; + + // if (CT_COMMUNICATOR != tc->type) + // { + // GNUNET_break (0); + // return GNUNET_SYSERR; + // } + GNUNET_MQ_check_boxed_message (msg); + return GNUNET_OK; +} + + +/** + * @brief Receive an incoming message. + * + * Pass the message to the client. + * + * @param cls Closure - communicator handle + * @param msg Message + */ +static void +handle_incoming_msg (void *cls, + const struct GNUNET_TRANSPORT_IncomingMessage *inc_msg) +{ + struct MyClient *client = cls; + struct GNUNET_TRANSPORT_TESTING_TransportCommunicatorHandle *tc_h = + client->tc; + struct GNUNET_MessageHeader *msg; + msg = (struct GNUNET_MessageHeader *) &inc_msg[1]; + size_t payload_len = ntohs (msg->size) - sizeof (struct + GNUNET_MessageHeader); + if (NULL != tc_h->incoming_msg_cb) + { + tc_h->incoming_msg_cb (tc_h->cb_cls, + tc_h, + (char*) &msg[1], + payload_len); + } + else + { + LOG (GNUNET_ERROR_TYPE_WARNING, + "Incoming message from communicator but no handler!\n"); + } + if (GNUNET_YES == ntohl (inc_msg->fc_on)) + { + /* send ACK when done to communicator for flow control! */ + struct GNUNET_MQ_Envelope *env; + struct GNUNET_TRANSPORT_IncomingMessageAck *ack; + + env = GNUNET_MQ_msg (ack, GNUNET_MESSAGE_TYPE_TRANSPORT_INCOMING_MSG_ACK); + GNUNET_assert (NULL != env); + ack->reserved = htonl (0); + ack->fc_id = inc_msg->fc_id; + ack->sender = inc_msg->sender; + GNUNET_MQ_send (tc_h->c_mq, env); + } + + GNUNET_SERVICE_client_continue (client->client); +} + + +/** + * @brief Communicator informs that it tries to establish requested queue + * + * @param cls Closure - communicator handle + * @param msg Message + */ +static void +handle_queue_create_ok (void *cls, + const struct GNUNET_TRANSPORT_CreateQueueResponse *msg) +{ + struct MyClient *client = cls; + struct GNUNET_TRANSPORT_TESTING_TransportCommunicatorHandle *tc_h = + client->tc; + + if (NULL != tc_h->queue_create_reply_cb) + { + tc_h->queue_create_reply_cb (tc_h->cb_cls, tc_h, GNUNET_YES); + } + GNUNET_SERVICE_client_continue (client->client); +} + + +/** + * @brief Communicator informs that it wont try establishing requested queue. + * + * It will not do so probably because the address is bougus (see comment to + * #GNUNET_MESSAGE_TYPE_TRANSPORT_QUEUE_CREATE_FAIL) + * + * @param cls Closure - communicator handle + * @param msg Message + */ +static void +handle_queue_create_fail ( + void *cls, + const struct GNUNET_TRANSPORT_CreateQueueResponse *msg) +{ + struct MyClient *client = cls; + struct GNUNET_TRANSPORT_TESTING_TransportCommunicatorHandle *tc_h = + client->tc; + + if (NULL != tc_h->queue_create_reply_cb) + { + tc_h->queue_create_reply_cb (tc_h->cb_cls, tc_h, GNUNET_NO); + } + GNUNET_SERVICE_client_continue (client->client); +} + + +/** + * New queue became available. Check message. + * + * @param cls the client + * @param aqm the send message that was sent + */ +static int +check_add_queue_message (void *cls, + const struct GNUNET_TRANSPORT_AddQueueMessage *aqm) +{ + GNUNET_MQ_check_zero_termination (aqm); + return GNUNET_OK; +} + + +/** + * @brief Handle new queue + * + * Store context and call client callback. + * + * @param cls Closure - communicator handle + * @param msg Message struct + */ +static void +handle_add_queue_message (void *cls, + const struct GNUNET_TRANSPORT_AddQueueMessage *msg) +{ + struct MyClient *client = cls; + struct GNUNET_TRANSPORT_TESTING_TransportCommunicatorHandle *tc_h = + client->tc; + struct GNUNET_TRANSPORT_TESTING_TransportCommunicatorQueue *tc_queue; + + LOG (GNUNET_ERROR_TYPE_DEBUG, + "Got queue with ID %u\n", msg->qid); + for (tc_queue = tc_h->queue_head; NULL != tc_queue; tc_queue = tc_queue->next) + { + if (tc_queue->qid == msg->qid) + break; + } + if (NULL == tc_queue) + { + tc_queue = + GNUNET_new (struct GNUNET_TRANSPORT_TESTING_TransportCommunicatorQueue); + tc_queue->tc_h = tc_h; + tc_queue->qid = msg->qid; + tc_queue->peer_id = msg->receiver; + GNUNET_CONTAINER_DLL_insert (tc_h->queue_head, tc_h->queue_tail, tc_queue); + } + GNUNET_assert (tc_queue->qid == msg->qid); + GNUNET_assert (0 == GNUNET_memcmp (&tc_queue->peer_id, &msg->receiver)); + tc_queue->nt = msg->nt; + tc_queue->mtu = ntohl (msg->mtu); + tc_queue->cs = msg->cs; + tc_queue->priority = ntohl (msg->priority); + tc_queue->q_len = GNUNET_ntohll (msg->q_len); + if (NULL != tc_h->add_queue_cb) + { + tc_h->add_queue_cb (tc_h->cb_cls, tc_h, tc_queue, tc_queue->mtu); + } + GNUNET_SERVICE_client_continue (client->client); +} + + +/** + * @brief Handle new queue + * + * Store context and call client callback. + * + * @param cls Closure - communicator handle + * @param msg Message struct + */ +static void +handle_update_queue_message (void *cls, + const struct + GNUNET_TRANSPORT_UpdateQueueMessage *msg) +{ + struct MyClient *client = cls; + struct GNUNET_TRANSPORT_TESTING_TransportCommunicatorHandle *tc_h = + client->tc; + struct GNUNET_TRANSPORT_TESTING_TransportCommunicatorQueue *tc_queue; + + LOG (GNUNET_ERROR_TYPE_DEBUG, + "Received queue update message for %u with q_len %" PRIu64 "\n", + msg->qid, GNUNET_ntohll (msg->q_len)); + tc_queue = tc_h->queue_head; + if (NULL != tc_queue) + { + while (tc_queue->qid != msg->qid) + { + tc_queue = tc_queue->next; + } + } + GNUNET_assert (tc_queue->qid == msg->qid); + GNUNET_assert (0 == GNUNET_memcmp (&tc_queue->peer_id, &msg->receiver)); + tc_queue->nt = msg->nt; + tc_queue->mtu = ntohl (msg->mtu); + tc_queue->cs = msg->cs; + tc_queue->priority = ntohl (msg->priority); + // Uncomment this for alternativ 1 of backchannel functionality + tc_queue->q_len += GNUNET_ntohll (msg->q_len); + // Until here for alternativ 1 + // Uncomment this for alternativ 2 of backchannel functionality + // tc_queue->q_len = GNUNET_ntohll (msg->q_len); + // Until here for alternativ 2 + GNUNET_SERVICE_client_continue (client->client); +} + + +/** + * @brief Shut down the service + * + * @param cls Closure - Handle to the service + */ +static void +shutdown_service (void *cls) +{ + struct GNUNET_SERVICE_Handle *h = cls; + + LOG (GNUNET_ERROR_TYPE_DEBUG, + "Shutting down service!\n"); + + GNUNET_SERVICE_stop (h); +} + + +/** + * @brief Callback called when new Client (Communicator) connects + * + * @param cls Closure - TransporCommmunicator Handle + * @param client Client + * @param mq Messagequeue + * + * @return TransportCommunicator Handle + */ +static void * +connect_cb (void *cls, + struct GNUNET_SERVICE_Client *client, + struct GNUNET_MQ_Handle *mq) +{ + struct GNUNET_TRANSPORT_TESTING_TransportCommunicatorHandle *tc_h = cls; + struct MyClient *new_c; + + LOG (GNUNET_ERROR_TYPE_DEBUG, "Client %p connected to %p.\n", + client, tc_h); + new_c = GNUNET_new (struct MyClient); + new_c->client = client; + new_c->c_mq = mq; + new_c->tc = tc_h; + GNUNET_CONTAINER_DLL_insert (tc_h->client_head, + tc_h->client_tail, + new_c); + + if (NULL == tc_h->queue_head) + return new_c; + /* Iterate over queues. They are yet to be opened. Request opening. */ + for (struct + GNUNET_TRANSPORT_TESTING_TransportCommunicatorQueue *tc_queue_iter = + tc_h->queue_head; + NULL != tc_queue_iter; + tc_queue_iter = tc_queue_iter->next) + { + if (NULL == tc_queue_iter->open_queue_env) + continue; + /* Send the previously created mq envelope to request the creation of the + * queue. */ + GNUNET_MQ_send (tc_h->c_mq, + tc_queue_iter->open_queue_env); + tc_queue_iter->open_queue_env = NULL; + } + return new_c; +} + + +/** + * @brief Callback called when Client disconnects + * + * @param cls Closure - TransportCommunicator Handle + * @param client Client + * @param internal_cls TransporCommmunicator Handle + */ +static void +disconnect_cb (void *cls, + struct GNUNET_SERVICE_Client *client, + void *internal_cls) +{ + struct MyClient *cl = cls; + struct GNUNET_TRANSPORT_TESTING_TransportCommunicatorHandle *tc_h = cls; + + for (cl = tc_h->client_head; NULL != cl; cl = cl->next) + { + if (cl->client != client) + continue; + GNUNET_CONTAINER_DLL_remove (tc_h->client_head, + tc_h->client_tail, + cl); + if (cl->c_mq == tc_h->c_mq) + tc_h->c_mq = NULL; + GNUNET_free (cl); + break; + } + LOG (GNUNET_ERROR_TYPE_DEBUG, "Client disconnected.\n"); +} + + +/** + * Message was transmitted. Process the request. + * + * @param cls the client + * @param sma the send message that was sent + */ +static void +handle_send_message_ack (void *cls, + const struct GNUNET_TRANSPORT_SendMessageToAck *sma) +{ + struct MyClient *client = cls; + GNUNET_SERVICE_client_continue (client->client); + // NOP +} + + +/** + * @brief Start the communicator part of the transport service + * + * @param communicator_available Callback to be called when a new communicator + * becomes available + * @param cfg Configuration + */ +static void +transport_communicator_start ( + struct GNUNET_TRANSPORT_TESTING_TransportCommunicatorHandle *tc_h) +{ + struct GNUNET_MQ_MessageHandler mh[] = { + GNUNET_MQ_hd_var_size (communicator_available, + GNUNET_MESSAGE_TYPE_TRANSPORT_NEW_COMMUNICATOR, + struct GNUNET_TRANSPORT_CommunicatorAvailableMessage, + tc_h), + GNUNET_MQ_hd_var_size (communicator_backchannel, + GNUNET_MESSAGE_TYPE_TRANSPORT_COMMUNICATOR_BACKCHANNEL, + struct GNUNET_TRANSPORT_CommunicatorBackchannel, + tc_h), + GNUNET_MQ_hd_var_size (add_address, + GNUNET_MESSAGE_TYPE_TRANSPORT_ADD_ADDRESS, + struct GNUNET_TRANSPORT_AddAddressMessage, + tc_h), + // GNUNET_MQ_hd_fixed_size (del_address, + // GNUNET_MESSAGE_TYPE_TRANSPORT_DEL_ADDRESS, + // struct GNUNET_TRANSPORT_DelAddressMessage, + // NULL), + GNUNET_MQ_hd_var_size (incoming_msg, + GNUNET_MESSAGE_TYPE_TRANSPORT_INCOMING_MSG, + struct GNUNET_TRANSPORT_IncomingMessage, + tc_h), + GNUNET_MQ_hd_fixed_size (queue_create_ok, + GNUNET_MESSAGE_TYPE_TRANSPORT_QUEUE_CREATE_OK, + struct GNUNET_TRANSPORT_CreateQueueResponse, + tc_h), + GNUNET_MQ_hd_fixed_size (queue_create_fail, + GNUNET_MESSAGE_TYPE_TRANSPORT_QUEUE_CREATE_FAIL, + struct GNUNET_TRANSPORT_CreateQueueResponse, + tc_h), + GNUNET_MQ_hd_var_size (add_queue_message, + GNUNET_MESSAGE_TYPE_TRANSPORT_QUEUE_SETUP, + struct GNUNET_TRANSPORT_AddQueueMessage, + tc_h), + GNUNET_MQ_hd_fixed_size (update_queue_message, + GNUNET_MESSAGE_TYPE_TRANSPORT_QUEUE_UPDATE, + struct GNUNET_TRANSPORT_UpdateQueueMessage, + tc_h), + // GNUNET_MQ_hd_fixed_size (del_queue_message, + // GNUNET_MESSAGE_TYPE_TRANSPORT_QUEUE_TEARDOWN, + // struct GNUNET_TRANSPORT_DelQueueMessage, + // NULL), + GNUNET_MQ_hd_fixed_size (send_message_ack, + GNUNET_MESSAGE_TYPE_TRANSPORT_SEND_MSG_ACK, + struct GNUNET_TRANSPORT_SendMessageToAck, + tc_h), + GNUNET_MQ_handler_end () + }; + + + tc_h->sh = GNUNET_SERVICE_start ("transport", + tc_h->cfg, + &connect_cb, + &disconnect_cb, + tc_h, + mh); + GNUNET_assert (NULL != tc_h->sh); +} + + +/** + * @brief Task run at shutdown to kill communicator and clean up + * + * @param cls Closure - Process of communicator + */ +static void +shutdown_process (struct GNUNET_OS_Process *proc) +{ + if (0 != GNUNET_OS_process_kill (proc, SIGTERM)) + { + LOG (GNUNET_ERROR_TYPE_WARNING, + "Error shutting down process with SIGERM, trying SIGKILL\n"); + if (0 != GNUNET_OS_process_kill (proc, SIGKILL)) + { + LOG (GNUNET_ERROR_TYPE_ERROR, + "Error shutting down process with SIGERM and SIGKILL\n"); + } + } + GNUNET_OS_process_destroy (proc); +} + +static void +shutdown_peerstore (void *cls) +{ + struct GNUNET_OS_Process *proc = cls; + shutdown_process (proc); +} + +static void +shutdown_communicator (void *cls) +{ + struct GNUNET_OS_Process *proc = cls; + shutdown_process (proc); +} + + +/** + * @brief Start the communicator + * + * @param cfgname Name of the communicator + */ +static void +communicator_start ( + struct GNUNET_TRANSPORT_TESTING_TransportCommunicatorHandle *tc_h, + const char *binary_name) +{ + char *binary; + char *loprefix; + char *section_name; + + LOG (GNUNET_ERROR_TYPE_DEBUG, "communicator_start\n"); + + section_name = strchr (binary_name, '-'); + section_name++; + + if (GNUNET_OK != GNUNET_CONFIGURATION_get_value_string (tc_h->cfg, + section_name, + "PREFIX", + &loprefix)) + loprefix = GNUNET_strdup (""); + + + binary = GNUNET_OS_get_libexec_binary_path (binary_name); + tc_h->c_proc = GNUNET_OS_start_process_s (GNUNET_OS_INHERIT_STD_OUT_AND_ERR, + NULL, + loprefix, + binary, + binary_name, + "-c", + tc_h->cfg_filename, + NULL); + if (NULL == tc_h->c_proc) + { + GNUNET_log (GNUNET_ERROR_TYPE_ERROR, "Failed to start communicator!"); + return; + } + LOG (GNUNET_ERROR_TYPE_INFO, "started communicator\n"); + GNUNET_free (binary); +} + + +/** + * @brief Task run at shutdown to kill communicator and clean up + * + * @param cls Closure - Process of communicator + */ +static void +shutdown_nat (void *cls) +{ + struct GNUNET_OS_Process *proc = cls; + shutdown_process (proc); +} + + +/** + * @brief Task run at shutdown to kill the resolver process + * + * @param cls Closure - Process of communicator + */ +static void +shutdown_resolver (void *cls) +{ + struct GNUNET_OS_Process *proc = cls; + shutdown_process (proc); +} + + +static void +resolver_start (struct + GNUNET_TRANSPORT_TESTING_TransportCommunicatorHandle *tc_h) +{ + char *binary; + + LOG (GNUNET_ERROR_TYPE_DEBUG, "resolver_start\n"); + binary = GNUNET_OS_get_libexec_binary_path ("gnunet-service-resolver"); + tc_h->resolver_proc = GNUNET_OS_start_process ( + GNUNET_OS_INHERIT_STD_OUT_AND_ERR + | GNUNET_OS_USE_PIPE_CONTROL, + NULL, + NULL, + NULL, + binary, + "gnunet-service-resolver", + "-c", + tc_h->cfg_filename, + NULL); + if (NULL == tc_h->resolver_proc) + { + GNUNET_log (GNUNET_ERROR_TYPE_ERROR, "Failed to start resolver service!"); + return; + } + LOG (GNUNET_ERROR_TYPE_INFO, "started resolver service\n"); + GNUNET_free (binary); + +} + + +/** + * @brief Start Peerstore + * + */ +static void +peerstore_start ( + struct GNUNET_TRANSPORT_TESTING_TransportCommunicatorHandle *tc_h) +{ + char *binary; + + binary = GNUNET_OS_get_libexec_binary_path ("gnunet-service-peerstore"); + tc_h->ps_proc = GNUNET_OS_start_process (GNUNET_OS_INHERIT_STD_OUT_AND_ERR, + NULL, + NULL, + NULL, + binary, + "gnunet-service-peerstore", + "-c", + tc_h->cfg_filename, + NULL); + if (NULL == tc_h->ps_proc) + { + GNUNET_log (GNUNET_ERROR_TYPE_ERROR, "Failed to start Peerstore!"); + return; + } + LOG (GNUNET_ERROR_TYPE_INFO, "started Peerstore\n"); + GNUNET_free (binary); +} + +/** + * @brief Start NAT + * + */ +static void +nat_start ( + struct GNUNET_TRANSPORT_TESTING_TransportCommunicatorHandle *tc_h) +{ + char *binary; + + LOG (GNUNET_ERROR_TYPE_DEBUG, "nat_start\n"); + binary = GNUNET_OS_get_libexec_binary_path ("gnunet-service-nat"); + tc_h->nat_proc = GNUNET_OS_start_process (GNUNET_OS_INHERIT_STD_OUT_AND_ERR + | GNUNET_OS_USE_PIPE_CONTROL, + NULL, + NULL, + NULL, + binary, + "gnunet-service-nat", + "-c", + tc_h->cfg_filename, + NULL); + if (NULL == tc_h->nat_proc) + { + GNUNET_log (GNUNET_ERROR_TYPE_ERROR, "Failed to start NAT!"); + return; + } + LOG (GNUNET_ERROR_TYPE_INFO, "started NAT\n"); + GNUNET_free (binary); +} + + +/** + * @brief Start communicator part of transport service and communicator + * + * @param service_name Name of the service + * @param cfg Configuration handle + * @param communicator_available_cb Callback that is called when a new + * @param add_address_cb Callback that is called when a new + * communicator becomes available + * @param cb_cls Closure to @a communicator_available_cb and @a + * + * @return Handle to the communicator duo + */ +struct GNUNET_TRANSPORT_TESTING_TransportCommunicatorHandle * +GNUNET_TRANSPORT_TESTING_transport_communicator_service_start ( + const char *service_name, + const char *binary_name, + const char *cfg_filename, + const struct GNUNET_PeerIdentity *peer_id, + GNUNET_TRANSPORT_TESTING_CommunicatorAvailableCallback + communicator_available_cb, + GNUNET_TRANSPORT_TESTING_AddAddressCallback add_address_cb, + GNUNET_TRANSPORT_TESTING_QueueCreateReplyCallback queue_create_reply_cb, + GNUNET_TRANSPORT_TESTING_AddQueueCallback add_queue_cb, + GNUNET_TRANSPORT_TESTING_IncomingMessageCallback incoming_message_cb, + GNUNET_TRANSPORT_TESTING_BackchannelCallback bc_cb, + void *cb_cls) +{ + struct GNUNET_TRANSPORT_TESTING_TransportCommunicatorHandle *tc_h; + + LOG (GNUNET_ERROR_TYPE_DEBUG, + "Starting new transport/communicator combo with config %s\n", + cfg_filename); + tc_h = + GNUNET_new (struct GNUNET_TRANSPORT_TESTING_TransportCommunicatorHandle); + tc_h->cfg_filename = GNUNET_strdup (cfg_filename); + tc_h->cfg = GNUNET_CONFIGURATION_create (); + if ((GNUNET_SYSERR == GNUNET_CONFIGURATION_load (tc_h->cfg, cfg_filename))) + { + GNUNET_log (GNUNET_ERROR_TYPE_ERROR, + _ ("Malformed configuration file `%s', exit ...\n"), + cfg_filename); + GNUNET_free (tc_h->cfg_filename); + GNUNET_CONFIGURATION_destroy (tc_h->cfg); + GNUNET_free (tc_h); + return NULL; + } + tc_h->bc_enabled = GNUNET_CONFIGURATION_get_value_yesno (tc_h->cfg, + "communicator-test", + "BACKCHANNEL_ENABLED"); + tc_h->communicator_available_cb = communicator_available_cb; + tc_h->add_address_cb = add_address_cb; + tc_h->queue_create_reply_cb = queue_create_reply_cb; + tc_h->add_queue_cb = add_queue_cb; + tc_h->incoming_msg_cb = incoming_message_cb; + tc_h->bc_cb = bc_cb; + tc_h->peer_id = *peer_id; + tc_h->cb_cls = cb_cls; + + /* Start communicator part of service */ + transport_communicator_start (tc_h); + /* Start NAT */ + nat_start (tc_h); + /* Start resolver service */ + resolver_start (tc_h); + /* Start peerstore service */ + peerstore_start (tc_h); + /* Schedule start communicator */ + communicator_start (tc_h, + binary_name); + return tc_h; +} + + +void +GNUNET_TRANSPORT_TESTING_transport_communicator_service_stop ( + struct GNUNET_TRANSPORT_TESTING_TransportCommunicatorHandle *tc_h) +{ + shutdown_communicator (tc_h->c_proc); + shutdown_service (tc_h->sh); + shutdown_nat (tc_h->nat_proc); + shutdown_resolver (tc_h->resolver_proc); + shutdown_peerstore (tc_h->ps_proc); + GNUNET_CONFIGURATION_destroy (tc_h->cfg); + GNUNET_free (tc_h); +} + + +/** + * @brief Instruct communicator to open a queue + * + * @param tc_h Handle to communicator which shall open queue + * @param peer_id Towards which peer + * @param address For which address + */ +void +GNUNET_TRANSPORT_TESTING_transport_communicator_open_queue ( + struct GNUNET_TRANSPORT_TESTING_TransportCommunicatorHandle *tc_h, + const struct GNUNET_PeerIdentity *peer_id, + const char *address) +{ + struct GNUNET_TRANSPORT_TESTING_TransportCommunicatorQueue *tc_queue; + static uint32_t idgen; + char *prefix; + struct GNUNET_TRANSPORT_CreateQueue *msg; + struct GNUNET_MQ_Envelope *env; + size_t alen; + + tc_queue = + GNUNET_new (struct GNUNET_TRANSPORT_TESTING_TransportCommunicatorQueue); + tc_queue->tc_h = tc_h; + prefix = GNUNET_HELLO_address_to_prefix (address); + if (NULL == prefix) + { + GNUNET_break (0); /* We got an invalid address!? */ + GNUNET_free (tc_queue); + return; + } + GNUNET_free (prefix); + alen = strlen (address) + 1; + env = + GNUNET_MQ_msg_extra (msg, alen, GNUNET_MESSAGE_TYPE_TRANSPORT_QUEUE_CREATE); + msg->request_id = htonl (idgen++); + tc_queue->qid = msg->request_id; + msg->receiver = *peer_id; + tc_queue->peer_id = *peer_id; + memcpy (&msg[1], address, alen); + if (NULL != tc_h->c_mq) + { + LOG (GNUNET_ERROR_TYPE_DEBUG, + "Sending queue create immediately\n"); + GNUNET_MQ_send (tc_h->c_mq, env); + } + else + { + tc_queue->open_queue_env = env; + } + GNUNET_CONTAINER_DLL_insert (tc_h->queue_head, tc_h->queue_tail, tc_queue); +} + + +/** + * @brief Instruct communicator to send data + * + * @param tc_queue The queue to use for sending + * @param cont function to call when done sending + * @param cont_cls closure for @a cont + * @param payload Data to send + * @param payload_size Size of the @a payload + */ +void +GNUNET_TRANSPORT_TESTING_transport_communicator_send + (struct GNUNET_TRANSPORT_TESTING_TransportCommunicatorHandle *tc_h, + GNUNET_SCHEDULER_TaskCallback cont, + void *cont_cls, + const void *payload, + size_t payload_size) +{ + struct GNUNET_MessageHeader *mh; + struct GNUNET_TRANSPORT_SendMessageTo *msg; + struct GNUNET_MQ_Envelope *env; + size_t inbox_size; + struct GNUNET_TRANSPORT_TESTING_TransportCommunicatorQueue *tc_queue; + struct GNUNET_TRANSPORT_TESTING_TransportCommunicatorQueue *tc_queue_tmp; + + tc_queue = NULL; + for (tc_queue_tmp = tc_h->queue_head; + NULL != tc_queue_tmp; + tc_queue_tmp = tc_queue_tmp->next) + { + if (tc_queue_tmp->q_len <= 0) + continue; + if (NULL == tc_queue) + { + LOG (GNUNET_ERROR_TYPE_DEBUG, + "Selecting queue with prio %u, len %" PRIu64 " and MTU %u\n", + tc_queue_tmp->priority, + tc_queue_tmp->q_len, + tc_queue_tmp->mtu); + tc_queue = tc_queue_tmp; + continue; + } + if (tc_queue->priority < tc_queue_tmp->priority) + { + LOG (GNUNET_ERROR_TYPE_DEBUG, + "Selecting queue with prio %u, len %" PRIu64 " and MTU %u\n", + tc_queue_tmp->priority, + tc_queue_tmp->q_len, + tc_queue_tmp->mtu); + tc_queue = tc_queue_tmp; + } + } + GNUNET_assert (NULL != tc_queue); + // Uncomment this for alternativ 1 of backchannel functionality + if (tc_queue->q_len != GNUNET_TRANSPORT_QUEUE_LENGTH_UNLIMITED) + tc_queue->q_len--; + // Until here for alternativ 1 + GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, + "Sending message\n"); + inbox_size = sizeof (struct GNUNET_MessageHeader) + payload_size; + env = GNUNET_MQ_msg_extra (msg, + inbox_size, + GNUNET_MESSAGE_TYPE_TRANSPORT_SEND_MSG); + GNUNET_assert (NULL != env); + msg->qid = htonl (tc_queue->qid); + msg->mid = tc_queue->mid++; + msg->receiver = tc_queue->peer_id; + mh = (struct GNUNET_MessageHeader *) &msg[1]; + mh->size = htons (inbox_size); + mh->type = GNUNET_MESSAGE_TYPE_DUMMY; + memcpy (&mh[1], + payload, + payload_size); + if (NULL != cont) + GNUNET_MQ_notify_sent (env, + cont, + cont_cls); + GNUNET_MQ_send (tc_queue->tc_h->c_mq, + env); +} diff --git a/src/transport/transport-testing-communicator.h b/src/transport/transport-testing-communicator.h new file mode 100644 index 000000000..693e61515 --- /dev/null +++ b/src/transport/transport-testing-communicator.h @@ -0,0 +1,355 @@ +/* + This file is part of GNUnet. + Copyright (C) 2019 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 transport/transport-testing-communicator.h + * @brief functions and structures related to testing-tng + * @author Christian Grothoff + * @author Julius Bünger + */ +#include "platform.h" +#include "gnunet_util_lib.h" +#include "gnunet_ats_transport_service.h" +#include "transport.h" + +/** + * @brief Queue of a communicator and some context + */ +struct GNUNET_TRANSPORT_TESTING_TransportCommunicatorQueue; + + +/** + * @brief Handle/Context to a single transmission + */ +struct GNUNET_TRANSPORT_TESTING_TransportCommunicatorTransmission; + +/** + * @brief Function signature for callbacks that are called when new + * backchannel message arrived + * + * @param cls Closure + * @param msg Backchannel message + * @param pid Target peer + */ +typedef struct GNUNET_TRANSPORT_TESTING_TransportCommunicatorHandle * +(*GNUNET_TRANSPORT_TESTING_BackchannelCallback)(void *cls, + struct GNUNET_MessageHeader *msg, + struct GNUNET_PeerIdentity *pid); + + +/** + * @brief Function signature for callbacks that are called when new + * communicators become available + * + * @param cls Closure + * @param tc_h Communicator handle + * @param cc Characteristics of communicator + * @param address_prefix Prefix of the address + */ +typedef void +(*GNUNET_TRANSPORT_TESTING_CommunicatorAvailableCallback)(void *cls, + struct + GNUNET_TRANSPORT_TESTING_TransportCommunicatorHandle + *tc_h, + enum + GNUNET_TRANSPORT_CommunicatorCharacteristics + cc, + char *address_prefix); + + +/** + * @brief Receive information about the address of a communicator. + * + * @param cls Closure + * @param tc_h Communicator handle + * @param address Address represented as string + * @param expiration Expiration + * @param aid Aid + * @param nt Network Type + */ +typedef void +(*GNUNET_TRANSPORT_TESTING_AddAddressCallback)(void *cls, + struct + GNUNET_TRANSPORT_TESTING_TransportCommunicatorHandle + *tc_h, + const char *address, + struct GNUNET_TIME_Relative + expiration, + uint32_t aid, + enum GNUNET_NetworkType nt); + + +/** + * @brief Get informed about the success of a queue request. + * + * @param cls Closure + * @param tc_h Communicator handle + * @param will_try #GNUNET_YES if communicator will try to create queue + */ +typedef void +(*GNUNET_TRANSPORT_TESTING_QueueCreateReplyCallback)(void *cls, + struct + GNUNET_TRANSPORT_TESTING_TransportCommunicatorHandle + *tc_h, + int will_try); + + +/** + * @brief Handle opening of queue + * + * @param cls Closure + * @param tc_h Communicator handle + * @param tc_queue Handle to newly opened queue + */ +typedef void +(*GNUNET_TRANSPORT_TESTING_AddQueueCallback)(void *cls, + struct + GNUNET_TRANSPORT_TESTING_TransportCommunicatorHandle + *tc_h, + struct + GNUNET_TRANSPORT_TESTING_TransportCommunicatorQueue + *tc_queue, + size_t mtu); + + +/** + * @brief Handle an incoming message + * + * @param cls Closure + * @param tc_h Handle to the receiving communicator + * @param msg Received message + */ +typedef void +(*GNUNET_TRANSPORT_TESTING_IncomingMessageCallback)(void *cls, + struct + GNUNET_TRANSPORT_TESTING_TransportCommunicatorHandle + *tc_h, + const char*payload, + size_t payload_len); + +/** + * @brief Handle to a transport communicator + */ +struct GNUNET_TRANSPORT_TESTING_TransportCommunicatorHandle +{ + /** + * Clients + */ + struct MyClient *client_head; + struct MyClient *client_tail; + + /** + * @brief Handle to the client + */ + struct GNUNET_MQ_Handle *c_mq; + + /** + * @brief Handle to the configuration + */ + struct GNUNET_CONFIGURATION_Handle *cfg; + + /** + * @brief File name of configuration file + */ + char *cfg_filename; + + struct GNUNET_PeerIdentity peer_id; + + /** + * @brief Handle to the transport service + */ + struct GNUNET_SERVICE_Handle *tsh; + + /** + * @brief Task that will be run on shutdown to stop and clean transport + * service + */ + struct GNUNET_SCHEDULER_Task *ts_shutdown_task; + + + /** + * @brief Process of the communicator + */ + struct GNUNET_OS_Process *c_proc; + + /** + * NAT process + */ + struct GNUNET_OS_Process *nat_proc; + + /** + * resolver service process + */ + struct GNUNET_OS_Process *resolver_proc; + + /** + * peerstore service process + */ + struct GNUNET_OS_Process *ps_proc; + + /** + * @brief Task that will be run on shutdown to stop and clean communicator + */ + struct GNUNET_SCHEDULER_Task *c_shutdown_task; + + /** + * @brief Characteristics of the communicator + */ + enum GNUNET_TRANSPORT_CommunicatorCharacteristics c_characteristics; + + /** + * @brief Specifies supported addresses + */ + char *c_addr_prefix; + + /** + * @brief Specifies supported addresses + */ + char *c_address; + + /** + * @brief Head of the DLL of queues associated with this communicator + */ + struct GNUNET_TRANSPORT_TESTING_TransportCommunicatorQueue *queue_head; + + /** + * @brief Tail of the DLL of queues associated with this communicator + */ + struct GNUNET_TRANSPORT_TESTING_TransportCommunicatorQueue *queue_tail; + + /* Callbacks + Closures */ + /** + * @brief Callback called when a new communicator connects + */ + GNUNET_TRANSPORT_TESTING_CommunicatorAvailableCallback + communicator_available_cb; + + /** + * @brief Callback called when a new communicator connects + */ + GNUNET_TRANSPORT_TESTING_AddAddressCallback add_address_cb; + + /** + * @brief Callback called when a new communicator connects + */ + GNUNET_TRANSPORT_TESTING_QueueCreateReplyCallback queue_create_reply_cb; + + /** + * @brief Callback called when a new communicator connects + */ + GNUNET_TRANSPORT_TESTING_AddQueueCallback add_queue_cb; + + /** + * @brief Callback called when a new communicator connects + */ + GNUNET_TRANSPORT_TESTING_IncomingMessageCallback incoming_msg_cb; + + /** + * @brief Backchannel callback + */ + GNUNET_TRANSPORT_TESTING_BackchannelCallback bc_cb; + + /** + * Our service handle + */ + struct GNUNET_SERVICE_Handle *sh; + + /** + * @brief Closure to the callback + */ + void *cb_cls; + + /** + * Backchannel supported + */ + int bc_enabled; +}; + +/** + * @brief Start communicator part of transport service and communicator + * + * @param service_name Name of the service + * @param cfg Configuration handle + * @param communicator_available Callback that is called when a new + * communicator becomes available + * @param add_address_cb Callback handling new addresses + * @param queue_create_reply_cb Callback handling success of queue requests + * @param add_queue_cb Callback handling freshly created queues + * @param incoming_message_cb Callback handling incoming messages + * @param cb_cls Closure to @p communicator_available + * + * @return Handle to the communicator duo + */ +struct GNUNET_TRANSPORT_TESTING_TransportCommunicatorHandle * +GNUNET_TRANSPORT_TESTING_transport_communicator_service_start ( + const char *service_name, + const char *binary_name, + const char *cfg_filename, + const struct GNUNET_PeerIdentity *peer_id, + GNUNET_TRANSPORT_TESTING_CommunicatorAvailableCallback + communicator_available_cb, + GNUNET_TRANSPORT_TESTING_AddAddressCallback add_address_cb, + GNUNET_TRANSPORT_TESTING_QueueCreateReplyCallback queue_create_reply_cb, + GNUNET_TRANSPORT_TESTING_AddQueueCallback add_queue_cb, + GNUNET_TRANSPORT_TESTING_IncomingMessageCallback incoming_message_cb, + GNUNET_TRANSPORT_TESTING_BackchannelCallback bc_cb, + void *cb_cls); + + +void +GNUNET_TRANSPORT_TESTING_transport_communicator_service_stop ( + struct GNUNET_TRANSPORT_TESTING_TransportCommunicatorHandle *tc_h); + + +/** + * @brief Instruct communicator to open a queue + * + * @param tc_h Handle to communicator which shall open queue + * @param peer_id Towards which peer + * @param address For which address + */ +void +GNUNET_TRANSPORT_TESTING_transport_communicator_open_queue (struct + GNUNET_TRANSPORT_TESTING_TransportCommunicatorHandle + *tc_h, + const struct + GNUNET_PeerIdentity + *peer_id, + const char *address); + + +/** + * @brief Instruct communicator to send data + * + * @param tc_queue The queue to use for sending + * @param cont function to call when done sending + * @param cont_cls closure for @a cont + * @param payload Data to send + * @param payload_size Size of the @a payload + */ +void +GNUNET_TRANSPORT_TESTING_transport_communicator_send (struct + GNUNET_TRANSPORT_TESTING_TransportCommunicatorHandle + *tc_h, + GNUNET_SCHEDULER_TaskCallback + cont, + void *cont_cls, + const void *payload, + size_t payload_size); diff --git a/src/transport/transport-testing2.c b/src/transport/transport-testing2.c deleted file mode 100644 index 076fbf331..000000000 --- a/src/transport/transport-testing2.c +++ /dev/null @@ -1,1164 +0,0 @@ -/* - This file is part of GNUnet. - Copyright (C) 2019 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 transport/transport-testing2.c - * @brief functions related to testing-tng - * @author Christian Grothoff - * @author Julius Bünger - */ -#include "platform.h" -#include "gnunet_util_lib.h" -#include "gnunet_protocols.h" -#include "gnunet_constants.h" -#include "transport-testing2.h" -#include "gnunet_ats_transport_service.h" -#include "gnunet_hello_lib.h" -#include "gnunet_signatures.h" -#include "transport.h" -#include - -#define LOG(kind, ...) GNUNET_log_from (kind, "transport-testing2", __VA_ARGS__) - -struct MyClient -{ - struct MyClient *prev; - struct MyClient *next; - /** - * @brief Handle to the client - */ - struct GNUNET_SERVICE_Client *client; - - /** - * @brief Handle to the client - */ - struct GNUNET_MQ_Handle *c_mq; - - /** - * The TCH - */ - struct GNUNET_TRANSPORT_TESTING_TransportCommunicatorHandle *tc; - -}; - -/** - * @brief Queue of a communicator and some context - */ -struct GNUNET_TRANSPORT_TESTING_TransportCommunicatorQueue -{ - /** - * @brief Handle to the TransportCommunicator - */ - struct GNUNET_TRANSPORT_TESTING_TransportCommunicatorHandle *tc_h; - - /** - * @brief Envelope to a message that requests the opening of the queue. - * - * If the client already requests queue(s), but the communicator is not yet - * connected, we cannot send the request to open the queue. Save it until the - * communicator becomes available and send it then. - */ - struct GNUNET_MQ_Envelope *open_queue_env; - - /** - * @brief Peer ID of the peer on the other side of the queue - */ - struct GNUNET_PeerIdentity peer_id; - - /** - * @brief Queue ID - */ - uint32_t qid; - - /** - * @brief Current message id - */ - uint64_t mid; - - /** - * An `enum GNUNET_NetworkType` in NBO. - */ - uint32_t nt; - - /** - * Maximum transmission unit. UINT32_MAX for unlimited. - */ - uint32_t mtu; - - /** - * Queue length. UINT64_MAX for unlimited. - */ - uint64_t q_len; - - /** - * Queue prio - */ - uint32_t priority; - - /** - * An `enum GNUNET_TRANSPORT_ConnectionStatus` in NBO. - */ - uint32_t cs; - - /** - * @brief Next element inside a DLL - */ - struct GNUNET_TRANSPORT_TESTING_TransportCommunicatorQueue *next; - - /** - * @brief Previous element inside a DLL - */ - struct GNUNET_TRANSPORT_TESTING_TransportCommunicatorQueue *prev; -}; - - -/** - * @brief Handle/Context to a single transmission - */ -struct GNUNET_TRANSPORT_TESTING_TransportCommunicatorTransmission -{ -}; - - -/** - * @brief Check whether incoming msg indicating available communicator is - * correct - * - * @param cls Closure - * @param msg Message struct - * - * @return GNUNET_YES in case message is correct - */ -static int -check_communicator_available ( - void *cls, - const struct GNUNET_TRANSPORT_CommunicatorAvailableMessage *msg) -{ - uint16_t size; - - size = ntohs (msg->header.size) - sizeof(*msg); - if (0 == size) - return GNUNET_OK; /* receive-only communicator */ - GNUNET_MQ_check_zero_termination (msg); - return GNUNET_OK; -} - - -/** - * @brief Handle new communicator - * - * Store characteristics of communicator, call respective client callback. - * - * @param cls Closure - communicator handle - * @param msg Message struct - */ -static void -handle_communicator_available ( - void *cls, - const struct GNUNET_TRANSPORT_CommunicatorAvailableMessage *msg) -{ - struct MyClient *client = cls; - struct GNUNET_TRANSPORT_TESTING_TransportCommunicatorHandle *tc_h = - client->tc; - uint16_t size; - tc_h->c_mq = client->c_mq; - - size = ntohs (msg->header.size) - sizeof(*msg); - if (0 == size) - { - GNUNET_SERVICE_client_continue (client->client); - return; /* receive-only communicator */ - } - tc_h->c_characteristics = ntohl (msg->cc); - tc_h->c_addr_prefix = GNUNET_strdup ((const char *) &msg[1]); - if (NULL != tc_h->communicator_available_cb) - { - LOG (GNUNET_ERROR_TYPE_DEBUG, "calling communicator_available_cb()\n"); - tc_h->communicator_available_cb (tc_h->cb_cls, - tc_h, - tc_h->c_characteristics, - tc_h->c_addr_prefix); - } - GNUNET_SERVICE_client_continue (client->client); - LOG (GNUNET_ERROR_TYPE_DEBUG, "finished communicator_available_cb()\n"); - -} - - -/** - * Incoming message. Test message is well-formed. - * - * @param cls the client - * @param msg the send message that was sent - * @return #GNUNET_OK if message is well-formed - */ -static int -check_communicator_backchannel (void *cls, - const struct - GNUNET_TRANSPORT_CommunicatorBackchannel *msg) -{ - // struct TransportClient *tc = cls; - - // if (CT_COMMUNICATOR != tc->type) - // { - // GNUNET_break (0); - // return GNUNET_SYSERR; - // } - // GNUNET_MQ_check_boxed_message (msg); - return GNUNET_OK; -} - - -/** - * @brief Receive an incoming message. - * - * Pass the message to the client. - * - * @param cls Closure - communicator handle - * @param msg Message - */ -static void -handle_communicator_backchannel (void *cls, - const struct - GNUNET_TRANSPORT_CommunicatorBackchannel * - bc_msg) -{ - struct MyClient *client = cls; - struct GNUNET_TRANSPORT_TESTING_TransportCommunicatorHandle *tc_h = - client->tc; - struct GNUNET_TRANSPORT_TESTING_TransportCommunicatorHandle *other_tc_h; - struct GNUNET_MessageHeader *msg; - msg = (struct GNUNET_MessageHeader *) &bc_msg[1]; - uint16_t isize = ntohs (msg->size); - const char *target_communicator = ((const char *) msg) + isize; - struct GNUNET_TRANSPORT_CommunicatorBackchannelIncoming *cbi; - struct GNUNET_MQ_Envelope *env; - - LOG (GNUNET_ERROR_TYPE_DEBUG, - "Received backchannel message\n"); - if (tc_h->bc_enabled != GNUNET_YES) - { - GNUNET_SERVICE_client_continue (client->client); - return; - } - /* Find client providing this communicator */ - /* Finally, deliver backchannel message to communicator */ - LOG (GNUNET_ERROR_TYPE_DEBUG, - "Delivering backchannel message of type %u to %s\n", - ntohs (msg->type), - target_communicator); - other_tc_h = tc_h->bc_cb (tc_h, msg, (struct - GNUNET_PeerIdentity*) &bc_msg->pid); - env = GNUNET_MQ_msg_extra ( - cbi, - isize, - GNUNET_MESSAGE_TYPE_TRANSPORT_COMMUNICATOR_BACKCHANNEL_INCOMING); - cbi->pid = tc_h->peer_id; - memcpy (&cbi[1], msg, isize); - - - GNUNET_MQ_send (other_tc_h->c_mq, env); - GNUNET_SERVICE_client_continue (client->client); -} - - -/** - * Address of our peer added. Test message is well-formed. - * - * @param cls the client - * @param aam the send message that was sent - * @return #GNUNET_OK if message is well-formed - */ -static int -check_add_address (void *cls, - const struct GNUNET_TRANSPORT_AddAddressMessage *msg) -{ - // if (CT_COMMUNICATOR != tc->type) - // { - // GNUNET_break (0); - // return GNUNET_SYSERR; - // } - GNUNET_MQ_check_zero_termination (msg); - return GNUNET_OK; -} - - -/** - * @brief The communicator informs about an address. - * - * Store address and call client callback. - * - * @param cls Closure - communicator handle - * @param msg Message - */ -static void -handle_add_address (void *cls, - const struct GNUNET_TRANSPORT_AddAddressMessage *msg) -{ - struct MyClient *client = cls; - struct GNUNET_TRANSPORT_TESTING_TransportCommunicatorHandle *tc_h = - client->tc; - uint16_t size; - size = ntohs (msg->header.size) - sizeof(*msg); - if (0 == size) - return; /* receive-only communicator */ - LOG (GNUNET_ERROR_TYPE_DEBUG, "received add address cb %u\n", size); - tc_h->c_address = GNUNET_strdup ((const char *) &msg[1]); - if (NULL != tc_h->add_address_cb) - { - LOG (GNUNET_ERROR_TYPE_DEBUG, "calling add_address_cb()\n"); - tc_h->add_address_cb (tc_h->cb_cls, - tc_h, - tc_h->c_address, - GNUNET_TIME_relative_ntoh (msg->expiration), - msg->aid, - ntohl (msg->nt)); - } - GNUNET_SERVICE_client_continue (client->client); -} - - -/** - * Incoming message. Test message is well-formed. - * - * @param cls the client - * @param msg the send message that was sent - * @return #GNUNET_OK if message is well-formed - */ -static int -check_incoming_msg (void *cls, - const struct GNUNET_TRANSPORT_IncomingMessage *msg) -{ - // struct TransportClient *tc = cls; - - // if (CT_COMMUNICATOR != tc->type) - // { - // GNUNET_break (0); - // return GNUNET_SYSERR; - // } - GNUNET_MQ_check_boxed_message (msg); - return GNUNET_OK; -} - - -/** - * @brief Receive an incoming message. - * - * Pass the message to the client. - * - * @param cls Closure - communicator handle - * @param msg Message - */ -static void -handle_incoming_msg (void *cls, - const struct GNUNET_TRANSPORT_IncomingMessage *inc_msg) -{ - struct MyClient *client = cls; - struct GNUNET_TRANSPORT_TESTING_TransportCommunicatorHandle *tc_h = - client->tc; - struct GNUNET_MessageHeader *msg; - msg = (struct GNUNET_MessageHeader *) &inc_msg[1]; - size_t payload_len = ntohs (msg->size) - sizeof (struct - GNUNET_MessageHeader); - if (NULL != tc_h->incoming_msg_cb) - { - tc_h->incoming_msg_cb (tc_h->cb_cls, - tc_h, - (char*) &msg[1], - payload_len); - } - else - { - LOG (GNUNET_ERROR_TYPE_WARNING, - "Incoming message from communicator but no handler!\n"); - } - if (GNUNET_YES == ntohl (inc_msg->fc_on)) - { - /* send ACK when done to communicator for flow control! */ - struct GNUNET_MQ_Envelope *env; - struct GNUNET_TRANSPORT_IncomingMessageAck *ack; - - env = GNUNET_MQ_msg (ack, GNUNET_MESSAGE_TYPE_TRANSPORT_INCOMING_MSG_ACK); - GNUNET_assert (NULL != env); - ack->reserved = htonl (0); - ack->fc_id = inc_msg->fc_id; - ack->sender = inc_msg->sender; - GNUNET_MQ_send (tc_h->c_mq, env); - } - - GNUNET_SERVICE_client_continue (client->client); -} - - -/** - * @brief Communicator informs that it tries to establish requested queue - * - * @param cls Closure - communicator handle - * @param msg Message - */ -static void -handle_queue_create_ok (void *cls, - const struct GNUNET_TRANSPORT_CreateQueueResponse *msg) -{ - struct MyClient *client = cls; - struct GNUNET_TRANSPORT_TESTING_TransportCommunicatorHandle *tc_h = - client->tc; - - if (NULL != tc_h->queue_create_reply_cb) - { - tc_h->queue_create_reply_cb (tc_h->cb_cls, tc_h, GNUNET_YES); - } - GNUNET_SERVICE_client_continue (client->client); -} - - -/** - * @brief Communicator informs that it wont try establishing requested queue. - * - * It will not do so probably because the address is bougus (see comment to - * #GNUNET_MESSAGE_TYPE_TRANSPORT_QUEUE_CREATE_FAIL) - * - * @param cls Closure - communicator handle - * @param msg Message - */ -static void -handle_queue_create_fail ( - void *cls, - const struct GNUNET_TRANSPORT_CreateQueueResponse *msg) -{ - struct MyClient *client = cls; - struct GNUNET_TRANSPORT_TESTING_TransportCommunicatorHandle *tc_h = - client->tc; - - if (NULL != tc_h->queue_create_reply_cb) - { - tc_h->queue_create_reply_cb (tc_h->cb_cls, tc_h, GNUNET_NO); - } - GNUNET_SERVICE_client_continue (client->client); -} - - -/** - * New queue became available. Check message. - * - * @param cls the client - * @param aqm the send message that was sent - */ -static int -check_add_queue_message (void *cls, - const struct GNUNET_TRANSPORT_AddQueueMessage *aqm) -{ - GNUNET_MQ_check_zero_termination (aqm); - return GNUNET_OK; -} - - -/** - * @brief Handle new queue - * - * Store context and call client callback. - * - * @param cls Closure - communicator handle - * @param msg Message struct - */ -static void -handle_add_queue_message (void *cls, - const struct GNUNET_TRANSPORT_AddQueueMessage *msg) -{ - struct MyClient *client = cls; - struct GNUNET_TRANSPORT_TESTING_TransportCommunicatorHandle *tc_h = - client->tc; - struct GNUNET_TRANSPORT_TESTING_TransportCommunicatorQueue *tc_queue; - - LOG (GNUNET_ERROR_TYPE_DEBUG, - "Got queue with ID %u\n", msg->qid); - for (tc_queue = tc_h->queue_head; NULL != tc_queue; tc_queue = tc_queue->next) - { - if (tc_queue->qid == msg->qid) - break; - } - if (NULL == tc_queue) - { - tc_queue = - GNUNET_new (struct GNUNET_TRANSPORT_TESTING_TransportCommunicatorQueue); - tc_queue->tc_h = tc_h; - tc_queue->qid = msg->qid; - tc_queue->peer_id = msg->receiver; - GNUNET_CONTAINER_DLL_insert (tc_h->queue_head, tc_h->queue_tail, tc_queue); - } - GNUNET_assert (tc_queue->qid == msg->qid); - GNUNET_assert (0 == GNUNET_memcmp (&tc_queue->peer_id, &msg->receiver)); - tc_queue->nt = msg->nt; - tc_queue->mtu = ntohl (msg->mtu); - tc_queue->cs = msg->cs; - tc_queue->priority = ntohl (msg->priority); - tc_queue->q_len = GNUNET_ntohll (msg->q_len); - if (NULL != tc_h->add_queue_cb) - { - tc_h->add_queue_cb (tc_h->cb_cls, tc_h, tc_queue, tc_queue->mtu); - } - GNUNET_SERVICE_client_continue (client->client); -} - - -/** - * @brief Handle new queue - * - * Store context and call client callback. - * - * @param cls Closure - communicator handle - * @param msg Message struct - */ -static void -handle_update_queue_message (void *cls, - const struct - GNUNET_TRANSPORT_UpdateQueueMessage *msg) -{ - struct MyClient *client = cls; - struct GNUNET_TRANSPORT_TESTING_TransportCommunicatorHandle *tc_h = - client->tc; - struct GNUNET_TRANSPORT_TESTING_TransportCommunicatorQueue *tc_queue; - - LOG (GNUNET_ERROR_TYPE_DEBUG, - "Received queue update message for %u with q_len %" PRIu64 "\n", - msg->qid, GNUNET_ntohll (msg->q_len)); - tc_queue = tc_h->queue_head; - if (NULL != tc_queue) - { - while (tc_queue->qid != msg->qid) - { - tc_queue = tc_queue->next; - } - } - GNUNET_assert (tc_queue->qid == msg->qid); - GNUNET_assert (0 == GNUNET_memcmp (&tc_queue->peer_id, &msg->receiver)); - tc_queue->nt = msg->nt; - tc_queue->mtu = ntohl (msg->mtu); - tc_queue->cs = msg->cs; - tc_queue->priority = ntohl (msg->priority); - // Uncomment this for alternativ 1 of backchannel functionality - tc_queue->q_len += GNUNET_ntohll (msg->q_len); - // Until here for alternativ 1 - // Uncomment this for alternativ 2 of backchannel functionality - // tc_queue->q_len = GNUNET_ntohll (msg->q_len); - // Until here for alternativ 2 - GNUNET_SERVICE_client_continue (client->client); -} - - -/** - * @brief Shut down the service - * - * @param cls Closure - Handle to the service - */ -static void -shutdown_service (void *cls) -{ - struct GNUNET_SERVICE_Handle *h = cls; - - LOG (GNUNET_ERROR_TYPE_DEBUG, - "Shutting down service!\n"); - - GNUNET_SERVICE_stop (h); -} - - -/** - * @brief Callback called when new Client (Communicator) connects - * - * @param cls Closure - TransporCommmunicator Handle - * @param client Client - * @param mq Messagequeue - * - * @return TransportCommunicator Handle - */ -static void * -connect_cb (void *cls, - struct GNUNET_SERVICE_Client *client, - struct GNUNET_MQ_Handle *mq) -{ - struct GNUNET_TRANSPORT_TESTING_TransportCommunicatorHandle *tc_h = cls; - struct MyClient *new_c; - - LOG (GNUNET_ERROR_TYPE_DEBUG, "Client %p connected to %p.\n", - client, tc_h); - new_c = GNUNET_new (struct MyClient); - new_c->client = client; - new_c->c_mq = mq; - new_c->tc = tc_h; - GNUNET_CONTAINER_DLL_insert (tc_h->client_head, - tc_h->client_tail, - new_c); - - if (NULL == tc_h->queue_head) - return new_c; - /* Iterate over queues. They are yet to be opened. Request opening. */ - for (struct - GNUNET_TRANSPORT_TESTING_TransportCommunicatorQueue *tc_queue_iter = - tc_h->queue_head; - NULL != tc_queue_iter; - tc_queue_iter = tc_queue_iter->next) - { - if (NULL == tc_queue_iter->open_queue_env) - continue; - /* Send the previously created mq envelope to request the creation of the - * queue. */ - GNUNET_MQ_send (tc_h->c_mq, - tc_queue_iter->open_queue_env); - tc_queue_iter->open_queue_env = NULL; - } - return new_c; -} - - -/** - * @brief Callback called when Client disconnects - * - * @param cls Closure - TransportCommunicator Handle - * @param client Client - * @param internal_cls TransporCommmunicator Handle - */ -static void -disconnect_cb (void *cls, - struct GNUNET_SERVICE_Client *client, - void *internal_cls) -{ - struct MyClient *cl = cls; - struct GNUNET_TRANSPORT_TESTING_TransportCommunicatorHandle *tc_h = cls; - - for (cl = tc_h->client_head; NULL != cl; cl = cl->next) - { - if (cl->client != client) - continue; - GNUNET_CONTAINER_DLL_remove (tc_h->client_head, - tc_h->client_tail, - cl); - if (cl->c_mq == tc_h->c_mq) - tc_h->c_mq = NULL; - GNUNET_free (cl); - break; - } - LOG (GNUNET_ERROR_TYPE_DEBUG, "Client disconnected.\n"); -} - - -/** - * Message was transmitted. Process the request. - * - * @param cls the client - * @param sma the send message that was sent - */ -static void -handle_send_message_ack (void *cls, - const struct GNUNET_TRANSPORT_SendMessageToAck *sma) -{ - struct MyClient *client = cls; - GNUNET_SERVICE_client_continue (client->client); - // NOP -} - - -/** - * @brief Start the communicator part of the transport service - * - * @param communicator_available Callback to be called when a new communicator - * becomes available - * @param cfg Configuration - */ -static void -transport_communicator_start ( - struct GNUNET_TRANSPORT_TESTING_TransportCommunicatorHandle *tc_h) -{ - struct GNUNET_MQ_MessageHandler mh[] = { - GNUNET_MQ_hd_var_size (communicator_available, - GNUNET_MESSAGE_TYPE_TRANSPORT_NEW_COMMUNICATOR, - struct GNUNET_TRANSPORT_CommunicatorAvailableMessage, - tc_h), - GNUNET_MQ_hd_var_size (communicator_backchannel, - GNUNET_MESSAGE_TYPE_TRANSPORT_COMMUNICATOR_BACKCHANNEL, - struct GNUNET_TRANSPORT_CommunicatorBackchannel, - tc_h), - GNUNET_MQ_hd_var_size (add_address, - GNUNET_MESSAGE_TYPE_TRANSPORT_ADD_ADDRESS, - struct GNUNET_TRANSPORT_AddAddressMessage, - tc_h), - // GNUNET_MQ_hd_fixed_size (del_address, - // GNUNET_MESSAGE_TYPE_TRANSPORT_DEL_ADDRESS, - // struct GNUNET_TRANSPORT_DelAddressMessage, - // NULL), - GNUNET_MQ_hd_var_size (incoming_msg, - GNUNET_MESSAGE_TYPE_TRANSPORT_INCOMING_MSG, - struct GNUNET_TRANSPORT_IncomingMessage, - tc_h), - GNUNET_MQ_hd_fixed_size (queue_create_ok, - GNUNET_MESSAGE_TYPE_TRANSPORT_QUEUE_CREATE_OK, - struct GNUNET_TRANSPORT_CreateQueueResponse, - tc_h), - GNUNET_MQ_hd_fixed_size (queue_create_fail, - GNUNET_MESSAGE_TYPE_TRANSPORT_QUEUE_CREATE_FAIL, - struct GNUNET_TRANSPORT_CreateQueueResponse, - tc_h), - GNUNET_MQ_hd_var_size (add_queue_message, - GNUNET_MESSAGE_TYPE_TRANSPORT_QUEUE_SETUP, - struct GNUNET_TRANSPORT_AddQueueMessage, - tc_h), - GNUNET_MQ_hd_fixed_size (update_queue_message, - GNUNET_MESSAGE_TYPE_TRANSPORT_QUEUE_UPDATE, - struct GNUNET_TRANSPORT_UpdateQueueMessage, - tc_h), - // GNUNET_MQ_hd_fixed_size (del_queue_message, - // GNUNET_MESSAGE_TYPE_TRANSPORT_QUEUE_TEARDOWN, - // struct GNUNET_TRANSPORT_DelQueueMessage, - // NULL), - GNUNET_MQ_hd_fixed_size (send_message_ack, - GNUNET_MESSAGE_TYPE_TRANSPORT_SEND_MSG_ACK, - struct GNUNET_TRANSPORT_SendMessageToAck, - tc_h), - GNUNET_MQ_handler_end () - }; - - - tc_h->sh = GNUNET_SERVICE_start ("transport", - tc_h->cfg, - &connect_cb, - &disconnect_cb, - tc_h, - mh); - GNUNET_assert (NULL != tc_h->sh); -} - - -/** - * @brief Task run at shutdown to kill communicator and clean up - * - * @param cls Closure - Process of communicator - */ -static void -shutdown_process (struct GNUNET_OS_Process *proc) -{ - if (0 != GNUNET_OS_process_kill (proc, SIGTERM)) - { - LOG (GNUNET_ERROR_TYPE_WARNING, - "Error shutting down process with SIGERM, trying SIGKILL\n"); - if (0 != GNUNET_OS_process_kill (proc, SIGKILL)) - { - LOG (GNUNET_ERROR_TYPE_ERROR, - "Error shutting down process with SIGERM and SIGKILL\n"); - } - } - GNUNET_OS_process_destroy (proc); -} - -static void -shutdown_peerstore (void *cls) -{ - struct GNUNET_OS_Process *proc = cls; - shutdown_process (proc); -} - -static void -shutdown_communicator (void *cls) -{ - struct GNUNET_OS_Process *proc = cls; - shutdown_process (proc); -} - - -/** - * @brief Start the communicator - * - * @param cfgname Name of the communicator - */ -static void -communicator_start ( - struct GNUNET_TRANSPORT_TESTING_TransportCommunicatorHandle *tc_h, - const char *binary_name) -{ - char *binary; - char *loprefix; - char *section_name; - - LOG (GNUNET_ERROR_TYPE_DEBUG, "communicator_start\n"); - - section_name = strchr (binary_name, '-'); - section_name++; - - if (GNUNET_OK != GNUNET_CONFIGURATION_get_value_string (tc_h->cfg, - section_name, - "PREFIX", - &loprefix)) - loprefix = GNUNET_strdup (""); - - - binary = GNUNET_OS_get_libexec_binary_path (binary_name); - tc_h->c_proc = GNUNET_OS_start_process_s (GNUNET_OS_INHERIT_STD_OUT_AND_ERR, - NULL, - loprefix, - binary, - binary_name, - "-c", - tc_h->cfg_filename, - NULL); - if (NULL == tc_h->c_proc) - { - GNUNET_log (GNUNET_ERROR_TYPE_ERROR, "Failed to start communicator!"); - return; - } - LOG (GNUNET_ERROR_TYPE_INFO, "started communicator\n"); - GNUNET_free (binary); -} - - -/** - * @brief Task run at shutdown to kill communicator and clean up - * - * @param cls Closure - Process of communicator - */ -static void -shutdown_nat (void *cls) -{ - struct GNUNET_OS_Process *proc = cls; - shutdown_process (proc); -} - - -/** - * @brief Task run at shutdown to kill the resolver process - * - * @param cls Closure - Process of communicator - */ -static void -shutdown_resolver (void *cls) -{ - struct GNUNET_OS_Process *proc = cls; - shutdown_process (proc); -} - - -static void -resolver_start (struct - GNUNET_TRANSPORT_TESTING_TransportCommunicatorHandle *tc_h) -{ - char *binary; - - LOG (GNUNET_ERROR_TYPE_DEBUG, "resolver_start\n"); - binary = GNUNET_OS_get_libexec_binary_path ("gnunet-service-resolver"); - tc_h->resolver_proc = GNUNET_OS_start_process ( - GNUNET_OS_INHERIT_STD_OUT_AND_ERR - | GNUNET_OS_USE_PIPE_CONTROL, - NULL, - NULL, - NULL, - binary, - "gnunet-service-resolver", - "-c", - tc_h->cfg_filename, - NULL); - if (NULL == tc_h->resolver_proc) - { - GNUNET_log (GNUNET_ERROR_TYPE_ERROR, "Failed to start resolver service!"); - return; - } - LOG (GNUNET_ERROR_TYPE_INFO, "started resolver service\n"); - GNUNET_free (binary); - -} - - -/** - * @brief Start Peerstore - * - */ -static void -peerstore_start ( - struct GNUNET_TRANSPORT_TESTING_TransportCommunicatorHandle *tc_h) -{ - char *binary; - - binary = GNUNET_OS_get_libexec_binary_path ("gnunet-service-peerstore"); - tc_h->ps_proc = GNUNET_OS_start_process (GNUNET_OS_INHERIT_STD_OUT_AND_ERR, - NULL, - NULL, - NULL, - binary, - "gnunet-service-peerstore", - "-c", - tc_h->cfg_filename, - NULL); - if (NULL == tc_h->ps_proc) - { - GNUNET_log (GNUNET_ERROR_TYPE_ERROR, "Failed to start Peerstore!"); - return; - } - LOG (GNUNET_ERROR_TYPE_INFO, "started Peerstore\n"); - GNUNET_free (binary); -} - -/** - * @brief Start NAT - * - */ -static void -nat_start ( - struct GNUNET_TRANSPORT_TESTING_TransportCommunicatorHandle *tc_h) -{ - char *binary; - - LOG (GNUNET_ERROR_TYPE_DEBUG, "nat_start\n"); - binary = GNUNET_OS_get_libexec_binary_path ("gnunet-service-nat"); - tc_h->nat_proc = GNUNET_OS_start_process (GNUNET_OS_INHERIT_STD_OUT_AND_ERR - | GNUNET_OS_USE_PIPE_CONTROL, - NULL, - NULL, - NULL, - binary, - "gnunet-service-nat", - "-c", - tc_h->cfg_filename, - NULL); - if (NULL == tc_h->nat_proc) - { - GNUNET_log (GNUNET_ERROR_TYPE_ERROR, "Failed to start NAT!"); - return; - } - LOG (GNUNET_ERROR_TYPE_INFO, "started NAT\n"); - GNUNET_free (binary); -} - - -/** - * @brief Start communicator part of transport service and communicator - * - * @param service_name Name of the service - * @param cfg Configuration handle - * @param communicator_available_cb Callback that is called when a new - * @param add_address_cb Callback that is called when a new - * communicator becomes available - * @param cb_cls Closure to @a communicator_available_cb and @a - * - * @return Handle to the communicator duo - */ -struct GNUNET_TRANSPORT_TESTING_TransportCommunicatorHandle * -GNUNET_TRANSPORT_TESTING_transport_communicator_service_start ( - const char *service_name, - const char *binary_name, - const char *cfg_filename, - const struct GNUNET_PeerIdentity *peer_id, - GNUNET_TRANSPORT_TESTING_CommunicatorAvailableCallback - communicator_available_cb, - GNUNET_TRANSPORT_TESTING_AddAddressCallback add_address_cb, - GNUNET_TRANSPORT_TESTING_QueueCreateReplyCallback queue_create_reply_cb, - GNUNET_TRANSPORT_TESTING_AddQueueCallback add_queue_cb, - GNUNET_TRANSPORT_TESTING_IncomingMessageCallback incoming_message_cb, - GNUNET_TRANSPORT_TESTING_BackchannelCallback bc_cb, - void *cb_cls) -{ - struct GNUNET_TRANSPORT_TESTING_TransportCommunicatorHandle *tc_h; - - LOG (GNUNET_ERROR_TYPE_DEBUG, - "Starting new transport/communicator combo with config %s\n", - cfg_filename); - tc_h = - GNUNET_new (struct GNUNET_TRANSPORT_TESTING_TransportCommunicatorHandle); - tc_h->cfg_filename = GNUNET_strdup (cfg_filename); - tc_h->cfg = GNUNET_CONFIGURATION_create (); - if ((GNUNET_SYSERR == GNUNET_CONFIGURATION_load (tc_h->cfg, cfg_filename))) - { - GNUNET_log (GNUNET_ERROR_TYPE_ERROR, - _ ("Malformed configuration file `%s', exit ...\n"), - cfg_filename); - GNUNET_free (tc_h->cfg_filename); - GNUNET_CONFIGURATION_destroy (tc_h->cfg); - GNUNET_free (tc_h); - return NULL; - } - tc_h->bc_enabled = GNUNET_CONFIGURATION_get_value_yesno (tc_h->cfg, - "communicator-test", - "BACKCHANNEL_ENABLED"); - tc_h->communicator_available_cb = communicator_available_cb; - tc_h->add_address_cb = add_address_cb; - tc_h->queue_create_reply_cb = queue_create_reply_cb; - tc_h->add_queue_cb = add_queue_cb; - tc_h->incoming_msg_cb = incoming_message_cb; - tc_h->bc_cb = bc_cb; - tc_h->peer_id = *peer_id; - tc_h->cb_cls = cb_cls; - - /* Start communicator part of service */ - transport_communicator_start (tc_h); - /* Start NAT */ - nat_start (tc_h); - /* Start resolver service */ - resolver_start (tc_h); - /* Start peerstore service */ - peerstore_start (tc_h); - /* Schedule start communicator */ - communicator_start (tc_h, - binary_name); - return tc_h; -} - - -void -GNUNET_TRANSPORT_TESTING_transport_communicator_service_stop ( - struct GNUNET_TRANSPORT_TESTING_TransportCommunicatorHandle *tc_h) -{ - shutdown_communicator (tc_h->c_proc); - shutdown_service (tc_h->sh); - shutdown_nat (tc_h->nat_proc); - shutdown_resolver (tc_h->resolver_proc); - shutdown_peerstore (tc_h->ps_proc); - GNUNET_CONFIGURATION_destroy (tc_h->cfg); - GNUNET_free (tc_h); -} - - -/** - * @brief Instruct communicator to open a queue - * - * @param tc_h Handle to communicator which shall open queue - * @param peer_id Towards which peer - * @param address For which address - */ -void -GNUNET_TRANSPORT_TESTING_transport_communicator_open_queue ( - struct GNUNET_TRANSPORT_TESTING_TransportCommunicatorHandle *tc_h, - const struct GNUNET_PeerIdentity *peer_id, - const char *address) -{ - struct GNUNET_TRANSPORT_TESTING_TransportCommunicatorQueue *tc_queue; - static uint32_t idgen; - char *prefix; - struct GNUNET_TRANSPORT_CreateQueue *msg; - struct GNUNET_MQ_Envelope *env; - size_t alen; - - tc_queue = - GNUNET_new (struct GNUNET_TRANSPORT_TESTING_TransportCommunicatorQueue); - tc_queue->tc_h = tc_h; - prefix = GNUNET_HELLO_address_to_prefix (address); - if (NULL == prefix) - { - GNUNET_break (0); /* We got an invalid address!? */ - GNUNET_free (tc_queue); - return; - } - GNUNET_free (prefix); - alen = strlen (address) + 1; - env = - GNUNET_MQ_msg_extra (msg, alen, GNUNET_MESSAGE_TYPE_TRANSPORT_QUEUE_CREATE); - msg->request_id = htonl (idgen++); - tc_queue->qid = msg->request_id; - msg->receiver = *peer_id; - tc_queue->peer_id = *peer_id; - memcpy (&msg[1], address, alen); - if (NULL != tc_h->c_mq) - { - LOG (GNUNET_ERROR_TYPE_DEBUG, - "Sending queue create immediately\n"); - GNUNET_MQ_send (tc_h->c_mq, env); - } - else - { - tc_queue->open_queue_env = env; - } - GNUNET_CONTAINER_DLL_insert (tc_h->queue_head, tc_h->queue_tail, tc_queue); -} - - -/** - * @brief Instruct communicator to send data - * - * @param tc_queue The queue to use for sending - * @param cont function to call when done sending - * @param cont_cls closure for @a cont - * @param payload Data to send - * @param payload_size Size of the @a payload - */ -void -GNUNET_TRANSPORT_TESTING_transport_communicator_send - (struct GNUNET_TRANSPORT_TESTING_TransportCommunicatorHandle *tc_h, - GNUNET_SCHEDULER_TaskCallback cont, - void *cont_cls, - const void *payload, - size_t payload_size) -{ - struct GNUNET_MessageHeader *mh; - struct GNUNET_TRANSPORT_SendMessageTo *msg; - struct GNUNET_MQ_Envelope *env; - size_t inbox_size; - struct GNUNET_TRANSPORT_TESTING_TransportCommunicatorQueue *tc_queue; - struct GNUNET_TRANSPORT_TESTING_TransportCommunicatorQueue *tc_queue_tmp; - - tc_queue = NULL; - for (tc_queue_tmp = tc_h->queue_head; - NULL != tc_queue_tmp; - tc_queue_tmp = tc_queue_tmp->next) - { - if (tc_queue_tmp->q_len <= 0) - continue; - if (NULL == tc_queue) - { - LOG (GNUNET_ERROR_TYPE_DEBUG, - "Selecting queue with prio %u, len %" PRIu64 " and MTU %u\n", - tc_queue_tmp->priority, - tc_queue_tmp->q_len, - tc_queue_tmp->mtu); - tc_queue = tc_queue_tmp; - continue; - } - if (tc_queue->priority < tc_queue_tmp->priority) - { - LOG (GNUNET_ERROR_TYPE_DEBUG, - "Selecting queue with prio %u, len %" PRIu64 " and MTU %u\n", - tc_queue_tmp->priority, - tc_queue_tmp->q_len, - tc_queue_tmp->mtu); - tc_queue = tc_queue_tmp; - } - } - GNUNET_assert (NULL != tc_queue); - // Uncomment this for alternativ 1 of backchannel functionality - if (tc_queue->q_len != GNUNET_TRANSPORT_QUEUE_LENGTH_UNLIMITED) - tc_queue->q_len--; - // Until here for alternativ 1 - GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, - "Sending message\n"); - inbox_size = sizeof (struct GNUNET_MessageHeader) + payload_size; - env = GNUNET_MQ_msg_extra (msg, - inbox_size, - GNUNET_MESSAGE_TYPE_TRANSPORT_SEND_MSG); - GNUNET_assert (NULL != env); - msg->qid = htonl (tc_queue->qid); - msg->mid = tc_queue->mid++; - msg->receiver = tc_queue->peer_id; - mh = (struct GNUNET_MessageHeader *) &msg[1]; - mh->size = htons (inbox_size); - mh->type = GNUNET_MESSAGE_TYPE_DUMMY; - memcpy (&mh[1], - payload, - payload_size); - if (NULL != cont) - GNUNET_MQ_notify_sent (env, - cont, - cont_cls); - GNUNET_MQ_send (tc_queue->tc_h->c_mq, - env); -} diff --git a/src/transport/transport-testing2.h b/src/transport/transport-testing2.h deleted file mode 100644 index 04f75fc88..000000000 --- a/src/transport/transport-testing2.h +++ /dev/null @@ -1,355 +0,0 @@ -/* - This file is part of GNUnet. - Copyright (C) 2019 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 transport/transport-testing2.h - * @brief functions and structures related to testing-tng - * @author Christian Grothoff - * @author Julius Bünger - */ -#include "platform.h" -#include "gnunet_util_lib.h" -#include "gnunet_ats_transport_service.h" -#include "transport.h" - -/** - * @brief Queue of a communicator and some context - */ -struct GNUNET_TRANSPORT_TESTING_TransportCommunicatorQueue; - - -/** - * @brief Handle/Context to a single transmission - */ -struct GNUNET_TRANSPORT_TESTING_TransportCommunicatorTransmission; - -/** - * @brief Function signature for callbacks that are called when new - * backchannel message arrived - * - * @param cls Closure - * @param msg Backchannel message - * @param pid Target peer - */ -typedef struct GNUNET_TRANSPORT_TESTING_TransportCommunicatorHandle * -(*GNUNET_TRANSPORT_TESTING_BackchannelCallback)(void *cls, - struct GNUNET_MessageHeader *msg, - struct GNUNET_PeerIdentity *pid); - - -/** - * @brief Function signature for callbacks that are called when new - * communicators become available - * - * @param cls Closure - * @param tc_h Communicator handle - * @param cc Characteristics of communicator - * @param address_prefix Prefix of the address - */ -typedef void -(*GNUNET_TRANSPORT_TESTING_CommunicatorAvailableCallback)(void *cls, - struct - GNUNET_TRANSPORT_TESTING_TransportCommunicatorHandle - *tc_h, - enum - GNUNET_TRANSPORT_CommunicatorCharacteristics - cc, - char *address_prefix); - - -/** - * @brief Receive information about the address of a communicator. - * - * @param cls Closure - * @param tc_h Communicator handle - * @param address Address represented as string - * @param expiration Expiration - * @param aid Aid - * @param nt Network Type - */ -typedef void -(*GNUNET_TRANSPORT_TESTING_AddAddressCallback)(void *cls, - struct - GNUNET_TRANSPORT_TESTING_TransportCommunicatorHandle - *tc_h, - const char *address, - struct GNUNET_TIME_Relative - expiration, - uint32_t aid, - enum GNUNET_NetworkType nt); - - -/** - * @brief Get informed about the success of a queue request. - * - * @param cls Closure - * @param tc_h Communicator handle - * @param will_try #GNUNET_YES if communicator will try to create queue - */ -typedef void -(*GNUNET_TRANSPORT_TESTING_QueueCreateReplyCallback)(void *cls, - struct - GNUNET_TRANSPORT_TESTING_TransportCommunicatorHandle - *tc_h, - int will_try); - - -/** - * @brief Handle opening of queue - * - * @param cls Closure - * @param tc_h Communicator handle - * @param tc_queue Handle to newly opened queue - */ -typedef void -(*GNUNET_TRANSPORT_TESTING_AddQueueCallback)(void *cls, - struct - GNUNET_TRANSPORT_TESTING_TransportCommunicatorHandle - *tc_h, - struct - GNUNET_TRANSPORT_TESTING_TransportCommunicatorQueue - *tc_queue, - size_t mtu); - - -/** - * @brief Handle an incoming message - * - * @param cls Closure - * @param tc_h Handle to the receiving communicator - * @param msg Received message - */ -typedef void -(*GNUNET_TRANSPORT_TESTING_IncomingMessageCallback)(void *cls, - struct - GNUNET_TRANSPORT_TESTING_TransportCommunicatorHandle - *tc_h, - const char*payload, - size_t payload_len); - -/** - * @brief Handle to a transport communicator - */ -struct GNUNET_TRANSPORT_TESTING_TransportCommunicatorHandle -{ - /** - * Clients - */ - struct MyClient *client_head; - struct MyClient *client_tail; - - /** - * @brief Handle to the client - */ - struct GNUNET_MQ_Handle *c_mq; - - /** - * @brief Handle to the configuration - */ - struct GNUNET_CONFIGURATION_Handle *cfg; - - /** - * @brief File name of configuration file - */ - char *cfg_filename; - - struct GNUNET_PeerIdentity peer_id; - - /** - * @brief Handle to the transport service - */ - struct GNUNET_SERVICE_Handle *tsh; - - /** - * @brief Task that will be run on shutdown to stop and clean transport - * service - */ - struct GNUNET_SCHEDULER_Task *ts_shutdown_task; - - - /** - * @brief Process of the communicator - */ - struct GNUNET_OS_Process *c_proc; - - /** - * NAT process - */ - struct GNUNET_OS_Process *nat_proc; - - /** - * resolver service process - */ - struct GNUNET_OS_Process *resolver_proc; - - /** - * peerstore service process - */ - struct GNUNET_OS_Process *ps_proc; - - /** - * @brief Task that will be run on shutdown to stop and clean communicator - */ - struct GNUNET_SCHEDULER_Task *c_shutdown_task; - - /** - * @brief Characteristics of the communicator - */ - enum GNUNET_TRANSPORT_CommunicatorCharacteristics c_characteristics; - - /** - * @brief Specifies supported addresses - */ - char *c_addr_prefix; - - /** - * @brief Specifies supported addresses - */ - char *c_address; - - /** - * @brief Head of the DLL of queues associated with this communicator - */ - struct GNUNET_TRANSPORT_TESTING_TransportCommunicatorQueue *queue_head; - - /** - * @brief Tail of the DLL of queues associated with this communicator - */ - struct GNUNET_TRANSPORT_TESTING_TransportCommunicatorQueue *queue_tail; - - /* Callbacks + Closures */ - /** - * @brief Callback called when a new communicator connects - */ - GNUNET_TRANSPORT_TESTING_CommunicatorAvailableCallback - communicator_available_cb; - - /** - * @brief Callback called when a new communicator connects - */ - GNUNET_TRANSPORT_TESTING_AddAddressCallback add_address_cb; - - /** - * @brief Callback called when a new communicator connects - */ - GNUNET_TRANSPORT_TESTING_QueueCreateReplyCallback queue_create_reply_cb; - - /** - * @brief Callback called when a new communicator connects - */ - GNUNET_TRANSPORT_TESTING_AddQueueCallback add_queue_cb; - - /** - * @brief Callback called when a new communicator connects - */ - GNUNET_TRANSPORT_TESTING_IncomingMessageCallback incoming_msg_cb; - - /** - * @brief Backchannel callback - */ - GNUNET_TRANSPORT_TESTING_BackchannelCallback bc_cb; - - /** - * Our service handle - */ - struct GNUNET_SERVICE_Handle *sh; - - /** - * @brief Closure to the callback - */ - void *cb_cls; - - /** - * Backchannel supported - */ - int bc_enabled; -}; - -/** - * @brief Start communicator part of transport service and communicator - * - * @param service_name Name of the service - * @param cfg Configuration handle - * @param communicator_available Callback that is called when a new - * communicator becomes available - * @param add_address_cb Callback handling new addresses - * @param queue_create_reply_cb Callback handling success of queue requests - * @param add_queue_cb Callback handling freshly created queues - * @param incoming_message_cb Callback handling incoming messages - * @param cb_cls Closure to @p communicator_available - * - * @return Handle to the communicator duo - */ -struct GNUNET_TRANSPORT_TESTING_TransportCommunicatorHandle * -GNUNET_TRANSPORT_TESTING_transport_communicator_service_start ( - const char *service_name, - const char *binary_name, - const char *cfg_filename, - const struct GNUNET_PeerIdentity *peer_id, - GNUNET_TRANSPORT_TESTING_CommunicatorAvailableCallback - communicator_available_cb, - GNUNET_TRANSPORT_TESTING_AddAddressCallback add_address_cb, - GNUNET_TRANSPORT_TESTING_QueueCreateReplyCallback queue_create_reply_cb, - GNUNET_TRANSPORT_TESTING_AddQueueCallback add_queue_cb, - GNUNET_TRANSPORT_TESTING_IncomingMessageCallback incoming_message_cb, - GNUNET_TRANSPORT_TESTING_BackchannelCallback bc_cb, - void *cb_cls); - - -void -GNUNET_TRANSPORT_TESTING_transport_communicator_service_stop ( - struct GNUNET_TRANSPORT_TESTING_TransportCommunicatorHandle *tc_h); - - -/** - * @brief Instruct communicator to open a queue - * - * @param tc_h Handle to communicator which shall open queue - * @param peer_id Towards which peer - * @param address For which address - */ -void -GNUNET_TRANSPORT_TESTING_transport_communicator_open_queue (struct - GNUNET_TRANSPORT_TESTING_TransportCommunicatorHandle - *tc_h, - const struct - GNUNET_PeerIdentity - *peer_id, - const char *address); - - -/** - * @brief Instruct communicator to send data - * - * @param tc_queue The queue to use for sending - * @param cont function to call when done sending - * @param cont_cls closure for @a cont - * @param payload Data to send - * @param payload_size Size of the @a payload - */ -void -GNUNET_TRANSPORT_TESTING_transport_communicator_send (struct - GNUNET_TRANSPORT_TESTING_TransportCommunicatorHandle - *tc_h, - GNUNET_SCHEDULER_TaskCallback - cont, - void *cont_cls, - const void *payload, - size_t payload_size); -- cgit v1.2.3 From 172ef59b934c067dd7ec8e72650e196c7ae2a04b Mon Sep 17 00:00:00 2001 From: Martin Schanzenbach Date: Mon, 30 Nov 2020 18:08:25 +0900 Subject: -start TNG transport test logic --- src/transport/Makefile.am | 5 + src/transport/transport-testing2.c | 923 ++++++++++++++++++++++++++++++++++++ src/transport/transport-testing2.h | 924 +++++++++++++++++++++++++++++++++++++ 3 files changed, 1852 insertions(+) create mode 100644 src/transport/transport-testing2.c create mode 100644 src/transport/transport-testing2.h (limited to 'src') diff --git a/src/transport/Makefile.am b/src/transport/Makefile.am index 477973af9..605d89cc0 100644 --- a/src/transport/Makefile.am +++ b/src/transport/Makefile.am @@ -168,10 +168,15 @@ libgnunettransporttesting_la_LDFLAGS = \ $(GN_LIB_LDFLAGS) libgnunettransporttesting2_la_SOURCES = \ + transport-testing2.c transport-testing2.h \ transport-testing-communicator.c transport-testing-communicator.h libgnunettransporttesting2_la_LIBADD = \ libgnunettransport.la \ + libgnunettransportapplication.la \ + libgnunettransportcore.la \ + $(top_builddir)/src/testing/libgnunettesting.la \ $(top_builddir)/src/hello/libgnunethello.la \ + $(top_builddir)/src/peerstore/libgnunetpeerstore.la \ $(top_builddir)/src/util/libgnunetutil.la libgnunettransporttesting2_la_LDFLAGS = \ $(GN_LIBINTL) \ diff --git a/src/transport/transport-testing2.c b/src/transport/transport-testing2.c new file mode 100644 index 000000000..ca338c52f --- /dev/null +++ b/src/transport/transport-testing2.c @@ -0,0 +1,923 @@ +/* + This file is part of GNUnet. + Copyright (C) 2006, 2009, 2015, 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 transport-testing.c + * @brief testing lib for transport service + * @author Matthias Wachs + * @author Christian Grothoff + */ +#include "transport-testing2.h" + + +#define LOG(kind, ...) GNUNET_log_from (kind, "transport-testing", __VA_ARGS__) + + +static struct GNUNET_TRANSPORT_TESTING_PeerContext * +find_peer_context (struct GNUNET_TRANSPORT_TESTING_Handle *tth, + const struct GNUNET_PeerIdentity *peer) +{ + struct GNUNET_TRANSPORT_TESTING_PeerContext *t; + + for (t = tth->p_head; NULL != t; t = t->next) + if (0 == memcmp (&t->id, + peer, + sizeof(struct GNUNET_PeerIdentity))) + return t; + return NULL; +} + + +/** + * Find any connecting context matching the given pair of peers. + * + * @param p1 first peer + * @param p2 second peer + * @param cb function to call + * @param cb_cls closure for @a cb + */ +void +GNUNET_TRANSPORT_TESTING_find_connecting_context (struct + GNUNET_TRANSPORT_TESTING_PeerContext + *p1, + struct + GNUNET_TRANSPORT_TESTING_PeerContext + *p2, + GNUNET_TRANSPORT_TESTING_ConnectContextCallback + cb, + void *cb_cls) +{ + struct GNUNET_TRANSPORT_TESTING_Handle *tth = p1->tth; + struct GNUNET_TRANSPORT_TESTING_ConnectRequest *cc; + struct GNUNET_TRANSPORT_TESTING_ConnectRequest *ccn; + + for (cc = tth->cc_head; NULL != cc; cc = ccn) + { + ccn = cc->next; + if ((cc->p1 == p1) && + (cc->p2 == p2)) + cb (cb_cls, + cc); + } +} + + +static void +set_p1c (void *cls, + struct GNUNET_TRANSPORT_TESTING_ConnectRequest *cx) +{ + int *found = cls; + + if (NULL != found) + *found = GNUNET_YES; + cx->p1_c = GNUNET_YES; +} + + +static void +set_mq (void *cls, + struct GNUNET_TRANSPORT_TESTING_ConnectRequest *cx) +{ + struct GNUNET_MQ_Handle *mq = cls; + + cx->mq = mq; +} + + +static void +set_p2c (void *cls, + struct GNUNET_TRANSPORT_TESTING_ConnectRequest *cx) +{ + int *found = cls; + + if (NULL != found) + *found = GNUNET_YES; + cx->p2_c = GNUNET_YES; +} + + +static void +clear_p1c (void *cls, + struct GNUNET_TRANSPORT_TESTING_ConnectRequest *cx) +{ + int *found = cls; + + if (NULL != found) + *found = GNUNET_YES; + cx->p1_c = GNUNET_NO; +} + + +static void +clear_p2c (void *cls, + struct GNUNET_TRANSPORT_TESTING_ConnectRequest *cx) +{ + int *found = cls; + + if (NULL != found) + *found = GNUNET_YES; + cx->p2_c = GNUNET_NO; +} + + +static void * +notify_connect (void *cls, + const struct GNUNET_PeerIdentity *peer, + struct GNUNET_MQ_Handle *mq) +{ + struct GNUNET_TRANSPORT_TESTING_PeerContext *p = cls; + struct GNUNET_TRANSPORT_TESTING_Handle *tth = p->tth; + char *p2_s; + struct GNUNET_TRANSPORT_TESTING_PeerContext *p2; + struct GNUNET_TRANSPORT_TESTING_ConnectRequest *cc; + struct GNUNET_TRANSPORT_TESTING_ConnectRequest *ccn; + int found; + void *ret; + + p2 = find_peer_context (p->tth, + peer); + if (NULL != p->nc) + ret = p->nc (p->cb_cls, + peer, + mq); + else + ret = NULL; + + if (NULL != p2) + GNUNET_asprintf (&p2_s, + "%u (`%s')", + p2->no, + GNUNET_i2s (&p2->id)); + else + GNUNET_asprintf (&p2_s, + "`%s'", + GNUNET_i2s (peer)); + LOG (GNUNET_ERROR_TYPE_DEBUG, + "Peers %s connected to peer %u (`%s')\n", + p2_s, + p->no, + GNUNET_i2s (&p->id)); + GNUNET_free (p2_s); + /* update flags in connecting contexts */ + found = GNUNET_NO; + GNUNET_TRANSPORT_TESTING_find_connecting_context (p, + p2, + &set_p1c, + &found); + if (GNUNET_NO == found) + { + cc = GNUNET_new (struct GNUNET_TRANSPORT_TESTING_ConnectRequest); + cc->p1 = p; + cc->p2 = p2; + cc->p1_c = GNUNET_YES; + GNUNET_CONTAINER_DLL_insert (tth->cc_head, + tth->cc_tail, + cc); + } + found = GNUNET_NO; + GNUNET_TRANSPORT_TESTING_find_connecting_context (p2, + p, + &set_p2c, + &found); + if (GNUNET_NO == found) + { + cc = GNUNET_new (struct GNUNET_TRANSPORT_TESTING_ConnectRequest); + cc->p1 = p2; + cc->p2 = p; + cc->p1_c = GNUNET_YES; + GNUNET_CONTAINER_DLL_insert (tth->cc_head, + tth->cc_tail, + cc); + } + GNUNET_TRANSPORT_TESTING_find_connecting_context (p, + p2, + &set_mq, + mq); + /* update set connected flag for all requests */ + for (cc = tth->cc_head; NULL != cc; cc = cc->next) + { + if (GNUNET_YES == cc->connected) + continue; + if ((GNUNET_YES == cc->p1_c) && + (GNUNET_YES == cc->p2_c)) + { + cc->connected = GNUNET_YES; + /* stop trying to connect */ + if (NULL != cc->tct) + { + GNUNET_SCHEDULER_cancel (cc->tct); + cc->tct = NULL; + } + if (NULL != cc->ats_sh) + { + GNUNET_ATS_connectivity_suggest_cancel (cc->ats_sh); + cc->ats_sh = NULL; + } + } + } + /* then notify application */ + for (cc = tth->cc_head; NULL != cc; cc = ccn) + { + ccn = cc->next; + if ((GNUNET_YES == cc->connected) && + (NULL != cc->cb)) + { + cc->cb (cc->cb_cls); + cc->cb = NULL; /* only notify once! */ + } + } + return ret; +} + + +/** + * Offer the current HELLO of P2 to P1. + * + * @param cls our `struct GNUNET_TRANSPORT_TESTING_ConnectRequest` + */ +static void +offer_hello (void *cls); + + +static void +notify_disconnect (void *cls, + const struct GNUNET_PeerIdentity *peer, + void *handler_cls) +{ + struct GNUNET_TRANSPORT_TESTING_PeerContext *p = cls; + struct GNUNET_TRANSPORT_TESTING_Handle *tth = p->tth; + char *p2_s; + /* Find PeerContext */ + int no = 0; + struct GNUNET_TRANSPORT_TESTING_PeerContext *p2 = NULL; + struct GNUNET_TRANSPORT_TESTING_ConnectRequest *cc; + + p2 = find_peer_context (p->tth, + peer); + no = p->no; + if (NULL != p2) + GNUNET_asprintf (&p2_s, + "%u (`%s')", + p2->no, + GNUNET_i2s (&p2->id)); + else + GNUNET_asprintf (&p2_s, + "`%s'", + GNUNET_i2s (peer)); + LOG (GNUNET_ERROR_TYPE_DEBUG, + "Peers %s disconnected from peer %u (`%s')\n", + p2_s, + no, + GNUNET_i2s (&p->id)); + GNUNET_free (p2_s); + /* notify about disconnect */ + if (NULL != p->nd) + p->nd (p->cb_cls, + peer, + handler_cls); + if (NULL == p2) + return; + /* clear MQ, it is now invalid */ + GNUNET_TRANSPORT_TESTING_find_connecting_context (p, + p2, + &set_mq, + NULL); + /* update set connected flags for all requests */ + GNUNET_TRANSPORT_TESTING_find_connecting_context (p, + p2, + &clear_p1c, + NULL); + GNUNET_TRANSPORT_TESTING_find_connecting_context (p2, + p, + &clear_p2c, + NULL); + /* resume connectivity requests as necessary */ + for (cc = tth->cc_head; NULL != cc; cc = cc->next) + { + if (GNUNET_NO == cc->connected) + continue; + if ((GNUNET_YES != cc->p1_c) || + (GNUNET_YES != cc->p2_c)) + { + cc->connected = GNUNET_NO; + /* start trying to connect */ + if (NULL == cc->tct) + cc->tct = GNUNET_SCHEDULER_add_now (&offer_hello, + cc); + if (NULL == cc->ats_sh) + cc->ats_sh = GNUNET_ATS_connectivity_suggest (cc->p1->ats, + &p2->id, + 1); + } + } +} + + +static void +hello_iter_cb (void *cb_cls, + const struct GNUNET_PEERSTORE_Record *record, + const char *emsg) +{ + struct GNUNET_TRANSPORT_TESTING_PeerContext *p = cb_cls; + //Check record type et al? + p->hello = GNUNET_malloc (record->value_size); + memcpy (p->hello, record->value, record->value_size); + + GNUNET_PEERSTORE_iterate_cancel (p->pic); + if (NULL != p->start_cb) + { + LOG (GNUNET_ERROR_TYPE_DEBUG, + "Peer %u (`%s') successfully started\n", + p->no, + GNUNET_i2s (&p->id)); + p->start_cb (p->start_cb_cls); + p->start_cb = NULL; + } +} + + +/** + * Start a peer with the given configuration + * @param tth the testing handle + * @param cfgname configuration file + * @param peer_id a unique number to identify the peer + * @param handlers functions for receiving messages + * @param nc connect callback + * @param nd disconnect callback + * @param cb_cls closure for callback + * @param start_cb start callback + * @param start_cb_cls closure for callback + * @return the peer context + */ +struct GNUNET_TRANSPORT_TESTING_PeerContext * +GNUNET_TRANSPORT_TESTING_start_peer (struct + GNUNET_TRANSPORT_TESTING_Handle *tth, + const char *cfgname, + int peer_id, + const struct + GNUNET_MQ_MessageHandler *handlers, + GNUNET_TRANSPORT_NotifyConnect nc, + GNUNET_TRANSPORT_NotifyDisconnect nd, + void *cb_cls, + GNUNET_SCHEDULER_TaskCallback start_cb, + void *start_cb_cls) +{ + char *emsg = NULL; + struct GNUNET_TRANSPORT_TESTING_PeerContext *p; + struct GNUNET_PeerIdentity dummy; + unsigned int i; + + if (GNUNET_NO == GNUNET_DISK_file_test (cfgname)) + { + LOG (GNUNET_ERROR_TYPE_ERROR, + "File not found: `%s'\n", + cfgname); + return NULL; + } + + p = GNUNET_new (struct GNUNET_TRANSPORT_TESTING_PeerContext); + p->tth = tth; + p->nc = nc; + p->nd = nd; + if (NULL != handlers) + { + for (i = 0; NULL != handlers[i].cb; i++) + ; + p->handlers = GNUNET_new_array (i + 1, + struct GNUNET_MQ_MessageHandler); + GNUNET_memcpy (p->handlers, + handlers, + i * sizeof(struct GNUNET_MQ_MessageHandler)); + } + if (NULL != cb_cls) + p->cb_cls = cb_cls; + else + p->cb_cls = p; + p->start_cb = start_cb; + if (NULL != start_cb_cls) + p->start_cb_cls = start_cb_cls; + else + p->start_cb_cls = p; + GNUNET_CONTAINER_DLL_insert (tth->p_head, + tth->p_tail, + p); + + /* Create configuration and call testing lib to modify it */ + p->cfg = GNUNET_CONFIGURATION_create (); + GNUNET_assert (GNUNET_OK == + GNUNET_CONFIGURATION_load (p->cfg, cfgname)); + if (GNUNET_SYSERR == + GNUNET_TESTING_configuration_create (tth->tl_system, + p->cfg)) + { + LOG (GNUNET_ERROR_TYPE_ERROR, + "Testing library failed to create unique configuration based on `%s'\n", + cfgname); + GNUNET_CONFIGURATION_destroy (p->cfg); + GNUNET_free (p); + return NULL; + } + + p->no = peer_id; + /* Configure peer with configuration */ + p->peer = GNUNET_TESTING_peer_configure (tth->tl_system, + p->cfg, + p->no, + NULL, + &emsg); + if (NULL == p->peer) + { + LOG (GNUNET_ERROR_TYPE_ERROR, + "Testing library failed to create unique configuration based on `%s': `%s'\n", + cfgname, + emsg); + GNUNET_TRANSPORT_TESTING_stop_peer (p); + GNUNET_free (emsg); + return NULL; + } + GNUNET_free (emsg); + if (GNUNET_OK != GNUNET_TESTING_peer_start (p->peer)) + { + LOG (GNUNET_ERROR_TYPE_ERROR, + "Testing library failed to create unique configuration based on `%s'\n", + cfgname); + GNUNET_TRANSPORT_TESTING_stop_peer (p); + return NULL; + } + + memset (&dummy, + '\0', + sizeof(dummy)); + GNUNET_TESTING_peer_get_identity (p->peer, + &p->id); + if (0 == memcmp (&dummy, + &p->id, + sizeof(struct GNUNET_PeerIdentity))) + { + LOG (GNUNET_ERROR_TYPE_ERROR, + "Testing library failed to obtain peer identity for peer %u\n", + p->no); + GNUNET_TRANSPORT_TESTING_stop_peer (p); + return NULL; + } + LOG (GNUNET_ERROR_TYPE_DEBUG, + "Peer %u configured with identity `%s'\n", + p->no, + GNUNET_i2s_full (&p->id)); + p->tmh = GNUNET_TRANSPORT_manipulation_connect (p->cfg); + p->th = GNUNET_TRANSPORT_core_connect (p->cfg, + NULL, + handlers, + p, + ¬ify_connect, + ¬ify_disconnect); + if ((NULL == p->th) || + (NULL == p->tmh)) + { + LOG (GNUNET_ERROR_TYPE_ERROR, + "Failed to connect to transport service for peer `%s': `%s'\n", + cfgname, + emsg); + GNUNET_TRANSPORT_TESTING_stop_peer (p); + return NULL; + } + p->ats = GNUNET_ATS_connectivity_init (p->cfg); + if (NULL == p->ats) + { + LOG (GNUNET_ERROR_TYPE_ERROR, + "Failed to connect to ATS service for peer `%s': `%s'\n", + cfgname, + emsg); + GNUNET_TRANSPORT_TESTING_stop_peer (p); + return NULL; + } + p->pic = GNUNET_PEERSTORE_iterate (p->ph, + "transport", + &p->id, + GNUNET_PEERSTORE_TRANSPORT_HELLO_KEY, + hello_iter_cb, + p); + GNUNET_assert (NULL != p->pic); + + return p; +} + + +/** + * Stops and restarts the given peer, sleeping (!) for 5s in between. + * + * @param p the peer + * @param restart_cb callback to call when restarted + * @param restart_cb_cls callback closure + * @return #GNUNET_OK in success otherwise #GNUNET_SYSERR + */ +int +GNUNET_TRANSPORT_TESTING_restart_peer (struct + GNUNET_TRANSPORT_TESTING_PeerContext *p, + GNUNET_SCHEDULER_TaskCallback restart_cb, + void *restart_cb_cls) +{ + struct GNUNET_TRANSPORT_TESTING_ConnectRequest *cc; + struct GNUNET_TRANSPORT_TESTING_ConnectRequest *ccn; + + /* shutdown */ + LOG (GNUNET_ERROR_TYPE_DEBUG, + "Stopping peer %u (`%s')\n", + p->no, + GNUNET_i2s (&p->id)); + if (NULL != p->pic) + { + GNUNET_PEERSTORE_iterate_cancel (p->pic); + p->pic = NULL; + } + if (NULL != p->th) + { + GNUNET_TRANSPORT_core_disconnect (p->th); + p->th = NULL; + } + if (NULL != p->tmh) + { + GNUNET_TRANSPORT_manipulation_disconnect (p->tmh); + p->tmh = NULL; + } + for (cc = p->tth->cc_head; NULL != cc; cc = ccn) + { + ccn = cc->next; + if ((cc->p1 == p) || + (cc->p2 == p)) + GNUNET_TRANSPORT_TESTING_connect_peers_cancel (cc); + } + if (NULL != p->ats) + { + GNUNET_ATS_connectivity_done (p->ats); + p->ats = NULL; + } + if (GNUNET_SYSERR == + GNUNET_TESTING_peer_stop (p->peer)) + { + LOG (GNUNET_ERROR_TYPE_ERROR, + "Failed to stop peer %u (`%s')\n", + p->no, + GNUNET_i2s (&p->id)); + return GNUNET_SYSERR; + } + + sleep (5); // YUCK! + + LOG (GNUNET_ERROR_TYPE_DEBUG, + "Restarting peer %u (`%s')\n", + p->no, + GNUNET_i2s (&p->id)); + /* restart */ + if (GNUNET_SYSERR == GNUNET_TESTING_peer_start (p->peer)) + { + LOG (GNUNET_ERROR_TYPE_ERROR, + "Failed to restart peer %u (`%s')\n", + p->no, + GNUNET_i2s (&p->id)); + return GNUNET_SYSERR; + } + + GNUNET_assert (NULL == p->start_cb); + p->start_cb = restart_cb; + p->start_cb_cls = restart_cb_cls; + + p->th = GNUNET_TRANSPORT_core_connect (p->cfg, + NULL, + p->handlers, + p, + ¬ify_connect, + ¬ify_disconnect); + GNUNET_assert (NULL != p->th); + p->ats = GNUNET_ATS_connectivity_init (p->cfg); + p->pic = GNUNET_PEERSTORE_iterate (p->ph, + "transport", + &p->id, + GNUNET_PEERSTORE_TRANSPORT_HELLO_KEY, + hello_iter_cb, + p); + GNUNET_assert (NULL != p->pic); + return GNUNET_OK; +} + + +/** + * Shutdown the given peer + * + * @param p the peer + */ +void +GNUNET_TRANSPORT_TESTING_stop_peer (struct + GNUNET_TRANSPORT_TESTING_PeerContext *p) +{ + struct GNUNET_TRANSPORT_TESTING_Handle *tth = p->tth; + struct GNUNET_TRANSPORT_TESTING_ConnectRequest *cc; + struct GNUNET_TRANSPORT_TESTING_ConnectRequest *ccn; + + for (cc = tth->cc_head; NULL != cc; cc = ccn) + { + ccn = cc->next; + if ((cc->p1 == p) || + (cc->p2 == p)) + GNUNET_TRANSPORT_TESTING_connect_peers_cancel (cc); + } + if (NULL != p->pic) + { + GNUNET_PEERSTORE_iterate_cancel (p->pic); + p->pic = NULL; + } + if (NULL != p->tmh) + { + GNUNET_TRANSPORT_manipulation_disconnect (p->tmh); + p->tmh = NULL; + } + if (NULL != p->th) + { + GNUNET_TRANSPORT_core_disconnect (p->th); + p->th = NULL; + } + if (NULL != p->peer) + { + if (GNUNET_OK != + GNUNET_TESTING_peer_stop (p->peer)) + { + LOG (GNUNET_ERROR_TYPE_DEBUG, + "Testing lib failed to stop peer %u (`%s')\n", + p->no, + GNUNET_i2s (&p->id)); + } + GNUNET_TESTING_peer_destroy (p->peer); + p->peer = NULL; + } + if (NULL != p->ats) + { + GNUNET_ATS_connectivity_done (p->ats); + p->ats = NULL; + } + if (NULL != p->hello) + { + GNUNET_free (p->hello); + p->hello = NULL; + } + if (NULL != p->cfg) + { + GNUNET_CONFIGURATION_destroy (p->cfg); + p->cfg = NULL; + } + if (NULL != p->handlers) + { + GNUNET_free (p->handlers); + p->handlers = NULL; + } + GNUNET_CONTAINER_DLL_remove (tth->p_head, + tth->p_tail, + p); + LOG (GNUNET_ERROR_TYPE_DEBUG, + "Peer %u (`%s') stopped\n", + p->no, + GNUNET_i2s (&p->id)); + GNUNET_free (p); +} + + +/** + * Function called after the HELLO was passed to the + * transport service. + * FIXME maybe schedule the application_validate somehow + */ +/* +static void +hello_offered (void *cls) +{ + struct GNUNET_TRANSPORT_TESTING_ConnectRequest *cc = cls; + + cc->oh = NULL; + cc->tct = GNUNET_SCHEDULER_add_delayed (GNUNET_TIME_UNIT_SECONDS, + &offer_hello, + cc); +}*/ + + +/** + * Offer the current HELLO of P2 to P1. + * + * @param cls our `struct GNUNET_TRANSPORT_TESTING_ConnectRequest` + */ +static void +offer_hello (void *cls) +{ + struct GNUNET_TRANSPORT_TESTING_ConnectRequest *cc = cls; + struct GNUNET_TRANSPORT_TESTING_PeerContext *p1 = cc->p1; + struct GNUNET_TRANSPORT_TESTING_PeerContext *p2 = cc->p2; + struct GNUNET_TIME_Absolute t; + enum GNUNET_NetworkType nt; + char *addr; + + cc->tct = NULL; + { + char *p2_s = GNUNET_strdup (GNUNET_i2s (&p2->id)); + + LOG (GNUNET_ERROR_TYPE_DEBUG, + "Asking peer %u (`%s') to connect peer %u (`%s'), providing HELLO with %s\n", + p1->no, + GNUNET_i2s (&p1->id), + p2->no, + p2_s, + cc->p2->hello); + GNUNET_free (p2_s); + } + + addr = GNUNET_HELLO_extract_address (cc->p2->hello, + cc->p2->hello_size, + &cc->p2->id, + &nt, + &t); + GNUNET_assert (NULL == addr); + GNUNET_TRANSPORT_application_validate (cc->p1->ah, + &cc->p2->id, + nt, + addr); + GNUNET_free (addr); +} + + +/** + * Initiate a connection from p1 to p2 by offering p1 p2's HELLO message + * + * Remarks: start_peer's notify_connect callback can be called before. + * + * @param tth transport testing handle + * @param p1 peer 1 + * @param p2 peer 2 + * @param cb the callback to call when both peers notified that they are connected + * @param cls callback cls + * @return a connect request handle + */ +struct GNUNET_TRANSPORT_TESTING_ConnectRequest * +GNUNET_TRANSPORT_TESTING_connect_peers (struct + GNUNET_TRANSPORT_TESTING_PeerContext *p1, + struct + GNUNET_TRANSPORT_TESTING_PeerContext *p2, + GNUNET_SCHEDULER_TaskCallback cb, + void *cls) +{ + struct GNUNET_TRANSPORT_TESTING_Handle *tth = p1->tth; + struct GNUNET_TRANSPORT_TESTING_ConnectRequest *cc; + struct GNUNET_TRANSPORT_TESTING_ConnectRequest *ccn; + + ccn = NULL; + for (cc = tth->cc_head; NULL != cc; cc = cc->next) + { + if ((cc->p1 == p1) && + (cc->p2 == p2)) + { + ccn = cc; + break; + } + } + + cc = GNUNET_new (struct GNUNET_TRANSPORT_TESTING_ConnectRequest); + cc->p1 = p1; + cc->p2 = p2; + cc->cb = cb; + if (NULL != cls) + cc->cb_cls = cls; + else + cc->cb_cls = cc; + if (NULL != ccn) + { + cc->p1_c = ccn->p1_c; + cc->p2_c = ccn->p2_c; + cc->connected = ccn->connected; + } + GNUNET_CONTAINER_DLL_insert (tth->cc_head, + tth->cc_tail, + cc); + cc->tct = GNUNET_SCHEDULER_add_now (&offer_hello, + cc); + cc->ats_sh = GNUNET_ATS_connectivity_suggest (cc->p1->ats, + &p2->id, + 1); + LOG (GNUNET_ERROR_TYPE_DEBUG, + "New connect request %p\n", + cc); + return cc; +} + + +/** + * Cancel the request to connect two peers + * Tou MUST cancel the request if you stop the peers before the peers connected succesfully + * + * @param tth transport testing handle + * @param cc a connect request handle + */ +void +GNUNET_TRANSPORT_TESTING_connect_peers_cancel (struct + GNUNET_TRANSPORT_TESTING_ConnectRequest + *cc) +{ + struct GNUNET_TRANSPORT_TESTING_Handle *tth = cc->p1->tth; + + LOG (GNUNET_ERROR_TYPE_DEBUG, + "Canceling connect request!\n"); + if (NULL != cc->tct) + { + GNUNET_SCHEDULER_cancel (cc->tct); + cc->tct = NULL; + } + if (NULL != cc->ats_sh) + { + GNUNET_ATS_connectivity_suggest_cancel (cc->ats_sh); + cc->ats_sh = NULL; + } + GNUNET_CONTAINER_DLL_remove (tth->cc_head, + tth->cc_tail, + cc); + GNUNET_free (cc); +} + + +/** + * Clean up the transport testing + * + * @param tth transport testing handle + */ +void +GNUNET_TRANSPORT_TESTING_done (struct GNUNET_TRANSPORT_TESTING_Handle *tth) +{ + struct GNUNET_TRANSPORT_TESTING_ConnectRequest *cc; + struct GNUNET_TRANSPORT_TESTING_ConnectRequest *ct; + struct GNUNET_TRANSPORT_TESTING_PeerContext *p; + struct GNUNET_TRANSPORT_TESTING_PeerContext *t; + + if (NULL == tth) + return; + cc = tth->cc_head; + while (NULL != cc) + { + ct = cc->next; + LOG (GNUNET_ERROR_TYPE_ERROR, + "Developer forgot to cancel connect request!\n"); + GNUNET_TRANSPORT_TESTING_connect_peers_cancel (cc); + cc = ct; + } + p = tth->p_head; + while (NULL != p) + { + t = p->next; + LOG (GNUNET_ERROR_TYPE_ERROR, + "Developer forgot to stop peer!\n"); + GNUNET_TRANSPORT_TESTING_stop_peer (p); + p = t; + } + GNUNET_TESTING_system_destroy (tth->tl_system, + GNUNET_YES); + + GNUNET_free (tth); +} + + +/** + * Initialize the transport testing + * + * @return transport testing handle + */ +struct GNUNET_TRANSPORT_TESTING_Handle * +GNUNET_TRANSPORT_TESTING_init () +{ + struct GNUNET_TRANSPORT_TESTING_Handle *tth; + + tth = GNUNET_new (struct GNUNET_TRANSPORT_TESTING_Handle); + tth->tl_system = GNUNET_TESTING_system_create ("transport-testing", + NULL, + NULL, + NULL); + if (NULL == tth->tl_system) + { + GNUNET_log (GNUNET_ERROR_TYPE_ERROR, + "Failed to initialize testing library!\n"); + GNUNET_free (tth); + return NULL; + } + return tth; +} + + +/* end of transport-testing.c */ diff --git a/src/transport/transport-testing2.h b/src/transport/transport-testing2.h new file mode 100644 index 000000000..3554436d8 --- /dev/null +++ b/src/transport/transport-testing2.h @@ -0,0 +1,924 @@ +/* + This file is part of GNUnet. + Copyright (C) 2006, 2009, 2015, 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 transport-testing.h + * @brief testing lib for transport service + * @author Matthias Wachs + * @author Christian Grothoff + */ +#ifndef TRANSPORT_TESTING_H +#define TRANSPORT_TESTING_H +#include "platform.h" +#include "gnunet_util_lib.h" +#include "gnunet_hello_lib.h" +#include "gnunet_peerstore_service.h" +#include "gnunet_transport_core_service.h" +#include "gnunet_transport_application_service.h" +#include "gnunet_transport_manipulation_service.h" +#include "gnunet_testing_lib.h" + + +/* ************* Basic functions for starting/stopping/connecting *********** */ + +/** + * Context for a single peer + */ +struct GNUNET_TRANSPORT_TESTING_PeerContext; + +/** + * Definition for a transport testing handle + */ +struct GNUNET_TRANSPORT_TESTING_Handle; + + +/** + * Context for a single peer + */ +struct GNUNET_TRANSPORT_TESTING_PeerContext +{ + /** + * Next element in the DLL + */ + struct GNUNET_TRANSPORT_TESTING_PeerContext *next; + + /** + * Previous element in the DLL + */ + struct GNUNET_TRANSPORT_TESTING_PeerContext *prev; + + /** + * Transport testing handle this peer belongs to + */ + struct GNUNET_TRANSPORT_TESTING_Handle *tth; + + /** + * Application handle + */ + struct GNUNET_TRANSPORT_ApplicationHandle *ah; + + /** + * Peer's configuration + */ + struct GNUNET_CONFIGURATION_Handle *cfg; + + /** + * Peer's transport service handle + */ + struct GNUNET_TRANSPORT_CoreHandle *th; + + /** + * Peer's transport service manipulation handle + */ + struct GNUNET_TRANSPORT_ManipulationHandle *tmh; + + /** + * Peer's ATS handle. + */ + struct GNUNET_ATS_ConnectivityHandle *ats; + + /** + * Peer's PEERSTORE Handle + */ + struct GNUNET_PEERSTORE_Handle *ph; + + /** + * Peer's transport get hello handle to retrieve peer's HELLO message + */ + struct GNUNET_PEERSTORE_IterateContext *pic; + + /** + * Hello + */ + char *hello; + + /** + * Hello size + */ + size_t hello_size; + + /** + * Peer's testing handle + */ + struct GNUNET_TESTING_Peer *peer; + + /** + * Peer identity + */ + struct GNUNET_PeerIdentity id; + + /** + * Handle for the peer's ARM process + */ + struct GNUNET_OS_Process *arm_proc; + + /** + * Receive callback + */ + struct GNUNET_MQ_MessageHandler *handlers; + + /** + * Notify connect callback + */ + GNUNET_TRANSPORT_NotifyConnect nc; + + /** + * Notify disconnect callback + */ + GNUNET_TRANSPORT_NotifyDisconnect nd; + + /** + * Startup completed callback + */ + GNUNET_SCHEDULER_TaskCallback start_cb; + + /** + * Closure for the @a nc and @a nd callbacks + */ + void *cb_cls; + + /** + * Closure for @e start_cb. + */ + void *start_cb_cls; + + /** + * An unique number to identify the peer + */ + unsigned int no; +}; + + +/** + * Handle for a request to connect two peers. + */ +struct GNUNET_TRANSPORT_TESTING_ConnectRequest +{ + /** + * Kept in a DLL. + */ + struct GNUNET_TRANSPORT_TESTING_ConnectRequest *next; + + /** + * Kept in a DLL. + */ + struct GNUNET_TRANSPORT_TESTING_ConnectRequest *prev; + + /** + * Peer we want to connect. + */ + struct GNUNET_TRANSPORT_TESTING_PeerContext *p1; + + /** + * Peer we want to connect. + */ + struct GNUNET_TRANSPORT_TESTING_PeerContext *p2; + + /** + * Task by which we accomplish the connection. + */ + struct GNUNET_SCHEDULER_Task *tct; + + /** + * Handle by which we ask ATS to faciliate the connection. + */ + struct GNUNET_ATS_ConnectivitySuggestHandle *ats_sh; + + /** + * Function to call upon completion. + */ + GNUNET_SCHEDULER_TaskCallback cb; + + /** + * Closure for @e cb. + */ + void *cb_cls; + + /** + * Message queue for sending from @a p1 to @a p2. + */ + struct GNUNET_MQ_Handle *mq; + + /** + * Set if peer1 says the connection is up to peer2. + */ + int p1_c; + + /** + * Set if peer2 says the connection is up to peer1. + */ + int p2_c; + + /** + * #GNUNET_YES if both @e p1_c and @e p2_c are #GNUNET_YES. + */ + int connected; +}; + + +/** + * Handle for a test run. + */ +struct GNUNET_TRANSPORT_TESTING_Handle +{ + /** + * Testing library system handle + */ + struct GNUNET_TESTING_System *tl_system; + + /** + * head DLL of connect contexts + */ + struct GNUNET_TRANSPORT_TESTING_ConnectRequest *cc_head; + + /** + * head DLL of connect contexts + */ + struct GNUNET_TRANSPORT_TESTING_ConnectRequest *cc_tail; + + /** + * head DLL of peers + */ + struct GNUNET_TRANSPORT_TESTING_PeerContext *p_head; + + /** + * tail DLL of peers + */ + struct GNUNET_TRANSPORT_TESTING_PeerContext *p_tail; +}; + + +/** + * Initialize the transport testing + * + * @return transport testing handle + */ +struct GNUNET_TRANSPORT_TESTING_Handle * +GNUNET_TRANSPORT_TESTING_init (void); + + +/** + * Clean up the transport testing + * + * @param tth transport testing handle + */ +void +GNUNET_TRANSPORT_TESTING_done (struct GNUNET_TRANSPORT_TESTING_Handle *tth); + + +/** + * Start a peer with the given configuration + * + * @param tth the testing handle + * @param cfgname configuration file + * @param peer_id the peer_id + * @param handlers functions for receiving messages + * @param nc connect callback + * @param nd disconnect callback + * @param cb_cls closure for @a nc and @a nd callback + * @param start_cb start callback + * @param start_cb_cls closure for @a start_cb + * @return the peer context + */ +struct GNUNET_TRANSPORT_TESTING_PeerContext * +GNUNET_TRANSPORT_TESTING_start_peer ( + struct GNUNET_TRANSPORT_TESTING_Handle *tth, + const char *cfgname, + int peer_id, + const struct GNUNET_MQ_MessageHandler *handlers, + GNUNET_TRANSPORT_NotifyConnect nc, + GNUNET_TRANSPORT_NotifyDisconnect nd, + void *cb_cls, + GNUNET_SCHEDULER_TaskCallback start_cb, + void *start_cb_cls); + + +/** + * Shutdown the given peer + * + * @param p the peer + */ +void +GNUNET_TRANSPORT_TESTING_stop_peer ( + struct GNUNET_TRANSPORT_TESTING_PeerContext *pc); + + +/** + * Stops and restarts the given peer, sleeping (!) for 5s in between. + * + * @param p the peer + * @param restart_cb restart callback + * @param restart_cb_cls callback closure + * @return #GNUNET_OK in success otherwise #GNUNET_SYSERR + */ +int +GNUNET_TRANSPORT_TESTING_restart_peer ( + struct GNUNET_TRANSPORT_TESTING_PeerContext *p, + GNUNET_SCHEDULER_TaskCallback restart_cb, + void *restart_cb_cls); + + +/** + * Connect the given peers and call the callback when both peers + * report the inbound connection. Remarks: start_peer's notify_connect + * callback can be called before. + * + * @param p1 peer 1 + * @param p2 peer 2 + * @param cb the callback to call when both peers notified that they are + * connected + * @param cls callback cls + * @return a connect request handle + */ +struct GNUNET_TRANSPORT_TESTING_ConnectRequest * +GNUNET_TRANSPORT_TESTING_connect_peers ( + struct GNUNET_TRANSPORT_TESTING_PeerContext *p1, + struct GNUNET_TRANSPORT_TESTING_PeerContext *p2, + GNUNET_SCHEDULER_TaskCallback cb, + void *cls); + + +/** + * Cancel the request to connect two peers. You MUST cancel the + * request if you stop the peers before the peers connected + * succesfully. + * + * @param cc a connect request handle + */ +void +GNUNET_TRANSPORT_TESTING_connect_peers_cancel ( + struct GNUNET_TRANSPORT_TESTING_ConnectRequest *cc); + + +/** + * Function called on matching connect requests. + * + * @param cls closure + * @param cc request matching the query + */ +typedef void (*GNUNET_TRANSPORT_TESTING_ConnectContextCallback) ( + void *cls, + struct GNUNET_TRANSPORT_TESTING_ConnectRequest *cc); + + +/** + * Find any connecting context matching the given pair of peers. + * + * @param p1 first peer + * @param p2 second peer + * @param cb function to call + * @param cb_cls closure for @a cb + */ +void +GNUNET_TRANSPORT_TESTING_find_connecting_context ( + struct GNUNET_TRANSPORT_TESTING_PeerContext *p1, + struct GNUNET_TRANSPORT_TESTING_PeerContext *p2, + GNUNET_TRANSPORT_TESTING_ConnectContextCallback cb, + void *cb_cls); + + +/* ********************** high-level process functions *************** */ + + +/** + * Function called once the peers have been launched and + * connected by #GNUNET_TRANSPORT_TESTING_connect_check(). + * + * @param cls closure + * @param num_peers size of the @a p array + * @param p the peers that were launched + */ +typedef void (*GNUNET_TRANSPORT_TESTING_ConnectContinuation) ( + void *cls, + unsigned int num_peers, + struct GNUNET_TRANSPORT_TESTING_PeerContext *p[]); + + +/** + * Internal data structure. + */ +struct GNUNET_TRANSPORT_TESTING_ConnectRequestList; + +/** + * Internal data structure. + */ +struct GNUNET_TRANSPORT_TESTING_InternalPeerContext; + + +GNUNET_NETWORK_STRUCT_BEGIN +struct GNUNET_TRANSPORT_TESTING_TestMessage +{ + /** + * Type is (usually) #GNUNET_TRANSPORT_TESTING_SIMPLE_MTYPE. + */ + struct GNUNET_MessageHeader header; + + /** + * Monotonically increasing counter throughout the test. + */ + uint32_t num GNUNET_PACKED; +}; +GNUNET_NETWORK_STRUCT_END + + +/** + * Function called by the transport for each received message. + * + * @param cls closure + * @param receiver receiver of the message + * @param sender sender of the message + * @param message the message + */ +typedef void (*GNUNET_TRANSPORT_TESTING_ReceiveCallback) ( + void *cls, + struct GNUNET_TRANSPORT_TESTING_PeerContext *receiver, + const struct GNUNET_PeerIdentity *sender, + const struct GNUNET_TRANSPORT_TESTING_TestMessage *message); + + +/** + * Function called to notify transport users that another + * peer connected to us. + * + * @param cls closure + * @param me peer experiencing the event + * @param other peer that connected to @a me + */ +typedef void (*GNUNET_TRANSPORT_TESTING_NotifyConnect) ( + void *cls, + struct GNUNET_TRANSPORT_TESTING_PeerContext *me, + const struct GNUNET_PeerIdentity *other); + + +/** + * Function called to notify transport users that another + * peer disconnected from us. + * + * @param cls closure + * @param me peer experiencing the event + * @param other peer that disconnected from @a me + */ +typedef void (*GNUNET_TRANSPORT_TESTING_NotifyDisconnect) ( + void *cls, + struct GNUNET_TRANSPORT_TESTING_PeerContext *me, + const struct GNUNET_PeerIdentity *other); + + +/** + * Closure that must be passed to + * #GNUNET_TRANSPORT_TESTING_connect_check. + */ +struct GNUNET_TRANSPORT_TESTING_ConnectCheckContext +{ + /** + * How should we continue after the connect? + */ + GNUNET_SCHEDULER_TaskCallback connect_continuation; + + /** + * Closure for @e connect_continuation. + */ + void *connect_continuation_cls; + + /** + * Which configuration file should we pass to the + * #GNUNET_PROGRAM_run() of the testcase? + */ + const char *config_file; + + /** + * Receiver argument to give for peers we start. + */ + GNUNET_TRANSPORT_TESTING_ReceiveCallback rec; + + /** + * Notify connect argument to give for peers we start. + */ + GNUNET_TRANSPORT_TESTING_NotifyConnect nc; + + /** + * Notify disconnect argument to give for peers we start. + */ + GNUNET_TRANSPORT_TESTING_NotifyDisconnect nd; + + /** + * Closure for @e rec, @e nc and @e nd. + */ + void *cls; + + /** + * Custom task to run on shutdown. + */ + GNUNET_SCHEDULER_TaskCallback shutdown_task; + + /** + * Closure for @e shutdown_task. + */ + void *shutdown_task_cls; + + /** + * Custom task to run after peers were started but before we try to + * connect them. If this function is set, we wait ONE second after + * running this function until we continue with connecting the + * peers. + */ + GNUNET_SCHEDULER_TaskCallback pre_connect_task; + + /** + * Closure for @e shutdown_task. + */ + void *pre_connect_task_cls; + + /** + * When should the testcase time out? + */ + struct GNUNET_TIME_Relative timeout; + + /** + * Should we try to create connections in both directions? + */ + int bi_directional; + + /* ******* fields set by #GNUNET_TRANSPORT_TESTING_connect_check **** */ + + /** + * Number of peers involved in the test. + */ + unsigned int num_peers; + + /** + * Configuration files we have, array with @e num_peers entries. + */ + char **cfg_files; + + /** + * Array with @e num_peers entries. + */ + struct GNUNET_TRANSPORT_TESTING_PeerContext **p; + + /** + * Name of the plugin. + */ + const char *test_plugin; + + /** + * Name of the testcase. + */ + const char *test_name; + + /** + * Configuration object for the testcase. + */ + const struct GNUNET_CONFIGURATION_Handle *cfg; + + /** + * Main testing handle. + */ + struct GNUNET_TRANSPORT_TESTING_Handle *tth; + + /** + * Result from the main function, set to #GNUNET_OK on success. + * Clients should set to #GNUNET_SYSERR to indicate test failure. + */ + int global_ret; + + /** + * Generator for the `num` field in test messages. Incremented each + * time #GNUNET_TRANSPORT_TESTING_simple_send or + * #GNUNET_TRANSPORT_TESTING_large_send are used to transmit a + * message. + */ + uint32_t send_num_gen; + + /* ******* internal state, clients should not mess with this **** */ + + /** + * Task run on timeout. + */ + struct GNUNET_SCHEDULER_Task *timeout_task; + + /** + * Task run to connect peers. + */ + struct GNUNET_SCHEDULER_Task *connect_task; + + /** + * Number of peers that have been started. + */ + unsigned int started; + + /** + * DLL of active connect requests. + */ + struct GNUNET_TRANSPORT_TESTING_ConnectRequestList *crl_head; + + /** + * DLL of active connect requests. + */ + struct GNUNET_TRANSPORT_TESTING_ConnectRequestList *crl_tail; + + /** + * Array with @e num_peers entries. + */ + struct GNUNET_TRANSPORT_TESTING_InternalPeerContext *ip; +}; + + +/** + * Find peer by peer ID. + * + * @param ccc context to search + * @param peer peer to look for + * @return NULL if @a peer was not found + */ +struct GNUNET_TRANSPORT_TESTING_PeerContext * +GNUNET_TRANSPORT_TESTING_find_peer ( + struct GNUNET_TRANSPORT_TESTING_ConnectCheckContext *ccc, + const struct GNUNET_PeerIdentity *peer); + + +/** + * Common implementation of the #GNUNET_TRANSPORT_TESTING_CheckCallback. + * Starts and connects the two peers, then invokes the + * `connect_continuation` from @a cls. Sets up a timeout to + * abort the test, and a shutdown handler to clean up properly + * on exit. + * + * @param cls closure of type `struct + * GNUNET_TRANSPORT_TESTING_ConnectCheckContext` + * @param tth_ initialized testing handle + * @param test_plugin_ name of the plugin + * @param test_name_ name of the test + * @param num_peers number of entries in the @a cfg_file array + * @param cfg_files array of names of configuration files for the peers + * @return #GNUNET_SYSERR on error + */ +int +GNUNET_TRANSPORT_TESTING_connect_check ( + void *cls, + struct GNUNET_TRANSPORT_TESTING_Handle *tth_, + const char *test_plugin_, + const char *test_name_, + unsigned int num_peers, + char *cfg_files[]); + + +/** + * Main function of a testcase. Called with the initial setup data + * for the test as derived from the source name and the binary name. + * + * @param cls closure + * @param tth_ initialized testing handle + * @param test_plugin_ name of the plugin + * @param test_name_ name of the test + * @param num_peers number of entries in the @a cfg_file array + * @param cfg_files array of names of configuration files for the peers + * @return #GNUNET_SYSERR on error + */ +typedef int (*GNUNET_TRANSPORT_TESTING_CheckCallback) ( + void *cls, + struct GNUNET_TRANSPORT_TESTING_Handle *tth_, + const char *test_plugin_, + const char *test_name_, + unsigned int num_peers, + char *cfg_files[]); + + +/** + * Setup testcase. Calls @a check with the data the test needs. + * + * @param argv0 binary name (argv[0]) + * @param filename source file name (__FILE__) + * @param num_peers number of peers to start + * @param check main function to run + * @param check_cls closure for @a check + * @return #GNUNET_OK on success + */ +int +GNUNET_TRANSPORT_TESTING_main_ (const char *argv0, + const char *filename, + unsigned int num_peers, + GNUNET_TRANSPORT_TESTING_CheckCallback check, + void *check_cls); + + +/** + * Setup testcase. Calls @a check with the data the test needs. + * + * @param num_peers number of peers to start + * @param check main function to run + * @param check_cls closure for @a check + * @return #GNUNET_OK on success + */ +#define GNUNET_TRANSPORT_TESTING_main(num_peers, check, check_cls) \ + GNUNET_TRANSPORT_TESTING_main_ (argv[0], \ + __FILE__, \ + num_peers, \ + check, \ + check_cls) + +/* ***************** Convenience functions for sending ********* */ + +/** + * Send a test message of type @a mtype and size @a msize from + * peer @a sender to peer @a receiver. The peers should be + * connected when this function is called. + * + * @param sender the sending peer + * @param receiver the receiving peer + * @param mtype message type to use + * @param msize size of the message, at least `sizeof (struct + * GNUNET_TRANSPORT_TESTING_TestMessage)` + * @param num unique message number + * @param cont continuation to call after transmission + * @param cont_cls closure for @a cont + * @return #GNUNET_OK if message was queued, + * #GNUNET_NO if peers are not connected + * #GNUNET_SYSERR if @a msize is illegal + */ +int +GNUNET_TRANSPORT_TESTING_send ( + struct GNUNET_TRANSPORT_TESTING_PeerContext *sender, + struct GNUNET_TRANSPORT_TESTING_PeerContext *receiver, + uint16_t mtype, + uint16_t msize, + uint32_t num, + GNUNET_SCHEDULER_TaskCallback cont, + void *cont_cls); + + +/** + * Message type used by #GNUNET_TRANSPORT_TESTING_simple_send(). + */ +#define GNUNET_TRANSPORT_TESTING_SIMPLE_MTYPE 12345 + +/** + * Alternative message type for tests. + */ +#define GNUNET_TRANSPORT_TESTING_SIMPLE_MTYPE2 12346 + + +/** + * Type of the closure argument to pass to + * #GNUNET_TRANSPORT_TESTING_simple_send() and + * #GNUNET_TRANSPORT_TESTING_large_send(). + */ +struct GNUNET_TRANSPORT_TESTING_SendClosure +{ + /** + * Context for the transmission. + */ + struct GNUNET_TRANSPORT_TESTING_ConnectCheckContext *ccc; + + /** + * Function that returns the desired message size. Overrides + * the message size, can be NULL in which case the message + * size is the default. + */ + size_t (*get_size_cb) (unsigned int n); + + /** + * Number of messages to be transmitted in a loop. + * Use zero for "forever" (until external shutdown). + */ + unsigned int num_messages; + + /** + * Function to call after all transmissions, can be NULL. + */ + GNUNET_SCHEDULER_TaskCallback cont; + + /** + * Closure for @e cont. + */ + void *cont_cls; +}; + + +/** + * Task that sends a minimalistic test message from the + * first peer to the second peer. + * + * @param cls the `struct GNUNET_TRANSPORT_TESTING_SendClosure` + * which should contain at least two peers, the first two + * of which should be currently connected + */ +void +GNUNET_TRANSPORT_TESTING_simple_send (void *cls); + +/** + * Size of a message sent with + * #GNUNET_TRANSPORT_TESTING_large_send(). Big enough + * to usually force defragmentation. + */ +#define GNUNET_TRANSPORT_TESTING_LARGE_MESSAGE_SIZE 2600 + +/** + * Task that sends a large test message from the + * first peer to the second peer. + * + * @param cls the `struct GNUNET_TRANSPORT_TESTING_SendClosure` + * which should contain at least two peers, the first two + * of which should be currently connected + */ +void +GNUNET_TRANSPORT_TESTING_large_send (void *cls); + + +/* ********************** log-only convenience functions ************* */ + + +/** + * Log a connect event. + * + * @param cls NULL + * @param me peer that had the event + * @param other peer that connected. + */ +void +GNUNET_TRANSPORT_TESTING_log_connect ( + void *cls, + struct GNUNET_TRANSPORT_TESTING_PeerContext *me, + const struct GNUNET_PeerIdentity *other); + + +/** + * Log a disconnect event. + * + * @param cls NULL + * @param me peer that had the event + * @param other peer that disconnected. + */ +void +GNUNET_TRANSPORT_TESTING_log_disconnect ( + void *cls, + struct GNUNET_TRANSPORT_TESTING_PeerContext *me, + const struct GNUNET_PeerIdentity *other); + + +/* ********************** low-level filename functions *************** */ + + +/** + * Extracts the test filename from an absolute file name and removes + * the extension. + * + * @param file absolute file name + * @return resulting test name + */ +char * +GNUNET_TRANSPORT_TESTING_get_test_name (const char *file); + + +/** + * This function takes the filename (e.g. argv[0), removes a "lt-"-prefix and + * if existing ".exe"-prefix and adds the peer-number + * + * @param file filename of the test, e.g. argv[0] + * @param count peer number + * @return configuration name to use + */ +char * +GNUNET_TRANSPORT_TESTING_get_config_name (const char *file, int count); + + +/** + * Extracts the plugin anme from an absolute file name and the test name + * @param file absolute file name + * @param test test name + * @return the plugin name + */ +char * +GNUNET_TRANSPORT_TESTING_get_test_plugin_name (const char *executable, + const char *testname); + + +/** + * Extracts the filename from an absolute file name and removes the + * extenstion + * + * @param file absolute file name + * @return the source name + */ +char * +GNUNET_TRANSPORT_TESTING_get_test_source_name (const char *file); + +#endif +/* end of transport_testing.h */ -- cgit v1.2.3 From ddbb4c740614d988431700bdcbb358de00be6313 Mon Sep 17 00:00:00 2001 From: Martin Schanzenbach Date: Mon, 30 Nov 2020 19:14:20 +0900 Subject: -fix link --- src/transport/Makefile.am | 1 + 1 file changed, 1 insertion(+) (limited to 'src') diff --git a/src/transport/Makefile.am b/src/transport/Makefile.am index 605d89cc0..800a27aa2 100644 --- a/src/transport/Makefile.am +++ b/src/transport/Makefile.am @@ -175,6 +175,7 @@ libgnunettransporttesting2_la_LIBADD = \ libgnunettransportapplication.la \ libgnunettransportcore.la \ $(top_builddir)/src/testing/libgnunettesting.la \ + $(top_builddir)/src/ats/libgnunetats.la \ $(top_builddir)/src/hello/libgnunethello.la \ $(top_builddir)/src/peerstore/libgnunetpeerstore.la \ $(top_builddir)/src/util/libgnunetutil.la -- cgit v1.2.3 From 1a3070b15b944b2c7406d123947a15af3fd7aa64 Mon Sep 17 00:00:00 2001 From: Florian Dold Date: Fri, 4 Dec 2020 14:52:45 +0100 Subject: gnunet-crypto-tvg: output JSON, fix memleaks This commit also bumps the version of libgnunetutil, due to the spell checking fix to xts in rsa (un)blinding. --- src/util/Makefile.am | 4 +- src/util/gnunet-crypto-tvg.c | 262 ++++++++++++++++++++++++++++++++----------- 2 files changed, 199 insertions(+), 67 deletions(-) (limited to 'src') diff --git a/src/util/Makefile.am b/src/util/Makefile.am index c5059bbb1..1949dceb0 100644 --- a/src/util/Makefile.am +++ b/src/util/Makefile.am @@ -138,7 +138,7 @@ libgnunetutil_la_LIBADD = \ libgnunetutil_la_LDFLAGS = \ $(GN_LIB_LDFLAGS) \ - -version-info 13:2:0 + -version-info 13:2:1 if HAVE_TESTING GNUNET_ECC = gnunet-ecc @@ -195,7 +195,7 @@ gnunet_crypto_tvg_SOURCES = \ gnunet-crypto-tvg.c gnunet_crypto_tvg_LDADD = \ libgnunetutil.la \ - $(GN_LIBINTL) -lgcrypt + $(GN_LIBINTL) -lgcrypt -ljansson gnunet_ecc_SOURCES = \ gnunet-ecc.c diff --git a/src/util/gnunet-crypto-tvg.c b/src/util/gnunet-crypto-tvg.c index c3fead62e..b9dbba065 100644 --- a/src/util/gnunet-crypto-tvg.c +++ b/src/util/gnunet-crypto-tvg.c @@ -22,11 +22,33 @@ * @file util/gnunet-crypto-tgv.c * @brief Generate test vectors for cryptographic operations. * @author Florian Dold + * + * Test vectors have the following format (TypeScript pseudo code): + * + * interface TestVectorFile { + * encoding: "base32crockford"; + * producer?: string; + * vectors: TestVector[]; + * } + * + * enum Operation { + * Hash("hash"), + * ... + * } + * + * interface TestVector { + * operation: Operation; + * // Inputs for the operation + * [ k: string]: string | number; + * }; + * + * */ #include "platform.h" #include "gnunet_util_lib.h" #include "gnunet_signatures.h" #include "gnunet_testing_lib.h" +#include #include GNUNET_NETWORK_STRUCT_BEGIN @@ -46,20 +68,68 @@ GNUNET_NETWORK_STRUCT_END /** - * Print data base32-crockford with a preceding label. + * Create a fresh test vector for a given operation label. + * + * @param vecs array of vectors to append the new vector to + * @param vecname label for the operation of the vector + * @returns the fresh test vector + */ +static json_t * +vec_for (json_t *vecs, const char *vecname) +{ + json_t *t = json_object (); + + json_object_set_new (t, + "operation", + json_string (vecname)); + json_array_append_new (vecs, t); + return t; +} + + +/** + * Add a base32crockford encoded value + * to a test vector. * - * @param label label to print - * @param data data to print + * @param vec test vector to add to + * @param label label for the value + * @param data data to add * @param size size of data */ static void -display_data (char *label, void *data, size_t size) +d2j (json_t *vec, + const char *label, + const void *data, + size_t size) { - char *enc = GNUNET_STRINGS_data_to_string_alloc (data, size); - printf ("%s %s\n", label, enc); - GNUNET_free (enc); + char *buf; + json_t *json; + + buf = GNUNET_STRINGS_data_to_string_alloc (data, size); + json = json_string (buf); + GNUNET_free (buf); + GNUNET_break (NULL != json); + + json_object_set_new (vec, label, json); } +/** + * Add a number to a test vector. + * + * @param vec test vector to add to + * @param label label for the value + * @param data data to add + * @param size size of data + */ +static void +uint2j (json_t *vec, + const char *label, + unsigned int num) +{ + json_t *json = json_integer (num); + + json_object_set_new (vec, label, json); +} /** * Main function that will be run. @@ -75,17 +145,31 @@ run (void *cls, const char *cfgfile, const struct GNUNET_CONFIGURATION_Handle *cfg) { + json_t *vecfile = json_object (); + json_t *vecs = json_array (); + + json_object_set_new (vecfile, + "encoding", + json_string ("base32crockford")); + json_object_set_new (vecfile, + "producer", + json_string ("GNUnet " PACKAGE_VERSION " " VCS_VERSION)); + json_object_set_new (vecfile, + "vectors", + vecs); + { + json_t *vec = vec_for (vecs, "hash"); struct GNUNET_HashCode hc; char *str = "Hello, GNUnet"; GNUNET_CRYPTO_hash (str, strlen (str), &hc); - printf ("hash code:\n"); - display_data (" input", str, strlen (str)); - display_data (" output", &hc, sizeof (struct GNUNET_HashCode)); + d2j (vec, "input", str, strlen (str)); + d2j (vec, "output", &hc, sizeof (struct GNUNET_HashCode)); } { + json_t *vec = vec_for (vecs, "ecdhe_key_derivation"); struct GNUNET_CRYPTO_EcdhePrivateKey priv1; struct GNUNET_CRYPTO_EcdhePublicKey pub1; struct GNUNET_CRYPTO_EcdhePrivateKey priv2; @@ -100,22 +184,26 @@ run (void *cls, &pub1, &skm)); - printf ("ecdhe key:\n"); - display_data (" priv1", - &priv1, - sizeof (struct GNUNET_CRYPTO_EcdhePrivateKey)); - display_data (" pub1", - &pub1, - sizeof (struct GNUNET_CRYPTO_EcdhePublicKey)); - display_data (" priv2", - &priv2, - sizeof (struct GNUNET_CRYPTO_EcdhePrivateKey)); - display_data (" skm", - &skm, - sizeof (struct GNUNET_HashCode)); + d2j (vec, + "priv1", + &priv1, + sizeof (struct GNUNET_CRYPTO_EcdhePrivateKey)); + d2j (vec, + "pub1", + &pub1, + sizeof (struct GNUNET_CRYPTO_EcdhePublicKey)); + d2j (vec, + "priv2", + &priv2, + sizeof (struct GNUNET_CRYPTO_EcdhePrivateKey)); + d2j (vec, + "skm", + &skm, + sizeof (struct GNUNET_HashCode)); } { + json_t *vec = vec_for (vecs, "eddsa_key_derivation"); struct GNUNET_CRYPTO_EddsaPrivateKey priv; struct GNUNET_CRYPTO_EddsaPublicKey pub; @@ -123,15 +211,17 @@ run (void *cls, GNUNET_CRYPTO_eddsa_key_get_public (&priv, &pub); - printf ("eddsa key:\n"); - display_data (" priv", - &priv, - sizeof (struct GNUNET_CRYPTO_EddsaPrivateKey)); - display_data (" pub", - &pub, - sizeof (struct GNUNET_CRYPTO_EddsaPublicKey)); + d2j (vec, + "priv", + &priv, + sizeof (struct GNUNET_CRYPTO_EddsaPrivateKey)); + d2j (vec, + "pub", + &pub, + sizeof (struct GNUNET_CRYPTO_EddsaPublicKey)); } { + json_t *vec = vec_for (vecs, "eddsa_signing"); struct GNUNET_CRYPTO_EddsaPrivateKey priv; struct GNUNET_CRYPTO_EddsaPublicKey pub; struct GNUNET_CRYPTO_EddsaSignature sig; @@ -151,22 +241,26 @@ run (void *cls, &sig, &pub)); - printf ("eddsa sig:\n"); - display_data (" priv", - &priv, - sizeof (struct GNUNET_CRYPTO_EddsaPrivateKey)); - display_data (" pub", - &pub, - sizeof (struct GNUNET_CRYPTO_EddsaPublicKey)); - display_data (" data", - &data, - sizeof (struct TestSignatureDataPS)); - display_data (" sig", - &sig, - sizeof (struct GNUNET_CRYPTO_EddsaSignature)); + d2j (vec, + "priv", + &priv, + sizeof (struct GNUNET_CRYPTO_EddsaPrivateKey)); + d2j (vec, + "pub", + &pub, + sizeof (struct GNUNET_CRYPTO_EddsaPublicKey)); + d2j (vec, + "data", + &data, + sizeof (struct TestSignatureDataPS)); + d2j (vec, + "sig", + &sig, + sizeof (struct GNUNET_CRYPTO_EddsaSignature)); } { + json_t *vec = vec_for (vecs, "kdf"); size_t out_len = 64; char out[out_len]; char *ikm = "I'm the secret input key material"; @@ -184,14 +278,28 @@ run (void *cls, strlen (ctx), NULL)); - printf ("kdf:\n"); - display_data (" salt", salt, strlen (salt)); - display_data (" ikm", ikm, strlen (ikm)); - display_data (" ctx", ctx, strlen (ctx)); - printf (" out_len %u\n", (unsigned int) out_len); - display_data (" out", out, out_len); + d2j (vec, + "salt", + salt, + strlen (salt)); + d2j (vec, + "ikm", + ikm, + strlen (ikm)); + d2j (vec, + "ctx", + ctx, + strlen (ctx)); + uint2j (vec, + "out_len %u\n", + (unsigned int) out_len); + d2j (vec, + "out", + out, + out_len); } { + json_t *vec = vec_for (vecs, "eddsa_ecdh"); struct GNUNET_CRYPTO_EcdhePrivateKey priv_ecdhe; struct GNUNET_CRYPTO_EcdhePublicKey pub_ecdhe; struct GNUNET_CRYPTO_EddsaPrivateKey priv_eddsa; @@ -204,25 +312,26 @@ run (void *cls, GNUNET_CRYPTO_eddsa_key_get_public (&priv_eddsa, &pub_eddsa); GNUNET_CRYPTO_ecdh_eddsa (&priv_ecdhe, &pub_eddsa, &key_material); - printf ("eddsa_ecdh:\n"); - display_data (" priv_ecdhe", + d2j (vec, "priv_ecdhe", &priv_ecdhe, sizeof (struct GNUNET_CRYPTO_EcdhePrivateKey)); - display_data (" pub_ecdhe", + d2j (vec, "pub_ecdhe", &pub_ecdhe, sizeof (struct GNUNET_CRYPTO_EcdhePublicKey)); - display_data (" priv_eddsa", + d2j (vec, "priv_eddsa", &priv_eddsa, sizeof (struct GNUNET_CRYPTO_EddsaPrivateKey)); - display_data (" pub_eddsa", + d2j (vec, "pub_eddsa", &pub_eddsa, sizeof (struct GNUNET_CRYPTO_EddsaPublicKey)); - display_data (" key_material", + d2j (vec, "key_material", &key_material, sizeof (struct GNUNET_HashCode)); } { + json_t *vec = vec_for (vecs, "rsa_blind_signing"); + struct GNUNET_CRYPTO_RsaPrivateKey *skey; struct GNUNET_CRYPTO_RsaPublicKey *pkey; struct GNUNET_HashCode message_hash; @@ -237,6 +346,7 @@ run (void *cls, size_t blinded_sig_enc_length; void *sig_enc_data; size_t sig_enc_length; + skey = GNUNET_CRYPTO_rsa_private_key_create (2048); pkey = GNUNET_CRYPTO_rsa_private_key_get_public (skey); GNUNET_CRYPTO_random_block (GNUNET_CRYPTO_QUALITY_WEAK, @@ -263,21 +373,43 @@ run (void *cls, & blinded_sig_enc_data); sig_enc_length = GNUNET_CRYPTO_rsa_signature_encode (sig, &sig_enc_data); - printf ("blind signing:\n"); - display_data (" message_hash", &message_hash, sizeof (struct - GNUNET_HashCode)); - display_data (" rsa_public_key", public_enc_data, public_enc_len); - display_data (" blinding_key_secret", &bks, sizeof (struct - GNUNET_CRYPTO_RsaBlindingKeySecret)); - display_data (" blinded_message", blinded_data, blinded_len); - display_data (" blinded_sig", blinded_sig_enc_data, - blinded_sig_enc_length); - display_data (" sig", sig_enc_data, sig_enc_length); + d2j (vec, + "message_hash", + &message_hash, + sizeof (struct GNUNET_HashCode)); + d2j (vec, + "rsa_public_key", + public_enc_data, + public_enc_len); + d2j (vec, + "blinding_key_secret", + &bks, + sizeof (struct GNUNET_CRYPTO_RsaBlindingKeySecret)); + d2j (vec, + "blinded_message", + blinded_data, + blinded_len); + d2j (vec, + "blinded_sig", + blinded_sig_enc_data, + blinded_sig_enc_length); + d2j (vec, + "sig", + sig_enc_data, + sig_enc_length); GNUNET_CRYPTO_rsa_private_key_free (skey); GNUNET_CRYPTO_rsa_public_key_free (pkey); GNUNET_CRYPTO_rsa_signature_free (sig); GNUNET_CRYPTO_rsa_signature_free (blinded_sig); + GNUNET_free (public_enc_data); + GNUNET_free (blinded_data); + GNUNET_free (sig_enc_data); + GNUNET_free (blinded_sig_enc_data); } + + json_dumpf (vecfile, stdout, JSON_INDENT (2)); + json_decref (vecfile); + printf ("\n"); } -- cgit v1.2.3 From 4c10ff3b40f6409548e38b763fd96866b69c0a38 Mon Sep 17 00:00:00 2001 From: Florian Dold Date: Fri, 4 Dec 2020 17:22:38 +0100 Subject: gnunet-crypto-tvg: add verification mode --- src/util/gnunet-crypto-tvg.c | 607 ++++++++++++++++++++++++++++++++++++++++++- 1 file changed, 595 insertions(+), 12 deletions(-) (limited to 'src') diff --git a/src/util/gnunet-crypto-tvg.c b/src/util/gnunet-crypto-tvg.c index b9dbba065..5915b4b44 100644 --- a/src/util/gnunet-crypto-tvg.c +++ b/src/util/gnunet-crypto-tvg.c @@ -23,6 +23,9 @@ * @brief Generate test vectors for cryptographic operations. * @author Florian Dold * + * Note that this program shouldn't depend on code in src/json/, + * so we're using raw jansson and no GNUnet JSON helpers. + * * Test vectors have the following format (TypeScript pseudo code): * * interface TestVectorFile { @@ -67,6 +70,18 @@ struct TestSignatureDataPS GNUNET_NETWORK_STRUCT_END +/** + * Should we verify or output test vectors? + */ +static int verify_flag = GNUNET_NO; + + +/** + * Global exit code. + */ +static int global_ret = 0; + + /** * Create a fresh test vector for a given operation label. * @@ -131,19 +146,552 @@ uint2j (json_t *vec, json_object_set_new (vec, label, json); } + +static int +expect_data_fixed (json_t *vec, + const char *name, + void *data, + size_t expect_len) +{ + const char *s = json_string_value (json_object_get (vec, name)); + + if (NULL == s) + return GNUNET_NO; + + if (GNUNET_OK != GNUNET_STRINGS_string_to_data (s, + strlen (s), + data, + expect_len)) + return GNUNET_NO; + return GNUNET_OK; +} + +static int +expect_data_dynamic (json_t *vec, + const char *name, + void **data, + size_t *ret_len) +{ + const char *s = json_string_value (json_object_get (vec, name)); + size_t len; + + if (NULL == s) + return GNUNET_NO; + + len = (strlen (s) * 5) / 8; + if (NULL != ret_len) + *ret_len = len; + *data = GNUNET_malloc (len); + + if (GNUNET_OK != GNUNET_STRINGS_string_to_data (s, strlen (s), *data, len)) + return GNUNET_NO; + return GNUNET_OK; +} + +#define RETONERR(x) do { int v = x; if (GNUNET_OK != v) return v; } while (0) + +static int +checkvec (const char *operation, + json_t *vec) +{ + GNUNET_log (GNUNET_ERROR_TYPE_INFO, + "checking %s\n", operation); + + if (0 == strcmp (operation, "hash")) + { + void *data; + size_t data_len; + struct GNUNET_HashCode hash_out; + struct GNUNET_HashCode hc; + + if (GNUNET_OK != expect_data_dynamic (vec, + "input", + &data, + &data_len)) + { + GNUNET_break (0); + return GNUNET_SYSERR; + } + if (GNUNET_OK != expect_data_fixed (vec, + "output", + &hash_out, + sizeof (hash_out))) + { + GNUNET_break (0); + return GNUNET_NO; + } + + GNUNET_CRYPTO_hash (data, data_len, &hc); + + if (0 != GNUNET_memcmp (&hc, &hash_out)) + { + GNUNET_break (0); + return GNUNET_NO; + } + } + else if (0 == strcmp (operation, "ecc_ecdh")) + { + struct GNUNET_CRYPTO_EcdhePrivateKey priv1; + struct GNUNET_CRYPTO_EcdhePublicKey pub1; + struct GNUNET_CRYPTO_EcdhePrivateKey priv2; + struct GNUNET_HashCode skm; + struct GNUNET_HashCode skm_comp; + + if (GNUNET_OK != expect_data_fixed (vec, + "priv1", + &priv1, + sizeof (priv1))) + { + GNUNET_break (0); + return GNUNET_NO; + } + if (GNUNET_OK != expect_data_fixed (vec, + "priv2", + &priv2, + sizeof (priv2))) + { + GNUNET_break (0); + return GNUNET_NO; + } + if (GNUNET_OK != expect_data_fixed (vec, + "pub1", + &pub1, + sizeof (pub1))) + { + GNUNET_break (0); + return GNUNET_NO; + } + if (GNUNET_OK != expect_data_fixed (vec, + "skm", + &skm, + sizeof (skm))) + { + GNUNET_break (0); + return GNUNET_NO; + } + GNUNET_assert (GNUNET_OK == + GNUNET_CRYPTO_ecc_ecdh (&priv2, + &pub1, + &skm_comp)); + if (0 != GNUNET_memcmp (&skm, &skm_comp)) + { + GNUNET_break (0); + return GNUNET_NO; + } + } + else if (0 == strcmp (operation, "eddsa_key_derivation")) + { + struct GNUNET_CRYPTO_EddsaPrivateKey priv; + struct GNUNET_CRYPTO_EddsaPublicKey pub; + struct GNUNET_CRYPTO_EddsaPublicKey pub_comp; + + if (GNUNET_OK != expect_data_fixed (vec, + "priv", + &priv, + sizeof (priv))) + { + GNUNET_break (0); + return GNUNET_NO; + } + + if (GNUNET_OK != expect_data_fixed (vec, + "pub", + &pub, + sizeof (pub))) + { + GNUNET_break (0); + return GNUNET_NO; + } + + GNUNET_CRYPTO_eddsa_key_get_public (&priv, + &pub_comp); + if (0 != GNUNET_memcmp (&pub, &pub_comp)) + { + GNUNET_break (0); + return GNUNET_NO; + } + + } + else if (0 == strcmp (operation, "eddsa_signing")) + { + struct GNUNET_CRYPTO_EddsaPrivateKey priv; + struct GNUNET_CRYPTO_EddsaPublicKey pub; + struct TestSignatureDataPS data = { 0 }; + struct GNUNET_CRYPTO_EddsaSignature sig; + struct GNUNET_CRYPTO_EddsaSignature sig_comp; + + if (GNUNET_OK != expect_data_fixed (vec, + "priv", + &priv, + sizeof (priv))) + { + GNUNET_break (0); + return GNUNET_NO; + } + + if (GNUNET_OK != expect_data_fixed (vec, + "pub", + &pub, + sizeof (pub))) + { + GNUNET_break (0); + return GNUNET_NO; + } + + if (GNUNET_OK != expect_data_fixed (vec, + "data", + &data, + sizeof (data))) + { + GNUNET_break (0); + return GNUNET_NO; + } + + if (GNUNET_OK != expect_data_fixed (vec, + "sig", + &sig, + sizeof (sig))) + { + GNUNET_break (0); + return GNUNET_NO; + } + + GNUNET_CRYPTO_eddsa_sign (&priv, + &data, + &sig_comp); + GNUNET_assert (GNUNET_OK == + GNUNET_CRYPTO_eddsa_verify (GNUNET_SIGNATURE_PURPOSE_TEST, + &data, + &sig, + &pub)); + if (0 != GNUNET_memcmp (&sig, &sig_comp)) + { + GNUNET_break (0); + return GNUNET_NO; + } + } + else if (0 == strcmp (operation, "kdf")) + { + size_t out_len; + void *out; + size_t out_len_comp; + void *out_comp; + void *ikm; + size_t ikm_len; + void *salt; + size_t salt_len; + void *ctx; + size_t ctx_len; + + if (GNUNET_OK != expect_data_dynamic (vec, + "out", + &out, + &out_len)) + { + GNUNET_break (0); + return GNUNET_SYSERR; + } + + out_len_comp = out_len; + out_comp = GNUNET_malloc (out_len_comp); + + if (GNUNET_OK != expect_data_dynamic (vec, + "ikm", + &ikm, + &ikm_len)) + { + GNUNET_break (0); + return GNUNET_SYSERR; + } + + if (GNUNET_OK != expect_data_dynamic (vec, + "salt", + &salt, + &salt_len)) + { + GNUNET_break (0); + return GNUNET_SYSERR; + } + + if (GNUNET_OK != expect_data_dynamic (vec, + "ctx", + &ctx, + &ctx_len)) + { + GNUNET_break (0); + return GNUNET_SYSERR; + } + + GNUNET_assert (GNUNET_OK == + GNUNET_CRYPTO_kdf (out_comp, + out_len_comp, + salt, + salt_len, + ikm, + ikm_len, + ctx, + ctx_len, + NULL)); + + if (0 != memcmp (out, out_comp, out_len)) + { + GNUNET_break (0); + return GNUNET_NO; + } + + } + else if (0 == strcmp (operation, "eddsa_ecdh")) + { + struct GNUNET_CRYPTO_EcdhePrivateKey priv_ecdhe; + struct GNUNET_CRYPTO_EcdhePublicKey pub_ecdhe; + struct GNUNET_CRYPTO_EddsaPrivateKey priv_eddsa; + struct GNUNET_CRYPTO_EddsaPublicKey pub_eddsa; + struct GNUNET_HashCode key_material; + struct GNUNET_HashCode key_material_comp; + + if (GNUNET_OK != expect_data_fixed (vec, + "priv_ecdhe", + &priv_ecdhe, + sizeof (priv_ecdhe))) + { + GNUNET_break (0); + return GNUNET_NO; + } + + if (GNUNET_OK != expect_data_fixed (vec, + "pub_ecdhe", + &pub_ecdhe, + sizeof (pub_ecdhe))) + { + GNUNET_break (0); + return GNUNET_NO; + } + + if (GNUNET_OK != expect_data_fixed (vec, + "priv_eddsa", + &priv_eddsa, + sizeof (priv_eddsa))) + { + GNUNET_break (0); + return GNUNET_NO; + } + + if (GNUNET_OK != expect_data_fixed (vec, + "pub_eddsa", + &pub_eddsa, + sizeof (pub_eddsa))) + { + GNUNET_break (0); + return GNUNET_NO; + } + + if (GNUNET_OK != expect_data_fixed (vec, + "key_material", + &key_material, + sizeof (key_material))) + { + GNUNET_break (0); + return GNUNET_NO; + } + + GNUNET_CRYPTO_ecdh_eddsa (&priv_ecdhe, &pub_eddsa, &key_material_comp); + + if (0 != GNUNET_memcmp (&key_material, &key_material_comp)) + { + GNUNET_break (0); + return GNUNET_NO; + } + } + else if (0 == strcmp (operation, "rsa_blind_signing")) + { + struct GNUNET_CRYPTO_RsaPrivateKey *skey; + struct GNUNET_CRYPTO_RsaPublicKey *pkey; + struct GNUNET_HashCode message_hash; + struct GNUNET_CRYPTO_RsaBlindingKeySecret bks; + struct GNUNET_CRYPTO_RsaSignature *blinded_sig; + struct GNUNET_CRYPTO_RsaSignature *sig; + void *blinded_data; + size_t blinded_len; + void *blinded_data_comp; + size_t blinded_len_comp; + void *public_enc_data; + size_t public_enc_len; + void *secret_enc_data; + size_t secret_enc_len; + void *sig_enc_data; + size_t sig_enc_length; + void *sig_enc_data_comp; + size_t sig_enc_length_comp; + + if (GNUNET_OK != expect_data_fixed (vec, + "message_hash", + &message_hash, + sizeof (message_hash))) + { + GNUNET_break (0); + return GNUNET_SYSERR; + } + + if (GNUNET_OK != expect_data_fixed (vec, + "blinding_key_secret", + &bks, + sizeof (bks))) + { + GNUNET_break (0); + return GNUNET_SYSERR; + } + + if (GNUNET_OK != expect_data_dynamic (vec, + "blinded_message", + &blinded_data, + &blinded_len)) + { + GNUNET_break (0); + return GNUNET_SYSERR; + } + + if (GNUNET_OK != expect_data_dynamic (vec, + "rsa_public_key", + &public_enc_data, + &public_enc_len)) + { + GNUNET_break (0); + return GNUNET_SYSERR; + } + + if (GNUNET_OK != expect_data_dynamic (vec, + "rsa_private_key", + &secret_enc_data, + &secret_enc_len)) + { + GNUNET_break (0); + return GNUNET_SYSERR; + } + + if (GNUNET_OK != expect_data_dynamic (vec, + "sig", + &sig_enc_data, + &sig_enc_length)) + { + GNUNET_break (0); + return GNUNET_SYSERR; + } + + pkey = GNUNET_CRYPTO_rsa_public_key_decode (public_enc_data, + public_enc_len); + GNUNET_assert (NULL != pkey); + skey = GNUNET_CRYPTO_rsa_private_key_decode (secret_enc_data, + secret_enc_len); + GNUNET_assert (NULL != skey); + + GNUNET_assert (GNUNET_YES == + GNUNET_CRYPTO_rsa_blind (&message_hash, + &bks, + pkey, + &blinded_data_comp, + &blinded_len_comp)); + if ( (blinded_len != blinded_len_comp) || (0 != memcmp (blinded_data, + blinded_data_comp, + blinded_len)) ) + { + GNUNET_break (0); + return GNUNET_NO; + } + blinded_sig = GNUNET_CRYPTO_rsa_sign_blinded (skey, blinded_data, + blinded_len); + sig = GNUNET_CRYPTO_rsa_unblind (blinded_sig, &bks, pkey); + GNUNET_assert (GNUNET_YES == GNUNET_CRYPTO_rsa_verify (&message_hash, sig, + pkey)); + public_enc_len = GNUNET_CRYPTO_rsa_public_key_encode (pkey, + &public_enc_data); + sig_enc_length_comp = GNUNET_CRYPTO_rsa_signature_encode (sig, &sig_enc_data_comp); + + if ( (sig_enc_length != sig_enc_length_comp) || + (0 != memcmp (sig_enc_data, sig_enc_data_comp, sig_enc_length) )) + { + GNUNET_break (0); + return GNUNET_NO; + } + } + else + { + GNUNET_log (GNUNET_ERROR_TYPE_ERROR, + "unsupported operation '%s'\n", operation); + } + + return GNUNET_OK; +} + /** - * Main function that will be run. + * Check test vectors from stdin. * - * @param cls closure - * @param args remaining command-line arguments - * @param cfgfile name of the configuration file used (for saving, can be NULL!) - * @param cfg configuration + * @returns global exit code */ -static void -run (void *cls, - char *const *args, - const char *cfgfile, - const struct GNUNET_CONFIGURATION_Handle *cfg) +static int +check_vectors () +{ + json_error_t err; + json_t *vecfile = json_loadf (stdin, 0, &err); + const char *encoding; + json_t *vectors; + + if (NULL == vecfile) + { + GNUNET_log (GNUNET_ERROR_TYPE_ERROR, "unable to parse JSON\n"); + return 1; + } + encoding = json_string_value (json_object_get (vecfile, + "encoding")); + if ( (NULL == encoding) || (0 != strcmp (encoding, "base32crockford")) ) + { + GNUNET_log (GNUNET_ERROR_TYPE_ERROR, "unsupported or missing encoding\n"); + json_decref (vecfile); + return 1; + } + vectors = json_object_get (vecfile, "vectors"); + if (!json_is_array (vectors)) + { + GNUNET_log (GNUNET_ERROR_TYPE_ERROR, "bad vectors\n"); + json_decref (vecfile); + return 1; + } + { + /* array is a JSON array */ + size_t index; + json_t *value; + int ret; + + json_array_foreach (vectors, index, value) { + const char *op = json_string_value (json_object_get (value, + "operation")); + + if (NULL == op) + { + GNUNET_log (GNUNET_ERROR_TYPE_ERROR, + "missing operation\n"); + ret = GNUNET_SYSERR; + break; + } + ret = checkvec (op, value); + if (GNUNET_OK != ret) + { + GNUNET_log (GNUNET_ERROR_TYPE_ERROR, + "bad vector %u\n", + (unsigned int) index); + break; + } + } + return (ret == GNUNET_OK) ? 0 : 1; + } +} + +/** + * Output test vectors. + * + * @returns global exit code + */ +static int +output_vectors () { json_t *vecfile = json_object (); json_t *vecs = json_array (); @@ -169,7 +717,7 @@ run (void *cls, d2j (vec, "output", &hc, sizeof (struct GNUNET_HashCode)); } { - json_t *vec = vec_for (vecs, "ecdhe_key_derivation"); + json_t *vec = vec_for (vecs, "ecc_ecdh"); struct GNUNET_CRYPTO_EcdhePrivateKey priv1; struct GNUNET_CRYPTO_EcdhePublicKey pub1; struct GNUNET_CRYPTO_EcdhePrivateKey priv2; @@ -342,6 +890,8 @@ run (void *cls, size_t blinded_len; void *public_enc_data; size_t public_enc_len; + void *secret_enc_data; + size_t secret_enc_len; void *blinded_sig_enc_data; size_t blinded_sig_enc_length; void *sig_enc_data; @@ -369,6 +919,8 @@ run (void *cls, pkey)); public_enc_len = GNUNET_CRYPTO_rsa_public_key_encode (pkey, &public_enc_data); + secret_enc_len = GNUNET_CRYPTO_rsa_private_key_encode (skey, + &secret_enc_data); blinded_sig_enc_length = GNUNET_CRYPTO_rsa_signature_encode (blinded_sig, & blinded_sig_enc_data); @@ -381,6 +933,10 @@ run (void *cls, "rsa_public_key", public_enc_data, public_enc_len); + d2j (vec, + "rsa_private_key", + secret_enc_data, + secret_enc_len); d2j (vec, "blinding_key_secret", &bks, @@ -410,6 +966,28 @@ run (void *cls, json_dumpf (vecfile, stdout, JSON_INDENT (2)); json_decref (vecfile); printf ("\n"); + + return 0; +} + +/** + * Main function that will be run. + * + * @param cls closure + * @param args remaining command-line arguments + * @param cfgfile name of the configuration file used (for saving, can be NULL!) + * @param cfg configuration + */ +static void +run (void *cls, + char *const *args, + const char *cfgfile, + const struct GNUNET_CONFIGURATION_Handle *cfg) +{ + if (GNUNET_YES == verify_flag) + global_ret = check_vectors (); + else + global_ret = output_vectors (); } @@ -425,6 +1003,11 @@ main (int argc, char *const *argv) { const struct GNUNET_GETOPT_CommandLineOption options[] = { + GNUNET_GETOPT_option_flag ('V', + "verify", + gettext_noop ( + "verify a test vector from stdin"), + &verify_flag), GNUNET_GETOPT_OPTION_END }; @@ -439,7 +1022,7 @@ main (int argc, options, &run, NULL)) return 1; - return 0; + return global_ret; } -- cgit v1.2.3 From 2f03e8b0c3599cb720f0ca36f5fae06523967c72 Mon Sep 17 00:00:00 2001 From: Florian Dold Date: Fri, 4 Dec 2020 17:33:27 +0100 Subject: add test vector unit test --- src/util/Makefile.am | 5 +++- src/util/crypto-test-vectors.json | 56 +++++++++++++++++++++++++++++++++++++++ src/util/test_crypto_vectors.sh | 3 +++ 3 files changed, 63 insertions(+), 1 deletion(-) create mode 100644 src/util/crypto-test-vectors.json create mode 100755 src/util/test_crypto_vectors.sh (limited to 'src') diff --git a/src/util/Makefile.am b/src/util/Makefile.am index 1949dceb0..d2e4b4d1a 100644 --- a/src/util/Makefile.am +++ b/src/util/Makefile.am @@ -169,7 +169,7 @@ noinst_PROGRAMS = \ if ENABLE_TEST_RUN AM_TESTS_ENVIRONMENT=export GNUNET_PREFIX=$${GNUNET_PREFIX:-@libdir@};export PATH=$${GNUNET_PREFIX:-@prefix@}/bin:$$PATH;unset XDG_DATA_HOME;unset XDG_CONFIG_HOME; -TESTS = $(check_PROGRAMS) +TESTS = $(check_PROGRAMS) $(check_SCRIPTS) endif gnunet_timeout_SOURCES = \ @@ -255,6 +255,9 @@ if HAVE_SSH_KEY # SSH_USING_TESTS = test_socks.nc endif +check_SCRIPTS = \ + test_crypto_vectors.sh + check_PROGRAMS = \ test_bio \ test_client.nc \ diff --git a/src/util/crypto-test-vectors.json b/src/util/crypto-test-vectors.json new file mode 100644 index 000000000..972b62c3e --- /dev/null +++ b/src/util/crypto-test-vectors.json @@ -0,0 +1,56 @@ +{ + "encoding": "base32crockford", + "producer": "GNUnet 0.14.0 git-64ad3b0a1", + "vectors": [ + { + "operation": "hash", + "input": "91JPRV3F5GG4EKJNDSJQ8", + "output": "D0R24RZ1TPASVQ2NY56CT8AJDYZE9ZGDB0GVZ05E9D4YGZQW2RC5YFPQ0Q86EPW836DY7VYQTNFFJT3ZR2K508F4JVS5JNJKYN2MMFR" + }, + { + "operation": "ecc_ecdh", + "priv1": "TFA439C75RT2JK9V6GTRRXH3QR3QC4SVJ1KBQ4MNY3S338GT6T50", + "pub1": "E19WJDA83485BC8EC8RV7FTAK86BESJG1YNYRENEC0JV7XEZ7M80", + "priv2": "2DT3B0TMY6VVP56YZKG5ASRSQAEV0GB4QMT9N6CTPDARNJ905APG", + "skm": "GY63DCHR6BGV2AKDM44V7A4H4DA0WJC7D5C2R7DXTWC9D83H7XM0PEQKKZ1K2HWMWBSBNPDWXDN7PA1R1WJKVQ2RDTNF1PBXCFHM9QR" + }, + { + "operation": "eddsa_key_derivation", + "priv": "8QC2VNF8443S5KPNKMB4XMV58BTHWAKZ7SVW5WG3KRB37567XS90", + "pub": "3M9KK1WSNM1RTY5P72HKFA264V4B7MVHVJ08Y90CV06DYHV8XPP0" + }, + { + "operation": "eddsa_signing", + "priv": "5077XJR9AMH4T97ACKFBVBJD0KFENHPV66B2Y1JBSKXBJKNZJ4E0", + "pub": "6E2F03JJ8AEDANTTZZ4SBZDFEEZSF8A9DVGTS6VFBCVZQYQ46RRG", + "data": "00000300000000000000", + "sig": "XCNJGJ96WPDH60YVMH6C74NGQSGJE3BC1TYMGX6BHY5DMZZZKTB373QTXJ507K5EBSG9YS2EYKHCX3ATRQ6P5MY9MXC4ZB1XSZ2X23G" + }, + { + "operation": "kdf", + "salt": "94KPT83PCNS7J83KC5P78Y8", + "ikm": "94KPT83MD1JJ0WV5CDS6AX10D5Q70XBM41NPAY90DNGQ8SBJD5GPR", + "ctx": "94KPT83141HPYVKMCNW78833D1TPWTSC41GPRWVF41NPWVVQDRG62WS04XMPWSKF4WG6JVH0EHM6A82J8S1G", + "out_len %u\n": 64, + "out": "GTMR4QT05Z9WF5HKVG0WK9RPXGHSMHJNW377G9GJXCA8B0FEKPF4D27RJMSJZYWSQNTBJ5EYVV7ZW18B48Z0JVJJ80RHB706Y96Q358" + }, + { + "operation": "eddsa_ecdh", + "priv_ecdhe": "5FBRFZY942H2PD96NFNYWZKYXCRFY11JWQ59V7G9B4M8EX1KE100", + "pub_ecdhe": "GDX7FC01AZYMG0BY0AMHR6E7KCGX9F6SWES16WZ1QWZ2VSYXKH00", + "priv_eddsa": "3HYHM9DZQ3D61APDQNBCSKJE452YEP6JK01DWR1J3VZAASFEA570", + "pub_eddsa": "87N7PFAHBX97HRE8XYW8KYN64YZDF4FCBR2BZ5SZN3QE3D2BF0R0", + "key_material": "QH0RAXXC9RYDEAXKNTAWM0WXJS25RS67H5T252EGA22RA6JTYRFDAEK8CJY85QSYWGYHQXK5Y1SWSRB3P0NXNXYP237EXMXQ3P2WE00" + }, + { + "operation": "rsa_blind_signing", + "message_hash": "XKQMJ4CNTXBFE1V2WR6JS063J7PZQE4XMB5JH3RS5X0THQ1JQSQ69Y7KDBC9TYRJEZH48MEPY2SF4QHQ4VHXC0YQX5935MQEGP0AX6R", + "rsa_public_key": "040000YRN1NVJ68RS6RJF52PGRCQG19ZKWQPSTJX2G7ZDCKSZFE2VW3HHA81YF5C639JHJF5TX8YTEE2FW2WQCG1PTKNBSPPJEJGA032CN3E8QZ27VWY0K6JFT8ZSYWRH2SKDMXW56A4QKY46JJBWJ6T0ZRVBW6S1HTHXVE2RW8MXRW5T801077MDY13N5F8Z1JZVKBJ06TK3S0YPEDBXK0VEHRHEQJ5X5XYKR4KQTFAZNBMKXY8836VCHBXTK4YNX6AJ1CK29SMJH3Z3QRM16A2TNQGFR0HSMV446BF7FMT2E379ZAT5ST4G3BM2NWZYW545S2SW5MG5S6M88XZZ7SKFD48YVXNZ205GGSEYJPVBMR76WG4ZG30WBCPC1N54XE12RMAG81D8C09WG22PKGGDHYXX68N04002", + "rsa_private_key": "50W3MTV5F4PP8RBMC4520A1H60X70XB2DHMP6BBBCNWGM81050SKMWKKC452081050RKMVHJ6MVKM06RN1NVJ68RS6RJF52PGRCQG19ZKWQPSTJX2G7ZDCKSZFE2VW3HHA81YF5C639JHJF5TX8YTEE2FW2WQCG1PTKNBSPPJEJGA032CN3E8QZ27VWY0K6JFT8ZSYWRH2SKDMXW56A4QKY46JJBWJ6T0ZRVBW6S1HTHXVE2RW8MXRW5T801077MDY13N5F8Z1JZVKBJ06TK3S0YPEDBXK0VEHRHEQJ5X5XYKR4KQTFAZNBMKXY8836VCHBXTK4YNX6AJ1CK29SMJH3Z3QRM16A2TNQGFR0HSMV446BF7FMT2E379ZAT5ST4G3BM2NWZYW545S2SW5MG5S6M88XZZ7SKFD48YVXNZ205GGSEYJPVBMR76WG4ZG30WBCPC1N54XE12RMAG81D8C09WG22PKGGDHYXX68N5452081050RKMS9K780G009918G2081918G20A8A40M32C9TE1S6JXK1EHJJTTV5F45208186CX74WV118G2081864X6WCHN6WX01P58DEWHJ669P4KS8NM635W0AFWZ5XPEMQ8M1ZVB4YFVVGPZ0WCAJ0FKSB1GTCMCKSEQA7PKKGKZ0Q5V40DPMXAYDNMKMM2G0RK58VJ5ZRHYZ7G4SMKYJ7YFQ648PCVD7F19JH5WZH1MMJZ4HPG7Y6TZ1P8CEMFEVGP7257E71EJ0081SX3FG8X9BT7RCQYWTWG1PMRY87NKKAZCR6VME4BNWHF9FFMY14XYKTQXAX4ZFJ20SPV4AZEMS7NF9JMGB4RJED4M8ZRXY509JGPNDW3Y04ED6S11JVSVX6GKGSTFTPHEEH40TX0NF7ZQ191E8PF1D41E9N227FZSYCVV927PZDFRG1C46BQMNPTX61SQ417W0R72V5K0D997BG8P52M20BA302F40GNMW43CFQF9J59918G2081864X6ACST04002A8A40G20A1H79J34D9P78SBPDS45EQZVX2D6R1GZ6FHKHDG4ABYZ6FCPSMMGZ29ZY5NS8B304D0QBD800A5SM3D8S92WKS3KFWFXE8X597TNJBR94BGNCFHY8TV63KQZ0RFMRTPHFA2XNFX2V4KECZNTHGKZNJTWH8051XP6FJJ6700A5KWMH24CK1KF9XVH2ATQJ4F1ZJZQM00A00ESTVKM5N58K5FN5TW34B1H1Q1CWRZXJ9QMBG0QKHXHZMFYZSN9ERV59935716NGSX9GBB3R9BY32TBTAJ7K0N391ATSE5263X5NKVDH7XCF1PF0WRTTJYBAJBQWVGJ8P7RGVWB27Q3S4AJJ55FS2T9K341EHATHJZQQTR0JWP5E4NQHR4GN60QMK2SY0VJM56N0NHJXRGAGJW3S9ABJ7M4TAV6YRJJ2H040G2GC9TE0RK4E9T03CET00DAJDXJ1NF511J69JMDDSVARPSFSS6AJTRMVXD10NVA4Z162ER74WNH0J6H2RTA9C9MZM4TEBP8P7AF0NANBH4XZJCNDZV7BEAMJ6R363GHZKGBR0HH1SATGWNJWGW2961MRFPX7S0RJK7CWYE7EX1XQ2683TENRPDKV29D1F1RNDD6P04MZTKSH5YMEZPKGEDRJZXXM9918G2081864X72C9J74X01ZXF256C681JDWRRG7T4AC9JRHP54YM65X9AT17YGC3G4569ZKBQEZ219Y7JG4V10F4AW7Q1XKGPTW3Y3X0WCTB06HM249Q094VHEYD4BTEQ2DF334W8G3VEB7N1CHCMPZEVVTR0XWQSNV6MBJRF5MBY6Z148YA36YA61EXA28PHE3KSN1M4HVF7B06JD736TSK9GC9CAG8F0MMGM81040M32EKN64S3JEG0YCC3PHPNBZAGQ2WE8HJHM28B049N2MQ94G8VPXNHG43C6ADB44DE1DK8ASMYTSXZWMAYKN1SS2GVFTVH8Q4N3TTJ3BKA61Y93QE17XNRF3S0CSSQTY3SVVAFHDA9APFFSMRYD67N4DXQ1X42NA270VF6H0MCRQ87JKVBQAB0CH2WH7RHYMCQ4KN50M2NEFE1YA6F2N2DG7Z9JA8A40G20A8A40G2J2H054500", + "blinding_key_secret": "3SWF49XZPHQMENTSBZQR7Z0B8ZSZ2JRARE79Q4VXZMQ7W6QABXMG", + "blinded_message": "3KHKZJZ30ABB4E56MA2V0EQWGCWH0QQG9P2ZHYHR186C5HZXJMM4N9WXAQTKS94QSV9Y17GGNXN5MB1PZZFG7Q0FY88QPKKRG4MYCPSMTZK5W59R0MJVNJ4P4AQM96TDG5W7RV8GSNR1QQZ1GNHW3CX6D6ZRTMXB2NKB5SSYTDJS79F5ZFBRZ4HVED9JBBPWSR79KVV5QQ4APBGHBCKGMF9NJJS53A1BVYHDEVYAGFYF2SNEP827ZP50FKJ5GKGV8NQ15ESEZ69AT7GJG0T3TZVENY2YN9CVR98W3BKEZ53J7VTANARG8SJS8AMJQ7S23P5HRJ7XE9KTNRNXKH49MXV9JHHYE5535N7AGWEKR47SBCGNF44Z7XJ9RV5BQV12ZRJKN4HBZQHDNCMH3QKX9Z6G64", + "blinded_sig": "ND1V807BK0G73SDXN582BP3Q21MWF4A76EGWD0KA3XGJAWPSVHNHKA44931ZRB9M76SYAFD8ZPTG3A7FH5G2CWGX76VXTCDX5XNRW7EEBNMPDAQ0ZEKF6AHP872SKCGRH89SK4NGC57M8BRA3ZRPDDT9XCBG3XY02VQH4Z0F39DPBS48K0EBMK7B9S3X6QDNR5ND5MV0G7G7T3VPKZRW94MQBKPY1T6K53MQGG4PV81D9YEWNRM3WE04NNQREYDA5ETVDWQ5ZCYV9HF4ZCMWVVGWDBDH732JA3NKZ2B8QK0E6XS0Y4GGGQJS6HFQ4PATGK3TS5GHJEPDF3A6XAFNJQV99CSJW7V1NC504NTQ5NJ8KAVC1758MBBV3SS2BND4YHF0Y4NWJNVH3STV166YWFKR8W", + "sig": "EC5MVSPGQMM96N2VT4R2G5104E61V8RY4PR6AK9F614TVVEN7D152T0DP97CDTRDDSQGBV4GZWXQPM90SW30R2RAKKHNDCXHQFAMRSW1XCBEKVKBGC6FP0AQY9S37NVR01VJ2WVX8PN29H2ZFFQBQ9JK96GTJZ3B7DD583S8Y93GH5KWEM41CZJ73QCRT1A2AGVXX5ACFR0T448MC81QB4EGCKP5Z96VCX6RPDD5S9A4295M0E9PPQJCN5G5JKWKG17HWEDF4A26ZMD8YW27EQBZ69GSEZX4PWEV7AXFGG5X0RPKCQEPCX7XDY6NXJ1E2FZBX259RDRCFNDAZS80T0DHD9NVE73QDDESZYEZTM1TM669GHPN8AF4QV8DNW7SFZZKJ67FWR8CZC0PWTEN4ZPTRM" + } + ] +} diff --git a/src/util/test_crypto_vectors.sh b/src/util/test_crypto_vectors.sh new file mode 100755 index 000000000..40700a324 --- /dev/null +++ b/src/util/test_crypto_vectors.sh @@ -0,0 +1,3 @@ +#!/usr/bin/env bash + +cat ./crypto-test-vectors.json | ./gnunet-crypto-tvg --verify -- cgit v1.2.3 From 1346641a163ed02540b6931fd4ad31ba6af4d64d Mon Sep 17 00:00:00 2001 From: Florian Dold Date: Fri, 4 Dec 2020 17:36:35 +0100 Subject: gnunet-crypto-tvg: fix bogus label --- src/util/gnunet-crypto-tvg.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'src') diff --git a/src/util/gnunet-crypto-tvg.c b/src/util/gnunet-crypto-tvg.c index 5915b4b44..1e9cc3174 100644 --- a/src/util/gnunet-crypto-tvg.c +++ b/src/util/gnunet-crypto-tvg.c @@ -839,7 +839,7 @@ output_vectors () ctx, strlen (ctx)); uint2j (vec, - "out_len %u\n", + "out_len", (unsigned int) out_len); d2j (vec, "out", -- cgit v1.2.3 From 2c5857012467c1420270545472be72d8fa9a5563 Mon Sep 17 00:00:00 2001 From: Florian Dold Date: Fri, 4 Dec 2020 17:51:15 +0100 Subject: -remove unused macro / add comment --- src/util/gnunet-crypto-tvg.c | 9 ++++++++- 1 file changed, 8 insertions(+), 1 deletion(-) (limited to 'src') diff --git a/src/util/gnunet-crypto-tvg.c b/src/util/gnunet-crypto-tvg.c index 1e9cc3174..8949f427c 100644 --- a/src/util/gnunet-crypto-tvg.c +++ b/src/util/gnunet-crypto-tvg.c @@ -188,8 +188,15 @@ expect_data_dynamic (json_t *vec, return GNUNET_OK; } -#define RETONERR(x) do { int v = x; if (GNUNET_OK != v) return v; } while (0) +/** + * Check a single vector. + * + * @param operation operator of the vector + * @param vec the vector, a JSON object. + * + * @returns GNUNET_OK if the vector is okay + */ static int checkvec (const char *operation, json_t *vec) -- cgit v1.2.3 From 4dce2caf4a001bdc03d117474b45fe8712e33a96 Mon Sep 17 00:00:00 2001 From: Christian Grothoff Date: Sat, 5 Dec 2020 10:46:04 +0100 Subject: -fix indentation --- src/util/crypto_rsa.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) (limited to 'src') diff --git a/src/util/crypto_rsa.c b/src/util/crypto_rsa.c index d5eca6225..fec4d13db 100644 --- a/src/util/crypto_rsa.c +++ b/src/util/crypto_rsa.c @@ -262,8 +262,8 @@ GNUNET_CRYPTO_rsa_private_key_decode (const void *buf, * @return NULL on error, otherwise the public key */ struct GNUNET_CRYPTO_RsaPublicKey * -GNUNET_CRYPTO_rsa_private_key_get_public (const struct - GNUNET_CRYPTO_RsaPrivateKey *priv) +GNUNET_CRYPTO_rsa_private_key_get_public ( + const struct GNUNET_CRYPTO_RsaPrivateKey *priv) { struct GNUNET_CRYPTO_RsaPublicKey *pub; gcry_mpi_t ne[2]; -- cgit v1.2.3 From 61f7bf618b336c4d9349067ececdd7e5f051d67c Mon Sep 17 00:00:00 2001 From: Julius Bünger Date: Mon, 7 Dec 2020 17:00:09 +0100 Subject: -rps: make format strings more portable --- src/rps/rps-test_util.c | 14 +++++++------- 1 file changed, 7 insertions(+), 7 deletions(-) (limited to 'src') diff --git a/src/rps/rps-test_util.c b/src/rps/rps-test_util.c index b73be3457..497225973 100644 --- a/src/rps/rps-test_util.c +++ b/src/rps/rps-test_util.c @@ -186,9 +186,9 @@ to_file_raw (const char *file_name, const char *buf, size_t size_buf) if (size_buf != size_written) { LOG (GNUNET_ERROR_TYPE_WARNING, - "Unable to write to file! (Size: %zu, size_written: %zu)\n", - size_buf, - size_written); + "Unable to write to file! (Size: %llu, size_written: %llu)\n", + (unsigned long long) size_buf, + (unsigned long long) size_written); if (GNUNET_YES != GNUNET_DISK_file_close (f)) LOG (GNUNET_ERROR_TYPE_WARNING, @@ -197,8 +197,8 @@ to_file_raw (const char *file_name, const char *buf, size_t size_buf) return; } LOG (GNUNET_ERROR_TYPE_WARNING, - "Wrote %zu bytes raw.\n", - size_written); + "Wrote %llu bytes raw.\n", + (unsigned long long) size_written); if (GNUNET_YES != GNUNET_DISK_file_close (f)) LOG (GNUNET_ERROR_TYPE_WARNING, "Unable to close file\n"); @@ -238,8 +238,8 @@ to_file_raw_unaligned (const char *file_name, "num_bits_buf_unaligned: %u\n", num_bits_buf_unaligned); LOG (GNUNET_ERROR_TYPE_DEBUG, - "ua args: size_buf: %zu, bits_needed: %u -> iter: %u\n", - size_buf, + "ua args: size_buf: %llu, bits_needed: %u -> iter: %u\n", + (unsigned long long) size_buf, bits_needed, bytes_iter); buf_write[0] = buf_unaligned; -- cgit v1.2.3 From 7ce054864a112f459a75ab542f844a8be0e6c47c Mon Sep 17 00:00:00 2001 From: Martin Schanzenbach Date: Tue, 8 Dec 2020 16:50:27 +0900 Subject: RECLAIM: Return userinfo claims from cache --- src/reclaim/oidc_helper.c | 78 ++++++++++------ src/reclaim/oidc_helper.h | 38 ++++++-- src/reclaim/plugin_rest_openid_connect.c | 151 +++++++++++++++++++++++++++++-- 3 files changed, 217 insertions(+), 50 deletions(-) (limited to 'src') diff --git a/src/reclaim/oidc_helper.c b/src/reclaim/oidc_helper.c index c6d56e02d..1dde7b673 100644 --- a/src/reclaim/oidc_helper.c +++ b/src/reclaim/oidc_helper.c @@ -567,6 +567,48 @@ OIDC_build_authz_code (const struct GNUNET_IDENTITY_PrivateKey *issuer, } +enum GNUNET_GenericReturnValue +check_code_challenge (const char *code_challenge, + uint32_t code_challenge_len, + const char *code_verifier) +{ + char *code_verifier_hash; + char *expected_code_challenge; + + if (0 == code_challenge_len) /* Only check if this code requires a CV */ + return GNUNET_OK; + if (NULL == code_verifier) + { + GNUNET_log (GNUNET_ERROR_TYPE_ERROR, + "Expected code verifier!\n"); + return GNUNET_SYSERR; + } + code_verifier_hash = GNUNET_malloc (256 / 8); + // hash code verifier + gcry_md_hash_buffer (GCRY_MD_SHA256, + code_verifier_hash, + code_verifier, + strlen (code_verifier)); + // encode code verifier + GNUNET_STRINGS_base64url_encode (code_verifier_hash, 256 / 8, + &expected_code_challenge); + GNUNET_free (code_verifier_hash); + if (0 != + strncmp (expected_code_challenge, code_challenge, code_challenge_len)) + { + GNUNET_log (GNUNET_ERROR_TYPE_ERROR, + "Invalid code verifier! Expected: %s, Got: %.*s\n", + expected_code_challenge, + code_challenge_len, + code_challenge); + GNUNET_free (expected_code_challenge); + return GNUNET_SYSERR; + } + GNUNET_free (expected_code_challenge); + return GNUNET_OK; +} + + /** * Parse reclaim ticket and nonce from * authorization code. @@ -589,16 +631,15 @@ OIDC_parse_authz_code (const struct GNUNET_IDENTITY_PublicKey *audience, struct GNUNET_RECLAIM_Ticket *ticket, struct GNUNET_RECLAIM_AttributeList **attrs, struct GNUNET_RECLAIM_PresentationList **presentations, - char **nonce_str) + char **nonce_str, + enum OIDC_VerificationOptions opts) { char *code_payload; char *ptr; char *plaintext; char *attrs_ser; char *presentations_ser; - char *expected_code_challenge; char *code_challenge; - char *code_verifier_hash; struct GNUNET_CRYPTO_EccSignaturePurpose *purpose; struct GNUNET_IDENTITY_Signature *signature; uint32_t code_challenge_len; @@ -636,38 +677,15 @@ OIDC_parse_authz_code (const struct GNUNET_IDENTITY_PublicKey *audience, // cmp code_challenge code_verifier code_challenge_len = ntohl (params->code_challenge_len); code_challenge = ((char *) ¶ms[1]); - if (0 != code_challenge_len) /* Only check if this code requires a CV */ + if (!(opts & OIDC_VERIFICATION_NO_CODE_VERIFIER)) { - if (NULL == code_verifier) - { - GNUNET_log (GNUNET_ERROR_TYPE_ERROR, - "Expected code verifier!\n"); - GNUNET_free (code_payload); - return GNUNET_SYSERR; - } - code_verifier_hash = GNUNET_malloc (256 / 8); - // hash code verifier - gcry_md_hash_buffer (GCRY_MD_SHA256, - code_verifier_hash, - code_verifier, - strlen (code_verifier)); - // encode code verifier - GNUNET_STRINGS_base64url_encode (code_verifier_hash, 256 / 8, - &expected_code_challenge); - GNUNET_free (code_verifier_hash); - if (0 != - strncmp (expected_code_challenge, code_challenge, code_challenge_len)) + if (GNUNET_OK != check_code_challenge (code_challenge, + code_challenge_len, + code_verifier)) { - GNUNET_log (GNUNET_ERROR_TYPE_ERROR, - "Invalid code verifier! Expected: %s, Got: %.*s\n", - expected_code_challenge, - code_challenge_len, - code_challenge); GNUNET_free (code_payload); - GNUNET_free (expected_code_challenge); return GNUNET_SYSERR; } - GNUNET_free (expected_code_challenge); } nonce_len = ntohl (params->nonce_len); if (0 != nonce_len) diff --git a/src/reclaim/oidc_helper.h b/src/reclaim/oidc_helper.h index eb1022423..2a8b7bbae 100644 --- a/src/reclaim/oidc_helper.h +++ b/src/reclaim/oidc_helper.h @@ -38,6 +38,19 @@ #define SERVER_ADDRESS "https://api.reclaim" +enum OIDC_VerificationOptions +{ + /** + * Strict verification + */ + OIDC_VERIFICATION_DEFAULT = 0, + + /** + * Do not check code verifier even if expected + */ + OIDC_VERIFICATION_NO_CODE_VERIFIER = 1 +}; + /** * Create a JWT from attributes * @@ -51,12 +64,13 @@ */ char* OIDC_generate_id_token (const struct GNUNET_IDENTITY_PublicKey *aud_key, - const struct GNUNET_IDENTITY_PublicKey *sub_key, - const struct GNUNET_RECLAIM_AttributeList *attrs, - const struct GNUNET_RECLAIM_PresentationList *presentations, - const struct GNUNET_TIME_Relative *expiration_time, - const char *nonce, - const char *secret_key); + const struct GNUNET_IDENTITY_PublicKey *sub_key, + const struct GNUNET_RECLAIM_AttributeList *attrs, + const struct + GNUNET_RECLAIM_PresentationList *presentations, + const struct GNUNET_TIME_Relative *expiration_time, + const char *nonce, + const char *secret_key); /** * Builds an OIDC authorization code including @@ -68,13 +82,15 @@ OIDC_generate_id_token (const struct GNUNET_IDENTITY_PublicKey *aud_key, * @param presentations credential presentation list * @param nonce the nonce to include in the code * @param code_challenge PKCE code challenge + * @param opts verification options * @return a new authorization code (caller must free) */ char* OIDC_build_authz_code (const struct GNUNET_IDENTITY_PrivateKey *issuer, const struct GNUNET_RECLAIM_Ticket *ticket, const struct GNUNET_RECLAIM_AttributeList *attrs, - const struct GNUNET_RECLAIM_PresentationList *presentations, + const struct + GNUNET_RECLAIM_PresentationList *presentations, const char *nonce, const char *code_challenge); @@ -99,7 +115,8 @@ OIDC_parse_authz_code (const struct GNUNET_IDENTITY_PublicKey *ecdsa_pub, struct GNUNET_RECLAIM_Ticket *ticket, struct GNUNET_RECLAIM_AttributeList **attrs, struct GNUNET_RECLAIM_PresentationList **presentations, - char **nonce); + char **nonce, + enum OIDC_VerificationOptions opts); /** * Build a token response for a token request @@ -126,7 +143,7 @@ OIDC_access_token_new (const struct GNUNET_RECLAIM_Ticket *ticket); * Parse an access token */ int -OIDC_access_token_parse (const char* token, +OIDC_access_token_parse (const char*token, struct GNUNET_RECLAIM_Ticket **ticket); @@ -154,6 +171,7 @@ OIDC_check_scopes_for_claim_request (const char *scopes, char * OIDC_generate_userinfo (const struct GNUNET_IDENTITY_PublicKey *sub_key, const struct GNUNET_RECLAIM_AttributeList *attrs, - const struct GNUNET_RECLAIM_PresentationList *presentations); + const struct + GNUNET_RECLAIM_PresentationList *presentations); #endif diff --git a/src/reclaim/plugin_rest_openid_connect.c b/src/reclaim/plugin_rest_openid_connect.c index 7a8a886bd..8d21a5c99 100644 --- a/src/reclaim/plugin_rest_openid_connect.c +++ b/src/reclaim/plugin_rest_openid_connect.c @@ -227,6 +227,11 @@ */ #define OIDC_ERROR_KEY_ACCESS_DENIED "access_denied" +/** + * How long to wait for a consume in userinfo endpoint + */ +#define CONSUME_TIMEOUT GNUNET_TIME_relative_multiply ( \ + GNUNET_TIME_UNIT_SECONDS,2) /** * OIDC ignored parameter array @@ -240,7 +245,12 @@ static char *OIDC_ignored_parameter_array[] = { "display", "acr_values" }; /** - * OIDC Hash map that keeps track of issued cookies + * OIDC hashmap for cached access tokens and codes + */ +struct GNUNET_CONTAINER_MultiHashMap *oidc_code_cache; + +/** + * OIDC hashmap that keeps track of issued cookies */ struct GNUNET_CONTAINER_MultiHashMap *OIDC_cookie_jar_map; @@ -459,6 +469,11 @@ struct RequestHandle */ struct GNUNET_RECLAIM_Operation *idp_op; + /** + * Timeout task for consume + */ + struct GNUNET_SCHEDULER_Task *consume_timeout_op; + /** * Attribute iterator */ @@ -505,6 +520,11 @@ struct RequestHandle */ char *url; + /** + * The passed access token + */ + char *access_token; + /** * The tld for redirect */ @@ -571,6 +591,8 @@ cleanup_handle (struct RequestHandle *handle) GNUNET_RECLAIM_ticket_iteration_stop (handle->ticket_it); if (NULL != handle->idp_op) GNUNET_RECLAIM_cancel (handle->idp_op); + if (NULL != handle->consume_timeout_op) + GNUNET_SCHEDULER_cancel (handle->consume_timeout_op); GNUNET_free (handle->url); GNUNET_free (handle->tld); GNUNET_free (handle->redirect_prefix); @@ -601,6 +623,8 @@ cleanup_handle (struct RequestHandle *handle) GNUNET_CONTAINER_DLL_remove (requests_head, requests_tail, handle); + if (NULL != handle->access_token) + GNUNET_free (handle->access_token); GNUNET_free (handle); } @@ -1282,8 +1306,8 @@ code_redirect (void *cls) { if (GNUNET_OK != GNUNET_IDENTITY_public_key_from_string (handle->oidc - ->login_identity, - &pubkey)) + ->login_identity, + &pubkey)) { handle->emsg = GNUNET_strdup (OIDC_ERROR_KEY_INVALID_COOKIE); handle->edesc = @@ -1662,7 +1686,7 @@ authorize_endpoint (struct GNUNET_REST_RequestHandle *con_handle, if (GNUNET_OK != GNUNET_IDENTITY_public_key_from_string (handle->oidc->client_id, - &handle->oidc->client_pkey)) + &handle->oidc->client_pkey)) { handle->emsg = GNUNET_strdup (OIDC_ERROR_KEY_UNAUTHORIZED_CLIENT); handle->edesc = GNUNET_strdup ("The client is not authorized to request an " @@ -2071,7 +2095,8 @@ token_endpoint (struct GNUNET_REST_RequestHandle *con_handle, // decode code if (GNUNET_OK != OIDC_parse_authz_code (&cid, code, code_verifier, &ticket, - &cl, &pl, &nonce)) + &cl, &pl, &nonce, + OIDC_VERIFICATION_DEFAULT)) { handle->emsg = GNUNET_strdup (OIDC_ERROR_KEY_INVALID_REQUEST); handle->edesc = GNUNET_strdup ("invalid code"); @@ -2080,7 +2105,6 @@ token_endpoint (struct GNUNET_REST_RequestHandle *con_handle, GNUNET_SCHEDULER_add_now (&do_error, handle); return; } - GNUNET_free (code); // create jwt if (GNUNET_OK != GNUNET_CONFIGURATION_get_value_time (cfg, @@ -2091,6 +2115,7 @@ token_endpoint (struct GNUNET_REST_RequestHandle *con_handle, handle->emsg = GNUNET_strdup (OIDC_ERROR_KEY_SERVER_ERROR); handle->edesc = GNUNET_strdup ("gnunet configuration failed"); handle->response_code = MHD_HTTP_INTERNAL_SERVER_ERROR; + GNUNET_free (code); GNUNET_SCHEDULER_add_now (&do_error, handle); return; } @@ -2105,6 +2130,7 @@ token_endpoint (struct GNUNET_REST_RequestHandle *con_handle, handle->emsg = GNUNET_strdup (OIDC_ERROR_KEY_INVALID_REQUEST); handle->edesc = GNUNET_strdup ("No signing secret configured!"); handle->response_code = MHD_HTTP_INTERNAL_SERVER_ERROR; + GNUNET_free (code); GNUNET_SCHEDULER_add_now (&do_error, handle); return; } @@ -2116,6 +2142,26 @@ token_endpoint (struct GNUNET_REST_RequestHandle *con_handle, (NULL != nonce) ? nonce : NULL, jwt_secret); access_token = OIDC_access_token_new (&ticket); + /* Store mapping from access token to code so we can later + * fall back on the provided attributes in userinfo + */ + GNUNET_CRYPTO_hash (access_token, + strlen (access_token), + &cache_key); + char *tmp_at = GNUNET_CONTAINER_multihashmap_get (oidc_code_cache, + &cache_key); + GNUNET_CONTAINER_multihashmap_put (oidc_code_cache, + &cache_key, + code, + GNUNET_CONTAINER_MULTIHASHMAPOPTION_REPLACE); + /* If there was a previus code in there, free the old value */ + if (NULL != tmp_at) + { + GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, + "OIDC access token already issued. Cleanup.\n"); + GNUNET_free (tmp_at); + } + OIDC_build_token_response (access_token, id_token, &expiration_time, @@ -2149,6 +2195,10 @@ consume_ticket (void *cls, struct GNUNET_RECLAIM_PresentationListEntry *atle; struct MHD_Response *resp; char *result_str; + + if (NULL != handle->consume_timeout_op) + GNUNET_SCHEDULER_cancel (handle->consume_timeout_op); + handle->consume_timeout_op = NULL; handle->idp_op = NULL; if (NULL == identity) @@ -2180,8 +2230,9 @@ consume_ticket (void *cls, for (atle = handle->presentations->list_head; NULL != atle; atle = atle->next) { - if (GNUNET_NO == GNUNET_RECLAIM_id_is_equal (&atle->presentation->credential_id, - &pres->credential_id)) + if (GNUNET_NO == GNUNET_RECLAIM_id_is_equal ( + &atle->presentation->credential_id, + &pres->credential_id)) continue; break; /** already in list **/ } @@ -2190,8 +2241,8 @@ consume_ticket (void *cls, /** Credential matches for attribute, add **/ atle = GNUNET_new (struct GNUNET_RECLAIM_PresentationListEntry); atle->presentation = GNUNET_RECLAIM_presentation_new (pres->type, - pres->data, - pres->data_size); + pres->data, + pres->data_size); GNUNET_CONTAINER_DLL_insert (handle->presentations->list_head, handle->presentations->list_tail, atle); @@ -2199,6 +2250,69 @@ consume_ticket (void *cls, } +static void +consume_timeout (void*cls) +{ + struct RequestHandle *handle = cls; + struct GNUNET_HashCode cache_key; + struct GNUNET_RECLAIM_AttributeList *cl = NULL; + struct GNUNET_RECLAIM_PresentationList *pl = NULL; + struct GNUNET_RECLAIM_Ticket ticket; + char *nonce; + char *cached_code; + + handle->consume_timeout_op = NULL; + if (NULL != handle->idp_op) + GNUNET_RECLAIM_cancel (handle->idp_op); + handle->idp_op = NULL; + + GNUNET_log (GNUNET_ERROR_TYPE_WARNING, + "Ticket consumptioned timed out. Using cache...\n"); + GNUNET_CRYPTO_hash (handle->access_token, + strlen (handle->access_token), + &cache_key); + cached_code = GNUNET_CONTAINER_multihashmap_get (oidc_code_cache, + &cache_key); + if (NULL == cached_code) + { + handle->emsg = GNUNET_strdup (OIDC_ERROR_KEY_INVALID_TOKEN); + handle->edesc = GNUNET_strdup ("No Access Token in cache!"); + handle->response_code = MHD_HTTP_UNAUTHORIZED; + GNUNET_SCHEDULER_add_now (&do_userinfo_error, handle); + return; + } + + // decode code + if (GNUNET_OK != OIDC_parse_authz_code (&handle->ticket.audience, + cached_code, NULL, &ticket, + &cl, &pl, &nonce, + OIDC_VERIFICATION_NO_CODE_VERIFIER)) + { + handle->emsg = GNUNET_strdup (OIDC_ERROR_KEY_INVALID_REQUEST); + handle->edesc = GNUNET_strdup ("invalid code"); + handle->response_code = MHD_HTTP_BAD_REQUEST; + GNUNET_free (cached_code); + GNUNET_SCHEDULER_add_now (&do_error, handle); + return; + } + + struct MHD_Response *resp; + char *result_str; + + result_str = OIDC_generate_userinfo (&handle->ticket.identity, + cl, + pl); + GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "Userinfo: %s\n", result_str); + resp = GNUNET_REST_create_response (result_str); + handle->proc (handle->proc_cls, resp, MHD_HTTP_OK); + GNUNET_free (result_str); + GNUNET_free (nonce); + GNUNET_RECLAIM_attribute_list_destroy (cl); + GNUNET_RECLAIM_presentation_list_destroy (pl); + cleanup_handle (handle); +} + + /** * Responds to userinfo GET and url-encoded POST request * @@ -2295,6 +2409,11 @@ userinfo_endpoint (struct GNUNET_REST_RequestHandle *con_handle, handle->presentations = GNUNET_new (struct GNUNET_RECLAIM_PresentationList); + /* If the consume takes too long, we use values from the cache */ + handle->access_token = GNUNET_strdup (authorization_access_token); + handle->consume_timeout_op = GNUNET_SCHEDULER_add_delayed (CONSUME_TIMEOUT, + &consume_timeout, + handle); handle->idp_op = GNUNET_RECLAIM_ticket_consume (idp, privkey, &handle->ticket, @@ -2554,6 +2673,10 @@ rest_identity_process_request (struct GNUNET_REST_RequestHandle *rest_handle, if (NULL == OIDC_cookie_jar_map) OIDC_cookie_jar_map = GNUNET_CONTAINER_multihashmap_create (10, GNUNET_NO); + if (NULL == oidc_code_cache) + oidc_code_cache = GNUNET_CONTAINER_multihashmap_create (10, + GNUNET_NO); + handle->response_code = 0; handle->timeout = GNUNET_TIME_UNIT_FOREVER_REL; handle->proc_cls = proc_cls; @@ -2646,6 +2769,14 @@ libgnunet_plugin_rest_openid_connect_done (void *cls) NULL); GNUNET_CONTAINER_multihashmap_destroy (OIDC_cookie_jar_map); } + if (NULL != oidc_code_cache) + { + GNUNET_CONTAINER_multihashmap_iterate (oidc_code_cache, + &cleanup_hashmap, + NULL); + GNUNET_CONTAINER_multihashmap_destroy (oidc_code_cache); + } + GNUNET_free (allow_methods); if (NULL != gns_handle) GNUNET_GNS_disconnect (gns_handle); -- cgit v1.2.3