/*
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
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;
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.
/**
* Current task performing the check.
*/
- GNUNET_SCHEDULER_TaskIdentifier task;
+ struct GNUNET_SCHEDULER_Task *task;
};
/**
* 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);
/**
* @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);
* @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)
{
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, "")))
/* 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
{
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);
}
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);
}
* @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,
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));
}
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;
}
/**
* 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);
}
*
* @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
{
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
* @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;
* @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;
* @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 =
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;
{
/* 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");
- bc->bl_pos = bc->bl_pos->next;
- bc->task = GNUNET_SCHEDULER_add_now (&do_blacklist_check, bc);
+ GNUNET_SERVER_receive_done (bl->client,
+ GNUNET_OK);
+ bl->call_receive_done = GNUNET_NO;
+ 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;
}
}
GST_blacklist_add_peer (const struct GNUNET_PeerIdentity *peer,
const char *transport_name)
{
- char * transport = NULL;
+ char *transport = NULL;
if (NULL != transport_name)
{
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);
}
+/**
+ * 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.
/* 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;
}
* @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,
/* 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;
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)
{
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);
}