From 11916b980c6f022ef4be5e34eea2a0abdce68b10 Mon Sep 17 00:00:00 2001 From: Christian Grothoff Date: Thu, 1 Nov 2018 15:29:10 +0100 Subject: attempting to fix #5464 --- src/cadet/.gitignore | 3 +- src/cadet/gnunet-service-cadet_channel.c | 7 +- src/transport/transport_api2_communication.c | 432 +++++++++++++++++++++++++++ 3 files changed, 439 insertions(+), 3 deletions(-) create mode 100644 src/transport/transport_api2_communication.c (limited to 'src') diff --git a/src/cadet/.gitignore b/src/cadet/.gitignore index 44382fde9..935049ce8 100644 --- a/src/cadet/.gitignore +++ b/src/cadet/.gitignore @@ -21,4 +21,5 @@ test_cadet_local test_cadet_single gnunet-service-cadet-new test_cadet_local_mq -test_cadet_*_new \ No newline at end of file +test_cadet_*_newtest_cadet_2_reopen +test_cadet_5_reopen diff --git a/src/cadet/gnunet-service-cadet_channel.c b/src/cadet/gnunet-service-cadet_channel.c index 06711dc8b..8ef598132 100644 --- a/src/cadet/gnunet-service-cadet_channel.c +++ b/src/cadet/gnunet-service-cadet_channel.c @@ -500,6 +500,11 @@ channel_destroy (struct CadetChannel *ch) GNUNET_free (crm->data_message); GNUNET_free (crm); } + if (CADET_CHANNEL_LOOSE == ch->state) + { + GSC_drop_loose_channel (&ch->h_port, + ch); + } if (NULL != ch->owner) { free_channel_client (ch->owner); @@ -1136,8 +1141,6 @@ GCCH_channel_local_destroy (struct CadetChannel *ch, target, but that never went anywhere. Nothing to do here. */ break; case CADET_CHANNEL_LOOSE: - GSC_drop_loose_channel (&ch->h_port, - ch); break; default: GCT_send_channel_destroy (ch->t, diff --git a/src/transport/transport_api2_communication.c b/src/transport/transport_api2_communication.c new file mode 100644 index 000000000..e33c5f444 --- /dev/null +++ b/src/transport/transport_api2_communication.c @@ -0,0 +1,432 @@ +/* + This file is part of GNUnet. + Copyright (C) 2018 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 . +*/ + +/** + * @file transport/transport_api2_communication.c + * @brief implementation of the gnunet_transport_communication_service.h API + * @author Christian Grothoff + */ +#include "platform.h" +#include "gnunet_util_lib.h" +#include "gnunet_protocols.h" +#include "gnunet_transport_communication_service.h" +#include "transport.h" + + +/** + * Opaque handle to the transport service for communicators. + */ +struct GNUNET_TRANSPORT_CommunicatorHandle +{ + /** + * Head of DLL of addresses this communicator offers to the transport service. + */ + struct GNUNET_TRANSPORT_AddressIdentifier *ai_head; + + /** + * Tail of DLL of addresses this communicator offers to the transport service. + */ + struct GNUNET_TRANSPORT_AddressIdentifier *ai_tail; + + /** + * Our configuration. + */ + const struct GNUNET_CONFIGURATION_Handle *cfg; + + /** + * Name of the communicator. + */ + const char *name; + + /** + * Function to call when the transport service wants us to initiate + * a communication channel with another peer. + */ + GNUNET_TRANSPORT_CommunicatorMqInit mq_init; + + /** + * Closure for @e mq_init. + */ + void *mq_init_cls; + + /** + * MTU of the communicator + */ + size_t mtu; + + /** + * Internal UUID for the address used in communication with the + * transport service. + */ + uint32_t aid_gen; + +}; + + + +/** + * Internal representation of an address a communicator is + * currently providing for the transport service. + */ +struct GNUNET_TRANSPORT_AddressIdentifier +{ + + /** + * Kept in a DLL. + */ + struct GNUNET_TRANSPORT_AddressIdentifier *next; + + /** + * Kept in a DLL. + */ + struct GNUNET_TRANSPORT_AddressIdentifier *prev; + + /** + * Transport handle where the address was added. + */ + struct GNUNET_TRANSPORT_CommunicatorHandle *ch; + + /** + * The actual address. + */ + char *address; + + /** + * When does the address expire? (Expected lifetime of the + * address.) + */ + struct GNUNET_TIME_Relative expiration; + + /** + * Internal UUID for the address used in communication with the + * transport service. + */ + uint32_t aid; + + /** + * Network type for the address. + */ + enum GNUNET_ATS_Network_Type nt; + +}; + + +/** + * (re)connect our communicator to the transport service + * + * @param ch handle to reconnect + */ +static void +reconnect (struct GNUNET_TRANSPORT_CommunicatorHandle *ch); + + +/** + * Send message to the transport service about address @a ai + * being now available. + * + * @param ai address to add + */ +static void +send_add_address (struct GNUNET_TRANSPORT_AddressIdentifier *ai) +{ + struct GNUNET_MQ_Envelope *env; + struct GNUNET_TRANSPORT_AddAddressMessage *aam; + + if (NULL == ai->ch->mq) + return; + env = GNUNET_MQ_msg_extra (aam, + strlen (ai->address) + 1, + GNUNET_MESSAGE_TYPE_TRANSPORT_ADD_ADDRESS); + aam->expiration = GNUNET_TIME_relative_to_nbo (ai->expiration); + aam->nt = htonl ((uint32_t) ai->nt); + memcpy (&aam[1], + ai->address, + strlen (ai->address) + 1); + GNUNET_MQ_send (ai->ch->mq, + env); +} + + +/** + * Send message to the transport service about address @a ai + * being no longer available. + * + * @param ai address to delete + */ +static void +send_del_address (struct GNUNET_TRANSPORT_AddressIdentifier *ai) +{ + struct GNUNET_MQ_Envelope *env; + struct GNUNET_TRANSPORT_DelAddressMessage *dam; + + if (NULL == ai->ch->mq) + return; + env = GNUNET_MQ_msg (dam, + GNUNET_MESSAGE_TYPE_TRANSPORT_DEL_ADDRESS); + dam.aid = htonl (ai->aid); + GNUNET_MQ_send (ai->ch->mq, + env); +} + + +/** + * Function called on MQ errors. + */ +static void +error_handler (void *cls, + enum GNUNET_MQ_Error error) +{ + struct GNUNET_TRANSPORT_CommunicatorHandle *ch = cls; + + GNUNET_MQ_destroy (ch->mq); + ch->mq = NULL; + /* TODO: maybe do this with exponential backoff/delay */ + reconnect (ch); +} + + +/** + * (re)connect our communicator to the transport service + * + * @param ch handle to reconnect + */ +static void +reconnect (struct GNUNET_TRANSPORT_CommunicatorHandle *ch) +{ + struct GNUNET_MQ_MessageHandler handlers[] = { + GNUNET_MQ_handler_end() + }; + + ch->mq = GNUNET_CLIENT_connect (cfg, + "transport", + handlers, + &error_handler, + ch); + for (struct GNUNET_TRANSPORT_AddressIdentifier ai = ch->ai_head; + NULL != ai; + ai = ai->next) + send_add_address (ai); +} + + +/** + * Connect to the transport service. + * + * @param cfg configuration to use + * @param name name of the communicator that is connecting + * @param mtu maximum message size supported by communicator, 0 if + * sending is not supported, SIZE_MAX for no MTU + * @param mq_init function to call to initialize a message queue given + * the address of another peer, can be NULL if the + * communicator only supports receiving messages + * @param mq_init_cls closure for @a mq_init + * @return NULL on error + */ +struct GNUNET_TRANSPORT_CommunicatorHandle * +GNUNET_TRANSPORT_communicator_connect (const struct GNUNET_CONFIGURATION_Handle *cfg, + const char *name, + size_t mtu, + GNUNET_TRANSPORT_CommunicatorMqInit mq_init, + void *mq_init_cls) +{ + struct GNUNET_TRANSPORT_CommunicatorHandle *ch; + + ch = GNUNET_new (struct GNUNET_TRANSPORT_CommunicatorHandle); + ch->cfg = cfg; + ch->name = name; + ch->mtu = mtu; + ch->mq_init = mq_init; + ch->mq_init_cls = mq_init_cls; + reconnect (ch); + if (NULL == ch->mq) + { + GNUNET_free (ch); + return NULL; + } + return ch; +} + + +/** + * Disconnect from the transport service. + * + * @param ch handle returned from connect + */ +void +GNUNET_TRANSPORT_communicator_disconnect (struct GNUNET_TRANSPORT_CommunicatorHandle *ch) +{ + while (NULL != ch->ai_head) + { + GNUNET_break (0); /* communicator forgot to remove address, warn! */ + GNUNET_TRANSPORT_communicator_address_remove (ch->ai_head); + } + GNUNET_MQ_destroy (ch->mq); + GNUNET_free (ch); +} + + +/* ************************* Receiving *************************** */ + + +/** + * Notify transport service that the communicator has received + * a message. + * + * @param ch connection to transport service + * @param sender presumed sender of the message (details to be checked + * by higher layers) + * @param msg the message + * @param cb function to call once handling the message is done, NULL if + * flow control is not supported by this communicator + * @param cb_cls closure for @a cb + * @return #GNUNET_OK if all is well, #GNUNET_NO if the message was + * immediately dropped due to memory limitations (communicator + * should try to apply back pressure), + * #GNUNET_SYSERR if the message is ill formed and communicator + * should try to reset stream + */ +int +GNUNET_TRANSPORT_communicator_receive (struct GNUNET_TRANSPORT_CommunicatorHandle *ch, + const struct GNUNET_PeerIdentity *sender, + const struct GNUNET_MessageHeader *msg, + GNUNET_TRANSPORT_MessageCompletedCallback cb, + void *cb_cls) +{ + struct GNUNET_MQ_Envelope *env; + struct GNUNET_TRANSPORT_IncomingMessage *im; + uint16_t msize; + + if (NULL == ai->ch->mq) + return; + msize = ntohs (msg->size); + env = GNUNET_MQ_msg_extra (im, + msize, + GNUNET_MESSAGE_TYPE_TRANSPORT_INCOMING_MSG); + if (NULL == env) + { + GNUNET_break (0); + return; + } + im->sender = *sender; + memcpy (&im[1], + msg, + msize); + GNUNET_MQ_send (ai->ch->mq, + env); +} + + +/* ************************* Discovery *************************** */ + +/** + * Handle returned to identify the internal data structure the transport + * API has created to manage a message queue to a particular peer. + */ +struct GNUNET_TRANSPORT_QueueHandle +{ +}; + + +/** + * Notify transport service that an MQ became available due to an + * "inbound" connection or because the communicator discovered the + * presence of another peer. + * + * @param ch connection to transport service + * @param peer peer with which we can now communicate + * @param address address in human-readable format, 0-terminated, UTF-8 + * @param nt which network type does the @a address belong to? + * @param mq message queue of the @a peer + * @return API handle identifying the new MQ + */ +struct GNUNET_TRANSPORT_QueueHandle * +GNUNET_TRANSPORT_communicator_mq_add (struct GNUNET_TRANSPORT_CommunicatorHandle *ch, + const struct GNUNET_PeerIdentity *peer, + const char *address, + enum GNUNET_ATS_Network_Type nt, + struct GNUNET_MQ_Handle *mq) +{ +} + + +/** + * Notify transport service that an MQ became unavailable due to a + * disconnect or timeout. + * + * @param qh handle for the queue that must be invalidated + */ +void +GNUNET_TRANSPORT_communicator_mq_del (struct GNUNET_TRANSPORT_QueueHandle *qh) +{ +} + + + + +/** + * Notify transport service about an address that this communicator + * provides for this peer. + * + * @param ch connection to transport service + * @param address our address in human-readable format, 0-terminated, UTF-8 + * @param nt which network type does the address belong to? + * @param expiration when does the communicator forsee this address expiring? + */ +struct GNUNET_TRANSPORT_AddressIdentifier * +GNUNET_TRANSPORT_communicator_address_add (struct GNUNET_TRANSPORT_CommunicatorHandle *ch, + const char *address, + enum GNUNET_ATS_Network_Type nt, + struct GNUNET_TIME_Relative expiration) +{ + struct GNUNET_TRANSPORT_AddressIdentifier *ai; + + ai = GNUNET_new (struct GNUNET_TRANSPORT_AddressIdentifier); + ai->ch = ch; + ai->address = GNUNET_strdup (address); + ai->nt = nt; + ai->expiration = expiration; + ai->aid = handle->aid_gen++; + GNUNET_CONTAINER_DLL_insert (handle->ai_head, + handle->ai_tail, + ai); + send_add_address (ai); + return ai; +} + + +/** + * Notify transport service about an address that this communicator no + * longer provides for this peer. + * + * @param ai address that is no longer provided + */ +void +GNUNET_TRANSPORT_communicator_address_remove (struct GNUNET_TRANSPORT_AddressIdentifier *ai) +{ + struct GNUNET_TRANSPORT_CommunicatorHandle *ch = ai->ch; + + send_del_address (ai); + GNUNET_free (ai->address); + GNUNET_CONTAINER_DLL_remove (ch->ai_head, + ch->ai_tail, + ai); + GNUNET_free (ai); +} + + +/* end of transport_api2_communication.c */ -- cgit v1.2.3