trying to fix #4003
[oweals/gnunet.git] / src / transport / gnunet-service-transport_blacklist.c
index dc59ce5959bef0f91617f2e604dcf1bf2dbc3724..987957911796143890d3bba4a1115a7dd1ba9faa 100644 (file)
@@ -1,6 +1,6 @@
 /*
      This file is part of GNUnet.
-     (C) 2010,2011 Christian Grothoff (and other contributing authors)
+     Copyright (C) 2010,2011 Christian Grothoff (and other contributing authors)
 
      GNUnet is free software; you can redistribute it and/or modify
      it under the terms of the GNU General Public License as published
 
      You should have received a copy of the GNU General Public License
      along with GNUnet; see the file COPYING.  If not, write to the
-     Free Software Foundation, Inc., 59 Temple Place - Suite 330,
-     Boston, MA 02111-1307, USA.
+     Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
+     Boston, MA 02110-1301, USA.
 */
 
 /**
  * @file transport/gnunet-service-transport_blacklist.c
  * @brief blacklisting implementation
- * @author Christian Grothoff, Matthias Wachs
+ * @author Christian Grothoff
+ * @author Matthias Wachs
  * @details This is the blacklisting component of transport service. With
  * blacklisting it is possible to deny connections to specific peers of
  * to use a specific plugin to a specific peer. Peers can be blacklisted using
@@ -100,12 +101,12 @@ struct Blacklisters
   struct GST_BlacklistCheck *bc;
 
   /**
-   * Set to GNUNET_YES if we're currently waiting for a reply.
+   * Set to #GNUNET_YES if we're currently waiting for a reply.
    */
   int waiting_for_reply;
 
   /**
-   * GNUNET_YES if we have to call receive_done for this client
+   * #GNUNET_YES if we have to call receive_done for this client
    */
   int call_receive_done;
 
@@ -140,10 +141,20 @@ struct GST_BlacklistCheck
   GST_BlacklistTestContinuation cont;
 
   /**
-   * Closure for cont.
+   * Closure for @e cont.
    */
   void *cont_cls;
 
+  /**
+   * Address for #GST_blacklist_abort_matching(), can be NULL.
+   */
+  struct GNUNET_HELLO_Address *address;
+
+  /**
+   * Session for #GST_blacklist_abort_matching(), can be NULL.
+   */
+  struct Session *session;
+
   /**
    * Current transmission request handle for this client, or NULL if no
    * request is pending.
@@ -158,7 +169,7 @@ struct GST_BlacklistCheck
   /**
    * Current task performing the check.
    */
-  GNUNET_SCHEDULER_TaskIdentifier task;
+  struct GNUNET_SCHEDULER_Task *task;
 
 };
 
@@ -193,11 +204,12 @@ static struct GNUNET_CONTAINER_MultiPeerMap *blacklist;
 /**
  * Perform next action in the blacklist check.
  *
- * @param cls the 'struct BlacklistCheck*'
+ * @param cls the `struct BlacklistCheck*`
  * @param tc unused
  */
 static void
-do_blacklist_check (void *cls, const struct GNUNET_SCHEDULER_TaskContext *tc);
+do_blacklist_check (void *cls, 
+                   const struct GNUNET_SCHEDULER_TaskContext *tc);
 
 
 /**
@@ -208,28 +220,29 @@ do_blacklist_check (void *cls, const struct GNUNET_SCHEDULER_TaskContext *tc);
  * @param client identification of the client
  */
 static void
-client_disconnect_notification (void *cls, struct GNUNET_SERVER_Client *client)
+client_disconnect_notification (void *cls,
+                               struct GNUNET_SERVER_Client *client)
 {
   struct Blacklisters *bl;
   struct GST_BlacklistCheck *bc;
 
-  if (client == NULL)
+  if (NULL == client)
     return;
   for (bl = bl_head; bl != NULL; bl = bl->next)
   {
     if (bl->client != client)
       continue;
-    for (bc = bc_head; bc != NULL; bc = bc->next)
+    for (bc = bc_head; NULL != bc; bc = bc->next)
     {
       if (bc->bl_pos != bl)
         continue;
       bc->bl_pos = bl->next;
-      if (bc->th != NULL)
+      if (NULL != bc->th)
       {
         GNUNET_SERVER_notify_transmit_ready_cancel (bc->th);
         bc->th = NULL;
       }
-      if (bc->task == GNUNET_SCHEDULER_NO_TASK)
+      if (NULL == bc->task)
         bc->task = GNUNET_SCHEDULER_add_now (&do_blacklist_check, bc);
     }
     GNUNET_CONTAINER_DLL_remove (bl_head, bl_tail, bl);
@@ -249,7 +262,8 @@ client_disconnect_notification (void *cls, struct GNUNET_SERVER_Client *client)
  * @param value value of the option
  */
 static void
-blacklist_cfg_iter (void *cls, const char *section,
+blacklist_cfg_iter (void *cls,
+                    const char *section,
                    const char *option,
                    const char *value)
 {
@@ -258,9 +272,10 @@ blacklist_cfg_iter (void *cls, const char *section,
   char *plugs;
   char *pos;
 
-  if (GNUNET_OK != GNUNET_CRYPTO_eddsa_public_key_from_string (option,
-                                                                 strlen (option),
-                                                                 &peer.public_key))
+  if (GNUNET_OK !=
+      GNUNET_CRYPTO_eddsa_public_key_from_string (option,
+                                                  strlen (option),
+                                                  &peer.public_key))
     return;
 
   if ((NULL == value) || (0 == strcmp(value, "")))
@@ -268,7 +283,8 @@ blacklist_cfg_iter (void *cls, const char *section,
     /* Blacklist whole peer */
     GST_blacklist_add_peer (&peer, NULL);
     GNUNET_log (GNUNET_ERROR_TYPE_INFO,
-               _("Adding blacklisting entry for peer `%s'\n"), GNUNET_i2s (&peer));
+               _("Adding blacklisting entry for peer `%s'\n"),
+                GNUNET_i2s (&peer));
   }
   else
   {
@@ -303,9 +319,13 @@ read_blacklist_configuration (const struct GNUNET_CONFIGURATION_Handle *cfg,
                   sizeof (cfg_sect),
                   "transport-blacklist-%s",
                   GNUNET_i2s_full (my_id));
-  GNUNET_CONFIGURATION_iterate_section_values (cfg, cfg_sect, &blacklist_cfg_iter, &res);
+  GNUNET_CONFIGURATION_iterate_section_values (cfg,
+                                               cfg_sect,
+                                               &blacklist_cfg_iter,
+                                               &res);
   GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
-              "Loaded %u blacklisting entries from configuration\n", res);
+              "Loaded %u blacklisting entries from configuration\n",
+              res);
 }
 
 
@@ -324,7 +344,8 @@ GST_blacklist_start (struct GNUNET_SERVER_Handle *server,
   GNUNET_assert (NULL != cfg);
   GNUNET_assert (NULL != my_id);
   read_blacklist_configuration (cfg, my_id);
-  GNUNET_SERVER_disconnect_notify (server, &client_disconnect_notification,
+  GNUNET_SERVER_disconnect_notify (server,
+                                   &client_disconnect_notification,
                                    NULL);
 }
 
@@ -335,7 +356,7 @@ GST_blacklist_start (struct GNUNET_SERVER_Handle *server,
  * @param cls unused
  * @param key host identity (unused)
  * @param value the blacklist entry
- * @return GNUNET_OK (continue to iterate)
+ * @return #GNUNET_OK (continue to iterate)
  */
 static int
 free_blacklist_entry (void *cls,
@@ -355,36 +376,39 @@ free_blacklist_entry (void *cls,
 void
 GST_blacklist_stop ()
 {
-  if (NULL != blacklist)
-  {
-    GNUNET_CONTAINER_multipeermap_iterate (blacklist, &free_blacklist_entry,
-                                           NULL);
-    GNUNET_CONTAINER_multipeermap_destroy (blacklist);
-    blacklist = NULL;
-  }
+  if (NULL == blacklist)
+    return;
+  GNUNET_CONTAINER_multipeermap_iterate (blacklist,
+                                         &free_blacklist_entry,
+                                         NULL);
+  GNUNET_CONTAINER_multipeermap_destroy (blacklist);
+  blacklist = NULL;
 }
 
 
 /**
  * Transmit blacklist query to the client.
  *
- * @param cls the 'struct GST_BlacklistCheck'
+ * @param cls the `struct GST_BlacklistCheck`
  * @param size number of bytes allowed
  * @param buf where to copy the message
- * @return number of bytes copied to buf
+ * @return number of bytes copied to @a buf
  */
 static size_t
-transmit_blacklist_message (void *cls, size_t size, void *buf)
+transmit_blacklist_message (void *cls, 
+                           size_t size,
+                           void *buf)
 {
   struct GST_BlacklistCheck *bc = cls;
   struct Blacklisters *bl;
   struct BlacklistMessage bm;
 
   bc->th = NULL;
-  if (size == 0)
+  if (0 == size)
   {
-    GNUNET_assert (bc->task == GNUNET_SCHEDULER_NO_TASK);
-    bc->task = GNUNET_SCHEDULER_add_now (&do_blacklist_check, bc);
+    GNUNET_assert (NULL == bc->task);
+    bc->task = GNUNET_SCHEDULER_add_now (&do_blacklist_check,
+                                        bc);
     GNUNET_log (GNUNET_ERROR_TYPE_WARNING,
                 "Failed to send blacklist test for peer `%s' to client\n",
                 GNUNET_i2s (&bc->peer));
@@ -392,16 +416,20 @@ transmit_blacklist_message (void *cls, size_t size, void *buf)
   }
   GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
               "Sending blacklist test for peer `%s' to client %p\n",
-              GNUNET_i2s (&bc->peer), bc->bl_pos->client);
+              GNUNET_i2s (&bc->peer), 
+             bc->bl_pos->client);
   bl = bc->bl_pos;
   bm.header.size = htons (sizeof (struct BlacklistMessage));
   bm.header.type = htons (GNUNET_MESSAGE_TYPE_TRANSPORT_BLACKLIST_QUERY);
   bm.is_allowed = htonl (0);
   bm.peer = bc->peer;
-  memcpy (buf, &bm, sizeof (bm));
+  memcpy (buf,
+         &bm, 
+         sizeof (bm));
   if (GNUNET_YES == bl->call_receive_done)
   {
-    GNUNET_SERVER_receive_done (bl->client, GNUNET_OK);
+    GNUNET_SERVER_receive_done (bl->client,
+                               GNUNET_OK);
     bl->call_receive_done = GNUNET_NO;
   }
 
@@ -413,36 +441,42 @@ transmit_blacklist_message (void *cls, size_t size, void *buf)
 /**
  * Perform next action in the blacklist check.
  *
- * @param cls the 'struct GST_BlacklistCheck*'
+ * @param cls the `struct GST_BlacklistCheck *`
  * @param tc unused
  */
 static void
-do_blacklist_check (void *cls, const struct GNUNET_SCHEDULER_TaskContext *tc)
+do_blacklist_check (void *cls,
+                    const struct GNUNET_SCHEDULER_TaskContext *tc)
 {
   struct GST_BlacklistCheck *bc = cls;
   struct Blacklisters *bl;
 
-  bc->task = GNUNET_SCHEDULER_NO_TASK;
+  bc->task = NULL;
   bl = bc->bl_pos;
-  if (bl == NULL)
+  if (NULL == bl)
   {
     GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
                 "No other blacklist clients active, will allow neighbour `%s'\n",
                 GNUNET_i2s (&bc->peer));
 
-    bc->cont (bc->cont_cls, &bc->peer, GNUNET_OK);
-    GNUNET_CONTAINER_DLL_remove(bc_head, bc_tail, bc);
-    GNUNET_free (bc);
+    bc->cont (bc->cont_cls, 
+             &bc->peer,
+             bc->address,
+             bc->session,
+             GNUNET_OK);
+    GST_blacklist_test_cancel (bc);
     return;
   }
-  if ((bl->bc != NULL) || (bl->waiting_for_reply != GNUNET_NO))
+  if ( (NULL != bl->bc) ||
+       (GNUNET_NO != bl->waiting_for_reply) )
     return;                     /* someone else busy with this client */
   bl->bc = bc;
   bc->th =
       GNUNET_SERVER_notify_transmit_ready (bl->client,
                                            sizeof (struct BlacklistMessage),
                                            GNUNET_TIME_UNIT_FOREVER_REL,
-                                           &transmit_blacklist_message, bc);
+                                           &transmit_blacklist_message, 
+                                          bc);
 }
 
 
@@ -452,24 +486,30 @@ do_blacklist_check (void *cls, const struct GNUNET_SCHEDULER_TaskContext *tc)
  *
  * @param cls unused
  * @param peer the neighbour that was investigated
- * @param allowed GNUNET_OK if we can keep it,
- *                GNUNET_NO if we must shutdown the connection
+ * @param address address associated with the request
+ * @param session session associated with the request
+ * @param allowed #GNUNET_OK if we can keep it,
+ *                #GNUNET_NO if we must shutdown the connection
  */
 static void
-confirm_or_drop_neighbour (void *cls, const struct GNUNET_PeerIdentity *peer,
+confirm_or_drop_neighbour (void *cls,
+                           const struct GNUNET_PeerIdentity *peer,
+                          const struct GNUNET_HELLO_Address *address,
+                          struct Session *session,
                            int allowed)
 {
   if (GNUNET_OK == allowed)
     return;                     /* we're done */
   GNUNET_STATISTICS_update (GST_stats,
-                            gettext_noop ("# disconnects due to blacklist"), 1,
+                            gettext_noop ("# disconnects due to blacklist"), 
+                           1,
                             GNUNET_NO);
   GST_neighbours_force_disconnect (peer);
 }
 
 
 /**
- * Closure for 'test_connection_ok'.
+ * Closure for #test_connection_ok().
  */
 struct TestConnectionContext
 {
@@ -484,12 +524,13 @@ struct TestConnectionContext
   struct Blacklisters *bl;
 };
 
+
 /**
  * Test if an existing connection is still acceptable given a new
  * blacklisting client.
  *
- * @param cls the 'struct TestConnectionContest'
- * @param peer neighbour's identity
+ * @param cls the `struct TestConnectionContext *`
+ * @param peer identity of the peer
  * @param address the address
  * @param state current state this peer is in
  * @param state_timeout timeout for the current state of the peer
@@ -497,19 +538,23 @@ struct TestConnectionContext
  * @param bandwidth_out bandwidth assigned outbound
  */
 static void
-test_connection_ok (void *cls, const struct GNUNET_PeerIdentity *peer,
-    const struct GNUNET_HELLO_Address *address,
-    enum GNUNET_TRANSPORT_PeerState state,
-    struct GNUNET_TIME_Absolute state_timeout,
-    struct GNUNET_BANDWIDTH_Value32NBO bandwidth_in,
-    struct GNUNET_BANDWIDTH_Value32NBO bandwidth_out)
+test_connection_ok (void *cls,
+                    const struct GNUNET_PeerIdentity *peer,
+                   const struct GNUNET_HELLO_Address *address,
+                   enum GNUNET_TRANSPORT_PeerState state,
+                   struct GNUNET_TIME_Absolute state_timeout,
+                   struct GNUNET_BANDWIDTH_Value32NBO bandwidth_in,
+                   struct GNUNET_BANDWIDTH_Value32NBO bandwidth_out)
 {
   struct TestConnectionContext *tcc = cls;
   struct GST_BlacklistCheck *bc;
 
   bc = GNUNET_new (struct GST_BlacklistCheck);
-  GNUNET_CONTAINER_DLL_insert(bc_head, bc_tail, bc);
+  GNUNET_CONTAINER_DLL_insert (bc_head,
+                              bc_tail,
+                              bc);
   bc->peer = *peer;
+  bc->address = GNUNET_HELLO_address_copy (address);
   bc->cont = &confirm_or_drop_neighbour;
   bc->cont_cls = NULL;
   bc->bl_pos = tcc->bl;
@@ -533,32 +578,33 @@ test_connection_ok (void *cls, const struct GNUNET_PeerIdentity *peer,
  * @param message the blacklist-init message that was sent
  */
 void
-GST_blacklist_handle_init (void *cls, struct GNUNET_SERVER_Client *client,
+GST_blacklist_handle_init (void *cls,
+                          struct GNUNET_SERVER_Client *client,
                            const struct GNUNET_MessageHeader *message)
 {
   struct Blacklisters *bl;
   struct TestConnectionContext tcc;
 
-  bl = bl_head;
-  while (bl != NULL)
-  {
+  for (bl = bl_head; NULL != bl; bl = bl->next)
     if (bl->client == client)
     {
       GNUNET_break (0);
       GNUNET_SERVER_receive_done (client, GNUNET_SYSERR);
       return;
     }
-    bl = bl->next;
-  }
 
   GNUNET_SERVER_client_mark_monitor (client);
   bl = GNUNET_new (struct Blacklisters);
   bl->client = client;
   bl->call_receive_done = GNUNET_YES;
   GNUNET_SERVER_client_keep (client);
-  GNUNET_CONTAINER_DLL_insert_after (bl_head, bl_tail, bl_tail, bl);
-
-  GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "New blacklist client %p\n", client);
+  GNUNET_CONTAINER_DLL_insert_after (bl_head,
+                                     bl_tail,
+                                     bl_tail,
+                                     bl);
+  GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
+              "New blacklist client %p\n",
+              client);
 
   /* confirm that all existing connections are OK! */
   tcc.bl = bl;
@@ -575,7 +621,8 @@ GST_blacklist_handle_init (void *cls, struct GNUNET_SERVER_Client *client,
  * @param message the blacklist-init message that was sent
  */
 void
-GST_blacklist_handle_reply (void *cls, struct GNUNET_SERVER_Client *client,
+GST_blacklist_handle_reply (void *cls,
+                           struct GNUNET_SERVER_Client *client,
                             const struct GNUNET_MessageHeader *message)
 {
   const struct BlacklistMessage *msg =
@@ -586,15 +633,19 @@ GST_blacklist_handle_reply (void *cls, struct GNUNET_SERVER_Client *client,
   bl = bl_head;
   while ((bl != NULL) && (bl->client != client))
     bl = bl->next;
-  if (bl == NULL)
+  if (NULL == bl)
   {
-    GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "Blacklist client disconnected\n");
-    GNUNET_SERVER_receive_done (client, GNUNET_SYSERR);
+    GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
+                "Blacklist client disconnected\n");
+    GNUNET_SERVER_receive_done (client,
+                               GNUNET_SYSERR);
     return;
   }
 
-  GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "Blacklist client %p sent reply for `%s'\n",
-      client, GNUNET_i2s(&msg->peer));
+  GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
+              "Blacklist client %p sent reply for `%s'\n",
+              client,
+              GNUNET_i2s (&msg->peer));
 
   bc = bl->bc;
   bl->bc = NULL;
@@ -604,32 +655,48 @@ GST_blacklist_handle_reply (void *cls, struct GNUNET_SERVER_Client *client,
   {
     /* only run this if the blacklist check has not been
      * cancelled in the meantime... */
+    GNUNET_assert (bc->bl_pos == bl);
     if (ntohl (msg->is_allowed) == GNUNET_SYSERR)
     {
       GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
                   "Blacklist check failed, peer not allowed\n");
-      bc->cont (bc->cont_cls, &bc->peer, GNUNET_NO);
-      GNUNET_CONTAINER_DLL_remove (bc_head, bc_tail, bc);
+      /* For the duration of the continuation, make the ongoing
+        check invisible (to avoid double-cancellation); then
+        add it back again so we can re-use GST_blacklist_test_cancel() */
+      GNUNET_CONTAINER_DLL_remove (bc_head,
+                                  bc_tail,
+                                  bc);
+      bc->cont (bc->cont_cls, 
+               &bc->peer,
+               bc->address,
+               bc->session,
+               GNUNET_NO);
+      GNUNET_CONTAINER_DLL_insert (bc_head,
+                                  bc_tail,
+                                  bc);
+      GST_blacklist_test_cancel (bc);
       GNUNET_SERVER_receive_done (bl->client, GNUNET_OK);
       bl->call_receive_done = GNUNET_NO;
-      GNUNET_free (bc);
       return;
     }
     else
     {
       GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
                   "Blacklist check succeeded, continuing with checks\n");
-      GNUNET_SERVER_receive_done (bl->client, GNUNET_OK);
+      GNUNET_SERVER_receive_done (bl->client,
+                                 GNUNET_OK);
       bl->call_receive_done = GNUNET_NO;
-      bc->bl_pos = bc->bl_pos->next;
-      bc->task = GNUNET_SCHEDULER_add_now (&do_blacklist_check, bc);
+      bc->bl_pos = bl->next;
+      bc->task = GNUNET_SCHEDULER_add_now (&do_blacklist_check, 
+                                          bc);
     }
   }
   /* check if any other blacklist checks are waiting for this blacklister */
   for (bc = bc_head; bc != NULL; bc = bc->next)
-    if ((bc->bl_pos == bl) && (GNUNET_SCHEDULER_NO_TASK == bc->task))
+    if ((bc->bl_pos == bl) && (NULL == bc->task))
     {
-      bc->task = GNUNET_SCHEDULER_add_now (&do_blacklist_check, bc);
+      bc->task = GNUNET_SCHEDULER_add_now (&do_blacklist_check, 
+                                          bc);
       break;
     }
 }
@@ -645,7 +712,7 @@ void
 GST_blacklist_add_peer (const struct GNUNET_PeerIdentity *peer,
                         const char *transport_name)
 {
-  char * transport = NULL;
+  char *transport = NULL;
 
   if (NULL != transport_name)
   {
@@ -658,7 +725,7 @@ GST_blacklist_add_peer (const struct GNUNET_PeerIdentity *peer,
     GNUNET_log (GNUNET_ERROR_TYPE_INFO,
                "Adding peer `%s' with all plugins to blacklist\n",
                GNUNET_i2s (peer));
-  if (blacklist == NULL)
+  if (NULL == blacklist)
     blacklist =
       GNUNET_CONTAINER_multipeermap_create (TRANSPORT_BLACKLIST_HT_SIZE,
                                            GNUNET_NO);
@@ -669,6 +736,38 @@ GST_blacklist_add_peer (const struct GNUNET_PeerIdentity *peer,
 }
 
 
+/**
+ * Abort blacklist if @a address and @a session match.
+ *
+ * @param address address used to abort matching checks
+ * @param session session used to abort matching checks
+ */
+void
+GST_blacklist_abort_matching (const struct GNUNET_HELLO_Address *address,
+                             struct Session *session)
+{
+  struct GST_BlacklistCheck *bc;
+  struct GST_BlacklistCheck *n;
+
+  n = bc_head; 
+  while (NULL != (bc = n))
+  {
+    n = bc->next;
+    if ( (bc->session == session) &&
+        (0 == GNUNET_HELLO_address_cmp (bc->address,
+                                        address)) )
+    {
+      bc->cont (bc->cont_cls,
+               &bc->peer,
+               bc->address,
+               bc->session,
+               GNUNET_SYSERR);
+      GST_blacklist_test_cancel (bc);
+    }
+  }
+}
+
+
 /**
  * Test if the given blacklist entry matches.  If so,
  * abort the iteration.
@@ -707,8 +806,9 @@ test_blacklisted (void *cls,
   /* blacklist check for specific transport */
   if ((NULL != transport_name) && (NULL != value))
   {
-       if (0 == strcmp (transport_name, be))
-                       return GNUNET_NO;           /* plugin is blacklisted! */
+    if (0 == strcmp (transport_name,
+                    be))
+      return GNUNET_NO;           /* plugin is blacklisted! */
   }
   return GNUNET_OK;
 }
@@ -720,24 +820,31 @@ test_blacklisted (void *cls,
  * @param peer the identity of the peer to test
  * @param transport_name name of the transport to test, never NULL
  * @param cont function to call with result
- * @param cont_cls closure for 'cont'
+ * @param cont_cls closure for @a cont
+ * @param address address to pass back to @a cont, can be NULL
+ * @param session session to pass back to @a cont, can be NULL
  * @return handle to the blacklist check, NULL if the decision
- *        was made instantly and 'cont' was already called
+ *        was made instantly and @a cont was already called
  */
 struct GST_BlacklistCheck *
 GST_blacklist_test_allowed (const struct GNUNET_PeerIdentity *peer,
                             const char *transport_name,
-                            GST_BlacklistTestContinuation cont, void *cont_cls)
+                            GST_BlacklistTestContinuation cont,
+                            void *cont_cls,
+                           const struct GNUNET_HELLO_Address *address,
+                           struct Session *session)
 {
   struct GST_BlacklistCheck *bc;
 
-  GNUNET_assert (peer != NULL);
-  GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "Blacklist check for peer `%s':%s\n",
-               GNUNET_i2s (peer), (NULL != transport_name) ? transport_name : "unspecified");
+  GNUNET_assert (NULL != peer);
+  GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
+              "Blacklist check for peer `%s':%s\n",
+              GNUNET_i2s (peer),
+              (NULL != transport_name) ? transport_name : "unspecified");
 
   /* Check local blacklist by iterating over hashmap
    * If iteration is aborted, we found a matching blacklist entry */
-  if ((blacklist != NULL) &&
+  if ((NULL != blacklist) &&
       (GNUNET_SYSERR ==
        GNUNET_CONTAINER_multipeermap_get_multiple (blacklist, peer,
                                                    &test_blacklisted,
@@ -746,28 +853,45 @@ GST_blacklist_test_allowed (const struct GNUNET_PeerIdentity *peer,
     /* Disallowed by config, disapprove instantly */
     GNUNET_STATISTICS_update (GST_stats,
                               gettext_noop ("# disconnects due to blacklist"),
-                              1, GNUNET_NO);
-    GNUNET_log (GNUNET_ERROR_TYPE_INFO, "Disallowing connection to peer `%s' on transport %s\n",
-               GNUNET_i2s (peer), (NULL != transport_name) ? transport_name : "unspecified");
-    if (cont != NULL)
-      cont (cont_cls, peer, GNUNET_NO);
+                              1, 
+                             GNUNET_NO);
+    GNUNET_log (GNUNET_ERROR_TYPE_INFO,
+                _("Disallowing connection to peer `%s' on transport %s\n"),
+               GNUNET_i2s (peer),
+                (NULL != transport_name) ? transport_name : "unspecified");
+    if (NULL != cont)
+      cont (cont_cls,      
+           peer, 
+           address,
+           session,
+           GNUNET_NO);
     return NULL;
   }
 
-  if (bl_head == NULL)
+  if (NULL == bl_head)
   {
     /* no blacklist clients, approve instantly */
-    if (cont != NULL)
-      cont (cont_cls, peer, GNUNET_OK);
-    GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "Allowing connection to peer `%s' %s\n",
-               GNUNET_i2s (peer), (NULL != transport_name) ? transport_name : "");
+    if (NULL != cont)
+      cont (cont_cls,
+           peer,
+           address,
+           session,
+           GNUNET_OK);
+    GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
+                "Allowing connection to peer `%s' %s\n",
+               GNUNET_i2s (peer),
+                (NULL != transport_name) ? transport_name : "");
     return NULL;
   }
 
   /* need to query blacklist clients */
   bc = GNUNET_new (struct GST_BlacklistCheck);
-  GNUNET_CONTAINER_DLL_insert (bc_head, bc_tail, bc);
+  GNUNET_CONTAINER_DLL_insert (bc_head, 
+                              bc_tail,
+                              bc);
   bc->peer = *peer;
+  bc->address = GNUNET_HELLO_address_copy (address);
+  bc->session = session;
   bc->cont = cont;
   bc->cont_cls = cont_cls;
   bc->bl_pos = bl_head;
@@ -784,8 +908,10 @@ GST_blacklist_test_allowed (const struct GNUNET_PeerIdentity *peer,
 void
 GST_blacklist_test_cancel (struct GST_BlacklistCheck *bc)
 {
-  GNUNET_CONTAINER_DLL_remove (bc_head, bc_tail, bc);
-  if (bc->bl_pos != NULL)
+  GNUNET_CONTAINER_DLL_remove (bc_head,
+                               bc_tail,
+                               bc);
+  if (NULL != bc->bl_pos)
   {
     if (bc->bl_pos->bc == bc)
     {
@@ -793,16 +919,17 @@ GST_blacklist_test_cancel (struct GST_BlacklistCheck *bc)
       bc->bl_pos->bc = NULL;
     }
   }
-  if (GNUNET_SCHEDULER_NO_TASK != bc->task)
+  if (NULL != bc->task)
   {
     GNUNET_SCHEDULER_cancel (bc->task);
-    bc->task = GNUNET_SCHEDULER_NO_TASK;
+    bc->task = NULL;
   }
   if (NULL != bc->th)
   {
     GNUNET_SERVER_notify_transmit_ready_cancel (bc->th);
     bc->th = NULL;
   }
+  GNUNET_free_non_null (bc->address);
   GNUNET_free (bc);
 }