--- /dev/null
+/*
+ This file is part of GNUnet.
+ (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
+ by the Free Software Foundation; either version 3, or (at your
+ option) any later version.
+
+ GNUnet is distributed in the hope that it will be useful, but
+ WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ General Public License for more details.
+
+ 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.
+*/
+
+/**
+ * @file transport/gnunet-service-transport_blacklist.c
+ * @brief blacklisting implementation
+ * @author Christian Grothoff
+ */
+#include "platform.h"
+#include "gnunet-service-transport.h"
+#include "gnunet-service-transport_blacklist.h"
+#include "gnunet-service-transport_neighbours.h"
+#include "transport.h"
+
+
+/**
+ * Size of the blacklist hash map.
+ */
+#define TRANSPORT_BLACKLIST_HT_SIZE 64
+
+
+/**
+ * Context we use when performing a blacklist check.
+ */
+struct BlacklistCheck;
+
+
+/**
+ * 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;
+
+ /**
+ * Client responsible for this entry.
+ */
+ struct GNUNET_SERVER_Client *client;
+
+ /**
+ * Blacklist check that we're currently performing.
+ */
+ struct BlacklistCheck *bc;
+
+};
+
+
+
+/**
+ * Context we use when performing a blacklist check.
+ */
+struct BlacklistCheck
+{
+
+ /**
+ * This is a linked list.
+ */
+ struct BlacklistCheck *next;
+
+ /**
+ * This is a linked list.
+ */
+ struct BlacklistCheck *prev;
+
+ /**
+ * Peer being checked.
+ */
+ struct GNUNET_PeerIdentity peer;
+
+ /**
+ * Continuation to call with the result.
+ */
+ GST_BlacklistTestContinuation cont;
+
+ /**
+ * Closure for cont.
+ */
+ void *cont_cls;
+
+ /**
+ * Current transmission request handle for this client, or NULL if no
+ * request is pending.
+ */
+ struct GNUNET_CONNECTION_TransmitHandle *th;
+
+ /**
+ * Our current position in the blacklisters list.
+ */
+ struct Blacklisters *bl_pos;
+
+ /**
+ * Current task performing the check.
+ */
+ GNUNET_SCHEDULER_TaskIdentifier task;
+
+};
+
+
+/**
+ * Head of DLL of active blacklisting queries.
+ */
+static struct BlacklistCheck *bc_head;
+
+/**
+ * Tail of DLL of active blacklisting queries.
+ */
+static struct BlacklistCheck *bc_tail;
+
+/**
+ * Head of DLL of blacklisting clients.
+ */
+static struct Blacklisters *bl_head;
+
+/**
+ * Tail of DLL of blacklisting clients.
+ */
+static struct Blacklisters *bl_tail;
+
+/**
+ * Hashmap of blacklisted peers. Values are of type 'char *' (transport names),
+ * can be NULL if we have no static blacklist.
+ */
+static struct GNUNET_CONTAINER_MultiHashMap *blacklist;
+
+
+/**
+ * Perform next action in the blacklist check.
+ *
+ * @param cls the 'struct BlacklistCheck*'
+ * @param tc unused
+ */
+static void
+do_blacklist_check (void *cls,
+ const struct GNUNET_SCHEDULER_TaskContext *tc);
+
+
+/**
+ * Called whenever a client is disconnected. Frees our
+ * resources associated with that client.
+ *
+ * @param cls closure (unused)
+ * @param client identification of the client
+ */
+static void
+client_disconnect_notification (void *cls,
+ struct GNUNET_SERVER_Client *client)
+{
+ struct Blacklisters *bl;
+ struct BlacklistCheck *bc;
+
+ if (client == NULL)
+ return;
+ for (bl = bl_head; bl != NULL; bl = bl->next)
+ {
+ if (bl->client != client)
+ continue;
+ for (bc = bc_head; bc != NULL; bc = bc->next)
+ {
+ if (bc->bl_pos != bl)
+ continue;
+ bc->bl_pos = bl->next;
+ if (bc->th != NULL)
+ {
+ GNUNET_CONNECTION_notify_transmit_ready_cancel (bc->th);
+ bc->th = NULL;
+ }
+ if (bc->task == GNUNET_SCHEDULER_NO_TASK)
+ bc->task = GNUNET_SCHEDULER_add_now (&do_blacklist_check,
+ bc);
+ break;
+ }
+ GNUNET_CONTAINER_DLL_remove (bl_head,
+ bl_tail,
+ bl);
+ GNUNET_SERVER_client_drop (bl->client);
+ GNUNET_free (bl);
+ break;
+ }
+}
+
+
+/**
+ * Read the blacklist file, containing transport:peer entries.
+ * Provided the transport is loaded, set up hashmap with these
+ * entries to blacklist peers by transport.
+ *
+ */
+static void
+read_blacklist_file ()
+{
+ char *fn;
+ char *data;
+ size_t pos;
+ size_t colon_pos;
+ int tsize;
+ struct GNUNET_PeerIdentity pid;
+ struct stat frstat;
+ struct GNUNET_CRYPTO_HashAsciiEncoded enc;
+ unsigned int entries_found;
+ char *transport_name;
+
+ if (GNUNET_OK !=
+ GNUNET_CONFIGURATION_get_value_filename (GST_cfg,
+ "TRANSPORT",
+ "BLACKLIST_FILE",
+ &fn))
+ {
+#if DEBUG_TRANSPORT
+ GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
+ "Option `%s' in section `%s' not specified!\n",
+ "BLACKLIST_FILE",
+ "TRANSPORT");
+#endif
+ return;
+ }
+ if (GNUNET_OK != GNUNET_DISK_file_test (fn))
+ GNUNET_DISK_fn_write (fn, NULL, 0,
+ GNUNET_DISK_PERM_USER_READ | GNUNET_DISK_PERM_USER_WRITE);
+ if (0 != STAT (fn, &frstat))
+ {
+ GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
+ _("Could not read blacklist file `%s'\n"),
+ fn);
+ GNUNET_free (fn);
+ return;
+ }
+ if (frstat.st_size == 0)
+ {
+#if DEBUG_TRANSPORT
+ GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
+ _("Blacklist file `%s' is empty.\n"),
+ fn);
+#endif
+ GNUNET_free (fn);
+ return;
+ }
+ /* FIXME: use mmap */
+ data = GNUNET_malloc_large (frstat.st_size);
+ GNUNET_assert(data != NULL);
+ if (frstat.st_size !=
+ GNUNET_DISK_fn_read (fn, data, frstat.st_size))
+ {
+ GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
+ _("Failed to read blacklist from `%s'\n"),
+ fn);
+ GNUNET_free (fn);
+ GNUNET_free (data);
+ return;
+ }
+ entries_found = 0;
+ pos = 0;
+ while ((pos < frstat.st_size) && isspace ( (unsigned char) data[pos]))
+ pos++;
+ while ((frstat.st_size >= sizeof (struct GNUNET_CRYPTO_HashAsciiEncoded)) &&
+ (pos <= frstat.st_size - sizeof (struct GNUNET_CRYPTO_HashAsciiEncoded)))
+ {
+ colon_pos = pos;
+ while ( (colon_pos < frstat.st_size) &&
+ (data[colon_pos] != ':') &&
+ (! isspace ( (unsigned char) data[colon_pos])) )
+ colon_pos++;
+ if (colon_pos >= frstat.st_size)
+ {
+ GNUNET_log (GNUNET_ERROR_TYPE_WARNING,
+ _("Syntax error in blacklist file at offset %llu, giving up!\n"),
+ (unsigned long long) colon_pos);
+ GNUNET_free (fn);
+ GNUNET_free (data);
+ return;
+ }
+
+ if (isspace( (unsigned char) data[colon_pos]))
+ {
+ GNUNET_log (GNUNET_ERROR_TYPE_WARNING,
+ _("Syntax error in blacklist file at offset %llu, skipping bytes.\n"),
+ (unsigned long long) colon_pos);
+ pos = colon_pos;
+ while ((pos < frstat.st_size) && isspace ( (unsigned char) data[pos]))
+ pos++;
+ continue;
+ }
+ tsize = colon_pos - pos;
+ if ((pos >= frstat.st_size) || (pos + tsize >= frstat.st_size) || (tsize == 0))
+ {
+ GNUNET_log (GNUNET_ERROR_TYPE_WARNING,
+ _("Syntax error in blacklist file at offset %llu, giving up!\n"),
+ (unsigned long long) colon_pos);
+ GNUNET_free (fn);
+ GNUNET_free (data);
+ return;
+ }
+
+ if (tsize < 1)
+ continue;
+
+ transport_name = GNUNET_malloc(tsize + 1);
+ memcpy(transport_name, &data[pos], tsize);
+ pos = colon_pos + 1;
+#if DEBUG_TRANSPORT
+ GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
+ "Read transport name `%s' in blacklist file.\n",
+ transport_name);
+#endif
+ memcpy (&enc,
+ &data[pos],
+ sizeof (struct GNUNET_CRYPTO_HashAsciiEncoded));
+ if (! isspace ( (unsigned char) enc.encoding[sizeof (struct GNUNET_CRYPTO_HashAsciiEncoded) - 1]))
+ {
+ GNUNET_log (GNUNET_ERROR_TYPE_WARNING,
+ _("Syntax error in blacklist file at offset %llu, skipping bytes.\n"),
+ (unsigned long long) pos);
+ pos++;
+ while ((pos < frstat.st_size) && (!isspace ( (unsigned char) data[pos])))
+ pos++;
+ GNUNET_free_non_null(transport_name);
+ continue;
+ }
+ enc.encoding[sizeof (struct GNUNET_CRYPTO_HashAsciiEncoded) - 1] = '\0';
+ if (GNUNET_OK != GNUNET_CRYPTO_hash_from_string ((char *) &enc, &pid.hashPubKey))
+ {
+ GNUNET_log (GNUNET_ERROR_TYPE_WARNING,
+ _("Syntax error in blacklist file at offset %llu, skipping bytes `%s'.\n"),
+ (unsigned long long) pos,
+ &enc);
+ }
+ else
+ {
+ if (0 != memcmp (&pid,
+ &GST_my_identity,
+ sizeof (struct GNUNET_PeerIdentity)))
+ {
+ entries_found++;
+ GST_blacklist_add_peer (&pid,
+ transport_name);
+ }
+ else
+ {
+ GNUNET_log (GNUNET_ERROR_TYPE_WARNING,
+ _("Found myself `%s' in blacklist (useless, ignored)\n"),
+ GNUNET_i2s (&pid));
+ }
+ }
+ pos = pos + sizeof (struct GNUNET_CRYPTO_HashAsciiEncoded);
+ GNUNET_free_non_null(transport_name);
+ while ((pos < frstat.st_size) && isspace ( (unsigned char) data[pos]))
+ pos++;
+ }
+ GNUNET_STATISTICS_update (GST_stats,
+ "# Transport entries blacklisted",
+ entries_found,
+ GNUNET_NO);
+ GNUNET_free (data);
+ GNUNET_free (fn);
+}
+
+
+/**
+ * Start blacklist subsystem.
+ *
+ * @param server server used to accept clients from
+ */
+void
+GST_blacklist_start (struct GNUNET_SERVER_Handle *server)
+{
+ read_blacklist_file ();
+ GNUNET_SERVER_disconnect_notify (server,
+ &client_disconnect_notification,
+ NULL);
+}
+
+
+/**
+ * Free the given entry in the blacklist.
+ *
+ * @param cls unused
+ * @param key host identity (unused)
+ * @param value the blacklist entry
+ * @return GNUNET_OK (continue to iterate)
+ */
+static int
+free_blacklist_entry (void *cls,
+ const GNUNET_HashCode *key,
+ void *value)
+{
+ char *be = value;
+
+ GNUNET_free (be);
+ return GNUNET_OK;
+}
+
+
+/**
+ * Stop blacklist subsystem.
+ */
+void
+GST_blacklist_stop ()
+{
+ if (NULL != blacklist)
+ {
+ GNUNET_CONTAINER_multihashmap_iterate (blacklist,
+ &free_blacklist_entry,
+ NULL);
+ GNUNET_CONTAINER_multihashmap_destroy (blacklist);
+ blacklist = NULL;
+ }
+}
+
+
+/**
+ * Transmit blacklist query to the client.
+ *
+ * @param cls the 'struct BlacklistCheck'
+ * @param size number of bytes allowed
+ * @param buf where to copy the message
+ * @return number of bytes copied to buf
+ */
+static size_t
+transmit_blacklist_message (void *cls,
+ size_t size,
+ void *buf)
+{
+ struct BlacklistCheck *bc = cls;
+ struct Blacklisters *bl;
+ struct BlacklistMessage bm;
+
+ bc->th = NULL;
+ if (size == 0)
+ {
+ GNUNET_assert (bc->task == GNUNET_SCHEDULER_NO_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));
+ return 0;
+ }
+#if DEBUG_TRANSPORT
+ GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
+ "Sending blacklist test for peer `%s' to client\n",
+ GNUNET_i2s (&bc->peer));
+#endif
+ 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));
+ GNUNET_SERVER_receive_done (bl->client, GNUNET_OK);
+ return sizeof (bm);
+}
+
+
+/**
+ * Perform next action in the blacklist check.
+ *
+ * @param cls the 'struct BlacklistCheck*'
+ * @param tc unused
+ */
+static void
+do_blacklist_check (void *cls,
+ const struct GNUNET_SCHEDULER_TaskContext *tc)
+{
+ struct BlacklistCheck *bc = cls;
+ struct Blacklisters *bl;
+
+ bc->task = GNUNET_SCHEDULER_NO_TASK;
+ bl = bc->bl_pos;
+ if (bl == NULL)
+ {
+#if DEBUG_TRANSPORT
+ GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
+ "No other blacklist clients active, will allow neighbour `%s'\n",
+ GNUNET_i2s (&bc->peer));
+#endif
+ bc->cont (bc->cont_cls,
+ &bc->peer,
+ GNUNET_OK);
+ GNUNET_free (bc);
+ return;
+ }
+ if (bl->bc != NULL)
+ 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);
+}
+
+
+/**
+ * Got the result about an existing connection from a new blacklister.
+ * Shutdown the neighbour if necessary.
+ *
+ * @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
+ */
+static void
+confirm_or_drop_neighbour (void *cls,
+ const struct GNUNET_PeerIdentity *peer,
+ int allowed)
+{
+ if (GNUNET_OK == allowed)
+ return; /* we're done */
+ GNUNET_STATISTICS_update (GST_stats,
+ gettext_noop ("# disconnects due to blacklist"),
+ 1,
+ GNUNET_NO);
+ GST_neighbours_force_disconnect (peer);
+}
+
+
+/**
+ * Closure for 'test_connection_ok'.
+ */
+struct TestConnectionContext
+{
+ /**
+ * Is this the first neighbour we're checking?
+ */
+ int first;
+
+ /**
+ * Handle to the blacklisting client we need to ask.
+ */
+ struct Blacklisters *bl;
+};
+
+
+/**
+ * Test if an existing connection is still acceptable given a new
+ * blacklisting client.
+ *
+ * @param cls the 'struct TestConnectionContest'
+ * @param pid neighbour's identity
+ */
+static void
+test_connection_ok (void *cls,
+ const struct GNUNET_PeerIdentity *neighbour)
+{
+ struct TestConnectionContext *tcc = cls;
+ struct BlacklistCheck *bc;
+
+ bc = GNUNET_malloc (sizeof (struct BlacklistCheck));
+ GNUNET_CONTAINER_DLL_insert (bc_head, bc_tail, bc);
+ bc->peer = *neighbour;
+ bc->cont = &confirm_or_drop_neighbour;
+ bc->cont_cls = NULL;
+ bc->bl_pos = tcc->bl;
+ if (GNUNET_YES == tcc->first)
+ {
+ /* all would wait for the same client, no need to
+ create more than just the first task right now */
+ bc->task = GNUNET_SCHEDULER_add_now (&do_blacklist_check,
+ bc);
+ tcc->first = GNUNET_NO;
+ }
+}
+
+
+
+/**
+ * Initialize a blacklisting client. We got a blacklist-init
+ * message from this client, add him to the list of clients
+ * to query for blacklisting.
+ *
+ * @param cls unused
+ * @param client the client
+ * @param message the blacklist-init message that was sent
+ */
+void
+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)
+ {
+ if (bl->client == client)
+ {
+ GNUNET_break (0);
+ GNUNET_SERVER_receive_done (client, GNUNET_SYSERR);
+ return;
+ }
+ bl = bl->next;
+ }
+ bl = GNUNET_malloc (sizeof (struct Blacklisters));
+ bl->client = client;
+ GNUNET_SERVER_client_keep (client);
+ GNUNET_CONTAINER_DLL_insert_after (bl_head, bl_tail, bl_tail, bl);
+
+ /* confirm that all existing connections are OK! */
+ tcc.bl = bl;
+ tcc.first = GNUNET_YES;
+ GST_neighbours_iterate (&test_connection_ok,
+ &tcc);
+}
+
+
+/**
+ * A blacklisting client has sent us reply. Process it.
+ *
+ * @param cls unused
+ * @param client the client
+ * @param message the blacklist-init message that was sent
+ */
+void
+GST_blacklist_handle_reply (void *cls,
+ struct GNUNET_SERVER_Client *client,
+ const struct GNUNET_MessageHeader *message)
+{
+ const struct BlacklistMessage *msg = (const struct BlacklistMessage*) message;
+ struct Blacklisters *bl;
+ struct BlacklistCheck *bc;
+
+ bl = bl_head;
+ while ( (bl != NULL) &&
+ (bl->client != client) )
+ bl = bl->next;
+ if (bl == NULL)
+ {
+#if DEBUG_TRANSPORT
+ GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
+ "Blacklist client disconnected\n");
+#endif
+ /* FIXME: other error handling here!? */
+ GNUNET_SERVER_receive_done (client, GNUNET_SYSERR);
+ return;
+ }
+ bc = bl->bc;
+ bl->bc = NULL;
+ if (ntohl (msg->is_allowed) == GNUNET_SYSERR)
+ {
+#if DEBUG_TRANSPORT
+ GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
+ "Blacklist check failed, peer not allowed\n");
+#endif
+ bc->cont (bc->cont_cls, &bc->peer, GNUNET_NO);
+ GNUNET_CONTAINER_DLL_remove (bc_head, bc_tail, bc);
+ GNUNET_free (bc);
+ }
+ else
+ {
+#if DEBUG_TRANSPORT
+ GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
+ "Blacklist check succeeded, continuing with checks\n");
+#endif
+ bc->bl_pos = bc->bl_pos->next;
+ bc->task = GNUNET_SCHEDULER_add_now (&do_blacklist_check,
+ bc);
+ }
+ /* check if any other bc's are waiting for this blacklister */
+ bc = bc_head;
+ while (bc != NULL)
+ {
+ if ( (bc->bl_pos == bl) &&
+ (GNUNET_SCHEDULER_NO_TASK == bc->task) )
+ bc->task = GNUNET_SCHEDULER_add_now (&do_blacklist_check,
+ bc);
+ bc = bc->next;
+ }
+}
+
+
+/**
+ * Add the given peer to the blacklist (for the given transport).
+ *
+ * @param peer peer to blacklist
+ * @param transport_name transport to blacklist for this peer, NULL for all
+ */
+void
+GST_blacklist_add_peer (const struct GNUNET_PeerIdentity *peer,
+ const char *transport_name)
+{
+#if DEBUG_TRANSPORT
+ GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
+ "Adding peer `%s' with plugin `%s' to blacklist\n",
+ GNUNET_i2s (peer),
+ transport_name);
+#endif
+ if (blacklist == NULL)
+ blacklist = GNUNET_CONTAINER_multihashmap_create(TRANSPORT_BLACKLIST_HT_SIZE);
+ GNUNET_CONTAINER_multihashmap_put (blacklist,
+ &peer->hashPubKey,
+ GNUNET_strdup (transport_name),
+ GNUNET_CONTAINER_MULTIHASHMAPOPTION_MULTIPLE);
+}
+
+
+/**
+ * Test if the given blacklist entry matches. If so,
+ * abort the iteration.
+ *
+ * @param cls the transport name to match (const char*)
+ * @param key the key (unused)
+ * @param value the 'char *' (name of a blacklisted transport)
+ * @return GNUNET_OK if the entry does not match, GNUNET_NO if it matches
+ */
+static int
+test_blacklisted (void *cls,
+ const GNUNET_HashCode *key,
+ void *value)
+{
+ const char *transport_name = cls;
+ char *be = value;
+
+ if (0 == strcmp (transport_name,
+ be))
+ return GNUNET_NO; /* abort iteration! */
+ return GNUNET_OK;
+}
+
+
+/**
+ * Test if a peer/transport combination is blacklisted.
+ *
+ * @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'
+ */
+void
+GST_blacklist_test_allowed (const struct GNUNET_PeerIdentity *peer,
+ const char *transport_name,
+ GST_BlacklistTestContinuation cont,
+ void *cont_cls)
+{
+ struct BlacklistCheck *bc;
+
+ if ( (blacklist != NULL) &&
+ (GNUNET_SYSERR ==
+ GNUNET_CONTAINER_multihashmap_get_multiple (blacklist,
+ &peer->hashPubKey,
+ &test_blacklisted,
+ (void*) transport_name)) )
+ {
+ /* disallowed by config, disapprove instantly */
+ GNUNET_STATISTICS_update (GST_stats,
+ gettext_noop ("# disconnects due to blacklist"),
+ 1,
+ GNUNET_NO);
+ if (cont != NULL)
+ cont (cont_cls, peer, GNUNET_NO);
+ return;
+ }
+
+ if (bl_head == NULL)
+ {
+ /* no blacklist clients, approve instantly */
+ if (cont != NULL)
+ cont (cont_cls, peer, GNUNET_OK);
+ return;
+ }
+
+ /* need to query blacklist clients */
+ bc = GNUNET_malloc (sizeof (struct BlacklistCheck));
+ GNUNET_CONTAINER_DLL_insert (bc_head, bc_tail, bc);
+ bc->peer = *peer;
+ bc->cont = cont;
+ bc->cont_cls = cont_cls;
+ bc->bl_pos = bl_head;
+ bc->task = GNUNET_SCHEDULER_add_now (&do_blacklist_check,
+ bc);
+}
+
+
+
+/* end of file gnunet-service-transport_blacklist.c */
--- /dev/null
+/*
+ This file is part of GNUnet.
+ (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
+ by the Free Software Foundation; either version 3, or (at your
+ option) any later version.
+
+ GNUnet is distributed in the hope that it will be useful, but
+ WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ General Public License for more details.
+
+ 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.
+*/
+
+/**
+ * @file transport/gnunet-service-transport_neighbours.c
+ * @brief neighbour management
+ * @author Christian Grothoff
+ */
+#include "platform.h"
+#include "gnunet-service-transport_neighbours.h"
+#include "gnunet-service-transport.h"
+
+// TODO:
+// - have a way to access the currently 'connected' session
+// (for sending and to notice disconnect of it!)
+// - have a way to access/update bandwidth/quota information per peer
+// (for CostReport/TrafficReport callbacks)
+
+
+
+/**
+ * Initialize the neighbours subsystem.
+ *
+ * @param cls closure for callbacks
+ * @param connect_cb function to call if we connect to a peer
+ * @param disconnect_cb function to call if we disconnect from a peer
+ */
+void
+GST_neighbours_start (void *cls,
+ GNUNET_TRANSPORT_NotifyConnect connect_cb,
+ GNUNET_TRANSPORT_NotifyDisconnect disconnect_cb)
+{
+}
+
+
+/**
+ * Cleanup the neighbours subsystem.
+ */
+void
+GST_neighbours_stop ()
+{
+}
+
+
+/**
+ * Try to create a connection to the given target (eventually).
+ *
+ * @param target peer to try to connect to
+ */
+void
+GST_neighbours_try_connect (const struct GNUNET_PeerIdentity *target)
+{
+}
+
+
+/**
+ * Test if we're connected to the given peer.
+ *
+ * @param target peer to test
+ * @return GNUNET_YES if we are connected, GNUNET_NO if not
+ */
+int
+GST_neighbours_test_connected (const struct GNUNET_PeerIdentity *target)
+{
+ return GNUNET_NO;
+}
+
+
+/**
+ * If we have an active connection to the given target, it must be shutdown.
+ *
+ * @param target peer to disconnect from
+ */
+void
+GST_neighbours_force_disconnect (const struct GNUNET_PeerIdentity *target)
+{
+}
+
+
+/**
+ * Iterate over all connected neighbours.
+ *
+ * @param cb function to call
+ * @param cb_cls closure for cb
+ */
+void
+GST_neighbours_iterate (GST_NeighbourIterator cb,
+ void *cb_cls)
+{
+}
+
+
+/**
+ * We have received a PONG. Update lifeness of the neighbour.
+ *
+ * @param sender peer sending the PONG
+ * @param hdr the PONG message (presumably)
+ * @param plugin_name name of transport that delivered the PONG
+ * @param sender_address address of the other peer, NULL if other peer
+ * connected to us
+ * @param sender_address_len number of bytes in sender_address
+ * @return GNUNET_OK if the message was well-formed, GNUNET_SYSERR if not
+ */
+int
+GST_neighbours_handle_pong (const struct GNUNET_PeerIdentity *sender,
+ const struct GNUNET_MessageHeader *hdr,
+ const char *plugin_name,
+ const void *sender_address,
+ size_t sender_address_len)
+{
+ return GNUNET_SYSERR;
+}
+
+
+/**
+ * We have received a CONNECT. Set the peer to connected.
+ *
+ * @param sender peer sending the PONG
+ * @param hdr the PONG message (presumably)
+ * @param plugin_name name of transport that delivered the PONG
+ * @param sender_address address of the other peer, NULL if other peer
+ * connected to us
+ * @param sender_address_len number of bytes in sender_address
+ * @return GNUNET_OK if the message was well-formed, GNUNET_SYSERR if not
+ */
+int
+GST_neighbours_handle_connect (const struct GNUNET_PeerIdentity *sender,
+ const struct GNUNET_MessageHeader *hdr,
+ const char *plugin_name,
+ const void *sender_address,
+ size_t sender_address_len)
+{
+ return GNUNET_SYSERR;
+}
+
+
+/**
+ * We have received a DISCONNECT. Set the peer to disconnected.
+ *
+ * @param sender peer sending the PONG
+ * @param hdr the PONG message (presumably)
+ * @param plugin_name name of transport that delivered the PONG
+ * @param sender_address address of the other peer, NULL if other peer
+ * connected to us
+ * @param sender_address_len number of bytes in sender_address
+ * @return GNUNET_OK if the message was well-formed, GNUNET_SYSERR if not
+ */
+int
+GST_neighbours_handle_disconnect (const struct GNUNET_PeerIdentity *sender,
+ const struct GNUNET_MessageHeader *hdr,
+ const char *plugin_name,
+ const void *sender_address,
+ size_t sender_address_len)
+{
+ return GNUNET_SYSERR;
+}
+
+
+/* end of file gnunet-service-transport_neighbours.c */
/**
* @file transport/gnunet-service-transport_neighbours.h
- * @brief plugin management API
+ * @brief neighbour management API
* @author Christian Grothoff
*/
#ifndef GNUNET_SERVICE_TRANSPORT_NEIGHBOURS_H
#include "gnunet_transport_service.h"
#include "gnunet_util_lib.h"
+// TODO:
+// - have a way to access the currently 'connected' session
+// (for sending and to notice disconnect of it!)
+// - have a way to access/update bandwidth/quota information per peer
+// (for CostReport/TrafficReport callbacks)
+
+
/**
+ * Initialize the neighbours subsystem.
*
+ * @param cls closure for callbacks
+ * @param connect_cb function to call if we connect to a peer
+ * @param disconnect_cb function to call if we disconnect from a peer
*/
void
GST_neighbours_start (void *cls,
GNUNET_TRANSPORT_NotifyConnect connect_cb,
GNUNET_TRANSPORT_NotifyDisconnect disconnect_cb);
+
/**
- *
+ * Cleanup the neighbours subsystem.
*/
void
GST_neighbours_stop (void);
+
/**
+ * Try to create a connection to the given target (eventually).
*
+ * @param target peer to try to connect to
*/
void
GST_neighbours_try_connect (const struct GNUNET_PeerIdentity *target);
+
/**
- *
+ * Test if we're connected to the given peer.
+ *
+ * @param target peer to test
+ * @return GNUNET_YES if we are connected, GNUNET_NO if not
*/
int
GST_neighbours_test_connected (const struct GNUNET_PeerIdentity *target);
+
/**
+ * If we have an active connection to the given target, it must be shutdown.
*
+ * @param target peer to disconnect from
*/
void
GST_neighbours_force_disconnect (const struct GNUNET_PeerIdentity *target);
+/**
+ * Function called for each connected neighbour.
+ *
+ * @param cls closure
+ * @param neighbour identity of the neighbour
+ */
typedef void (*GST_NeighbourIterator)(void *cls,
const struct GNUNET_PeerIdentity *neighbour);
+/**
+ * Iterate over all connected neighbours.
+ *
+ * @param cb function to call
+ * @param cb_cls closure for cb
+ */
void
GST_neighbours_iterate (GST_NeighbourIterator cb,
void *cb_cls);
/**
+ * We have received a PONG. Update lifeness of the neighbour.
*
+ * @param sender peer sending the PONG
+ * @param hdr the PONG message (presumably)
+ * @param plugin_name name of transport that delivered the PONG
+ * @param sender_address address of the other peer, NULL if other peer
+ * connected to us
+ * @param sender_address_len number of bytes in sender_address
+ * @return GNUNET_OK if the message was well-formed, GNUNET_SYSERR if not
*/
int
GST_neighbours_handle_pong (const struct GNUNET_PeerIdentity *sender,
const void *sender_address,
size_t sender_address_len);
+
/**
+ * We have received a CONNECT. Set the peer to connected.
*
+ * @param sender peer sending the PONG
+ * @param hdr the PONG message (presumably)
+ * @param plugin_name name of transport that delivered the PONG
+ * @param sender_address address of the other peer, NULL if other peer
+ * connected to us
+ * @param sender_address_len number of bytes in sender_address
+ * @return GNUNET_OK if the message was well-formed, GNUNET_SYSERR if not
*/
int
GST_neighbours_handle_connect (const struct GNUNET_PeerIdentity *sender,
const void *sender_address,
size_t sender_address_len);
+
/**
+ * We have received a DISCONNECT. Set the peer to disconnected.
*
+ * @param sender peer sending the PONG
+ * @param hdr the PONG message (presumably)
+ * @param plugin_name name of transport that delivered the PONG
+ * @param sender_address address of the other peer, NULL if other peer
+ * connected to us
+ * @param sender_address_len number of bytes in sender_address
+ * @return GNUNET_OK if the message was well-formed, GNUNET_SYSERR if not
*/
int
GST_neighbours_handle_disconnect (const struct GNUNET_PeerIdentity *sender,
size_t sender_address_len);
-
-
#endif
/* end of file gnunet-service-transport_neighbours.h */