From 49da466bce647497cfc034db9e9761804e9d1a36 Mon Sep 17 00:00:00 2001 From: "Nathan S. Evans" Date: Thu, 11 Mar 2010 10:38:11 +0000 Subject: [PATCH] shell for dv plugin and service, not yet working --- src/dv/Makefile.am | 66 ++++++ src/dv/dv.h | 165 +++++++++++++++ src/dv/dv_api.c | 392 ++++++++++++++++++++++++++++++++++ src/dv/gnunet-service-dv.c | 278 ++++++++++++++++++++++++ src/dv/plugin_transport_dv.c | 400 +++++++++++++++++++++++++++++++++++ 5 files changed, 1301 insertions(+) create mode 100644 src/dv/Makefile.am create mode 100644 src/dv/dv.h create mode 100644 src/dv/dv_api.c create mode 100644 src/dv/gnunet-service-dv.c create mode 100644 src/dv/plugin_transport_dv.c diff --git a/src/dv/Makefile.am b/src/dv/Makefile.am new file mode 100644 index 000000000..755f89d59 --- /dev/null +++ b/src/dv/Makefile.am @@ -0,0 +1,66 @@ +INCLUDES = -I$(top_srcdir)/src/include + +if MINGW + WINFLAGS = -Wl,--no-undefined -Wl,--export-all-symbols +endif + +if USE_COVERAGE + AM_CFLAGS = --coverage -O0 + XLIB = -lgcov +endif + +plugindir = $(libdir)/gnunet + +lib_LTLIBRARIES = libgnunetdv.la + +plugin_LTLIBRARIES = libgnunet_plugin_transport_dv.la + +libgnunetdv_la_SOURCES = \ + dv_api.c dv.h +libgnunetdv_la_LIBADD = \ + $(top_builddir)/src/util/libgnunetutil.la \ + $(top_builddir)/src/core/libgnunetcore.la \ + $(GN_LIBINTL) $(XLIB) +libgnunetdv_la_LDFLAGS = \ + $(GN_LIB_LDFLAGS) $(WINFLAGS) \ + -version-info 0:0:0 + + +bin_PROGRAMS = \ + gnunet-service-dv + +gnunet_service_dv_SOURCES = \ + gnunet-service-dv.c +gnunet_service_dv_LDADD = \ + $(top_builddir)/src/dv/libgnunetdv.la \ + $(top_builddir)/src/util/libgnunetutil.la \ + $(GN_LIBINTL) + +libgnunet_plugin_transport_dv_la_SOURCES = \ + plugin_transport_dv.c +libgnunet_plugin_transport_dv_la_LIBADD = \ + $(top_builddir)/src/hello/libgnunethello.la \ + $(top_builddir)/src/dv/libgnunetdv.la \ + $(top_builddir)/src/peerinfo/libgnunetpeerinfo.la \ + $(top_builddir)/src/util/libgnunetutil.la +libgnunet_plugin_transport_dv_la_LDFLAGS = \ + $(GN_PLUGIN_LDFLAGS) + + +#check_PROGRAMS = \ +# test_statistics_api + +TESTS = $(check_PROGRAMS) $(check_SCRIPTS) + +#test_statistics_api_SOURCES = \ +# test_statistics_api.c +#test_statistics_api_LDADD = \ +# $(top_builddir)/src/statistics/libgnunetstatistics.la \ +# $(top_builddir)/src/util/libgnunetutil.la + +#EXTRA_DIST = \ +# test_statistics_api_data.conf + +#check_SCRIPTS = \ +# test_gnunet_statistics.sh + diff --git a/src/dv/dv.h b/src/dv/dv.h new file mode 100644 index 000000000..3063bc917 --- /dev/null +++ b/src/dv/dv.h @@ -0,0 +1,165 @@ +/* + This file is part of GNUnet. + (C) 2001, 2002, 2003, 2004, 2009 Christian Grothoff (and other contributing authors) + + GNUnet is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published + by the Free Software Foundation; either version 2, 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 + General Public License for more details. + + You should have received a copy of the GNU General Public License + along with GNUnet; see the file COPYING. If not, write to the + Free Software Foundation, Inc., 59 Temple Place - Suite 330, + Boston, MA 02111-1307, USA. +*/ + +/** + * @author Christian Grothoff + * @author NOT Nathan Evans + * @file dv/dv.h + */ +#ifndef DV_H +#define DV_H + +#include "gnunet_common.h" + +#define DEBUG_DV GNUNET_YES +#define DEBUG_DV_API GNUNET_YES + +typedef void (*GNUNET_DV_MessageReceivedHandler) (void *cls, + struct GNUNET_PeerIdentity *sender, + struct GNUNET_MessageHeader *msg, + unsigned int distance, + char *sender_address, + size_t sender_address_len); + +/** + * DV Message, contains a message that was received + * via DV for this peer! + * + * Sender address is copied to the end of this struct. + */ +struct GNUNET_DV_MessageReceived +{ + /** + * Type: GNUNET_MESSAGE_TYPE_TRANSPORT_DV_MESSAGE + */ + struct GNUNET_MessageHeader header; + + /** + * The sender of the message + */ + struct GNUNET_PeerIdentity *sender; + + /** + * The message that was sent + */ + struct GNUNET_MessageHeader *msg; + + /** + * The distance to the peer that we received the message from + */ + size_t distance; + + /** + * Length of the sender address, appended to end of this message + */ + size_t sender_address_len; + +}; + + +/** + * DV Message, indicates that we have learned of a new DV level peer. + * + * Sender address is copied to the end of this struct. + */ +struct GNUNET_DV_ConnectMessage +{ + /** + * Type: GNUNET_MESSAGE_TYPE_TRANSPORT_DV_MESSAGE + */ + struct GNUNET_MessageHeader header; + + /** + * The sender of the message + */ + struct GNUNET_PeerIdentity *sender; + + /** + * The message that was sent + */ + struct GNUNET_MessageHeader *msg; + + /** + * The distance to the peer that we received the message from + */ + size_t distance; + + /** + * Length of the sender address, appended to end of this message + */ + size_t sender_address_len; + +}; + + +/** + * Message to send a message over DV via a specific peer + */ +struct GNUNET_DV_SendMessage +{ + /** + * Type: GNUNET_MESSAGE_TYPE_DV_SEND + */ + struct GNUNET_MessageHeader header; + + /** + * Intended final recipient of this message + */ + struct GNUNET_PeerIdentity target; + + /** + * The message(s) to be sent. + */ + char *msgbuf; + + /** + * The size of the msgbuf + */ + size_t msgbuf_size; + + /** + * Message priority + */ + size_t priority; + + /** + * How long can we delay sending? + */ + struct GNUNET_TIME_Relative timeout; + + /** + * Size of the address (appended to end of struct) + */ + size_t addrlen; + + /* + * Sender, appended to end of struct tells via whom + * to send this message. + */ + +}; + +struct GNUNET_DV_Handle * +GNUNET_DV_connect (struct GNUNET_SCHEDULER_Handle *sched, + const struct GNUNET_CONFIGURATION_Handle *cfg, + GNUNET_DV_MessageReceivedHandler receive_handler, + void *receive_handler_cls); + +#endif diff --git a/src/dv/dv_api.c b/src/dv/dv_api.c new file mode 100644 index 000000000..8c536b207 --- /dev/null +++ b/src/dv/dv_api.c @@ -0,0 +1,392 @@ +/* + This file is part of GNUnet. + (C) 2009, 2010 Christian Grothoff (and other contributing authors) + + GNUnet is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published + by the Free Software Foundation; either version 2, 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 + General Public License for more details. + + You should have received a copy of the GNU General Public License + along with GNUnet; see the file COPYING. If not, write to the + Free Software Foundation, Inc., 59 Temple Place - Suite 330, + Boston, MA 02111-1307, USA. +*/ + +/** + * @file transport/dv_api.c + * @brief library to access the DV service + * @author Christian Grothoff + * @author Not Nathan Evans + */ +#include "platform.h" +#include "gnunet_bandwidth_lib.h" +#include "gnunet_client_lib.h" +#include "gnunet_constants.h" +#include "gnunet_container_lib.h" +#include "gnunet_arm_service.h" +#include "gnunet_hello_lib.h" +#include "gnunet_protocols.h" +#include "gnunet_server_lib.h" +#include "gnunet_time_lib.h" +#include "gnunet_dv_service.h" +#include "dv.h" + + +struct PendingMessages +{ + /** + * Linked list of pending messages + */ + struct PendingMessages *next; + + /** + * Message that is pending + */ + struct GNUNET_DV_SendMessage *msg; + + /** + * Timeout for this message + */ + struct GNUNET_TIME_Absolute timeout; + +}; + +/** + * Handle for the service. + */ +struct GNUNET_DV_Handle +{ + /** + * Our scheduler. + */ + struct GNUNET_SCHEDULER_Handle *sched; + + /** + * Configuration to use. + */ + const struct GNUNET_CONFIGURATION_Handle *cfg; + + /** + * Socket (if available). + */ + struct GNUNET_CLIENT_Connection *client; + + /** + * Currently pending transmission request. + */ + struct GNUNET_CLIENT_TransmitHandle *th; + + /** + * List of the currently pending messages for the DV service. + */ + struct PendingMessages *pending_list; + + /** + * Message we are currently sending. + */ + struct PendingMessages *current; + + /** + * Kill off the connection and any pending messages. + */ + int do_destroy; + + /** + * Handler for messages we receive from the DV service + */ + GNUNET_DV_MessageReceivedHandler receive_handler; + + /** + * Closure for the receive handler + */ + void *receive_cls; + +}; + + +/** + * Try to (re)connect to the dv service. + * + * @return GNUNET_YES on success, GNUNET_NO on failure. + */ +static int +try_connect (struct GNUNET_DV_Handle *ret) +{ + if (ret->client != NULL) + return GNUNET_OK; + ret->client = GNUNET_CLIENT_connect (ret->sched, "dv", ret->cfg); + if (ret->client != NULL) + return GNUNET_YES; +#if DEBUG_STATISTICS + GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, + _("Failed to connect to the dv service!\n")); +#endif + return GNUNET_NO; +} + +static void process_pending_message(struct GNUNET_DV_Handle *handle); + +/** + * Send complete, schedule next + */ +static void +finish (struct GNUNET_DV_Handle *handle, int code) +{ + struct PendingMessages *pos = handle->current; + handle->current = NULL; + process_pending_message (handle); + + GNUNET_free (pos); +} + + +static size_t +transmit_pending (void *cls, size_t size, void *buf) +{ + struct GNUNET_DV_Handle *handle = cls; + size_t ret; + + if (buf == NULL) + { + finish(handle, GNUNET_SYSERR); + return 0; + } + handle->th = NULL; + + return ret; +} + +/** + * Try to send messages from list of messages to send + */ +static void process_pending_message(struct GNUNET_DV_Handle *handle) +{ + struct GNUNET_TIME_Relative timeout; + + if (handle->current != NULL) + return; /* action already pending */ + if (GNUNET_YES != try_connect (handle)) + { + finish (handle, GNUNET_SYSERR); + return; + } + + /* schedule next action */ + handle->current = handle->pending_list; + if (NULL == handle->current) + { + if (handle->do_destroy) + { + handle->do_destroy = GNUNET_NO; + //GNUNET_DV_disconnect (handle); /* FIXME: replace with proper disconnect stuffs */ + } + return; + } + handle->pending_list = handle->pending_list->next; + handle->current->next = NULL; + + timeout = GNUNET_TIME_absolute_get_remaining (handle->current->timeout); + if (NULL == + (handle->th = GNUNET_CLIENT_notify_transmit_ready (handle->client, + ntohs(handle->current->msg->msgbuf_size), + timeout, + GNUNET_YES, + &transmit_pending, handle))) + { +#if DEBUG_STATISTICS + GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, + "Failed to transmit request to dv service.\n"); +#endif + finish (handle, GNUNET_SYSERR); + } +} + +/** + * Add a pending message to the linked list + * + * @param handle handle to the specified DV api + * @param msg the message to add to the list + */ +static void add_pending(struct GNUNET_DV_Handle *handle, struct GNUNET_DV_SendMessage *msg) +{ + struct PendingMessages *new_message; + struct PendingMessages *pos; + struct PendingMessages *last; + + new_message = GNUNET_malloc(sizeof(struct PendingMessages)); + new_message->msg = msg; + + if (handle->pending_list != NULL) + { + pos = handle->pending_list; + while(pos != NULL) + { + last = pos; + pos = pos->next; + } + new_message->next = last->next; /* Should always be null */ + last->next = new_message; + } + else + { + new_message->next = handle->pending_list; /* Will always be null */ + handle->pending_list = new_message; + } + + process_pending_message(handle); +} + + + + +void handle_message_receipt (void *cls, + const struct GNUNET_MessageHeader * msg) +{ + struct GNUNET_DV_Handle *handle = cls; + struct GNUNET_DV_MessageReceived *received_msg; + char *sender_address; + + GNUNET_assert(ntohs(msg->type) == GNUNET_MESSAGE_TYPE_TRANSPORT_DV_RECEIVE); + + if (ntohs(msg->size) < sizeof(struct GNUNET_DV_MessageReceived)) + return; + + received_msg = (struct GNUNET_DV_MessageReceived *)msg; + GNUNET_assert(ntohs(msg->size) == (sizeof(struct GNUNET_DV_MessageReceived) + ntohs(received_msg->msg->size) + ntohs(received_msg->sender_address_len))); + + sender_address = GNUNET_malloc(ntohs(received_msg->sender_address_len)); + sender_address = memcpy(sender_address, &received_msg[1], ntohs(received_msg->sender_address_len)); + + handle->receive_handler(handle->receive_cls, + received_msg->sender, + received_msg->msg, + ntohl(received_msg->distance), + sender_address, + ntohs(received_msg->sender_address_len)); + + GNUNET_free(sender_address); + + GNUNET_CLIENT_receive (handle->client, + &handle_message_receipt, + handle, GNUNET_TIME_UNIT_FOREVER_REL); +} + +/** + * Send a message from the plugin to the DV service indicating that + * a message should be sent via DV to some peer. + * + * @target the final target of the message + * @msgbuf the msg(s) to send + * @msgbuf_size the size of msgbuf + * @priority priority to pass on to core when sending the message + * @timeout how long can this message be delayed (pass through to core) + * @addr the address of this peer (internally known to DV) + * @addrlen the length of the peer address + * + */ +int GNUNET_DV_send (struct GNUNET_DV_Handle *dv_handle, + const struct GNUNET_PeerIdentity *target, + const char *msgbuf, + size_t msgbuf_size, + unsigned int priority, + struct GNUNET_TIME_Relative timeout, + const void *addr, + size_t addrlen) +{ + struct GNUNET_DV_SendMessage *msg; + + msg = GNUNET_malloc(sizeof(struct GNUNET_DV_SendMessage) + msgbuf_size + addrlen); + msg->header.size = htons(sizeof(struct GNUNET_DV_SendMessage) + msgbuf_size + addrlen); + msg->header.type = htons(GNUNET_MESSAGE_TYPE_TRANSPORT_DV_SEND); + memcpy(&msg->target, target, sizeof(struct GNUNET_PeerIdentity)); + msg->msgbuf = GNUNET_malloc(msgbuf_size); + memcpy(msg->msgbuf, msgbuf, msgbuf_size); + msg->msgbuf_size = htons(msgbuf_size); + msg->priority = htonl(priority); + msg->timeout = timeout; + msg->addrlen = htons(addrlen); + memcpy(&msg[1], addr, addrlen); + + add_pending(dv_handle, msg); + process_pending_message(dv_handle); + + return GNUNET_OK; +} + +/** + * Connect to the DV service + * + * @param sched the scheduler to use + * @param cfg the configuration to use + * + * @return handle to the DV service + */ +struct GNUNET_DV_Handle * +GNUNET_DV_connect (struct GNUNET_SCHEDULER_Handle *sched, + const struct GNUNET_CONFIGURATION_Handle *cfg, + GNUNET_DV_MessageReceivedHandler receive_handler, + void *receive_handler_cls) +{ + struct GNUNET_DV_Handle *handle; + + handle = GNUNET_malloc(sizeof(struct GNUNET_DV_Handle)); + + handle->cfg = cfg; + handle->sched = sched; + handle->pending_list = NULL; + handle->current = NULL; + handle->do_destroy = GNUNET_NO; + handle->th = NULL; + handle->client = GNUNET_CLIENT_connect(sched, "dv", cfg); + handle->receive_handler = receive_handler; + handle->receive_cls = receive_handler_cls; + + if (handle->client == NULL) + return NULL; + + GNUNET_CLIENT_receive (handle->client, + &handle_message_receipt, + handle, GNUNET_TIME_UNIT_FOREVER_REL); + + return handle; +} + +/** + * Disconnect from the DV service + * + * @param handle the current handle to the service to disconnect + */ +void GNUNET_DV_disconnect(struct GNUNET_DV_Handle *handle) +{ + struct PendingMessages *pos; + + GNUNET_assert(handle != NULL); + + if (handle->th != NULL) /* We have a live transmit request in the Aether */ + { + GNUNET_CLIENT_notify_transmit_ready_cancel (handle->th); + handle->th = NULL; + } + if (handle->current != NULL) /* We are trying to send something now, clean it up */ + GNUNET_free(handle->current); + while (NULL != (pos = handle->pending_list)) /* Remove all pending sends from the list */ + { + handle->pending_list = pos->next; + GNUNET_free(pos); + } + if (handle->client != NULL) /* Finally, disconnect from the service */ + { + GNUNET_CLIENT_disconnect (handle->client); + handle->client = NULL; + } + + GNUNET_free (handle); +} + +/* end of dv_api.c */ diff --git a/src/dv/gnunet-service-dv.c b/src/dv/gnunet-service-dv.c new file mode 100644 index 000000000..92f5c96aa --- /dev/null +++ b/src/dv/gnunet-service-dv.c @@ -0,0 +1,278 @@ +/* + This file is part of GNUnet. + (C) 2009 Christian Grothoff (and other contributing authors) + + GNUnet is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published + by the Free Software Foundation; either version 2, 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 + General Public License for more details. + + You should have received a copy of the GNU General Public License + along with GNUnet; see the file COPYING. If not, write to the + Free Software Foundation, Inc., 59 Temple Place - Suite 330, + Boston, MA 02111-1307, USA. +*/ + +/** + * @file dv/gnunet-service-dv.c + * @brief the distance vector service, primarily handles gossip of nearby + * peers and sending/receiving DV messages from core and decapsulating + * them + * + * @author Christian Grothoff + * @author Nathan Evans + * + */ +#include "platform.h" +#include "gnunet_client_lib.h" +#include "gnunet_getopt_lib.h" +#include "gnunet_os_lib.h" +#include "gnunet_protocols.h" +#include "gnunet_service_lib.h" +#include "gnunet_core_service.h" +#include "gnunet_signal_lib.h" +#include "dv.h" + +/** + * DV Service Context stuff goes here... + */ +static struct GNUNET_CORE_Handle *coreAPI; + +static struct GNUNET_PeerIdentity *my_identity; + +const struct GNUNET_CONFIGURATION_Handle *cfg; + +struct GNUNET_SCHEDULER_Handle *sched; + +GNUNET_SCHEDULER_TaskIdentifier cleanup_task; + +/** + * Core handler for dv data messages. Whatever this message + * contains all we really have to do is rip it out of its + * DV layering and give it to our pal the DV plugin to report + * in with. + * + * @param cls closure + * @param client identification of the client + * @param message the actual message + */ +void handle_dv_data_message (void *cls, + struct GNUNET_SERVER_Client * + client, + const struct + GNUNET_MessageHeader * + message) +{ +#if DEBUG_DV + GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, + "%s: Receives %s message!\n", "dv", "DV DATA"); +#endif +} + +/** + * Core handler for dv gossip messages. These will be used + * by us to create a HELLO message for the newly peer containing + * which direct peer we can connect through, and what the cost + * is. This HELLO will then be scheduled for validation by the + * transport service so that it can be used by all others. + * + * @param cls closure + * @param client identification of the client + * @param message the actual message + */ +void handle_dv_gossip_message (void *cls, + struct GNUNET_SERVER_Client * + client, + const struct GNUNET_MessageHeader * + message) +{ +#if DEBUG_DV + GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, + "%s: Receives %s message!\n", "dv", "DV GOSSIP"); +#endif +} + + +/** + * Service server's handler for message send requests (which come + * bubbling up to us through the DV plugin). + * + * @param cls closure + * @param client identification of the client + * @param message the actual message + */ +void send_dv_message (void *cls, + struct GNUNET_SERVER_Client * client, + const struct GNUNET_MessageHeader * message) +{ +#if DEBUG_DV + GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, + "%s: Receives %s message!\n", "dv", "SEND"); +#endif +} + +/** + * List of handlers for the messages understood by this + * service. + * + * Hmm... will we need to register some handlers with core and + * some handlers with our server here? Because core should be + * getting the incoming DV messages (from whichever lower level + * transport) and then our server should be getting messages + * from the dv_plugin, right? + */ +static struct GNUNET_SERVER_MessageHandler core_handlers[] = { + {&handle_dv_data_message, NULL, GNUNET_MESSAGE_TYPE_DV_DATA, 0}, + {&handle_dv_gossip_message, NULL, GNUNET_MESSAGE_TYPE_DV_GOSSIP, 0}, + {NULL, NULL, 0, 0} +}; + +static struct GNUNET_SERVER_MessageHandler plugin_handlers[] = { + {&send_dv_message, NULL, GNUNET_MESSAGE_TYPE_TRANSPORT_DV_SEND, 0}, + {NULL, NULL, 0, 0} +}; + + +/** + * Task run during shutdown. + * + * @param cls unused + * @param tc unused + */ +static void +shutdown_task (void *cls, + const struct GNUNET_SCHEDULER_TaskContext *tc) +{ + + GNUNET_CORE_disconnect (coreAPI); +} + +/** + * To be called on core init/fail. + */ +void core_init (void *cls, + struct GNUNET_CORE_Handle * server, + const struct GNUNET_PeerIdentity *my_identity, + const struct GNUNET_CRYPTO_RsaPublicKeyBinaryEncoded * publicKey) +{ + + if (server == NULL) + { + GNUNET_SCHEDULER_cancel(sched, cleanup_task); + GNUNET_SCHEDULER_add_now(sched, &shutdown_task, NULL); + } +#if DEBUG_DV + GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, + "%s: Core initialized, I am peer: %s\n", "dv", GNUNET_i2s(my_identity)); +#endif + coreAPI = server; +} + +/** + * Method called whenever a given peer either connects. + * + * @param cls closure + * @param peer peer identity this notification is about + * @param latency reported latency of the connection with 'other' + * @param distance reported distance (DV) to 'other' + */ +void handle_core_connect (void *cls, + const struct GNUNET_PeerIdentity * peer, + struct GNUNET_TIME_Relative latency, + uint32_t distance) +{ + +#if DEBUG_DV + GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, + "%s: Receives core connect message!\n", "dv"); +#endif +} + +/** + * Method called whenever a given peer either connects. + * + * @param cls closure + * @param peer peer identity this notification is about + * @param latency reported latency of the connection with 'other' + * @param distance reported distance (DV) to 'other' + */ +void handle_core_disconnect (void *cls, + const struct GNUNET_PeerIdentity * peer, + struct GNUNET_TIME_Relative latency, + uint32_t distance) +{ +#if DEBUG_DV + GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, + "%s: Receives core disconnect message!\n", "dv"); +#endif +} + + +/** + * Process dv requests. + * + * @param cls closure + * @param sched scheduler to use + * @param server the initialized server + * @param c configuration to use + */ +static void +run (void *cls, + struct GNUNET_SCHEDULER_Handle *scheduler, + struct GNUNET_SERVER_Handle *server, + const struct GNUNET_CONFIGURATION_Handle *c) +{ + struct GNUNET_TIME_Relative timeout; + sched = scheduler; + cfg = c; + GNUNET_SERVER_add_handlers (server, plugin_handlers); + coreAPI = + GNUNET_CORE_connect (sched, + cfg, + timeout, + NULL, /* FIXME: anything we want to pass around? */ + &core_init, + NULL, /* Don't care about pre-connects */ + &handle_core_connect, + &handle_core_disconnect, + NULL, + NULL, + NULL, + NULL, + core_handlers); + + if (coreAPI == NULL) + return; + /* load (server); Huh? */ + + /* Scheduled the task to clean up when shutdown is called */ + + cleanup_task = GNUNET_SCHEDULER_add_delayed (sched, + GNUNET_TIME_UNIT_FOREVER_REL, + &shutdown_task, + NULL); +} + + +/** + * The main function for the dv service. + * + * @param argc number of arguments from the command line + * @param argv command line arguments + * @return 0 ok, 1 on error + */ +int +main (int argc, char *const *argv) +{ + return (GNUNET_OK == + GNUNET_SERVICE_run (argc, + argv, + "dv", + GNUNET_SERVICE_OPTION_NONE, + &run, NULL)) ? 0 : 1; +} diff --git a/src/dv/plugin_transport_dv.c b/src/dv/plugin_transport_dv.c new file mode 100644 index 000000000..aa25c97e6 --- /dev/null +++ b/src/dv/plugin_transport_dv.c @@ -0,0 +1,400 @@ +/* + This file is part of GNUnet + (C) 2002, 2003, 2004, 2005, 2006, 2007, 2008, 2009 Christian Grothoff (and other contributing authors) + + GNUnet is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published + by the Free Software Foundation; either version 2, 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 + General Public License for more details. + + You should have received a copy of the GNU General Public License + along with GNUnet; see the file COPYING. If not, write to the + Free Software Foundation, Inc., 59 Temple Place - Suite 330, + Boston, MA 02111-1307, USA. +*/ + +/** + * @file transport/plugin_transport_dv.c + * @brief DV transport service, takes incoming DV requests and deals with + * the DV service + * @author Christian Grothoff + */ + +/** + * TODO: + * + * As a start, the dv plugin needs to listen for information from the dv + * service. The plugin (?) will be notified by core (?) when a tcp/udp/whatever + * message comes in that should be for dv. The plugin will then hand off the message + * to the dv service which will decrypt/validate the message (?) and then send the + * result back to us (the transport) which will then send the message to the transport + * service (yikes). + * + * Or, core will notify the dv service directly which will validate, + * etc. and then just send a message to us. + * + * For starters, this plugin needs to have a client which will listen for messages from + * the dv service that need to be sent up to the gnunet-transport-service. + * + * Messages sent from the dv transport get passed to the dv service which deals + * with the actual sending (how much state does this transport need? should it know + * which peers it is currently connected to and their distances, or just assume that + * anything should be passed along to the dv service?). + */ +#include "platform.h" +#include "gnunet_protocols.h" +#include "gnunet_connection_lib.h" +#include "gnunet_server_lib.h" +#include "gnunet_service_lib.h" +#include "gnunet_statistics_service.h" +#include "gnunet_dv_service.h" +#include "gnunet_transport_service.h" +#include "../transport/plugin_transport.h" +#include "dv.h" + +#define DEBUG_TEMPLATE GNUNET_NO + +/** + * Encapsulation of all of the state of the plugin. + */ +struct Plugin; + + +/** + * Session handle for connections. + */ +struct Session +{ + + /** + * Stored in a linked list. + */ + struct Session *next; + + /** + * Pointer to the global plugin struct. + */ + struct Plugin *plugin; + + /** + * The client (used to identify this connection) + */ + /* void *client; */ + + /** + * Continuation function to call once the transmission buffer + * has again space available. NULL if there is no + * continuation to call. + */ + GNUNET_TRANSPORT_TransmitContinuation transmit_cont; + + /** + * Closure for transmit_cont. + */ + void *transmit_cont_cls; + + /** + * To whom are we talking to (set to our identity + * if we are still waiting for the welcome message) + */ + struct GNUNET_PeerIdentity sender; + + /** + * At what time did we reset last_received last? + */ + struct GNUNET_TIME_Absolute last_quota_update; + + /** + * How many bytes have we received since the "last_quota_update" + * timestamp? + */ + uint64_t last_received; + + /** + * Number of bytes per ms that this peer is allowed + * to send to us. + */ + uint32_t quota; + +}; + +/** + * Encapsulation of all of the state of the plugin. + */ +struct Plugin +{ + /** + * Our environment. + */ + struct GNUNET_TRANSPORT_PluginEnvironment *env; + + /** + * List of open sessions. + */ + struct Session *sessions; + + /** + * Handle for the statistics service. + */ + struct GNUNET_STATISTICS_Handle *statistics; + + /** + * Our server. + */ + struct GNUNET_SERVER_Handle *server; + + /* + * Handle to the running service. + */ + struct GNUNET_SERVICE_Context *service; + + /** + * Copy of the handler array where the closures are + * set to this struct's instance. + */ + struct GNUNET_SERVER_MessageHandler *handlers; + + /** + * Handle to the DV service + */ + struct GNUNET_DV_Handle *dv_handle; + +}; + + +void handle_dv_message_received (void *cls, + struct GNUNET_PeerIdentity *sender, + struct GNUNET_MessageHeader *msg, + unsigned int distance, + char *sender_address, + size_t sender_address_len) +{ + struct Plugin *plugin = cls; + + plugin->env->receive(plugin, + sender, + msg, + distance, + sender_address, + sender_address_len); + +} + + +/* Question: how does the transport service learn of a newly connected (gossipped about) + * DV peer? Should the plugin (here) create a HELLO for that peer and send it along, + * or should the DV service create a HELLO and send it to us via the other part? + */ + +/** + * Function that can be used by the transport service to transmit + * a message using the plugin. + * + * @param cls closure + * @param target who should receive this message + * @param priority how important is the message + * @param msgbuf the message to transmit + * @param msgbuf_size number of bytes in 'msgbuf' + * @param timeout when should we time out + * @param addr the address to use (can be NULL if the plugin + * is "on its own" (i.e. re-use existing TCP connection)) + * @param addrlen length of the address in bytes + * @param force_address GNUNET_YES if the plugin MUST use the given address, + * otherwise the plugin may use other addresses or + * existing connections (if available) + * @param cont continuation to call once the message has + * been transmitted (or if the transport is ready + * for the next transmission call; or if the + * peer disconnected...) + * @param cont_cls closure for cont + * @return number of bytes used (on the physical network, with overheads); + * -1 on hard errors (i.e. address invalid); 0 is a legal value + * and does NOT mean that the message was not transmitted (DV) + */ +static ssize_t +dv_plugin_send (void *cls, + const struct GNUNET_PeerIdentity *target, + const char *msgbuf, + size_t msgbuf_size, + unsigned int priority, + struct GNUNET_TIME_Relative timeout, + const void *addr, + size_t addrlen, + int force_address, + GNUNET_TRANSPORT_TransmitContinuation + cont, void *cont_cls) +{ + int ret = 0; + struct Plugin *plugin = cls; + + /* FIXME: do we want the dv plugin to remember sent messages to call continuation once message actually goes out? + * Or do we just call the continuation once we've notified the plugin? + */ + ret = GNUNET_DV_send(plugin->dv_handle, + target, + msgbuf, + msgbuf_size, + priority, + timeout, + addr, + addrlen); + /*, cont, cont_cls);*/ + + if (ret == 0) + cont(cls, target, GNUNET_OK); + else + cont(cls, target, GNUNET_SYSERR); + + return ret; +} + + + +/** + * Function that can be used to force the plugin to disconnect + * from the given peer and cancel all previous transmissions + * (and their continuations). + * + * @param cls closure + * @param target peer from which to disconnect + */ +static void +dv_plugin_disconnect (void *cls, + const struct GNUNET_PeerIdentity *target) +{ + // struct Plugin *plugin = cls; + // FIXME +} + + +/** + * Convert the transports address to a nice, human-readable + * format. + * + * @param cls closure + * @param type name of the transport that generated the address + * @param addr one of the addresses of the host, NULL for the last address + * the specific address format depends on the transport + * @param addrlen length of the address + * @param numeric should (IP) addresses be displayed in numeric form? + * @param timeout after how long should we give up? + * @param asc function to call on each string + * @param asc_cls closure for asc + */ +static void +dv_plugin_address_pretty_printer (void *cls, + const char *type, + const void *addr, + size_t addrlen, + int numeric, + struct GNUNET_TIME_Relative timeout, + GNUNET_TRANSPORT_AddressStringCallback + asc, void *asc_cls) +{ + asc (asc_cls, NULL); +} + + + +/** + * Another peer has suggested an address for this + * peer and transport plugin. Check that this could be a valid + * address. If so, consider adding it to the list + * of addresses. + * + * @param cls closure + * @param addr pointer to the address + * @param addrlen length of addr + * @return GNUNET_OK if this is a plausible address for this peer + * and transport + * + * FIXME: does this mean anything for the DV plugin? + */ +static int +dv_plugin_address_suggested (void *cls, + void *addr, size_t addrlen) +{ + /* struct Plugin *plugin = cls; */ + + /* check if the address is plausible; if so, + add it to our list! */ + return GNUNET_OK; +} + + +/** + * Entry point for the plugin. + */ +void * +gnunet_plugin_transport_dv_init (void *cls) +{ + struct GNUNET_TRANSPORT_PluginEnvironment *env = cls; + struct GNUNET_TRANSPORT_PluginFunctions *api; + struct Plugin *plugin; + unsigned long long port; + struct GNUNET_SERVICE_Context *service; + + service = GNUNET_SERVICE_start ("transport-dv", env->sched, env->cfg); + if (service == NULL) + { + GNUNET_log_from (GNUNET_ERROR_TYPE_WARNING, + "dv", + _ + ("Failed to start service for `%s' transport plugin.\n"), + "dv"); + return NULL; + } + + if ((GNUNET_OK != + GNUNET_CONFIGURATION_get_value_number (env->cfg, + "transport-dv", + "PORT", + &port))) + { + GNUNET_log_from (GNUNET_ERROR_TYPE_ERROR, + "dv", + _ + ("Require valid port number for service `%s' in configuration!\n"), + "transport-dv"); + GNUNET_SERVICE_stop (service); + return NULL; + } + + plugin = GNUNET_malloc (sizeof (struct Plugin)); + plugin->env = env; + plugin->statistics = NULL; + plugin->service = service; + plugin->server = GNUNET_SERVICE_get_server (service); + + plugin->dv_handle = GNUNET_DV_connect(env->sched, env->cfg, &handle_dv_message_received, plugin); + + api = GNUNET_malloc (sizeof (struct GNUNET_TRANSPORT_PluginFunctions)); + api->cls = plugin; + api->send = &dv_plugin_send; + api->disconnect = &dv_plugin_disconnect; + api->address_pretty_printer = &dv_plugin_address_pretty_printer; + api->check_address = &dv_plugin_address_suggested; + return api; +} + + +/** + * Exit point from the plugin. + */ +void * +gnunet_plugin_transport_dv_done (void *cls) +{ + struct GNUNET_TRANSPORT_PluginFunctions *api = cls; + struct Plugin *plugin = api->cls; + + GNUNET_free (plugin); + GNUNET_free (api); + return NULL; +} + +/* end of plugin_transport_template.c */ -- 2.25.1