-fix assertion failure
[oweals/gnunet.git] / src / transport / gnunet-service-transport_neighbours.c
index 6f1c4efa54c693205258f3a3aaedadb3e833baec..47e2713870609e97b384ba20ac990aae32df1f7f 100644 (file)
 /**
  * How often do we send KEEPALIVE messages to each of our neighbours and measure
  * the latency with this neighbour?
- * (idle timeout is 5 minutes or 300 seconds, so with 30s interval we
- * send 10 keepalives in each interval, so 10 messages would need to be
+ * (idle timeout is 5 minutes or 300 seconds, so with 100s interval we
+ * send 3 keepalives in each interval, so 3 messages would need to be
  * lost in a row for a disconnect).
  */
-#define KEEPALIVE_FREQUENCY GNUNET_TIME_relative_multiply (GNUNET_TIME_UNIT_SECONDS, 30)
+#define KEEPALIVE_FREQUENCY GNUNET_TIME_relative_multiply (GNUNET_TIME_UNIT_SECONDS, 100)
 
 /**
  * How long are we willing to wait for a response from ATS before timing out?
@@ -842,69 +842,16 @@ set_address (struct NeighbourAddress *na,
   }
 }
 
-/**
- * Free a neighbour map entry.
- *
- * @param n entry to free
- */
-static void
-free_neighbour_without_terminating_sessions (struct NeighbourMapEntry *n)
-{
-  struct MessageQueue *mq;
-  n->is_active = NULL; /* always free'd by its own continuation! */
-
-  /* fail messages currently in the queue */
-  while (NULL != (mq = n->messages_head))
-  {
-    GNUNET_CONTAINER_DLL_remove (n->messages_head, n->messages_tail, mq);
-    if (NULL != mq->cont)
-      mq->cont (mq->cont_cls, GNUNET_SYSERR);
-    GNUNET_free (mq);
-  }
-  /* It is too late to send other peer disconnect notifications, but at
-     least internally we need to get clean... */
-  if (GNUNET_YES == test_connected (n))
-  {
-    GNUNET_STATISTICS_set (GST_stats,
-                           gettext_noop ("# peers connected"),
-                           --neighbours_connected,
-                           GNUNET_NO);
-    disconnect_notify_cb (callback_cls, &n->id);
-  }
-
-  n->state = S_DISCONNECT_FINISHED;
-
-  GNUNET_assert (GNUNET_YES ==
-                 GNUNET_CONTAINER_multihashmap_remove (neighbours,
-                                                       &n->id.hashPubKey, n));
-
-  /* cut transport-level connection */
-  free_address (&n->primary_address);
-  free_address (&n->alternative_address);
-
-  // FIXME-ATS-API: we might want to be more specific about
-  // which states we do this from in the future (ATS should
-  // have given us a 'suggest_address' handle, and if we have
-  // such a handle, we should cancel the operation here!
-  GNUNET_ATS_suggest_address_cancel (GST_ats, &n->id);
-
-  if (GNUNET_SCHEDULER_NO_TASK != n->task)
-  {
-    GNUNET_SCHEDULER_cancel (n->task);
-    n->task = GNUNET_SCHEDULER_NO_TASK;
-  }
-  /* free rest of memory */
-  GNUNET_free (n);
-}
-
 
 /**
  * Free a neighbour map entry.
  *
  * @param n entry to free
+ * @param keep_sessions GNUNET_NO to tell plugin to terminate sessions,
+ *                      GNUNET_YES to keep all sessions
  */
 static void
-free_neighbour (struct NeighbourMapEntry *n)
+free_neighbour (struct NeighbourMapEntry *n, int keep_sessions)
 {
   struct MessageQueue *mq;
   struct GNUNET_TRANSPORT_PluginFunctions *papi;
@@ -939,8 +886,9 @@ free_neighbour (struct NeighbourMapEntry *n)
      API gives us not even the means to selectively kill only one of
      them! Killing all sessions like this seems to be very, very
      wrong. */
-  if ( (NULL != n->primary_address.address) &&
-       (NULL != (papi = GST_plugins_find (n->primary_address.address->transport_name))) )
+  if ((GNUNET_NO == keep_sessions) &&
+      (NULL != n->primary_address.address) &&
+      (NULL != (papi = GST_plugins_find (n->primary_address.address->transport_name))))
     papi->disconnect (papi->cls, &n->id);
 
   n->state = S_DISCONNECT_FINISHED;
@@ -1038,7 +986,8 @@ send_disconnect_cont (void *cls, const struct GNUNET_PeerIdentity *target,
   if (S_DISCONNECT != n->state)
     return; /* have created a fresh entry since */
   n->state = S_DISCONNECT;
-  GNUNET_SCHEDULER_cancel (n->task);
+  if (GNUNET_SCHEDULER_NO_TASK != n->task)
+    GNUNET_SCHEDULER_cancel (n->task);
   n->task = GNUNET_SCHEDULER_add_now (&master_task, n);
 }
 
@@ -1102,7 +1051,7 @@ disconnect_neighbour (struct NeighbourMapEntry *n)
   case S_INIT_BLACKLIST:
     /* other peer is completely unaware of us, no need to send DISCONNECT */
     n->state = S_DISCONNECT_FINISHED;
-    free_neighbour (n);
+    free_neighbour (n, GNUNET_NO);
     return;
   case S_CONNECT_SENT:
     send_disconnect (n); 
@@ -1112,7 +1061,7 @@ disconnect_neighbour (struct NeighbourMapEntry *n)
   case S_CONNECT_RECV_BLACKLIST:
     /* we never ACK'ed the other peer's request, no need to send DISCONNECT */
     n->state = S_DISCONNECT_FINISHED;
-    free_neighbour (n);
+    free_neighbour (n, GNUNET_NO);
     return;
   case S_CONNECT_RECV_ACK:
     /* we DID ACK the other peer's request, must send DISCONNECT */
@@ -1178,19 +1127,15 @@ transmit_send_continuation (void *cls,
   struct MessageQueue *mq = cls;
   struct NeighbourMapEntry *n;
 
-  n = lookup_neighbour (receiver);
-  if (NULL == n)
-  {
-    GNUNET_break (0);
-    return;
-  }
-
+  if (NULL == (n = lookup_neighbour (receiver)))
+    return; /* disconnect or other error while transmitting, can happen */
   if (n->is_active == mq)
   {
     /* this is still "our" neighbour, remove us from its queue
        and allow it to send the next message now */
     n->is_active = NULL;
-    GNUNET_SCHEDULER_cancel (n->task);
+    if (GNUNET_SCHEDULER_NO_TASK != n->task)
+      GNUNET_SCHEDULER_cancel (n->task);
     n->task = GNUNET_SCHEDULER_add_now (&master_task, n);    
   }
   GNUNET_assert (bytes_in_send_queue >= mq->message_buf_size);
@@ -1544,7 +1489,8 @@ GST_neighbours_send (const struct GNUNET_PeerIdentity *target, const void *msg,
   if ( (NULL != n->is_active) ||
        ( (NULL == n->primary_address.session) && (NULL == n->primary_address.address)) )
     return;
-  GNUNET_SCHEDULER_cancel (n->task);
+  if (GNUNET_SCHEDULER_NO_TASK != n->task)
+    GNUNET_SCHEDULER_cancel (n->task);
   n->task = GNUNET_SCHEDULER_add_now (&master_task, n);
 }
 
@@ -1714,7 +1660,7 @@ GST_neighbours_try_connect (const struct GNUNET_PeerIdentity *target)
     case S_NOT_CONNECTED:
       /* this should not be possible */
       GNUNET_break (0);
-      free_neighbour (n);
+      free_neighbour (n, GNUNET_NO);
       break;
     case S_INIT_ATS:
     case S_INIT_BLACKLIST:
@@ -1738,7 +1684,7 @@ GST_neighbours_try_connect (const struct GNUNET_PeerIdentity *target)
       return; /* already connected */
     case S_DISCONNECT:
       /* get rid of remains, ready to re-try immediately */
-      free_neighbour (n);
+      free_neighbour (n, GNUNET_NO);
       break;
     case S_DISCONNECT_FINISHED:
       /* should not be possible */      
@@ -1746,7 +1692,7 @@ GST_neighbours_try_connect (const struct GNUNET_PeerIdentity *target)
     default:
       GNUNET_log (GNUNET_ERROR_TYPE_ERROR, "Unhandled state `%s' \n",print_state (n->state));
       GNUNET_break (0);
-      free_neighbour (n);
+      free_neighbour (n, GNUNET_NO);
       break;
     }
   }
@@ -1794,7 +1740,7 @@ handle_test_blacklist_cont (void *cls,
   case S_NOT_CONNECTED:
     /* this should not be possible */
     GNUNET_break (0);
-    free_neighbour (n);
+    free_neighbour (n, GNUNET_NO);
     break;
   case S_INIT_ATS:
     /* still waiting on ATS suggestion */
@@ -1962,7 +1908,7 @@ handle_test_blacklist_cont (void *cls,
   default:
     GNUNET_log (GNUNET_ERROR_TYPE_ERROR, "Unhandled state `%s' \n",print_state (n->state));
     GNUNET_break (0);
-    free_neighbour (n);
+    free_neighbour (n, GNUNET_NO);
     break;
   }
  cleanup:
@@ -2111,7 +2057,7 @@ GST_neighbours_handle_connect (const struct GNUNET_MessageHeader *message,
     break;
   case S_DISCONNECT:
     /* get rid of remains without terminating sessions, ready to re-try */
-    free_neighbour_without_terminating_sessions (n);
+    free_neighbour (n, GNUNET_YES);
     n = setup_neighbour (peer);
     n->state = S_CONNECT_RECV_ATS;
     GNUNET_ATS_reset_backoff (GST_ats, peer);
@@ -2124,7 +2070,7 @@ GST_neighbours_handle_connect (const struct GNUNET_MessageHeader *message,
   default:
     GNUNET_log (GNUNET_ERROR_TYPE_ERROR, "Unhandled state `%s' \n",print_state (n->state));
     GNUNET_break (0);
-    free_neighbour (n);
+    free_neighbour (n, GNUNET_NO);
     break;
   }
 }
@@ -2193,7 +2139,7 @@ GST_neighbours_switch_to_address (const struct GNUNET_PeerIdentity *peer,
   {
   case S_NOT_CONNECTED:
     GNUNET_break (0);
-    free_neighbour (n);
+    free_neighbour (n, GNUNET_NO);
     return;
   case S_INIT_ATS:
     set_address (&n->primary_address,
@@ -2256,7 +2202,7 @@ GST_neighbours_switch_to_address (const struct GNUNET_PeerIdentity *peer,
     /* ATS asks us to switch a life connection; see if we can get
        a CONNECT_ACK on it before we actually do this! */
     set_address (&n->alternative_address,
-                address, session, bandwidth_in, bandwidth_out, GNUNET_YES);
+                address, session, bandwidth_in, bandwidth_out, GNUNET_NO);
     n->state = S_CONNECTED_SWITCHING_BLACKLIST;
     check_blacklist (&n->id,
                     GNUNET_TIME_absolute_get (),
@@ -2302,7 +2248,7 @@ GST_neighbours_switch_to_address (const struct GNUNET_PeerIdentity *peer,
     }
     /* ATS asks us to switch a life connection, update blacklist check */
     set_address (&n->alternative_address,
-                address, session, bandwidth_in, bandwidth_out, GNUNET_YES);
+                address, session, bandwidth_in, bandwidth_out, GNUNET_NO);
     check_blacklist (&n->id,
                     GNUNET_TIME_absolute_get (),
                     address, session, ats, ats_count);
@@ -2317,7 +2263,7 @@ GST_neighbours_switch_to_address (const struct GNUNET_PeerIdentity *peer,
     }
     /* ATS asks us to switch a life connection, update blacklist check */
     set_address (&n->alternative_address,
-                address, session, bandwidth_in, bandwidth_out, GNUNET_YES);
+                address, session, bandwidth_in, bandwidth_out, GNUNET_NO);
     n->state = S_CONNECTED_SWITCHING_BLACKLIST;
     check_blacklist (&n->id,
                     GNUNET_TIME_absolute_get (),
@@ -2360,7 +2306,7 @@ master_task (void *cls,
     /* invalid state for master task, clean up */
     GNUNET_break (0);
     n->state = S_DISCONNECT_FINISHED;
-    free_neighbour (n);
+    free_neighbour (n, GNUNET_NO);
     return;
   case S_INIT_ATS:
     if (0 == delay.rel_value)
@@ -2369,7 +2315,7 @@ master_task (void *cls,
                  "Connection to `%s' timed out waiting for ATS to provide address\n",
                  GNUNET_i2s (&n->id));
       n->state = S_DISCONNECT_FINISHED;
-      free_neighbour (n);
+      free_neighbour (n, GNUNET_NO);
       return;
     }
     break;
@@ -2380,7 +2326,7 @@ master_task (void *cls,
                  "Connection to `%s' timed out waiting for BLACKLIST to approve address\n",
                  GNUNET_i2s (&n->id));
       n->state = S_DISCONNECT_FINISHED;
-      free_neighbour (n);
+      free_neighbour (n, GNUNET_NO);
       return;
     }
     break;
@@ -2401,7 +2347,7 @@ master_task (void *cls,
                  "Connection to `%s' timed out waiting ATS to provide address to use for CONNECT_ACK\n",
                  GNUNET_i2s (&n->id));
       n->state = S_DISCONNECT_FINISHED;
-      free_neighbour (n);
+      free_neighbour (n, GNUNET_NO);
       return;
     }
     break;
@@ -2412,7 +2358,7 @@ master_task (void *cls,
                  "Connection to `%s' timed out waiting BLACKLIST to approve address to use for CONNECT_ACK\n",
                  GNUNET_i2s (&n->id));
       n->state = S_DISCONNECT_FINISHED;
-      free_neighbour (n);
+      free_neighbour (n, GNUNET_NO);
       return;
     }
     break;
@@ -2497,7 +2443,7 @@ master_task (void *cls,
                "Cleaning up connection to `%s' after sending DISCONNECT\n",
                GNUNET_i2s (&n->id));
     n->state = S_DISCONNECT_FINISHED;
-    free_neighbour (n);
+    free_neighbour (n, GNUNET_NO);
     return;
   case S_DISCONNECT_FINISHED:
     /* how did we get here!? */
@@ -2510,10 +2456,10 @@ master_task (void *cls,
   }
   delay = GNUNET_TIME_relative_min (GNUNET_TIME_absolute_get_remaining (n->keep_alive_time),
                                    delay);
-  GNUNET_assert (GNUNET_SCHEDULER_NO_TASK == n->task);
-  n->task = GNUNET_SCHEDULER_add_delayed (delay,
-                                         &master_task,
-                                         n);
+  if (GNUNET_SCHEDULER_NO_TASK == n->task)
+    n->task = GNUNET_SCHEDULER_add_delayed (delay,
+                                           &master_task,
+                                           n);
 }
 
 
@@ -2584,7 +2530,7 @@ GST_neighbours_handle_connect_ack (const struct GNUNET_MessageHeader *message,
   {
   case S_NOT_CONNECTED:
     GNUNET_break (0);
-    free_neighbour (n);
+    free_neighbour (n, GNUNET_NO);
     return;
   case S_INIT_ATS:
   case S_INIT_BLACKLIST:
@@ -2645,7 +2591,7 @@ GST_neighbours_handle_connect_ack (const struct GNUNET_MessageHeader *message,
     /* new address worked; adopt it and go back to connected! */
     n->state = S_CONNECTED;
     n->timeout = GNUNET_TIME_relative_to_absolute (GNUNET_CONSTANTS_IDLE_CONNECTION_TIMEOUT);
-    GNUNET_assert (GNUNET_NO == n->alternative_address.ats_active);
+    GNUNET_break (GNUNET_NO == n->alternative_address.ats_active);
     set_address (&n->primary_address,
                 n->alternative_address.address,
                 n->alternative_address.session,
@@ -2724,11 +2670,11 @@ GST_neighbours_session_terminated (const struct GNUNET_PeerIdentity *peer,
   {
   case S_NOT_CONNECTED:
     GNUNET_break (0);
-    free_neighbour (n);
+    free_neighbour (n, GNUNET_NO);
     return;
   case S_INIT_ATS:
     GNUNET_break (0);
-    free_neighbour (n);
+    free_neighbour (n, GNUNET_NO);
     return;
   case S_INIT_BLACKLIST:
   case S_CONNECT_SENT:
@@ -2743,7 +2689,7 @@ GST_neighbours_session_terminated (const struct GNUNET_PeerIdentity *peer,
   case S_CONNECT_RECV_ACK:
     /* error on inbound session; free neighbour entirely */
     free_address (&n->primary_address);
-    free_neighbour (n);
+    free_neighbour (n, GNUNET_NO);
     return;
   case S_CONNECTED:
     free_address (&n->primary_address);
@@ -3153,7 +3099,7 @@ disconnect_all_neighbours (void *cls, const GNUNET_HashCode * key, void *value)
              "Disconnecting peer `%4s', %s\n",
               GNUNET_i2s (&n->id), "SHUTDOWN_TASK");
   n->state = S_DISCONNECT_FINISHED;
-  free_neighbour (n);
+  free_neighbour (n, GNUNET_NO);
   return GNUNET_OK;
 }