From 541caf3dec54aaee621fed935e667f9ee423ef31 Mon Sep 17 00:00:00 2001 From: Christian Grothoff Date: Sun, 18 Apr 2010 20:23:40 +0000 Subject: towards fixing blacklisting APIs and implementation --- TODO | 16 +- src/core/core.h | 13 +- src/core/core_api.c | 28 -- src/core/gnunet-service-core.c | 14 - src/core/test_core_api.c | 6 +- src/core/test_core_api_start_only.c | 6 +- src/fs/gnunet-service-fs.c | 1 - src/hostlist/gnunet-daemon-hostlist.c | 2 +- src/include/gnunet_core_service.h | 4 +- src/include/gnunet_protocols.h | 15 +- src/include/gnunet_transport_service.h | 97 ++---- src/testing/test_testing_topology.c | 3 +- src/testing/testing.c | 4 +- src/topology/gnunet-daemon-topology.c | 278 +++------------ src/transport/Makefile.am | 3 +- src/transport/gnunet-service-transport_blacklist.c | 142 +++++--- src/transport/gnunet-service-transport_blacklist.h | 35 +- src/transport/transport.h | 17 +- src/transport/transport_api_blacklist.c | 385 ++++++++------------- 19 files changed, 347 insertions(+), 722 deletions(-) diff --git a/TODO b/TODO index 2054d5df1..d4bed6bc1 100644 --- a/TODO +++ b/TODO @@ -2,20 +2,10 @@ * PEERINFO: [CG] - trust: need *fast* way to check/update trust in peers (async peerinfo would not be right; certainly not with the current API) +* TRANSPORT: [CG] + - need to implement and test new blacklisting code (server-side only, client API exists) * TOPOLOGY: [CG] - - If the topology daemon crashes, peers that were put on the - blacklist with transport will never be removed from it (until - transport service dies); we should use the blacklist notification - API to learn about the exact set of blacklisted peers at all times - (FIXME: the transport_api implementation of blacklisting - also does not work nicely for this since it won't let us know about - disconnect-reconnect events and the implicit whitelisting - that might happen here; that's not so bad since we will - re-blacklist on pre-connect attempts anyway, so this is - a minor issue; OTOH, we might want to be more explicit about - allowing/forbidding connects on pre-connect to avoid - entering connect attempts to just be blacklisted shortly afterwards). - - needs more testing (especially F2F topology) + - needs more testing (especially F2F topology) -- need transport blacklisting to be implemented first! * FS: [CG] - support recursive download even if filename is NULL and we hence do not generate files on disk (use temp_filename) diff --git a/src/core/core.h b/src/core/core.h index 45d138140..f91995734 100644 --- a/src/core/core.h +++ b/src/core/core.h @@ -43,13 +43,12 @@ * transmitted to the client. */ #define GNUNET_CORE_OPTION_NOTHING 0 -#define GNUNET_CORE_OPTION_SEND_PRE_CONNECT 1 -#define GNUNET_CORE_OPTION_SEND_CONNECT 2 -#define GNUNET_CORE_OPTION_SEND_DISCONNECT 4 -#define GNUNET_CORE_OPTION_SEND_FULL_INBOUND 8 -#define GNUNET_CORE_OPTION_SEND_HDR_INBOUND 16 -#define GNUNET_CORE_OPTION_SEND_FULL_OUTBOUND 32 -#define GNUNET_CORE_OPTION_SEND_HDR_OUTBOUND 64 +#define GNUNET_CORE_OPTION_SEND_CONNECT 1 +#define GNUNET_CORE_OPTION_SEND_DISCONNECT 2 +#define GNUNET_CORE_OPTION_SEND_FULL_INBOUND 4 +#define GNUNET_CORE_OPTION_SEND_HDR_INBOUND 8 +#define GNUNET_CORE_OPTION_SEND_FULL_OUTBOUND 16 +#define GNUNET_CORE_OPTION_SEND_HDR_OUTBOUND 32 /** diff --git a/src/core/core_api.c b/src/core/core_api.c index 4672c7843..42e8f1c06 100644 --- a/src/core/core_api.c +++ b/src/core/core_api.c @@ -55,12 +55,6 @@ struct GNUNET_CORE_Handle */ GNUNET_CORE_StartupCallback init; - /** - * Function to call whenever we're notified about a peer connecting - * (pre-connects, no session key exchange yet). - */ - GNUNET_CORE_ConnectEventHandler pre_connects; - /** * Function to call whenever we're notified about a peer connecting. */ @@ -406,23 +400,6 @@ main_notify_handler (void *cls, const struct GNUNET_MessageHeader *msg) #endif switch (ntohs (msg->type)) { - case GNUNET_MESSAGE_TYPE_CORE_NOTIFY_PRE_CONNECT: - if (NULL == h->pre_connects) - { - GNUNET_break (0); - break; - } - if (msize != sizeof (struct ConnectNotifyMessage)) - { - GNUNET_break (0); - break; - } - cnm = (const struct ConnectNotifyMessage *) msg; - h->pre_connects (h->cls, - &cnm->peer, - GNUNET_TIME_relative_ntoh (cnm->latency), - ntohl (cnm->distance)); - break; case GNUNET_MESSAGE_TYPE_CORE_NOTIFY_CONNECT: if (NULL == h->connects) { @@ -662,8 +639,6 @@ transmit_start (void *cls, size_t size, void *buf) init->header.type = htons (GNUNET_MESSAGE_TYPE_CORE_INIT); init->header.size = htons (msize); opt = GNUNET_CORE_OPTION_NOTHING; - if (h->pre_connects != NULL) - opt |= GNUNET_CORE_OPTION_SEND_PRE_CONNECT; if (h->connects != NULL) opt |= GNUNET_CORE_OPTION_SEND_CONNECT; if (h->disconnects != NULL) @@ -705,7 +680,6 @@ transmit_start (void *cls, size_t size, void *buf) * @param cls closure for the various callbacks that follow (including handlers in the handlers array) * @param init callback to call on timeout or once we have successfully * connected to the core service; note that timeout is only meaningful if init is not NULL - * @param pre_connects function to call on peer pre-connect (no session key yet), can be NULL * @param connects function to call on peer connect, can be NULL * @param disconnects function to call on peer disconnect / timeout, can be NULL * @param inbound_notify function to call for all inbound messages, can be NULL @@ -726,7 +700,6 @@ GNUNET_CORE_connect (struct GNUNET_SCHEDULER_Handle *sched, struct GNUNET_TIME_Relative timeout, void *cls, GNUNET_CORE_StartupCallback init, - GNUNET_CORE_ConnectEventHandler pre_connects, GNUNET_CORE_ConnectEventHandler connects, GNUNET_CORE_DisconnectEventHandler disconnects, GNUNET_CORE_MessageCallback inbound_notify, @@ -742,7 +715,6 @@ GNUNET_CORE_connect (struct GNUNET_SCHEDULER_Handle *sched, h->cfg = cfg; h->cls = cls; h->init = init; - h->pre_connects = pre_connects; h->connects = connects; h->disconnects = disconnects; h->inbound_notify = inbound_notify; diff --git a/src/core/gnunet-service-core.c b/src/core/gnunet-service-core.c index 044b7496e..bad6f05d3 100644 --- a/src/core/gnunet-service-core.c +++ b/src/core/gnunet-service-core.c @@ -3450,13 +3450,6 @@ handle_transport_receive (void *cls, (n->status != PEER_STATE_KEY_CONFIRMED)) { GNUNET_break_op (0); - /* blacklist briefly (?); might help recover (?) */ - GNUNET_TRANSPORT_blacklist (sched, cfg, - &n->peer, - GNUNET_TIME_UNIT_SECONDS, - GNUNET_TIME_relative_multiply (GNUNET_TIME_UNIT_MILLISECONDS, - 5), - NULL, NULL); return; } handle_encrypted_message (n, (const struct EncryptedMessage *) message); @@ -3626,7 +3619,6 @@ handle_transport_notify_connect (void *cls, unsigned int distance) { struct Neighbour *n; - struct ConnectNotifyMessage cnm; if (0 == memcmp (peer, &my_identity, sizeof (struct GNUNET_PeerIdentity))) { @@ -3665,12 +3657,6 @@ handle_transport_notify_connect (void *cls, "Received connection from `%4s'.\n", GNUNET_i2s (&n->peer)); #endif - cnm.header.size = htons (sizeof (struct ConnectNotifyMessage)); - cnm.header.type = htons (GNUNET_MESSAGE_TYPE_CORE_NOTIFY_PRE_CONNECT); - cnm.distance = htonl (n->last_distance); - cnm.latency = GNUNET_TIME_relative_hton (n->last_latency); - cnm.peer = *peer; - send_to_all_clients (&cnm.header, GNUNET_YES, GNUNET_CORE_OPTION_SEND_PRE_CONNECT); GNUNET_TRANSPORT_set_quota (transport, &n->peer, n->bw_in, diff --git a/src/core/test_core_api.c b/src/core/test_core_api.c index 78d6b7fe1..6b8387461 100644 --- a/src/core/test_core_api.c +++ b/src/core/test_core_api.c @@ -229,8 +229,7 @@ init_notify (void *cls, p2.cfg, TIMEOUT, &p2, - &init_notify, - NULL, + &init_notify, &connect_notify, &disconnect_notify, &inbound_notify, @@ -325,8 +324,7 @@ run (void *cls, TIMEOUT, &p1, &init_notify, - NULL, - &connect_notify, + &connect_notify, &disconnect_notify, &inbound_notify, GNUNET_YES, &outbound_notify, GNUNET_YES, handlers); diff --git a/src/core/test_core_api_start_only.c b/src/core/test_core_api_start_only.c index e8bfdd4e5..86eff056c 100644 --- a/src/core/test_core_api_start_only.c +++ b/src/core/test_core_api_start_only.c @@ -130,8 +130,7 @@ init_notify (void *cls, p2.cfg, TIMEOUT, &p2, - &init_notify, - NULL, + &init_notify, &connect_notify, &disconnect_notify, &inbound_notify, @@ -185,8 +184,7 @@ run (void *cls, TIMEOUT, &p1, &init_notify, - NULL, - &connect_notify, + &connect_notify, &disconnect_notify, &inbound_notify, GNUNET_YES, &outbound_notify, GNUNET_YES, handlers); diff --git a/src/fs/gnunet-service-fs.c b/src/fs/gnunet-service-fs.c index faf436bc0..0d1d3d9e4 100644 --- a/src/fs/gnunet-service-fs.c +++ b/src/fs/gnunet-service-fs.c @@ -3025,7 +3025,6 @@ main_init (struct GNUNET_SCHEDULER_Handle *s, GNUNET_TIME_UNIT_FOREVER_REL, NULL, NULL, - NULL, &peer_connect_handler, &peer_disconnect_handler, NULL, GNUNET_NO, diff --git a/src/hostlist/gnunet-daemon-hostlist.c b/src/hostlist/gnunet-daemon-hostlist.c index c06ee5f56..ca0f11cae 100644 --- a/src/hostlist/gnunet-daemon-hostlist.c +++ b/src/hostlist/gnunet-daemon-hostlist.c @@ -296,7 +296,7 @@ run (void *cls, GNUNET_TIME_UNIT_FOREVER_REL, NULL, &core_init, - NULL, &connect_handler, &disconnect_handler, + &connect_handler, &disconnect_handler, NULL, GNUNET_NO, NULL, GNUNET_NO, learning? learn_handlers : no_learn_handlers); diff --git a/src/include/gnunet_core_service.h b/src/include/gnunet_core_service.h index 47b8d6f98..b7dc6f7da 100644 --- a/src/include/gnunet_core_service.h +++ b/src/include/gnunet_core_service.h @@ -51,7 +51,7 @@ struct GNUNET_CORE_Handle; /** - * Method called whenever a given peer either connects. + * Method called whenever a given peer connects. * * @param cls closure * @param peer peer identity this notification is about @@ -164,7 +164,6 @@ typedef void * @param cls closure for the various callbacks that follow (including handlers in the handlers array) * @param init callback to call on timeout or once we have successfully * connected to the core service; note that timeout is only meaningful if init is not NULL - * @param pre_connects function to call on peer pre-connect (no session key yet), can be NULL * @param connects function to call on peer connect, can be NULL * @param disconnects function to call on peer disconnect / timeout, can be NULL * @param inbound_notify function to call for all inbound messages, can be NULL @@ -200,7 +199,6 @@ GNUNET_CORE_connect (struct GNUNET_SCHEDULER_Handle *sched, struct GNUNET_TIME_Relative timeout, void *cls, GNUNET_CORE_StartupCallback init, - GNUNET_CORE_ConnectEventHandler pre_connects, GNUNET_CORE_ConnectEventHandler connects, GNUNET_CORE_DisconnectEventHandler disconnects, GNUNET_CORE_MessageCallback inbound_notify, diff --git a/src/include/gnunet_protocols.h b/src/include/gnunet_protocols.h index 602137f98..d992c9fb7 100644 --- a/src/include/gnunet_protocols.h +++ b/src/include/gnunet_protocols.h @@ -174,16 +174,19 @@ extern "C" #define GNUNET_MESSAGE_TYPE_TRANSPORT_ADDRESS_REPLY 28 /** - * Change in blacklisting status of a peer. + * Register a client that wants to do blacklisting. */ -#define GNUNET_MESSAGE_TYPE_TRANSPORT_BLACKLIST 29 +#define GNUNET_MESSAGE_TYPE_TRANSPORT_BLACKLIST_INIT 29 /** - * Request to transport to notify us about any blacklisting status - * changes on this connection (and to immediately send all - * active blacklist entries). + * Query to a blacklisting client (is this peer blacklisted)? */ -#define GNUNET_MESSAGE_TYPE_TRANSPORT_BLACKLIST_NOTIFY 30 +#define GNUNET_MESSAGE_TYPE_TRANSPORT_BLACKLIST_QUERY 30 + +/** + * Reply from blacklisting client (answer to blacklist query). + */ +#define GNUNET_MESSAGE_TYPE_TRANSPORT_BLACKLIST_REPLY 31 /** * Transport PING message diff --git a/src/include/gnunet_transport_service.h b/src/include/gnunet_transport_service.h index 711ebb599..57bdecd17 100644 --- a/src/include/gnunet_transport_service.h +++ b/src/include/gnunet_transport_service.h @@ -299,99 +299,52 @@ GNUNET_TRANSPORT_address_lookup (struct GNUNET_SCHEDULER_Handle *sched, /** - * Handle for blacklisting requests. + * Handle for blacklisting peers. */ -struct GNUNET_TRANSPORT_BlacklistRequest; +struct GNUNET_TRANSPORT_Blacklist; /** - * Blacklist a peer for a given period of time. All connections - * (inbound and outbound) to a peer that is blacklisted will be - * dropped (as soon as we learn who the connection is for). A second - * call to this function for the same peer overrides previous - * blacklisting requests. - * - * @param sched scheduler to use - * @param cfg configuration to use - * @param peer identity of peer to blacklist - * @param duration how long to blacklist, use GNUNET_TIME_UNIT_ZERO to - * re-enable connections - * @param timeout when should this operation (trying to establish the - * blacklisting time out) - * @param cont continuation to call once the request has been processed - * @param cont_cls closure for cont - * @return NULL on error, otherwise handle for cancellation - */ -struct GNUNET_TRANSPORT_BlacklistRequest * -GNUNET_TRANSPORT_blacklist (struct GNUNET_SCHEDULER_Handle *sched, - const struct GNUNET_CONFIGURATION_Handle *cfg, - const struct GNUNET_PeerIdentity *peer, - struct GNUNET_TIME_Relative duration, - struct GNUNET_TIME_Relative timeout, - GNUNET_SCHEDULER_Task cont, - void *cont_cls); - - -/** - * Abort transmitting the blacklist request. Note that this function - * is NOT for removing a peer from the blacklist (for that, call - * GNUNET_TRANSPORT_blacklist with a duration of zero). This function - * is only for aborting the transmission of a blacklist request - * (i.e. because of shutdown). - * - * @param br handle of the request that is to be cancelled - */ -void -GNUNET_TRANSPORT_blacklist_cancel (struct GNUNET_TRANSPORT_BlacklistRequest * br); - - -/** - * Handle for blacklist notifications. - */ -struct GNUNET_TRANSPORT_BlacklistNotification; - - -/** - * Signature of function called whenever the blacklist status of - * a peer changes. This includes changes to the duration of the - * blacklist status as well as the expiration of an existing - * blacklist status. + * Function that decides if a connection is acceptable or not. * * @param cls closure - * @param peer identity of peer with the change - * @param until GNUNET_TIME_UNIT_ZERO_ABS if the peer is no - * longer blacklisted, otherwise the time at - * which the current blacklisting will expire + * @param pid peer to approve or disapproave + * @return GNUNET_OK if the connection is allowed */ -typedef void (*GNUNET_TRANSPORT_BlacklistCallback)(void *cls, - const struct GNUNET_PeerIdentity *peer, - struct GNUNET_TIME_Absolute until); +typedef int (*GNUNET_TRANSPORT_BlacklistCallback)(void *cls, + const struct GNUNET_PeerIdentity *pid); /** - * Call a function whenever a peer's blacklisting status changes. + * Install a blacklist callback. The service will be queried for all + * existing connections as well as any fresh connections to check if + * they are permitted. If the blacklisting callback is unregistered, + * all hosts that were denied in the past will automatically be + * whitelisted again. Cancelling the blacklist handle is also the + * only way to re-enable connections from peers that were previously + * blacklisted. * * @param sched scheduler to use * @param cfg configuration to use - * @param bc function to call on status changes - * @param bc_cls closure for bc + * @param cb callback to invoke to check if connections are allowed + * @param cb_cls closure for cb * @return NULL on error, otherwise handle for cancellation */ -struct GNUNET_TRANSPORT_BlacklistNotification * -GNUNET_TRANSPORT_blacklist_notify (struct GNUNET_SCHEDULER_Handle *sched, - const struct GNUNET_CONFIGURATION_Handle *cfg, - GNUNET_TRANSPORT_BlacklistCallback bc, - void *bc_cls); +struct GNUNET_TRANSPORT_Blacklist * +GNUNET_TRANSPORT_blacklist (struct GNUNET_SCHEDULER_Handle *sched, + const struct GNUNET_CONFIGURATION_Handle *cfg, + GNUNET_TRANSPORT_BlacklistCallback cb, + void *cb_cls); /** - * Stop calling the notification callback associated with - * the given blacklist notification. + * Abort the blacklist. Note that this function is the only way for + * removing a peer from the blacklist. * - * @param bn handle of the request that is to be cancelled + * @param br handle of the request that is to be cancelled */ void -GNUNET_TRANSPORT_blacklist_notify_cancel (struct GNUNET_TRANSPORT_BlacklistNotification * bn); +GNUNET_TRANSPORT_blacklist_cancel (struct GNUNET_TRANSPORT_Blacklist *br); diff --git a/src/testing/test_testing_topology.c b/src/testing/test_testing_topology.c index 7f5411fc4..4c7fc01ba 100644 --- a/src/testing/test_testing_topology.c +++ b/src/testing/test_testing_topology.c @@ -392,8 +392,7 @@ setup_handlers () temp_daemon->cfg, TIMEOUT, new_connection, - &init_notify, - NULL, + &init_notify, NULL, NULL, NULL, diff --git a/src/testing/testing.c b/src/testing/testing.c index 2b9b560fa..eae5076e0 100644 --- a/src/testing/testing.c +++ b/src/testing/testing.c @@ -265,7 +265,7 @@ start_fsm (void *cls, const struct GNUNET_SCHEDULER_TaskContext *tc) ARM_START_WAIT, d, &testing_init, - NULL, NULL, NULL, + NULL, NULL, NULL, GNUNET_NO, NULL, GNUNET_NO, no_handlers); break; @@ -904,7 +904,7 @@ GNUNET_TESTING_daemons_connect (struct GNUNET_TESTING_Daemon *d1, timeout, ctx, NULL, - NULL, &connect_notify, NULL, + &connect_notify, NULL, NULL, GNUNET_NO, NULL, GNUNET_NO, no_handlers); if (ctx->d1core == NULL) diff --git a/src/topology/gnunet-daemon-topology.c b/src/topology/gnunet-daemon-topology.c index b175d82ae..0aca503c1 100644 --- a/src/topology/gnunet-daemon-topology.c +++ b/src/topology/gnunet-daemon-topology.c @@ -105,12 +105,6 @@ struct Peer */ struct GNUNET_CONTAINER_BloomFilter *filter; - /** - * Our request handle for *whitelisting* this peer (NULL if - * no whitelisting request is pending). - */ - struct GNUNET_TRANSPORT_BlacklistRequest *wh; - /** * Until what time should we not try to connect again * to this peer? @@ -153,39 +147,6 @@ struct Peer */ int is_connected; - /** - * Are we currently blocking this peer (via blacklist)? - */ - int is_blocked; - -}; - - -/** - * Entry in linked list of active 'disconnect' requests that we have issued. - */ -struct DisconnectList -{ - /** - * This is a doubly-linked list. - */ - struct DisconnectList *next; - - /** - * This is a doubly-linked list. - */ - struct DisconnectList *prev; - - /** - * Our request handle. - */ - struct GNUNET_TRANSPORT_BlacklistRequest *rh; - - /** - * Peer we tried to disconnect. - */ - struct GNUNET_PeerIdentity peer; - }; @@ -232,6 +193,11 @@ static struct GNUNET_CONTAINER_MultiHashMap *peers; */ static struct GNUNET_STATISTICS_Handle *stats; +/** + * Blacklist (NULL if we have none). + */ +static struct GNUNET_TRANSPORT_Blacklist *blacklist; + /** * Flag to disallow non-friend connections (pure F2F mode). */ @@ -263,119 +229,31 @@ static unsigned int friend_count; */ static int autoconnect; -/** - * Head of doubly-linked list of active 'disconnect' requests that we have issued. - */ -static struct DisconnectList *disconnect_head; - -/** - * Head of doubly-linked list of active 'disconnect' requests that we have issued. - */ -static struct DisconnectList *disconnect_tail; - /** - * Function called once our request to 'disconnect' a peer - * has completed. + * Function that decides if a connection is acceptable or not. + * If we have a blacklist, only friends are allowed, so the check + * is rather simple. * - * @param cls our 'struct DisconnectList' - * @param tc unused + * @param cls closure + * @param pid peer to approve or disapproave + * @return GNUNET_OK if the connection is allowed */ -static void -disconnect_done (void *cls, - const struct GNUNET_SCHEDULER_TaskContext *tc) +static int +blacklist_check (void *cls, + const struct GNUNET_PeerIdentity *pid) { - struct DisconnectList *dl = cls; + struct Peer *pos; + pos = GNUNET_CONTAINER_multihashmap_get (peers, &pid->hashPubKey); + if ( (pos != NULL) && + (pos->is_friend == GNUNET_YES) ) + return GNUNET_OK; GNUNET_STATISTICS_update (stats, gettext_noop ("# peers blacklisted"), 1, GNUNET_NO); - GNUNET_CONTAINER_DLL_remove (disconnect_head, - disconnect_tail, - dl); - GNUNET_free (dl); -} - - -/** - * Force a disconnect from the specified peer. - * - * @param pl peer to disconnect - */ -static void -force_disconnect (struct Peer *pl) -{ - const struct GNUNET_PeerIdentity *peer = &pl->pid; - 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, - disconnect_tail, - dl); - dl->rh = GNUNET_TRANSPORT_blacklist (sched, cfg, - peer, - GNUNET_TIME_UNIT_FOREVER_REL, - GNUNET_TIME_UNIT_FOREVER_REL, - &disconnect_done, - dl); -} - - - -/** - * Function called once our request to 'whitelist' a peer - * has completed. - * - * @param cls our 'struct Peer' - * @param tc unused - */ -static void -whitelist_done (void *cls, - const struct GNUNET_SCHEDULER_TaskContext *tc) -{ - struct Peer *pl = cls; - - pl->wh = NULL; - GNUNET_STATISTICS_update (stats, - gettext_noop ("# peers blacklisted"), - -1, - GNUNET_NO); -} - - -/** - * Whitelist the given peer (if it was blacklisted before). - * - * @param cls closure (not used) - * @param pid identity of the peer - * @param value peer to free - * @return GNUNET_YES (always: continue to iterate) - */ -static int -whitelist_peer (void *cls, - const GNUNET_HashCode *pid, - void *value) -{ - struct Peer *pl = value; - - if (! pl->is_blocked) - return GNUNET_YES; - pl->wh = GNUNET_TRANSPORT_blacklist (sched, cfg, - &pl->pid, - GNUNET_TIME_UNIT_ZERO, - GNUNET_TIME_UNIT_FOREVER_REL, - &whitelist_done, - pl); - pl->is_blocked = GNUNET_NO; - return GNUNET_YES; + return GNUNET_SYSERR; } @@ -386,22 +264,11 @@ whitelist_peer (void *cls, static void whitelist_peers () { - struct DisconnectList *dl; - - /* first, cancel all blacklisting requests */ - while (NULL != (dl = disconnect_head)) + if (blacklist != NULL) { - GNUNET_CONTAINER_DLL_remove (disconnect_head, - disconnect_tail, - dl); - GNUNET_TRANSPORT_blacklist_cancel (dl->rh); - GNUNET_free (dl); + GNUNET_TRANSPORT_blacklist_cancel (blacklist); + blacklist = NULL; } - /* then, specifically whitelist all peers that we - know to have blacklisted */ - GNUNET_CONTAINER_multihashmap_iterate (peers, - &whitelist_peer, - NULL); } @@ -477,8 +344,6 @@ free_peer (void *cls, pos)); 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) @@ -521,8 +386,6 @@ attempt_connect (struct Peer *pos) return; if (GNUNET_OK != is_connection_allowed (pos)) return; - if (GNUNET_YES == pos->is_blocked) - return; if (GNUNET_TIME_absolute_get_remaining (pos->greylisted_until).value > 0) return; if (GNUNET_YES == pos->is_friend) @@ -593,7 +456,6 @@ remove_from_greylist (void *cls, pos); } if ( (GNUNET_NO == pos->is_friend) && - (GNUNET_NO == pos->is_blocked) && (GNUNET_NO == pos->is_connected) ) { free_peer (NULL, &pos->pid.hashPubKey, pos); @@ -863,18 +725,7 @@ connect_notify (void *cls, if (pos == NULL) { pos = make_peer (peer, NULL, GNUNET_NO); - if (GNUNET_OK != is_connection_allowed (pos)) - { - GNUNET_assert (pos->is_friend == GNUNET_NO); - pos->is_connected = GNUNET_YES; -#if DEBUG_TOPOLOGY - GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, - "Connection to `%s' is forbidden, forcing disconnect!\n", - GNUNET_i2s (peer)); -#endif - force_disconnect (pos); - return; - } + GNUNET_break (GNUNET_OK == is_connection_allowed (pos)); } else { @@ -898,35 +749,6 @@ connect_notify (void *cls, } -/** - * Disconnect from all non-friends (we're below quota). - * - * @param cls closure, not used - * @param pid identity of a peer - * @param value 'struct Peer*' for the peer - * @return GNUNET_YES (continue to iterate) - */ -static int -drop_non_friends (void *cls, - const GNUNET_HashCode *pid, - void *value) -{ - struct Peer *pos = value; - - if ( (GNUNET_NO == pos->is_friend) && - (GNUNET_YES == pos->is_connected) ) - { -#if DEBUG_TOPOLOGY - GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, - "Connection to `%s' is not from a friend, forcing disconnect!\n", - GNUNET_i2s (&pos->pid)); -#endif - force_disconnect (pos); - } - return GNUNET_YES; -} - - /** * Try to add more peers to our connection set. * @@ -995,17 +817,10 @@ disconnect_notify (void *cls, GNUNET_CONTAINER_multihashmap_iterate (peers, &try_add_peers, NULL); - if (friend_count < minimum_friend_count) - { - /* disconnect from all non-friends */ -#if DEBUG_TOPOLOGY - GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, - "Not enough friendly connections, dropping all non-friend connections\n"); -#endif - GNUNET_CONTAINER_multihashmap_iterate (peers, - &drop_non_friends, - NULL); - } + if ( (friend_count < minimum_friend_count) && + (blacklist == NULL) ) + blacklist = GNUNET_TRANSPORT_blacklist (sched, cfg, + &blacklist_check, NULL); } @@ -1389,13 +1204,21 @@ handle_encrypted_hello (void *cls, GNUNET_NO); peer = GNUNET_CONTAINER_multihashmap_get (peers, &pid.hashPubKey); - if ( (peer != NULL) && - (peer->is_blocked) ) - return GNUNET_OK; /* ignore: currently blocked */ - if ( (GNUNET_YES == friends_only) && - ( (peer == NULL) || - (GNUNET_YES != peer->is_friend) ) ) - return GNUNET_OK; /* ignore: not a friend */ + if (peer == NULL) + { + if ( (GNUNET_YES == friends_only) || + (friend_count < minimum_friend_count) ) + return GNUNET_OK; + } + else + { + if ( (GNUNET_YES != peer->is_friend) && + (GNUNET_YES == friends_only) ) + return GNUNET_OK; + if ( (GNUNET_YES != peer->is_friend) && + (friend_count < minimum_friend_count) ) + return GNUNET_OK; + } if (transport != NULL) GNUNET_TRANSPORT_offer_hello (transport, message); @@ -1468,8 +1291,6 @@ static void cleaning_task (void *cls, const struct GNUNET_SCHEDULER_TaskContext *tc) { - struct DisconnectList *dl; - if (NULL != peerinfo_notify) { GNUNET_PEERINFO_notify_cancel (peerinfo_notify); @@ -1486,14 +1307,7 @@ cleaning_task (void *cls, GNUNET_CORE_disconnect (handle); handle = NULL; } - while (NULL != (dl = disconnect_head)) - { - GNUNET_CONTAINER_DLL_remove (disconnect_head, - disconnect_tail, - dl); - GNUNET_TRANSPORT_blacklist_cancel (dl->rh); - GNUNET_free (dl); - } + whitelist_peers (); if (stats != NULL) { GNUNET_STATISTICS_destroy (stats, GNUNET_NO); @@ -1560,6 +1374,9 @@ run (void *cls, minimum_friend_count, autoconnect ? "autoconnect enabled" : "autoconnect disabled"); #endif + if (friend_count < minimum_friend_count) + blacklist = GNUNET_TRANSPORT_blacklist (sched, cfg, + &blacklist_check, NULL); transport = GNUNET_TRANSPORT_connect (sched, cfg, NULL, @@ -1571,7 +1388,6 @@ run (void *cls, GNUNET_TIME_UNIT_FOREVER_REL, NULL, &core_init, - NULL, &connect_notify, &disconnect_notify, NULL, GNUNET_NO, diff --git a/src/transport/Makefile.am b/src/transport/Makefile.am index 70c6c6c75..71e6470e3 100644 --- a/src/transport/Makefile.am +++ b/src/transport/Makefile.am @@ -57,8 +57,7 @@ gnunet_transport_LDADD = \ $(GN_LIBINTL) gnunet_service_transport_SOURCES = \ - gnunet-service-transport.c plugin_transport.h \ - gnunet-service-transport_blacklist.c gnunet-service-transport_blacklist.h + gnunet-service-transport.c plugin_transport.h gnunet_service_transport_LDADD = \ $(top_builddir)/src/peerinfo/libgnunetpeerinfo.la \ $(top_builddir)/src/statistics/libgnunetstatistics.la \ diff --git a/src/transport/gnunet-service-transport_blacklist.c b/src/transport/gnunet-service-transport_blacklist.c index 8f78f498f..08ed2c9d2 100644 --- a/src/transport/gnunet-service-transport_blacklist.c +++ b/src/transport/gnunet-service-transport_blacklist.c @@ -43,17 +43,60 @@ struct BlacklistEntry struct GNUNET_PeerIdentity peer; /** - * How long until this entry times out? + * Client responsible for this entry. */ - struct GNUNET_TIME_Absolute until; + struct GNUNET_SERVER_Client *client; + +}; + + +/** + * Information kept for each client registered to perform + * blacklisting. + */ +struct Blacklisters +{ + /** + * This is a linked list. + */ + struct Blacklisters *next; + + /** + * This is a linked list. + */ + struct Blacklisters *prev; /** - * Task scheduled to run the moment the time does run out. + * Client responsible for this entry. */ - GNUNET_SCHEDULER_TaskIdentifier timeout_task; + struct GNUNET_SERVER_Client *client; + }; +/** + * State of blacklist check to be performed for each + * connecting peer. + */ +struct BlacklistCheck +{ + + + + /** + * Identity of the peer being checked. + */ + struct GNUNET_PeerIdentity peer; + + /** + * Clients we still need to ask. + */ + struct GNUNET_SERVER_Client *pending; + +}; + + + /** * Map of blacklisted peers (maps from peer identities * to 'struct BlacklistEntry*' values). @@ -61,14 +104,14 @@ struct BlacklistEntry static struct GNUNET_CONTAINER_MultiHashMap *blacklist; /** - * Notifications for blacklisting. + * Head of DLL of blacklisting clients. */ -static struct GNUNET_SERVER_NotificationContext *blacklist_notifiers; +static struct Blacklisters *bl_head; /** - * Our scheduler. + * Tail of DLL of blacklisting clients. */ -static struct GNUNET_SCHEDULER_Handle *sched; +static struct Blacklisters *bl_tail; /** @@ -86,8 +129,6 @@ free_blacklist_entry (void *cls, { struct BlacklistEntry *be = value; - GNUNET_SCHEDULER_cancel (sched, - be->timeout_task); GNUNET_free (be); return GNUNET_YES; } @@ -108,37 +149,28 @@ shutdown_task (void *cls, NULL); GNUNET_CONTAINER_multihashmap_destroy (blacklist); blacklist = NULL; - GNUNET_SERVER_notification_context_destroy (blacklist_notifiers); - blacklist_notifiers = NULL; } /** - * Task run when a blacklist entry times out. + * Handle a request to start a blacklist. * - * @param cls closure (the 'struct BlacklistEntry*') - * @param tc scheduler context (unused) + * @param cls closure (always NULL) + * @param client identification of the client + * @param message the actual message */ -static void -timeout_task (void *cls, - const struct GNUNET_SCHEDULER_TaskContext *tc) +void +GNUNET_TRANSPORT_handle_blacklist_init (void *cls, + struct GNUNET_SERVER_Client *client, + const struct GNUNET_MessageHeader *message) { - struct BlacklistEntry *be = cls; - struct BlacklistMessage msg; - - be->timeout_task = GNUNET_SCHEDULER_NO_TASK; - msg.header.type = htons (GNUNET_MESSAGE_TYPE_TRANSPORT_BLACKLIST); - msg.header.size = htons (sizeof (struct BlacklistMessage)); - msg.reserved = htonl (0); - msg.peer = be->peer; - msg.until = GNUNET_TIME_absolute_hton (GNUNET_TIME_UNIT_ZERO_ABS); - GNUNET_assert (GNUNET_YES == GNUNET_CONTAINER_multihashmap_remove (blacklist, - &be->peer.hashPubKey, - be)); - GNUNET_free (be); - GNUNET_SERVER_notification_context_broadcast (blacklist_notifiers, - &msg.header, - GNUNET_NO); + struct Blacklisters *bl; + + bl = GNUNET_malloc (sizeof (struct Blacklisters)); + bl->client = client; + GNUNET_SERVER_client_keep (client); + GNUNET_CONTAINER_DLL_insert (bl_head, bl_tail, bl); + /* FIXME: confirm that all existing connections are OK! */ } @@ -150,38 +182,33 @@ timeout_task (void *cls, * @param message the actual message */ void -GNUNET_TRANSPORT_handle_blacklist (void *cls, - struct GNUNET_SERVER_Client *client, - const struct GNUNET_MessageHeader *message) +GNUNET_TRANSPORT_handle_blacklist_reply (void *cls, + struct GNUNET_SERVER_Client *client, + const struct GNUNET_MessageHeader *message) { - struct BlacklistEntry *be; + struct Blacklisters *bl; const struct BlacklistMessage *msg = (const struct BlacklistMessage*) message; - be = GNUNET_CONTAINER_multihashmap_get (blacklist, - &msg->peer.hashPubKey); - if (be != NULL) + bl = bl_head; + while ( (bl != NULL) && + (bl->client != client) ) + bl = bl->next; + if (bl == NULL) { - GNUNET_SCHEDULER_cancel (sched, - be->timeout_task); + GNUNET_SERVER_client_done (client, GNUNET_SYSERR); + return; } - else - { + if (ntohl (msg->is_allowed) == GNUNET_SYSERR) + { be = GNUNET_malloc (sizeof (struct BlacklistEntry)); be->peer = msg->peer; + be->client = client; GNUNET_CONTAINER_multihashmap_put (blacklist, &msg->peer.hashPubKey, be, - GNUNET_CONTAINER_MULTIHASHMAPOPTION_UNIQUE_ONLY); + GNUNET_CONTAINER_MULTIHASHMAPOPTION_MULTIPLE); } - be->until = GNUNET_TIME_absolute_ntoh (msg->until); - be->timeout_task = GNUNET_SCHEDULER_add_delayed (sched, - GNUNET_TIME_absolute_get_remaining (be->until), - &timeout_task, - be); - GNUNET_SERVER_notification_context_broadcast (blacklist_notifiers, - &msg->header, - GNUNET_NO); - GNUNET_SERVER_receive_done (client, GNUNET_OK); + /* FIXME: trigger continuation... */ } @@ -243,7 +270,9 @@ GNUNET_TRANSPORT_handle_blacklist_notify (void *cls, int GNUNET_TRANSPORT_blacklist_check (const struct GNUNET_PeerIdentity *id) { - return GNUNET_CONTAINER_multihashmap_contains (blacklist, &id->hashPubKey); + if (GNUNET_CONTAINER_multihashmap_contains (blacklist, &id->hashPubKey)) + return GNUNET_YES; + } @@ -263,7 +292,6 @@ GNUNET_TRANSPORT_blacklist_init (struct GNUNET_SERVER_Handle *server, GNUNET_TIME_UNIT_FOREVER_REL, &shutdown_task, NULL); - blacklist_notifiers = GNUNET_SERVER_notification_context_create (server, 0); } diff --git a/src/transport/gnunet-service-transport_blacklist.h b/src/transport/gnunet-service-transport_blacklist.h index 92f81a2e9..32e26431e 100644 --- a/src/transport/gnunet-service-transport_blacklist.h +++ b/src/transport/gnunet-service-transport_blacklist.h @@ -31,16 +31,16 @@ #include "transport.h" /** - * Handle a request to blacklist a peer. + * Handle a request to start a blacklist. * * @param cls closure (always NULL) * @param client identification of the client * @param message the actual message */ void -GNUNET_TRANSPORT_handle_blacklist (void *cls, - struct GNUNET_SERVER_Client *client, - const struct GNUNET_MessageHeader *message); +GNUNET_TRANSPORT_handle_blacklist_init (void *cls, + struct GNUNET_SERVER_Client *client, + const struct GNUNET_MessageHeader *message); /** @@ -51,30 +51,9 @@ GNUNET_TRANSPORT_handle_blacklist (void *cls, * @param message the actual message */ void -GNUNET_TRANSPORT_handle_blacklist_notify (void *cls, - struct GNUNET_SERVER_Client *client, - const struct GNUNET_MessageHeader *message); - - -/** - * Is the given peer currently blacklisted? - * - * @param id identity of the peer - * @return GNUNET_YES if the peer is blacklisted, GNUNET_NO if not - */ -int -GNUNET_TRANSPORT_blacklist_check (const struct GNUNET_PeerIdentity *id); - - -/** - * Initialize the blacklisting subsystem. - * - * @param server server we handle requests from (transport service server) - * @param s scheduler to use - */ -void -GNUNET_TRANSPORT_blacklist_init (struct GNUNET_SERVER_Handle *server, - struct GNUNET_SCHEDULER_Handle *s); +GNUNET_TRANSPORT_handle_blacklist_reply (void *cls, + struct GNUNET_SERVER_Client *client, + const struct GNUNET_MessageHeader *message); #endif diff --git a/src/transport/transport.h b/src/transport/transport.h index d66b87b35..b2ef01bb5 100644 --- a/src/transport/transport.h +++ b/src/transport/transport.h @@ -268,27 +268,22 @@ struct BlacklistMessage { /** - * Type will be GNUNET_MESSAGE_TYPE_TRANSPORT_BLACKLIST + * Type will be GNUNET_MESSAGE_TYPE_TRANSPORT_BLACKLIST_QUERY or + * GNUNET_MESSAGE_TYPE_TRANSPORT_BLACKLIST_REPLY. */ struct GNUNET_MessageHeader header; /** - * Reserved (for alignment). + * 0 for the query, GNUNET_OK (allowed) or GNUNET_SYSERR (disallowed) + * for the response. */ - uint32_t reserved GNUNET_PACKED; + uint32_t is_allowed GNUNET_PACKED; /** - * Which peer is being blacklisted (or has seen its - * blacklisting expire)? + * Which peer is being blacklisted or queried? */ struct GNUNET_PeerIdentity peer; - /** - * Until what time is this peer blacklisted (zero for - * no longer blacklisted). - */ - struct GNUNET_TIME_AbsoluteNBO until; - }; diff --git a/src/transport/transport_api_blacklist.c b/src/transport/transport_api_blacklist.c index c8838f1b6..5d2d616e8 100644 --- a/src/transport/transport_api_blacklist.c +++ b/src/transport/transport_api_blacklist.c @@ -36,7 +36,7 @@ /** * Handle for blacklisting requests. */ -struct GNUNET_TRANSPORT_BlacklistRequest +struct GNUNET_TRANSPORT_Blacklist { /** @@ -45,342 +45,255 @@ struct GNUNET_TRANSPORT_BlacklistRequest struct GNUNET_CLIENT_Connection * client; /** - * Function to call when done. - */ - GNUNET_SCHEDULER_Task cont; - - /** - * Clsoure for 'cont'. + * Scheduler to use. */ - void *cont_cls; + struct GNUNET_SCHEDULER_Handle *sched; /** - * Scheduler to use. + * Configuration to use. */ - struct GNUNET_SCHEDULER_Handle *sched; + const struct GNUNET_CONFIGURATION_Handle *cfg; /** - * Pending handle for the blacklisting request. + * Pending handle for the current request. */ struct GNUNET_CLIENT_TransmitHandle *th; - + /** - * How long should 'peer' be blacklisted? + * Function to call for determining if a peer is allowed + * to communicate with us. */ - struct GNUNET_TIME_Absolute duration; - + GNUNET_TRANSPORT_BlacklistCallback cb; + /** - * Which peer is being blacklisted? + * Closure for 'cb'. + */ + void *cb_cls; + + /** + * Peer currently under consideration. */ struct GNUNET_PeerIdentity peer; - + }; /** - * Function called to notify a client about the socket - * begin ready to queue more data. "buf" will be - * NULL and "size" zero if the socket was closed for - * writing in the meantime. + * Establish blacklist connection to transport service. * - * @param cls closure - * @param size number of bytes available in buf - * @param buf where the callee should write the message - * @return number of bytes written to buf + * @param br overall handle */ -static size_t -transmit_blacklist_request (void *cls, - size_t size, void *buf) -{ - struct GNUNET_TRANSPORT_BlacklistRequest *br = cls; - struct BlacklistMessage req; - - if (buf == NULL) - { - GNUNET_SCHEDULER_add_continuation (br->sched, - br->cont, - br->cont_cls, - GNUNET_SCHEDULER_REASON_TIMEOUT); - GNUNET_free (br); - return 0; - } - req.header.size = htons (sizeof (req)); - req.header.type = htons (GNUNET_MESSAGE_TYPE_TRANSPORT_BLACKLIST); - req.reserved = htonl (0); - req.peer = br->peer; - req.until = GNUNET_TIME_absolute_hton (br->duration); - memcpy (buf, &req, sizeof (req)); - GNUNET_SCHEDULER_add_continuation (br->sched, - br->cont, - br->cont_cls, - GNUNET_SCHEDULER_REASON_PREREQ_DONE); - GNUNET_free (br); - return sizeof (req); -} +static void +reconnect (struct GNUNET_TRANSPORT_Blacklist *br); /** - * Blacklist a peer for a given period of time. All connections - * (inbound and outbound) to a peer that is blacklisted will be - * dropped (as soon as we learn who the connection is for). A second - * call to this function for the same peer overrides previous - * blacklisting requests. + * Send our reply to a blacklisting request. * - * @param sched scheduler to use - * @param cfg configuration to use - * @param peer identity of peer to blacklist - * @param duration how long to blacklist, use GNUNET_TIME_UNIT_ZERO to - * re-enable connections - * @param timeout when should this operation (trying to establish the - * blacklisting time out) - * @param cont continuation to call once the request has been processed - * @param cont_cls closure for cont - * @return NULL on error, otherwise handle for cancellation + * @param br our overall context */ -struct GNUNET_TRANSPORT_BlacklistRequest * -GNUNET_TRANSPORT_blacklist (struct GNUNET_SCHEDULER_Handle *sched, - const struct GNUNET_CONFIGURATION_Handle *cfg, - const struct GNUNET_PeerIdentity *peer, - struct GNUNET_TIME_Relative duration, - struct GNUNET_TIME_Relative timeout, - GNUNET_SCHEDULER_Task cont, - void *cont_cls) -{ - struct GNUNET_CLIENT_Connection * client; - struct GNUNET_TRANSPORT_BlacklistRequest *ret; - - client = GNUNET_CLIENT_connect (sched, "transport", cfg); - if (NULL == client) - return NULL; - ret = GNUNET_malloc (sizeof (struct GNUNET_TRANSPORT_BlacklistRequest)); - ret->client = client; - ret->peer = *peer; - ret->duration = GNUNET_TIME_relative_to_absolute (duration); - ret->sched = sched; - ret->cont = cont; - ret->cont_cls = cont_cls; - ret->th = GNUNET_CLIENT_notify_transmit_ready (client, - sizeof (struct BlacklistMessage), - timeout, - GNUNET_YES, - &transmit_blacklist_request, - ret); - GNUNET_assert (NULL != ret->th); - return ret; -} +static void +reply (struct GNUNET_TRANSPORT_Blacklist *br); /** - * Abort transmitting the blacklist request. Note that this function - * is NOT for removing a peer from the blacklist (for that, call - * GNUNET_TRANSPORT_blacklist with a duration of zero). This function - * is only for aborting the transmission of a blacklist request - * (i.e. because of shutdown). + * Handle blacklist queries. * - * @param br handle of the request that is to be cancelled + * @param cls our overall handle + * @param msg query */ -void -GNUNET_TRANSPORT_blacklist_cancel (struct GNUNET_TRANSPORT_BlacklistRequest * br) -{ - GNUNET_CLIENT_notify_transmit_ready_cancel (br->th); - GNUNET_free (br); -} - - -/** - * Handle for blacklist notifications. - */ -struct GNUNET_TRANSPORT_BlacklistNotification +static void +query_handler (void *cls, + const struct GNUNET_MessageHeader *msg) { - - /** - * Function to call whenever there is a change. - */ - GNUNET_TRANSPORT_BlacklistCallback notify; - - /** - * Closure for notify. - */ - void *notify_cls; - - /** - * Scheduler to use. - */ - struct GNUNET_SCHEDULER_Handle *sched; - - /** - * Configuration to use. - */ - const struct GNUNET_CONFIGURATION_Handle *cfg; + struct GNUNET_TRANSPORT_Blacklist *br = cls; + const struct BlacklistMessage *bm; - /** - * Connection to transport service. - */ - struct GNUNET_CLIENT_Connection * client; - - /** - * Pending handle for the notification request. - */ - struct GNUNET_CLIENT_TransmitHandle *th; -}; + if ( (ntohs(msg->size) != sizeof (struct BlacklistMessage)) || + (ntohs(msg->type) != GNUNET_MESSAGE_TYPE_TRANSPORT_BLACKLIST_QUERY) ) + { + reconnect (br); + return; + } + bm = (const struct BlacklistMessage *)msg; + GNUNET_break (0 == ntohl (bm->is_allowed)); + br->peer = bm->peer; + reply (br); +} /** - * Send a request to receive blacklisting notifications + * Receive blacklist queries from transport service. * - * @param bn context to initialize + * @param br overall handle */ static void -request_notifications (struct GNUNET_TRANSPORT_BlacklistNotification *bn); +receive (struct GNUNET_TRANSPORT_Blacklist *br) +{ + GNUNET_CLIENT_receive (br->client, + &query_handler, + br, + GNUNET_TIME_UNIT_FOREVER_REL); +} /** - * Destroy the existing connection to the transport service and - * setup a new one (the existing one had serious problems). - * - * @param bn context to re-initialize + * Transmit the blacklist initialization request to the service. + * + * @param cls closure (struct GNUNET_TRANSPORT_Blacklist*) + * @param size number of bytes available in buf + * @param buf where the callee should write the message + * @return number of bytes written to buf */ -static void -retry_get_notifications (struct GNUNET_TRANSPORT_BlacklistNotification *bn) +static size_t +transmit_blacklist_init (void *cls, + size_t size, void *buf) { - GNUNET_CLIENT_disconnect (bn->client, GNUNET_NO); - bn->client = GNUNET_CLIENT_connect (bn->sched, "transport", bn->cfg); - request_notifications (bn); + struct GNUNET_TRANSPORT_Blacklist *br = cls; + struct GNUNET_MessageHeader req; + + if (buf == NULL) + { + reconnect (br); + return 0; + } + req.size = htons (sizeof (struct GNUNET_MessageHeader)); + req.type = htons (GNUNET_MESSAGE_TYPE_TRANSPORT_BLACKLIST_INIT); + memcpy (buf, &req, sizeof (req)); + receive (br); + return sizeof (req); } /** - * Function called whenever we get a blacklisting notification. - * Pass it on to the callback and wait for more. + * Establish blacklist connection to transport service. * - * @param cls our 'struct GNUNET_TRANSPORT_BlacklistNotification *' - * @param msg the blacklisting notification, NULL on error + * @param br overall handle */ static void -recv_blacklist_info (void *cls, - const struct GNUNET_MessageHeader *msg) +reconnect (struct GNUNET_TRANSPORT_Blacklist *br) { - struct GNUNET_TRANSPORT_BlacklistNotification *bn = cls; - const struct BlacklistMessage *req; - - if ( (msg == NULL) || - (sizeof(struct BlacklistMessage) != ntohs(msg->size)) || - (GNUNET_MESSAGE_TYPE_TRANSPORT_BLACKLIST != ntohs(msg->type)) ) - { - retry_get_notifications (bn); - return; - } - req = (const struct BlacklistMessage*) msg; - bn->notify (bn->notify_cls, - &req->peer, - GNUNET_TIME_absolute_ntoh (req->until)); - GNUNET_CLIENT_receive (bn->client, - &recv_blacklist_info, - bn, - GNUNET_TIME_UNIT_FOREVER_REL); + if (br->client != NULL) + GNUNET_CLIENT_disconnect (br->client, GNUNET_NO); + br->client = GNUNET_CLIENT_connect (br->sched, + "transport", + br->cfg); + br->th = GNUNET_CLIENT_notify_transmit_ready (br->client, + sizeof (struct GNUNET_MessageHeader), + GNUNET_TIME_UNIT_FOREVER_REL, + GNUNET_YES, + &transmit_blacklist_init, + br); } /** - * Function called to notify a client about the socket - * begin ready to queue more data. "buf" will be - * NULL and "size" zero if the socket was closed for - * writing in the meantime. + * Transmit the blacklist response to the service. * - * @param cls closure + * @param cls closure (struct GNUNET_TRANSPORT_Blacklist*) * @param size number of bytes available in buf * @param buf where the callee should write the message * @return number of bytes written to buf */ -static size_t -transmit_notify_request (void *cls, - size_t size, void *buf) +static size_t +transmit_blacklist_reply (void *cls, + size_t size, void *buf) { - struct GNUNET_TRANSPORT_BlacklistNotification *bn = cls; - struct GNUNET_MessageHeader hdr; + struct GNUNET_TRANSPORT_Blacklist *br = cls; + struct BlacklistMessage req; - bn->th = NULL; if (buf == NULL) { - retry_get_notifications (bn); + reconnect (br); return 0; } - GNUNET_assert (size >= sizeof(hdr)); - hdr.size = htons (sizeof (hdr)); - hdr.type = htons (GNUNET_MESSAGE_TYPE_TRANSPORT_BLACKLIST_NOTIFY); - memcpy (buf, &hdr, sizeof(hdr)); - return sizeof(hdr); + req.header.size = htons (sizeof (req)); + req.header.type = htons (GNUNET_MESSAGE_TYPE_TRANSPORT_BLACKLIST_REPLY); + req.is_allowed = htonl (br->cb (br->cb_cls, &br->peer)); + req.peer = br->peer; + memcpy (buf, &req, sizeof (req)); + receive (br); + return sizeof (req); } /** - * Send a request to receive blacklisting notifications + * Send our reply to a blacklisting request. * - * @param bn context to initialize + * @param br our overall context */ static void -request_notifications (struct GNUNET_TRANSPORT_BlacklistNotification *bn) +reply (struct GNUNET_TRANSPORT_Blacklist *br) { - GNUNET_assert (bn->client != NULL); - bn->th = GNUNET_CLIENT_notify_transmit_ready (bn->client, - sizeof (struct GNUNET_MessageHeader), + br->th = GNUNET_CLIENT_notify_transmit_ready (br->client, + sizeof (struct BlacklistMessage), GNUNET_TIME_UNIT_FOREVER_REL, - GNUNET_YES, - &transmit_notify_request, - bn); - GNUNET_assert (bn->th != NULL); - GNUNET_CLIENT_receive (bn->client, - &recv_blacklist_info, - bn, - GNUNET_TIME_UNIT_FOREVER_REL); + GNUNET_NO, + &transmit_blacklist_reply, + br); + if (br->th == NULL) + { + reconnect (br); + return; + } } /** - * Call a function whenever a peer's blacklisting status changes. + * Install a blacklist callback. The service will be queried for all + * existing connections as well as any fresh connections to check if + * they are permitted. If the blacklisting callback is unregistered, + * all hosts that were denied in the past will automatically be + * whitelisted again. Cancelling the blacklist handle is also the + * only way to re-enable connections from peers that were previously + * blacklisted. * * @param sched scheduler to use * @param cfg configuration to use - * @param bc function to call on status changes - * @param bc_cls closure for bc + * @param cb callback to invoke to check if connections are allowed + * @param cb_cls closure for cb * @return NULL on error, otherwise handle for cancellation */ -struct GNUNET_TRANSPORT_BlacklistNotification * -GNUNET_TRANSPORT_blacklist_notify (struct GNUNET_SCHEDULER_Handle *sched, - const struct GNUNET_CONFIGURATION_Handle *cfg, - GNUNET_TRANSPORT_BlacklistCallback bc, - void *bc_cls) +struct GNUNET_TRANSPORT_Blacklist * +GNUNET_TRANSPORT_blacklist (struct GNUNET_SCHEDULER_Handle *sched, + const struct GNUNET_CONFIGURATION_Handle *cfg, + GNUNET_TRANSPORT_BlacklistCallback cb, + void *cb_cls) { - struct GNUNET_TRANSPORT_BlacklistNotification *ret; struct GNUNET_CLIENT_Connection * client; + struct GNUNET_TRANSPORT_Blacklist *ret; client = GNUNET_CLIENT_connect (sched, "transport", cfg); if (NULL == client) return NULL; - ret = GNUNET_malloc (sizeof (struct GNUNET_TRANSPORT_BlacklistNotification)); + ret = GNUNET_malloc (sizeof (struct GNUNET_TRANSPORT_Blacklist)); ret->client = client; ret->sched = sched; ret->cfg = cfg; - ret->notify = bc; - ret->notify_cls = bc_cls; - request_notifications (ret); + ret->th = GNUNET_CLIENT_notify_transmit_ready (client, + sizeof (struct GNUNET_MessageHeader), + GNUNET_TIME_UNIT_FOREVER_REL, + GNUNET_YES, + &transmit_blacklist_init, + ret); return ret; } /** - * Stop calling the notification callback associated with - * the given blacklist notification. + * Abort the blacklist. Note that this function is the only way for + * removing a peer from the blacklist. * - * @param bn handle of the request that is to be cancelled + * @param br handle of the request that is to be cancelled */ void -GNUNET_TRANSPORT_blacklist_notify_cancel (struct GNUNET_TRANSPORT_BlacklistNotification * bn) +GNUNET_TRANSPORT_blacklist_cancel (struct GNUNET_TRANSPORT_Blacklist *br) { - if (bn->th != NULL) - GNUNET_CLIENT_notify_transmit_ready_cancel (bn->th); - GNUNET_CLIENT_disconnect (bn->client, GNUNET_NO); - GNUNET_free (bn); + if (br->th != NULL) + GNUNET_CLIENT_notify_transmit_ready_cancel (br->th); + GNUNET_CLIENT_disconnect (br->client, GNUNET_NO); + GNUNET_free (br); } + /* end of transport_api_blacklist.c */ -- cgit v1.2.3