From 4b86063584ff95cc79b0af4f712dd5166962c1e9 Mon Sep 17 00:00:00 2001 From: Christian Grothoff Date: Fri, 19 Mar 2010 13:42:36 +0000 Subject: [PATCH] better session selection --- src/transport/gnunet-service-transport.c | 10 ++-- src/transport/plugin_transport_tcp.c | 71 ++++++++++++++++++++---- 2 files changed, 63 insertions(+), 18 deletions(-) diff --git a/src/transport/gnunet-service-transport.c b/src/transport/gnunet-service-transport.c index 75580ce79..7c66011e3 100644 --- a/src/transport/gnunet-service-transport.c +++ b/src/transport/gnunet-service-transport.c @@ -866,11 +866,6 @@ static void try_transmission_to_peer (struct NeighbourList *neighbour); /** * Find an entry in the neighbour list for a particular peer. - * if sender_address is not specified (NULL) then return the - * first matching entry. If sender_address is specified, then - * make sure that the address and address_len also matches. - * - * FIXME: This description does not fit the function. * * @return NULL if not found. */ @@ -1241,6 +1236,7 @@ try_transmission_to_peer (struct NeighbourList *neighbour) struct MessageQueue *mq; struct GNUNET_TIME_Relative timeout; ssize_t ret; + int force_address; if (neighbour->messages_head == NULL) { @@ -1252,6 +1248,7 @@ try_transmission_to_peer (struct NeighbourList *neighbour) rl = NULL; mq = neighbour->messages_head; /* FIXME: support bi-directional use of TCP */ + force_address = GNUNET_YES; if (mq->specific_address == NULL) { mq->specific_address = find_ready_address(neighbour); @@ -1259,6 +1256,7 @@ try_transmission_to_peer (struct NeighbourList *neighbour) gettext_noop ("# transport selected peer address freely"), 1, GNUNET_NO); + force_address = GNUNET_NO; } if (mq->specific_address == NULL) { @@ -1347,7 +1345,7 @@ try_transmission_to_peer (struct NeighbourList *neighbour) GNUNET_CONSTANTS_IDLE_CONNECTION_TIMEOUT, mq->specific_address->addr, mq->specific_address->addrlen, - GNUNET_YES /* FIXME: sometimes, we want to be more tolerant here! */, + force_address, &transmit_send_continuation, mq); if (ret == -1) { diff --git a/src/transport/plugin_transport_tcp.c b/src/transport/plugin_transport_tcp.c index afba750f2..72c99b3ea 100644 --- a/src/transport/plugin_transport_tcp.c +++ b/src/transport/plugin_transport_tcp.c @@ -173,6 +173,12 @@ struct Session */ void *connect_addr; + /** + * Last activity on this connection. Used to select preferred + * connection. + */ + struct GNUNET_TIME_Absolute last_activity; + /** * Length of connect_addr. */ @@ -297,6 +303,7 @@ create_session (struct Plugin *plugin, "Creating new session for peer `%4s'\n", GNUNET_i2s (target)); ret = GNUNET_malloc (sizeof (struct Session)); + ret->last_activity = GNUNET_TIME_absolute_get (); ret->plugin = plugin; ret->next = plugin->sessions; plugin->sessions = ret; @@ -438,6 +445,7 @@ do_transmit (void *cls, size_t size, void *buf) cancel everything don't cause us to use a session that no longer exists... */ process_pending_messages (session); + session->last_activity = GNUNET_TIME_absolute_get (); pid = session->target; /* we'll now call callbacks that may cancel the session; hence we should not use 'session' after this point */ @@ -579,6 +587,41 @@ disconnect_session (struct Session *session) } +/** + * Given two otherwise equivalent sessions, pick the better one. + * + * @param s1 one session (also default) + * @param s2 other session + * @return "better" session (more active) + */ +static struct Session * +select_better_session (struct Session *s1, + struct Session *s2) +{ + if (s1 == NULL) + return s2; + if (s2 == NULL) + return s1; + if ( (s1->expecting_welcome == GNUNET_NO) && + (s2->expecting_welcome == GNUNET_YES) ) + return s1; + if ( (s1->expecting_welcome == GNUNET_YES) && + (s2->expecting_welcome == GNUNET_NO) ) + return s2; + if (s1->last_activity.value < s2->last_activity.value) + return s2; + if (s1->last_activity.value > s2->last_activity.value) + return s1; + if ( (GNUNET_YES == s1->inbound) && + (GNUNET_NO == s2->inbound) ) + return s1; + if ( (GNUNET_NO == s1->inbound) && + (GNUNET_YES == s2->inbound) ) + return s2; + return s1; +} + + /** * Function that can be used by the transport service to transmit * a message using the plugin. Note that in the case of a @@ -628,6 +671,7 @@ tcp_plugin_send (void *cls, { struct Plugin *plugin = cls; struct Session *session; + struct Session *cand_session; struct Session *next; struct PendingMessage *pm; struct GNUNET_CONNECTION_Handle *sa; @@ -640,25 +684,24 @@ tcp_plugin_send (void *cls, /* FIXME: we could do this a cheaper with a hash table where we could restrict the iteration to entries that match the target peer... */ + cand_session = NULL; next = plugin->sessions; while (NULL != (session = next)) { next = session->next; - if (session->client == NULL) - continue; + GNUNET_assert (session->client != NULL); if (0 != memcmp (target, &session->target, sizeof (struct GNUNET_PeerIdentity))) continue; - if (GNUNET_SYSERR == force_address) + if ( ( (GNUNET_SYSERR == force_address) && + (session->expecting_welcome == GNUNET_NO) ) || + (GNUNET_NO == force_address) ) { - if (session->expecting_welcome == GNUNET_NO) - break; /* established and reliable (TCP!) */ - else - continue; /* not established */ + cand_session = select_better_session (cand_session, + session); + continue; } - if (GNUNET_NO == force_address) - break; GNUNET_break (GNUNET_YES == force_address); if (addr == NULL) { @@ -669,11 +712,14 @@ tcp_plugin_send (void *cls, continue; if (addrlen != session->connect_alen) continue; - if (0 == memcmp (session->connect_addr, + if (0 != memcmp (session->connect_addr, addr, addrlen)) - break; + continue; + cand_session = select_better_session (cand_session, + session); } + session = cand_session; if ( (session == NULL) && (addr == NULL) ) { @@ -1112,18 +1158,19 @@ handle_tcp_data (void *cls, struct Session *session; struct GNUNET_TIME_Relative delay; - session = find_session_by_client (plugin, client); if (GNUNET_MESSAGE_TYPE_TRANSPORT_TCP_WELCOME == ntohs(message->type)) { /* We don't want to propagate WELCOME messages up! */ GNUNET_SERVER_receive_done (client, GNUNET_OK); return; } + session = find_session_by_client (plugin, client); if ( (NULL == session) || (GNUNET_NO != session->expecting_welcome)) { GNUNET_SERVER_receive_done (client, GNUNET_SYSERR); return; } + session->last_activity = GNUNET_TIME_absolute_get (); #if DEBUG_TCP GNUNET_log_from (GNUNET_ERROR_TYPE_DEBUG, "tcp", -- 2.25.1