--- /dev/null
+/*
+ This file is part of GNUnet.
+ Copyright (C) 2010-2016, 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 <http://www.gnu.org/licenses/>.
+ */
+/**
+ * @file transport/gnunet-service-transport.c
+ * @brief main for gnunet-service-transport
+ * @author Christian Grothoff
+ */
+#include "platform.h"
+#include "gnunet_util_lib.h"
+#include "gnunet_statistics_service.h"
+#include "gnunet_transport_service.h"
+#include "gnunet_peerinfo_service.h"
+#include "gnunet_ats_service.h"
+#include "gnunet-service-transport.h"
+#include "transport.h"
+
+
+/**
+ * How many messages can we have pending for a given client process
+ * before we start to drop incoming messages? We typically should
+ * have only one client and so this would be the primary buffer for
+ * messages, so the number should be chosen rather generously.
+ *
+ * The expectation here is that most of the time the queue is large
+ * enough so that a drop is virtually never required. Note that
+ * this value must be about as large as 'TOTAL_MSGS' in the
+ * 'test_transport_api_reliability.c', otherwise that testcase may
+ * fail.
+ */
+#define MAX_PENDING (128 * 1024)
+
+
+/**
+ * What type of client is the `struct TransportClient` about?
+ */
+enum ClientType
+{
+ /**
+ * We do not know yet (client is fresh).
+ */
+ CT_NONE = 0,
+
+ /**
+ * Is the CORE service, we need to forward traffic to it.
+ */
+ CT_CORE = 1,
+
+ /**
+ * It is a monitor, forward monitor data.
+ */
+ CT_MONITOR = 2,
+
+ /**
+ * It is a communicator, use for communication.
+ */
+ CT_COMMUNICATOR = 3
+};
+
+
+/**
+ * Client connected to the transport service.
+ */
+struct TransportClient
+{
+
+ /**
+ * Kept in a DLL.
+ */
+ struct TransportClient *next;
+
+ /**
+ * Kept in a DLL.
+ */
+ struct TransportClient *prev;
+
+ /**
+ * Handle to the client.
+ */
+ struct GNUNET_SERVICE_Client *client;
+
+ /**
+ * Message queue to the client.
+ */
+ struct GNUNET_MQ_Handle *mq;
+
+ /**
+ * What type of client is this?
+ */
+ enum ClientType type;
+
+ union
+ {
+
+ /**
+ * Peer identity to monitor the addresses of.
+ * Zero to monitor all neighbours. Valid if
+ * @e type is #CT_MONITOR.
+ */
+ struct GNUNET_PeerIdentity monitor_peer;
+
+ /**
+ * If @e type is #CT_COMMUNICATOR, this communicator
+ * supports communicating using these addresses.
+ */
+ const char *address_prefix;
+
+ } details;
+
+};
+
+
+/**
+ * Head of linked list of all clients to this service.
+ */
+static struct TransportClient *clients_head;
+
+/**
+ * Tail of linked list of all clients to this service.
+ */
+static struct TransportClient *clients_tail;
+
+/**
+ * Statistics handle.
+ */
+struct GNUNET_STATISTICS_Handle *GST_stats;
+
+/**
+ * Configuration handle.
+ */
+const struct GNUNET_CONFIGURATION_Handle *GST_cfg;
+
+/**
+ * Configuration handle.
+ */
+struct GNUNET_PeerIdentity GST_my_identity;
+
+/**
+ * Handle to peerinfo service.
+ */
+struct GNUNET_PEERINFO_Handle *GST_peerinfo;
+
+/**
+ * Our private key.
+ */
+struct GNUNET_CRYPTO_EddsaPrivateKey *GST_my_private_key;
+
+
+/**
+ * Called whenever a client connects. Allocates our
+ * data structures associated with that client.
+ *
+ * @param cls closure, NULL
+ * @param client identification of the client
+ * @param mq message queue for the client
+ * @return our `struct TransportClient`
+ */
+static void *
+client_connect_cb (void *cls,
+ struct GNUNET_SERVICE_Client *client,
+ struct GNUNET_MQ_Handle *mq)
+{
+ struct TransportClient *tc;
+
+ tc = GNUNET_new (struct TransportClient);
+ tc->client = client;
+ tc->mq = mq;
+ GNUNET_CONTAINER_DLL_insert (clients_head,
+ clients_tail,
+ tc);
+ GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
+ "Client %p connected\n",
+ tc);
+ return tc;
+}
+
+
+/**
+ * Called whenever a client is disconnected. Frees our
+ * resources associated with that client.
+ *
+ * @param cls closure, NULL
+ * @param client identification of the client
+ * @param app_ctx our `struct TransportClient`
+ */
+static void
+client_disconnect_cb (void *cls,
+ struct GNUNET_SERVICE_Client *client,
+ void *app_ctx)
+{
+ struct TransportClient *tc = app_ctx;
+
+ GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
+ "Client %p disconnected, cleaning up.\n",
+ tc);
+ GNUNET_CONTAINER_DLL_remove (clients_head,
+ clients_tail,
+ tc);
+ switch (tc->type)
+ {
+ case CT_NONE:
+ break;
+ case CT_CORE:
+ break;
+ case CT_MONITOR:
+ break;
+ case CT_COMMUNICATOR:
+ break;
+ }
+ GNUNET_free (tc);
+}
+
+
+/**
+ * Initialize a "CORE" client. We got a start message from this
+ * client, so add it to the list of clients for broadcasting of
+ * inbound messages.
+ *
+ * @param cls the client
+ * @param start the start message that was sent
+ */
+static void
+handle_client_start (void *cls,
+ const struct StartMessage *start)
+{
+ struct TransportClient *tc = cls;
+ const struct GNUNET_MessageHeader *hello;
+ uint32_t options;
+
+ options = ntohl (start->options);
+ if ( (0 != (1 & options)) &&
+ (0 !=
+ memcmp (&start->self,
+ &GST_my_identity,
+ sizeof (struct GNUNET_PeerIdentity)) ) )
+ {
+ /* client thinks this is a different peer, reject */
+ GNUNET_break (0);
+ GNUNET_SERVICE_client_drop (tc->client);
+ return;
+ }
+ if (CT_NONE != tc->type)
+ {
+ GNUNET_break (0);
+ GNUNET_SERVICE_client_drop (tc->client);
+ return;
+ }
+ tc->type = CT_CORE;
+#if 0
+ hello = GST_hello_get ();
+ if (NULL != hello)
+ unicast (tc,
+ hello,
+ GNUNET_NO);
+#endif
+ GNUNET_SERVICE_client_continue (tc->client);
+}
+
+
+/**
+ * Client sent us a HELLO. Check the request.
+ *
+ * @param cls the client
+ * @param message the HELLO message
+ */
+static int
+check_client_hello (void *cls,
+ const struct GNUNET_MessageHeader *message)
+{
+ (void) cls;
+ return GNUNET_OK; /* FIXME: check here? */
+}
+
+
+/**
+ * Client sent us a HELLO. Process the request.
+ *
+ * @param cls the client
+ * @param message the HELLO message
+ */
+static void
+handle_client_hello (void *cls,
+ const struct GNUNET_MessageHeader *message)
+{
+ struct TransportClient *tc = cls;
+
+ GNUNET_log (GNUNET_ERROR_TYPE_INFO,
+ "Received HELLO message\n");
+ GNUNET_SERVICE_client_continue (tc->client);
+}
+
+
+/**
+ * Client asked for transmission to a peer. Process the request.
+ *
+ * @param cls the client
+ * @param obm the send message that was sent
+ */
+static int
+check_client_send (void *cls,
+ const struct OutboundMessage *obm)
+{
+ uint16_t size;
+ const struct GNUNET_MessageHeader *obmm;
+
+ (void) cls;
+ size = ntohs (obm->header.size) - sizeof (struct OutboundMessage);
+ if (size < sizeof (struct GNUNET_MessageHeader))
+ {
+ GNUNET_break (0);
+ return GNUNET_SYSERR;
+ }
+ obmm = (const struct GNUNET_MessageHeader *) &obm[1];
+ if (size != ntohs (obmm->size))
+ {
+ GNUNET_break (0);
+ return GNUNET_SYSERR;
+ }
+ return GNUNET_OK;
+}
+
+
+/**
+ * Client asked for transmission to a peer. Process the request.
+ *
+ * @param cls the client
+ * @param obm the send message that was sent
+ */
+static void
+handle_client_send (void *cls,
+ const struct OutboundMessage *obm)
+{
+ struct TransportClient *tc = cls;
+ const struct GNUNET_MessageHeader *obmm;
+
+ obmm = (const struct GNUNET_MessageHeader *) &obm[1];
+}
+
+
+/**
+ * Communicator started. Test message is well-formed.
+ *
+ * @param cls the client
+ * @param cam the send message that was sent
+ */
+static int
+check_communicator_available (void *cls,
+ const struct GNUNET_TRANSPORT_CommunicatorAvailableMessage *cam)
+{
+ const char *addr;
+ uint16_t size;
+
+ (void) cls;
+ size = ntohs (cam->header.size) - sizeof (*cam);
+ if (0 == size)
+ return GNUNET_OK; /* receive-only communicator */
+ addr = (const char *) &cam[1];
+ if ('\0' != addr[size-1])
+ {
+ GNUNET_break (0);
+ return GNUNET_SYSERR;
+ }
+ return GNUNET_OK;
+}
+
+
+/**
+ * Communicator started. Process the request.
+ *
+ * @param cls the client
+ * @param cam the send message that was sent
+ */
+static void
+handle_communicator_available (void *cls,
+ const struct GNUNET_TRANSPORT_CommunicatorAvailableMessage *cam)
+{
+ struct TransportClient *tc = cls;
+ uint16_t size;
+
+ if (CT_NONE != tc->type)
+ {
+ GNUNET_break (0);
+ GNUNET_SERVICE_client_drop (tc->client);
+ return;
+ }
+ tc->type = CT_COMMUNICATOR;
+ size = ntohs (cam->header.size) - sizeof (*cam);
+ if (0 == size)
+ return GNUNET_OK; /* receive-only communicator */
+ tc->details.address_prefix = GNUNET_strdup ((const char *) &cam[1]);
+ GNUNET_SERVICE_client_continue (tc->client);
+}
+
+
+/**
+ * Address of our peer added. Test message is well-formed.
+ *
+ * @param cls the client
+ * @param aam the send message that was sent
+ */
+static int
+check_add_address (void *cls,
+ const struct GNUNET_TRANSPORT_AddAddressMessage *aam)
+{
+ const char *addr;
+ uint16_t size;
+
+ (void) cls;
+ size = ntohs (aam->header.size) - sizeof (*aam);
+ if (0 == size)
+ {
+ GNUNET_break (0);
+ return GNUNET_SYSERR;
+ }
+ addr = (const char *) &cam[1];
+ if ('\0' != addr[size-1])
+ {
+ GNUNET_break (0);
+ return GNUNET_SYSERR;
+ }
+ return GNUNET_OK;
+}
+
+
+/**
+ * Address of our peer added. Process the request.
+ *
+ * @param cls the client
+ * @param aam the send message that was sent
+ */
+static void
+handle_add_address (void *cls,
+ const struct GNUNET_TRANSPORT_AddAddressMessage *aam)
+{
+ struct TransportClient *tc = cls;
+
+ GNUNET_SERVICE_client_continue (tc->client);
+}
+
+
+/**
+ * Address of our peer deleted. Process the request.
+ *
+ * @param cls the client
+ * @param dam the send message that was sent
+ */
+static void
+handle_del_address (void *cls,
+ const struct GNUNET_TRANSPORT_DelAddressMessage *dam)
+{
+ struct TransportClient *tc = cls;
+
+ GNUNET_SERVICE_client_continue (tc->client);
+}
+
+
+/**
+ * Client asked for transmission to a peer. Process the request.
+ *
+ * @param cls the client
+ * @param obm the send message that was sent
+ */
+static int
+check_incoming_msg (void *cls,
+ const struct GNUNET_TRANSPORT_IncomingMessage *im)
+{
+ uint16_t size;
+ const struct GNUNET_MessageHeader *obmm;
+
+ (void) cls;
+ size = ntohs (im->header.size) - sizeof (*im);
+ if (size < sizeof (struct GNUNET_MessageHeader))
+ {
+ GNUNET_break (0);
+ return GNUNET_SYSERR;
+ }
+ obmm = (const struct GNUNET_MessageHeader *) &im[1];
+ if (size != ntohs (obmm->size))
+ {
+ GNUNET_break (0);
+ return GNUNET_SYSERR;
+ }
+ return GNUNET_OK;
+}
+
+
+/**
+ * Incoming meessage. Process the request.
+ *
+ * @param cls the client
+ * @param im the send message that was received
+ */
+static void
+handle_incoming_msg (void *cls,
+ const struct GNUNET_TRANSPORT_IncomingMessage *im)
+{
+ struct TransportClient *tc = cls;
+
+ GNUNET_SERVICE_client_continue (tc->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)
+{
+ const char *addr;
+ uint16_t size;
+
+ (void) cls;
+ size = ntohs (aqm->header.size) - sizeof (*aqm);
+ if (0 == size)
+ {
+ GNUNET_break (0);
+ return GNUNET_SYSERR;
+ }
+ addr = (const char *) &aqm[1];
+ if ('\0' != addr[size-1])
+ {
+ GNUNET_break (0);
+ return GNUNET_SYSERR;
+ }
+ return GNUNET_OK;
+}
+
+
+/**
+ * New queue became available. Process the request.
+ *
+ * @param cls the client
+ * @param aqm the send message that was sent
+ */
+static void
+handle_add_queue_message (void *cls,
+ const struct GNUNET_TRANSPORT_AddQueueMessage *aqm)
+{
+ struct TransportClient *tc = cls;
+
+ GNUNET_SERVICE_client_continue (tc->client);
+}
+
+
+/**
+ * Queue to a peer went down. Process the request.
+ *
+ * @param cls the client
+ * @param dqm the send message that was sent
+ */
+static void
+handle_del_queue_message (void *cls,
+ const struct GNUNET_TRANSPORT_DelQueueMessage *dqm)
+{
+ struct TransportClient *tc = cls;
+
+ GNUNET_SERVICE_client_continue (tc->client);
+}
+
+
+/**
+ * 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 TransportClient *tc = cls;
+
+ GNUNET_SERVICE_client_continue (tc->client);
+}
+
+
+/**
+ * Function called when the service shuts down. Unloads our plugins
+ * and cancels pending validations.
+ *
+ * @param cls closure, unused
+ */
+static void
+shutdown_task (void *cls)
+{
+ (void) cls;
+
+ if (NULL != GST_stats)
+ {
+ GNUNET_STATISTICS_destroy (GST_stats,
+ GNUNET_NO);
+ GST_stats = NULL;
+ }
+ if (NULL != GST_my_private_key)
+ {
+ GNUNET_free (GST_my_private_key);
+ GST_my_private_key = NULL;
+ }
+}
+
+
+/**
+ * Initiate transport service.
+ *
+ * @param cls closure
+ * @param c configuration to use
+ * @param service the initialized service
+ */
+static void
+run (void *cls,
+ const struct GNUNET_CONFIGURATION_Handle *c,
+ struct GNUNET_SERVICE_Handle *service)
+{
+ /* setup globals */
+ GST_cfg = c;
+ if (GNUNET_OK !=
+ GNUNET_CONFIGURATION_get_value_time (c,
+ "transport",
+ "HELLO_EXPIRATION",
+ &hello_expiration))
+ {
+ hello_expiration = GNUNET_CONSTANTS_HELLO_ADDRESS_EXPIRATION;
+ }
+ GST_my_private_key = GNUNET_CRYPTO_eddsa_key_create_from_configuration (cfg);
+ if (NULL == GST_my_private_key)
+ {
+ GNUNET_log(GNUNET_ERROR_TYPE_ERROR,
+ _("Transport service is lacking key configuration settings. Exiting.\n"));
+ GNUNET_SCHEDULER_shutdown ();
+ return;
+ }
+ GNUNET_CRYPTO_eddsa_key_get_public (GST_my_private_key,
+ &GST_my_identity.public_key);
+ GNUNET_log(GNUNET_ERROR_TYPE_INFO,
+ "My identity is `%s'\n",
+ GNUNET_i2s_full (&GST_my_identity));
+
+ GST_stats = GNUNET_STATISTICS_create ("transport",
+ GST_cfg);
+ GNUNET_SCHEDULER_add_shutdown (&shutdown_task,
+ NULL);
+ /* start subsystems */
+}
+
+
+/**
+ * Define "main" method using service macro.
+ */
+GNUNET_SERVICE_MAIN
+("transport",
+ GNUNET_SERVICE_OPTION_NONE,
+ &run,
+ &client_connect_cb,
+ &client_disconnect_cb,
+ NULL,
+ /* communication with core */
+ GNUNET_MQ_hd_fixed_size (client_start,
+ GNUNET_MESSAGE_TYPE_TRANSPORT_START,
+ struct StartMessage,
+ NULL),
+ GNUNET_MQ_hd_var_size (client_hello,
+ GNUNET_MESSAGE_TYPE_HELLO,
+ struct GNUNET_MessageHeader,
+ NULL),
+ GNUNET_MQ_hd_var_size (client_send,
+ GNUNET_MESSAGE_TYPE_TRANSPORT_SEND,
+ struct OutboundMessage,
+ NULL),
+ /* communication with communicators */
+ GNUNET_MQ_hd_var_size (communicator_available,
+ GNUNET_MESSAGE_TYPE_TRANSPORT_NEW_COMMUNICATOR,
+ struct GNUNET_TRANSPORT_CommunicatorAvailableMessage,
+ NULL),
+ GNUNET_MQ_hd_var_size (add_address,
+ GNUNET_MESSAGE_TYPE_TRANSPORT_ADD_ADDRESS,
+ struct GNUNET_TRANSPORT_AddAddressMessage,
+ NULL),
+ 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,
+ NULL),
+ GNUNET_MQ_hd_var_size (add_queue_message,
+ GNUNET_MESSAGE_TYPE_TRANSPORT_QUEUE_SETUP,
+ struct GNUNET_TRANSPORT_AddQueueMessage,
+ NULL),
+ 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,
+ NULL),
+ GNUNET_MQ_handler_end ());
+
+
+/* end of file gnunet-service-transport.c */