complete state reset functionality
[oweals/gnunet.git] / src / transport / gnunet-service-transport_neighbours_3way.c
index db1d643f9e499bde603659a02604024193aa32ca..516ef6b7063154f556592f73ede9e050664be5bc 100644 (file)
 
 #define ATS_RESPONSE_TIMEOUT GNUNET_TIME_relative_multiply (GNUNET_TIME_UNIT_SECONDS, 3)
 
+
+#define SETUP_CONNECTION_TIMEOUT GNUNET_TIME_relative_multiply (GNUNET_TIME_UNIT_SECONDS, 5)
+
+
 /**
  * Entry in neighbours.
  */
@@ -286,8 +290,18 @@ struct NeighbourMapEntry
    */
   struct GNUNET_TIME_Absolute connect_ts;
 
+  /**
+   * Timeout for ATS
+   * We asked ATS for a new address for this peer
+   */
   GNUNET_SCHEDULER_TaskIdentifier ats_suggest;
 
+  /**
+   * Task the resets the peer state after due to an pending
+   * unsuccessful connection setup
+   */
+  GNUNET_SCHEDULER_TaskIdentifier state_reset;
+
   /**
    * How often has the other peer (recently) violated the inbound
    * traffic limit?  Incremented by 10 per violation, decremented by 1
@@ -295,18 +309,11 @@ struct NeighbourMapEntry
    */
   unsigned int quota_violation_count;
 
-  /**
-   * Number of values in 'ats' array.
-   */
-  //unsigned int ats_count;
-
 
   /**
-   * Do we currently consider this neighbour connected? (as far as
-   * the connect/disconnect callbacks are concerned)?
+   * The current state of the peer
+   * Element of enum State
    */
-  //int is_connected;
-
   int state;
 
 };
@@ -404,6 +411,49 @@ print_state (int state)
   return NULL;
 }
 
+static int
+change (struct NeighbourMapEntry * n, int state, int line);
+
+static void
+ats_suggest_cancel (void *cls,
+    const struct GNUNET_SCHEDULER_TaskContext *tc);
+
+static void
+reset_task (void *cls,
+            const struct GNUNET_SCHEDULER_TaskContext *tc)
+{
+  struct NeighbourMapEntry * n = cls;
+
+  n->state_reset = GNUNET_SCHEDULER_NO_TASK;
+
+#if DEBUG_TRANSPORT
+  GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
+      "Connection to peer `%s' %s failed in state `%s', resetting connection attempt \n",
+      GNUNET_i2s (&n->id), GST_plugins_a2s(n->plugin_name, n->addr, n->addrlen), print_state(n->state));
+#endif
+  GNUNET_STATISTICS_update (GST_stats,
+                            gettext_noop ("# failed connection attempts due to timeout"),
+                            1,
+                            GNUNET_NO);
+
+  /* resetting state */
+  n->state = S_NOT_CONNECTED;
+
+  /* destroying address */
+  GNUNET_ATS_address_destroyed (GST_ats,
+                                &n->id,
+                                n->plugin_name,
+                                n->addr,
+                                n->addrlen,
+                                NULL);
+
+  /* request new address */
+  if (n->ats_suggest != GNUNET_SCHEDULER_NO_TASK)
+    GNUNET_SCHEDULER_cancel(n->ats_suggest);
+  n->ats_suggest = GNUNET_SCHEDULER_add_delayed (ATS_RESPONSE_TIMEOUT, ats_suggest_cancel, n);
+  GNUNET_ATS_suggest_address(GST_ats, &n->id);
+}
+
 static int
 change (struct NeighbourMapEntry * n, int state, int line)
 {
@@ -418,13 +468,33 @@ change (struct NeighbourMapEntry * n, int state, int line)
         (state == S_DISCONNECT))
     {
       allowed = GNUNET_YES;
+
+      /* Schedule reset task */
+      if ((state == S_CONNECT_RECV) || (state == S_CONNECT_SENT) )
+      {
+        GNUNET_assert (n->state_reset == GNUNET_SCHEDULER_NO_TASK);
+        n->state_reset = GNUNET_SCHEDULER_add_delayed (SETUP_CONNECTION_TIMEOUT, &reset_task, n);
+      }
+
       break;
     }
     break;
   case S_CONNECT_RECV:
     if ((state == S_NOT_CONNECTED) || (state == S_DISCONNECT) ||
-        (state == S_CONNECTED))
+        (state == S_CONNECTED) || /* FIXME SENT -> RECV ISSUE!*/ (state == S_CONNECT_SENT))
     {
+      if ((state == S_CONNECTED) || (state == S_DISCONNECT) || (state == S_NOT_CONNECTED))
+      {
+#if DEBUG_TRANSPORT
+        GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
+            "Removed reset task for peer `%s' %s failed in state transition `%s' -> `%s' \n",
+            GNUNET_i2s (&n->id), GST_plugins_a2s(n->plugin_name, n->addr, n->addrlen), print_state(n->state), print_state(state));
+#endif
+        GNUNET_assert (n->state_reset != GNUNET_SCHEDULER_NO_TASK);
+        GNUNET_SCHEDULER_cancel (n->state_reset);
+        n->state_reset = GNUNET_SCHEDULER_NO_TASK;
+      }
+
       allowed = GNUNET_YES;
       break;
     }
@@ -433,6 +503,18 @@ change (struct NeighbourMapEntry * n, int state, int line)
     if ((state == S_NOT_CONNECTED) || (state == S_CONNECTED) ||
         (state == S_DISCONNECT) || /* FIXME SENT -> RECV ISSUE!*/ (state == S_CONNECT_RECV))
     {
+      if ((state == S_CONNECTED) || (state == S_DISCONNECT) || (state == S_NOT_CONNECTED))
+      {
+#if DEBUG_TRANSPORT
+        GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
+            "Removed reset task for peer `%s' %s failed in state transition `%s' -> `%s' \n",
+            GNUNET_i2s (&n->id), GST_plugins_a2s(n->plugin_name, n->addr, n->addrlen), print_state(n->state), print_state(state));
+#endif
+        GNUNET_assert (n->state_reset != GNUNET_SCHEDULER_NO_TASK);
+        GNUNET_SCHEDULER_cancel (n->state_reset);
+        n->state_reset = GNUNET_SCHEDULER_NO_TASK;
+      }
+
       allowed = GNUNET_YES;
       break;
     }
@@ -470,8 +552,10 @@ change (struct NeighbourMapEntry * n, int state, int line)
   }
 
   n->state = state;
-  GNUNET_log (GNUNET_ERROR_TYPE_ERROR, "State for neighbour `%s' %X changed from `%s' to `%s' in line %u\n",
+#if DEBUG_TRANSPORT
+  GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "State for neighbour `%s' %X changed from `%s' to `%s' in line %u\n",
       GNUNET_i2s (&n->id), n, old, new, line);
+#endif
   GNUNET_free (old);
   GNUNET_free (new);
   return GNUNET_OK;
@@ -673,15 +757,18 @@ GST_neighbours_start (void *cls, GNUNET_TRANSPORT_NotifyConnect connect_cb,
   neighbours = GNUNET_CONTAINER_multihashmap_create (NEIGHBOUR_TABLE_SIZE);
 }
 
-/*
+
 static void
 send_disconnect_cont (void *cls,
     const struct GNUNET_PeerIdentity * target,
     int result)
 {
+#if DEBUG_TRANSPORT
   struct NeighbourMapEntry *n = cls;
-
-}*/
+  GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "Sending DISCONNECT message to peer `%4s': %i\n",
+              GNUNET_i2s (&n->id), result);
+#endif
+}
 
 static int
 send_disconnect (struct NeighbourMapEntry *n)
@@ -708,10 +795,10 @@ send_disconnect (struct NeighbourMapEntry *n)
                                          &disconnect_msg.purpose,
                                          &disconnect_msg.signature));
 
-  ret = send_with_plugin(&n->id,
-      (const char *) &disconnect_msg, sizeof (disconnect_msg),
-      UINT32_MAX, GNUNET_TIME_UNIT_FOREVER_REL, n->session, n->plugin_name, n->addr, n->addrlen,
-      GNUNET_YES, NULL, NULL);
+  ret = send_with_plugin(&n->id, (const char *) &disconnect_msg, sizeof (disconnect_msg),
+                          UINT32_MAX, GNUNET_TIME_UNIT_FOREVER_REL,
+                          n->session, n->plugin_name, n->addr, n->addrlen,
+                          GNUNET_YES, &send_disconnect_cont, n);
 
   if (ret == GNUNET_SYSERR)
     return GNUNET_SYSERR;
@@ -733,9 +820,6 @@ disconnect_neighbour (struct NeighbourMapEntry *n)
   struct MessageQueue *mq;
   int was_connected = is_connected(n);
 
-  if (is_disconnecting(n) == GNUNET_YES)
-    return;
-
   /* send DISCONNECT MESSAGE */
   if (is_connected(n) || is_connecting(n))
   {
@@ -897,7 +981,7 @@ ats_suggest_cancel (void *cls,
 
   n->ats_suggest = GNUNET_SCHEDULER_NO_TASK;
 
-  GNUNET_log (GNUNET_ERROR_TYPE_WARNING,
+  GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
               " ATS did not suggested address to connect to peer `%s'\n",
               GNUNET_i2s (&n->id));
 
@@ -964,9 +1048,9 @@ send_connect_continuation (void *cls,
                                  n->addrlen,
                                  NULL);
 
-    if (n(ATS_RESPONSE_TIMEOUT, at_suggest != GNUNET_SCHEDULER_NO_TASK)
+    if (n->ats_suggest!= GNUNET_SCHEDULER_NO_TASK)
       GNUNET_SCHEDULER_cancel(n->ats_suggest);
-    n->ats_suggest = GNUNET_SCHEDULER_add_delayed delayed (ATS_RESPONSE_TIMEOUT, ats_suggest_cancel, n);
+    n->ats_suggest = GNUNET_SCHEDULER_add_delayed (ATS_RESPONSE_TIMEOUT, ats_suggest_cancel, n);
     GNUNET_ATS_suggest_address(GST_ats, &n->id);
     return;
   }
@@ -1155,17 +1239,10 @@ GST_neighbours_switch_to_address_3way (const struct GNUNET_PeerIdentity *peer,
     connect_msg.timestamp =
         GNUNET_TIME_absolute_hton (GNUNET_TIME_absolute_get ());
 
-    ret = send_with_plugin (peer, (const char *) &connect_msg, msg_len, 0, GNUNET_TIME_UNIT_FOREVER_REL, session, plugin_name, address, address_len, GNUNET_YES, &send_connect_continuation, n);
-    if (ret == GNUNET_SYSERR)
-    {
-      GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
-                "Failed to send CONNECT_MESSAGE to `%4s' using plugin `%s' address '%s' session %X\n",
-                GNUNET_i2s (peer), plugin_name,
-                (address_len == 0) ? "<inbound>" : GST_plugins_a2s (plugin_name,
-                                                                    address,
-                                                                    address_len),
-                session);
-    }
+    ret = send_with_plugin (peer, (const char *) &connect_msg, msg_len, UINT32_MAX, GNUNET_TIME_UNIT_FOREVER_REL,
+                            session, plugin_name, address, address_len,
+                            GNUNET_YES, &send_connect_continuation, n);
+
     return GNUNET_NO;
   }
   /* We received a CONNECT message and asked ATS for an address */
@@ -1178,7 +1255,9 @@ GST_neighbours_switch_to_address_3way (const struct GNUNET_PeerIdentity *peer,
     connect_msg.reserved = htonl (0);
     connect_msg.timestamp = GNUNET_TIME_absolute_hton (GNUNET_TIME_absolute_get ());
 
-    ret = send_with_plugin(&n->id, (const void *) &connect_msg, msg_len, 0, GNUNET_TIME_UNIT_FOREVER_REL, session, plugin_name, address, address_len, GNUNET_YES, &send_connect_ack_continuation, n);
+    ret = send_with_plugin(&n->id, (const void *) &connect_msg, msg_len, UINT32_MAX, GNUNET_TIME_UNIT_FOREVER_REL,
+                           session, plugin_name, address, address_len,
+                           GNUNET_YES, &send_connect_ack_continuation, n);
     if (ret == GNUNET_SYSERR)
     {
       change_state (n, S_NOT_CONNECTED);
@@ -1197,7 +1276,9 @@ GST_neighbours_switch_to_address_3way (const struct GNUNET_PeerIdentity *peer,
     connect_msg.timestamp =
         GNUNET_TIME_absolute_hton (GNUNET_TIME_absolute_get ());
 
-    ret = send_with_plugin (peer, (const char *) &connect_msg, msg_len, 0, GNUNET_TIME_UNIT_FOREVER_REL, session, plugin_name, address, address_len, GNUNET_YES, &send_switch_address_continuation, n);
+    ret = send_with_plugin (peer, (const char *) &connect_msg, msg_len, UINT32_MAX, GNUNET_TIME_UNIT_FOREVER_REL,
+                            session, plugin_name, address, address_len,
+                            GNUNET_YES, &send_switch_address_continuation, n);
     if (ret == GNUNET_SYSERR)
     {
       GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
@@ -1210,8 +1291,12 @@ GST_neighbours_switch_to_address_3way (const struct GNUNET_PeerIdentity *peer,
     }
     return GNUNET_NO;
   }
-
-  GNUNET_log (GNUNET_ERROR_TYPE_ERROR, "Invalid connection state to switch addresses %u ", n->state);
+  else if (n->state == S_CONNECT_SENT)
+  {
+      //FIXME
+     return GNUNET_NO;
+  }
+  GNUNET_log (GNUNET_ERROR_TYPE_ERROR, "Invalid connection state to switch addresses %u \n", n->state);
   GNUNET_break_op (0);
   return GNUNET_NO;
 }
@@ -1287,9 +1372,6 @@ GST_neighbours_try_connect (const struct GNUNET_PeerIdentity *target)
               GNUNET_i2s (&n->id));
 #endif
 
-  if (n->ats_suggest != GNUNET_SCHEDULER_NO_TASK)
-    GNUNET_SCHEDULER_cancel(n->ats_suggest);
-   n->ats_suggest = GNUNET_SCHEDULER_add_delayed (ATS_RESPONSE_TIMEOUT, ats_suggest_cancel, n);
    GNUNET_ATS_suggest_address (GST_ats, &n->id);
 }
 
@@ -1480,9 +1562,6 @@ GST_neighbours_calculate_receive_delay (const struct GNUNET_PeerIdentity
   }
   if (!is_connected(n))
   {
-    GNUNET_log (GNUNET_ERROR_TYPE_WARNING,
-               _("Plugin gave us %d bytes of data but somehow the session is not marked as UP yet!\n"),
-               (int) size);
     *do_forward = GNUNET_SYSERR;
     return GNUNET_TIME_UNIT_ZERO;
   }
@@ -1783,16 +1862,15 @@ GST_neighbours_handle_connect_ack (const struct GNUNET_MessageHeader *message,
   const struct SessionConnectMessage *scm;
   struct QuotaSetMessage q_msg;
   struct GNUNET_MessageHeader msg;
-  struct GNUNET_TIME_Absolute ts;
   struct NeighbourMapEntry *n;
   size_t msg_len;
   size_t ret;
+  int was_connected;
 
 #if DEBUG_TRANSPORT
-#endif
-  GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
+  GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
       "Received CONNECT_ACK message from peer `%s'\n", GNUNET_i2s (peer));
-
+#endif
 
   if (ntohs (message->size) != sizeof (struct SessionConnectMessage))
   {
@@ -1802,7 +1880,6 @@ GST_neighbours_handle_connect_ack (const struct GNUNET_MessageHeader *message,
 
   scm = (const struct SessionConnectMessage *) message;
   GNUNET_break_op (ntohl (scm->reserved) == 0);
-  ts = GNUNET_TIME_absolute_ntoh (scm->timestamp);
   n = lookup_neighbour (peer);
   if (NULL == n)
     n = setup_neighbour (peer);
@@ -1826,7 +1903,9 @@ GST_neighbours_handle_connect_ack (const struct GNUNET_MessageHeader *message,
                              plugin_name, sender_address, sender_address_len,
                              session, ats, ats_count);
 
-  change_state (n, S_CONNECTED);
+  was_connected = is_connected(n);
+  if (!is_connected(n))
+    change_state (n, S_CONNECTED);
 
 #if DEBUG_TRANSPORT
   GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
@@ -1835,18 +1914,15 @@ GST_neighbours_handle_connect_ack (const struct GNUNET_MessageHeader *message,
 #endif
   GST_neighbours_set_incoming_quota(&n->id, n->bandwidth_in);
 
-  n->keepalive_task = GNUNET_SCHEDULER_add_delayed (KEEPALIVE_FREQUENCY,
-                                                      &neighbour_keepalive_task,
-                                                      n);
   /* send ACK (ACK)*/
   msg_len =  sizeof (msg);
   msg.size = htons (msg_len);
   msg.type = htons (GNUNET_MESSAGE_TYPE_TRANSPORT_SESSION_ACK);
 
-  ret = send_with_plugin (&n->id, (const char *) &msg, msg_len, 0,
-      GNUNET_TIME_UNIT_FOREVER_REL,
-      n->session, n->plugin_name, n->addr, n->addrlen,
-      GNUNET_YES, NULL, NULL);
+  ret = send_with_plugin (&n->id, (const char *) &msg, msg_len, UINT32_MAX,
+                          GNUNET_TIME_UNIT_FOREVER_REL,
+                          n->session, n->plugin_name, n->addr, n->addrlen,
+                          GNUNET_YES, NULL, NULL);
 
   if (ret == GNUNET_SYSERR)
     GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
@@ -1857,21 +1933,30 @@ GST_neighbours_handle_connect_ack (const struct GNUNET_MessageHeader *message,
                                                                  n->addrlen),
               n->session);
 
-  neighbours_connected++;
-  GNUNET_STATISTICS_update (GST_stats, gettext_noop ("# peers connected"), 1,
-                            GNUNET_NO);
-  connect_notify_cb (callback_cls, &n->id, ats, ats_count);
+
+  if (!was_connected)
+  {
+    if (n->keepalive_task == GNUNET_SCHEDULER_NO_TASK)
+      n->keepalive_task = GNUNET_SCHEDULER_add_delayed (KEEPALIVE_FREQUENCY,
+                                                        &neighbour_keepalive_task,
+                                                        n);
+
+    neighbours_connected++;
+    GNUNET_STATISTICS_update (GST_stats, gettext_noop ("# peers connected"), 1,
+                              GNUNET_NO);
+    connect_notify_cb (callback_cls, &n->id, ats, ats_count);
 
 #if DEBUG_TRANSPORT
-  GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
-              "Sending outbound quota of %u Bps for peer `%s' to all clients\n",
-              ntohl (n->bandwidth_out.value__), GNUNET_i2s (peer));
+    GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
+                "Sending outbound quota of %u Bps for peer `%s' to all clients\n",
+                ntohl (n->bandwidth_out.value__), GNUNET_i2s (peer));
 #endif
-  q_msg.header.size = htons (sizeof (struct QuotaSetMessage));
-  q_msg.header.type = htons (GNUNET_MESSAGE_TYPE_TRANSPORT_SET_QUOTA);
-  q_msg.quota = n->bandwidth_out;
-  q_msg.peer = (*peer);
-  GST_clients_broadcast (&q_msg.header, GNUNET_NO);
+    q_msg.header.size = htons (sizeof (struct QuotaSetMessage));
+    q_msg.header.type = htons (GNUNET_MESSAGE_TYPE_TRANSPORT_SET_QUOTA);
+    q_msg.quota = n->bandwidth_out;
+    q_msg.peer = (*peer);
+    GST_clients_broadcast (&q_msg.header, GNUNET_NO);
+  }
 }
 
 void
@@ -1932,7 +2017,8 @@ GST_neighbours_handle_ack (const struct GNUNET_MessageHeader *message,
 
   GST_neighbours_set_incoming_quota(&n->id, n->bandwidth_in);
 
-  n->keepalive_task = GNUNET_SCHEDULER_add_delayed (KEEPALIVE_FREQUENCY,
+  if (n->keepalive_task == GNUNET_SCHEDULER_NO_TASK)
+    n->keepalive_task = GNUNET_SCHEDULER_add_delayed (KEEPALIVE_FREQUENCY,
                                                       &neighbour_keepalive_task,
                                                       n);
 
@@ -2054,10 +2140,9 @@ GST_neighbours_handle_connect (const struct GNUNET_MessageHeader *message,
   struct BlackListCheckContext * bcc = NULL;
 
 #if DEBUG_TRANSPORT
-#endif
-  GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
+  GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
       "Received CONNECT message from peer `%s'\n", GNUNET_i2s (peer));
-
+#endif
 
   if (ntohs (message->size) != sizeof (struct SessionConnectMessage))
   {