From 1e83b104b323d90664e90af7a12166308ba6ee7a Mon Sep 17 00:00:00 2001 From: Christian Grothoff Date: Thu, 21 Jan 2010 21:03:45 +0000 Subject: [PATCH] towards a new conveniance API --- TODO | 44 +++-- src/include/gnunet_server_lib.h | 91 +++++++++++ src/peerinfo/gnunet-service-peerinfo.c | 2 + src/util/Makefile.am | 1 + src/util/server.c | 39 +++++ src/util/server_nc.c | 218 +++++++++++++++++++++++++ 6 files changed, 381 insertions(+), 14 deletions(-) create mode 100644 src/util/server_nc.c diff --git a/TODO b/TODO index 1d975e95a..992f61f80 100644 --- a/TODO +++ b/TODO @@ -12,24 +12,40 @@ away), in order in which they will likely be done: * UPNP [Milan] Urgent items (before announcing ng.gnunet.org): +* UTIL: + - provide higher-level convenience API for servers/services that + need to send a stream of notifications to clients; instead + of having each service queue messages and "send when ready", + simply have a way to add a client to the notification set + and to 'notify client' or 'notify all clients' + (useful for peerinfo (new hellos), transport (our hello; blacklist), + core (misc monitoring features), statistics (change notifications) + and likely others) + - server/service API change for ARM inetd'ing + (listen as well as support for start with multiple, already + bound & listening sockets!) +* TRANSPORT: + - main service not implemented [Nate] + - blacklist not implemented [Christian] + - testcases crash & burn (no surprise) * CORE: - - test currently fails spectacularly - - request disconnect not implemented - - request connect not working - - various notification options not implemented -* topology - - (forced) disconnect does not work as implemented (still?) - - needs testing (not sure the current testcase does much...) -* testing: - - timeout_hello_task is not used but should be (so we can fail - properly) + - request disconnect not implemented [Christian] + - various notification options not implemented [Christian] + - test currently fails spectacularly [segv of transport service] + => need transport to work first! + - request connect not working [Christian, need transport first] +* PEERINFO: + - make sue we also trigger notifications whenever HELLOs expire +* TOPOLOGY: + - needs testing [need transport first] +* TESTING: - check that 'GNUNET_TRANSPORT_get_hello' is associated with - a TIMEOUT task wherever else appropriate (other testcases - in particular!) -* hostlist + a cancel request wherever appropriate (other testcases + in particular!) [Christian] +* HOSTLIST: - test fails (looks like it works, but that's because of a bad connectivity notification; somehow core is unable to send - messages successfully via transport) + messages successfully via transport) [need transport first] * FS (basic anonymous FS only) - implement FS service (P2P operations) + how to send queries (soliciting is not there in core; do we diff --git a/src/include/gnunet_server_lib.h b/src/include/gnunet_server_lib.h index ecfead5ab..100dc9659 100644 --- a/src/include/gnunet_server_lib.h +++ b/src/include/gnunet_server_lib.h @@ -138,6 +138,8 @@ struct GNUNET_SERVER_Handle *GNUNET_SERVER_create (struct /** * Free resources held by this server. + * + * @param s server to destroy */ void GNUNET_SERVER_destroy (struct GNUNET_SERVER_Handle *s); @@ -192,6 +194,7 @@ struct GNUNET_CONNECTION_TransmitHandle * @param client client we were processing a message of * @param success GNUNET_OK to keep the connection open and * continue to receive + * GNUNET_NO to close the connection (normal behavior) * GNUNET_SYSERR to close the connection (signal * serious error) */ @@ -413,6 +416,18 @@ void GNUNET_SERVER_disconnect_notify (struct GNUNET_SERVER_Handle *server, callback, void *callback_cls); +/** + * Ask the server to stop notifying us whenever a client disconnects. + * + * @param server the server manageing the clients + * @param callback function to call on disconnect + * @param callback_cls closure for callback + */ +void GNUNET_SERVER_disconnect_notify_cancel (struct GNUNET_SERVER_Handle *server, + GNUNET_SERVER_DisconnectCallback + callback, void *callback_cls); + + /** * Ask the server to disconnect from the given client. * This is the same as returning GNUNET_SYSERR from a message @@ -440,6 +455,7 @@ GNUNET_SERVER_ignore_shutdown (struct GNUNET_SERVER_Handle *h, int do_ignore); + /** * The tansmit context is the key datastructure for a conveniance API * used for transmission of complex results to the client followed @@ -490,6 +506,81 @@ GNUNET_SERVER_transmit_context_run (struct GNUNET_SERVER_TransmitContext *tc, +/** + * The notification context is the key datastructure for a conveniance + * API used for transmission of notifications to the client until the + * client disconnects (or the notification context is destroyed, in + * which case we disconnect these clients). Essentially, all + * (notification) messages are queued up until the client is able to + * read them. + */ +struct GNUNET_SERVER_NotificationContext; + + +/** + * Create a new notification context. + * + * @param server server for which this function creates the context + * @param queue_length maximum number of messages to keep in + * the notification queue; optional messages are dropped + * it the queue gets longer than this number of messages + * @return handle to the notification context + */ +struct GNUNET_SERVER_NotificationContext * +GNUNET_SERVER_notification_context_create (struct GNUNET_SERVER_Handle *server, + unsigned int queue_length); + + +/** + * Destroy the context, force disconnect for all clients. + * + * @param nc context to destroy. + */ +void +GNUNET_SERVER_notification_context_destroy (struct GNUNET_SERVER_NotificationContext *nc); + + +/** + * Add a client to the notification context. + * + * @param nc context to modify + * @param client client to add + */ +void +GNUNET_SERVER_notification_context_add (struct GNUNET_SERVER_NotificationContext *nc, + struct GNUNET_SERVER_Client *client); + + +/** + * Send a message to a particular client; must have + * already been added to the notification context. + * + * @param nc context to modify + * @param client client to transmit to + * @param msg message to send + * @param can_drop can this message be dropped due to queue length limitations + */ +void +GNUNET_SERVER_notification_context_unicast (struct GNUNET_SERVER_NotificationContext *nc, + struct GNUNET_SERVER_Client *client, + const struct GNUNET_MessageHeader *msg, + int can_drop); + + +/** + * Send a message to all clients of this context. + * + * @param nc context to modify + * @param msg message to send + * @param can_drop can this message be dropped due to queue length limitations + */ +void +GNUNET_SERVER_notification_context_broadcast (struct GNUNET_SERVER_NotificationContext *nc, + const struct GNUNET_MessageHeader *msg, + int can_drop); + + + #if 0 /* keep Emacsens' auto-indent happy */ { #endif diff --git a/src/peerinfo/gnunet-service-peerinfo.c b/src/peerinfo/gnunet-service-peerinfo.c index f0d8b0606..2f3e2c8e1 100644 --- a/src/peerinfo/gnunet-service-peerinfo.c +++ b/src/peerinfo/gnunet-service-peerinfo.c @@ -103,6 +103,7 @@ struct PendingEntry * Entry to tell the client about. */ struct HostEntry *he; + }; @@ -131,6 +132,7 @@ struct NotifyList * Handle for a transmit ready request. */ struct GNUNET_CONNECTION_TransmitHandle *transmit_ctx; + }; diff --git a/src/util/Makefile.am b/src/util/Makefile.am index d4c35ccdb..037ab64b2 100644 --- a/src/util/Makefile.am +++ b/src/util/Makefile.am @@ -59,6 +59,7 @@ libgnunetutil_la_SOURCES = \ resolver_api.c \ scheduler.c \ server.c \ + server_nc.c \ server_tc.c \ service.c \ signal.c \ diff --git a/src/util/server.c b/src/util/server.c index 036c8a441..adc19ecb7 100644 --- a/src/util/server.c +++ b/src/util/server.c @@ -1117,6 +1117,44 @@ GNUNET_SERVER_disconnect_notify (struct GNUNET_SERVER_Handle *server, } +/** + * Ask the server to stop notifying us whenever a client disconnects. + * + * @param server the server manageing the clients + * @param callback function to call on disconnect + * @param callback_cls closure for callback + */ +void +GNUNET_SERVER_disconnect_notify_cancel (struct GNUNET_SERVER_Handle *server, + GNUNET_SERVER_DisconnectCallback callback, + void *callback_cls) +{ + struct NotifyList *pos; + struct NotifyList *prev; + + prev = NULL; + pos = server->disconnect_notify_list; + while (pos != NULL) + { + if ( (pos->callback == callback) && + (pos->callback_cls == callback_cls ) ) + break; + prev = pos; + pos = pos->next; + } + if (pos == NULL) + { + GNUNET_break (0); + return; + } + if (prev == NULL) + server->disconnect_notify_list = pos->next; + else + prev->next = pos->next; + GNUNET_free (pos); +} + + /** * Ask the server to disconnect from the given client. * This is the same as returning GNUNET_SYSERR from a message @@ -1171,6 +1209,7 @@ GNUNET_SERVER_notify_transmit_ready (struct GNUNET_SERVER_Client *client, * @param client client we were processing a message of * @param success GNUNET_OK to keep the connection open and * continue to receive + * GNUNET_NO to close the connection (normal behavior) * GNUNET_SYSERR to close the connection (signal * serious error) */ diff --git a/src/util/server_nc.c b/src/util/server_nc.c new file mode 100644 index 000000000..89e59b799 --- /dev/null +++ b/src/util/server_nc.c @@ -0,0 +1,218 @@ +/* + This file is part of GNUnet. + (C) 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 util/server_nc.c + * @brief convenience functions for transmission of + * a notification stream + * @author Christian Grothoff + */ + +#include "platform.h" +#include "gnunet_common.h" +#include "gnunet_connection_lib.h" +#include "gnunet_scheduler_lib.h" +#include "gnunet_server_lib.h" +#include "gnunet_time_lib.h" + + +struct PendingMessageList +{ + + struct PendingMessageList *next; + + const struct GNUNET_MessageHeader *msg; + + int can_drop; + +}; + + +struct ClientList +{ + + struct ClientList *next; + + struct GNUNET_SERVER_Client *client; + + struct GNUNET_CONNECTION_TransmitHandle *th; + + struct PendingMessageList *pending; + + unsigned int num_pending; + +}; + + +/** + * The notification context is the key datastructure for a conveniance + * API used for transmission of notifications to the client until the + * client disconnects (or the notification context is destroyed, in + * which case we disconnect these clients). Essentially, all + * (notification) messages are queued up until the client is able to + * read them. + */ +struct GNUNET_SERVER_NotificationContext +{ + + struct GNUNET_SERVER_Handle *server; + + struct ClientList *clients; + + unsigned int queue_length; + +}; + + +static void +handle_client_disconnect (void *cls, + struct GNUNET_SERVER_Client *client) +{ + struct GNUNET_SERVER_NotificationContext *nc = cls; + struct ClientList *pos; + struct ClientList *prev; + struct PendingMessageList *pml; + + prev = NULL; + pos = nc->clients; + while (NULL != pos) + { + if (pos->client == client) + break; + prev = pos; + pos = pos->next; + } + if (pos == NULL) + return; + if (prev == NULL) + nc->clients = pos->next; + else + prev->next = pos->next; + while (NULL != (pml = pos->pending)) + { + pos->pending = pml->next; + GNUNET_free (pml); + } + GNUNET_free (pos); +} + + +/** + * Create a new notification context. + * + * @param server server for which this function creates the context + * @param queue_length maximum number of messages to keep in + * the notification queue; optional messages are dropped + * it the queue gets longer than this number of messages + * @return handle to the notification context + */ +struct GNUNET_SERVER_NotificationContext * +GNUNET_SERVER_notification_context_create (struct GNUNET_SERVER_Handle *server, + unsigned int queue_length) +{ + struct GNUNET_SERVER_NotificationContext *ret; + + ret = GNUNET_malloc (sizeof (struct GNUNET_SERVER_NotificationContext)); + ret->server = server; + ret->queue_length = queue_length; + GNUNET_SERVER_disconnect_notify (server, + &handle_client_disconnect, + ret); + return ret; +} + + +/** + * Destroy the context, force disconnect for all clients. + * + * @param nc context to destroy. + */ +void +GNUNET_SERVER_notification_context_destroy (struct GNUNET_SERVER_NotificationContext *nc) +{ + struct ClientList *pos; + struct PendingMessageList *pml; + + while (NULL != (pos = nc->clients)) + { + nc->clients = pos->next; + GNUNET_SERVER_receive_done (pos->client, GNUNET_NO); + GNUNET_SERVER_client_drop (pos->client); + while (NULL != (pml = pos->pending)) + { + pos->pending = pml->next; + GNUNET_free (pml); + } + GNUNET_free (pos); + } + GNUNET_SERVER_disconnect_notify_cancel (nc->server, + &handle_client_disconnect, + nc); + GNUNET_free (nc); +} + + +/** + * Add a client to the notification context. + * + * @param nc context to modify + * @param client client to add + */ +void +GNUNET_SERVER_notification_context_add (struct GNUNET_SERVER_NotificationContext *nc, + struct GNUNET_SERVER_Client *client) +{ +} + + +/** + * Send a message to a particular client; must have + * already been added to the notification context. + * + * @param nc context to modify + * @param client client to transmit to + * @param msg message to send + * @param can_drop can this message be dropped due to queue length limitations + */ +void +GNUNET_SERVER_notification_context_unicast (struct GNUNET_SERVER_NotificationContext *nc, + struct GNUNET_SERVER_Client *client, + const struct GNUNET_MessageHeader *msg, + int can_drop) +{ +} + + +/** + * Send a message to all clients of this context. + * + * @param nc context to modify + * @param msg message to send + * @param can_drop can this message be dropped due to queue length limitations + */ +void +GNUNET_SERVER_notification_context_broadcast (struct GNUNET_SERVER_NotificationContext *nc, + const struct GNUNET_MessageHeader *msg, + int can_drop) +{ +} + + +/* end of server_nc.c */ -- 2.25.1