From: Matthias Wachs Date: Wed, 15 Jan 2014 17:18:11 +0000 (+0000) Subject: transport validation monitoring API (not yet complete) + CLI X-Git-Tag: initial-import-from-subversion-38251~5032 X-Git-Url: https://git.librecmc.org/?a=commitdiff_plain;h=2368c95a00afc72a8f03ab67bca1ff41328eecdf;p=oweals%2Fgnunet.git transport validation monitoring API (not yet complete) + CLI + fix for crash in transport/plugin_transport_udp.c --- diff --git a/src/transport/Makefile.am b/src/transport/Makefile.am index 76dc50af9..acfaa9403 100644 --- a/src/transport/Makefile.am +++ b/src/transport/Makefile.am @@ -408,6 +408,7 @@ check_PROGRAMS = \ $(BT_TIMEOUT_TEST) \ test_transport_api_multi \ test_transport_api_monitoring \ + test_transport_api_monitoring_validation \ test_transport_blacklisting_no_bl \ test_transport_blacklisting_outbound_bl_full \ test_transport_blacklisting_outbound_bl_plugin \ @@ -473,6 +474,7 @@ TESTS = \ $(BT_TIMEOUT_TEST) \ test_transport_api_multi \ test_transport_api_monitoring \ + test_transport_api_monitoring_validation \ test_transport_blacklisting_no_bl \ test_transport_blacklisting_outbound_bl_full \ test_transport_blacklisting_outbound_bl_plugin \ @@ -1100,7 +1102,6 @@ test_transport_api_multi_LDADD = \ $(top_builddir)/src/util/libgnunetutil.la \ $(top_builddir)/src/transport/libgnunettransporttesting.la - test_transport_api_monitoring_SOURCES = \ test_transport_api_monitoring.c test_transport_api_monitoring_LDADD = \ @@ -1109,6 +1110,14 @@ test_transport_api_monitoring_LDADD = \ $(top_builddir)/src/util/libgnunetutil.la \ $(top_builddir)/src/transport/libgnunettransporttesting.la +test_transport_api_monitoring_validation_SOURCES = \ + test_transport_api_monitoring_validation.c +test_transport_api_monitoring_validation_LDADD = \ + $(top_builddir)/src/transport/libgnunettransport.la \ + $(top_builddir)/src/hello/libgnunethello.la \ + $(top_builddir)/src/util/libgnunetutil.la \ + $(top_builddir)/src/transport/libgnunettransporttesting.la + EXTRA_DIST = \ test_plugin_hostkey \ @@ -1207,6 +1216,8 @@ test_transport_api_bluetooth_peer1.conf\ test_transport_api_bluetooth_peer2.conf\ test_transport_api_monitoring_peer1.conf\ test_transport_api_monitoring_peer2.conf\ +test_transport_api_monitoring_validation_peer1.conf\ +test_transport_api_monitoring_validation_peer2.conf\ test_transport_defaults.conf\ test_transport_startonly.conf\ test_transport_api_disconnect_tcp_peer1.conf\ diff --git a/src/transport/gnunet-service-transport.c b/src/transport/gnunet-service-transport.c index d52d6ab69..66f177145 100644 --- a/src/transport/gnunet-service-transport.c +++ b/src/transport/gnunet-service-transport.c @@ -764,12 +764,42 @@ neighbours_changed_notification (void *cls, "Notifying about change for peer `%s' with address `%s' in state `%s' timing out at %s\n", GNUNET_i2s (peer), (NULL != address) ? GST_plugins_a2s (address) : "", - GNUNET_TRANSPORT_p2s (state), + GNUNET_TRANSPORT_ps2s (state), GNUNET_STRINGS_absolute_time_to_string (state_timeout)); GST_clients_broadcast_peer_notification (peer, address, state, state_timeout); } +/** + * 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 + * @param state current state this peer is in + * @param state_timeout timeout for the current state of the peer + * @param bandwidth_in bandwidth assigned inbound + * @param bandwidth_out bandwidth assigned outbound + */ +static void +validation_changed_notification (void *cls, + const struct GNUNET_PeerIdentity *peer, + const struct GNUNET_HELLO_Address *address, + struct GNUNET_TIME_Absolute last_validation, + struct GNUNET_TIME_Absolute valid_until, + struct GNUNET_TIME_Absolute next_validation, + enum GNUNET_TRANSPORT_ValidationState state) +{ + GNUNET_log(GNUNET_ERROR_TYPE_DEBUG, + "Notifying about change for for validation entry for peer `%s' with address `%s'\n", + GNUNET_i2s (peer), + (NULL != address) ? GST_plugins_a2s (address) : ""); + + GST_clients_broadcast_validation_notification (peer, address, + last_validation, valid_until, next_validation, state); +} + /** * Function called when the service shuts down. Unloads our plugins * and cancels pending validations. @@ -918,7 +948,7 @@ run (void *cls, struct GNUNET_SERVER_Handle *server, &neighbours_disconnect_notification, &neighbours_changed_notification, (max_fd / 3) * 2); GST_clients_start (GST_server); - GST_validation_start ((max_fd / 3)); + GST_validation_start (&validation_changed_notification, NULL, (max_fd / 3)); } /** diff --git a/src/transport/gnunet-service-transport_clients.c b/src/transport/gnunet-service-transport_clients.c index ca7a40539..fb848d0af 100644 --- a/src/transport/gnunet-service-transport_clients.c +++ b/src/transport/gnunet-service-transport_clients.c @@ -190,19 +190,34 @@ struct AddressToStringContext *a2s_tail; /** * Head of linked list of monitoring clients. */ -static struct MonitoringClient *monitoring_clients_head; +static struct MonitoringClient *peer_monitoring_clients_head; /** * Tail of linked list of monitoring clients. */ -static struct MonitoringClient *monitoring_clients_tail; +static struct MonitoringClient *peer_monitoring_clients_tail; + +/** + * Head of linked list of validation monitoring clients. + */ +static struct MonitoringClient *val_monitoring_clients_head; + +/** + * Tail of linked list of validation monitoring clients. + */ +static struct MonitoringClient *val_monitoring_clients_tail; /** * Notification context, to send updates on changes to active addresses * of our neighbours. */ -static struct GNUNET_SERVER_NotificationContext *nc; +static struct GNUNET_SERVER_NotificationContext *peer_nc; +/** + * Notification context, to send updates on changes to active addresses + * of our neighbours. + */ +static struct GNUNET_SERVER_NotificationContext *val_nc; /** * Find the internal handle associated with the given client handle @@ -251,11 +266,12 @@ setup_client (struct GNUNET_SERVER_Client *client) * @return handle to the monitoring client */ static struct MonitoringClient * -lookup_monitoring_client (struct GNUNET_SERVER_Client *client) +lookup_monitoring_client (struct MonitoringClient *head, + struct GNUNET_SERVER_Client *client) { struct MonitoringClient *mc; - for (mc = monitoring_clients_head; NULL != mc; mc = mc->next) + for (mc = head; NULL != mc; mc = mc->next) if (mc->client == client) return mc; return NULL; @@ -272,27 +288,58 @@ lookup_monitoring_client (struct GNUNET_SERVER_Client *client) * @return handle to the new monitoring client */ static struct MonitoringClient * -setup_monitoring_client (struct GNUNET_SERVER_Client *client, +setup_peer_monitoring_client (struct GNUNET_SERVER_Client *client, struct GNUNET_PeerIdentity *peer) { struct MonitoringClient *mc; static struct GNUNET_PeerIdentity all_zeros; - GNUNET_assert (lookup_monitoring_client (client) == NULL); + GNUNET_assert (lookup_monitoring_client (peer_monitoring_clients_head, client) == NULL); mc = GNUNET_new (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_CONTAINER_DLL_insert (peer_monitoring_clients_head, peer_monitoring_clients_tail, mc); + GNUNET_SERVER_notification_context_add (peer_nc, client); if (0 != memcmp (peer, &all_zeros, sizeof (struct GNUNET_PeerIdentity))) - GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, + GNUNET_log (GNUNET_ERROR_TYPE_INFO, "Client %p started monitoring of the peer `%s'\n", mc, GNUNET_i2s (peer)); else - GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, + GNUNET_log (GNUNET_ERROR_TYPE_INFO, + "Client %p started monitoring all peers\n", mc); + return mc; +} + +/** + * 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_val_monitoring_client (struct GNUNET_SERVER_Client *client, + struct GNUNET_PeerIdentity *peer) +{ + struct MonitoringClient *mc; + static struct GNUNET_PeerIdentity all_zeros; + + GNUNET_assert (lookup_monitoring_client (val_monitoring_clients_head, client) == NULL); + mc = GNUNET_new (struct MonitoringClient); + mc->client = client; + mc->peer = *peer; + GNUNET_CONTAINER_DLL_insert (val_monitoring_clients_head, val_monitoring_clients_tail, mc); + GNUNET_SERVER_notification_context_add (val_nc, client); + + if (0 != memcmp (peer, &all_zeros, sizeof (struct GNUNET_PeerIdentity))) + GNUNET_log (GNUNET_ERROR_TYPE_INFO, + "Client %p started monitoring of the peer `%s'\n", + mc, GNUNET_i2s (peer)); + else + GNUNET_log (GNUNET_ERROR_TYPE_INFO, "Client %p started monitoring all peers\n", mc); return mc; } @@ -425,11 +472,19 @@ client_disconnect_notification (void *cls, struct GNUNET_SERVER_Client *client) if (client == NULL) return; - mc = lookup_monitoring_client (client); + mc = lookup_monitoring_client (peer_monitoring_clients_head, client); if (mc != NULL) { - GNUNET_CONTAINER_DLL_remove (monitoring_clients_head, - monitoring_clients_tail, + GNUNET_CONTAINER_DLL_remove (peer_monitoring_clients_head, + peer_monitoring_clients_tail, + mc); + GNUNET_free (mc); + } + mc = lookup_monitoring_client (val_monitoring_clients_head, client); + if (mc != NULL) + { + GNUNET_CONTAINER_DLL_remove (val_monitoring_clients_head, + val_monitoring_clients_tail, mc); GNUNET_free (mc); } @@ -852,7 +907,7 @@ clients_handle_address_to_string (void *cls, /** - * Compose AddressIterateResponseMessage using the given peer and address. + * Compose #PeerIterateResponseMessage using the given peer and address. * * @param peer identity of the peer * @param address the address, NULL on disconnect @@ -896,8 +951,52 @@ compose_address_iterate_response_message (const struct GNUNET_PeerIdentity *peer return msg; } +/** + * Compose #PeerIterateResponseMessage using the given peer and address. + * + * @param peer identity of the peer + * @param address the address, NULL on disconnect + * @return composed message + */ +static struct ValidationIterateResponseMessage * +compose_validation_iterate_response_message (const struct GNUNET_PeerIdentity *peer, + const struct GNUNET_HELLO_Address *address) +{ + struct ValidationIterateResponseMessage *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 ValidationIterateResponseMessage) + alen + tlen); + msg = GNUNET_malloc (size); + msg->header.size = htons (size); + msg->header.type = + htons (GNUNET_MESSAGE_TYPE_TRANSPORT_MONITOR_VALIDATION_RESPONSE); + msg->reserved = htonl (0); + msg->peer = *peer; + msg->addrlen = htonl (alen); + msg->pluginlen = htonl (tlen); + + if (NULL != address) + { + msg->local_address_info = htonl((uint32_t) address->local_info); + addr = (char *) &msg[1]; + memcpy (addr, address->address, alen); + memcpy (&addr[alen], address->transport_name, tlen); + } + return msg; +} -struct PeerIterationContext +struct IterationContext { struct GNUNET_SERVER_TransmitContext *tc; @@ -906,6 +1005,46 @@ struct PeerIterationContext int all; }; +/** + * Output information of neighbours to the given client. + * + * @param cls the 'struct PeerIterationContext' + * @param peer identity of the neighbour + * @param address the address + * @param state current state this peer is in + * @param state_timeout timeout for the current state of the peer + * @param bandwidth_in inbound quota in NBO + * @param bandwidth_out outbound quota in NBO + */ +static void +send_validation_information (void *cls, + const struct GNUNET_PeerIdentity *peer, + const struct GNUNET_HELLO_Address *address, + struct GNUNET_TIME_Absolute last_validation, + struct GNUNET_TIME_Absolute valid_until, + struct GNUNET_TIME_Absolute next_validation, + enum GNUNET_TRANSPORT_ValidationState state) +{ + struct IterationContext *pc = cls; + struct ValidationIterateResponseMessage *msg; + + if ( (GNUNET_YES == pc->all) || + (0 == memcmp (peer, &pc->id, sizeof (pc->id))) ) + { + GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, + "Sending information about for validation entry for peer `%s' using address `%s'\n", + GNUNET_i2s(peer), (address != NULL) ? GST_plugins_a2s (address) : ""); + msg = compose_validation_iterate_response_message (peer, address); + msg->last_validation = GNUNET_TIME_absolute_hton(last_validation); + msg->valid_until = GNUNET_TIME_absolute_hton(valid_until); + msg->next_validation = GNUNET_TIME_absolute_hton(next_validation); + msg->state = htonl ((uint32_t) state); + GNUNET_SERVER_transmit_context_append_message (pc->tc, &msg->header); + GNUNET_free (msg); + } +} + + /** * Output information of neighbours to the given client. * @@ -926,7 +1065,7 @@ send_peer_information (void *cls, struct GNUNET_BANDWIDTH_Value32NBO bandwidth_in, struct GNUNET_BANDWIDTH_Value32NBO bandwidth_out) { - struct PeerIterationContext *pc = cls; + struct IterationContext *pc = cls; struct PeerIterateResponseMessage *msg; if ( (GNUNET_YES == pc->all) || @@ -936,7 +1075,7 @@ send_peer_information (void *cls, "Sending information about `%s' using address `%s' in state `%s'\n", GNUNET_i2s(peer), (address != NULL) ? GST_plugins_a2s (address) : "", - GNUNET_TRANSPORT_p2s (state)); + GNUNET_TRANSPORT_ps2s (state)); msg = compose_address_iterate_response_message (peer, address); msg->state = htonl (state); msg->state_timeout = GNUNET_TIME_absolute_hton(state_timeout); @@ -947,7 +1086,6 @@ send_peer_information (void *cls, - /** * Client asked to obtain information about a specific or all peers * Process the request. @@ -963,7 +1101,7 @@ clients_handle_monitor_peers (void *cls, struct GNUNET_SERVER_Client *client, static struct GNUNET_PeerIdentity all_zeros; struct GNUNET_SERVER_TransmitContext *tc; struct PeerMonitorMessage *msg; - struct PeerIterationContext pc; + struct IterationContext pc; if (ntohs (message->type) != GNUNET_MESSAGE_TYPE_TRANSPORT_MONITOR_PEER_REQUEST) { @@ -979,7 +1117,7 @@ clients_handle_monitor_peers (void *cls, struct GNUNET_SERVER_Client *client, } msg = (struct PeerMonitorMessage *) message; if ( (GNUNET_YES != ntohl (msg->one_shot)) && - (NULL != lookup_monitoring_client (client)) ) + (NULL != lookup_monitoring_client (peer_monitoring_clients_head, client)) ) { GNUNET_log (GNUNET_ERROR_TYPE_DEBUG | GNUNET_ERROR_TYPE_BULK, "ServerClient %p tried to start monitoring twice\n", @@ -1008,7 +1146,7 @@ clients_handle_monitor_peers (void *cls, struct GNUNET_SERVER_Client *client, if (GNUNET_YES != ntohl (msg->one_shot)) { - setup_monitoring_client (client, &msg->peer); + setup_peer_monitoring_client (client, &msg->peer); } else { @@ -1020,6 +1158,78 @@ clients_handle_monitor_peers (void *cls, struct GNUNET_SERVER_Client *client, } +/** + * Client asked to obtain information about a specific or all validation + * processes + * + * @param cls unused + * @param client the client + * @param message the peer address information request + */ +static void +clients_handle_monitor_validation (void *cls, struct GNUNET_SERVER_Client *client, + const struct GNUNET_MessageHeader *message) +{ + static struct GNUNET_PeerIdentity all_zeros; + struct GNUNET_SERVER_TransmitContext *tc; + struct PeerMonitorMessage *msg; + struct IterationContext pc; + + if (ntohs (message->type) != GNUNET_MESSAGE_TYPE_TRANSPORT_MONITOR_VALIDATION_REQUEST) + { + GNUNET_break (0); + GNUNET_SERVER_receive_done (client, GNUNET_SYSERR); + return; + } + if (ntohs (message->size) != sizeof (struct ValidationMonitorMessage)) + { + GNUNET_break (0); + GNUNET_SERVER_receive_done (client, GNUNET_SYSERR); + return; + } + msg = (struct PeerMonitorMessage *) message; + if ( (GNUNET_YES != ntohl (msg->one_shot)) && + (NULL != lookup_monitoring_client (val_monitoring_clients_head, client)) ) + { + GNUNET_log (GNUNET_ERROR_TYPE_DEBUG | GNUNET_ERROR_TYPE_BULK, + "ServerClient %p tried to start monitoring twice\n", + client); + GNUNET_break (0); + GNUNET_SERVER_receive_done (client, GNUNET_SYSERR); + return; + } + GNUNET_SERVER_disable_receive_done_warning (client); + pc.tc = tc = GNUNET_SERVER_transmit_context_create (client); + + /* Send initial list */ + if (0 == memcmp (&msg->peer, &all_zeros, sizeof (struct GNUNET_PeerIdentity))) + { + /* iterate over all neighbours */ + pc.all = GNUNET_YES; + pc.id = msg->peer; + } + else + { + /* just return one neighbour */ + pc.all = GNUNET_NO; + pc.id = msg->peer; + } + + GST_validation_iterate (&send_validation_information, &pc); + + if (GNUNET_YES != ntohl (msg->one_shot)) + { + GNUNET_break (0); + setup_val_monitoring_client (client, &msg->peer); + } + else + { + GNUNET_SERVER_transmit_context_append_data (tc, NULL, 0, + GNUNET_MESSAGE_TYPE_TRANSPORT_MONITOR_PEER_RESPONSE); + } + GNUNET_SERVER_transmit_context_run (tc, GNUNET_TIME_UNIT_FOREVER_REL); +} + /** * Start handling requests from clients. * @@ -1043,6 +1253,9 @@ GST_clients_start (struct GNUNET_SERVER_Handle *server) {&clients_handle_monitor_peers, NULL, GNUNET_MESSAGE_TYPE_TRANSPORT_MONITOR_PEER_REQUEST, sizeof (struct PeerMonitorMessage)}, + {&clients_handle_monitor_validation, NULL, + GNUNET_MESSAGE_TYPE_TRANSPORT_MONITOR_VALIDATION_REQUEST, + sizeof (struct ValidationMonitorMessage)}, {&GST_blacklist_handle_init, NULL, GNUNET_MESSAGE_TYPE_TRANSPORT_BLACKLIST_INIT, sizeof (struct GNUNET_MessageHeader)}, @@ -1053,7 +1266,8 @@ GST_clients_start (struct GNUNET_SERVER_Handle *server) GNUNET_MESSAGE_TYPE_TRANSPORT_TRAFFIC_METRIC, 0}, {NULL, NULL, 0, 0} }; - nc = GNUNET_SERVER_notification_context_create (server, 0); + peer_nc = GNUNET_SERVER_notification_context_create (server, 0); + val_nc = GNUNET_SERVER_notification_context_create (server, 0); GNUNET_SERVER_add_handlers (server, handlers); GNUNET_SERVER_disconnect_notify (server, &client_disconnect_notification, NULL); @@ -1074,10 +1288,15 @@ GST_clients_stop () GNUNET_CONTAINER_DLL_remove (a2s_head, a2s_tail, cur); GNUNET_free (cur); } - if (NULL != nc) + if (NULL != peer_nc) + { + GNUNET_SERVER_notification_context_destroy (peer_nc); + peer_nc = NULL; + } + if (NULL != val_nc) { - GNUNET_SERVER_notification_context_destroy (nc); - nc = NULL; + GNUNET_SERVER_notification_context_destroy (val_nc); + val_nc = NULL; } } @@ -1142,7 +1361,7 @@ GST_clients_broadcast_peer_notification (const struct GNUNET_PeerIdentity *peer, msg = compose_address_iterate_response_message (peer, address); msg->state = htonl (state); msg->state_timeout = GNUNET_TIME_absolute_hton (state_timeout); - mc = monitoring_clients_head; + mc = peer_monitoring_clients_head; while (mc != NULL) { if ((0 == memcmp (&mc->peer, &all_zeros, @@ -1150,7 +1369,7 @@ GST_clients_broadcast_peer_notification (const struct GNUNET_PeerIdentity *peer, (0 == memcmp (&mc->peer, peer, sizeof (struct GNUNET_PeerIdentity)))) { - GNUNET_SERVER_notification_context_unicast (nc, mc->client, + GNUNET_SERVER_notification_context_unicast (peer_nc, mc->client, &msg->header, GNUNET_NO); } @@ -1159,5 +1378,52 @@ GST_clients_broadcast_peer_notification (const struct GNUNET_PeerIdentity *peer, GNUNET_free (msg); } +/** + * 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 + * @param state the current state of the peer + * @param state_timeout the time out for the state + */ +void +GST_clients_broadcast_validation_notification ( + const struct GNUNET_PeerIdentity *peer, + const struct GNUNET_HELLO_Address *address, + struct GNUNET_TIME_Absolute last_validation, + struct GNUNET_TIME_Absolute valid_until, + struct GNUNET_TIME_Absolute next_validation, + enum GNUNET_TRANSPORT_ValidationState state) +{ + struct ValidationIterateResponseMessage *msg; + struct MonitoringClient *mc; + static struct GNUNET_PeerIdentity all_zeros; + + GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, + "Sending information about for validation entry for peer `%s' using address `%s'\n", + GNUNET_i2s(peer), (address != NULL) ? GST_plugins_a2s (address) : ""); + + msg = compose_validation_iterate_response_message (peer, address); + msg->last_validation = GNUNET_TIME_absolute_hton(last_validation); + msg->valid_until = GNUNET_TIME_absolute_hton(valid_until); + msg->next_validation = GNUNET_TIME_absolute_hton(next_validation); + msg->state = htonl ((uint32_t) state); + mc = val_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 (val_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 5b151382c..29c46c06b 100644 --- a/src/transport/gnunet-service-transport_clients.h +++ b/src/transport/gnunet-service-transport_clients.h @@ -85,6 +85,15 @@ GST_clients_broadcast_peer_notification (const struct GNUNET_PeerIdentity *peer, enum GNUNET_TRANSPORT_PeerState state, struct GNUNET_TIME_Absolute state_timeout); +void +GST_clients_broadcast_validation_notification ( + const struct GNUNET_PeerIdentity *peer, + const struct GNUNET_HELLO_Address *address, + struct GNUNET_TIME_Absolute last_validation, + struct GNUNET_TIME_Absolute valid_until, + struct GNUNET_TIME_Absolute next_validation, + enum GNUNET_TRANSPORT_ValidationState state); + #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 2090c71b5..fbd524f3b 100644 --- a/src/transport/gnunet-service-transport_neighbours.c +++ b/src/transport/gnunet-service-transport_neighbours.c @@ -589,7 +589,7 @@ set_state (struct NeighbourMapEntry *n, enum GNUNET_TRANSPORT_PeerState s) n->state = s; GNUNET_log (GNUNET_ERROR_TYPE_INFO, "Neighbour `%s' changed state to %s\n", GNUNET_i2s (&n->id), - GNUNET_TRANSPORT_p2s(s)); + GNUNET_TRANSPORT_ps2s(s)); neighbour_change_cb (callback_cls, &n->id, n->primary_address.address, @@ -615,7 +615,7 @@ set_state_and_timeout (struct NeighbourMapEntry *n, n->timeout = timeout; GNUNET_log (GNUNET_ERROR_TYPE_INFO, "Neighbour `%s' changed state to %s with timeout %s\n", GNUNET_i2s (&n->id), - GNUNET_TRANSPORT_p2s(s), + GNUNET_TRANSPORT_ps2s(s), GNUNET_STRINGS_absolute_time_to_string (timeout)); neighbour_change_cb (callback_cls, &n->id, @@ -1029,7 +1029,7 @@ disconnect_neighbour (struct NeighbourMapEntry *n) GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "Disconnecting from peer %s in state %s\n", GNUNET_i2s (&n->id), - GNUNET_TRANSPORT_p2s (n->state)); + GNUNET_TRANSPORT_ps2s (n->state)); /* depending on state, notify neighbour and/or upper layers of this peer about disconnect */ switch (n->state) @@ -1091,7 +1091,7 @@ disconnect_neighbour (struct NeighbourMapEntry *n) default: GNUNET_log (GNUNET_ERROR_TYPE_ERROR, "Unhandled state `%s'\n", - GNUNET_TRANSPORT_p2s (n->state)); + GNUNET_TRANSPORT_ps2s (n->state)); GNUNET_break (0); break; } @@ -1775,7 +1775,7 @@ GST_neighbours_try_connect (const struct GNUNET_PeerIdentity *target) GNUNET_log (GNUNET_ERROR_TYPE_INFO, "Asked to connect to peer `%s' (state: %s)\n", GNUNET_i2s (target), - (NULL != n) ? GNUNET_TRANSPORT_p2s(n->state) : "NEW PEER"); + (NULL != n) ? GNUNET_TRANSPORT_ps2s(n->state) : "NEW PEER"); if (NULL != n) { switch (n->state) @@ -1816,7 +1816,7 @@ GST_neighbours_try_connect (const struct GNUNET_PeerIdentity *target) default: GNUNET_log (GNUNET_ERROR_TYPE_ERROR, "Unhandled state `%s'\n", - GNUNET_TRANSPORT_p2s (n->state)); + GNUNET_TRANSPORT_ps2s (n->state)); GNUNET_break (0); free_neighbour (n, GNUNET_NO); break; @@ -1876,7 +1876,7 @@ handle_test_blacklist_cont (void *cls, GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "Received blacklist result for peer `%s' in state %s/%d\n", GNUNET_i2s (peer), - GNUNET_TRANSPORT_p2s (n->state), + GNUNET_TRANSPORT_ps2s (n->state), n->send_connect_ack); switch (n->state) { @@ -2066,7 +2066,7 @@ handle_test_blacklist_cont (void *cls, default: GNUNET_log (GNUNET_ERROR_TYPE_ERROR, "Unhandled state `%s'\n", - GNUNET_TRANSPORT_p2s (n->state)); + GNUNET_TRANSPORT_ps2s (n->state)); GNUNET_break (0); free_neighbour (n, GNUNET_NO); break; @@ -2167,7 +2167,7 @@ GST_neighbours_handle_connect (const struct GNUNET_MessageHeader *message, GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "Received SESSION_CONNECT for peer `%s' in state %s/%d\n", GNUNET_i2s (peer), - GNUNET_TRANSPORT_p2s (n->state), + GNUNET_TRANSPORT_ps2s (n->state), n->send_connect_ack); switch (n->state) { @@ -2234,7 +2234,7 @@ GST_neighbours_handle_connect (const struct GNUNET_MessageHeader *message, default: GNUNET_log (GNUNET_ERROR_TYPE_ERROR, "Unhandled state `%s'\n", - GNUNET_TRANSPORT_p2s (n->state)); + GNUNET_TRANSPORT_ps2s (n->state)); GNUNET_break (0); return GNUNET_SYSERR; } @@ -2311,7 +2311,7 @@ GST_neighbours_switch_to_address (const struct GNUNET_PeerIdentity *peer, GST_plugins_a2s (address), session, GNUNET_i2s (peer), - GNUNET_TRANSPORT_p2s (n->state), + GNUNET_TRANSPORT_ps2s (n->state), n->send_connect_ack, ntohl (bandwidth_in.value__), ntohl (bandwidth_out.value__)); @@ -2471,7 +2471,7 @@ GST_neighbours_switch_to_address (const struct GNUNET_PeerIdentity *peer, default: GNUNET_log (GNUNET_ERROR_TYPE_ERROR, "Unhandled state `%s'\n", - GNUNET_TRANSPORT_p2s (n->state)); + GNUNET_TRANSPORT_ps2s (n->state)); GNUNET_break (0); break; } @@ -2638,7 +2638,7 @@ master_task (void *cls, GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "Master task runs for neighbour `%s' in state %s with timeout in %s\n", GNUNET_i2s (&n->id), - GNUNET_TRANSPORT_p2s(n->state), + GNUNET_TRANSPORT_ps2s(n->state), GNUNET_STRINGS_relative_time_to_string (delay, GNUNET_YES)); switch (n->state) @@ -2809,7 +2809,7 @@ master_task (void *cls, default: GNUNET_log (GNUNET_ERROR_TYPE_ERROR, "Unhandled state `%s'\n", - GNUNET_TRANSPORT_p2s (n->state)); + GNUNET_TRANSPORT_ps2s (n->state)); GNUNET_break (0); break; } @@ -2993,7 +2993,7 @@ GST_neighbours_handle_connect_ack (const struct GNUNET_MessageHeader *message, default: GNUNET_log (GNUNET_ERROR_TYPE_ERROR, "Unhandled state `%s'\n", - GNUNET_TRANSPORT_p2s (n->state)); + GNUNET_TRANSPORT_ps2s (n->state)); GNUNET_break (0); return GNUNET_SYSERR; } @@ -3112,7 +3112,7 @@ GST_neighbours_session_terminated (const struct GNUNET_PeerIdentity *peer, default: GNUNET_log (GNUNET_ERROR_TYPE_ERROR, "Unhandled state `%s'\n", - GNUNET_TRANSPORT_p2s (n->state)); + GNUNET_TRANSPORT_ps2s (n->state)); GNUNET_break (0); break; } @@ -3169,7 +3169,7 @@ GST_neighbours_handle_session_ack (const struct GNUNET_MessageHeader *message, GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "Received SESSION_ACK message from peer `%s' in state %s/%d\n", GNUNET_i2s (peer), - GNUNET_TRANSPORT_p2s (n->state), + GNUNET_TRANSPORT_ps2s (n->state), n->send_connect_ack); GNUNET_STATISTICS_update (GST_stats, gettext_noop ("# unexpected SESSION_ACK messages"), 1, @@ -3467,7 +3467,7 @@ GST_neighbour_get_latency (const struct GNUNET_PeerIdentity *peer) default: GNUNET_log (GNUNET_ERROR_TYPE_ERROR, "Unhandled state `%s'\n", - GNUNET_TRANSPORT_p2s (n->state)); + GNUNET_TRANSPORT_ps2s (n->state)); GNUNET_break (0); break; } diff --git a/src/transport/gnunet-service-transport_validation.c b/src/transport/gnunet-service-transport_validation.c index 07ed2eeca..e18412588 100644 --- a/src/transport/gnunet-service-transport_validation.c +++ b/src/transport/gnunet-service-transport_validation.c @@ -217,6 +217,11 @@ struct ValidationEntry */ struct GNUNET_TIME_Absolute send_time; + /** + * At what time do we send the next validation request (PING)? + */ + struct GNUNET_TIME_Absolute next_validation; + /** * Until when is this address valid? * ZERO if it is not currently considered valid. @@ -243,6 +248,10 @@ struct ValidationEntry */ struct GNUNET_TIME_Relative latency; + /** + * Current state of this validation entry + */ + enum GNUNET_TRANSPORT_ValidationState state; /** * Challenge number we used. */ @@ -336,6 +345,9 @@ static unsigned int validations_fast_start_threshold; */ static struct GNUNET_TIME_Absolute validation_next; +static GST_ValidationChangedCallback validation_entry_changed_cb; +static void *validation_entry_changed_cb_cls; + /** * Context for the validation entry match function. */ @@ -377,6 +389,24 @@ validation_entry_match (void *cls, const struct GNUNET_PeerIdentity * key, void return GNUNET_YES; } +static void +validation_entry_changed (struct ValidationEntry *ve, enum GNUNET_TRANSPORT_ValidationState state) +{ + char *t_sent = GNUNET_strdup(GNUNET_STRINGS_absolute_time_to_string(ve->send_time)); + char *t_valid = GNUNET_strdup(GNUNET_STRINGS_absolute_time_to_string(ve->valid_until)); + char *t_next = GNUNET_strdup(GNUNET_STRINGS_absolute_time_to_string(ve->next_validation)); + GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "Validation entry changed for peer `%s' address `%s':\n\tSent: %s\n\tValid: %s\n\tNext: %s\n", + GNUNET_i2s(&ve->pid), GST_plugins_a2s(ve->address), + t_sent, t_valid, t_next); + ve->state = state; + + GNUNET_free (t_sent); + GNUNET_free (t_valid); + GNUNET_free (t_next); + validation_entry_changed_cb (validation_entry_changed_cb_cls, &ve->pid, + ve->address, ve->send_time, ve->valid_until, ve->next_validation, state); +} + /** * Iterate over validation entries and free them. @@ -391,6 +421,12 @@ cleanup_validation_entry (void *cls, const struct GNUNET_PeerIdentity * key, voi { struct ValidationEntry *ve = value; + ve->next_validation = GNUNET_TIME_absolute_get_zero_(); + ve->valid_until = GNUNET_TIME_UNIT_ZERO_ABS; + + /* Notify about deleted entry */ + validation_entry_changed (ve, GNUNET_TRANSPORT_VS_REMOVE); + if (NULL != ve->bc) { GST_blacklist_test_cancel (ve->bc); @@ -586,6 +622,8 @@ transmit_ping_if_allowed (void *cls, GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "Validation started, %u validation processes running\n", validations_running); + /* Notify about PING sent */ + validation_entry_changed (ve, GNUNET_TRANSPORT_VS_UPDATE); } } @@ -631,6 +669,7 @@ revalidate_address (void *cls, GST_plugins_a2s (ve->address)); ve->revalidation_task = GNUNET_SCHEDULER_add_delayed (delay, &revalidate_address, ve); + ve->next_validation = GNUNET_TIME_absolute_add(GNUNET_TIME_absolute_get(), delay); return; } blocked_for = GNUNET_TIME_absolute_get_remaining(validation_next); @@ -645,6 +684,7 @@ revalidate_address (void *cls, GST_plugins_a2s (ve->address)); ve->revalidation_task = GNUNET_SCHEDULER_add_delayed (blocked_for, &revalidate_address, ve); + ve->next_validation = GNUNET_TIME_absolute_add(GNUNET_TIME_absolute_get(), blocked_for); return; } ve->revalidation_block = GNUNET_TIME_relative_to_absolute (canonical_delay); @@ -675,6 +715,7 @@ revalidate_address (void *cls, GST_plugins_a2s (ve->address)); ve->revalidation_task = GNUNET_SCHEDULER_add_delayed (delay, &revalidate_address, ve); + ve->next_validation = GNUNET_TIME_absolute_add(GNUNET_TIME_absolute_get(), delay); /* start PINGing by checking blacklist */ GNUNET_STATISTICS_update (GST_stats, @@ -730,6 +771,7 @@ find_validation_entry (const struct GNUNET_CRYPTO_EddsaPublicKey *public_key, GNUNET_CONTAINER_multipeermap_put (validation_map, &address->peer, ve, GNUNET_CONTAINER_MULTIHASHMAPOPTION_MULTIPLE); + validation_entry_changed (ve, GNUNET_TRANSPORT_VS_NEW); ve->expecting_pong = GNUNET_NO; return ve; } @@ -779,8 +821,10 @@ add_valid_address (void *cls, GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "Starting revalidations for valid address `%s'\n", GST_plugins_a2s (ve->address)); + ve->next_validation = GNUNET_TIME_absolute_get(); ve->revalidation_task = GNUNET_SCHEDULER_add_now (&revalidate_address, ve); } + validation_entry_changed (ve, GNUNET_TRANSPORT_VS_UPDATE); ats.type = htonl (GNUNET_ATS_NETWORK_TYPE); ats.value = htonl (ve->network); @@ -822,7 +866,7 @@ process_peerinfo_hello (void *cls, const struct GNUNET_PeerIdentity *peer, * @param max_fds maximum number of fds to use */ void -GST_validation_start (unsigned int max_fds) +GST_validation_start (GST_ValidationChangedCallback cb, void *cb_cls, unsigned int max_fds) { /** * Initialization for validation throttling @@ -840,6 +884,8 @@ GST_validation_start (unsigned int max_fds) validation_delay.rel_value_us = (GNUNET_CONSTANTS_IDLE_CONNECTION_TIMEOUT.rel_value_us) / (max_fds / 2); validations_fast_start_threshold = (max_fds / 2); validations_running = 0; + validation_entry_changed_cb = cb; + validation_entry_changed_cb_cls = cb_cls; GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "Validation uses a fast start threshold of %u connections and a delay between of %s\n ", validations_fast_start_threshold, GNUNET_STRINGS_relative_time_to_string (validation_delay, @@ -1396,6 +1442,9 @@ GST_validation_handle_pong (const struct GNUNET_PeerIdentity *sender, GNUNET_break (0); } + /* Notify about new validity */ + validation_entry_changed (ve, GNUNET_TRANSPORT_VS_UPDATE); + /* build HELLO to store in PEERINFO */ ve->copied = GNUNET_NO; hello = GNUNET_HELLO_create (&ve->public_key, @@ -1600,5 +1649,54 @@ GST_validation_get_address_latency (const struct GNUNET_PeerIdentity *sender, return ve->latency; } +/** + * Closure for the validation_entries_iterate function. + */ +struct ValidationIteratorContext +{ + /** + * Function to call on each validation entry + */ + GST_ValidationChangedCallback cb; + + /** + * Closure for 'cb'. + */ + void *cb_cls; +}; + +static int +validation_entries_iterate (void *cls, + const struct GNUNET_PeerIdentity *key, + void *value) +{ + struct ValidationIteratorContext *ic = cls; + struct ValidationEntry *ve = value; + + GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "Notifying about validation entry for peer `%s' address `%s' \n", + GNUNET_i2s (&ve->pid), GST_plugins_a2s (ve->address)); + ic->cb (ic->cb_cls, &ve->pid, ve->address, ve->send_time, + ve->valid_until, ve->next_validation, ve->state); + + return GNUNET_OK; +} + +/** + * Iterate over all iteration entries + * + * @param cb function to call + * @param cb_cls closure for cb + */ +void +GST_validation_iterate (GST_ValidationChangedCallback cb, void *cb_cls) +{ + struct ValidationIteratorContext ic; + + if (NULL == validation_map) + return; /* can happen during shutdown */ + ic.cb = cb; + ic.cb_cls = cb_cls; + GNUNET_CONTAINER_multipeermap_iterate (validation_map, &validation_entries_iterate, &ic); +} /* end of file gnunet-service-transport_validation.c */ diff --git a/src/transport/gnunet-service-transport_validation.h b/src/transport/gnunet-service-transport_validation.h index e07afc409..d117faca5 100644 --- a/src/transport/gnunet-service-transport_validation.h +++ b/src/transport/gnunet-service-transport_validation.h @@ -31,6 +31,26 @@ #include "gnunet_util_lib.h" #include "gnunet_hello_lib.h" +/** + * Function called for each address (or address status change) that + * the validation module is aware of (for the given target). + * + * @param cls closure + * @param public_key public key for the peer, never NULL + * @param valid_until is ZERO if we never validated the address, + * otherwise a time up to when we consider it (or was) valid + * @param validation_block is FOREVER if the address is for an unsupported plugin (from PEERINFO) + * is ZERO if the address is considered valid (no validation needed) + * otherwise a time in the future if we're currently denying re-validation + * @param address the address + */ +typedef void (*GST_ValidationChangedCallback) (void *cls, + const struct GNUNET_PeerIdentity *peer, + const struct GNUNET_HELLO_Address *address, + struct GNUNET_TIME_Absolute last_validation, + struct GNUNET_TIME_Absolute valid_until, + struct GNUNET_TIME_Absolute next_validation, + enum GNUNET_TRANSPORT_ValidationState state); /** * Start the validation subsystem. @@ -38,7 +58,7 @@ * @param max_fds maximum number of fds to use */ void -GST_validation_start (unsigned int max_fds); +GST_validation_start (GST_ValidationChangedCallback cb, void *cb_cls, unsigned int max_fds); /** @@ -79,6 +99,14 @@ GST_validation_get_address_latency (const struct GNUNET_PeerIdentity *sender, const struct GNUNET_HELLO_Address *address, struct Session *session); +/** + * Iterate over all iteration entries + * + * @param cb function to call + * @param cb_cls closure for cb + */ +void +GST_validation_iterate (GST_ValidationChangedCallback cb, void *cb_cls); /** * We've received a PING. If appropriate, generate a PONG. diff --git a/src/transport/gnunet-transport.c b/src/transport/gnunet-transport.c index c2d35cd66..c8408b757 100644 --- a/src/transport/gnunet-transport.c +++ b/src/transport/gnunet-transport.c @@ -88,6 +88,11 @@ static int benchmark_receive; */ static int iterate_connections; +/** + * Option -d. + */ +static int iterate_validation; + /** * Option -a. */ @@ -156,7 +161,9 @@ static struct GNUNET_CONTAINER_MultiPeerMap *monitored_peers; /** * */ -struct GNUNET_TRANSPORT_PeerMonitoringContext *pic; +static struct GNUNET_TRANSPORT_PeerMonitoringContext *pic; + +static struct GNUNET_TRANSPORT_ValidationMonitoringContext *vic; /** * Identity of the peer we transmit to / connect to. @@ -269,6 +276,11 @@ shutdown_task (void *cls, const struct GNUNET_SCHEDULER_TaskContext *tc) GNUNET_TRANSPORT_monitor_peers_cancel (pic); pic = NULL; } + if (NULL != vic) + { + GNUNET_TRANSPORT_monitor_validation_entries_cancel (vic); + vic = NULL; + } if (NULL != th) { GNUNET_TRANSPORT_notify_transmit_ready_cancel (th); @@ -430,6 +442,17 @@ fail_timeout (void *cls, const struct GNUNET_SCHEDULER_TaskContext *tc) display_test_result (tstc, GNUNET_NO); } +void process_validation_cb (void *cls, + const struct GNUNET_PeerIdentity *peer, + const struct GNUNET_HELLO_Address *address, + struct GNUNET_TIME_Absolute last_validation, + struct GNUNET_TIME_Absolute valid_until, + struct GNUNET_TIME_Absolute next_validation, + enum GNUNET_TRANSPORT_ValidationState state) +{ + GNUNET_break (0); +} + /** * Test our plugin's configuration (NAT traversal, etc.). * @@ -694,7 +717,7 @@ print_info (const struct GNUNET_PeerIdentity *id, const char *transport, GNUNET_i2s (id), (NULL == transport) ? "" : transport, (NULL == transport) ? "" : addr, - GNUNET_TRANSPORT_p2s (state), + GNUNET_TRANSPORT_ps2s (state), GNUNET_STRINGS_absolute_time_to_string (state_timeout)); } else @@ -951,7 +974,7 @@ testservice_task (void *cls, int result) } counter = benchmark_send + benchmark_receive + iterate_connections - + monitor_connections + monitor_connects + try_connect; + + monitor_connections + monitor_connects + try_connect + iterate_validation; if (1 < counter) { @@ -1060,6 +1083,11 @@ testservice_task (void *cls, int result) pic = GNUNET_TRANSPORT_monitor_peers (cfg, (NULL == cpid) ? NULL : &pid, GNUNET_NO, TIMEOUT, &process_peer_monitoring_cb, (void *) cfg); } + else if (iterate_validation) /* -d: Print information about validations */ + { + vic = GNUNET_TRANSPORT_monitor_validation_entries (cfg, (NULL == cpid) ? NULL : &pid, + GNUNET_YES, TIMEOUT, &process_validation_cb, (void *) cfg); + } else if (monitor_connects) /* -e : Monitor (dis)connect events continuously */ { monitor_connect_counter = 0; @@ -1120,6 +1148,9 @@ main (int argc, char * const *argv) 0, &GNUNET_GETOPT_set_one, &benchmark_receive }, { 'C', "connect", NULL, gettext_noop ("connect to a peer"), 0, &GNUNET_GETOPT_set_one, &try_connect }, + { 'd', "validation", NULL, + gettext_noop ("print information for all pending validations "), + 0, &GNUNET_GETOPT_set_one, &iterate_validation }, { 'i', "information", NULL, gettext_noop ("provide information about all current connections (once)"), 0, &GNUNET_GETOPT_set_one, &iterate_connections }, diff --git a/src/transport/plugin_transport_udp.c b/src/transport/plugin_transport_udp.c index 9e3fc4fdf..e7ab1a818 100644 --- a/src/transport/plugin_transport_udp.c +++ b/src/transport/plugin_transport_udp.c @@ -1308,7 +1308,7 @@ session_timeout (void *cls, const struct GNUNET_SCHEDULER_TaskContext *tc) "Session %p was idle for %s, disconnecting\n", s, GNUNET_STRINGS_relative_time_to_string (UDP_SESSION_TIME_OUT, GNUNET_YES)); /* call session destroy function */ - udp_disconnect_session (s->plugin, s); + udp_disconnect_session (plugin, s); } /** diff --git a/src/transport/test_transport_api_monitoring.c b/src/transport/test_transport_api_monitoring.c index f726344dd..0767893ed 100644 --- a/src/transport/test_transport_api_monitoring.c +++ b/src/transport/test_transport_api_monitoring.c @@ -98,15 +98,20 @@ end () GNUNET_SCHEDULER_cancel (send_task); if (die_task != GNUNET_SCHEDULER_NO_TASK) + { GNUNET_SCHEDULER_cancel (die_task); + die_task = GNUNET_SCHEDULER_NO_TASK; + } if (th != NULL) GNUNET_TRANSPORT_notify_transmit_ready_cancel (th); th = NULL; - GNUNET_TRANSPORT_TESTING_stop_peer (tth, p1); + if (NULL != p1) + GNUNET_TRANSPORT_TESTING_stop_peer (tth, p1); p1 = NULL; - GNUNET_TRANSPORT_TESTING_stop_peer (tth, p2); + if (NULL != p2) + GNUNET_TRANSPORT_TESTING_stop_peer (tth, p2); p2 = NULL; if (NULL != pmc_p1) @@ -382,8 +387,8 @@ static void monitor1_cb (void *cls, if ((NULL == peer) || (NULL == p1)) return; - GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "Monitor 1: %s %s %s\n", - GNUNET_i2s (peer), GNUNET_TRANSPORT_p2s(state), GNUNET_STRINGS_absolute_time_to_string(state_timeout)); + GNUNET_log (GNUNET_ERROR_TYPE_INFO, "Monitor 1: %s %s %s\n", + GNUNET_i2s (peer), GNUNET_TRANSPORT_ps2s(state), GNUNET_STRINGS_absolute_time_to_string(state_timeout)); if ((0 == memcmp (peer, &p2->id, sizeof (p2->id)) && (GNUNET_YES == GNUNET_TRANSPORT_is_connected(state)) && GNUNET_NO == p1_c) ) @@ -404,8 +409,8 @@ static void monitor2_cb (void *cls, if ((NULL == peer) || (NULL == p2)) return; - GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "Monitor 2: %s %s %s\n", - GNUNET_i2s (peer), GNUNET_TRANSPORT_p2s (state), GNUNET_STRINGS_absolute_time_to_string(state_timeout)); + GNUNET_log (GNUNET_ERROR_TYPE_INFO, "Monitor 2: %s %s %s\n", + GNUNET_i2s (peer), GNUNET_TRANSPORT_ps2s (state), GNUNET_STRINGS_absolute_time_to_string(state_timeout)); if ((0 == memcmp (peer, &p1->id, sizeof (p1->id)) && (GNUNET_YES == GNUNET_TRANSPORT_is_connected(state)) && GNUNET_NO == p2_c) ) @@ -432,13 +437,14 @@ run (void *cls, char *const *args, const char *cfgfile, ¬ify_disconnect, &start_cb, NULL); pmc_p1 = GNUNET_TRANSPORT_monitor_peers (p1->cfg, NULL, GNUNET_NO, GNUNET_TIME_UNIT_FOREVER_REL, &monitor1_cb, NULL); + GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "Peer 1 started\n"); p2 = GNUNET_TRANSPORT_TESTING_start_peer (tth, cfg_file_p2, 2, ¬ify_receive, ¬ify_connect, ¬ify_disconnect, &start_cb, NULL); pmc_p2 = GNUNET_TRANSPORT_monitor_peers (p2->cfg, NULL, GNUNET_NO, GNUNET_TIME_UNIT_FOREVER_REL, &monitor2_cb, NULL); - + GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "Peer 1 started\n"); if ((p1 == NULL) || (p2 == NULL)) { GNUNET_log (GNUNET_ERROR_TYPE_ERROR, "Fail! Could not start peers!\n"); diff --git a/src/transport/test_transport_api_monitoring_validation_peer1.conf b/src/transport/test_transport_api_monitoring_validation_peer1.conf new file mode 100644 index 000000000..aca9c1e7c --- /dev/null +++ b/src/transport/test_transport_api_monitoring_validation_peer1.conf @@ -0,0 +1,6 @@ +@INLINE@ template_cfg_peer1.conf +[PATHS] +GNUNET_TEST_HOME = /tmp/test-transport/api-monitoring-val-p1/ + +[transport] +PLUGINS=tcp diff --git a/src/transport/test_transport_api_monitoring_validation_peer2.conf b/src/transport/test_transport_api_monitoring_validation_peer2.conf new file mode 100644 index 000000000..86dfcbbbc --- /dev/null +++ b/src/transport/test_transport_api_monitoring_validation_peer2.conf @@ -0,0 +1,7 @@ +@INLINE@ template_cfg_peer2.conf +[PATHS] +GNUNET_TEST_HOME = /tmp/test-transport/api-monitoring-val-p2/ + +[TRANSPORT] +PLUGINS=tcp + diff --git a/src/transport/transport.h b/src/transport/transport.h index 5a2f04056..dab5415c2 100644 --- a/src/transport/transport.h +++ b/src/transport/transport.h @@ -341,15 +341,20 @@ struct AddressLookupMessage }; -#if 0 /** - * Message from the library to the transport service - * asking for human readable addresses known for a peer. + * Message from the transport service to the library containing information + * about a peer. Information contained are: + * - current address used to communicate with this peer + * - state + * - state timeout + * + * Memory layout: + * [AddressIterateResponseMessage][address[addrlen]][transportname[pluginlen]] */ -struct PeerLookupMessage +struct ValidationIterateResponseMessage { /** - * Type will be GNUNET_MESSAGE_TYPE_TRANSPORT_PEER_ADDRESS_LOOKUP + * Type is #GNUNET_MESSAGE_TYPE_TRANSPORT_MONITOR_VALIDATION_RESPONSE */ struct GNUNET_MessageHeader header; @@ -359,16 +364,59 @@ struct PeerLookupMessage uint32_t reserved; /** - * timeout to give up. FIXME: remove in the future. + * Peer identity */ - struct GNUNET_TIME_RelativeNBO timeout; + struct GNUNET_PeerIdentity peer; + + /** + * Local info about the address + */ + uint32_t local_address_info GNUNET_PACKED; + + /** + * Address length + */ + uint32_t addrlen GNUNET_PACKED; + + /** + * Length of the plugin name + */ + uint32_t pluginlen GNUNET_PACKED; + + /** + * State + */ + uint32_t state GNUNET_PACKED; + + struct GNUNET_TIME_AbsoluteNBO last_validation; + + struct GNUNET_TIME_AbsoluteNBO valid_until; + + struct GNUNET_TIME_AbsoluteNBO next_validation; +}; + +/** + * Message from the library to the transport service + * asking for binary addresses known for a peer. + */ +struct ValidationMonitorMessage +{ + /** + * Type will be #GNUNET_MESSAGE_TYPE_TRANSPORT_MONITOR_VALIDATION_REQUEST + */ + struct GNUNET_MessageHeader header; + + /** + * One shot call or continous replies? + */ + uint32_t one_shot; /** * The identity of the peer to look up. */ struct GNUNET_PeerIdentity peer; + }; -#endif /** @@ -378,7 +426,7 @@ struct PeerLookupMessage struct PeerMonitorMessage { /** - * Type will be GNUNET_MESSAGE_TYPE_TRANSPORT_ADDRESS_ITERATE + * Type will be #GNUNET_MESSAGE_TYPE_TRANSPORT_MONITOR_PEER_REQUEST */ struct GNUNET_MessageHeader header; @@ -387,11 +435,6 @@ struct PeerMonitorMessage */ uint32_t one_shot; - /** - * timeout to give up. FIXME: remove in the future - */ - struct GNUNET_TIME_AbsoluteNBO timeout; - /** * The identity of the peer to look up. */ diff --git a/src/transport/transport_api_monitoring.c b/src/transport/transport_api_monitoring.c index 50517cc6c..9820151d5 100644 --- a/src/transport/transport_api_monitoring.c +++ b/src/transport/transport_api_monitoring.c @@ -173,7 +173,7 @@ GNUNET_TRANSPORT_is_connected (enum GNUNET_TRANSPORT_PeerState state) default: GNUNET_log (GNUNET_ERROR_TYPE_ERROR, "Unhandled state `%s' \n", - GNUNET_TRANSPORT_p2s (state)); + GNUNET_TRANSPORT_ps2s (state)); GNUNET_break (0); break; } @@ -181,13 +181,13 @@ GNUNET_TRANSPORT_is_connected (enum GNUNET_TRANSPORT_PeerState state) } /** - * Convert state to human-readable string. + * Convert peer state to human-readable string. * * @param state the state value * @return corresponding string */ const char * -GNUNET_TRANSPORT_p2s (enum GNUNET_TRANSPORT_PeerState state) +GNUNET_TRANSPORT_ps2s (enum GNUNET_TRANSPORT_PeerState state) { switch (state) { @@ -229,6 +229,31 @@ GNUNET_TRANSPORT_p2s (enum GNUNET_TRANSPORT_PeerState state) } } +/** + * Convert validation state to human-readable string. + * + * @param state the state value + * @return corresponding string + */ +const char * +GNUNET_TRANSPORT_vs2s (enum GNUNET_TRANSPORT_ValidationState state) +{ + switch (state) + { + case GNUNET_TRANSPORT_VS_NEW: + return "NEW"; + case GNUNET_TRANSPORT_VS_REMOVE: + return "REMOVE"; + case GNUNET_TRANSPORT_VS_TIMEOUT: + return "TIMEOUT"; + case GNUNET_TRANSPORT_VS_UPDATE: + return "UPDATE"; + default: + GNUNET_break (0); + return "UNDEFINED"; + } +} + /** * Function called with responses from the service. @@ -238,34 +263,66 @@ GNUNET_TRANSPORT_p2s (enum GNUNET_TRANSPORT_PeerState state) * message with the human-readable address */ static void -peer_response_processor (void *cls, - const struct GNUNET_MessageHeader *msg); +peer_response_processor (void *cls, const struct GNUNET_MessageHeader *msg); +/** + * Function called with responses from the service. + * + * @param cls our 'struct GNUNET_TRANSPORT_PeerAddressLookupContext*' + * @param msg NULL on timeout or error, otherwise presumably a + * message with the human-readable address + */ +static void +val_response_processor (void *cls, const struct GNUNET_MessageHeader *msg); + /** * Send our subscription request to the service. * * @param pal_ctx our context */ static void -send_request (struct GNUNET_TRANSPORT_PeerMonitoringContext *pal_ctx) +send_peer_mon_request (struct GNUNET_TRANSPORT_PeerMonitoringContext *pal_ctx) { struct PeerMonitorMessage msg; msg.header.size = htons (sizeof (struct PeerMonitorMessage)); msg.header.type = htons (GNUNET_MESSAGE_TYPE_TRANSPORT_MONITOR_PEER_REQUEST); msg.one_shot = htonl (pal_ctx->one_shot); - msg.timeout = GNUNET_TIME_absolute_hton (pal_ctx->timeout); msg.peer = pal_ctx->peer; GNUNET_assert (GNUNET_OK == GNUNET_CLIENT_transmit_and_get_response (pal_ctx->client, - &msg.header, - GNUNET_TIME_absolute_get_remaining (pal_ctx->timeout), - GNUNET_YES, - &peer_response_processor, - pal_ctx)); + &msg.header, + GNUNET_TIME_absolute_get_remaining (pal_ctx->timeout), + GNUNET_YES, + &peer_response_processor, + pal_ctx)); } +/** + * Send our subscription request to the service. + * + * @param pal_ctx our context + */ +static void +send_val_mon_request (struct GNUNET_TRANSPORT_ValidationMonitoringContext *val_ctx) +{ + struct ValidationMonitorMessage msg; + + msg.header.size = htons (sizeof (struct PeerMonitorMessage)); + msg.header.type = htons (GNUNET_MESSAGE_TYPE_TRANSPORT_MONITOR_VALIDATION_REQUEST); + msg.one_shot = htonl (val_ctx->one_shot); + msg.peer = val_ctx->peer; + GNUNET_assert (GNUNET_OK == + GNUNET_CLIENT_transmit_and_get_response (val_ctx->client, + &msg.header, + GNUNET_TIME_absolute_get_remaining (val_ctx->timeout), + GNUNET_YES, + &val_response_processor, + val_ctx)); +} + + /** * Task run to re-establish the connection. * @@ -281,7 +338,7 @@ do_connect (void *cls, pal_ctx->reconnect_task = GNUNET_SCHEDULER_NO_TASK; pal_ctx->client = GNUNET_CLIENT_connect ("transport", pal_ctx->cfg); GNUNET_assert (NULL != pal_ctx->client); - send_request (pal_ctx); + send_peer_mon_request (pal_ctx); } @@ -302,6 +359,154 @@ reconnect (struct GNUNET_TRANSPORT_PeerMonitoringContext *pal_ctx) pal_ctx); } +/** + * Function called with responses from the service. + * + * @param cls our 'struct GNUNET_TRANSPORT_PeerMonitoringContext*' + * @param msg NULL on timeout or error, otherwise presumably a + * message with the human-readable address + */ +static void +val_response_processor (void *cls, const struct GNUNET_MessageHeader *msg) +{ + struct GNUNET_TRANSPORT_ValidationMonitoringContext *val_ctx = cls; + GNUNET_break (0); + if (msg == NULL) + { + GNUNET_break (0); + if (val_ctx->one_shot) + { + /* Disconnect */ + val_ctx->cb (val_ctx->cb_cls, NULL, NULL, + GNUNET_TIME_UNIT_ZERO_ABS, GNUNET_TIME_UNIT_ZERO_ABS, + GNUNET_TIME_UNIT_ZERO_ABS, GNUNET_TRANSPORT_VS_TIMEOUT); + GNUNET_TRANSPORT_monitor_peers_cancel (val_ctx); + } + else + { + reconnect (val_ctx); + } + return; + } + + /* expect more replies */ + GNUNET_CLIENT_receive (val_ctx->client, &val_response_processor, + val_ctx, GNUNET_TIME_absolute_get_remaining (val_ctx->timeout)); + + return; + + struct ValidationIterateResponseMessage *vir_msg; + struct GNUNET_HELLO_Address *address; + const char *addr; + const char *transport_name; + uint16_t size; + size_t alen; + size_t tlen; +#if 0 + + size = ntohs (msg->size); + GNUNET_break (ntohs (msg->type) == + GNUNET_MESSAGE_TYPE_TRANSPORT_MONITOR_PEER_RESPONSE); + if (size == sizeof (struct GNUNET_MessageHeader)) + { + /* Done! */ + if (pal_ctx->one_shot) + { + pal_ctx->cb (pal_ctx->cb_cls, NULL, NULL, + GNUNET_TRANSPORT_PS_NOT_CONNECTED, GNUNET_TIME_UNIT_ZERO_ABS); + GNUNET_TRANSPORT_monitor_peers_cancel (pal_ctx); + } + else + { + reconnect (pal_ctx); + } + return; + } + + if ((size < sizeof (struct PeerIterateResponseMessage)) || + (ntohs (msg->type) != + GNUNET_MESSAGE_TYPE_TRANSPORT_MONITOR_PEER_RESPONSE)) + { + GNUNET_break (0); + if (pal_ctx->one_shot) + { + pal_ctx->cb (pal_ctx->cb_cls, NULL, NULL, + GNUNET_TRANSPORT_PS_NOT_CONNECTED, GNUNET_TIME_UNIT_ZERO_ABS); + GNUNET_TRANSPORT_monitor_peers_cancel (pal_ctx); + } + else + { + reconnect (pal_ctx); + } + return; + } + + pir_msg = (struct PeerIterateResponseMessage *) msg; + tlen = ntohl (pir_msg->pluginlen); + alen = ntohl (pir_msg->addrlen); + + if (size != sizeof (struct PeerIterateResponseMessage) + tlen + alen) + { + GNUNET_break (0); + if (pal_ctx->one_shot) + { + pal_ctx->cb (pal_ctx->cb_cls, NULL, NULL, + GNUNET_TRANSPORT_PS_NOT_CONNECTED, GNUNET_TIME_UNIT_ZERO_ABS); + GNUNET_TRANSPORT_monitor_peers_cancel (pal_ctx); + } + else + { + reconnect (pal_ctx); + } + return; + } + + if ( (0 == tlen) && (0 == alen) ) + { + /* No address available */ + pal_ctx->cb (pal_ctx->cb_cls, &pir_msg->peer, NULL, + ntohl(pir_msg->state), + GNUNET_TIME_absolute_ntoh (pir_msg->state_timeout)); + } + else + { + if (0 == tlen) + { + GNUNET_break (0); /* This must not happen: address without plugin */ + return; + } + addr = (const char *) &pir_msg[1]; + transport_name = &addr[alen]; + + if (transport_name[tlen - 1] != '\0') + { + /* Corrupt plugin name */ + GNUNET_break (0); + if (pal_ctx->one_shot) + { + pal_ctx->cb (pal_ctx->cb_cls, NULL, NULL, + GNUNET_TRANSPORT_PS_NOT_CONNECTED, GNUNET_TIME_UNIT_ZERO_ABS); + GNUNET_TRANSPORT_monitor_peers_cancel (pal_ctx); + } + else + { + reconnect (pal_ctx); + } + return; + } + + /* notify client */ + address = GNUNET_HELLO_address_allocate (&pir_msg->peer, + transport_name, addr, alen, ntohl(pir_msg->local_address_info)); + pal_ctx->cb (pal_ctx->cb_cls, &pir_msg->peer, address, + ntohl(pir_msg->state), + GNUNET_TIME_absolute_ntoh (pir_msg->state_timeout)); + GNUNET_HELLO_address_free (address); + } +#endif + +} + /** * Function called with responses from the service. @@ -321,7 +526,7 @@ peer_response_processor (void *cls, const struct GNUNET_MessageHeader *msg) uint16_t size; size_t alen; size_t tlen; - + GNUNET_break (0); if (msg == NULL) { if (pal_ctx->one_shot) @@ -394,7 +599,6 @@ peer_response_processor (void *cls, const struct GNUNET_MessageHeader *msg) return; } - if ( (0 == tlen) && (0 == alen) ) { /* No address available */ @@ -498,7 +702,7 @@ GNUNET_TRANSPORT_monitor_peers (const struct GNUNET_CONFIGURATION_Handle *cfg, pal_ctx->peer = *peer; pal_ctx->one_shot = one_shot; pal_ctx->client = client; - send_request (pal_ctx); + send_peer_mon_request (pal_ctx); return pal_ctx; } @@ -548,8 +752,26 @@ GNUNET_TRANSPORT_monitor_validation_entries (const struct GNUNET_TRANSPORT_ValidationIterateCallback validation_callback, void *validation_callback_cls) { - /* Not implemented */ - return NULL; + struct GNUNET_TRANSPORT_ValidationMonitoringContext *val_ctx; + struct GNUNET_CLIENT_Connection *client; + + client = GNUNET_CLIENT_connect ("transport", cfg); + if (client == NULL) + return NULL; + if (GNUNET_YES != one_shot) + timeout = GNUNET_TIME_UNIT_FOREVER_REL; + val_ctx = GNUNET_new (struct GNUNET_TRANSPORT_ValidationMonitoringContext); + val_ctx->cb = validation_callback; + val_ctx->cb_cls = validation_callback_cls; + val_ctx->cfg = cfg; + val_ctx->timeout = GNUNET_TIME_relative_to_absolute (timeout); + if (NULL != peer) + val_ctx->peer = *peer; + val_ctx->one_shot = one_shot; + val_ctx->client = client; + send_val_mon_request (val_ctx); + + return val_ctx; } @@ -561,7 +783,17 @@ GNUNET_TRANSPORT_monitor_validation_entries (const struct void GNUNET_TRANSPORT_monitor_validation_entries_cancel (struct GNUNET_TRANSPORT_ValidationMonitoringContext *vic) { - /* Not implemented */ + if (NULL != vic->client) + { + GNUNET_CLIENT_disconnect (vic->client); + vic->client = NULL; + } + if (GNUNET_SCHEDULER_NO_TASK != vic->reconnect_task) + { + GNUNET_SCHEDULER_cancel (vic->reconnect_task); + vic->reconnect_task = GNUNET_SCHEDULER_NO_TASK; + } + GNUNET_free (vic); }