* @file topology/gnunet-daemon-topology.c
* @brief code for maintaining the mesh topology
* @author Christian Grothoff
- *
- * OPTIMIZATIONS:
- * - move code to use hash table instead of linked list
- * - instead of periodically discarding blacklisted entries,
- * simply add task that is triggered at the right time (earlier free,
- * more balanced load)
- * - check if new HELLO learned is different from old HELLO
- * before resetting entire state!
*/
#include <stdlib.h>
*/
struct GNUNET_CONTAINER_BloomFilter *filter;
+ /**
+ * Our request handle for *whitelisting* this peer (NULL if
+ * no whitelisting request is pending).
+ */
+ struct GNUNET_TRANSPORT_BlacklistRequest *wh;
+
/**
* Is this peer listed here because he is a friend?
*/
*/
int is_connected;
+ /**
+ * Are we currently blocking this peer (via blacklist)?
+ */
+ int is_blocked;
+
/**
* Until what time should we not try to connect again
* to this peer?
/**
* Force a disconnect from the specified peer.
- * FIXME: this policy change is never undone; how do we reconnect ever?
*/
static void
-force_disconnect (const struct GNUNET_PeerIdentity *peer)
+force_disconnect (struct PeerList *pl)
{
+ const struct GNUNET_PeerIdentity *peer = &pl->id;
struct DisconnectList *dl;
+ if (NULL != pl->wh)
+ {
+ GNUNET_TRANSPORT_blacklist_cancel (pl->wh);
+ pl->wh = NULL;
+ }
+ pl->is_blocked = GNUNET_YES;
dl = GNUNET_malloc (sizeof (struct DisconnectList));
dl->peer = *peer;
GNUNET_CONTAINER_DLL_insert (disconnect_head,
}
+
+/**
+ * Function called once our request to 'whitelist' a peer
+ * has completed.
+ *
+ * @param cls our 'struct PeerList'
+ * @param tc unused
+ */
+static void
+whitelist_done (void *cls,
+ const struct GNUNET_SCHEDULER_TaskContext *tc)
+{
+ struct PeerList *pl = cls;
+
+ pl->wh = NULL;
+}
+
+
+/**
+ * Whitelist all peers that we blacklisted; we've passed
+ * the minimum number of friends.
+ */
+static void
+whitelist_peers ()
+{
+ struct PeerList *pl;
+ struct DisconnectList *dl;
+
+ /* first, cancel all blacklisting requests */
+ while (NULL != (dl = disconnect_head))
+ {
+ GNUNET_CONTAINER_DLL_remove (disconnect_head,
+ disconnect_tail,
+ dl);
+ GNUNET_TRANSPORT_blacklist_cancel (dl->rh);
+ GNUNET_free (dl);
+ }
+ /* then, specifically whitelist all peers that we
+ know to have blacklisted */
+ pl = peers;
+ while (pl != NULL)
+ {
+ if (pl->is_blocked)
+ {
+ pl->wh = GNUNET_TRANSPORT_blacklist (sched, cfg,
+ &pl->id,
+ GNUNET_TIME_UNIT_ZERO,
+ GNUNET_TIME_UNIT_FOREVER_REL,
+ &whitelist_done,
+ pl);
+ pl->is_blocked = GNUNET_NO;
+ }
+ pl = pl->next;
+ }
+}
+
+
/**
* Function called by core when our attempt to connect succeeded.
*/
prev->next = pos->next;
if (pos->hello_req != NULL)
GNUNET_CORE_notify_transmit_ready_cancel (pos->hello_req);
+ if (pos->wh != NULL)
+ GNUNET_TRANSPORT_blacklist_cancel (pos->wh);
if (pos->connect_req != NULL)
GNUNET_CORE_peer_request_connect_cancel (pos->connect_req);
if (pos->hello_delay_task != GNUNET_SCHEDULER_NO_TASK)
GNUNET_SCHEDULER_cancel (sched,
pos->hello_delay_task);
+ GNUNET_free_non_null (pos->hello);
+ if (pos->filter != NULL)
+ GNUNET_CONTAINER_bloomfilter_free (peer->filter);
GNUNET_free (pos);
}
"Connection to `%s' is forbidden, forcing disconnect!\n",
GNUNET_i2s (peer));
#endif
- force_disconnect (&pos->id);
+ force_disconnect (pos);
return;
}
}
}
pos->is_connected = GNUNET_YES;
if (pos->is_friend)
- friend_count++;
+ {
+ if ( (friend_count == minimum_friend_count - 1) &&
+ (GNUNET_YES != friends_only) )
+ whitelist_peers ();
+ friend_count++;
+ }
reschedule_hellos (pos);
}
"Connection to `%s' is not from a friend, forcing disconnect!\n",
GNUNET_i2s (&pos->id));
#endif
- force_disconnect (&pos->id);
+ force_disconnect (pos);
}
pos = pos->next;
}
if (peer == NULL)
peer = make_peer (&pid, hello, GNUNET_NO);
// FIXME: check if 'hello' is any different from peer->hello?
- GNUNET_free_non_null (peer->hello);
#if DEBUG_TOPOLOGY
GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
"Found `%s' from peer `%s' for advertising\n",
GNUNET_i2s (&pid));
#endif
size = GNUNET_HELLO_size (hello);
+ GNUNET_free_non_null (peer->hello);
peer->hello = GNUNET_malloc (size);
memcpy (peer->hello, hello, size);
if (peer->filter != NULL)
next = pos->next;
if ( (GNUNET_NO == pos->is_friend) &&
(GNUNET_NO == pos->is_connected) &&
+ (GNUNET_NO == pos->is_blocked) &&
(0 == GNUNET_TIME_absolute_get_remaining (pos->blacklisted_until).value) )
free_peer (pos);
}