X-Git-Url: https://git.librecmc.org/?a=blobdiff_plain;f=src%2Ftransport%2Fgnunet-service-transport.c;h=efe53e0215388c90c214f377540e225ca77e5ed1;hb=cf45b8dff29c366d51aa2e6ea6a64b99b514b9c9;hp=f0fff02a7e4ba7b38215d69646fd39c3f2a1aedb;hpb=20bc0ad630965adedb63c8eacf96a118f5d7ed0b;p=oweals%2Fgnunet.git diff --git a/src/transport/gnunet-service-transport.c b/src/transport/gnunet-service-transport.c index f0fff02a7..efe53e021 100644 --- a/src/transport/gnunet-service-transport.c +++ b/src/transport/gnunet-service-transport.c @@ -67,8 +67,13 @@ /** * How long until a HELLO verification attempt should time out? + * Must be rather small, otherwise a partially successful HELLO + * validation (some addresses working) might not be available + * before a client's request for a connection fails for good. + * Besides, if a single request to an address takes a long time, + * then the peer is unlikely worthwhile anyway. */ -#define HELLO_VERIFICATION_TIMEOUT GNUNET_TIME_UNIT_MINUTES +#define HELLO_VERIFICATION_TIMEOUT GNUNET_TIME_relative_multiply (GNUNET_TIME_UNIT_SECONDS, 3) /** * How often do we re-add (cheaper) plugins to our list of plugins @@ -547,7 +552,7 @@ struct GNUNET_SCHEDULER_Handle *sched; /** * Our configuration. */ -struct GNUNET_CONFIGURATION_Handle *cfg; +const struct GNUNET_CONFIGURATION_Handle *cfg; /** * Linked list of all clients to this service. @@ -667,7 +672,7 @@ transmit_to_client_callback (void *cls, size_t size, void *buf) uint16_t msize; size_t tsize; const struct GNUNET_MessageHeader *msg; - struct GNUNET_NETWORK_TransmitHandle *th; + struct GNUNET_CONNECTION_TransmitHandle *th; char *cbuf; if (buf == NULL) @@ -692,6 +697,11 @@ transmit_to_client_callback (void *cls, size_t size, void *buf) msize = ntohs (msg->size); if (msize + tsize > size) break; +#if DEBUG_TRANSPORT + GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, + "Transmitting message of type %u to client.\n", + ntohs (msg->type)); +#endif client->message_queue_head = q->next; if (q->next == NULL) client->message_queue_tail = NULL; @@ -700,9 +710,9 @@ transmit_to_client_callback (void *cls, size_t size, void *buf) GNUNET_free (q); client->message_count--; } - GNUNET_assert (tsize > 0); if (NULL != q) { + GNUNET_assert (msize >= sizeof (struct GNUNET_MessageHeader)); th = GNUNET_SERVER_notify_transmit_ready (client->client, msize, GNUNET_TIME_UNIT_FOREVER_REL, @@ -730,7 +740,7 @@ transmit_to_client (struct TransportClient *client, { struct ClientMessageQueueEntry *q; uint16_t msize; - struct GNUNET_NETWORK_TransmitHandle *th; + struct GNUNET_CONNECTION_TransmitHandle *th; if ((client->message_count >= MAX_PENDING) && (GNUNET_YES == may_drop)) { @@ -743,6 +753,7 @@ transmit_to_client (struct TransportClient *client, } client->message_count++; msize = ntohs (msg->size); + GNUNET_assert (msize >= sizeof (struct GNUNET_MessageHeader)); q = GNUNET_malloc (sizeof (struct ClientMessageQueueEntry) + msize); memcpy (&q[1], msg, msize); /* append to message queue */ @@ -798,24 +809,32 @@ try_alternative_plugins (struct NeighbourList *neighbour) /** - * Check the ready list for the given neighbour and - * if a plugin is ready for transmission (and if we - * have a message), do so! + * The peer specified by the given neighbour has timed-out or a plugin + * has disconnected. We may either need to do nothing (other plugins + * still up), or trigger a full disconnect and clean up. This + * function updates our state and do the necessary notifications. + * Also notifies our clients that the neighbour is now officially + * gone. * - * @param neighbour target peer for which to check the plugins + * @param n the neighbour list entry for the peer + * @param check should we just check if all plugins + * disconnected or must we ask all plugins to + * disconnect? */ -static void try_transmission_to_peer (struct NeighbourList *neighbour); +static void +disconnect_neighbour (struct NeighbourList *n, + int check); /** - * The peer specified by the given neighbour has timed-out. Update - * our state and do the necessary notifications. Also notifies - * our clients that the neighbour is now officially gone. + * Check the ready list for the given neighbour and + * if a plugin is ready for transmission (and if we + * have a message), do so! * - * @param n the neighbour list entry for the peer + * @param neighbour target peer for which to check the plugins */ -static void -disconnect_neighbour (struct NeighbourList *n); +static void +try_transmission_to_peer (struct NeighbourList *neighbour); /** @@ -868,11 +887,16 @@ transmit_send_continuation (void *cls, "Transmission to peer `%s' failed, marking connection as down.\n", GNUNET_i2s(target)); rl->connected = GNUNET_NO; + rl->plugin_handle = NULL; } if (!mq->internal_msg) rl->transmit_ready = GNUNET_YES; if (mq->client != NULL) { + GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, + "Notifying client %p about failed transission to peer `%4s'.\n", + mq->client, + GNUNET_i2s(target)); send_ok_msg.header.size = htons (sizeof (send_ok_msg)); send_ok_msg.header.type = htons (GNUNET_MESSAGE_TYPE_TRANSPORT_SEND_OK); send_ok_msg.success = htonl (result); @@ -885,8 +909,8 @@ transmit_send_continuation (void *cls, another message (if available) */ if (result == GNUNET_OK) try_transmission_to_peer (n); - else - disconnect_neighbour (n); + else + disconnect_neighbour (n, GNUNET_YES); } @@ -1159,9 +1183,9 @@ update_addresses (struct TransportPlugin *plugin, int fresh) struct AddressList *next; int expired; - if (plugin->address_update_task != GNUNET_SCHEDULER_NO_PREREQUISITE_TASK) + if (plugin->address_update_task != GNUNET_SCHEDULER_NO_TASK) GNUNET_SCHEDULER_cancel (plugin->env.sched, plugin->address_update_task); - plugin->address_update_task = GNUNET_SCHEDULER_NO_PREREQUISITE_TASK; + plugin->address_update_task = GNUNET_SCHEDULER_NO_TASK; now = GNUNET_TIME_absolute_get (); min_remaining = GNUNET_TIME_UNIT_FOREVER_REL; expired = GNUNET_NO; @@ -1194,9 +1218,6 @@ update_addresses (struct TransportPlugin *plugin, int fresh) if (min_remaining.value < GNUNET_TIME_UNIT_FOREVER_REL.value) plugin->address_update_task = GNUNET_SCHEDULER_add_delayed (plugin->env.sched, - GNUNET_NO, - GNUNET_SCHEDULER_PRIORITY_IDLE, - GNUNET_SCHEDULER_NO_PREREQUISITE_TASK, min_remaining, &expire_address_task, plugin); @@ -1213,7 +1234,7 @@ static void expire_address_task (void *cls, const struct GNUNET_SCHEDULER_TaskContext *tc) { struct TransportPlugin *plugin = cls; - plugin->address_update_task = GNUNET_SCHEDULER_NO_PREREQUISITE_TASK; + plugin->address_update_task = GNUNET_SCHEDULER_NO_TASK; update_addresses (plugin, GNUNET_NO); } @@ -1438,6 +1459,7 @@ cleanup_validation (void *cls, const struct GNUNET_SCHEDULER_TaskContext *tc) struct ValidationList *pos; struct ValidationList *prev; struct GNUNET_TIME_Absolute now; + struct GNUNET_TIME_Absolute first; struct GNUNET_HELLO_Message *hello; struct GNUNET_PeerIdentity pid; struct NeighbourList *n; @@ -1493,16 +1515,19 @@ cleanup_validation (void *cls, const struct GNUNET_SCHEDULER_TaskContext *tc) /* finally, reschedule cleanup if needed; list is ordered by timeout, so we need the last element... */ - pos = pending_validations; - while ((pos != NULL) && (pos->next != NULL)) - pos = pos->next; - if (NULL != pos) - GNUNET_SCHEDULER_add_delayed (sched, - GNUNET_NO, - GNUNET_SCHEDULER_PRIORITY_IDLE, - GNUNET_SCHEDULER_NO_PREREQUISITE_TASK, - GNUNET_TIME_absolute_get_remaining - (pos->timeout), &cleanup_validation, NULL); + if (NULL != pending_validations) + { + first = pending_validations->timeout; + pos = pending_validations; + while (pos != NULL) + { + first = GNUNET_TIME_absolute_min (first, pos->timeout); + pos = pos->next; + } + GNUNET_SCHEDULER_add_delayed (sched, + GNUNET_TIME_absolute_get_remaining (first), + &cleanup_validation, NULL); + } } @@ -1530,7 +1555,7 @@ plugin_env_notify_validation (void *cls, uint32_t challenge, const char *sender_addr) { - int all_done; + unsigned int not_done; int matched; struct ValidationList *pos; struct ValidationAddress *va; @@ -1557,7 +1582,7 @@ plugin_env_notify_validation (void *cls, GNUNET_i2s(peer)); return; } - all_done = GNUNET_YES; + not_done = 0; matched = GNUNET_NO; va = pos->addresses; while (va != NULL) @@ -1566,7 +1591,10 @@ plugin_env_notify_validation (void *cls, { #if DEBUG_TRANSPORT GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, - "Confirmed validity of peer address.\n"); + "Confirmed validity of address, peer `%4s' has address `%s'.\n", + GNUNET_i2s (peer), + GNUNET_a2s ((const struct sockaddr*) &va[1], + va->addr_len)); #endif GNUNET_log (GNUNET_ERROR_TYPE_INFO | GNUNET_ERROR_TYPE_BULK, _("Another peer saw us using the address `%s' via `%s'. If this is not plausible, this address should be listed in the configuration as implausible to avoid MiM attacks.\n"), @@ -1578,7 +1606,7 @@ plugin_env_notify_validation (void *cls, matched = GNUNET_YES; } if (va->ok != GNUNET_YES) - all_done = GNUNET_NO; + not_done++; va = va->next; } if (GNUNET_NO == matched) @@ -1589,15 +1617,29 @@ plugin_env_notify_validation (void *cls, ("Received `%s' message but have no record of a matching `%s' message. Ignoring.\n"), "PONG", "PING"); } - if (GNUNET_YES == all_done) + if (0 == not_done) { +#if DEBUG_TRANSPORT + GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, + "All addresses validated, will now construct `%s' for `%4s'.\n", + "HELLO", + GNUNET_i2s (peer)); +#endif pos->timeout.value = 0; - GNUNET_SCHEDULER_add_delayed (sched, - GNUNET_NO, - GNUNET_SCHEDULER_PRIORITY_IDLE, - GNUNET_SCHEDULER_NO_PREREQUISITE_TASK, - GNUNET_TIME_UNIT_ZERO, - &cleanup_validation, NULL); + GNUNET_SCHEDULER_add_with_priority (sched, + GNUNET_SCHEDULER_PRIORITY_IDLE, + &cleanup_validation, NULL); + } + else + { +#if DEBUG_TRANSPORT + GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, + "Still waiting for %u additional `%s' messages before constructing `%s' for `%4s'.\n", + not_done, + "PONG", + "HELLO", + GNUNET_i2s (peer)); +#endif } } @@ -1718,14 +1760,21 @@ check_hello_validated (void *cls, GNUNET_assert (GNUNET_OK == GNUNET_HELLO_get_id (chvc->hello, &apeer)); +#if DEBUG_TRANSPORT + GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, + "Ready to validate addresses from `%s' message for peer `%4s'\n", + "HELLO", GNUNET_i2s (&apeer)); +#endif va = chvc->e->addresses; while (va != NULL) { #if DEBUG_TRANSPORT GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, - "Establishing `%s' connection to validate `%s' of `%4s'\n", + "Establishing `%s' connection to validate `%s' address `%s' of `%4s'\n", va->transport_name, "HELLO", + GNUNET_a2s ((const struct sockaddr*) &va[1], + va->addr_len), GNUNET_i2s (&apeer)); #endif tp = find_transport (va->transport_name); @@ -1740,14 +1789,9 @@ check_hello_validated (void *cls, va->ok = GNUNET_SYSERR; va = va->next; } - if (chvc->e->next == NULL) - GNUNET_SCHEDULER_add_delayed (sched, - GNUNET_NO, - GNUNET_SCHEDULER_PRIORITY_IDLE, - GNUNET_SCHEDULER_NO_PREREQUISITE_TASK, - GNUNET_TIME_absolute_get_remaining - (chvc->e->timeout), &cleanup_validation, - NULL); + GNUNET_SCHEDULER_add_delayed (sched, + GNUNET_TIME_absolute_get_remaining (chvc->e->timeout), + &cleanup_validation, NULL); GNUNET_free (chvc); } @@ -1833,19 +1877,37 @@ process_hello (struct TransportPlugin *plugin, /** - * The peer specified by the given neighbour has timed-out. Update - * our state and do the necessary notifications. Also notifies - * our clients that the neighbour is now officially gone. + * The peer specified by the given neighbour has timed-out or a plugin + * has disconnected. We may either need to do nothing (other plugins + * still up), or trigger a full disconnect and clean up. This + * function updates our state and do the necessary notifications. + * Also notifies our clients that the neighbour is now officially + * gone. * * @param n the neighbour list entry for the peer + * @param check should we just check if all plugins + * disconnected or must we ask all plugins to + * disconnect? */ static void -disconnect_neighbour (struct NeighbourList *n) +disconnect_neighbour (struct NeighbourList *n, + int check) { struct ReadyList *rpos; struct NeighbourList *npos; struct NeighbourList *nprev; struct MessageQueue *mq; + + if (GNUNET_YES == check) + { + rpos = n->plugins; + while (NULL != rpos) + { + if (GNUNET_YES == rpos->connected) + return; /* still connected */ + rpos = rpos->next; + } + } #if DEBUG_TRANSPORT GNUNET_log (GNUNET_ERROR_TYPE_DEBUG | GNUNET_ERROR_TYPE_BULK, @@ -1869,13 +1931,16 @@ disconnect_neighbour (struct NeighbourList *n) /* notify all clients about disconnect */ notify_clients_disconnect (&n->id); - /* clean up all plugins, cancel connections & pending transmissions */ + /* clean up all plugins, cancel connections and pending transmissions */ while (NULL != (rpos = n->plugins)) { n->plugins = rpos->next; GNUNET_assert (rpos->neighbour == n); - rpos->plugin->api->cancel (rpos->plugin->api->cls, - rpos->plugin_handle, rpos, &n->id); + if (GNUNET_YES == rpos->connected) + rpos->plugin->api->cancel (rpos->plugin->api->cls, + rpos->plugin_handle, + rpos, + &n->id); GNUNET_free (rpos); } @@ -1886,7 +1951,9 @@ disconnect_neighbour (struct NeighbourList *n) GNUNET_assert (mq->neighbour == n); GNUNET_free (mq); } - + if (n->timeout_task != GNUNET_SCHEDULER_NO_TASK) + GNUNET_SCHEDULER_cancel (sched, + n->timeout_task); /* finally, free n itself */ GNUNET_free (n); } @@ -1935,8 +2002,8 @@ neighbour_timeout_task (void *cls, "Neighbour `%4s' has timed out!\n", GNUNET_i2s(&n->id)); #endif - n->timeout_task = GNUNET_SCHEDULER_NO_PREREQUISITE_TASK; - disconnect_neighbour (n); + n->timeout_task = GNUNET_SCHEDULER_NO_TASK; + disconnect_neighbour (n, GNUNET_NO); } @@ -1969,9 +2036,6 @@ setup_new_neighbour (const struct GNUNET_PeerIdentity *peer) n->quota_in = (GNUNET_CONSTANTS_DEFAULT_BPM_IN_OUT + 59999) / (60 * 1000); add_plugins (n); n->timeout_task = GNUNET_SCHEDULER_add_delayed (sched, - GNUNET_NO, - GNUNET_SCHEDULER_PRIORITY_IDLE, - GNUNET_SCHEDULER_NO_PREREQUISITE_TASK, GNUNET_CONSTANTS_IDLE_CONNECTION_TIMEOUT, &neighbour_timeout_task, n); transmit_to_peer (NULL, 0, @@ -1988,6 +2052,7 @@ setup_new_neighbour (const struct GNUNET_PeerIdentity *peer) * reducing the rate at which they read from the socket * and generally forward to our receive callback. * + * @param cls the "struct TransportPlugin *" we gave to the plugin * @param plugin_context value to pass to this plugin * to respond to the given peer (use is optional, * but may speed up processing) @@ -2042,13 +2107,19 @@ plugin_env_receive (void *cls, } if (message == NULL) { +#if DEBUG_TRANSPORT + GNUNET_log (GNUNET_ERROR_TYPE_DEBUG | GNUNET_ERROR_TYPE_BULK, + "Receive failed from `%4s', triggering disconnect\n", + GNUNET_i2s(&n->id)); +#endif + /* TODO: call stats */ if ((service_context != NULL) && (service_context->plugin_handle == plugin_context)) { service_context->connected = GNUNET_NO; service_context->plugin_handle = NULL; } - /* TODO: call stats */ + disconnect_neighbour (n, GNUNET_YES); return NULL; } #if DEBUG_TRANSPORT @@ -2076,9 +2147,7 @@ plugin_env_receive (void *cls, n->peer_timeout = GNUNET_TIME_relative_to_absolute (GNUNET_CONSTANTS_IDLE_CONNECTION_TIMEOUT); n->timeout_task = - GNUNET_SCHEDULER_add_delayed (sched, GNUNET_NO, - GNUNET_SCHEDULER_PRIORITY_IDLE, - GNUNET_SCHEDULER_NO_PREREQUISITE_TASK, + GNUNET_SCHEDULER_add_delayed (sched, GNUNET_CONSTANTS_IDLE_CONNECTION_TIMEOUT, &neighbour_timeout_task, n); update_quota (n); @@ -2090,7 +2159,8 @@ plugin_env_receive (void *cls, _ ("Dropping incoming message due to repeated bandwidth quota violations.\n")); /* TODO: call stats */ - GNUNET_assert (NULL != service_context->neighbour); + GNUNET_assert ( (service_context == NULL) || + (NULL != service_context->neighbour) ); return service_context; } switch (ntohs (message->type)) @@ -2135,7 +2205,8 @@ plugin_env_receive (void *cls, } GNUNET_free (im); } - GNUNET_assert (NULL != service_context->neighbour); + GNUNET_assert ( (service_context == NULL) || + (NULL != service_context->neighbour) ); return service_context; } @@ -2363,8 +2434,10 @@ handle_try_connect (void *cls, tcm = (const struct TryConnectMessage *) message; #if DEBUG_TRANSPORT GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, - "Received `%s' request from client asking to connect to `%4s'\n", - "TRY_CONNECT", GNUNET_i2s (&tcm->peer)); + "Received `%s' request from client %p asking to connect to `%4s'\n", + "TRY_CONNECT", + client, + GNUNET_i2s (&tcm->peer)); #endif if (NULL == find_neighbour (&tcm->peer)) setup_new_neighbour (&tcm->peer); @@ -2498,6 +2571,42 @@ client_disconnect_notification (void *cls, } +/** + * Function called when the service shuts down. Unloads our plugins. + * + * @param cls closure, unused + * @param tc task context (unused) + */ +static void +unload_plugins (void *cls, + const struct GNUNET_SCHEDULER_TaskContext *tc) +{ + struct TransportPlugin *plug; + struct AddressList *al; + +#if DEBUG_TRANSPORT + GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, + "Transport service is unloading plugins...\n"); +#endif + while (NULL != (plug = plugins)) + { + plugins = plug->next; + GNUNET_break (NULL == GNUNET_PLUGIN_unload (plug->lib_name, plug->api)); + GNUNET_free (plug->lib_name); + GNUNET_free (plug->short_name); + while (NULL != (al = plug->addresses)) + { + plug->addresses = al->next; + GNUNET_free (al); + } + GNUNET_free (plug); + } + if (my_private_key != NULL) + GNUNET_CRYPTO_rsa_key_free (my_private_key); + GNUNET_free_non_null (our_hello); +} + + /** * Initiate transport service. * @@ -2509,7 +2618,8 @@ client_disconnect_notification (void *cls, static void run (void *cls, struct GNUNET_SCHEDULER_Handle *s, - struct GNUNET_SERVER_Handle *serv, struct GNUNET_CONFIGURATION_Handle *c) + struct GNUNET_SERVER_Handle *serv, + const struct GNUNET_CONFIGURATION_Handle *c) { char *plugs; char *pos; @@ -2571,6 +2681,9 @@ run (void *cls, } GNUNET_free (plugs); } + GNUNET_SCHEDULER_add_delayed (sched, + GNUNET_TIME_UNIT_FOREVER_REL, + &unload_plugins, NULL); if (no_transports) refresh_hello (); #if DEBUG_TRANSPORT @@ -2582,41 +2695,6 @@ run (void *cls, } -/** - * Function called when the service shuts - * down. Unloads our plugins. - * - * @param cls closure - * @param cfg configuration to use - */ -static void -unload_plugins (void *cls, struct GNUNET_CONFIGURATION_Handle *cfg) -{ - struct TransportPlugin *plug; - struct AddressList *al; - -#if DEBUG_TRANSPORT - GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, - "Transport service is unloading plugins...\n"); -#endif - while (NULL != (plug = plugins)) - { - plugins = plug->next; - GNUNET_break (NULL == GNUNET_PLUGIN_unload (plug->lib_name, plug->api)); - GNUNET_free (plug->lib_name); - GNUNET_free (plug->short_name); - while (NULL != (al = plug->addresses)) - { - plug->addresses = al->next; - GNUNET_free (al); - } - GNUNET_free (plug); - } - if (my_private_key != NULL) - GNUNET_CRYPTO_rsa_key_free (my_private_key); -} - - /** * The main function for the transport service. * @@ -2628,10 +2706,10 @@ int main (int argc, char *const *argv) { return (GNUNET_OK == - GNUNET_SERVICE_run (argc, - argv, - "transport", - &run, NULL, &unload_plugins, NULL)) ? 0 : 1; + GNUNET_SERVICE_run (argc, + argv, + "transport", + &run, NULL)) ? 0 : 1; } /* end of gnunet-service-transport.c */