From: Christian Grothoff Date: Mon, 6 Feb 2012 09:35:56 +0000 (+0000) Subject: -applying patch from vminko to fix #1972: adding support for continuous transport... X-Git-Tag: initial-import-from-subversion-38251~14930 X-Git-Url: https://git.librecmc.org/?a=commitdiff_plain;h=7e599b44d257d9d9c6100e4050dc1eb09c9e13d2;p=oweals%2Fgnunet.git -applying patch from vminko to fix #1972: adding support for continuous transport-level connection monitoring --- diff --git a/src/transport/gnunet-service-transport.c b/src/transport/gnunet-service-transport.c index eec1684db..8b96babc3 100644 --- a/src/transport/gnunet-service-transport.c +++ b/src/transport/gnunet-service-transport.c @@ -493,6 +493,23 @@ neighbours_disconnect_notification (void *cls, } +/** + * Function called to notify transport users that a neighbour peer changed its + * active address. + * + * @param cls closure + * @param peer peer this update is about (never NULL) + * @param address address, NULL on disconnect + */ +static void +neighbours_address_notification (void *cls, + const struct GNUNET_PeerIdentity *peer, + const struct GNUNET_HELLO_Address *address) +{ + GST_clients_broadcast_address_notification (peer, address); +} + + /** * Function called when the service shuts down. Unloads our plugins * and cancels pending validations. @@ -589,8 +606,10 @@ run (void *cls, struct GNUNET_SERVER_Handle *server, &plugin_env_address_change_notification, &plugin_env_session_end, &plugin_env_address_to_type); - GST_neighbours_start (NULL, &neighbours_connect_notification, - &neighbours_disconnect_notification); + GST_neighbours_start (NULL, + &neighbours_connect_notification, + &neighbours_disconnect_notification, + &neighbours_address_notification); GST_clients_start (server); GST_validation_start (); } diff --git a/src/transport/gnunet-service-transport_clients.c b/src/transport/gnunet-service-transport_clients.c index 7ce455f7d..3cc5aac34 100644 --- a/src/transport/gnunet-service-transport_clients.c +++ b/src/transport/gnunet-service-transport_clients.c @@ -116,6 +116,35 @@ struct TransportClient }; +/** + * Client monitoring changes of active addresses of our neighbours. + */ +struct MonitoringClient +{ + /** + * This is a doubly-linked list. + */ + struct MonitoringClient *next; + + /** + * This is a doubly-linked list. + */ + struct MonitoringClient *prev; + + /** + * Handle to the client. + */ + struct GNUNET_SERVER_Client *client; + + /** + * Peer identity to monitor the addresses of. + * Zero to monitor all neighrours. + */ + struct GNUNET_PeerIdentity peer; + +}; + + /** * Head of linked list of all clients to this service. */ @@ -126,6 +155,23 @@ static struct TransportClient *clients_head; */ static struct TransportClient *clients_tail; +/** + * Head of linked list of monitoring clients. + */ +static struct MonitoringClient *monitoring_clients_head; + +/** + * Tail of linked list of monitoring clients. + */ +static struct MonitoringClient *monitoring_clients_tail; + +/** + * Notification context, to send updates on changes to active addresses + * of our neighbours. + */ +struct GNUNET_SERVER_NotificationContext *nc = NULL; + + /** * Find the internal handle associated with the given client handle * @@ -170,6 +216,60 @@ setup_client (struct GNUNET_SERVER_Client *client) } +/** + * Find the handle to the monitoring client associated with the given + * client handle + * + * @param client server's client handle to look up + * @return handle to the monitoring client + */ +static struct MonitoringClient * +lookup_monitoring_client (struct GNUNET_SERVER_Client *client) +{ + struct MonitoringClient *mc; + + mc = monitoring_clients_head; + while (mc != NULL) + { + if (mc->client == client) + return mc; + mc = mc->next; + } + return NULL; +} + + +/** + * Setup a new monitoring client using the given server client handle and + * the peer identity. + * + * @param client server's client handle to create our internal handle for + * @param peer identity of the peer to monitor the addresses of, + * zero to monitor all neighrours. + * @return handle to the new monitoring client + */ +static struct MonitoringClient * +setup_monitoring_client (struct GNUNET_SERVER_Client *client, + struct GNUNET_PeerIdentity *peer) +{ + struct MonitoringClient *mc; + + GNUNET_assert (lookup_monitoring_client (client) == NULL); + mc = GNUNET_malloc (sizeof (struct MonitoringClient)); + mc->client = client; + mc->peer = *peer; + GNUNET_CONTAINER_DLL_insert (monitoring_clients_head, + monitoring_clients_tail, + mc); + GNUNET_SERVER_notification_context_add (nc, client); + + GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, + "Client %X started monitoring of the peer `%s'\n", + mc, GNUNET_i2s (peer)); + return mc; +} + + /** * Function called to notify a client about the socket being ready to * queue more data. "buf" will be NULL and "size" zero if the socket @@ -287,10 +387,19 @@ static void client_disconnect_notification (void *cls, struct GNUNET_SERVER_Client *client) { struct TransportClient *tc; + struct MonitoringClient *mc; struct ClientMessageQueueEntry *mqe; if (client == NULL) return; + mc = lookup_monitoring_client (client); + if (mc != NULL) + { + GNUNET_CONTAINER_DLL_remove (monitoring_clients_head, + monitoring_clients_tail, + mc); + GNUNET_free (mc); + } tc = lookup_client (client); if (tc == NULL) return; @@ -689,6 +798,52 @@ clients_handle_address_to_string (void *cls, } +/** + * Compose AddressIterateResponseMessage using the given peer and address. + * + * @param peer identity of the peer + * @param address the address, NULL on disconnect + * @return composed message + */ +static struct AddressIterateResponseMessage * +compose_address_iterate_response_message (const struct GNUNET_PeerIdentity + *peer, + const struct GNUNET_HELLO_Address + *address) +{ + struct AddressIterateResponseMessage *msg; + size_t size; + size_t tlen; + size_t alen; + char *addr; + + GNUNET_assert (NULL != peer); + if (NULL != address) + { + tlen = strlen (address->transport_name) + 1; + alen = address->address_length; + } + else + tlen = alen = 0; + size = (sizeof (struct AddressIterateResponseMessage) + alen + tlen); + msg = GNUNET_malloc (size); + msg->header.size = htons (size); + msg->header.type = + htons (GNUNET_MESSAGE_TYPE_TRANSPORT_ADDRESS_ITERATE_RESPONSE); + msg->reserved = htonl (0); + msg->peer = *peer; + msg->addrlen = htonl (alen); + msg->pluginlen = htonl (tlen); + if (NULL != address) + { + addr = (char *) &msg[1]; + memcpy (addr, address->address, alen); + memcpy (&addr[alen], address->transport_name, tlen); + } + return msg; +} + + /** * Output the active address of connected neighbours to the given client. * @@ -705,34 +860,10 @@ output_address (void *cls, const struct GNUNET_PeerIdentity *peer, { struct GNUNET_SERVER_TransmitContext *tc = cls; struct AddressIterateResponseMessage *msg; - size_t size; - size_t tlen; - size_t alen; - char *addr; - tlen = strlen (address->transport_name) + 1; - alen = address->address_length; - size = (sizeof (struct AddressIterateResponseMessage) + alen + tlen); - { - char buf[size]; - - msg = (struct AddressIterateResponseMessage *) buf; - msg->reserved = htonl (0); - msg->peer = *peer; - msg->addrlen = htonl (alen); - msg->pluginlen = htonl (tlen); - addr = (char *) &msg[1]; - memcpy (addr, address->address, alen); - memcpy (&addr[alen], address->transport_name, tlen); - GNUNET_SERVER_transmit_context_append_data (tc, - &buf[sizeof - (struct - GNUNET_MessageHeader)], - size - - sizeof (struct - GNUNET_MessageHeader), - GNUNET_MESSAGE_TYPE_TRANSPORT_ADDRESS_ITERATE_RESPONSE); - } + msg = compose_address_iterate_response_message (peer, address); + GNUNET_SERVER_transmit_context_append_message (tc, &msg->header); + GNUNET_free (msg); } @@ -753,6 +884,7 @@ clients_handle_address_iterate (void *cls, struct GNUNET_SERVER_Client *client, struct GNUNET_SERVER_TransmitContext *tc; struct AddressIterateMessage *msg; struct GNUNET_HELLO_Address *address; + struct MonitoringClient *mc; if (ntohs (message->type) != GNUNET_MESSAGE_TYPE_TRANSPORT_ADDRESS_ITERATE) { @@ -767,13 +899,6 @@ clients_handle_address_iterate (void *cls, struct GNUNET_SERVER_Client *client, return; } msg = (struct AddressIterateMessage *) message; - if (GNUNET_YES != ntohl (msg->one_shot)) - { - GNUNET_log (GNUNET_ERROR_TYPE_ERROR, - "Address monitoring not implemented\n"); - GNUNET_SERVER_receive_done (client, GNUNET_SYSERR); - return; - } GNUNET_SERVER_disable_receive_done_warning (client); tc = GNUNET_SERVER_transmit_context_create (client); if (0 == memcmp (&msg->peer, &all_zeros, sizeof (struct GNUNET_PeerIdentity))) @@ -788,8 +913,24 @@ clients_handle_address_iterate (void *cls, struct GNUNET_SERVER_Client *client, if (address != NULL) output_address (tc, &msg->peer, NULL, 0, address); } + if (GNUNET_YES != ntohl (msg->one_shot)) + { + mc = lookup_monitoring_client (client); + if (mc != NULL) + { + GNUNET_log (GNUNET_ERROR_TYPE_DEBUG | GNUNET_ERROR_TYPE_BULK, + "ServerClient %X tried to start monitoring twice (MonitoringClient %X)\n", + client, mc); + GNUNET_break (0); + GNUNET_SERVER_receive_done (client, GNUNET_SYSERR); + return; + } + setup_monitoring_client (client, &msg->peer); + GNUNET_SERVER_receive_done (client, GNUNET_OK); + return; + } GNUNET_SERVER_transmit_context_append_data (tc, NULL, 0, - GNUNET_MESSAGE_TYPE_TRANSPORT_ADDRESS_ITERATE_RESPONSE); + GNUNET_MESSAGE_TYPE_TRANSPORT_ADDRESS_ITERATE_RESPONSE); GNUNET_SERVER_transmit_context_run (tc, GNUNET_TIME_UNIT_FOREVER_REL); } @@ -825,6 +966,7 @@ GST_clients_start (struct GNUNET_SERVER_Handle *server) sizeof (struct BlacklistMessage)}, {NULL, NULL, 0, 0} }; + nc = GNUNET_SERVER_notification_context_create (server, 0); GNUNET_SERVER_add_handlers (server, handlers); GNUNET_SERVER_disconnect_notify (server, &client_disconnect_notification, NULL); @@ -837,7 +979,11 @@ GST_clients_start (struct GNUNET_SERVER_Handle *server) void GST_clients_stop () { - /* nothing to do */ + if (NULL != nc) + { + GNUNET_SERVER_notification_context_destroy (nc); + nc = NULL; + } } @@ -881,4 +1027,39 @@ GST_clients_unicast (struct GNUNET_SERVER_Client *client, } +/** + * Broadcast the new active address to all clients monitoring the peer. + * + * @param peer peer this update is about (never NULL) + * @param address address, NULL on disconnect + */ +void +GST_clients_broadcast_address_notification (const struct GNUNET_PeerIdentity + *peer, + const struct GNUNET_HELLO_Address + *address) +{ + struct AddressIterateResponseMessage *msg; + struct MonitoringClient *mc; + static struct GNUNET_PeerIdentity all_zeros; + + msg = compose_address_iterate_response_message (peer, address); + mc = monitoring_clients_head; + while (mc != NULL) + { + if ((0 == memcmp (&mc->peer, &all_zeros, + sizeof (struct GNUNET_PeerIdentity))) || + (0 == memcmp (&mc->peer, peer, + sizeof (struct GNUNET_PeerIdentity)))) + { + GNUNET_SERVER_notification_context_unicast (nc, mc->client, + &msg->header, GNUNET_NO); + } + + mc = mc->next; + } + GNUNET_free (msg); +} + + /* end of file gnunet-service-transport_clients.c */ diff --git a/src/transport/gnunet-service-transport_clients.h b/src/transport/gnunet-service-transport_clients.h index d428fb257..9556620dd 100644 --- a/src/transport/gnunet-service-transport_clients.h +++ b/src/transport/gnunet-service-transport_clients.h @@ -28,6 +28,7 @@ #include "gnunet_statistics_service.h" #include "gnunet_util_lib.h" +#include "gnunet_hello_lib.h" /** @@ -68,6 +69,18 @@ GST_clients_unicast (struct GNUNET_SERVER_Client *client, const struct GNUNET_MessageHeader *msg, int may_drop); +/** + * Broadcast the new active address to all clients monitoring the peer. + * + * @param peer peer this update is about (never NULL) + * @param address address, NULL on disconnect + */ +void +GST_clients_broadcast_address_notification (const struct GNUNET_PeerIdentity + *peer, + const struct GNUNET_HELLO_Address + *address); + #endif /* end of file gnunet-service-transport_clients.h */ diff --git a/src/transport/gnunet-service-transport_neighbours.c b/src/transport/gnunet-service-transport_neighbours.c index 0f81ab7be..a6f42052c 100644 --- a/src/transport/gnunet-service-transport_neighbours.c +++ b/src/transport/gnunet-service-transport_neighbours.c @@ -357,7 +357,7 @@ struct NeighbourMapEntry static struct GNUNET_CONTAINER_MultiHashMap *neighbours; /** - * Closure for connect_notify_cb and disconnect_notify_cb + * Closure for connect_notify_cb, disconnect_notify_cb and address_change_cb */ static void *callback_cls; @@ -371,6 +371,11 @@ static GNUNET_TRANSPORT_NotifyConnect connect_notify_cb; */ static GNUNET_TRANSPORT_NotifyDisconnect disconnect_notify_cb; +/** + * Function to call when we changed an active address of a neighbour. + */ +static GNUNET_TRANSPORT_PeerIterateCallback address_change_cb; + /** * counter for connected neighbours */ @@ -492,9 +497,12 @@ reset_task (void *cls, const struct GNUNET_SCHEDULER_TaskContext *tc) static int change (struct NeighbourMapEntry *n, int state, int line) { + int previous_state; /* allowed transitions */ int allowed = GNUNET_NO; + previous_state = n->state; + switch (n->state) { case S_NOT_CONNECTED: @@ -584,7 +592,13 @@ change (struct NeighbourMapEntry *n, int state, int line) GNUNET_assert (0); } - + if (NULL != address_change_cb) + { + if (n->state == S_CONNECTED) + address_change_cb (callback_cls, &n->id, n->address); + else if (previous_state == S_CONNECTED) + address_change_cb (callback_cls, &n->id, NULL); + } return GNUNET_OK; } @@ -839,14 +853,19 @@ transmission_task (void *cls, const struct GNUNET_SCHEDULER_TaskContext *tc) * @param cls closure for callbacks * @param connect_cb function to call if we connect to a peer * @param disconnect_cb function to call if we disconnect from a peer + * @param address_cb function to call if we change an active address + * of a neighbour */ void -GST_neighbours_start (void *cls, GNUNET_TRANSPORT_NotifyConnect connect_cb, - GNUNET_TRANSPORT_NotifyDisconnect disconnect_cb) +GST_neighbours_start (void *cls, + GNUNET_TRANSPORT_NotifyConnect connect_cb, + GNUNET_TRANSPORT_NotifyDisconnect disconnect_cb, + GNUNET_TRANSPORT_PeerIterateCallback address_cb) { callback_cls = cls; connect_notify_cb = connect_cb; disconnect_notify_cb = disconnect_cb; + address_change_cb = address_cb; neighbours = GNUNET_CONTAINER_multihashmap_create (NEIGHBOUR_TABLE_SIZE); } @@ -1164,6 +1183,7 @@ GST_neighbours_stop () callback_cls = NULL; connect_notify_cb = NULL; disconnect_notify_cb = NULL; + address_change_cb = NULL; } struct ContinutionContext @@ -1496,7 +1516,6 @@ GST_neighbours_switch_to_address (const struct GNUNET_PeerIdentity *peer, GNUNET_ATS_address_in_use (GST_ats, n->address, n->session, GNUNET_NO); n->address_state = UNUSED; } - } /* set new address */ @@ -1511,6 +1530,9 @@ GST_neighbours_switch_to_address (const struct GNUNET_PeerIdentity *peer, GNUNET_SCHEDULER_add_delayed (GNUNET_CONSTANTS_IDLE_CONNECTION_TIMEOUT, &neighbour_timeout_task, n); + if (NULL != address_change_cb && n->state == S_CONNECTED) + address_change_cb (callback_cls, &n->id, n->address); + #if TEST_NEW_CODE /* Obtain an session for this address from plugin */ struct GNUNET_TRANSPORT_PluginFunctions *papi; diff --git a/src/transport/gnunet-service-transport_neighbours.h b/src/transport/gnunet-service-transport_neighbours.h index 425274f79..f6e599db1 100644 --- a/src/transport/gnunet-service-transport_neighbours.h +++ b/src/transport/gnunet-service-transport_neighbours.h @@ -42,10 +42,13 @@ * @param cls closure for callbacks * @param connect_cb function to call if we connect to a peer * @param disconnect_cb function to call if we disconnect from a peer + * @param peer_address_cb function to call if a neighbour's active address changes */ void -GST_neighbours_start (void *cls, GNUNET_TRANSPORT_NotifyConnect connect_cb, - GNUNET_TRANSPORT_NotifyDisconnect disconnect_cb); +GST_neighbours_start (void *cls, + GNUNET_TRANSPORT_NotifyConnect connect_cb, + GNUNET_TRANSPORT_NotifyDisconnect disconnect_cb, + GNUNET_TRANSPORT_PeerIterateCallback peer_address_cb); /** diff --git a/src/transport/transport_api_address_lookup.c b/src/transport/transport_api_address_lookup.c index 9ae9b4031..a21daab5e 100644 --- a/src/transport/transport_api_address_lookup.c +++ b/src/transport/transport_api_address_lookup.c @@ -103,9 +103,7 @@ peer_address_response_processor (void *cls, return; } - if ((size < - sizeof (struct GNUNET_MessageHeader) + - sizeof (struct AddressIterateResponseMessage)) || + if ((size < sizeof (struct AddressIterateResponseMessage)) || (ntohs (msg->type) != GNUNET_MESSAGE_TYPE_TRANSPORT_ADDRESS_ITERATE_RESPONSE)) { @@ -127,28 +125,35 @@ peer_address_response_processor (void *cls, return; } - addr = (const char *) &air_msg[1]; - transport_name = &addr[alen]; - - if (transport_name[tlen - 1] != '\0') + if (alen == 0 && tlen == 0) { - GNUNET_break_op (0); - pal_ctx->cb (pal_ctx->cb_cls, NULL, NULL); - GNUNET_TRANSPORT_peer_get_active_addresses_cancel (pal_ctx); - return; + pal_ctx->cb (pal_ctx->cb_cls, &air_msg->peer, NULL); + } + else + { + addr = (const char *) &air_msg[1]; + transport_name = &addr[alen]; + + if (transport_name[tlen - 1] != '\0') + { + GNUNET_break_op (0); + pal_ctx->cb (pal_ctx->cb_cls, NULL, NULL); + GNUNET_TRANSPORT_peer_get_active_addresses_cancel (pal_ctx); + return; + } + + /* notify client */ + address = + GNUNET_HELLO_address_allocate (&air_msg->peer, transport_name, addr, + alen); + pal_ctx->cb (pal_ctx->cb_cls, &air_msg->peer, address); + GNUNET_HELLO_address_free (address); } /* expect more replies */ GNUNET_CLIENT_receive (pal_ctx->client, &peer_address_response_processor, pal_ctx, GNUNET_TIME_absolute_get_remaining (pal_ctx->timeout)); - - /* notify client */ - address = - GNUNET_HELLO_address_allocate (&air_msg->peer, transport_name, addr, - alen); - pal_ctx->cb (pal_ctx->cb_cls, &air_msg->peer, address); - GNUNET_HELLO_address_free (address); } @@ -165,7 +170,7 @@ peer_address_response_processor (void *cls, * @param peer peer identity to look up the addresses of, CHANGE: allow NULL for all (connected) peers * @param one_shot GNUNET_YES to return the current state and then end (with NULL+NULL), * GNUNET_NO to monitor the set of addresses used (continuously, must be explicitly cancelled) - * @param timeout how long is the lookup allowed to take at most + * @param timeout how long is the lookup allowed to take at most (irrelevant if one_shot is set to GNUNET_NO) * @param peer_address_callback function to call with the results * @param peer_address_callback_cls closure for peer_address_callback */ @@ -184,15 +189,11 @@ GNUNET_TRANSPORT_peer_get_active_addresses (const struct struct GNUNET_CLIENT_Connection *client; struct GNUNET_TIME_Absolute abs_timeout; - if (GNUNET_YES != one_shot) - { - GNUNET_log (GNUNET_ERROR_TYPE_ERROR, - "Address monitoring not implemented\n"); - return NULL; - } client = GNUNET_CLIENT_connect ("transport", cfg); if (client == NULL) return NULL; + if (GNUNET_YES != one_shot) + timeout = GNUNET_TIME_UNIT_FOREVER_REL; abs_timeout = GNUNET_TIME_relative_to_absolute (timeout); msg.header.size = htons (sizeof (struct AddressIterateMessage)); msg.header.type = htons (GNUNET_MESSAGE_TYPE_TRANSPORT_ADDRESS_ITERATE);