/*
This file is part of GNUnet.
- (C) 2009 Christian Grothoff (and other contributing authors)
+ (C) 2009, 2010 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 2, or (at your
+ 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
* @brief low-level P2P messaging
* @author Christian Grothoff
*
- * NOTE:
- * - This code uses 'GNUNET_a2s' for debug printing in many places,
- * which is technically wrong since it assumes we have IP+Port
- * (v4/v6) addresses. Once we add transports like http or smtp
- * this will have to be changed!
*/
#include "platform.h"
#include "gnunet_client_lib.h"
#include "gnunet_protocols.h"
#include "gnunet_service_lib.h"
#include "gnunet_signatures.h"
-#include "plugin_transport.h"
+#include "gnunet_transport_plugin.h"
#include "transport.h"
+#define DEBUG_BLACKLIST GNUNET_YES
+
+#define DEBUG_PING_PONG GNUNET_YES
+
+#define DEBUG_TRANSPORT_HELLO GNUNET_YES
+
/**
* Should we do some additional checks (to validate behavior
* of clients)?
* How many messages can we have pending for a given client process
* before we start to drop incoming messages? We typically should
* have only one client and so this would be the primary buffer for
- * messages, so the number should be chosen rather generously.
+ * messages, so the number should be chosen rather generously.
*
* The expectation here is that most of the time the queue is large
- * enough so that a drop is virtually never required.
+ * enough so that a drop is virtually never required. Note that
+ * this value must be about as large as 'TOTAL_MSGS' in the
+ * 'test_transport_api_reliability.c', otherwise that testcase may
+ * fail.
+ */
+#define MAX_PENDING (128 * 1024)
+
+/**
+ * Size of the per-transport blacklist hash maps.
*/
-#define MAX_PENDING 128
+#define TRANSPORT_BLACKLIST_HT_SIZE 16
/**
* How often should we try to reconnect to a peer using a particular
#define MAX_CONNECT_RETRY 3
/**
- * Limit on the number of ready-to-run tasks when validating
- * HELLOs. If more tasks are ready to run, we will drop
+ * Limit on the number of ready-to-run tasks when validating
+ * HELLOs. If more tasks are ready to run, we will drop
* HELLOs instead of validating them.
*/
#define MAX_HELLO_LOAD 4
* Besides, if a single request to an address takes a long time,
* then the peer is unlikely worthwhile anyway.
*/
-#define HELLO_VERIFICATION_TIMEOUT GNUNET_TIME_relative_multiply (GNUNET_TIME_UNIT_SECONDS, 30)
+#define HELLO_VERIFICATION_TIMEOUT GNUNET_TIME_relative_multiply (GNUNET_TIME_UNIT_SECONDS, 15)
+
+/**
+ * How long is a PONG signature valid? We'll recycle a signature until
+ * 1/4 of this time is remaining. PONGs should expire so that if our
+ * external addresses change an adversary cannot replay them indefinitely.
+ * OTOH, we don't want to spend too much time generating PONG signatures,
+ * so they must have some lifetime to reduce our CPU usage.
+ */
+#define PONG_SIGNATURE_LIFETIME GNUNET_TIME_relative_multiply (GNUNET_TIME_UNIT_HOURS, 1)
/**
* Priority to use for PONG messages.
GNUNET_SCHEDULER_TaskIdentifier revalidate_task;
/**
- * Length of addr.
+ * The address.
*/
- size_t addrlen;
+ const void *addr;
/**
- * The address.
+ * Session (or NULL if no valid session currently exists or if the
+ * plugin does not use sessions).
*/
- const void *addr;
+ struct Session *session;
/**
* What was the last latency observed for this address, plugin and peer?
unsigned int connect_attempts;
/**
- * DV distance to this peer (1 if no DV is used).
+ * DV distance to this peer (1 if no DV is used).
* FIXME: need to set this from transport plugins!
*/
uint32_t distance;
+ /**
+ * Length of addr.
+ */
+ uint16_t addrlen;
+
/**
* Have we ever estimated the latency of this address? Used to
* ensure that the first time we add an address, we immediately
* successfully transmit or receive data to a peer via a particular
* address, we set this to GNUNET_YES. If we later get an error
* (disconnect notification, transmission failure, timeout), we set
- * it back to GNUNET_NO.
+ * it back to GNUNET_NO.
*/
int8_t connected;
/**
- * Entry in linked list of network addresses for ourselves.
+ * Entry in linked list of network addresses for ourselves. Also
+ * includes a cached signature for 'struct TransportPongMessage's.
*/
struct OwnAddressList
{
struct OwnAddressList *next;
/**
- * The address, actually a pointer to the end
- * of this struct. Do not free!
- */
- const void *addr;
-
- /**
- * How long until we auto-expire this address (unless it is
+ * How long until we actually auto-expire this address (unless it is
* re-confirmed by the transport)?
*/
struct GNUNET_TIME_Absolute expires;
+ /**
+ * How long until the current signature expires? (ZERO if the
+ * signature was never created).
+ */
+ struct GNUNET_TIME_Absolute pong_sig_expires;
+
+ /**
+ * Signature for a 'struct TransportPongMessage' for this address.
+ */
+ struct GNUNET_CRYPTO_RsaSignature pong_signature;
+
/**
* Length of addr.
*/
- size_t addrlen;
+ uint32_t addrlen;
};
*/
int rebuild;
+ /**
+ * Hashmap of blacklisted peers for this particular transport.
+ */
+ struct GNUNET_CONTAINER_MultiHashMap *blacklist;
};
struct NeighbourList;
*/
struct MessageQueue *messages_tail;
+ /**
+ * Buffer for at most one payload message used when we receive
+ * payload data before our PING-PONG has succeeded. We then
+ * store such messages in this intermediary buffer until the
+ * connection is fully up.
+ */
+ struct GNUNET_MessageHeader *pre_connect_message_buffer;
+
/**
* Context for peerinfo iteration.
* NULL after we are done processing peerinfo's information.
unsigned int quota_violation_count;
/**
- * DV distance to this peer (1 if no DV is used).
+ * DV distance to this peer (1 if no DV is used).
*/
uint32_t distance;
*/
int public_key_valid;
+ /**
+ * Performance data for the peer.
+ */
+ struct GNUNET_TRANSPORT_ATS_Information *ats;
+
+ /**
+ * Identity of the neighbour.
+ */
+ struct GNUNET_PeerIdentity peer;
+
};
/**
* Message used to ask a peer to validate receipt (to check an address
- * from a HELLO).
+ * from a HELLO). Followed by the address we are trying to validate,
+ * or an empty address if we are just sending a PING to confirm that a
+ * connection which the receiver (of the PING) initiated is still valid.
*/
struct TransportPingMessage
{
struct GNUNET_MessageHeader header;
/**
- * Random challenge number (in network byte order).
+ * Challenge code (to ensure fresh reply).
*/
uint32_t challenge GNUNET_PACKED;
/**
* Message used to validate a HELLO. The challenge is included in the
* confirmation to make matching of replies to requests possible. The
- * signature signs the original challenge number, our public key, the
- * sender's address (so that the sender can check that the address we
- * saw is plausible for him and possibly detect a MiM attack) and a
- * timestamp (to limit replay).<p>
+ * signature signs our public key, an expiration time and our address.<p>
*
- * This message is followed by the address of the
- * client that we are observing (which is part of what
- * is being signed).
+ * This message is followed by our transport address that the PING tried
+ * to confirm (if we liked it). The address can be empty (zero bytes)
+ * if the PING had not address either (and we received the request via
+ * a connection that we initiated).
*/
struct TransportPongMessage
{
struct GNUNET_MessageHeader header;
/**
- * For padding, always zero.
+ * Challenge code from PING (showing freshness). Not part of what
+ * is signed so that we can re-use signatures.
*/
- uint32_t reserved GNUNET_PACKED;
+ uint32_t challenge GNUNET_PACKED;
/**
* Signature.
struct GNUNET_CRYPTO_RsaSignature signature;
/**
- * What are we signing and why?
+ * What are we signing and why? Two possible reason codes can be here:
+ * GNUNET_SIGNATURE_PURPOSE_TRANSPORT_PONG_OWN to confirm that this is a
+ * plausible address for this peer (pid is set to identity of signer); or
+ * GNUNET_SIGNATURE_PURPOSE_TRANSPORT_PONG_USING to confirm that this is
+ * an address we used to connect to the peer with the given pid.
*/
struct GNUNET_CRYPTO_RsaSignaturePurpose purpose;
/**
- * Random challenge number (in network byte order).
+ * When does this signature expire?
*/
- uint32_t challenge GNUNET_PACKED;
+ struct GNUNET_TIME_AbsoluteNBO expiration;
/**
- * Who signed this message?
+ * Either the identity of the peer Who signed this message, or the
+ * identity of the peer that we're connected to using the given
+ * address (depending on purpose.type).
*/
- struct GNUNET_CRYPTO_RsaPublicKeyBinaryEncoded signer;
+ struct GNUNET_PeerIdentity pid;
/**
- * Size of address appended to this message
+ * Size of address appended to this message (part of what is
+ * being signed, hence not redundant).
*/
- size_t addrlen;
+ uint32_t addrlen;
};
/**
* Current transmit request handle.
- */
+ */
struct GNUNET_CONNECTION_TransmitHandle *th;
/**
};
+/**
+ * Context of currently active requests to peerinfo
+ * for validation of HELLOs.
+ */
+struct CheckHelloValidatedContext;
+
+
/**
* Entry in map of all HELLOs awaiting validation.
*/
struct ValidationEntry
{
+ /**
+ * NULL if this entry is not part of a larger HELLO validation.
+ */
+ struct CheckHelloValidatedContext *chvc;
+
/**
* The address, actually a pointer to the end
* of this struct. Do not free!
struct GNUNET_TIME_Absolute send_time;
/**
- * Length of addr.
+ * Session being validated (or NULL for none).
*/
- size_t addrlen;
+ struct Session *session;
/**
* Challenge number we used.
*/
uint32_t challenge;
+ /**
+ * Length of addr.
+ */
+ uint16_t addrlen;
+
};
* NULL after we are done processing peerinfo's information.
*/
struct GNUNET_PEERINFO_IteratorContext *piter;
-
+
/**
* Was a HELLO known for this peer to peerinfo?
*/
int hello_known;
+ /**
+ * Number of validation entries currently referring to this
+ * CHVC.
+ */
+ unsigned int ve_count;
};
+
/**
* Our HELLO message.
*/
static struct GNUNET_HELLO_Message *our_hello;
-/**
- * "version" of "our_hello". Used to see if a given neighbour has
- * already been sent the latest version of our HELLO message.
- */
-static unsigned int our_hello_version;
-
/**
* Our public key.
*/
*/
static struct GNUNET_CRYPTO_RsaPrivateKey *my_private_key;
-/**
- * Our scheduler.
- */
-struct GNUNET_SCHEDULER_Handle *sched;
-
/**
* Our configuration.
*/
static struct TransportPlugin *plugins;
/**
- * Our server.
+ * Handle to peerinfo service.
*/
-static struct GNUNET_SERVER_Handle *server;
+static struct GNUNET_PEERINFO_Handle *peerinfo;
/**
* All known neighbours and their HELLOs.
*/
static struct GNUNET_STATISTICS_Handle *stats;
-
/**
* The peer specified by the given neighbour has timed-out or a plugin
* has disconnected. We may either need to do nothing (other plugins
/**
* Find an entry in the neighbour list for a particular peer.
- *
+ *
* @return NULL if not found.
*/
static struct NeighbourList *
return head;
}
+/**
+ * Is a particular peer blacklisted for a particular transport?
+ *
+ * @param peer the peer to check for
+ * @param plugin the plugin used to connect to the peer
+ *
+ * @return GNUNET_YES if the peer is blacklisted, GNUNET_NO if not
+ */
+static int
+is_blacklisted (const struct GNUNET_PeerIdentity *peer, struct TransportPlugin *plugin)
+{
+
+ if (plugin->blacklist != NULL)
+ {
+ if (GNUNET_CONTAINER_multihashmap_contains(plugin->blacklist, &peer->hashPubKey) == GNUNET_YES)
+ {
+#if DEBUG_BLACKLIST
+ GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
+ _("Peer `%s:%s' is blacklisted!\n"),
+ plugin->short_name, GNUNET_i2s (peer));
+#endif
+ return GNUNET_YES;
+ }
+ }
+
+ return GNUNET_NO;
+}
+
+
+static void
+add_peer_to_blacklist (struct GNUNET_PeerIdentity *peer, char *transport_name)
+{
+ struct TransportPlugin *plugin;
+
+ plugin = find_transport(transport_name);
+ if (plugin == NULL) /* Nothing to do */
+ return;
+ if (plugin->blacklist == NULL)
+ plugin->blacklist = GNUNET_CONTAINER_multihashmap_create(TRANSPORT_BLACKLIST_HT_SIZE);
+ GNUNET_assert(plugin->blacklist != NULL);
+ GNUNET_CONTAINER_multihashmap_put(plugin->blacklist, &peer->hashPubKey,
+ NULL,
+ GNUNET_CONTAINER_MULTIHASHMAPOPTION_REPLACE);
+}
+
+
+/**
+ * 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 (const struct GNUNET_CONFIGURATION_Handle *cfg)
+{
+ 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 (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,
+ &my_identity,
+ sizeof (struct GNUNET_PeerIdentity)))
+ {
+ entries_found++;
+ add_peer_to_blacklist (&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_free (data);
+ GNUNET_free (fn);
+}
+
/**
* Function called to notify a client about the socket being ready to
GNUNET_STATISTICS_update (stats,
gettext_noop ("# bytes discarded (could not transmit to client)"),
ntohs (((const struct GNUNET_MessageHeader*)&q[1])->size),
- GNUNET_NO);
+ GNUNET_NO);
GNUNET_CONTAINER_DLL_remove (client->message_queue_head,
client->message_queue_tail,
q);
}
+/**
+ * Convert an address to a string.
+ *
+ * @param plugin name of the plugin responsible for the address
+ * @param addr binary address
+ * @param addr_len number of bytes in addr
+ * @return NULL on error, otherwise address string
+ */
+static const char*
+a2s (const char *plugin,
+ const void *addr,
+ uint16_t addr_len)
+{
+ struct TransportPlugin *p;
+
+ if (plugin == NULL)
+ return NULL;
+ p = find_transport (plugin);
+ if (p == NULL)
+ return NULL;
+ return p->api->address_to_string (p->api->cls,
+ addr,
+ addr_len);
+}
+
+
+/**
+ * Mark the given FAL entry as 'connected' (and hence preferred for
+ * sending); also mark all others for the same peer as 'not connected'
+ * (since only one can be preferred).
+ *
+ * @param fal address to set to 'connected'
+ */
+static void
+mark_address_connected (struct ForeignAddressList *fal)
+{
+ struct ForeignAddressList *pos;
+ int cnt;
+
+ GNUNET_assert (GNUNET_YES == fal->validated);
+ if (fal->connected == GNUNET_YES)
+ return; /* nothing to do */
+ cnt = GNUNET_YES;
+ pos = fal->ready_list->addresses;
+ while (pos != NULL)
+ {
+ if (GNUNET_YES == pos->connected)
+ {
+#if DEBUG_TRANSPORT
+ GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
+ "Marking address `%s' as no longer connected (due to connect on other address)\n",
+ a2s (pos->ready_list->plugin->short_name,
+ pos->addr,
+ pos->addrlen));
+#endif
+ GNUNET_break (cnt == GNUNET_YES);
+ cnt = GNUNET_NO;
+ pos->connected = GNUNET_NO;
+ GNUNET_STATISTICS_update (stats,
+ gettext_noop ("# connected addresses"),
+ -1,
+ GNUNET_NO);
+ }
+ pos = pos->next;
+ }
+ fal->connected = GNUNET_YES;
+ if (GNUNET_YES == cnt)
+ {
+ GNUNET_STATISTICS_update (stats,
+ gettext_noop ("# connected addresses"),
+ 1,
+ GNUNET_NO);
+ }
+}
+
+
/**
* Send the specified message to the specified client. Since multiple
* messages may be pending for the same client at a time, this code
{
GNUNET_log (GNUNET_ERROR_TYPE_INFO,
_
- ("Dropping message, have %u messages pending (%u is the soft limit)\n"),
- client->message_count, MAX_PENDING);
- /* TODO: call to statistics... */
+ ("Dropping message of type %u and size %u, have %u messages pending (%u is the soft limit)\n"),
+ ntohs (msg->type),
+ ntohs (msg->size),
+ client->message_count,
+ MAX_PENDING);
+ GNUNET_STATISTICS_update (stats,
+ gettext_noop ("# messages dropped due to slow client"),
+ 1,
+ GNUNET_NO);
return;
}
msize = ntohs (msg->size);
GNUNET_CONTAINER_DLL_insert_after (client->message_queue_head,
client->message_queue_tail,
client->message_queue_tail,
- q);
+ q);
client->message_count++;
if (client->th == NULL)
{
send_ok_msg.success = htonl (result);
send_ok_msg.latency = GNUNET_TIME_relative_hton (n->latency);
send_ok_msg.peer = n->id;
- transmit_to_client (client, &send_ok_msg.header, GNUNET_NO);
+ transmit_to_client (client, &send_ok_msg.header, GNUNET_NO);
}
*
* @param cls closure, identifies the entry on the
* message queue that was transmitted and the
- * client responsible for queueing the message
+ * client responsible for queuing the message
* @param target the peer receiving the message
* @param result GNUNET_OK on success, if the transmission
* failed, we should not tell the client to transmit
{
struct MessageQueue *mq = cls;
struct NeighbourList *n;
-
+
GNUNET_STATISTICS_update (stats,
gettext_noop ("# bytes pending with plugins"),
- (int64_t) mq->message_buf_size,
GNUNET_STATISTICS_update (stats,
gettext_noop ("# bytes successfully transmitted by plugins"),
mq->message_buf_size,
- GNUNET_NO);
+ GNUNET_NO);
}
else
{
GNUNET_STATISTICS_update (stats,
gettext_noop ("# bytes with transmission failure by plugins"),
mq->message_buf_size,
- GNUNET_NO);
- }
+ GNUNET_NO);
+ }
n = find_neighbour(&mq->neighbour_id);
GNUNET_assert (n != NULL);
if (mq->specific_address != NULL)
{
- if (result == GNUNET_OK)
+ if (result == GNUNET_OK)
{
mq->specific_address->timeout =
GNUNET_TIME_relative_to_absolute
(GNUNET_CONSTANTS_IDLE_CONNECTION_TIMEOUT);
- if (mq->specific_address->connected != GNUNET_YES)
- {
- GNUNET_STATISTICS_update (stats,
- gettext_noop ("# connected addresses"),
- 1,
- GNUNET_NO);
- mq->specific_address->connected = GNUNET_YES;
- }
- }
+ if (mq->specific_address->validated == GNUNET_YES)
+ mark_address_connected (mq->specific_address);
+ }
else
{
if (mq->specific_address->connected != GNUNET_NO)
{
+#if DEBUG_TRANSPORT
+ GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
+ "Marking address `%s' as no longer connected (due to transmission problem)\n",
+ a2s (mq->specific_address->ready_list->plugin->short_name,
+ mq->specific_address->addr,
+ mq->specific_address->addrlen));
+#endif
GNUNET_STATISTICS_update (stats,
gettext_noop ("# connected addresses"),
-1,
GNUNET_NO);
mq->specific_address->connected = GNUNET_NO;
}
- }
- if (! mq->internal_msg)
+ }
+ if (! mq->internal_msg)
mq->specific_address->in_transmit = GNUNET_NO;
}
if (mq->client != NULL)
addresses = head->addresses;
while (addresses != NULL)
{
- if ( (addresses->timeout.value < now.value) &&
+ if ( (addresses->timeout.abs_value < now.abs_value) &&
(addresses->connected == GNUNET_YES) )
{
#if DEBUG_TRANSPORT
while (addresses != NULL)
{
#if DEBUG_TRANSPORT > 1
- GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
- "Have address `%s' for peer `%4s' (status: %d, %d, %d, %u, %llums, %u)\n",
- GNUNET_a2s (addresses->addr,
- addresses->addrlen),
- GNUNET_i2s (&neighbour->id),
- addresses->connected,
- addresses->in_transmit,
- addresses->validated,
- addresses->connect_attempts,
- (unsigned long long) addresses->timeout.value,
- (unsigned int) addresses->distance);
+ if (addresses->addr != NULL)
+ GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
+ "Have address `%s' for peer `%4s' (status: %d, %d, %d, %u, %llums, %u)\n",
+ a2s (head->plugin->short_name,
+ addresses->addr,
+ addresses->addrlen),
+ GNUNET_i2s (&neighbour->id),
+ addresses->connected,
+ addresses->in_transmit,
+ addresses->validated,
+ addresses->connect_attempts,
+ (unsigned long long) addresses->timeout.abs_value,
+ (unsigned int) addresses->distance);
#endif
- if ( ( (best_address == NULL) ||
+ if ( ( (best_address == NULL) ||
(addresses->connected == GNUNET_YES) ||
(best_address->connected == GNUNET_NO) ) &&
(addresses->in_transmit == GNUNET_NO) &&
- ( (best_address == NULL) ||
- (addresses->latency.value < best_address->latency.value)) )
- best_address = addresses;
+ ( (best_address == NULL) ||
+ (addresses->latency.rel_value < best_address->latency.rel_value)) )
+ best_address = addresses;
/* FIXME: also give lower-latency addresses that are not
connected a chance some times... */
addresses = addresses->next;
{
#if DEBUG_TRANSPORT
GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
- "Best address found has latency of %llu ms.\n",
- best_address->latency.value);
+ "Best address found (`%s') has latency of %llu ms.\n",
+ (best_address->addrlen > 0)
+ ? a2s (best_address->ready_list->plugin->short_name,
+ best_address->addr,
+ best_address->addrlen)
+ : "<inbound>",
+ best_address->latency.rel_value);
#endif
}
else
force_address = GNUNET_YES;
if (mq->specific_address == NULL)
{
- mq->specific_address = find_ready_address(neighbour);
+ mq->specific_address = find_ready_address(neighbour);
GNUNET_STATISTICS_update (stats,
gettext_noop ("# transport selected peer address freely"),
1,
- GNUNET_NO);
+ GNUNET_NO);
force_address = GNUNET_NO;
}
if (mq->specific_address == NULL)
GNUNET_STATISTICS_update (stats,
gettext_noop ("# transport failed to selected peer address"),
1,
- GNUNET_NO);
+ GNUNET_NO);
timeout = GNUNET_TIME_absolute_get_remaining (mq->timeout);
- if (timeout.value == 0)
+ if (timeout.rel_value == 0)
{
#if DEBUG_TRANSPORT
GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
GNUNET_STATISTICS_update (stats,
gettext_noop ("# bytes discarded (no destination address available)"),
mq->message_buf_size,
- GNUNET_NO);
+ GNUNET_NO);
if (mq->client != NULL)
transmit_send_ok (mq->client, neighbour, GNUNET_NO);
GNUNET_CONTAINER_DLL_remove (neighbour->messages_head,
neighbour->messages_tail,
mq);
GNUNET_free (mq);
- return; /* nobody ready */
+ return; /* nobody ready */
}
GNUNET_STATISTICS_update (stats,
gettext_noop ("# message delivery deferred (no address)"),
1,
GNUNET_NO);
if (neighbour->retry_task != GNUNET_SCHEDULER_NO_TASK)
- GNUNET_SCHEDULER_cancel (sched,
- neighbour->retry_task);
- neighbour->retry_task = GNUNET_SCHEDULER_add_delayed (sched,
- timeout,
+ GNUNET_SCHEDULER_cancel (neighbour->retry_task);
+ neighbour->retry_task = GNUNET_SCHEDULER_add_delayed (timeout,
&retry_transmission_task,
neighbour);
#if DEBUG_TRANSPORT
"No validated destination address available to transmit message of size %u to peer `%4s', will wait %llums to find an address.\n",
mq->message_buf_size,
GNUNET_i2s (&mq->neighbour_id),
- timeout.value);
+ timeout.rel_value);
#endif
/* FIXME: might want to trigger peerinfo lookup here
(unless that's already pending...) */
- return;
+ return;
}
GNUNET_CONTAINER_DLL_remove (neighbour->messages_head,
neighbour->messages_tail,
GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
"Sending message of size %u for `%4s' to `%s' via plugin `%s'\n",
mq->message_buf_size,
- GNUNET_i2s (&neighbour->id),
- GNUNET_a2s (mq->specific_address->addr,
- mq->specific_address->addrlen),
+ GNUNET_i2s (&neighbour->id),
+ (mq->specific_address->addr != NULL)
+ ? a2s (mq->plugin->short_name,
+ mq->specific_address->addr,
+ mq->specific_address->addrlen)
+ : "<inbound>",
rl->plugin->short_name);
#endif
GNUNET_STATISTICS_update (stats,
mq->message_buf_size,
mq->priority,
GNUNET_CONSTANTS_IDLE_CONNECTION_TIMEOUT,
+ mq->specific_address->session,
mq->specific_address->addr,
mq->specific_address->addrlen,
force_address,
{
/* failure, but 'send' would not call continuation in this case,
so we need to do it here! */
- transmit_send_continuation (mq,
+ transmit_send_continuation (mq,
&mq->neighbour_id,
GNUNET_SYSERR);
}
mq = GNUNET_malloc (sizeof (struct MessageQueue) + message_buf_size);
mq->specific_address = peer_address;
mq->client = client;
+ /* FIXME: this memcpy can be up to 7% of our total runtime! */
memcpy (&mq[1], message_buf, message_buf_size);
mq->message_buf = (const char*) &mq[1];
mq->message_buf_size = message_buf_size;
mq->internal_msg = is_internal;
mq->priority = priority;
mq->timeout = GNUNET_TIME_relative_to_absolute (timeout);
- if (is_internal)
+ if (is_internal)
GNUNET_CONTAINER_DLL_insert (neighbour->messages_head,
neighbour->messages_tail,
mq);
}
ret = GNUNET_HELLO_add_address (gc->plug_pos->short_name,
gc->expiration,
- gc->addr_pos->addr,
+ &gc->addr_pos[1],
gc->addr_pos->addrlen, buf, max);
gc->addr_pos = gc->addr_pos->next;
return ret;
GNUNET_free_non_null (our_hello);
our_hello = hello;
- our_hello_version++;
- GNUNET_PEERINFO_add_peer (cfg, sched, &my_identity, our_hello);
+ GNUNET_PEERINFO_add_peer (peerinfo, our_hello);
npos = neighbours;
while (npos != NULL)
{
GNUNET_NO);
transmit_to_peer (NULL, NULL, 0,
HELLO_ADDRESS_EXPIRATION,
- (const char *) our_hello,
+ (const char *) our_hello,
GNUNET_HELLO_size(our_hello),
GNUNET_NO, npos);
npos = npos->next;
* expired
*/
static void
-update_addresses (struct TransportPlugin *plugin, int fresh)
+update_addresses (struct TransportPlugin *plugin,
+ int fresh)
{
static struct GNUNET_TIME_Absolute last_update;
struct GNUNET_TIME_Relative min_remaining;
int expired;
if (plugin->address_update_task != GNUNET_SCHEDULER_NO_TASK)
- GNUNET_SCHEDULER_cancel (plugin->env.sched, plugin->address_update_task);
+ GNUNET_SCHEDULER_cancel (plugin->address_update_task);
plugin->address_update_task = GNUNET_SCHEDULER_NO_TASK;
now = GNUNET_TIME_absolute_get ();
min_remaining = GNUNET_TIME_UNIT_FOREVER_REL;
- expired = (GNUNET_TIME_absolute_get_duration (last_update).value > (HELLO_ADDRESS_EXPIRATION.value / 4));
+ expired = (GNUNET_TIME_absolute_get_duration (last_update).rel_value > (HELLO_ADDRESS_EXPIRATION.rel_value / 4));
prev = NULL;
pos = plugin->addresses;
while (pos != NULL)
{
next = pos->next;
- if (pos->expires.value < now.value)
+ if (pos->expires.abs_value < now.abs_value)
{
expired = GNUNET_YES;
if (prev == NULL)
plugin->addresses = pos->next;
else
- prev->next = pos->next;
+ prev->next = pos->next;
GNUNET_free (pos);
}
else
{
remaining = GNUNET_TIME_absolute_get_remaining (pos->expires);
- if (remaining.value < min_remaining.value)
+ if (remaining.rel_value < min_remaining.rel_value)
min_remaining = remaining;
prev = pos;
}
GNUNET_TIME_relative_divide (HELLO_ADDRESS_EXPIRATION,
2));
plugin->address_update_task
- = GNUNET_SCHEDULER_add_delayed (plugin->env.sched,
- min_remaining,
+ = GNUNET_SCHEDULER_add_delayed (min_remaining,
&expire_address_task, plugin);
}
/**
- * Function that must be called by each plugin to notify the
- * transport service about the addresses under which the transport
- * provided by the plugin can be reached.
+ * Iterator over hash map entries that NULLs the session of validation
+ * entries that match the given session.
*
- * @param cls closure
- * @param name name of the transport that generated the address
- * @param addr one of the addresses of the host, NULL for the last address
- * the specific address format depends on the transport
- * @param addrlen length of the address
- * @param expires when should this address automatically expire?
+ * @param cls closure (the 'struct Session*' to match against)
+ * @param key current key code (peer ID, not used)
+ * @param value value in the hash map ('struct ValidationEntry*')
+ * @return GNUNET_YES (we should continue to iterate)
*/
-static void
-plugin_env_notify_address (void *cls,
- const char *name,
- const void *addr,
- size_t addrlen,
- struct GNUNET_TIME_Relative expires)
+static int
+remove_session_validations (void *cls,
+ const GNUNET_HashCode * key,
+ void *value)
{
- struct TransportPlugin *p = cls;
- struct OwnAddressList *al;
- struct GNUNET_TIME_Absolute abex;
-
- abex = GNUNET_TIME_relative_to_absolute (expires);
- GNUNET_assert (p == find_transport (name));
-
- al = p->addresses;
- while (al != NULL)
- {
- if ((addrlen == al->addrlen) && (0 == memcmp (addr, &al[1], addrlen)))
- {
- if (al->expires.value < abex.value)
- al->expires = abex;
- return;
- }
- al = al->next;
- }
+ struct Session *session = cls;
+ struct ValidationEntry *ve = value;
- al = GNUNET_malloc (sizeof (struct OwnAddressList) + addrlen);
- al->addr = &al[1];
- al->next = p->addresses;
- p->addresses = al;
- al->expires = abex;
- al->addrlen = addrlen;
- memcpy (&al[1], addr, addrlen);
- update_addresses (p, GNUNET_YES);
+ if (session == ve->session)
+ ve->session = NULL;
+ return GNUNET_YES;
}
/**
- * Notify all of our clients about a peer connecting.
- */
+ * We've been disconnected from the other peer (for some
+ * connection-oriented transport). Either quickly
+ * re-establish the connection or signal the disconnect
+ * to the CORE.
+ *
+ * Only signal CORE level disconnect if ALL addresses
+ * for the peer are exhausted.
+ *
+ * @param p overall plugin context
+ * @param nl neighbour that was disconnected
+ */
+static void
+try_fast_reconnect (struct TransportPlugin *p,
+ struct NeighbourList *nl)
+{
+ /* FIXME-MW: fast reconnect / transport switching not implemented... */
+ /* Note: the idea here is to hide problems with transports (or
+ switching between plugins) from the core to eliminate the need to
+ re-negotiate session keys and the like; OTOH, we should tell core
+ quickly (much faster than timeout) `if a connection was lost and
+ could not be re-established (i.e. other peer went down or is
+ unable / refuses to communicate);
+
+ So we should consider:
+ 1) ideally: our own willingness / need to connect
+ 2) prior failures to connect to this peer (by plugin)
+ 3) ideally: reasons why other peer terminated (as far as knowable)
+
+ Most importantly, it must be POSSIBLE for another peer to terminate
+ a connection for a while (without us instantly re-establishing it).
+ Similarly, if another peer is gone we should quickly notify CORE.
+ OTOH, if there was a minor glitch (i.e. crash of gnunet-service-transport
+ on the other end), we should reconnect in such a way that BOTH CORE
+ services never even notice.
+ Furthermore, the same mechanism (or small variation) could be used
+ to switch to a better-performing plugin (ATS).
+
+ Finally, this needs to be tested throughly... */
+
+ /*
+ * GNUNET_NO in the call below makes transport disconnect the peer,
+ * even if only a single address (out of say, six) went away. This
+ * function must be careful to ONLY disconnect if the peer is gone,
+ * not just a specifi address.
+ *
+ * More specifically, half the places it was used had it WRONG.
+ */
+
+ /* No reconnect, signal disconnect instead! */
+ GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
+ "Disconnecting peer `%4s', %s\n", GNUNET_i2s(&nl->id),
+ "try_fast_reconnect");
+ disconnect_neighbour (nl, GNUNET_YES);
+}
+
+
+/**
+ * Function that will be called whenever the plugin internally
+ * cleans up a session pointer and hence the service needs to
+ * discard all of those sessions as well. Plugins that do not
+ * use sessions can simply omit calling this function and always
+ * use NULL wherever a session pointer is needed.
+ *
+ * @param cls closure
+ * @param peer which peer was the session for
+ * @param session which session is being destoyed
+ */
+static void
+plugin_env_session_end (void *cls,
+ const struct GNUNET_PeerIdentity *peer,
+ struct Session *session)
+{
+ struct TransportPlugin *p = cls;
+ struct NeighbourList *nl;
+ struct ReadyList *rl;
+ struct ForeignAddressList *pos;
+ struct ForeignAddressList *prev;
+
+ GNUNET_CONTAINER_multihashmap_iterate (validation_map,
+ &remove_session_validations,
+ session);
+ nl = find_neighbour (peer);
+ if (nl == NULL)
+ return; /* was never marked as connected */
+ rl = nl->plugins;
+ while (rl != NULL)
+ {
+ if (rl->plugin == p)
+ break;
+ rl = rl->next;
+ }
+ if (rl == NULL)
+ return; /* was never marked as connected */
+ prev = NULL;
+ pos = rl->addresses;
+ while ( (pos != NULL) &&
+ (pos->session != session) )
+ {
+ prev = pos;
+ pos = pos->next;
+ }
+ if (pos == NULL)
+ return; /* was never marked as connected */
+ pos->session = NULL;
+ if (pos->addrlen != 0)
+ {
+ if (nl->received_pong != GNUNET_NO)
+ try_fast_reconnect (p, nl);
+ return;
+ }
+ /* was inbound connection, free 'pos' */
+ if (prev == NULL)
+ rl->addresses = pos->next;
+ else
+ prev->next = pos->next;
+ if (GNUNET_SCHEDULER_NO_TASK != pos->revalidate_task)
+ {
+ GNUNET_SCHEDULER_cancel (pos->revalidate_task);
+ pos->revalidate_task = GNUNET_SCHEDULER_NO_TASK;
+ }
+ GNUNET_free (pos);
+ if (nl->received_pong == GNUNET_NO)
+ return; /* nothing to do, never connected... */
+ /* check if we have any validated addresses left */
+ pos = rl->addresses;
+ while (pos != NULL)
+ {
+ if (pos->validated)
+ {
+ try_fast_reconnect (p, nl);
+ return;
+ }
+ pos = pos->next;
+ }
+ /* no valid addresses left, signal disconnect! */
+
+ GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
+ "Disconnecting peer `%4s', %s\n", GNUNET_i2s(&nl->id),
+ "plugin_env_session_end");
+ /* FIXME: This doesn't mean there are no addresses left for this PEER,
+ * it means there aren't any left for this PLUGIN/PEER combination! So
+ * calling disconnect_neighbor here with GNUNET_NO forces disconnect
+ * when it isn't necessary. Using GNUNET_YES at least checks to see
+ * if there are any addresses that work first, so as not to overdo it.
+ * --NE
+ */
+ disconnect_neighbour (nl, GNUNET_YES);
+}
+
+
+/**
+ * Function that must be called by each plugin to notify the
+ * transport service about the addresses under which the transport
+ * provided by the plugin can be reached.
+ *
+ * @param cls closure
+ * @param name name of the transport that generated the address
+ * @param addr one of the addresses of the host, NULL for the last address
+ * the specific address format depends on the transport
+ * @param addrlen length of the address
+ * @param expires when should this address automatically expire?
+ */
+static void
+plugin_env_notify_address (void *cls,
+ const char *name,
+ const void *addr,
+ uint16_t addrlen,
+ struct GNUNET_TIME_Relative expires)
+{
+ struct TransportPlugin *p = cls;
+ struct OwnAddressList *al;
+ struct GNUNET_TIME_Absolute abex;
+
+ GNUNET_assert (addr != NULL);
+ abex = GNUNET_TIME_relative_to_absolute (expires);
+ GNUNET_assert (p == find_transport (name));
+ al = p->addresses;
+ while (al != NULL)
+ {
+ if ((addrlen == al->addrlen) && (0 == memcmp (addr, &al[1], addrlen)))
+ {
+ al->expires = abex;
+ update_addresses (p, GNUNET_NO);
+ return;
+ }
+ al = al->next;
+ }
+
+ al = GNUNET_malloc (sizeof (struct OwnAddressList) + addrlen);
+ al->next = p->addresses;
+ p->addresses = al;
+ al->expires = abex;
+ al->addrlen = addrlen;
+ memcpy (&al[1], addr, addrlen);
+ update_addresses (p, GNUNET_YES);
+}
+
+
+/**
+ * Notify all of our clients about a peer connecting.
+ */
static void
notify_clients_connect (const struct GNUNET_PeerIdentity *peer,
struct GNUNET_TIME_Relative latency,
- uint32_t distance)
+ uint32_t distance)
{
- struct ConnectInfoMessage cim;
+ struct ConnectInfoMessage * cim;
struct TransportClient *cpos;
+ uint32_t ats_count;
+ size_t size;
#if DEBUG_TRANSPORT
GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
gettext_noop ("# peers connected"),
1,
GNUNET_NO);
- cim.header.size = htons (sizeof (struct ConnectInfoMessage));
- cim.header.type = htons (GNUNET_MESSAGE_TYPE_TRANSPORT_CONNECT);
- cim.distance = htonl (distance);
- cim.latency = GNUNET_TIME_relative_hton (latency);
- memcpy (&cim.id, peer, sizeof (struct GNUNET_PeerIdentity));
+
+ ats_count = 2;
+ size = sizeof (struct ConnectInfoMessage) + ats_count * sizeof (struct GNUNET_TRANSPORT_ATS_Information);
+ if (size > GNUNET_SERVER_MAX_MESSAGE_SIZE)
+ {
+ GNUNET_break(0);
+ }
+ cim = GNUNET_malloc (size);
+
+ cim->header.size = htons (size);
+ cim->header.type = htons (GNUNET_MESSAGE_TYPE_TRANSPORT_CONNECT);
+ cim->ats_count = htonl(2);
+ (&(cim->ats))[0].type = htonl (GNUNET_TRANSPORT_ATS_QUALITY_NET_DISTANCE);
+ (&(cim->ats))[0].value = htonl (distance);
+ (&(cim->ats))[1].type = htonl (GNUNET_TRANSPORT_ATS_QUALITY_NET_DELAY);
+ (&(cim->ats))[1].value = htonl ((uint32_t) latency.rel_value);
+ (&(cim->ats))[2].type = htonl (GNUNET_TRANSPORT_ATS_ARRAY_TERMINATOR);
+ (&(cim->ats))[2].value = htonl (0);
+ memcpy (&cim->id, peer, sizeof (struct GNUNET_PeerIdentity));
cpos = clients;
while (cpos != NULL)
{
- transmit_to_client (cpos, &cim.header, GNUNET_NO);
+ transmit_to_client (cpos, &(cim->header), GNUNET_NO);
cpos = cpos->next;
}
+ GNUNET_free (cim);
}
*
* @param neighbour which peer we care about
* @param tname name of the transport plugin
+ * @param session session to look for, NULL for 'any'; otherwise
+ * can be used for the service to "learn" this session ID
+ * if 'addr' matches
* @param addr binary address
* @param addrlen length of addr
* @return NULL if no such entry exists
static struct ForeignAddressList *
find_peer_address(struct NeighbourList *neighbour,
const char *tname,
+ struct Session *session,
const char *addr,
- size_t addrlen)
+ uint16_t addrlen)
{
struct ReadyList *head;
- struct ForeignAddressList *address_head;
+ struct ForeignAddressList *pos;
head = neighbour->plugins;
while (head != NULL)
}
if (head == NULL)
return NULL;
-
- address_head = head->addresses;
- while ( (address_head != NULL) &&
- ( (address_head->addrlen != addrlen) ||
- (memcmp(address_head->addr, addr, addrlen) != 0) ) )
- address_head = address_head->next;
- return address_head;
+ pos = head->addresses;
+ while ( (pos != NULL) &&
+ ( (pos->addrlen != addrlen) ||
+ (memcmp(pos->addr, addr, addrlen) != 0) ) )
+ {
+ if ( (session != NULL) &&
+ (pos->session == session) )
+ return pos;
+ pos = pos->next;
+ }
+ if ( (session != NULL) && (pos != NULL) )
+ pos->session = session; /* learn it! */
+ return pos;
}
*
* @param neighbour which peer we care about
* @param tname name of the transport plugin
+ * @param session session of the plugin, or NULL for none
* @param addr binary address
* @param addrlen length of addr
* @return NULL if we do not have a transport plugin for 'tname'
static struct ForeignAddressList *
add_peer_address (struct NeighbourList *neighbour,
const char *tname,
- const char *addr,
- size_t addrlen)
+ struct Session *session,
+ const char *addr,
+ uint16_t addrlen)
{
struct ReadyList *head;
struct ForeignAddressList *ret;
- ret = find_peer_address (neighbour, tname, addr, addrlen);
+ ret = find_peer_address (neighbour, tname, session, addr, addrlen);
if (ret != NULL)
return ret;
head = neighbour->plugins;
+
while (head != NULL)
{
if (0 == strcmp (tname, head->plugin->short_name))
if (head == NULL)
return NULL;
ret = GNUNET_malloc(sizeof(struct ForeignAddressList) + addrlen);
- ret->addr = (const char*) &ret[1];
- memcpy (&ret[1], addr, addrlen);
+ ret->session = session;
+ if (addrlen > 0)
+ {
+ ret->addr = (const char*) &ret[1];
+ memcpy (&ret[1], addr, addrlen);
+ }
+ else
+ {
+ ret->addr = NULL;
+ }
ret->addrlen = addrlen;
ret->expires = GNUNET_TIME_relative_to_absolute
(GNUNET_CONSTANTS_IDLE_CONNECTION_TIMEOUT);
ret->latency = GNUNET_TIME_relative_get_forever();
ret->distance = -1;
ret->timeout = GNUNET_TIME_relative_to_absolute
- (GNUNET_CONSTANTS_IDLE_CONNECTION_TIMEOUT);
+ (GNUNET_CONSTANTS_IDLE_CONNECTION_TIMEOUT);
ret->ready_list = head;
ret->next = head->addresses;
head->addresses = ret;
const char *tname;
/**
- * Length of addr.
+ * Session, or NULL.
*/
- size_t addrlen;
+ struct Session *session;
/**
* Set to GNUNET_YES if the address exists.
*/
int exists;
+
+ /**
+ * Length of addr.
+ */
+ uint16_t addrlen;
+
};
{
struct CheckAddressExistsClosure *caec = cls;
struct ValidationEntry *ve = value;
+
if ( (0 == strcmp (caec->tname,
ve->transport_name)) &&
(caec->addrlen == ve->addrlen) &&
caec->exists = GNUNET_YES;
return GNUNET_NO;
}
+ if ( (ve->session != NULL) &&
+ (caec->session == ve->session) )
+ {
+ caec->exists = GNUNET_YES;
+ return GNUNET_NO;
+ }
+ return GNUNET_YES;
+}
+
+
+
+/**
+ * Iterator to free entries in the validation_map.
+ *
+ * @param cls closure (unused)
+ * @param key current key code
+ * @param value value in the hash map (validation to abort)
+ * @return GNUNET_YES (always)
+ */
+static int
+abort_validation (void *cls,
+ const GNUNET_HashCode * key,
+ void *value)
+{
+ struct ValidationEntry *va = value;
+
+ if (GNUNET_SCHEDULER_NO_TASK != va->timeout_task)
+ GNUNET_SCHEDULER_cancel (va->timeout_task);
+ GNUNET_free (va->transport_name);
+ if (va->chvc != NULL)
+ {
+ va->chvc->ve_count--;
+ if (va->chvc->ve_count == 0)
+ {
+ GNUNET_CONTAINER_DLL_remove (chvc_head,
+ chvc_tail,
+ va->chvc);
+ GNUNET_free (va->chvc);
+ }
+ va->chvc = NULL;
+ }
+ GNUNET_free (va);
return GNUNET_YES;
}
struct ValidationEntry *va = cls;
struct GNUNET_PeerIdentity pid;
+ va->timeout_task = GNUNET_SCHEDULER_NO_TASK;
GNUNET_STATISTICS_update (stats,
gettext_noop ("# address validation timeouts"),
1,
sizeof (struct
GNUNET_CRYPTO_RsaPublicKeyBinaryEncoded),
&pid.hashPubKey);
- GNUNET_CONTAINER_multihashmap_remove (validation_map,
- &pid.hashPubKey,
- va);
- GNUNET_free (va->transport_name);
- GNUNET_free (va);
+ GNUNET_break (GNUNET_OK ==
+ GNUNET_CONTAINER_multihashmap_remove (validation_map,
+ &pid.hashPubKey,
+ va));
+ abort_validation (NULL, NULL, va);
}
add_to_foreign_address_list (void *cls,
const char *tname,
struct GNUNET_TIME_Absolute expiration,
- const void *addr, size_t addrlen)
+ const void *addr,
+ uint16_t addrlen)
{
struct NeighbourList *n = cls;
struct ForeignAddressList *fal;
int try;
GNUNET_STATISTICS_update (stats,
- gettext_noop ("# valid peer addresses returned by peerinfo"),
+ gettext_noop ("# valid peer addresses returned by PEERINFO"),
1,
- GNUNET_NO);
+ GNUNET_NO);
try = GNUNET_NO;
- fal = find_peer_address (n, tname, addr, addrlen);
+ fal = find_peer_address (n, tname, NULL, addr, addrlen);
if (fal == NULL)
{
-#if DEBUG_TRANSPORT
+#if DEBUG_TRANSPORT_HELLO
GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
- "Adding address `%s' (%s) for peer `%4s' due to peerinfo data for %llums.\n",
- GNUNET_a2s (addr, addrlen),
+ "Adding address `%s' (%s) for peer `%4s' due to PEERINFO data for %llums.\n",
+ a2s (tname, addr, addrlen),
tname,
GNUNET_i2s (&n->id),
- expiration.value);
+ expiration.abs_value);
#endif
- fal = add_peer_address (n, tname, addr, addrlen);
+ fal = add_peer_address (n, tname, NULL, addr, addrlen);
if (fal == NULL)
{
GNUNET_STATISTICS_update (stats,
gettext_noop ("# previously validated addresses lacking transport"),
1,
- GNUNET_NO);
+ GNUNET_NO);
}
else
{
}
if (fal == NULL)
{
- GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
+ GNUNET_log (GNUNET_ERROR_TYPE_WARNING,
"Failed to add new address for `%4s'\n",
GNUNET_i2s (&n->id));
return GNUNET_OK;
}
if (fal->validated == GNUNET_NO)
{
- fal->validated = GNUNET_YES;
+ fal->validated = GNUNET_YES;
GNUNET_STATISTICS_update (stats,
gettext_noop ("# peer addresses considered valid"),
1,
- GNUNET_NO);
+ GNUNET_NO);
}
if (try == GNUNET_YES)
{
* @param cls closure ('struct NeighbourList*')
* @param peer id of the peer, NULL for last call
* @param h hello message for the peer (can be NULL)
- * @param trust amount of trust we have in the peer (not used)
*/
static void
add_hello_for_peer (void *cls,
const struct GNUNET_PeerIdentity *peer,
- const struct GNUNET_HELLO_Message *h,
- uint32_t trust)
+ const struct GNUNET_HELLO_Message *h)
{
struct NeighbourList *n = cls;
if (peer == NULL)
{
+ GNUNET_STATISTICS_update (stats,
+ gettext_noop ("# outstanding peerinfo iterate requests"),
+ -1,
+ GNUNET_NO);
n->piter = NULL;
return;
- }
+ }
if (h == NULL)
return; /* no HELLO available */
#if DEBUG_TRANSPORT
/**
* Create a fresh entry in our neighbour list for the given peer.
* Will try to transmit our current HELLO to the new neighbour.
+ * Do not call this function directly, use 'setup_peer_check_blacklist.
*
* @param peer the peer for which we create the entry
+ * @param do_hello should we schedule transmitting a HELLO
* @return the new neighbour list entry
*/
static struct NeighbourList *
-setup_new_neighbour (const struct GNUNET_PeerIdentity *peer)
+setup_new_neighbour (const struct GNUNET_PeerIdentity *peer,
+ int do_hello)
{
struct NeighbourList *n;
struct TransportPlugin *tp;
struct ReadyList *rl;
+#if DEBUG_TRANSPORT
+ GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
+ "Setting up state for neighbour `%4s'\n",
+ GNUNET_i2s (peer));
+#endif
GNUNET_assert (our_hello != NULL);
GNUNET_STATISTICS_update (stats,
gettext_noop ("# active neighbours"),
tp = plugins;
while (tp != NULL)
{
- if (tp->api->send != NULL)
+ if ((tp->api->send != NULL) && (!is_blacklisted(peer, tp)))
{
rl = GNUNET_malloc (sizeof (struct ReadyList));
rl->neighbour = n;
}
tp = tp->next;
}
- n->latency = GNUNET_TIME_UNIT_FOREVER_REL;
- n->distance = -1;
- n->timeout_task = GNUNET_SCHEDULER_add_delayed (sched,
- GNUNET_CONSTANTS_IDLE_CONNECTION_TIMEOUT,
- &neighbour_timeout_task, n);
- n->piter = GNUNET_PEERINFO_iterate (cfg, sched, peer,
- 0, GNUNET_TIME_UNIT_FOREVER_REL,
- &add_hello_for_peer, n);
- transmit_to_peer (NULL, NULL, 0,
- HELLO_ADDRESS_EXPIRATION,
- (const char *) our_hello, GNUNET_HELLO_size(our_hello),
- GNUNET_NO, n);
- return n;
+ n->latency = GNUNET_TIME_UNIT_FOREVER_REL;
+ n->distance = -1;
+ n->timeout_task = GNUNET_SCHEDULER_add_delayed (GNUNET_CONSTANTS_IDLE_CONNECTION_TIMEOUT,
+ &neighbour_timeout_task, n);
+ if (do_hello)
+ {
+ GNUNET_STATISTICS_update (stats,
+ gettext_noop ("# peerinfo new neighbor iterate requests"),
+ 1,
+ GNUNET_NO);
+ GNUNET_STATISTICS_update (stats,
+ gettext_noop ("# outstanding peerinfo iterate requests"),
+ 1,
+ GNUNET_NO);
+ n->piter = GNUNET_PEERINFO_iterate (peerinfo, peer,
+ GNUNET_TIME_UNIT_FOREVER_REL,
+ &add_hello_for_peer, n);
+
+ GNUNET_STATISTICS_update (stats,
+ gettext_noop ("# HELLO's sent to new neighbors"),
+ 1,
+ GNUNET_NO);
+ transmit_to_peer (NULL, NULL, 0,
+ HELLO_ADDRESS_EXPIRATION,
+ (const char *) our_hello, GNUNET_HELLO_size(our_hello),
+ GNUNET_NO, n);
+ }
+ return n;
+}
+
+
+/**
+ * Function called after we have checked if communicating
+ * with a given peer is acceptable.
+ *
+ * @param cls closure
+ * @param n NULL if communication is not acceptable
+ */
+typedef void (*SetupContinuation)(void *cls,
+ struct NeighbourList *n);
+
+
+/**
+ * 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;
+
+};
+
+
+/**
+ * Head of DLL of blacklisting clients.
+ */
+static struct Blacklisters *bl_head;
+
+/**
+ * Tail of DLL of blacklisting clients.
+ */
+static struct Blacklisters *bl_tail;
+
+
+/**
+ * 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;
+
+ /**
+ * Option for setup neighbour afterwards.
+ */
+ int do_hello;
+
+ /**
+ * Continuation to call with the result.
+ */
+ SetupContinuation 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;
+
+
+/**
+ * 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);
+
+
+/**
+ * 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);
+ return 0;
+ }
+ 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)
+ {
+ bc->cont (bc->cont_cls,
+ setup_new_neighbour (&bc->peer, bc->do_hello));
+ GNUNET_free (bc);
+ return;
+ }
+ if (bl->bc == NULL)
+ {
+ bl->bc = bc;
+ bc->th = GNUNET_SERVER_notify_transmit_ready (bl->client,
+ sizeof (struct BlacklistMessage),
+ GNUNET_TIME_UNIT_FOREVER_REL,
+ &transmit_blacklist_message,
+ bc);
+ }
+}
+
+
+/**
+ * Obtain a 'struct NeighbourList' for the given peer. If such an entry
+ * does not yet exist, check the blacklist. If the blacklist says creating
+ * one is acceptable, create one and call the continuation; otherwise
+ * call the continuation with NULL.
+ *
+ * @param peer peer to setup or look up a struct NeighbourList for
+ * @param do_hello should we also schedule sending our HELLO to the peer
+ * if this is a new record
+ * @param cont function to call with the 'struct NeigbhbourList*'
+ * @param cont_cls closure for cont
+ */
+static void
+setup_peer_check_blacklist (const struct GNUNET_PeerIdentity *peer,
+ int do_hello,
+ SetupContinuation cont,
+ void *cont_cls)
+{
+ struct NeighbourList *n;
+ struct BlacklistCheck *bc;
+
+ n = find_neighbour(peer);
+ if (n != NULL)
+ {
+ if (cont != NULL)
+ cont (cont_cls, n);
+ return;
+ }
+ if (bl_head == NULL)
+ {
+ if (cont != NULL)
+ cont (cont_cls, setup_new_neighbour (peer, do_hello));
+ else
+ setup_new_neighbour(peer, do_hello);
+ return;
+ }
+ bc = GNUNET_malloc (sizeof (struct BlacklistCheck));
+ GNUNET_CONTAINER_DLL_insert (bc_head, bc_tail, bc);
+ bc->peer = *peer;
+ bc->do_hello = do_hello;
+ bc->cont = cont;
+ bc->cont_cls = cont_cls;
+ bc->bl_pos = bl_head;
+ bc->task = GNUNET_SCHEDULER_add_now (&do_blacklist_check,
+ bc);
+}
+
+
+/**
+ * Function called with the result of querying a new blacklister about
+ * it being allowed (or not) to continue to talk to an existing neighbour.
+ *
+ * @param cls the original 'struct NeighbourList'
+ * @param n NULL if we need to disconnect
+ */
+static void
+confirm_or_drop_neighbour (void *cls,
+ struct NeighbourList *n)
+{
+ struct NeighbourList * orig = cls;
+
+ if (n == NULL)
+ {
+ GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
+ "Disconnecting peer `%4s', %s\n", GNUNET_i2s(&orig->id),
+ "confirm_or_drop_neighboUr");
+ disconnect_neighbour (orig, GNUNET_NO);
+ }
+}
+
+
+/**
+ * Handle a request to start a blacklist.
+ *
+ * @param cls closure (always NULL)
+ * @param client identification of the client
+ * @param message the actual message
+ */
+static void
+handle_blacklist_init (void *cls,
+ struct GNUNET_SERVER_Client *client,
+ const struct GNUNET_MessageHeader *message)
+{
+ struct Blacklisters *bl;
+ struct BlacklistCheck *bc;
+ struct NeighbourList *n;
+
+ 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! */
+ n = neighbours;
+ while (NULL != n)
+ {
+ bc = GNUNET_malloc (sizeof (struct BlacklistCheck));
+ GNUNET_CONTAINER_DLL_insert (bc_head, bc_tail, bc);
+ bc->peer = n->id;
+ bc->do_hello = GNUNET_NO;
+ bc->cont = &confirm_or_drop_neighbour;
+ bc->cont_cls = n;
+ bc->bl_pos = bl;
+ if (n == neighbours) /* 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);
+ n = n->next;
+ }
+}
+
+
+/**
+ * Handle a request to blacklist a peer.
+ *
+ * @param cls closure (always NULL)
+ * @param client identification of the client
+ * @param message the actual message
+ */
+static void
+handle_blacklist_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)
+ {
+ GNUNET_SERVER_receive_done (client, GNUNET_SYSERR);
+ return;
+ }
+ bc = bl->bc;
+ bl->bc = NULL;
+ if (ntohl (msg->is_allowed) == GNUNET_SYSERR)
+ {
+ bc->cont (bc->cont_cls, NULL);
+ GNUNET_CONTAINER_DLL_remove (bc_head, bc_tail, bc);
+ GNUNET_free (bc);
+ }
+ else
+ {
+ 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;
+ }
}
/**
- * Send periodic PING messages to a give foreign address.
+ * Send periodic PING messages to a given foreign address.
*
* @param cls our 'struct PeriodicValidationContext*'
* @param tc task context
*/
-static void
-send_periodic_ping (void *cls,
+static void
+send_periodic_ping (void *cls,
const struct GNUNET_SCHEDULER_TaskContext *tc)
{
struct ForeignAddressList *peer_address = cls;
struct CheckAddressExistsClosure caec;
char * message_buf;
uint16_t hello_size;
+ size_t slen;
size_t tsize;
peer_address->revalidate_task = GNUNET_SCHEDULER_NO_TASK;
if (tc->reason == GNUNET_SCHEDULER_REASON_SHUTDOWN)
- return;
+ return;
tp = peer_address->ready_list->plugin;
neighbour = peer_address->ready_list->neighbour;
if (GNUNET_YES != neighbour->public_key_valid)
{
/* no public key yet, try again later */
- schedule_next_ping (peer_address);
+ schedule_next_ping (peer_address);
return;
}
caec.addr = peer_address->addr;
caec.addrlen = peer_address->addrlen;
caec.tname = tp->short_name;
+ caec.session = peer_address->session;
caec.exists = GNUNET_NO;
GNUNET_CONTAINER_multihashmap_iterate (validation_map,
&check_address_exists,
#if DEBUG_TRANSPORT > 1
GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
"Some validation of address `%s' via `%s' for peer `%4s' already in progress.\n",
- GNUNET_a2s (peer_address->addr,
- peer_address->addrlen),
+ (peer_address->addr != NULL)
+ ? a2s (tp->short_name,
+ peer_address->addr,
+ peer_address->addrlen)
+ : "<inbound>",
tp->short_name,
GNUNET_i2s (&neighbour->id));
#endif
- schedule_next_ping (peer_address);
+ schedule_next_ping (peer_address);
return;
}
va = GNUNET_malloc (sizeof (struct ValidationEntry) + peer_address->addrlen);
va->transport_name = GNUNET_strdup (tp->short_name);
- va->challenge = GNUNET_CRYPTO_random_u32 (GNUNET_CRYPTO_QUALITY_WEAK,
- (unsigned int) -1);
+ va->challenge = GNUNET_CRYPTO_random_u32 (GNUNET_CRYPTO_QUALITY_NONCE,
+ UINT_MAX);
va->send_time = GNUNET_TIME_absolute_get();
- va->addr = (const void*) &va[1];
- memcpy (&va[1], peer_address->addr, peer_address->addrlen);
- va->addrlen = peer_address->addrlen;
-
+ va->session = peer_address->session;
+ if (peer_address->addr != NULL)
+ {
+ va->addr = (const void*) &va[1];
+ memcpy (&va[1], peer_address->addr, peer_address->addrlen);
+ va->addrlen = peer_address->addrlen;
+ }
memcpy(&va->publicKey,
- &neighbour->publicKey,
+ &neighbour->publicKey,
sizeof(struct GNUNET_CRYPTO_RsaPublicKeyBinaryEncoded));
- va->timeout_task = GNUNET_SCHEDULER_add_delayed (sched,
- HELLO_VERIFICATION_TIMEOUT,
+ va->timeout_task = GNUNET_SCHEDULER_add_delayed (HELLO_VERIFICATION_TIMEOUT,
&timeout_hello_validation,
va);
GNUNET_CONTAINER_multihashmap_put (validation_map,
&neighbour->id.hashPubKey,
va,
GNUNET_CONTAINER_MULTIHASHMAPOPTION_MULTIPLE);
- hello_size = GNUNET_HELLO_size(our_hello);
+
+ if (peer_address->validated != GNUNET_YES)
+ hello_size = GNUNET_HELLO_size(our_hello);
+ else
+ hello_size = 0;
+
tsize = sizeof(struct TransportPingMessage) + hello_size;
+
+ if (peer_address->addr != NULL)
+ {
+ slen = strlen (tp->short_name) + 1;
+ tsize += slen + peer_address->addrlen;
+ }
+ else
+ {
+ slen = 0; /* make gcc happy */
+ }
message_buf = GNUNET_malloc(tsize);
- ping.challenge = htonl(va->challenge);
- ping.header.size = htons(sizeof(struct TransportPingMessage));
ping.header.type = htons(GNUNET_MESSAGE_TYPE_TRANSPORT_PING);
+ ping.challenge = htonl(va->challenge);
memcpy(&ping.target, &neighbour->id, sizeof(struct GNUNET_PeerIdentity));
- memcpy(message_buf, our_hello, hello_size);
+ if (peer_address->validated != GNUNET_YES)
+ {
+ memcpy(message_buf, our_hello, hello_size);
+ }
+
+ if (peer_address->addr != NULL)
+ {
+ ping.header.size = htons(sizeof(struct TransportPingMessage) +
+ peer_address->addrlen +
+ slen);
+ memcpy(&message_buf[hello_size + sizeof (struct TransportPingMessage)],
+ tp->short_name,
+ slen);
+ memcpy(&message_buf[hello_size + sizeof (struct TransportPingMessage) + slen],
+ peer_address->addr,
+ peer_address->addrlen);
+ }
+ else
+ {
+ ping.header.size = htons(sizeof(struct TransportPingMessage));
+ }
+
memcpy(&message_buf[hello_size],
&ping,
sizeof(struct TransportPingMessage));
+
#if DEBUG_TRANSPORT_REVALIDATION
GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
- "Performing re-validation of address `%s' via `%s' for peer `%4s' sending `%s' (%u bytes) and `%s' (%u bytes)\n",
- GNUNET_a2s (peer_address->addr,
- peer_address->addrlen),
+ "Performing re-validation of address `%s' via `%s' for peer `%4s' sending `%s' (%u bytes) and `%s'\n",
+ (peer_address->addr != NULL)
+ ? a2s (peer_address->plugin->short_name,
+ peer_address->addr,
+ peer_address->addrlen)
+ : "<inbound>",
tp->short_name,
GNUNET_i2s (&neighbour->id),
"HELLO", hello_size,
- "PING", sizeof (struct TransportPingMessage));
+ "PING");
#endif
+ if (peer_address->validated != GNUNET_YES)
+ GNUNET_STATISTICS_update (stats,
+ gettext_noop ("# PING with HELLO messages sent"),
+ 1,
+ GNUNET_NO);
+ else
+ GNUNET_STATISTICS_update (stats,
+ gettext_noop ("# PING without HELLO messages sent"),
+ 1,
+ GNUNET_NO);
GNUNET_STATISTICS_update (stats,
gettext_noop ("# PING messages sent for re-validation"),
1,
if (fal->revalidate_task != GNUNET_SCHEDULER_NO_TASK)
return;
delay = GNUNET_TIME_absolute_get_remaining (fal->expires);
- delay.value /= 2; /* do before expiration */
+ delay.rel_value /= 2; /* do before expiration */
delay = GNUNET_TIME_relative_min (delay,
LATENCY_EVALUATION_MAX_DELAY);
if (GNUNET_YES != fal->estimated)
{
delay = GNUNET_TIME_UNIT_ZERO;
fal->estimated = GNUNET_YES;
- }
+ }
if (GNUNET_YES == fal->connected)
{
delay = GNUNET_TIME_relative_min (delay,
CONNECTED_LATENCY_EVALUATION_MAX_DELAY);
- }
+ }
/* FIXME: also adjust delay based on how close the last
observed latency is to the latency of the best alternative */
/* bound how fast we can go */
delay = GNUNET_TIME_relative_max (delay,
GNUNET_TIME_UNIT_SECONDS);
/* randomize a bit (to avoid doing all at the same time) */
- delay.value += GNUNET_CRYPTO_random_u32 (GNUNET_CRYPTO_QUALITY_WEAK, 1000);
- fal->revalidate_task = GNUNET_SCHEDULER_add_delayed(sched,
- delay,
- &send_periodic_ping,
+ delay.rel_value += GNUNET_CRYPTO_random_u32 (GNUNET_CRYPTO_QUALITY_WEAK, 1000);
+ fal->revalidate_task = GNUNET_SCHEDULER_add_delayed(delay,
+ &send_periodic_ping,
fal);
}
+
+
+/**
+ * Function that will be called if we receive some payload
+ * from another peer.
+ *
+ * @param message the payload
+ * @param n peer who claimed to be the sender
+ */
+static void
+handle_payload_message (const struct GNUNET_MessageHeader *message,
+ struct NeighbourList *n)
+{
+ struct InboundMessage *im;
+ struct TransportClient *cpos;
+ uint16_t msize;
+
+ msize = ntohs (message->size);
+ if (n->received_pong == GNUNET_NO)
+ {
+ GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
+ "Received message of type %u and size %u from `%4s', but no pong yet!!\n",
+ ntohs (message->type),
+ ntohs (message->size),
+ GNUNET_i2s (&n->id));
+ GNUNET_free_non_null (n->pre_connect_message_buffer);
+ n->pre_connect_message_buffer = GNUNET_malloc (msize);
+ memcpy (n->pre_connect_message_buffer, message, msize);
+ return;
+ }
+
+#if DEBUG_TRANSPORT
+ GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
+ "Received message of type %u and size %u from `%4s', sending to all clients.\n",
+ ntohs (message->type),
+ ntohs (message->size),
+ GNUNET_i2s (&n->id));
+#endif
+ if (GNUNET_YES == GNUNET_BANDWIDTH_tracker_consume (&n->in_tracker,
+ (ssize_t) msize))
+ {
+ n->quota_violation_count++;
+#if DEBUG_TRANSPORT
+ GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
+ "Bandwidth quota (%u b/s) violation detected (total of %u).\n",
+ n->in_tracker.available_bytes_per_s__,
+ n->quota_violation_count);
+#endif
+ /* Discount 32k per violation */
+ GNUNET_BANDWIDTH_tracker_consume (&n->in_tracker,
+ - 32 * 1024);
+ }
+ else
+ {
+ if (n->quota_violation_count > 0)
+ {
+ /* try to add 32k back */
+ GNUNET_BANDWIDTH_tracker_consume (&n->in_tracker,
+ 32 * 1024);
+ n->quota_violation_count--;
+ }
+ }
+ GNUNET_STATISTICS_update (stats,
+ gettext_noop ("# payload received from other peers"),
+ msize,
+ GNUNET_NO);
+ /* transmit message to all clients */
+ uint32_t ats_count = 2;
+ size_t size = sizeof (struct InboundMessage) + ats_count * sizeof (struct GNUNET_TRANSPORT_ATS_Information) + msize;
+ if (size > GNUNET_SERVER_MAX_MESSAGE_SIZE)
+ GNUNET_break(0);
+
+ im = GNUNET_malloc (size);
+ im->header.size = htons (size);
+ im->header.type = htons (GNUNET_MESSAGE_TYPE_TRANSPORT_RECV);
+ im->peer = n->id;
+ im->ats_count = htonl(ats_count);
+ /* Setting ATS data */
+ (&(im->ats))[0].type = htonl (GNUNET_TRANSPORT_ATS_QUALITY_NET_DISTANCE);
+ (&(im->ats))[0].value = htonl (n->distance);
+ (&(im->ats))[1].type = htonl (GNUNET_TRANSPORT_ATS_QUALITY_NET_DELAY);
+ (&(im->ats))[1].value = htonl ((uint32_t) n->latency.rel_value);
+ (&(im->ats))[ats_count].type = htonl (GNUNET_TRANSPORT_ATS_ARRAY_TERMINATOR);
+ (&(im->ats))[ats_count].value = htonl (0);
+
+ memcpy (&((&(im->ats))[ats_count+1]), message, msize);
+ cpos = clients;
+ while (cpos != NULL)
+ {
+ transmit_to_client (cpos, &im->header, GNUNET_YES);
+ cpos = cpos->next;
+ }
+ GNUNET_free (im);
+}
+
+
/**
* Iterator over hash map entries. Checks if the given validation
* entry is for the same challenge as what is given in the PONG.
struct GNUNET_PeerIdentity target;
struct NeighbourList *n;
struct ForeignAddressList *fal;
+ struct OwnAddressList *oal;
+ struct TransportPlugin *tp;
+ struct GNUNET_MessageHeader *prem;
+ uint16_t ps;
+ const char *addr;
+ size_t slen;
+ size_t alen;
- if (ve->challenge != challenge)
- return GNUNET_YES;
+ ps = ntohs (pong->header.size);
+ if (ps < sizeof (struct TransportPongMessage))
+ {
+ GNUNET_break_op (0);
+ return GNUNET_NO;
+ }
+ addr = (const char*) &pong[1];
+ slen = strlen (ve->transport_name) + 1;
+ if ( (ps - sizeof (struct TransportPongMessage) < slen) ||
+ (ve->challenge != challenge) ||
+ (addr[slen-1] != '\0') ||
+ (0 != strcmp (addr, ve->transport_name)) ||
+ (ntohl (pong->purpose.size)
+ != sizeof (struct GNUNET_CRYPTO_RsaSignaturePurpose) +
+ sizeof (uint32_t) +
+ sizeof (struct GNUNET_TIME_AbsoluteNBO) +
+ sizeof (struct GNUNET_PeerIdentity) + ps - sizeof (struct TransportPongMessage)) )
+ {
+ return GNUNET_YES;
+ }
+
+ alen = ps - sizeof (struct TransportPongMessage) - slen;
+ switch (ntohl (pong->purpose.purpose))
+ {
+ case GNUNET_SIGNATURE_PURPOSE_TRANSPORT_PONG_OWN:
+ if ( (ve->addrlen + slen != ntohl (pong->addrlen)) ||
+ (0 != memcmp (&addr[slen],
+ ve->addr,
+ ve->addrlen)) )
+ {
+ return GNUNET_YES; /* different entry, keep trying! */
+ }
+ if (0 != memcmp (&pong->pid,
+ key,
+ sizeof (struct GNUNET_PeerIdentity)))
+ {
+ GNUNET_break_op (0);
+ return GNUNET_NO;
+ }
+ if (GNUNET_OK !=
+ GNUNET_CRYPTO_rsa_verify (GNUNET_SIGNATURE_PURPOSE_TRANSPORT_PONG_OWN,
+ &pong->purpose,
+ &pong->signature,
+ &ve->publicKey))
+ {
+ GNUNET_break_op (0);
+ return GNUNET_NO;
+ }
#if DEBUG_TRANSPORT
- GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
- "Confirmed validity of address, peer `%4s' has address `%s' (%s).\n",
- GNUNET_h2s (key),
- GNUNET_a2s ((const struct sockaddr *) ve->addr,
- ve->addrlen),
- ve->transport_name);
+ GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
+ "Confirmed validity of address, peer `%4s' has address `%s' (%s).\n",
+ GNUNET_h2s (key),
+ a2s (ve->transport_name,
+ (const struct sockaddr *) ve->addr,
+ ve->addrlen),
+ ve->transport_name);
#endif
+ break;
+ case GNUNET_SIGNATURE_PURPOSE_TRANSPORT_PONG_USING:
+ if (0 != memcmp (&pong->pid,
+ &my_identity,
+ sizeof (struct GNUNET_PeerIdentity)))
+ {
+ GNUNET_break_op (0);
+ return GNUNET_NO;
+ }
+ if (ve->addrlen != 0)
+ {
+ /* must have been for a different validation entry */
+ return GNUNET_YES;
+ }
+ tp = find_transport (ve->transport_name);
+ if (tp == NULL)
+ {
+ GNUNET_break (0);
+ return GNUNET_YES;
+ }
+ oal = tp->addresses;
+ while (NULL != oal)
+ {
+ if ( (oal->addrlen == alen) &&
+ (0 == memcmp (&oal[1],
+ &addr[slen],
+ alen)) )
+ break;
+ oal = oal->next;
+ }
+ if (oal == NULL)
+ {
+ GNUNET_log (GNUNET_ERROR_TYPE_WARNING,
+ _("Not accepting PONG with address `%s' since I cannot confirm having this address.\n"),
+ a2s (ve->transport_name,
+ &addr[slen],
+ alen));
+ return GNUNET_NO;
+ }
+ if (GNUNET_OK !=
+ GNUNET_CRYPTO_rsa_verify (GNUNET_SIGNATURE_PURPOSE_TRANSPORT_PONG_USING,
+ &pong->purpose,
+ &pong->signature,
+ &ve->publicKey))
+ {
+ GNUNET_break_op (0);
+ return GNUNET_NO;
+ }
+
+#if DEBUG_TRANSPORT
+ GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
+ "Confirmed that peer `%4s' is talking to us using address `%s' (%s) for us.\n",
+ GNUNET_h2s (key),
+ a2s (ve->transport_name,
+ &addr[slen],
+ alen),
+ ve->transport_name);
+#endif
+ break;
+ default:
+ GNUNET_break_op (0);
+ return GNUNET_NO;
+ }
+ if (GNUNET_TIME_absolute_get_remaining (GNUNET_TIME_absolute_ntoh (pong->expiration)).rel_value == 0)
+ {
+ GNUNET_log (GNUNET_ERROR_TYPE_INFO,
+ _("Received expired signature. Check system time.\n"));
+ return GNUNET_NO;
+ }
GNUNET_STATISTICS_update (stats,
gettext_noop ("# address validation successes"),
1,
GNUNET_CRYPTO_hash (&ve->publicKey,
sizeof (struct GNUNET_CRYPTO_RsaPublicKeyBinaryEncoded),
&target.hashPubKey);
- avac.done = GNUNET_NO;
- avac.ve = ve;
- hello = GNUNET_HELLO_create (&ve->publicKey,
- &add_validated_address,
- &avac);
- GNUNET_PEERINFO_add_peer (cfg, sched,
- &target,
- hello);
- GNUNET_free (hello);
+ if (ve->addr != NULL)
+ {
+ avac.done = GNUNET_NO;
+ avac.ve = ve;
+ hello = GNUNET_HELLO_create (&ve->publicKey,
+ &add_validated_address,
+ &avac);
+ GNUNET_PEERINFO_add_peer (peerinfo,
+ hello);
+ GNUNET_free (hello);
+ }
n = find_neighbour (&target);
if (n != NULL)
{
n->public_key_valid = GNUNET_YES;
fal = add_peer_address (n,
ve->transport_name,
+ ve->session,
ve->addr,
ve->addrlen);
GNUNET_assert (fal != NULL);
fal->expires = GNUNET_TIME_relative_to_absolute (HELLO_ADDRESS_EXPIRATION);
fal->validated = GNUNET_YES;
+ mark_address_connected (fal);
GNUNET_STATISTICS_update (stats,
gettext_noop ("# peer addresses considered valid"),
1,
- GNUNET_NO);
+ GNUNET_NO);
fal->latency = GNUNET_TIME_absolute_get_duration (ve->send_time);
schedule_next_ping (fal);
- if (n->latency.value == GNUNET_TIME_UNIT_FOREVER_REL.value)
+ if (n->latency.rel_value == GNUNET_TIME_UNIT_FOREVER_REL.rel_value)
n->latency = fal->latency;
else
- n->latency.value = (fal->latency.value + n->latency.value) / 2;
+ n->latency.rel_value = (fal->latency.rel_value + n->latency.rel_value) / 2;
+
n->distance = fal->distance;
if (GNUNET_NO == n->received_pong)
{
- notify_clients_connect (&target, n->latency, n->distance);
n->received_pong = GNUNET_YES;
+ notify_clients_connect (&target, n->latency, n->distance);
+ if (NULL != (prem = n->pre_connect_message_buffer))
+ {
+ n->pre_connect_message_buffer = NULL;
+ handle_payload_message (prem, n);
+ GNUNET_free (prem);
+ }
}
if (n->retry_task != GNUNET_SCHEDULER_NO_TASK)
{
- GNUNET_SCHEDULER_cancel (sched,
- n->retry_task);
+ GNUNET_SCHEDULER_cancel (n->retry_task);
n->retry_task = GNUNET_SCHEDULER_NO_TASK;
try_transmission_to_peer (n);
}
GNUNET_CONTAINER_multihashmap_remove (validation_map,
key,
ve));
- GNUNET_SCHEDULER_cancel (sched,
- ve->timeout_task);
- GNUNET_free (ve->transport_name);
- GNUNET_free (ve);
+ abort_validation (NULL, NULL, ve);
return GNUNET_NO;
}
return;
}
-#if 0
- /* FIXME: add given address to potential pool of our addresses
- (for voting) */
- GNUNET_log (GNUNET_ERROR_TYPE_INFO | GNUNET_ERROR_TYPE_BULK,
- _("Another peer saw us using the address `%s' via `%s'.\n"),
- GNUNET_a2s ((const struct sockaddr *) &pong[1],
- ntohs(pong->addrlen)),
- va->transport_name);
+}
+
+
+/**
+ * Try to validate a neighbour's address by sending him our HELLO and a PING.
+ *
+ * @param cls the 'struct ValidationEntry*'
+ * @param neighbour neighbour to validate, NULL if validation failed
+ */
+static void
+transmit_hello_and_ping (void *cls,
+ struct NeighbourList *neighbour)
+{
+ struct ValidationEntry *va = cls;
+ struct ForeignAddressList *peer_address;
+ struct TransportPingMessage ping;
+ uint16_t hello_size;
+ size_t tsize;
+ char * message_buf;
+ struct GNUNET_PeerIdentity id;
+ size_t slen;
+
+ GNUNET_CRYPTO_hash (&va->publicKey,
+ sizeof (struct GNUNET_CRYPTO_RsaPublicKeyBinaryEncoded),
+ &id.hashPubKey);
+ if (neighbour == NULL)
+ {
+ /* FIXME: stats... */
+ GNUNET_break (GNUNET_OK ==
+ GNUNET_CONTAINER_multihashmap_remove (validation_map,
+ &id.hashPubKey,
+ va));
+ abort_validation (NULL, NULL, va);
+ return;
+ }
+ neighbour->publicKey = va->publicKey;
+ neighbour->public_key_valid = GNUNET_YES;
+ peer_address = add_peer_address (neighbour,
+ va->transport_name, NULL,
+ (const void*) &va[1],
+ va->addrlen);
+ if (peer_address == NULL)
+ {
+ GNUNET_log (GNUNET_ERROR_TYPE_WARNING,
+ "Failed to add peer `%4s' for plugin `%s'\n",
+ GNUNET_i2s (&neighbour->id),
+ va->transport_name);
+ GNUNET_break (GNUNET_OK ==
+ GNUNET_CONTAINER_multihashmap_remove (validation_map,
+ &id.hashPubKey,
+ va));
+ abort_validation (NULL, NULL, va);
+ return;
+ }
+ hello_size = GNUNET_HELLO_size(our_hello);
+ slen = strlen(va->transport_name) + 1;
+ tsize = sizeof(struct TransportPingMessage) + hello_size + va->addrlen + slen;
+ message_buf = GNUNET_malloc(tsize);
+ ping.challenge = htonl(va->challenge);
+ ping.header.size = htons(sizeof(struct TransportPingMessage) + slen + va->addrlen);
+ ping.header.type = htons(GNUNET_MESSAGE_TYPE_TRANSPORT_PING);
+ memcpy(&ping.target, &neighbour->id, sizeof(struct GNUNET_PeerIdentity));
+ memcpy(message_buf, our_hello, hello_size);
+ memcpy(&message_buf[hello_size],
+ &ping,
+ sizeof(struct TransportPingMessage));
+ memcpy(&message_buf[hello_size + sizeof (struct TransportPingMessage)],
+ va->transport_name,
+ slen);
+ memcpy(&message_buf[hello_size + sizeof (struct TransportPingMessage) + slen],
+ &va[1],
+ va->addrlen);
+#if DEBUG_TRANSPORT
+ GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
+ "Performing validation of address `%s' via `%s' for peer `%4s' sending `%s' (%u bytes) and `%s' (%u bytes)\n",
+ (va->addrlen == 0)
+ ? "<inbound>"
+ : a2s (va->transport_name,
+ (const void*) &va[1], va->addrlen),
+ va->transport_name,
+ GNUNET_i2s (&neighbour->id),
+ "HELLO", hello_size,
+ "PING", sizeof (struct TransportPingMessage) + va->addrlen + slen);
#endif
+
+ GNUNET_STATISTICS_update (stats,
+ gettext_noop ("# PING messages sent for initial validation"),
+ 1,
+ GNUNET_NO);
+ transmit_to_peer (NULL, peer_address,
+ GNUNET_SCHEDULER_PRIORITY_DEFAULT,
+ HELLO_VERIFICATION_TIMEOUT,
+ message_buf, tsize,
+ GNUNET_YES, neighbour);
+ GNUNET_free(message_buf);
}
run_validation (void *cls,
const char *tname,
struct GNUNET_TIME_Absolute expiration,
- const void *addr, size_t addrlen)
+ const void *addr,
+ uint16_t addrlen)
{
struct CheckHelloValidatedContext *chvc = cls;
struct GNUNET_PeerIdentity id;
struct TransportPlugin *tp;
struct ValidationEntry *va;
- struct NeighbourList *neighbour;
- struct ForeignAddressList *peer_address;
- struct TransportPingMessage ping;
struct GNUNET_CRYPTO_RsaPublicKeyBinaryEncoded pk;
struct CheckAddressExistsClosure caec;
- char * message_buf;
- uint16_t hello_size;
- size_t tsize;
+ struct OwnAddressList *oal;
+
+ GNUNET_assert (addr != NULL);
GNUNET_STATISTICS_update (stats,
gettext_noop ("# peer addresses scheduled for validation"),
1,
- GNUNET_NO);
+ GNUNET_NO);
tp = find_transport (tname);
if (tp == NULL)
{
("Transport `%s' not loaded, will not try to validate peer address using this transport.\n"),
tname);
GNUNET_STATISTICS_update (stats,
- gettext_noop ("# peer addresses not validated (no applicable transport plugin available)"),
+ gettext_noop ("# peer addresses not validated (plugin not available)"),
1,
- GNUNET_NO);
+ GNUNET_NO);
return GNUNET_OK;
}
+ /* check if this is one of our own addresses */
+ oal = tp->addresses;
+ while (NULL != oal)
+ {
+ if ( (oal->addrlen == addrlen) &&
+ (0 == memcmp (&oal[1],
+ addr,
+ addrlen)) )
+ {
+ /* not plausible, this address is equivalent to our own address! */
+ GNUNET_STATISTICS_update (stats,
+ gettext_noop ("# peer addresses not validated (loopback)"),
+ 1,
+ GNUNET_NO);
+ return GNUNET_OK;
+ }
+ oal = oal->next;
+ }
GNUNET_HELLO_get_key (chvc->hello, &pk);
GNUNET_CRYPTO_hash (&pk,
sizeof (struct
GNUNET_CRYPTO_RsaPublicKeyBinaryEncoded),
&id.hashPubKey);
+
+ if (is_blacklisted(&id, tp))
+ {
+#if DEBUG_TRANSPORT
+ GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
+ "Attempted to validate blacklisted peer `%s' using `%s'!\n",
+ GNUNET_i2s(&id),
+ tname);
+#endif
+ return GNUNET_OK;
+ }
+
caec.addr = addr;
caec.addrlen = addrlen;
+ caec.session = NULL;
caec.tname = tname;
caec.exists = GNUNET_NO;
GNUNET_CONTAINER_multihashmap_iterate (validation_map,
#if DEBUG_TRANSPORT > 1
GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
"Validation of address `%s' via `%s' for peer `%4s' already in progress.\n",
- GNUNET_a2s (addr, addrlen),
+ a2s (tname, addr, addrlen),
tname,
GNUNET_i2s (&id));
#endif
GNUNET_STATISTICS_update (stats,
gettext_noop ("# peer addresses not validated (in progress)"),
1,
- GNUNET_NO);
+ GNUNET_NO);
return GNUNET_OK;
}
va = GNUNET_malloc (sizeof (struct ValidationEntry) + addrlen);
+ va->chvc = chvc;
+ chvc->ve_count++;
va->transport_name = GNUNET_strdup (tname);
- va->challenge = GNUNET_CRYPTO_random_u32 (GNUNET_CRYPTO_QUALITY_WEAK,
- (unsigned int) -1);
+ va->challenge = GNUNET_CRYPTO_random_u32 (GNUNET_CRYPTO_QUALITY_NONCE,
+ UINT_MAX);
va->send_time = GNUNET_TIME_absolute_get();
va->addr = (const void*) &va[1];
memcpy (&va[1], addr, addrlen);
va->addrlen = addrlen;
GNUNET_HELLO_get_key (chvc->hello,
&va->publicKey);
- va->timeout_task = GNUNET_SCHEDULER_add_delayed (sched,
- HELLO_VERIFICATION_TIMEOUT,
+ va->timeout_task = GNUNET_SCHEDULER_add_delayed (HELLO_VERIFICATION_TIMEOUT,
&timeout_hello_validation,
va);
GNUNET_CONTAINER_multihashmap_put (validation_map,
&id.hashPubKey,
va,
GNUNET_CONTAINER_MULTIHASHMAPOPTION_MULTIPLE);
- neighbour = find_neighbour(&id);
- if (neighbour == NULL)
- neighbour = setup_new_neighbour(&id);
- neighbour->publicKey = va->publicKey;
- neighbour->public_key_valid = GNUNET_YES;
- peer_address = add_peer_address(neighbour, tname, addr, addrlen);
- GNUNET_assert(peer_address != NULL);
- hello_size = GNUNET_HELLO_size(our_hello);
- tsize = sizeof(struct TransportPingMessage) + hello_size;
- message_buf = GNUNET_malloc(tsize);
- ping.challenge = htonl(va->challenge);
- ping.header.size = htons(sizeof(struct TransportPingMessage));
- ping.header.type = htons(GNUNET_MESSAGE_TYPE_TRANSPORT_PING);
- memcpy(&ping.target, &id, sizeof(struct GNUNET_PeerIdentity));
- memcpy(message_buf, our_hello, hello_size);
- memcpy(&message_buf[hello_size],
- &ping,
- sizeof(struct TransportPingMessage));
-#if DEBUG_TRANSPORT
- GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
- "Performing validation of address `%s' via `%s' for peer `%4s' sending `%s' (%u bytes) and `%s' (%u bytes)\n",
- GNUNET_a2s (addr, addrlen),
- tname,
- GNUNET_i2s (&id),
- "HELLO", hello_size,
- "PING", sizeof (struct TransportPingMessage));
-#endif
- GNUNET_STATISTICS_update (stats,
- gettext_noop ("# PING messages sent for initial validation"),
- 1,
- GNUNET_NO);
- transmit_to_peer (NULL, peer_address,
- GNUNET_SCHEDULER_PRIORITY_DEFAULT,
- HELLO_VERIFICATION_TIMEOUT,
- message_buf, tsize,
- GNUNET_YES, neighbour);
- GNUNET_free(message_buf);
+ setup_peer_check_blacklist (&id, GNUNET_NO,
+ &transmit_hello_and_ping,
+ va);
return GNUNET_OK;
}
* @param cls closure
* @param peer id of the peer, NULL for last call
* @param h hello message for the peer (can be NULL)
- * @param trust amount of trust we have in the peer (not used)
*/
static void
check_hello_validated (void *cls,
const struct GNUNET_PeerIdentity *peer,
- const struct GNUNET_HELLO_Message *h,
- uint32_t trust)
+ const struct GNUNET_HELLO_Message *h)
{
struct CheckHelloValidatedContext *chvc = cls;
struct GNUNET_HELLO_Message *plain_hello;
if (peer == NULL)
{
+ GNUNET_STATISTICS_update (stats,
+ gettext_noop ("# outstanding peerinfo iterate requests"),
+ -1,
+ GNUNET_NO);
chvc->piter = NULL;
- GNUNET_CONTAINER_DLL_remove (chvc_head,
- chvc_tail,
- chvc);
if (GNUNET_NO == chvc->hello_known)
{
/* notify PEERINFO about the peer now, so that we at least
sizeof (struct GNUNET_CRYPTO_RsaPublicKeyBinaryEncoded),
&target.hashPubKey);
plain_hello = GNUNET_HELLO_create (&pk,
- NULL,
+ NULL,
NULL);
- GNUNET_PEERINFO_add_peer (cfg, sched, &target, plain_hello);
+ GNUNET_PEERINFO_add_peer (peerinfo, plain_hello);
GNUNET_free (plain_hello);
-#if DEBUG_TRANSPORT
+#if DEBUG_TRANSPORT_HELLO
GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
- "Peerinfo had no `%s' message for peer `%4s', full validation needed.\n",
+ "PEERINFO had no `%s' message for peer `%4s', full validation needed.\n",
"HELLO",
GNUNET_i2s (&target));
#endif
GNUNET_STATISTICS_update (stats,
gettext_noop ("# new HELLOs requiring full validation"),
1,
- GNUNET_NO);
+ GNUNET_NO);
GNUNET_HELLO_iterate_addresses (chvc->hello,
- GNUNET_NO,
- &run_validation,
+ GNUNET_NO,
+ &run_validation,
chvc);
}
else
GNUNET_STATISTICS_update (stats,
gettext_noop ("# duplicate HELLO (peer known)"),
1,
- GNUNET_NO);
+ GNUNET_NO);
+ }
+ chvc->ve_count--;
+ if (chvc->ve_count == 0)
+ {
+ GNUNET_CONTAINER_DLL_remove (chvc_head,
+ chvc_tail,
+ chvc);
+ GNUNET_free (chvc);
}
- GNUNET_free (chvc);
return;
- }
+ }
if (h == NULL)
return;
-#if DEBUG_TRANSPORT
+#if DEBUG_TRANSPORT_HELLO
GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
- "Peerinfo had `%s' message for peer `%4s', validating only new addresses.\n",
+ "PEERINFO had `%s' message for peer `%4s', validating only new addresses.\n",
"HELLO",
GNUNET_i2s (peer));
#endif
n = find_neighbour (peer);
if (n != NULL)
{
+#if DEBUG_TRANSPORT_HELLO
+ GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
+ "Calling hello_iterate_addresses for %s!\n",
+ GNUNET_i2s (peer));
+#endif
GNUNET_HELLO_iterate_addresses (h,
GNUNET_NO,
&add_to_foreign_address_list,
}
else
{
+#if DEBUG_TRANSPORT_HELLO
+ GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
+ "No existing neighbor record for %s!\n",
+ GNUNET_i2s (peer));
+#endif
GNUNET_STATISTICS_update (stats,
gettext_noop ("# no existing neighbour record (validating HELLO)"),
1,
- GNUNET_NO);
+ GNUNET_NO);
}
GNUNET_STATISTICS_update (stats,
gettext_noop ("# HELLO validations (update case)"),
1,
- GNUNET_NO);
+ GNUNET_NO);
GNUNET_HELLO_iterate_new_addresses (chvc->hello,
h,
GNUNET_TIME_relative_to_absolute (HELLO_REVALIDATION_START_TIME),
- &run_validation,
+ &run_validation,
chvc);
}
+
/**
* Process HELLO-message.
*
const struct GNUNET_HELLO_Message *hello;
struct CheckHelloValidatedContext *chvc;
struct GNUNET_CRYPTO_RsaPublicKeyBinaryEncoded publicKey;
-
+#if DEBUG_TRANSPORT_HELLO > 2
+ char *my_id;
+#endif
hsize = ntohs (message->size);
if ((ntohs (message->type) != GNUNET_MESSAGE_TYPE_HELLO) ||
(hsize < sizeof (struct GNUNET_MessageHeader)))
GNUNET_STATISTICS_update (stats,
gettext_noop ("# HELLOs received for validation"),
1,
- GNUNET_NO);
+ GNUNET_NO);
+
/* first, check if load is too high */
- if (GNUNET_SCHEDULER_get_load (sched,
- GNUNET_SCHEDULER_PRIORITY_BACKGROUND) > MAX_HELLO_LOAD)
+ if (GNUNET_SCHEDULER_get_load (GNUNET_SCHEDULER_PRIORITY_BACKGROUND) > MAX_HELLO_LOAD)
{
GNUNET_STATISTICS_update (stats,
gettext_noop ("# HELLOs ignored due to high load"),
1,
- GNUNET_NO);
+ GNUNET_NO);
+#if DEBUG_TRANSPORT_HELLO
+ GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
+ "Ignoring `%s' for `%4s', load too high.\n",
+ "HELLO",
+ GNUNET_i2s (&target));
+#endif
return GNUNET_OK;
}
hello = (const struct GNUNET_HELLO_Message *) message;
if (GNUNET_OK != GNUNET_HELLO_get_key (hello, &publicKey))
{
+#if DEBUG_TRANSPORT_HELLO
+ GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
+ "Unable to get public key from `%s' for `%4s'!\n",
+ "HELLO",
+ GNUNET_i2s (&target));
+#endif
GNUNET_break_op (0);
return GNUNET_SYSERR;
}
+
GNUNET_CRYPTO_hash (&publicKey,
sizeof (struct GNUNET_CRYPTO_RsaPublicKeyBinaryEncoded),
&target.hashPubKey);
+
+#if DEBUG_TRANSPORT_HELLO
+ GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
+ "Received `%s' message for `%4s'\n",
+ "HELLO",
+ GNUNET_i2s (&target));
+#endif
+
if (0 == memcmp (&my_identity,
&target,
sizeof (struct GNUNET_PeerIdentity)))
GNUNET_STATISTICS_update (stats,
gettext_noop ("# HELLOs ignored for validation (is my own HELLO)"),
1,
- GNUNET_NO);
- return GNUNET_OK;
+ GNUNET_NO);
+ return GNUNET_OK;
+ }
+ chvc = chvc_head;
+ while (NULL != chvc)
+ {
+ if (GNUNET_HELLO_equals (hello,
+ chvc->hello,
+ GNUNET_TIME_absolute_get ()).abs_value > 0)
+ {
+#if DEBUG_TRANSPORT_HELLO > 2
+ GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
+ "Received duplicate `%s' message for `%4s'; ignored\n",
+ "HELLO",
+ GNUNET_i2s (&target));
+#endif
+ return GNUNET_OK; /* validation already pending */
+ }
+ if (GNUNET_HELLO_size(hello) == GNUNET_HELLO_size (chvc->hello))
+ GNUNET_break (0 != memcmp (hello, chvc->hello,
+ GNUNET_HELLO_size(hello)));
+ chvc = chvc->next;
+ }
+
+#if BREAK_TESTS
+ struct NeighbourList *temp_neighbor = find_neighbour(&target);
+ if ((NULL != temp_neighbor))
+ {
+ fprintf(stderr, "Already know peer, ignoring hello\n");
+ return GNUNET_OK;
+ }
+#endif
+
+#if DEBUG_TRANSPORT_HELLO > 2
+ if (plugin != NULL)
+ {
+ my_id = GNUNET_strdup(GNUNET_i2s(plugin->env.my_identity));
+ GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
+ "%s: Starting validation of `%s' message for `%4s' via '%s' of size %u\n",
+ my_id,
+ "HELLO",
+ GNUNET_i2s (&target),
+ plugin->short_name,
+ GNUNET_HELLO_size(hello));
+ GNUNET_free(my_id);
}
-#if DEBUG_TRANSPORT > 1
- GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
- "Processing `%s' message for `%4s' of size %u\n",
- "HELLO",
- GNUNET_i2s (&target),
- GNUNET_HELLO_size(hello));
#endif
chvc = GNUNET_malloc (sizeof (struct CheckHelloValidatedContext) + hsize);
+ chvc->ve_count = 1;
chvc->hello = (const struct GNUNET_HELLO_Message *) &chvc[1];
memcpy (&chvc[1], hello, hsize);
GNUNET_CONTAINER_DLL_insert (chvc_head,
chvc);
/* finally, check if HELLO was previously validated
(continuation will then schedule actual validation) */
- chvc->piter = GNUNET_PEERINFO_iterate (cfg,
- sched,
+ GNUNET_STATISTICS_update (stats,
+ gettext_noop ("# peerinfo process hello iterate requests"),
+ 1,
+ GNUNET_NO);
+ GNUNET_STATISTICS_update (stats,
+ gettext_noop ("# outstanding peerinfo iterate requests"),
+ 1,
+ GNUNET_NO);
+ chvc->piter = GNUNET_PEERINFO_iterate (peerinfo,
&target,
- 0,
HELLO_VERIFICATION_TIMEOUT,
&check_hello_validated, chvc);
return GNUNET_OK;
* gone.
*
* @param n the neighbour list entry for the peer
- * @param check should we just check if all plugins
- * disconnected or must we ask all plugins to
- * disconnect?
+ * @param check GNUNET_YES to check if ALL addresses for this peer
+ * are gone, GNUNET_NO to force a disconnect of the peer
+ * regardless of whether other addresses exist.
*/
static void
disconnect_neighbour (struct NeighbourList *n, int check)
while (peer_addresses != NULL)
{
if (GNUNET_YES == peer_addresses->connected)
- return; /* still connected */
+ {
+ GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
+ "NOT Disconnecting from `%4s', still have live addresses!\n",
+ GNUNET_i2s (&n->id));
+ return; /* still connected */
+ }
peer_addresses = peer_addresses->next;
}
rpos = rpos->next;
GNUNET_STATISTICS_update (stats,
gettext_noop ("# connected addresses"),
-1,
- GNUNET_NO);
+ GNUNET_NO);
if (GNUNET_YES == peer_pos->validated)
GNUNET_STATISTICS_update (stats,
gettext_noop ("# peer addresses considered valid"),
-1,
- GNUNET_NO);
+ GNUNET_NO);
if (GNUNET_SCHEDULER_NO_TASK != peer_pos->revalidate_task)
{
- GNUNET_SCHEDULER_cancel (sched,
- peer_pos->revalidate_task);
+ GNUNET_SCHEDULER_cancel (peer_pos->revalidate_task);
peer_pos->revalidate_task = GNUNET_SCHEDULER_NO_TASK;
}
GNUNET_free(peer_pos);
GNUNET_CONTAINER_DLL_remove (n->messages_head,
n->messages_tail,
mq);
- GNUNET_assert (0 == memcmp(&mq->neighbour_id,
+ GNUNET_assert (0 == memcmp(&mq->neighbour_id,
&n->id,
sizeof(struct GNUNET_PeerIdentity)));
GNUNET_free (mq);
}
if (n->timeout_task != GNUNET_SCHEDULER_NO_TASK)
{
- GNUNET_SCHEDULER_cancel (sched, n->timeout_task);
+ GNUNET_SCHEDULER_cancel (n->timeout_task);
n->timeout_task = GNUNET_SCHEDULER_NO_TASK;
}
if (n->retry_task != GNUNET_SCHEDULER_NO_TASK)
{
- GNUNET_SCHEDULER_cancel (sched, n->retry_task);
+ GNUNET_SCHEDULER_cancel (n->retry_task);
n->retry_task = GNUNET_SCHEDULER_NO_TASK;
}
if (n->piter != NULL)
{
GNUNET_PEERINFO_iterate_cancel (n->piter);
+ GNUNET_STATISTICS_update (stats,
+ gettext_noop ("# outstanding peerinfo iterate requests"),
+ -1,
+ GNUNET_NO);
n->piter = NULL;
}
/* finally, free n itself */
gettext_noop ("# active neighbours"),
-1,
GNUNET_NO);
+ GNUNET_free_non_null (n->pre_connect_message_buffer);
GNUNET_free (n);
}
/**
* We have received a PING message from someone. Need to send a PONG message
- * in response to the peer by any means necessary.
+ * in response to the peer by any means necessary.
*/
-static int
+static int
handle_ping(void *cls, const struct GNUNET_MessageHeader *message,
const struct GNUNET_PeerIdentity *peer,
+ struct Session *session,
const char *sender_address,
- size_t sender_address_len)
+ uint16_t sender_address_len)
{
struct TransportPlugin *plugin = cls;
+ struct SessionHeader *session_header = (struct SessionHeader*) session;
struct TransportPingMessage *ping;
struct TransportPongMessage *pong;
struct NeighbourList *n;
struct ReadyList *rl;
struct ForeignAddressList *fal;
+ struct OwnAddressList *oal;
+ const char *addr;
+ size_t alen;
+ size_t slen;
- if (ntohs (message->size) != sizeof (struct TransportPingMessage))
+ if (ntohs (message->size) < sizeof (struct TransportPingMessage))
{
GNUNET_break_op (0);
return GNUNET_SYSERR;
}
+
ping = (struct TransportPingMessage *) message;
if (0 != memcmp (&ping->target,
plugin->env.my_identity,
sizeof (struct GNUNET_PeerIdentity)))
{
GNUNET_log (GNUNET_ERROR_TYPE_WARNING,
- _("Received `%s' message not destined for me!\n"),
- "PING");
+ _("Received `%s' message from `%s' destined for `%s' which is not me!\n"),
+ "PING",
+ (sender_address != NULL)
+ ? a2s (plugin->short_name,
+ (const struct sockaddr *)sender_address,
+ sender_address_len)
+ : "<inbound>",
+ GNUNET_i2s (&ping->target));
return GNUNET_SYSERR;
}
-#if DEBUG_TRANSPORT
+#if DEBUG_PING_PONG
GNUNET_log (GNUNET_ERROR_TYPE_DEBUG | GNUNET_ERROR_TYPE_BULK,
"Processing `%s' from `%s'\n",
- "PING",
- GNUNET_a2s ((const struct sockaddr *)sender_address,
- sender_address_len));
+ "PING",
+ (sender_address != NULL)
+ ? a2s (plugin->short_name,
+ (const struct sockaddr *)sender_address,
+ sender_address_len)
+ : "<inbound>");
#endif
GNUNET_STATISTICS_update (stats,
gettext_noop ("# PING messages received"),
1,
GNUNET_NO);
- pong = GNUNET_malloc (sizeof (struct TransportPongMessage) + sender_address_len);
- pong->header.size = htons (sizeof (struct TransportPongMessage) + sender_address_len);
- pong->header.type = htons (GNUNET_MESSAGE_TYPE_TRANSPORT_PONG);
- pong->purpose.size =
- htonl (sizeof (struct GNUNET_CRYPTO_RsaSignaturePurpose) +
- sizeof (uint32_t) +
- sizeof (struct GNUNET_CRYPTO_RsaPublicKeyBinaryEncoded) + sender_address_len);
- pong->purpose.purpose = htonl (GNUNET_SIGNATURE_PURPOSE_TRANSPORT_TCP_PING);
- pong->challenge = ping->challenge;
- pong->addrlen = htons(sender_address_len);
- memcpy(&pong->signer,
- &my_public_key,
- sizeof(struct GNUNET_CRYPTO_RsaPublicKeyBinaryEncoded));
- memcpy (&pong[1], sender_address, sender_address_len);
- GNUNET_assert (GNUNET_OK ==
- GNUNET_CRYPTO_rsa_sign (my_private_key,
- &pong->purpose, &pong->signature));
+ addr = (const char*) &ping[1];
+ alen = ntohs (message->size) - sizeof (struct TransportPingMessage);
+ slen = strlen (plugin->short_name) + 1;
+ if (alen == 0)
+ {
+ /* peer wants to confirm that we have an outbound connection to him */
+ if (session == NULL)
+ {
+ GNUNET_log (GNUNET_ERROR_TYPE_INFO,
+ _("Refusing to create PONG since I do not have a session with `%s'.\n"),
+ GNUNET_i2s (peer));
+ return GNUNET_SYSERR;
+ }
+ pong = GNUNET_malloc (sizeof (struct TransportPongMessage) + sender_address_len + slen);
+ pong->header.size = htons (sizeof (struct TransportPongMessage) + sender_address_len + slen);
+ pong->header.type = htons (GNUNET_MESSAGE_TYPE_TRANSPORT_PONG);
+ pong->purpose.size =
+ htonl (sizeof (struct GNUNET_CRYPTO_RsaSignaturePurpose) +
+ sizeof (uint32_t) +
+ sizeof (struct GNUNET_TIME_AbsoluteNBO) +
+ sizeof (struct GNUNET_PeerIdentity) + sender_address_len + slen);
+ pong->purpose.purpose = htonl (GNUNET_SIGNATURE_PURPOSE_TRANSPORT_PONG_USING);
+ pong->challenge = ping->challenge;
+ pong->addrlen = htonl(sender_address_len + slen);
+ memcpy(&pong->pid,
+ peer,
+ sizeof(struct GNUNET_PeerIdentity));
+ memcpy (&pong[1],
+ plugin->short_name,
+ slen);
+ memcpy (&((char*)&pong[1])[slen],
+ sender_address,
+ sender_address_len);
+ if (GNUNET_TIME_absolute_get_remaining (session_header->pong_sig_expires).rel_value < PONG_SIGNATURE_LIFETIME.rel_value / 4)
+ {
+ /* create / update cached sig */
+#if DEBUG_TRANSPORT
+ GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
+ "Creating PONG signature to indicate active connection.\n");
+#endif
+ session_header->pong_sig_expires = GNUNET_TIME_relative_to_absolute (PONG_SIGNATURE_LIFETIME);
+ pong->expiration = GNUNET_TIME_absolute_hton (session_header->pong_sig_expires);
+ GNUNET_assert (GNUNET_OK ==
+ GNUNET_CRYPTO_rsa_sign (my_private_key,
+ &pong->purpose,
+ &session_header->pong_signature));
+ }
+ else
+ {
+ pong->expiration = GNUNET_TIME_absolute_hton (session_header->pong_sig_expires);
+ }
+ memcpy (&pong->signature,
+ &session_header->pong_signature,
+ sizeof (struct GNUNET_CRYPTO_RsaSignature));
+
+
+ }
+ else
+ {
+ /* peer wants to confirm that this is one of our addresses */
+ addr += slen;
+ alen -= slen;
+ if (GNUNET_OK !=
+ plugin->api->check_address (plugin->api->cls,
+ addr,
+ alen))
+ {
+ GNUNET_log (GNUNET_ERROR_TYPE_INFO,
+ _("Not confirming PING with address `%s' since I cannot confirm having this address.\n"),
+ a2s (plugin->short_name,
+ addr,
+ alen));
+ return GNUNET_NO;
+ }
+ oal = plugin->addresses;
+ while (NULL != oal)
+ {
+ if ( (oal->addrlen == alen) &&
+ (0 == memcmp (addr,
+ &oal[1],
+ alen)) )
+ break;
+ oal = oal->next;
+ }
+ pong = GNUNET_malloc (sizeof (struct TransportPongMessage) + alen + slen);
+ pong->header.size = htons (sizeof (struct TransportPongMessage) + alen + slen);
+ pong->header.type = htons (GNUNET_MESSAGE_TYPE_TRANSPORT_PONG);
+ pong->purpose.size =
+ htonl (sizeof (struct GNUNET_CRYPTO_RsaSignaturePurpose) +
+ sizeof (uint32_t) +
+ sizeof (struct GNUNET_TIME_AbsoluteNBO) +
+ sizeof (struct GNUNET_PeerIdentity) + alen + slen);
+ pong->purpose.purpose = htonl (GNUNET_SIGNATURE_PURPOSE_TRANSPORT_PONG_OWN);
+ pong->challenge = ping->challenge;
+ pong->addrlen = htonl(alen + slen);
+ memcpy(&pong->pid,
+ &my_identity,
+ sizeof(struct GNUNET_PeerIdentity));
+ memcpy (&pong[1], plugin->short_name, slen);
+ memcpy (&((char*)&pong[1])[slen], addr, alen);
+ if ( (oal != NULL) &&
+ (GNUNET_TIME_absolute_get_remaining (oal->pong_sig_expires).rel_value < PONG_SIGNATURE_LIFETIME.rel_value / 4) )
+ {
+ /* create / update cached sig */
+#if DEBUG_TRANSPORT
+ GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
+ "Creating PONG signature to indicate ownership.\n");
+#endif
+ oal->pong_sig_expires = GNUNET_TIME_absolute_min (oal->expires,
+ GNUNET_TIME_relative_to_absolute (PONG_SIGNATURE_LIFETIME));
+ pong->expiration = GNUNET_TIME_absolute_hton (oal->pong_sig_expires);
+ GNUNET_assert (GNUNET_OK ==
+ GNUNET_CRYPTO_rsa_sign (my_private_key,
+ &pong->purpose,
+ &oal->pong_signature));
+ memcpy (&pong->signature,
+ &oal->pong_signature,
+ sizeof (struct GNUNET_CRYPTO_RsaSignature));
+ }
+ else if (oal == NULL)
+ {
+ /* not using cache (typically DV-only) */
+ pong->expiration = GNUNET_TIME_absolute_hton (GNUNET_TIME_relative_to_absolute (PONG_SIGNATURE_LIFETIME));
+ GNUNET_assert (GNUNET_OK ==
+ GNUNET_CRYPTO_rsa_sign (my_private_key,
+ &pong->purpose,
+ &pong->signature));
+ }
+ else
+ {
+ /* can used cached version */
+ pong->expiration = GNUNET_TIME_absolute_hton (oal->pong_sig_expires);
+ memcpy (&pong->signature,
+ &oal->pong_signature,
+ sizeof (struct GNUNET_CRYPTO_RsaSignature));
+ }
+ }
n = find_neighbour(peer);
- if (n == NULL)
- n = setup_new_neighbour(peer);
+ GNUNET_assert (n != NULL);
/* first try reliable response transmission */
rl = n->plugins;
while (rl != NULL)
peer,
(const char*) pong,
ntohs (pong->header.size),
- TRANSPORT_PONG_PRIORITY,
+ TRANSPORT_PONG_PRIORITY,
HELLO_VERIFICATION_TIMEOUT,
+ fal->session,
fal->addr,
fal->addrlen,
GNUNET_SYSERR,
GNUNET_STATISTICS_update (stats,
gettext_noop ("# PONGs unicast via reliable transport"),
1,
- GNUNET_NO);
+ GNUNET_NO);
GNUNET_free (pong);
return GNUNET_OK;
}
GNUNET_STATISTICS_update (stats,
gettext_noop ("# PONGs multicast to all available addresses"),
1,
- GNUNET_NO);
+ GNUNET_NO);
rl = n->plugins;
while (rl != NULL)
{
while (fal != NULL)
{
transmit_to_peer(NULL, fal,
- TRANSPORT_PONG_PRIORITY,
+ TRANSPORT_PONG_PRIORITY,
HELLO_VERIFICATION_TIMEOUT,
- (const char *)pong,
- ntohs(pong->header.size),
- GNUNET_YES,
+ (const char *)pong,
+ ntohs(pong->header.size),
+ GNUNET_YES,
n);
fal = fal->next;
}
* @param message the message, NULL if we only care about
* learning about the delay until we should receive again
* @param distance in overlay hops; use 1 unless DV (or 0 if message == NULL)
+ * @param session identifier used for this session (can be NULL)
* @param sender_address binary address of the sender (if observed)
* @param sender_address_len number of bytes in sender_address
- * @return how long the plugin should wait until receiving more data
+ * @return how long in ms the plugin should wait until receiving more data
* (plugins that do not support this, can ignore the return value)
*/
static struct GNUNET_TIME_Relative
plugin_env_receive (void *cls, const struct GNUNET_PeerIdentity *peer,
const struct GNUNET_MessageHeader *message,
- unsigned int distance, const char *sender_address,
- size_t sender_address_len)
+ const struct GNUNET_TRANSPORT_ATS_Information *ats,
+ uint32_t ats_count,
+ struct Session *session,
+ const char *sender_address,
+ uint16_t sender_address_len)
{
- struct ReadyList *service_context;
struct TransportPlugin *plugin = cls;
- struct TransportClient *cpos;
- struct InboundMessage *im;
+ struct ReadyList *service_context;
struct ForeignAddressList *peer_address;
uint16_t msize;
struct NeighbourList *n;
struct GNUNET_TIME_Relative ret;
+ if (is_blacklisted (peer, plugin))
+ return GNUNET_TIME_UNIT_FOREVER_REL;
+ uint32_t distance;
+ int c;
n = find_neighbour (peer);
if (n == NULL)
- n = setup_new_neighbour (peer);
+ n = setup_new_neighbour (peer, GNUNET_YES);
service_context = n->plugins;
while ((service_context != NULL) && (plugin != service_context->plugin))
service_context = service_context->next;
GNUNET_assert ((plugin->api->send == NULL) || (service_context != NULL));
+ peer_address = NULL;
+ distance = 1;
+ for (c=0; c<ats_count; c++)
+ {
+ if (ntohl(ats[c].type) == GNUNET_TRANSPORT_ATS_QUALITY_NET_DISTANCE)
+ {
+ distance = ntohl(ats[c].value);
+ }
+ }
+
if (message != NULL)
{
- peer_address = add_peer_address(n,
- plugin->short_name,
- sender_address,
- sender_address_len);
+ if ( (session != NULL) ||
+ (sender_address != NULL) )
+ peer_address = add_peer_address (n,
+ plugin->short_name,
+ session,
+ sender_address,
+ sender_address_len);
if (peer_address != NULL)
{
peer_address->distance = distance;
- if (peer_address->connected == GNUNET_NO)
- {
- /* FIXME: be careful here to not mark
- MULTIPLE addresses as connected! */
- peer_address->connected = GNUNET_YES;
- GNUNET_STATISTICS_update (stats,
- gettext_noop ("# connected addresses"),
- 1,
- GNUNET_NO);
- }
+ if (GNUNET_YES == peer_address->validated)
+ mark_address_connected (peer_address);
peer_address->timeout
=
GNUNET_TIME_relative_to_absolute
schedule_next_ping (peer_address);
}
/* update traffic received amount ... */
- msize = ntohs (message->size);
+ msize = ntohs (message->size);
GNUNET_STATISTICS_update (stats,
gettext_noop ("# bytes received from other peers"),
msize,
n->peer_timeout =
GNUNET_TIME_relative_to_absolute
(GNUNET_CONSTANTS_IDLE_CONNECTION_TIMEOUT);
- GNUNET_SCHEDULER_cancel (sched,
- n->timeout_task);
+ GNUNET_SCHEDULER_cancel (n->timeout_task);
n->timeout_task =
- GNUNET_SCHEDULER_add_delayed (sched,
- GNUNET_CONSTANTS_IDLE_CONNECTION_TIMEOUT,
+ GNUNET_SCHEDULER_add_delayed (GNUNET_CONSTANTS_IDLE_CONNECTION_TIMEOUT,
&neighbour_timeout_task, n);
if (n->quota_violation_count > QUOTA_VIOLATION_DROP_THRESHOLD)
{
GNUNET_log (GNUNET_ERROR_TYPE_WARNING |
GNUNET_ERROR_TYPE_BULK,
_
- ("Dropping incoming message due to repeated bandwidth quota (%u b/s) violations (total of %u).\n"),
+ ("Dropping incoming message due to repeated bandwidth quota (%u b/s) violations (total of %u).\n"),
n->in_tracker.available_bytes_per_s__,
n->quota_violation_count);
GNUNET_STATISTICS_update (stats,
GNUNET_NO);
return GNUNET_CONSTANTS_QUOTA_VIOLATION_TIMEOUT;
}
+
+#if DEBUG_PING_PONG
+ GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
+ "Received message of type %u and size %u from `%4s', sending to all clients.\n",
+ ntohs (message->type),
+ ntohs (message->size),
+ GNUNET_i2s (peer));
+#endif
switch (ntohs (message->type))
{
case GNUNET_MESSAGE_TYPE_HELLO:
process_hello (plugin, message);
break;
case GNUNET_MESSAGE_TYPE_TRANSPORT_PING:
- handle_ping(plugin, message, peer, sender_address, sender_address_len);
+ handle_ping (plugin, message, peer, session, sender_address, sender_address_len);
break;
case GNUNET_MESSAGE_TYPE_TRANSPORT_PONG:
- handle_pong(plugin, message, peer, sender_address, sender_address_len);
+ handle_pong (plugin, message, peer, sender_address, sender_address_len);
break;
default:
-#if DEBUG_TRANSPORT
- GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
- "Received message of type %u from `%4s', sending to all clients.\n",
- ntohs (message->type), GNUNET_i2s (peer));
-#endif
- if (GNUNET_YES == GNUNET_BANDWIDTH_tracker_consume (&n->in_tracker,
- (ssize_t) msize))
- {
- n->quota_violation_count++;
-#if DEBUG_TRANSPORT
- GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
- "Bandwidth quota (%u b/s) violation detected (total of %u).\n",
- n->in_tracker.available_bytes_per_s__,
- n->quota_violation_count);
-#endif
- /* Discount 32k per violation */
- GNUNET_BANDWIDTH_tracker_consume (&n->in_tracker,
- - 32 * 1024);
- }
- else
- {
- if (n->quota_violation_count > 0)
- {
- /* try to add 32k back */
- GNUNET_BANDWIDTH_tracker_consume (&n->in_tracker,
- 32 * 1024);
- n->quota_violation_count--;
- }
- }
- GNUNET_STATISTICS_update (stats,
- gettext_noop ("# payload received from other peers"),
- msize,
- GNUNET_NO);
- /* transmit message to all clients */
- im = GNUNET_malloc (sizeof (struct InboundMessage) + msize);
- im->header.size = htons (sizeof (struct InboundMessage) + msize);
- im->header.type = htons (GNUNET_MESSAGE_TYPE_TRANSPORT_RECV);
- im->latency = GNUNET_TIME_relative_hton (n->latency);
- im->peer = *peer;
- memcpy (&im[1], message, msize);
- cpos = clients;
- while (cpos != NULL)
- {
- transmit_to_client (cpos, &im->header, GNUNET_YES);
- cpos = cpos->next;
- }
- GNUNET_free (im);
+ handle_payload_message (message, n);
+ break;
}
- }
+ }
ret = GNUNET_BANDWIDTH_tracker_get_delay (&n->in_tracker, 0);
- if (ret.value > 0)
+ if (ret.rel_value > 0)
{
- GNUNET_log (GNUNET_ERROR_TYPE_WARNING,
+ GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
"Throttling read (%llu bytes excess at %u b/s), waiting %llums before reading more.\n",
(unsigned long long) n->in_tracker.consumption_since_last_update__,
(unsigned int) n->in_tracker.available_bytes_per_s__,
- (unsigned long long) ret.value);
+ (unsigned long long) ret.rel_value);
GNUNET_STATISTICS_update (stats,
gettext_noop ("# ms throttling suggested"),
- (int64_t) ret.value,
- GNUNET_NO);
+ (int64_t) ret.rel_value,
+ GNUNET_NO);
}
return ret;
}
-
/**
* Handle START-message. This is the first message sent to us
* by any client which causes us to add it to our list.
struct GNUNET_SERVER_Client *client,
const struct GNUNET_MessageHeader *message)
{
+ const struct StartMessage *start;
struct TransportClient *c;
- struct ConnectInfoMessage cim;
+ struct ConnectInfoMessage * cim;
struct NeighbourList *n;
+ uint32_t ats_count;
+ size_t size;
+ start = (const struct StartMessage*) message;
#if DEBUG_TRANSPORT
GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
"Received `%s' request from client\n", "START");
}
c = c->next;
}
+ if ( (GNUNET_NO != ntohl (start->do_check)) &&
+ (0 != memcmp (&start->self,
+ &my_identity,
+ sizeof (struct GNUNET_PeerIdentity))) )
+ {
+ GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
+ _("Rejecting control connection from peer `%s', which is not me!\n"),
+ GNUNET_i2s (&start->self));
+ GNUNET_SERVER_receive_done (client, GNUNET_SYSERR);
+ return;
+ }
c = GNUNET_malloc (sizeof (struct TransportClient));
c->next = clients;
clients = c;
c->client = client;
if (our_hello != NULL)
- {
+ {
#if DEBUG_TRANSPORT
GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
"Sending our own `%s' to new client\n", "HELLO");
(const struct GNUNET_MessageHeader *) our_hello,
GNUNET_NO);
/* tell new client about all existing connections */
- cim.header.size = htons (sizeof (struct ConnectInfoMessage));
- cim.header.type = htons (GNUNET_MESSAGE_TYPE_TRANSPORT_CONNECT);
- n = neighbours;
+ ats_count = 2;
+ size = sizeof (struct ConnectInfoMessage) + ats_count * sizeof (struct GNUNET_TRANSPORT_ATS_Information);
+ if (size > GNUNET_SERVER_MAX_MESSAGE_SIZE)
+ {
+ GNUNET_break(0);
+ }
+ cim = GNUNET_malloc (size);
+
+ cim->header.size = htons (size);
+ cim->header.type = htons (GNUNET_MESSAGE_TYPE_TRANSPORT_CONNECT);
+ cim->ats_count = htonl(ats_count);
+ (&(cim->ats))[2].type = htonl (GNUNET_TRANSPORT_ATS_ARRAY_TERMINATOR);
+ (&(cim->ats))[2].value = htonl (0);
+ n = neighbours;
while (n != NULL)
- {
- if (GNUNET_YES == n->received_pong)
- {
- cim.id = n->id;
- cim.latency = GNUNET_TIME_relative_hton (n->latency);
- cim.distance = htonl (n->distance);
- transmit_to_client (c, &cim.header, GNUNET_NO);
- }
+ {
+ if (GNUNET_YES == n->received_pong)
+ {
+ (&(cim->ats))[0].type = htonl (GNUNET_TRANSPORT_ATS_QUALITY_NET_DISTANCE);
+ (&(cim->ats))[0].value = htonl (n->distance);
+ (&(cim->ats))[1].type = htonl (GNUNET_TRANSPORT_ATS_QUALITY_NET_DELAY);
+ (&(cim->ats))[1].value = htonl ((uint32_t) n->latency.rel_value);
+ cim->id = n->id;
+ transmit_to_client (c, &cim->header, GNUNET_NO);
+ }
n = n->next;
- }
- }
+ }
+ }
GNUNET_SERVER_receive_done (client, GNUNET_OK);
+ GNUNET_free(cim);
}
GNUNET_STATISTICS_update (stats,
gettext_noop ("# HELLOs received from clients"),
1,
- GNUNET_NO);
+ GNUNET_NO);
ret = process_hello (NULL, message);
GNUNET_SERVER_receive_done (client, ret);
}
+/**
+ * Closure for 'transmit_client_message'; followed by
+ * 'msize' bytes of the actual message.
+ */
+struct TransmitClientMessageContext
+{
+ /**
+ * Client on whom's behalf we are sending.
+ */
+ struct GNUNET_SERVER_Client *client;
+
+ /**
+ * Timeout for the transmission.
+ */
+ struct GNUNET_TIME_Absolute timeout;
+
+ /**
+ * Message priority.
+ */
+ uint32_t priority;
+
+ /**
+ * Size of the message in bytes.
+ */
+ uint16_t msize;
+};
+
+
+/**
+ * Schedule transmission of a message we got from a client to a peer.
+ *
+ * @param cls the 'struct TransmitClientMessageContext*'
+ * @param n destination, or NULL on error (in that case, drop the message)
+ */
+static void
+transmit_client_message (void *cls,
+ struct NeighbourList *n)
+{
+ struct TransmitClientMessageContext *tcmc = cls;
+ struct TransportClient *tc;
+
+ tc = clients;
+ while ((tc != NULL) && (tc->client != tcmc->client))
+ tc = tc->next;
+
+ if (n != NULL)
+ {
+ transmit_to_peer (tc, NULL, tcmc->priority,
+ GNUNET_TIME_absolute_get_remaining (tcmc->timeout),
+ (char *)&tcmc[1],
+ tcmc->msize, GNUNET_NO, n);
+ }
+ GNUNET_SERVER_receive_done (tcmc->client, GNUNET_OK);
+ GNUNET_SERVER_client_drop (tcmc->client);
+ GNUNET_free (tcmc);
+}
+
+
/**
* Handle SEND-message.
*
struct GNUNET_SERVER_Client *client,
const struct GNUNET_MessageHeader *message)
{
- struct TransportClient *tc;
- struct NeighbourList *n;
const struct OutboundMessage *obm;
const struct GNUNET_MessageHeader *obmm;
+ struct TransmitClientMessageContext *tcmc;
uint16_t size;
uint16_t msize;
GNUNET_STATISTICS_update (stats,
gettext_noop ("# payload received for other peers"),
size,
- GNUNET_NO);
+ GNUNET_NO);
obm = (const struct OutboundMessage *) message;
-#if DEBUG_TRANSPORT
- GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
- "Received `%s' request from client with target `%4s'\n",
- "SEND", GNUNET_i2s (&obm->peer));
-#endif
obmm = (const struct GNUNET_MessageHeader *) &obm[1];
- msize = ntohs (obmm->size);
- if (size != msize + sizeof (struct OutboundMessage))
- {
- GNUNET_break (0);
- GNUNET_SERVER_receive_done (client, GNUNET_SYSERR);
- return;
- }
- n = find_neighbour (&obm->peer);
- if (n == NULL)
- n = setup_new_neighbour (&obm->peer);
- tc = clients;
- while ((tc != NULL) && (tc->client != client))
- tc = tc->next;
+ msize = size - sizeof (struct OutboundMessage);
-#if DEBUG_TRANSPORT
GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
- "Client asked to transmit %u-byte message of type %u to `%4s'\n",
- ntohs (obmm->size),
- ntohs (obmm->type), GNUNET_i2s (&obm->peer));
-#endif
- transmit_to_peer (tc, NULL, ntohl (obm->priority),
- GNUNET_TIME_relative_ntoh (obm->timeout),
- (char *)obmm,
- ntohs (obmm->size), GNUNET_NO, n);
- GNUNET_SERVER_receive_done (client, GNUNET_OK);
+ "Received `%s' request from client with target `%4s' and message of type %u and size %u\n",
+ "SEND", GNUNET_i2s (&obm->peer),
+ ntohs (obmm->type),
+ msize);
+
+ tcmc = GNUNET_malloc (sizeof (struct TransmitClientMessageContext) + msize);
+ tcmc->client = client;
+ tcmc->priority = ntohl (obm->priority);
+ tcmc->timeout = GNUNET_TIME_relative_to_absolute (GNUNET_TIME_relative_ntoh (obm->timeout));
+ tcmc->msize = msize;
+ /* FIXME: this memcpy can be up to 7% of our total runtime */
+ memcpy (&tcmc[1], obmm, msize);
+ GNUNET_SERVER_client_keep (client);
+ setup_peer_check_blacklist (&obm->peer, GNUNET_YES,
+ &transmit_client_message,
+ tcmc);
}
+/**
+ * Handle request connect message
+ *
+ * @param cls closure (always NULL)
+ * @param client identification of the client
+ * @param message the actual message
+ */
+static void
+handle_request_connect (void *cls,
+ struct GNUNET_SERVER_Client *client,
+ const struct GNUNET_MessageHeader *message)
+{
+ const struct TransportRequestConnectMessage *trcm =
+ (const struct TransportRequestConnectMessage *) message;
+
+ GNUNET_STATISTICS_update (stats,
+ gettext_noop ("# REQUEST CONNECT messages received"),
+ 1,
+ GNUNET_NO);
+ GNUNET_log(GNUNET_ERROR_TYPE_DEBUG, "Received a request connect message for peer %s\n", GNUNET_i2s(&trcm->peer));
+ setup_peer_check_blacklist (&trcm->peer, GNUNET_YES,
+ NULL, NULL);
+ GNUNET_SERVER_receive_done (client, GNUNET_OK);
+}
+
/**
* Handle SET_QUOTA-message.
*
const struct QuotaSetMessage *qsm =
(const struct QuotaSetMessage *) message;
struct NeighbourList *n;
-
+
GNUNET_STATISTICS_update (stats,
gettext_noop ("# SET QUOTA messages received"),
1,
- GNUNET_NO);
+ GNUNET_NO);
n = find_neighbour (&qsm->peer);
if (n == NULL)
{
GNUNET_STATISTICS_update (stats,
gettext_noop ("# SET QUOTA messages ignored (no such peer)"),
1,
- GNUNET_NO);
+ GNUNET_NO);
return;
}
#if DEBUG_TRANSPORT
GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
"Received `%s' request (new quota %u, old quota %u) from client for peer `%4s'\n",
- "SET_QUOTA",
+ "SET_QUOTA",
(unsigned int) ntohl (qsm->quota.value__),
(unsigned int) n->in_tracker.available_bytes_per_s__,
GNUNET_i2s (&qsm->peer));
#endif
GNUNET_BANDWIDTH_tracker_update_quota (&n->in_tracker,
qsm->quota);
- if (0 == ntohl (qsm->quota.value__))
- disconnect_neighbour (n, GNUNET_NO);
+ if (0 == ntohl (qsm->quota.value__))
+ {
+ GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
+ "Disconnecting peer `%4s', %s\n", GNUNET_i2s(&n->id),
+ "SET_QUOTA");
+ disconnect_neighbour (n, GNUNET_NO);
+ }
GNUNET_SERVER_receive_done (client, GNUNET_OK);
}
/**
- * Take the given address and append it to the set of results send back to
+ * Take the given address and append it to the set of results sent back to
* the client.
- *
+ *
* @param cls the transmission context used ('struct GNUNET_SERVER_TransmitContext*')
* @param address the resolved name, NULL to indicate the last response
*/
slen = 0;
else
slen = strlen (address) + 1;
+
GNUNET_SERVER_transmit_context_append_data (tc, address, slen,
GNUNET_MESSAGE_TYPE_TRANSPORT_ADDRESS_REPLY);
if (NULL == address)
tc = GNUNET_SERVER_transmit_context_create (client);
lsPlugin->api->address_pretty_printer (lsPlugin->api->cls,
nameTransport,
- address, addressLen,
+ address, addressLen,
numeric,
rtimeout,
&transmit_address_to_client, tc);
}
-/**
- * List of handlers for the messages understood by this
- * service.
- */
-static struct GNUNET_SERVER_MessageHandler handlers[] = {
- {&handle_start, NULL,
- GNUNET_MESSAGE_TYPE_TRANSPORT_START, 0},
- {&handle_hello, NULL,
- GNUNET_MESSAGE_TYPE_HELLO, 0},
- {&handle_send, NULL,
- GNUNET_MESSAGE_TYPE_TRANSPORT_SEND, 0},
- {&handle_set_quota, NULL,
- GNUNET_MESSAGE_TYPE_TRANSPORT_SET_QUOTA, sizeof (struct QuotaSetMessage)},
- {&handle_address_lookup, NULL,
- GNUNET_MESSAGE_TYPE_TRANSPORT_ADDRESS_LOOKUP,
- 0},
- {NULL, NULL, 0, 0}
-};
-
/**
* Setup the environment for this plugin.
create_environment (struct TransportPlugin *plug)
{
plug->env.cfg = cfg;
- plug->env.sched = sched;
plug->env.my_identity = &my_identity;
+ plug->env.our_hello = &our_hello;
plug->env.cls = plug;
plug->env.receive = &plugin_env_receive;
plug->env.notify_address = &plugin_env_notify_address;
+ plug->env.session_end = &plugin_env_session_end;
plug->env.max_connections = max_connect_per_transport;
plug->env.stats = stats;
}
* Start the specified transport (load the plugin).
*/
static void
-start_transport (struct GNUNET_SERVER_Handle *server, const char *name)
+start_transport (struct GNUNET_SERVER_Handle *server,
+ const char *name)
{
struct TransportPlugin *plug;
char *libname;
struct TransportClient *pos;
struct TransportClient *prev;
struct ClientMessageQueueEntry *mqe;
+ struct Blacklisters *bl;
+ struct BlacklistCheck *bc;
if (client == NULL)
return;
GNUNET_log (GNUNET_ERROR_TYPE_DEBUG | GNUNET_ERROR_TYPE_BULK,
"Client disconnected, cleaning up.\n");
#endif
+ /* clean up blacklister */
+ bl = bl_head;
+ while (bl != NULL)
+ {
+ if (bl->client == client)
+ {
+ bc = bc_head;
+ while (bc != NULL)
+ {
+ if (bc->bl_pos == bl)
+ {
+ 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;
+ }
+ bc = bc->next;
+ }
+ GNUNET_CONTAINER_DLL_remove (bl_head,
+ bl_tail,
+ bl);
+ GNUNET_SERVER_client_drop (bl->client);
+ GNUNET_free (bl);
+ break;
+ }
+ bl = bl->next;
+ }
+ /* clean up 'normal' clients */
prev = NULL;
pos = clients;
while ((pos != NULL) && (pos->client != client))
}
-/**
- * Iterator to free entries in the validation_map.
- *
- * @param cls closure (unused)
- * @param key current key code
- * @param value value in the hash map (validation to abort)
- * @return GNUNET_YES (always)
- */
-static int
-abort_validation (void *cls,
- const GNUNET_HashCode * key,
- void *value)
-{
- struct ValidationEntry *va = value;
-
- GNUNET_SCHEDULER_cancel (sched, va->timeout_task);
- GNUNET_free (va->transport_name);
- GNUNET_free (va);
- return GNUNET_YES;
-}
-
-
/**
* Function called when the service shuts down. Unloads our plugins
* and cancels pending validations.
struct CheckHelloValidatedContext *chvc;
while (neighbours != NULL)
- disconnect_neighbour (neighbours, GNUNET_NO);
+ {
+ GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
+ "Disconnecting peer `%4s', %s\n", GNUNET_i2s(&neighbours->id),
+ "SHUTDOWN_TASK");
+ disconnect_neighbour (neighbours, GNUNET_NO);
+ }
#if DEBUG_TRANSPORT
GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
"Transport service is unloading plugins...\n");
plugins = plug->next;
if (plug->address_update_task != GNUNET_SCHEDULER_NO_TASK)
{
- GNUNET_SCHEDULER_cancel (plug->env.sched,
- plug->address_update_task);
+ GNUNET_SCHEDULER_cancel (plug->address_update_task);
plug->address_update_task = GNUNET_SCHEDULER_NO_TASK;
}
GNUNET_break (NULL == GNUNET_PLUGIN_unload (plug->lib_name, plug->api));
GNUNET_CRYPTO_rsa_key_free (my_private_key);
GNUNET_free_non_null (our_hello);
+ GNUNET_CONTAINER_multihashmap_iterate (validation_map,
+ &abort_validation,
+ NULL);
+ GNUNET_CONTAINER_multihashmap_destroy (validation_map);
+ validation_map = NULL;
+
/* free 'chvc' data structure */
while (NULL != (chvc = chvc_head))
{
chvc_head = chvc->next;
- GNUNET_PEERINFO_iterate_cancel (chvc->piter);
+ if (chvc->piter != NULL)
+ {
+ GNUNET_PEERINFO_iterate_cancel (chvc->piter);
+ GNUNET_STATISTICS_update (stats,
+ gettext_noop ("# outstanding peerinfo iterate requests"),
+ -1,
+ GNUNET_NO);
+ }
+ else
+ GNUNET_break (0);
+ GNUNET_assert (chvc->ve_count == 0);
GNUNET_free (chvc);
}
chvc_tail = NULL;
- GNUNET_CONTAINER_multihashmap_iterate (validation_map,
- &abort_validation,
- NULL);
- GNUNET_CONTAINER_multihashmap_destroy (validation_map);
- validation_map = NULL;
if (stats != NULL)
{
GNUNET_STATISTICS_destroy (stats, GNUNET_NO);
stats = NULL;
}
+ if (peerinfo != NULL)
+ {
+ GNUNET_PEERINFO_disconnect (peerinfo);
+ peerinfo = NULL;
+ }
+ /* Can we assume those are gone by now, or do we need to clean up
+ explicitly!? */
+ GNUNET_break (bl_head == NULL);
+ GNUNET_break (bc_head == NULL);
}
* Initiate transport service.
*
* @param cls closure
- * @param s scheduler to use
- * @param serv the initialized server
+ * @param server the initialized server
* @param c configuration to use
*/
static void
run (void *cls,
- struct GNUNET_SCHEDULER_Handle *s,
- struct GNUNET_SERVER_Handle *serv,
+ struct GNUNET_SERVER_Handle *server,
const struct GNUNET_CONFIGURATION_Handle *c)
{
+ static const struct GNUNET_SERVER_MessageHandler handlers[] = {
+ {&handle_start, NULL,
+ GNUNET_MESSAGE_TYPE_TRANSPORT_START, sizeof (struct StartMessage)},
+ {&handle_hello, NULL,
+ GNUNET_MESSAGE_TYPE_HELLO, 0},
+ {&handle_send, NULL,
+ GNUNET_MESSAGE_TYPE_TRANSPORT_SEND, 0},
+ {&handle_request_connect, NULL,
+ GNUNET_MESSAGE_TYPE_TRANSPORT_REQUEST_CONNECT, sizeof(struct TransportRequestConnectMessage)},
+ {&handle_set_quota, NULL,
+ GNUNET_MESSAGE_TYPE_TRANSPORT_SET_QUOTA, sizeof (struct QuotaSetMessage)},
+ {&handle_address_lookup, NULL,
+ GNUNET_MESSAGE_TYPE_TRANSPORT_ADDRESS_LOOKUP,
+ 0},
+ {&handle_blacklist_init, NULL,
+ GNUNET_MESSAGE_TYPE_TRANSPORT_BLACKLIST_INIT, sizeof (struct GNUNET_MessageHeader)},
+ {&handle_blacklist_reply, NULL,
+ GNUNET_MESSAGE_TYPE_TRANSPORT_BLACKLIST_REPLY, sizeof (struct BlacklistMessage)},
+ {NULL, NULL, 0, 0}
+ };
char *plugs;
char *pos;
int no_transports;
unsigned long long tneigh;
char *keyfile;
- sched = s;
cfg = c;
- stats = GNUNET_STATISTICS_create (sched, "transport", cfg);
+ stats = GNUNET_STATISTICS_create ("transport", cfg);
validation_map = GNUNET_CONTAINER_multihashmap_create (64);
/* parse configuration */
if ((GNUNET_OK !=
GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
_
("Transport service is lacking key configuration settings. Exiting.\n"));
- GNUNET_SCHEDULER_shutdown (s);
+ GNUNET_SCHEDULER_shutdown ();
if (stats != NULL)
{
GNUNET_STATISTICS_destroy (stats, GNUNET_NO);
return;
}
max_connect_per_transport = (uint32_t) tneigh;
+ peerinfo = GNUNET_PEERINFO_connect (cfg);
+ if (peerinfo == NULL)
+ {
+ GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
+ _("Could not access PEERINFO service. Exiting.\n"));
+ GNUNET_SCHEDULER_shutdown ();
+ if (stats != NULL)
+ {
+ GNUNET_STATISTICS_destroy (stats, GNUNET_NO);
+ stats = NULL;
+ }
+ GNUNET_CONTAINER_multihashmap_destroy (validation_map);
+ validation_map = NULL;
+ GNUNET_free (keyfile);
+ return;
+ }
my_private_key = GNUNET_CRYPTO_rsa_key_create_from_file (keyfile);
GNUNET_free (keyfile);
if (my_private_key == NULL)
GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
_
("Transport service could not access hostkey. Exiting.\n"));
- GNUNET_SCHEDULER_shutdown (s);
+ GNUNET_SCHEDULER_shutdown ();
if (stats != NULL)
{
GNUNET_STATISTICS_destroy (stats, GNUNET_NO);
GNUNET_CRYPTO_hash (&my_public_key,
sizeof (my_public_key), &my_identity.hashPubKey);
/* setup notification */
- server = serv;
GNUNET_SERVER_disconnect_notify (server,
&client_disconnect_notification, NULL);
/* load plugins... */
}
GNUNET_free (plugs);
}
- GNUNET_SCHEDULER_add_delayed (sched,
- GNUNET_TIME_UNIT_FOREVER_REL,
+ GNUNET_SCHEDULER_add_delayed (GNUNET_TIME_UNIT_FOREVER_REL,
&shutdown_task, NULL);
if (no_transports)
refresh_hello ();
#if DEBUG_TRANSPORT
GNUNET_log (GNUNET_ERROR_TYPE_INFO, _("Transport service ready.\n"));
#endif
+ /* If we have a blacklist file, read from it */
+ read_blacklist_file(cfg);
/* process client requests */
GNUNET_SERVER_add_handlers (server, handlers);
}
int
main (int argc, char *const *argv)
{
+ a2s (NULL, NULL, 0); /* make compiler happy */
return (GNUNET_OK ==
GNUNET_SERVICE_run (argc,
argv,