From 87487477c67697355c79d2fe079d23a5b31c7ab6 Mon Sep 17 00:00:00 2001 From: Christian Grothoff Date: Fri, 22 Jan 2010 15:14:39 +0000 Subject: [PATCH] updates to peerinfo to use new nc API --- TODO | 7 +- src/core/gnunet-service-core.c | 2 + src/datastore/gnunet-service-datastore.c | 2 + src/fs/gnunet-service-fs.c | 2 + src/include/gnunet_server_lib.h | 9 +- src/peerinfo/gnunet-service-peerinfo.c | 259 +++++------------------ src/transport/gnunet-service-transport.c | 2 + src/transport/plugin_transport_tcp.c | 2 + src/util/server.c | 1 + src/util/server_nc.c | 12 +- src/util/test_server_disconnect.c | 2 + src/util/test_server_with_client.c | 2 + 12 files changed, 91 insertions(+), 211 deletions(-) diff --git a/TODO b/TODO index 992f61f80..cfeec44d1 100644 --- a/TODO +++ b/TODO @@ -18,8 +18,8 @@ Urgent items (before announcing ng.gnunet.org): 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) + (transport (our hello), + core (misc monitoring features) and likely others) - server/service API change for ARM inetd'ing (listen as well as support for start with multiple, already @@ -66,7 +66,8 @@ Urgent items (before announcing ng.gnunet.org): (async peerinfo would not be right) - OS: existing waitpid call is not nice (not integratable with scheduler! fix this!) * STATISTICS: - - synchronous/asynchronous API (& implementation) is not nice + - synchronous/asynchronous API (& implementation) is not nice; + => provide notification-based API - does not seem to work with timeouts (especially if service is not running) * ARM: - need to get rid of synchronous API for service starts (cause all kinds of problems) diff --git a/src/core/gnunet-service-core.c b/src/core/gnunet-service-core.c index 32b39fd7f..915217ea1 100644 --- a/src/core/gnunet-service-core.c +++ b/src/core/gnunet-service-core.c @@ -1034,6 +1034,8 @@ handle_client_disconnect (void *cls, struct GNUNET_SERVER_Client *client) struct Client *prev; struct Event *e; + if (client == NULL) + return; #if DEBUG_CORE_CLIENT GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "Client has disconnected from core service.\n"); diff --git a/src/datastore/gnunet-service-datastore.c b/src/datastore/gnunet-service-datastore.c index 1766ef96c..161fbc1d8 100644 --- a/src/datastore/gnunet-service-datastore.c +++ b/src/datastore/gnunet-service-datastore.c @@ -1233,6 +1233,8 @@ cleanup_reservations (void *cls, struct ReservationList *prev; struct ReservationList *next; + if (client == NULL) + return; prev = NULL; pos = reservations; while (NULL != pos) diff --git a/src/fs/gnunet-service-fs.c b/src/fs/gnunet-service-fs.c index 541f656c6..b8855632c 100644 --- a/src/fs/gnunet-service-fs.c +++ b/src/fs/gnunet-service-fs.c @@ -2273,6 +2273,8 @@ handle_client_disconnect (void *cls, struct ClientList *cprev; struct ClientRequestList *rl; + if (client == NULL) + return; lgc = lgc_head; while ( (NULL != lgc) && (lgc->client != client) ) diff --git a/src/include/gnunet_server_lib.h b/src/include/gnunet_server_lib.h index 100dc9659..5609d7a9e 100644 --- a/src/include/gnunet_server_lib.h +++ b/src/include/gnunet_server_lib.h @@ -394,7 +394,8 @@ int GNUNET_SERVER_client_get_address (struct GNUNET_SERVER_Client *client, * is disconnected on the network level. * * @param cls closure - * @param client identification of the client + * @param client identification of the client; NULL + * for the last call when the server is destroyed */ typedef void (*GNUNET_SERVER_DisconnectCallback) (void *cls, struct GNUNET_SERVER_Client @@ -405,7 +406,11 @@ typedef void (*GNUNET_SERVER_DisconnectCallback) (void *cls, * Ask the server to notify us whenever a client disconnects. * This function is called whenever the actual network connection * is closed; the reference count may be zero or larger than zero - * at this point. + * at this point. If the server is destroyed before this + * notification is explicitly cancelled, the 'callback' will + * once be called with a 'client' argument of NULL to indicate + * that the server itself is now gone (and that the callback + * won't be called anymore and also can no longer be cancelled). * * @param server the server manageing the clients * @param callback function to call on disconnect diff --git a/src/peerinfo/gnunet-service-peerinfo.c b/src/peerinfo/gnunet-service-peerinfo.c index 2f3e2c8e1..5b2b999d6 100644 --- a/src/peerinfo/gnunet-service-peerinfo.c +++ b/src/peerinfo/gnunet-service-peerinfo.c @@ -88,54 +88,6 @@ struct HostEntry }; -/** - * Entries that we still need to tell the client about. - */ -struct PendingEntry -{ - - /** - * This is a linked list. - */ - struct PendingEntry *next; - - /** - * Entry to tell the client about. - */ - struct HostEntry *he; - -}; - - -/** - * Clients to notify of changes to the peer information. - */ -struct NotifyList -{ - - /** - * This is a linked list. - */ - struct NotifyList *next; - - /** - * Client to notify. - */ - struct GNUNET_SERVER_Client *client; - - /** - * Notifications pending for this entry. - */ - struct PendingEntry *pending; - - /** - * Handle for a transmit ready request. - */ - struct GNUNET_CONNECTION_TransmitHandle *transmit_ctx; - -}; - - /** * The in-memory list of known hosts. */ @@ -144,7 +96,7 @@ static struct HostEntry *hosts; /** * Clients to immediately notify about all changes. */ -static struct NotifyList *notify_list; +static struct GNUNET_SERVER_NotificationContext *notify_list; /** * Directory where the hellos are stored in (data/hosts) @@ -157,117 +109,24 @@ static char *networkIdDirectory; static char *trustDirectory; -/** - * Transmit peer information messages from the pending queue - * to the client. - * - * @param cls the 'struct NotifyList' that we are processing - * @param size number of bytes we can transmit - * @param vbuf where to write the messages - * @return number of bytes written to vbuf - */ -static size_t -transmit_pending_notification (void *cls, - size_t size, - void *vbuf) -{ - struct NotifyList *nl = cls; - char *buf = vbuf; - struct PendingEntry *pos; - struct PendingEntry *next; - struct InfoMessage im; - uint16_t hs; - size_t left; - - nl->transmit_ctx = NULL; - next = nl->pending; - pos = nl->pending; - left = size; - while (pos != NULL) - { - hs = (pos->he->hello == NULL) ? 0 : GNUNET_HELLO_size (pos->he->hello); - if (left < sizeof (struct InfoMessage) + hs) - break; - next = pos->next; - im.header.size = htons (hs + sizeof (struct InfoMessage)); - im.header.type = htons (GNUNET_MESSAGE_TYPE_PEERINFO_INFO); - im.trust = htonl (pos->he->trust); - im.peer = pos->he->identity; - memcpy (&buf[size - left], &im, sizeof (struct InfoMessage)); - memcpy (&buf[size - left + sizeof (struct InfoMessage)], pos->he->hello, hs); - left -= hs + sizeof (struct InfoMessage); - GNUNET_free (pos); - pos = next; - } - nl->pending = next; - if (nl->pending != NULL) - { - nl->transmit_ctx - = GNUNET_SERVER_notify_transmit_ready (nl->client, - sizeof (struct InfoMessage) + hs, - GNUNET_TIME_UNIT_FOREVER_REL, - &transmit_pending_notification, - nl); - } - return size - left; -} - - - -/** - * Notify client about host change. Checks if the - * respective host entry is already in the list of things - * to send to the client, and if not, adds it. Also - * triggers a new request for transmission if the pending - * list was previously empty. - * - * @param nl client to notify - * @param he entry to notify about - */ -static void -do_notify (struct NotifyList *nl, - struct HostEntry *he) -{ - struct PendingEntry *pe; - uint16_t hsize; - - pe = nl->pending; - while (NULL != pe) - { - if (pe->he == he) - return; /* already in list */ - pe = pe->next; - } - pe = GNUNET_malloc (sizeof (struct PendingEntry)); - pe->next = nl->pending; - pe->he = he; - nl->pending = pe; - if (nl->transmit_ctx != NULL) - return; /* already trying to transmit */ - hsize = (he->hello == NULL) ? 0 : GNUNET_HELLO_size (he->hello); - nl->transmit_ctx = GNUNET_SERVER_notify_transmit_ready (nl->client, - sizeof (struct InfoMessage) + hsize, - GNUNET_TIME_UNIT_FOREVER_REL, - &transmit_pending_notification, - nl); -} - - /** * Notify all clients in the notify list about the * given host entry changing. */ -static void -notify_all (struct HostEntry *he) +static struct InfoMessage * +make_info_message (const struct HostEntry *he) { - struct NotifyList *nl; - - nl = notify_list; - while (NULL != nl) - { - do_notify (nl, he); - nl = nl->next; - } + struct InfoMessage *im; + size_t hs; + + hs = (he->hello == NULL) ? 0 : GNUNET_HELLO_size (he->hello); + im = GNUNET_malloc (sizeof (struct InfoMessage) + hs); + im->header.size = htons (hs + sizeof (struct InfoMessage)); + im->header.type = htons (GNUNET_MESSAGE_TYPE_PEERINFO_INFO); + im->trust = htonl (he->trust); + im->peer = he->identity; + memcpy (&im[1], he->hello, hs); + return im; } @@ -328,6 +187,7 @@ get_trust_filename (const struct GNUNET_PeerIdentity *id) return fn; } + /** * Find the host entry for the given peer. Call * only when synchronized! @@ -347,6 +207,25 @@ lookup_host_entry (const struct GNUNET_PeerIdentity *id) } +/** + * Broadcast information about the given entry to all + * clients that care. + * + * @param entry entry to broadcast about + */ +static void +notify_all (struct HostEntry *entry) +{ + struct InfoMessage *msg; + + msg = make_info_message (entry); + GNUNET_SERVER_notification_context_broadcast (notify_list, + &msg->header, + GNUNET_NO); + GNUNET_free (msg); +} + + /** * Add a host to the list. * @@ -451,7 +330,7 @@ change_host_trust (const struct GNUNET_PeerIdentity *hostId, int value) host->trust += value; } if (host->trust != old_trust) - notify_all (host); + notify_all (host); return value; } @@ -834,18 +713,20 @@ handle_notify (void *cls, struct GNUNET_SERVER_Client *client, const struct GNUNET_MessageHeader *message) { - struct NotifyList *nl; + struct InfoMessage *msg; struct HostEntry *pos; - nl = GNUNET_malloc (sizeof (struct NotifyList)); - nl->next = notify_list; - nl->client = client; - GNUNET_SERVER_client_keep (client); - notify_list = nl; + GNUNET_SERVER_notification_context_add (notify_list, + client); pos = hosts; while (NULL != pos) { - do_notify (nl, pos); + msg = make_info_message (pos); + GNUNET_SERVER_notification_context_unicast (notify_list, + client, + &msg->header, + GNUNET_NO); + GNUNET_free (msg); pos = pos->next; } } @@ -868,48 +749,17 @@ static struct GNUNET_SERVER_MessageHandler handlers[] = { /** - * Function that is called when a client disconnects. + * Clean up our state. Called during shutdown. + * + * @param cls unused + * @param tc scheduler task context, unused */ static void -notify_disconnect (void *cls, - struct GNUNET_SERVER_Client *client) +shutdown_task (void *cls, + const struct GNUNET_SCHEDULER_TaskContext *tc) { - struct NotifyList *pos; - struct NotifyList *prev; - struct NotifyList *next; - struct PendingEntry *p; - - pos = notify_list; - prev = NULL; - while (pos != NULL) - { - next = pos->next; - if (pos->client == client) - { - while (NULL != (p = pos->pending)) - { - pos->pending = p->next; - GNUNET_free (p); - } - if (pos->transmit_ctx != NULL) - { - GNUNET_CONNECTION_notify_transmit_ready_cancel (pos->transmit_ctx); - pos->transmit_ctx = NULL; - } - if (prev == NULL) - notify_list = next; - else - prev->next = next; - GNUNET_SERVER_client_drop (client); - GNUNET_free (pos); - } - else - { - prev = pos; - } - pos = next; - } - + GNUNET_SERVER_notification_context_destroy (notify_list); + notify_list = NULL; } @@ -927,6 +777,7 @@ run (void *cls, struct GNUNET_SERVER_Handle *server, const struct GNUNET_CONFIGURATION_Handle *cfg) { + notify_list = GNUNET_SERVER_notification_context_create (server, 0); GNUNET_assert (GNUNET_OK == GNUNET_CONFIGURATION_get_value_filename (cfg, "peerinfo", @@ -948,7 +799,9 @@ run (void *cls, GNUNET_SCHEDULER_add_with_priority (sched, GNUNET_SCHEDULER_PRIORITY_IDLE, &cron_clean_data_hosts, NULL); - GNUNET_SERVER_disconnect_notify (server, ¬ify_disconnect, NULL); + GNUNET_SCHEDULER_add_delayed (sched, + GNUNET_TIME_UNIT_FOREVER_REL, + &shutdown_task, NULL); GNUNET_SERVER_add_handlers (server, handlers); } diff --git a/src/transport/gnunet-service-transport.c b/src/transport/gnunet-service-transport.c index b05e8360a..fe8b5043e 100644 --- a/src/transport/gnunet-service-transport.c +++ b/src/transport/gnunet-service-transport.c @@ -2743,6 +2743,8 @@ client_disconnect_notification (void *cls, struct TransportClient *prev; struct ClientMessageQueueEntry *mqe; + if (client == NULL) + return; #if DEBUG_TRANSPORT GNUNET_log (GNUNET_ERROR_TYPE_DEBUG | GNUNET_ERROR_TYPE_BULK, "Client disconnected, cleaning up.\n"); diff --git a/src/transport/plugin_transport_tcp.c b/src/transport/plugin_transport_tcp.c index 23ed867b7..51b1ce5e1 100644 --- a/src/transport/plugin_transport_tcp.c +++ b/src/transport/plugin_transport_tcp.c @@ -1146,6 +1146,8 @@ disconnect_notify (void *cls, struct GNUNET_SERVER_Client *client) struct Plugin *plugin = cls; struct Session *session; + if (client == NULL) + return; session = find_session_by_client (plugin, client); if (session == NULL) return; /* unknown, nothing to do */ diff --git a/src/util/server.c b/src/util/server.c index adc19ecb7..6f2ffe232 100644 --- a/src/util/server.c +++ b/src/util/server.c @@ -538,6 +538,7 @@ GNUNET_SERVER_destroy (struct GNUNET_SERVER_Handle *s) } while (NULL != (npos = s->disconnect_notify_list)) { + npos->callback (npos->callback_cls, NULL); s->disconnect_notify_list = npos->next; GNUNET_free (npos); } diff --git a/src/util/server_nc.c b/src/util/server_nc.c index 9b6eefe1f..05a4913a8 100644 --- a/src/util/server_nc.c +++ b/src/util/server_nc.c @@ -146,6 +146,11 @@ handle_client_disconnect (void *cls, struct ClientList *prev; struct PendingMessageList *pml; + if (client == NULL) + { + nc->server = NULL; + return; + } prev = NULL; pos = nc->clients; while (NULL != pos) @@ -219,9 +224,10 @@ GNUNET_SERVER_notification_context_destroy (struct GNUNET_SERVER_NotificationCon } GNUNET_free (pos); } - GNUNET_SERVER_disconnect_notify_cancel (nc->server, - &handle_client_disconnect, - nc); + if (nc->server != NULL) + GNUNET_SERVER_disconnect_notify_cancel (nc->server, + &handle_client_disconnect, + nc); GNUNET_free (nc); } diff --git a/src/util/test_server_disconnect.c b/src/util/test_server_disconnect.c index 76a73d348..b10719e73 100644 --- a/src/util/test_server_disconnect.c +++ b/src/util/test_server_disconnect.c @@ -138,6 +138,8 @@ disconnect_notify (void *cls, const struct GNUNET_MessageHeader *msg) static void notify_disconnect (void *cls, struct GNUNET_SERVER_Client *clientarg) { + if (clientarg == NULL) + return; GNUNET_assert (ok == 6); ok++; GNUNET_CLIENT_receive (client, diff --git a/src/util/test_server_with_client.c b/src/util/test_server_with_client.c index 68b842ef8..adce0b432 100644 --- a/src/util/test_server_with_client.c +++ b/src/util/test_server_with_client.c @@ -123,6 +123,8 @@ clean_up (void *cls, const struct GNUNET_SCHEDULER_TaskContext *tc) static void notify_disconnect (void *cls, struct GNUNET_SERVER_Client *client) { + if (client == NULL) + return; GNUNET_assert (ok == 5); ok = 0; GNUNET_SCHEDULER_add_now (sched, -- 2.25.1